From 96602a66769c04a7fc5e5fbe0baff684211d56cb Mon Sep 17 00:00:00 2001 From: chihlasm Date: Sat, 28 Mar 2026 21:44:04 +0000 Subject: [PATCH] fix: return pending_task_lane in session detail API response + debug logging _build_session_detail was omitting pending_task_lane, is_branching, and active_branch_id from the GET /ai-sessions/{id} response. The fields existed on the schema and model but were never passed in the manual constructor, so task lane state could never be restored on navigation. Also adds console logging to AssistantChatPage selectChat flow to diagnose message restoration, and fixes ScriptTemplateEditor stepper dismiss firing during programmatic script_body updates. Co-Authored-By: Claude Opus 4.6 (1M context) --- backend/app/api/endpoints/ai_sessions.py | 3 +++ .../components/script-editor/ScriptTemplateEditor.tsx | 10 +++++++--- frontend/src/pages/AssistantChatPage.tsx | 7 ++++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/backend/app/api/endpoints/ai_sessions.py b/backend/app/api/endpoints/ai_sessions.py index 4ffd7097..537737e6 100644 --- a/backend/app/api/endpoints/ai_sessions.py +++ b/backend/app/api/endpoints/ai_sessions.py @@ -117,6 +117,9 @@ def _build_session_detail(session: AISession) -> AISessionDetail: resolved_at=session.resolved_at, steps=step_responses, conversation_messages=session.conversation_messages or [], + pending_task_lane=session.pending_task_lane, + is_branching=getattr(session, 'is_branching', False), + active_branch_id=str(session.active_branch_id) if getattr(session, 'active_branch_id', None) else None, ) diff --git a/frontend/src/components/script-editor/ScriptTemplateEditor.tsx b/frontend/src/components/script-editor/ScriptTemplateEditor.tsx index 0b3a8671..d0e3228e 100644 --- a/frontend/src/components/script-editor/ScriptTemplateEditor.tsx +++ b/frontend/src/components/script-editor/ScriptTemplateEditor.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react' +import { useState, useEffect, useRef } from 'react' import { ArrowLeft, Loader2, Save, Scan, Trash2 } from 'lucide-react' import { Input } from '@/components/ui/Input' import { Textarea } from '@/components/ui/Textarea' @@ -64,16 +64,19 @@ export function ScriptTemplateEditor({ templateId, onBack, onSaved }: Props) { const [detectedCandidates, setDetectedCandidates] = useState([]) const [showStepper, setShowStepper] = useState(false) const [detectionSummary, setDetectionSummary] = useState(null) + const acceptingCandidateRef = useRef(false) const { canShareScriptTemplate } = usePermissions() - // Dismiss stepper if user edits the script body during detection + // Dismiss stepper if user manually edits the script body during detection + // (but NOT when handleAcceptCandidate programmatically updates script_body) const scriptBodyRef = form.script_body useEffect(() => { - if (showStepper) { + if (showStepper && !acceptingCandidateRef.current) { setShowStepper(false) setDetectedCandidates([]) } + acceptingCandidateRef.current = false // eslint-disable-next-line react-hooks/exhaustive-deps }, [scriptBodyRef]) @@ -263,6 +266,7 @@ export function ScriptTemplateEditor({ templateId, onBack, onSaved }: Props) { sensitive: overrides.sensitive, } + acceptingCandidateRef.current = true setForm(f => ({ ...f, script_body: updatedScript, diff --git a/frontend/src/pages/AssistantChatPage.tsx b/frontend/src/pages/AssistantChatPage.tsx index 3a95f680..30e20a2b 100644 --- a/frontend/src/pages/AssistantChatPage.tsx +++ b/frontend/src/pages/AssistantChatPage.tsx @@ -102,7 +102,9 @@ export default function AssistantChatPage() { // Restore session from sessionStorage on mount (when URL has no session ID) useEffect(() => { + console.log('[AssistantChat] Mount restore check — urlSessionId:', urlSessionId, 'activeChatId:', activeChatId) if (!urlSessionId && activeChatId) { + console.log('[AssistantChat] Calling selectChat to restore:', activeChatId) selectChat(activeChatId) } }, []) // eslint-disable-line react-hooks/exhaustive-deps @@ -207,6 +209,7 @@ export default function AssistantChatPage() { } const selectChat = useCallback(async (chatId: string) => { + console.log('[AssistantChat] selectChat called with:', chatId) setActiveChatId(chatId) // Clear TaskLane when switching chats — will restore from backend if available setShowTaskLane(false) @@ -214,6 +217,7 @@ export default function AssistantChatPage() { setActiveActions([]) try { const detail = await aiSessionsApi.getSession(chatId) + console.log('[AssistantChat] getSession response — messages:', detail.conversation_messages?.length, 'pending_task_lane:', !!detail.pending_task_lane) setMessages( (detail.conversation_messages || []).map(m => ({ role: m.role as 'user' | 'assistant', @@ -237,7 +241,8 @@ export default function AssistantChatPage() { } } } - } catch { + } catch (err) { + console.error('[AssistantChat] Failed to load chat session:', err) setMessages([]) } }, [])