Files
resolutionflow/frontend/src/components/flowpilot/FlowPilotIntake.tsx
chihlasm 5494816b06 feat(ai-session): add FlowPilot AI-powered troubleshooting sessions
Implements Phase 1 of the FlowPilot-First pivot — the core AI session
experience where engineers describe a problem and FlowPilot guides them
through structured diagnosis with selectable options, free-text escape
hatches, and auto-generated documentation on resolution.

Backend: AISession + AISessionStep models, FlowPilot Engine (LLM
orchestration with structured JSON output), Flow Matching Engine v1
(semantic + keyword + recency scoring), 8 API endpoints with auth,
rate limiting, and AI quota enforcement.

Frontend: Intake screen, conversational session view with sidebar,
step cards with options/actions/resolution suggestions, resolve/escalate
modals, documentation view with rating, session history integration,
and /pilot route with sidebar navigation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 14:27:36 +00:00

120 lines
4.7 KiB
TypeScript

import { useState } from 'react'
import { Sparkles, FileText, Terminal } from 'lucide-react'
import type { AISessionCreateRequest } from '@/types/ai-session'
interface FlowPilotIntakeProps {
onSubmit: (request: AISessionCreateRequest) => void
isLoading: boolean
}
export function FlowPilotIntake({ onSubmit, isLoading }: FlowPilotIntakeProps) {
const [text, setText] = useState('')
const [showLogs, setShowLogs] = useState(false)
const [logContent, setLogContent] = useState('')
const handleSubmit = () => {
if (!text.trim() && !logContent.trim()) return
const intake_content: Record<string, unknown> = {}
if (text.trim()) intake_content.text = text.trim()
if (logContent.trim()) intake_content.log_content = logContent.trim()
const intake_type = logContent.trim()
? text.trim() ? 'combined' : 'log_paste'
: 'free_text'
onSubmit({ intake_type, intake_content })
}
const hasContent = text.trim() || logContent.trim()
if (isLoading) {
return (
<div className="flex items-center justify-center min-h-[50vh]">
<div className="text-center">
<div className="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-2xl bg-primary/10">
<Sparkles size={24} className="text-primary animate-pulse" />
</div>
<p className="text-sm font-medium text-foreground">Analyzing your issue...</p>
<p className="mt-1 text-xs text-muted-foreground">FlowPilot is classifying the problem and searching for relevant flows</p>
</div>
</div>
)
}
return (
<div className="flex items-start justify-center pt-[10vh]">
<div className="w-full max-w-2xl">
<div className="text-center mb-6">
<h1 className="font-heading text-2xl font-bold tracking-tight text-foreground">
What are you troubleshooting?
</h1>
<p className="mt-2 text-sm text-muted-foreground">
Describe the issue, paste an error message, or paste log output
</p>
</div>
<div className="glass-card-static p-5 space-y-4">
{/* Main text area */}
<textarea
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="e.g. User can't access shared drive after password reset, getting 'Access Denied' in Event Viewer..."
className="w-full rounded-lg border border-border bg-card px-4 py-3 text-sm text-foreground placeholder:text-muted-foreground focus:border-[rgba(6,182,212,0.3)] focus:outline-none resize-none"
rows={5}
autoFocus
/>
{/* Input type toggles */}
<div className="flex items-center gap-2">
<button
onClick={() => setShowLogs(!showLogs)}
className={`flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs font-medium transition-colors ${
showLogs
? 'bg-primary/10 text-primary border border-primary/20'
: 'bg-card/50 text-muted-foreground border border-border hover:text-foreground'
}`}
>
<Terminal size={12} />
Paste Logs
</button>
<button
disabled
className="flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs font-medium bg-card/50 text-[#5a6170] border border-border opacity-50 cursor-not-allowed"
title="Coming in Phase 2"
>
<FileText size={12} />
Pull from Ticket
</button>
</div>
{/* Log paste area */}
{showLogs && (
<textarea
value={logContent}
onChange={(e) => setLogContent(e.target.value)}
placeholder="Paste log output, error messages, or Event Viewer entries here..."
className="w-full rounded-lg border border-border bg-card px-4 py-3 font-mono text-xs text-foreground placeholder:text-muted-foreground focus:border-[rgba(6,182,212,0.3)] focus:outline-none resize-none"
rows={6}
/>
)}
{/* Submit */}
<div className="flex items-center justify-between">
<p className="text-[0.6875rem] text-[#5a6170]">
FlowPilot will analyze your input and guide you through diagnosis
</p>
<button
onClick={handleSubmit}
disabled={!hasContent}
className="rounded-lg bg-gradient-brand px-5 py-2.5 text-sm font-semibold text-[#101114] shadow-lg shadow-primary/20 hover:opacity-90 active:scale-[0.97] disabled:opacity-40 disabled:shadow-none transition-all"
>
Start Session
</button>
</div>
</div>
</div>
</div>
)
}