Thread and State Lifecycle
Thread and State Lifecycle
หัวข้อที่มีชื่อว่า “Thread and State Lifecycle”This page documents the actual runtime lifecycle implemented in kobi-ai chat hooks/components.
1. Thread Lifecycle States
หัวข้อที่มีชื่อว่า “1. Thread Lifecycle States”| State | Meaning | Main Code Path |
|---|---|---|
new | No materialized thread yet | ChatPane + useChatLifecycle |
pending_thread | Thread is pre-created for upload flow but not bound to UI state yet | ChatPane.ensureThread() |
thread_ready | Real UUID thread exists and is bound to current route/session | useChatSender + saveSession |
streaming | AI response is in progress | useChatSender, useChatActions.readResumeStream |
hitl_pending | AI proposed resumable actions waiting decision | ActionProposal, actionResumeGuards |
hitl_staged | Batch decision staged per action (staged_approved/staged_rejected) | useChatActions + hitlBatchState |
hitl_submitted | Batch submitted to /api/ai/resume (submitted) | useChatActions.handleBatchConfirm |
2. First Message Without Hard Refresh
หัวข้อที่มีชื่อว่า “2. First Message Without Hard Refresh”Current implementation supports pre-create + silent URL update:
sequenceDiagram
participant UI as ChatPane
participant BFF as /api/chat/threads
participant SENDER as useChatSender
participant ROUTER as Next router/history
alt file upload precreate
UI->>BFF: createThread()
BFF-->>UI: thread UUID
UI->>UI: keep in pendingThreadRef only
end
UI->>SENDER: sendMessage(threadId override optional)
alt no thread exists
SENDER->>BFF: createThread()
BFF-->>SENDER: thread UUID
end
SENDER->>ROUTER: navigate(..., { replace: true, silent: true })
SENDER->>UI: continue send/stream on same mounted pane
The silent route update uses window.history.replaceState to avoid remount jitter.
3. URL and Session Synchronization
หัวข้อที่มีชื่อว่า “3. URL and Session Synchronization”useChatLifecycle enforces these rules:
- If URL thread is
new, reset to clean local state. - If URL thread is UUID and differs from current state, load messages for that thread.
- If a UUID thread is not found, clear saved session and redirect to base route.
- Quick chat empty-thread URL is treated as invalid and redirected to base route.
- Project/team mode can treat empty thread as valid (when team-scoped context is provided).
- Saved session restoration can rewrite URL when no explicit URL thread is present.
4. BFF Thread Requirements
หัวข้อที่มีชื่อว่า “4. BFF Thread Requirements”/api/ai/* proxy path requires materialized thread context:
- Canonical field:
threadId - Deprecated alias accepted:
sessionId - Mismatched
threadId/sessionIdreturns400 - Missing/
newthread returns400(“Thread ID is required. Create thread via /api/chat/threads first”)
There is no server-side auto-generation fallback in the BFF proxy path.
5. HITL Batch Lifecycle
หัวข้อที่มีชื่อว่า “5. HITL Batch Lifecycle”Batch flow is dynamic, not fixed-size:
- Collect pending resumable actions for one message (
collectHitlBatchCandidates). - Stage per-action decision (
staged_approvedorstaged_rejected). - Allow undo/reset before submit.
- Submit one
/api/ai/resumecall withdecisions[]. - Set temporary
submitted, then finalize toapproved/rejectedafter response.
Because mapping is by toolCallId/tool_call_id, batch size can be N=1..k depending on model output.
6. Resume and Non-UUID Message IDs
หัวข้อที่มีชื่อว่า “6. Resume and Non-UUID Message IDs”ActionContext avoids DB fetch for temporary client-only message IDs:
- If
messageIdis UUID-like, it may fetch from DB. - If
messageIdis not UUID-like, it uses local message context directly.
This avoids invalid UUID errors like:
invalid input syntax for type uuid: "resume-bot-..."
7. Canvas Refresh After Decisions
หัวข้อที่มีชื่อว่า “7. Canvas Refresh After Decisions”After successful resume:
- Strategy mode triggers
useStrategyStore.loadItemsByThreadimmediately and with delayed retry. - Other modes trigger canvas refresh callback twice (immediate + delayed retry).
This double refresh is intentional to smooth eventual consistency between stream completion and persisted mutations.
8. Practical Guardrails
หัวข้อที่มีชื่อว่า “8. Practical Guardrails”- Never assume one interrupt equals one action; handle
decisions[]arrays. - Keep action->tool_call_id mapping stable when mutating message action lists.
- Prefer staged UI states over immediate destructive state changes for better recovery and undo behavior.