session reliability: reconnect, knowledge loop, retire request_execution
Phase 1 — crash recovery: SSE auto-reconnect + backoff, polling gate during disconnect, connection banner with retry button, empty-response retry 3x, non-terminal resume on empty response, persistent error cards. Phase 2/4 — visibility + continuation: custom ExecutionStatus renderer, approvals extracted on every tool_result (not just done), activity bar with status/goal, SessionDigest live polling, Continue button. Phase 3 — cleanup: complete_task auto-cancels orphaned approvals, deletes assent/destructive window keys, propose_plan marks pending steps as replaced, plan step seq-order enforcement. Phase 5 — knowledge loop: list_lxcs state filter (active/destroyed), SOUL.md unmissable writeback section, propose_plan validation nudge, complete_task writeback check, upsert_knowledge about array support, plan generation grouping in frontend, session approval count badge. Retire request_execution — all mutations now route through run. Updated SOUL.md, AGENTS.md, CLIENTS.md, skills, and agent system notes. Migration 020: plan step generation column, audit_log session_id index, nomos_plan_executions pending-approval index.
This commit is contained in:
@@ -16,18 +16,27 @@
|
||||
// still refetch once outcome/summary land, not just on session switch.
|
||||
let loadedKey = $state<string | null>(null)
|
||||
|
||||
// Reload the digest whenever the session changes, the task's status changes
|
||||
// (e.g. it just completed), or a stream finishes — "what did this session
|
||||
// actually do" is only meaningful once executions have had a chance to land.
|
||||
let pollTimer: ReturnType<typeof setInterval> | null = $state(null)
|
||||
|
||||
$effect(() => {
|
||||
const sid = $currentSession
|
||||
const busy = $streaming
|
||||
const status = $currentTask?.status ?? ''
|
||||
if (!sid || busy) return
|
||||
const key = `${sid}:${status}`
|
||||
if (loadedKey === key) return
|
||||
loadedKey = key
|
||||
fetchSessionDigest(sid).then((d) => (digest = d))
|
||||
if (loadedKey !== key) {
|
||||
loadedKey = key
|
||||
fetchSessionDigest(sid).then((d) => (digest = d))
|
||||
}
|
||||
// Poll every 10s while the session is active.
|
||||
if (status !== 'done' && status !== 'failed') {
|
||||
if (!pollTimer) pollTimer = setInterval(() => fetchSessionDigest(sid).then((d) => (digest = d)), 10000)
|
||||
} else {
|
||||
if (pollTimer) { clearInterval(pollTimer); pollTimer = null }
|
||||
}
|
||||
return () => {
|
||||
if (pollTimer) { clearInterval(pollTimer); pollTimer = null }
|
||||
}
|
||||
})
|
||||
|
||||
function statusVariant(status: string): 'default' | 'secondary' | 'destructive' | 'outline' {
|
||||
|
||||
Reference in New Issue
Block a user