From 37bae9d7f6330c6e424d244e2eb2b619a37f5a6e Mon Sep 17 00:00:00 2001 From: Theo Browne Date: Fri, 25 Sep 2026 14:02:02 -0700 Subject: [PATCH] perf(server): stop keeping every Claude SDK message for live sessions ClaudeAdapter pushed every parent assistant message and every tool-result user message (subagent ones too) into the turn state, then copied them into context.turns until the session stopped. Nothing read them: readThread has no production caller, ProviderService discards the rollback snapshot, and rollback uses the native Claude history plus turnStartMessageIds. Keep only the turn ids, so readThread and rollbackThread still report the correct turn count. Same fix as #9684 for OpenCode. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../src/provider/Layers/ClaudeAdapter.ts | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/apps/server/src/provider/Layers/ClaudeAdapter.ts b/apps/server/src/provider/Layers/ClaudeAdapter.ts index 11a5322b4eee..a4dbfc6dddae 100644 --- a/apps/server/src/provider/Layers/ClaudeAdapter.ts +++ b/apps/server/src/provider/Layers/ClaudeAdapter.ts @@ -267,7 +267,6 @@ interface ClaudeTurnState { * steered instead (the queued message continues the same turn). */ readonly synthetic?: boolean; - readonly items: Array; readonly assistantTextBlocks: Map; readonly assistantTextBlockOrder: Array; readonly capturedProposedPlanKeys: Set; @@ -422,10 +421,8 @@ interface ClaudeSessionContext { resumeSessionId: string | undefined; readonly pendingApprovals: Map; readonly pendingUserInputs: Map; - readonly turns: Array<{ - id: TurnId; - items: Array; - }>; + /** Turn ids completed in this live session. The native Claude session file is the transcript. */ + readonly turns: Array<{ readonly id: TurnId }>; readonly inFlightTools: Map; readonly claudeTasks: Map; readonly taskAgents: Map; @@ -2176,10 +2173,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( } return { threadId, - turns: context.turns.map((turn) => ({ - id: turn.id, - items: [...turn.items], - })), + turns: context.turns.map((turn) => ({ id: turn.id, items: [] })), }; }); @@ -2808,10 +2802,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( }); } - context.turns.push({ - id: turnState.turnId, - items: [...turnState.items], - }); + context.turns.push({ id: turnState.turnId }); yield* emitThreadTokenUsage(context, usageSnapshot, { rawMethod: "claude/result", @@ -3175,10 +3166,6 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( return; } - if (context.turnState) { - context.turnState.items.push(message.message); - } - for (const toolResult of toolResultBlocksFromUserMessage(message)) { const toolEntry = Array.from(context.inFlightTools.entries()).find( ([, tool]) => tool.itemId === toolResult.toolUseId, @@ -3378,7 +3365,6 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( turnId, startedAt, synthetic: true, - items: [], assistantTextBlocks: new Map(), assistantTextBlockOrder: [], capturedProposedPlanKeys: new Set(), @@ -3461,7 +3447,6 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( cwd: path.resolve(context.session.cwd ?? "."), }); } - context.turnState.items.push(message.message); if ( normalizeClaudeActiveTokenUsage( message.message.usage, @@ -5205,7 +5190,6 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( const turnState: ClaudeTurnState = { turnId, startedAt: yield* nowIso, - items: [], assistantTextBlocks: new Map(), assistantTextBlockOrder: [], capturedProposedPlanKeys: new Set(),