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) <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-03-28 21:44:04 +00:00
parent 4fa26149e6
commit 96602a6676
3 changed files with 16 additions and 4 deletions

View File

@@ -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,
)

View File

@@ -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<ParameterCandidate[]>([])
const [showStepper, setShowStepper] = useState(false)
const [detectionSummary, setDetectionSummary] = useState<string | null>(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,

View File

@@ -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([])
}
}, [])