fix(OBS-02): task badge immediately reflects final status from WS event
All checks were successful
Stuffle/nebula-os/pipeline/head This commit was not built

Root cause: taskStatus was only updated after tasksApi.get() resolved
(100-300ms after WS fires), so badge stayed 'running' during that gap.
Secondary bug: used task.status from the refetch which can be stale.

Fix:
- setPendingTaskIds and taskStatus flip happen synchronously on WS event
  receipt, before the API enrichment call — badge changes instantly
- tasksApi.get() still called to get content + tokenCost, but now
  uses finalStatus from WS type (not potentially-stale task.status)
- .catch() path removed redundant status override (already set above)
This commit is contained in:
2026-04-21 00:21:55 +05:30
parent d872254106
commit f47989c776

View File

@@ -1916,12 +1916,19 @@ export function ChatWorkspace() {
const taskId = msg.entity_id
if (!taskId || !pendingTaskIds.has(taskId)) return
if (msg.type === 'task.completed' || msg.type === 'task.failed') {
const finalStatus = msg.type === 'task.completed' ? 'completed' : 'failed'
// Immediately flip status from WS event — stops "Running…" badge without waiting for API
setPendingTaskIds(prev => { const n = new Set(prev); n.delete(taskId); return n })
setMessages(prev => prev.map(m =>
m.taskId === taskId ? { ...m, taskStatus: finalStatus } : m
))
// Enrich with full output + token cost once the API call resolves
tasksApi.get(taskId).then(task => {
setPendingTaskIds(prev => { const n = new Set(prev); n.delete(taskId); return n })
setMessages(prev => prev.map(m =>
m.taskId === taskId ? {
...m, content: extractOutput(task),
taskStatus: task.status,
...m,
content: extractOutput(task),
taskStatus: finalStatus, // use WS type, not potentially-stale task.status
tokenCost: task.token_usage?.cost_usd ?? undefined,
} : m
))
@@ -1929,7 +1936,7 @@ export function ChatWorkspace() {
qc.invalidateQueries({ queryKey: ['tasks'] })
}).catch(() => {
setMessages(prev => prev.map(m =>
m.taskId === taskId ? { ...m, taskStatus: msg.type === 'task.failed' ? 'failed' : 'completed', content: 'Could not fetch result.' } : m
m.taskId === taskId ? { ...m, content: 'Could not fetch result.' } : m
))
})
}