From 1dd93a3a18cc1bcf227b2b603fe429f00aac0fae Mon Sep 17 00:00:00 2001 From: saravmajestic Date: Tue, 26 May 2026 05:27:53 +0000 Subject: [PATCH 1/3] fix: [AI-6771] cancel() race condition and idle state on normal loop exit Fix B1: Remove premature SessionStatus.set(idle) from cancel() main path. On abort, the processor catch block publishes session.error then sets idle, preserving correct event ordering. The !match fallback still sets idle directly since no processor is running in that case. Fix B2: Add SessionStatus.set(idle) after the while loop exits normally so callers waiting on session.status:idle receive the event on clean completion. --- packages/opencode/src/session/prompt.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index ae8934e44..9e1648608 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -303,13 +303,15 @@ export namespace SessionPrompt { const s = state() const match = s[sessionID] if (!match) { + // Session already ended or was never started — set idle directly since no processor will do it await SessionStatus.set(sessionID, { type: "idle" }) return } match.abort.abort() delete s[sessionID] - await SessionStatus.set(sessionID, { type: "idle" }) - return + // Do NOT call SessionStatus.set(idle) here — on abort the processor's catch block + // publishes session.error THEN sets idle, preserving correct event ordering. + // On normal completion, loop() sets idle after the while loop exits. } // altimate_change end @@ -1110,6 +1112,11 @@ export namespace SessionPrompt { } continue } + // altimate_change start — set idle on normal loop exit; abort path is handled by processor catch block + if (!abort.aborted) { + await SessionStatus.set(sessionID, { type: "idle" }) + } + // altimate_change end SessionCompaction.prune({ sessionID }) // altimate_change start — session end telemetry const outcome = abort.aborted From 36b239085cbbd15b444dab077c6a4295e4373bb7 Mon Sep 17 00:00:00 2001 From: saravmajestic Date: Tue, 26 May 2026 08:19:15 +0000 Subject: [PATCH 2/3] feat: [AI-6771] add telemetry for streaming error scenarios Add Telemetry.track({ type: "error", context: "streaming" }) in the non-retry, non-overflow branch of the processor.ts streaming catch block. Covers: - MessageAbortedError (Stop button / dispose) - UnknownError (SSE chunk timeout after retry exhaustion) - APIError (provider failures after retry exhaustion) - AuthError and any other unhandled streaming error Event fields: session_id, error_name, error_message, context --- packages/opencode/src/session/processor.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/opencode/src/session/processor.ts b/packages/opencode/src/session/processor.ts index 98409b1a9..3db946da5 100644 --- a/packages/opencode/src/session/processor.ts +++ b/packages/opencode/src/session/processor.ts @@ -533,6 +533,18 @@ export namespace SessionProcessor { sessionID: input.assistantMessage.sessionID, error: input.assistantMessage.error, }) + // altimate_change start — telemetry for unhandled streaming errors (non-retry, non-overflow) + // Covers: MessageAbortedError (Stop/dispose), UnknownError (SSE chunk timeout), + // APIError (provider failures after retry exhaustion), AuthError, and any other streaming error. + Telemetry.track({ + type: "error", + timestamp: Date.now(), + session_id: input.assistantMessage.sessionID, + error_name: error.name, + error_message: (error.data as any)?.message ?? String((e as any)?.message ?? ""), + context: "streaming", + }) + // altimate_change end // altimate_change start — SessionStatus.set became async; await so idle state flushes before exit await SessionStatus.set(input.sessionID, { type: "idle" }) // altimate_change end From c829f2dabb94310f01fb980bcc2ede12fd75c981 Mon Sep 17 00:00:00 2001 From: "altimate-harness-bot[bot]" <274995457+altimate-harness-bot[bot]@users.noreply.github.com> Date: Wed, 27 May 2026 02:39:22 +0000 Subject: [PATCH 3/3] fix: reword cancel() comment to avoid false-positive in SessionStatus guard test --- packages/opencode/src/session/prompt.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 9e1648608..2db0d14c7 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -309,9 +309,9 @@ export namespace SessionPrompt { } match.abort.abort() delete s[sessionID] - // Do NOT call SessionStatus.set(idle) here — on abort the processor's catch block + // Do NOT set idle status here — on abort the processor's catch block // publishes session.error THEN sets idle, preserving correct event ordering. - // On normal completion, loop() sets idle after the while loop exits. + // On normal completion, loop() sets idle after the while loop exits (see below). } // altimate_change end