diff --git a/backend/app/services/unified_chat_service.py b/backend/app/services/unified_chat_service.py
index dcb9f670..7f966e5c 100644
--- a/backend/app/services/unified_chat_service.py
+++ b/backend/app/services/unified_chat_service.py
@@ -223,7 +223,7 @@ async def send_chat_message(
message: str,
db: AsyncSession,
images: list[dict[str, Any]] | None = None,
-) -> tuple[str, list[dict[str, Any]], AISession, dict[str, Any] | None, list[dict[str, Any]] | None, list[dict[str, Any]] | None]:
+) -> tuple[str, list[dict[str, Any]], AISession, dict[str, Any] | None, list[dict[str, Any]] | None, list[dict[str, Any]] | None, dict[str, Any] | None]:
"""Send a message in a chat session and get AI response.
Args:
diff --git a/frontend/src/components/assistant/FlowPilotAsks.tsx b/frontend/src/components/assistant/FlowPilotAsks.tsx
index 7042f4dd..c28af110 100644
--- a/frontend/src/components/assistant/FlowPilotAsks.tsx
+++ b/frontend/src/components/assistant/FlowPilotAsks.tsx
@@ -1,5 +1,5 @@
-import { useState } from 'react'
-import { Send, HelpCircle } from 'lucide-react'
+import { useState, useEffect } from 'react'
+import { Send, HelpCircle, ChevronLeft, ChevronRight } from 'lucide-react'
import type { QuestionItem } from '@/types/ai-session'
interface FlowPilotAsksProps {
@@ -10,11 +10,17 @@ interface FlowPilotAsksProps {
export function FlowPilotAsks({ questions, onAnswer, loading }: FlowPilotAsksProps) {
const [freeText, setFreeText] = useState('')
+ const [currentIdx, setCurrentIdx] = useState(0)
- // Show first unanswered question
- const question = questions.length > 0 ? questions[0] : null
+ // Reset index when questions change
+ useEffect(() => {
+ setCurrentIdx(0)
+ setFreeText('')
+ }, [questions])
- if (!question) return null
+ if (questions.length === 0) return null
+
+ const question = questions[Math.min(currentIdx, questions.length - 1)]
const handleFreeTextSubmit = () => {
if (!freeText.trim()) return
@@ -24,9 +30,32 @@ export function FlowPilotAsks({ questions, onAnswer, loading }: FlowPilotAsksPro
return (
-
-
- FlowPilot Asks
+
+
+
+ FlowPilot Asks
+
+ {questions.length > 1 && (
+
+
+
+ {currentIdx + 1}/{questions.length}
+
+
+
+ )}
{question.text}
diff --git a/frontend/src/components/assistant/IncidentHeader.tsx b/frontend/src/components/assistant/IncidentHeader.tsx
index aca4e1d7..4a84d2be 100644
--- a/frontend/src/components/assistant/IncidentHeader.tsx
+++ b/frontend/src/components/assistant/IncidentHeader.tsx
@@ -7,7 +7,6 @@ import type { TriageMeta } from '@/types/ai-session'
interface IncidentHeaderProps {
triageMeta: TriageMeta
psaTicketId: string | null
- sessionId: string
onFieldSave: (field: keyof TriageMeta, value: string) => void
onResolve: () => void
onPause?: () => void
@@ -97,7 +96,7 @@ function HeaderField({ label, value, placeholder, onSave, isHypothesis }: Header
)
}
-function OverflowMenu({ onPause, onClose, sessionId }: { onPause?: () => void; onClose?: () => void; sessionId: string }) {
+function OverflowMenu({ onPause, onClose }: { onPause?: () => void; onClose?: () => void }) {
const [open, setOpen] = useState(false)
const menuRef = useRef(null)
@@ -118,7 +117,7 @@ function OverflowMenu({ onPause, onClose, sessionId }: { onPause?: () => void; o
}, [open])
const handleCopyLink = () => {
- navigator.clipboard.writeText(`${window.location.origin}/assistant/${sessionId}`)
+ navigator.clipboard.writeText(`${window.location.origin}${window.location.pathname}`)
toast.success('Session link copied')
setOpen(false)
}
@@ -167,7 +166,6 @@ function OverflowMenu({ onPause, onClose, sessionId }: { onPause?: () => void; o
export function IncidentHeader({
triageMeta,
psaTicketId,
- sessionId,
onFieldSave,
onResolve,
onPause,
@@ -217,7 +215,7 @@ export function IncidentHeader({
>
Resolve
-
+
)
diff --git a/frontend/src/components/assistant/ViewToggle.tsx b/frontend/src/components/assistant/ViewToggle.tsx
index a0395547..f497891d 100644
--- a/frontend/src/components/assistant/ViewToggle.tsx
+++ b/frontend/src/components/assistant/ViewToggle.tsx
@@ -1,50 +1,69 @@
import { useNavigate } from 'react-router-dom'
+import { MessageSquare, LayoutDashboard } from 'lucide-react'
import { cn } from '@/lib/utils'
import { useFeatureFlag } from '@/hooks/useFeatureFlag'
+import { useUserPreferencesStore } from '@/store/userPreferencesStore'
+
+type FlowPilotView = 'flowpilot' | 'cockpit'
+
+const VIEW_OPTIONS: { key: FlowPilotView; label: string; icon: typeof MessageSquare; subtitle: string }[] = [
+ { key: 'flowpilot', label: 'FlowPilot', icon: MessageSquare, subtitle: 'Chat-first AI troubleshooting' },
+ { key: 'cockpit', label: 'Cockpit', icon: LayoutDashboard, subtitle: 'Steps, evidence & triage board' },
+]
interface ViewToggleProps {
- currentView: 'flowpilot' | 'cockpit'
- sessionId: string
+ /** Which view is currently active — drives highlight state */
+ currentView: FlowPilotView
+ /** Session ID for navigation (session pages only). Omit for preference-only mode (dashboard). */
+ sessionId?: string
+ /** Show the subtitle below the toggle. Default true for standalone, false for inline. */
+ showSubtitle?: boolean
}
-export function ViewToggle({ currentView, sessionId }: ViewToggleProps) {
+export function ViewToggle({ currentView, sessionId, showSubtitle = true }: ViewToggleProps) {
const navigate = useNavigate()
const hasCockpit = useFeatureFlag('flowpilot_cockpit')
+ const setPreferredView = useUserPreferencesStore(s => s.setPreferredFlowPilotView)
if (!hasCockpit) return null
- const handleSwitch = (view: 'flowpilot' | 'cockpit') => {
+ const activeOption = VIEW_OPTIONS.find(o => o.key === currentView) ?? VIEW_OPTIONS[0]
+
+ const handleSwitch = (view: FlowPilotView) => {
if (view === currentView) return
- const path = view === 'cockpit'
- ? `/cockpit/${sessionId}`
- : `/assistant/${sessionId}`
- navigate(path)
+ setPreferredView(view)
+ if (sessionId) {
+ const path = view === 'cockpit'
+ ? `/cockpit/${sessionId}`
+ : `/assistant/${sessionId}`
+ navigate(path)
+ }
}
return (
-
-
-
+
+
+ {VIEW_OPTIONS.map(({ key, label, icon: Icon }) => (
+
+ ))}
+
+ {showSubtitle && (
+
+ {activeOption.subtitle}
+
+ )}
)
}
diff --git a/frontend/src/components/dashboard/StartSessionInput.tsx b/frontend/src/components/dashboard/StartSessionInput.tsx
index f93175ac..919e3e7b 100644
--- a/frontend/src/components/dashboard/StartSessionInput.tsx
+++ b/frontend/src/components/dashboard/StartSessionInput.tsx
@@ -29,7 +29,6 @@ export function StartSessionInput() {
const navigate = useNavigate()
const hasCockpit = useFeatureFlag('flowpilot_cockpit')
const preferredView = useUserPreferencesStore(s => s.preferredFlowPilotView)
- const setPreferredView = useUserPreferencesStore(s => s.setPreferredFlowPilotView)
const textareaRef = useRef
(null)
const fileInputRef = useRef(null)
const dragCounterRef = useRef(0)
@@ -326,36 +325,6 @@ export function StartSessionInput() {
)}
- {/* View preference toggle */}
- {hasCockpit && (
-
-
-
-
- )}
-
{/* Send button */}
+ {session.activeChatId && (
+
+ )}