From 8088c39fd69243e9ca115018696cdd818b54080f Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Tue, 7 Apr 2026 20:02:48 +0700 Subject: [PATCH] Fix OpenCode usage regression and update workspace tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-add usage stamping on turn_completed events for OpenCode agents — the extractAndResetUsage callsite was removed during context window meter work, causing token counts and cost to be lost after each turn. Update workspace tests to account for the new async reconciliation that fires after workspace update fanout. --- .../src/server/agent/providers/opencode-agent.ts | 11 +++++++++++ .../src/server/session.workspace-git-watch.test.ts | 6 ++++-- packages/server/src/server/session.workspaces.test.ts | 10 ++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/packages/server/src/server/agent/providers/opencode-agent.ts b/packages/server/src/server/agent/providers/opencode-agent.ts index 7965c96f1..6f004d11f 100644 --- a/packages/server/src/server/agent/providers/opencode-agent.ts +++ b/packages/server/src/server/agent/providers/opencode-agent.ts @@ -2041,6 +2041,17 @@ class OpenCodeAgentSession implements AgentSession { if (translatedEvent.type === "permission_requested") { this.pendingPermissions.set(translatedEvent.request.id, translatedEvent.request); } + if (translatedEvent.type === "turn_completed") { + if (hasNormalizedOpenCodeUsage(this.accumulatedUsage)) { + translatedEvent.usage = this.accumulatedUsage; + } + const contextWindowMaxTokens = + this.resolveSelectedModelContextWindowMaxTokens(); + this.accumulatedUsage = + contextWindowMaxTokens !== undefined + ? { contextWindowMaxTokens } + : {}; + } } return translated; diff --git a/packages/server/src/server/session.workspace-git-watch.test.ts b/packages/server/src/server/session.workspace-git-watch.test.ts index 38c3a0290..db704bcd0 100644 --- a/packages/server/src/server/session.workspace-git-watch.test.ts +++ b/packages/server/src/server/session.workspace-git-watch.test.ts @@ -255,7 +255,8 @@ describe("workspace git watch targets", () => { diffStat: { additions: 1, deletions: 0 }, }; - sessionAny.listWorkspaceDescriptorsSnapshot = async () => [descriptor]; + sessionAny.buildWorkspaceDescriptorMap = async () => + new Map([[descriptor.id, descriptor]]); await sessionAny.ensureWorkspaceRegistered("/tmp/repo"); sessionAny.primeWorkspaceGitWatchFingerprints([descriptor]); @@ -477,7 +478,8 @@ describe("workspace git watch targets", () => { diffStat: { additions: 1, deletions: 0 }, }; - sessionAny.listWorkspaceDescriptorsSnapshot = async () => [descriptor]; + sessionAny.buildWorkspaceDescriptorMap = async () => + new Map([[descriptor.id, descriptor]]); await sessionAny.ensureWorkspaceRegistered("/tmp/repo"); sessionAny.primeWorkspaceGitWatchFingerprints([descriptor]); diff --git a/packages/server/src/server/session.workspaces.test.ts b/packages/server/src/server/session.workspaces.test.ts index 879ed0370..c054ca006 100644 --- a/packages/server/src/server/session.workspaces.test.ts +++ b/packages/server/src/server/session.workspaces.test.ts @@ -1127,15 +1127,21 @@ describe("workspace aggregation", () => { }; await session.emitWorkspaceUpdateForCwd("/tmp/repo/worktree"); + await new Promise((resolve) => setTimeout(resolve, 0)); const workspaceUpdates = emitted.filter( (message) => message.type === "workspace_update", ) as any[]; - expect(workspaceUpdates).toHaveLength(2); - expect(workspaceUpdates.map((entry) => entry.payload.kind)).toEqual(["upsert", "upsert"]); + expect(workspaceUpdates).toHaveLength(3); + expect(workspaceUpdates.map((entry) => entry.payload.kind)).toEqual([ + "upsert", + "upsert", + "upsert", + ]); expect(workspaceUpdates.map((entry) => entry.payload.workspace.id).sort()).toEqual([ "/tmp/repo", "/tmp/repo/worktree", + "/tmp/repo/worktree", ]); });