feat: AI marker system prompt fixes, TaskLane activation, and FlowPilot updates

- Fix system prompt to ensure [QUESTIONS]/[ACTIONS] markers in AI responses
- Add format reminder injection to user messages for marker compliance
- Wire TaskLane activation in prefill and resume paths
- Add ActionCardGroup component for structured question/action rendering
- Update FlowPilot session and step card components
- Update ai-session schemas and types for marker data

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-03-26 19:57:39 +00:00
parent 37d217b12a
commit 3c0a29115c
14 changed files with 913 additions and 42 deletions

View File

@@ -10,6 +10,7 @@ import type {
StatusUpdateContext,
StatusUpdateResponse,
} from '@/types/ai-session'
import type { BranchResponse } from '@/types/branching'
import { ConfidenceIndicator } from './ConfidenceIndicator'
import { FlowPilotStepCard } from './FlowPilotStepCard'
import { FlowPilotMessageBar } from './FlowPilotMessageBar'
@@ -17,6 +18,8 @@ import { SessionDocView } from './SessionDocView'
import { StatusUpdateModal } from './StatusUpdateModal'
import { SessionTicketCard } from './SessionTicketCard'
import { SimilarSessions } from './SimilarSessions'
import { BranchMap } from '@/components/session/BranchMap'
import { BranchTransitionBar } from '@/components/session/BranchTransitionBar'
import { TicketPickerModal } from '@/components/session/TicketPickerModal'
import { aiSessionsApi } from '@/api'
import { toast } from '@/lib/toast'
@@ -36,6 +39,10 @@ interface FlowPilotSessionProps {
onRate: (rating: number) => void
onReloadSession?: () => Promise<void>
onGenerateStatusUpdate?: (audience: StatusUpdateAudience, length: StatusUpdateLength, context: StatusUpdateContext) => Promise<StatusUpdateResponse>
// Branching props (optional — only present for branching sessions)
branches?: BranchResponse[]
activeBranchId?: string | null
onBranchSwitch?: (branchId: string) => void
}
export function FlowPilotSession({
@@ -52,12 +59,34 @@ export function FlowPilotSession({
onRate,
onReloadSession,
onGenerateStatusUpdate,
branches,
activeBranchId,
onBranchSwitch,
}: FlowPilotSessionProps) {
const scrollRef = useRef<HTMLDivElement>(null)
const [showTicketPicker, setShowTicketPicker] = useState(false)
const [linkingTicket, setLinkingTicket] = useState(false)
const [showShareCommunication, setShowShareCommunication] = useState(false)
const [showMobileSidebar, setShowMobileSidebar] = useState(false)
const prevBranchIdRef = useRef<string | null>(null)
const [branchTransition, setBranchTransition] = useState<{
from: BranchResponse | null
to: BranchResponse
} | null>(null)
// Track branch switches and show transition bar
useEffect(() => {
if (!activeBranchId || !branches?.length) return
const prev = prevBranchIdRef.current
if (prev && prev !== activeBranchId) {
const fromBranch = branches.find(b => b.id === prev) ?? null
const toBranch = branches.find(b => b.id === activeBranchId)
if (toBranch) {
setBranchTransition({ from: fromBranch, to: toBranch })
}
}
prevBranchIdRef.current = activeBranchId
}, [activeBranchId, branches])
const handleLinkTicket = async (ticketId: string, _ticket: PSATicketInfo) => {
if (!session.psa_connection_id && !session.ticket_data) {
@@ -218,6 +247,14 @@ export function FlowPilotSession({
{/* Conversation column — pb-24 provides clearance for the fixed message bar */}
<div ref={scrollRef} className="flex-1 overflow-y-auto p-3 pb-24 sm:p-4 sm:pb-24 lg:p-6 lg:pb-24">
<div className="mx-auto max-w-2xl space-y-3">
{/* Branch transition bar */}
{branchTransition && (
<BranchTransitionBar
fromBranch={branchTransition.from}
toBranch={branchTransition.to}
/>
)}
{allSteps.map((step) => (
<FlowPilotStepCard
key={step.step_id}
@@ -226,6 +263,8 @@ export function FlowPilotSession({
isProcessing={isProcessing && currentStep?.step_id === step.step_id}
sessionId={session.id}
onRespond={onRespond}
onBranchSwitch={onBranchSwitch}
activeBranchId={activeBranchId}
/>
))}
</div>
@@ -236,6 +275,15 @@ export function FlowPilotSession({
className="hidden w-72 shrink-0 overflow-y-auto border-l border-border p-4 lg:block"
>
<div className="space-y-4">
{/* Branch map (branching sessions only) */}
{session.is_branching && branches && branches.length > 0 && onBranchSwitch && (
<BranchMap
branches={branches}
activeBranchId={activeBranchId ?? null}
onSelectBranch={onBranchSwitch}
/>
)}
{/* Ticket context */}
{session.psa_ticket_id ? (
<SessionTicketCard