fix: resolve task lane stale state, partial submit, and closure bugs #125

Merged
chihlasm merged 4 commits from fix/task-lane-partial-submit into main 2026-04-06 20:31:41 +00:00
Showing only changes of commit 990f04489f - Show all commits

View File

@@ -259,6 +259,11 @@ export default function AssistantChatPage() {
}, []) }, [])
const handleNewChat = async () => { const handleNewChat = async () => {
// Clear stale state immediately — don't wait for API to return
setShowTaskLane(false)
setActiveQuestions([])
setActiveActions([])
setMessages([])
try { try {
const session = await aiSessionsApi.createChatSession({ const session = await aiSessionsApi.createChatSession({
intake_type: 'free_text', intake_type: 'free_text',
@@ -275,11 +280,6 @@ export default function AssistantChatPage() {
currentChatRef.current = session.session_id currentChatRef.current = session.session_id
setChats(prev => [chatItem, ...prev]) setChats(prev => [chatItem, ...prev])
setActiveChatId(session.session_id) setActiveChatId(session.session_id)
setMessages([])
// Clear TaskLane from previous session
setShowTaskLane(false)
setActiveQuestions([])
setActiveActions([])
} catch { } catch {
toast.error('Failed to create chat') toast.error('Failed to create chat')
} }
@@ -315,11 +315,14 @@ export default function AssistantChatPage() {
setMessages(prev => [...prev, { role: 'user', content: userMessage }]) setMessages(prev => [...prev, { role: 'user', content: userMessage }])
setLoading(true) setLoading(true)
const sentForChatId = activeChatId
try { try {
const response = await aiSessionsApi.sendChatMessage(activeChatId, { const response = await aiSessionsApi.sendChatMessage(activeChatId, {
message: userMessage, message: userMessage,
upload_ids: completedUploadIds.length > 0 ? completedUploadIds : undefined, upload_ids: completedUploadIds.length > 0 ? completedUploadIds : undefined,
}) })
// Guard: discard if user switched to a different chat while this was in flight
if (currentChatRef.current !== sentForChatId) return
analytics.aiFeatureUsed({ feature: 'assistant_chat' }) analytics.aiFeatureUsed({ feature: 'assistant_chat' })
setMessages(prev => [ setMessages(prev => [
...prev, ...prev,
@@ -327,20 +330,20 @@ export default function AssistantChatPage() {
]) ])
setChats(prev => setChats(prev =>
prev.map(c => prev.map(c =>
c.id === activeChatId c.id === sentForChatId
? { ...c, message_count: c.message_count + 2, title: c.message_count === 0 ? userMessage.slice(0, 100) : c.title, updated_at: new Date().toISOString() } ? { ...c, message_count: c.message_count + 2, title: c.message_count === 0 ? userMessage.slice(0, 100) : c.title, updated_at: new Date().toISOString() }
: c : c
) )
) )
// Load branches if fork was created // Load branches if fork was created
if (response.fork && activeChatId) { if (response.fork && sentForChatId) {
branching.loadBranches(activeChatId) branching.loadBranches(sentForChatId)
} }
// Show task lane if AI sent questions or actions // Show task lane if AI sent questions or actions
const hasQuestions = response.questions && response.questions.length > 0 const hasQuestions = response.questions && response.questions.length > 0
const hasActions = response.actions && response.actions.length > 0 const hasActions = response.actions && response.actions.length > 0
if (hasQuestions || hasActions) { if (hasQuestions || hasActions) {
if (activeChatId) clearTaskState(activeChatId) clearTaskState(sentForChatId)
setActiveQuestions(response.questions || []) setActiveQuestions(response.questions || [])
setActiveActions(response.actions || []) setActiveActions(response.actions || [])
setShowTaskLane(true) setShowTaskLane(true)
@@ -377,19 +380,22 @@ export default function AssistantChatPage() {
setMessages(prev => [...prev, { role: 'user', content: userMessage }]) setMessages(prev => [...prev, { role: 'user', content: userMessage }])
setLoading(true) setLoading(true)
const sentForChatId = activeChatId
try { try {
const response = await aiSessionsApi.sendChatMessage(activeChatId, { message: userMessage }) const response = await aiSessionsApi.sendChatMessage(activeChatId, { message: userMessage })
// Guard: discard if user switched to a different chat while this was in flight
if (currentChatRef.current !== sentForChatId) return
setMessages(prev => [ setMessages(prev => [
...prev, ...prev,
{ role: 'assistant', content: response.content, suggestedFlows: response.suggested_flows, fork: response.fork, actions: response.actions, questions: response.questions }, { role: 'assistant', content: response.content, suggestedFlows: response.suggested_flows, fork: response.fork, actions: response.actions, questions: response.questions },
]) ])
if (response.fork && activeChatId) { if (response.fork && sentForChatId) {
branching.loadBranches(activeChatId) branching.loadBranches(sentForChatId)
} }
// Update task lane based on AI response // Update task lane based on AI response
const hasQuestions = response.questions && response.questions.length > 0 const hasQuestions = response.questions && response.questions.length > 0
const hasActions = response.actions && response.actions.length > 0 const hasActions = response.actions && response.actions.length > 0
if (activeChatId) clearTaskState(activeChatId) clearTaskState(sentForChatId)
if (hasQuestions || hasActions) { if (hasQuestions || hasActions) {
setActiveQuestions(response.questions || []) setActiveQuestions(response.questions || [])
setActiveActions(response.actions || []) setActiveActions(response.actions || [])
@@ -430,6 +436,10 @@ export default function AssistantChatPage() {
} }
const handleResumeNew = async (summary: string) => { const handleResumeNew = async (summary: string) => {
// Clear stale state immediately — don't wait for API to return
setShowTaskLane(false)
setActiveQuestions([])
setActiveActions([])
try { try {
const resumePrompt = `I'm continuing a previous troubleshooting session. Here's where we left off:\n\n${summary}\n\nPlease review this context and help me continue from where we stopped.` const resumePrompt = `I'm continuing a previous troubleshooting session. Here's where we left off:\n\n${summary}\n\nPlease review this context and help me continue from where we stopped.`
const session = await aiSessionsApi.createChatSession({ const session = await aiSessionsApi.createChatSession({