From ef5f0c0ddafd58c73a1bf9c3c57c0566b8fc14f7 Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Sat, 26 Sep 2026 13:12:14 -0700 Subject: [PATCH] perf(server): Claude item ordinals no longer copy a session-wide map per item The Claude V2 adapter kept every item ordinal of the session in one Map that it copied on each new item and never pruned, so a long session paid O(items) memory and O(items^2) copying. Ordinals are only ever looked up by the turn that allocated them (a resumed subagent keeps its ordinal on the session subagent registry), so the map now lives on the turn context, is mutated in place, and goes away when the turn settles. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../Adapters/ClaudeAdapterV2.ts | 38 +++++++------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts b/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts index 26e71b5167e8..812998e5cc64 100644 --- a/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts +++ b/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts @@ -2479,6 +2479,10 @@ interface ActiveClaudeTurnContext { readonly providerTurnId: OrchestrationV2ProviderTurn["id"]; readonly providerTurnOrdinal: number; readonly startedAt: DateTime.Utc; + // Item ordinals allocated in this turn. Later turns never look items up + // here: a subagent resumed from another turn keeps its ordinal on the + // session subagent registry. + readonly itemOrdinals: Map; readonly assistant: { fallbackText: string; fallbackNativeItemId: string; @@ -2788,8 +2792,6 @@ export function makeClaudeAdapterV2( const steeredTurns = yield* Ref.make(new Set()); const queryContext = yield* Ref.make(null); const openedNativeThreads = yield* Ref.make(new Set()); - const itemOrdinals = yield* Ref.make(new Map()); - const nextItemOrdinalsByTurn = yield* Ref.make(new Map()); const latestPlanByKind = yield* Ref.make(new Map()); const planIdsByNativeItem = yield* Ref.make( new Map(), @@ -3284,29 +3286,16 @@ export function makeClaudeAdapterV2( }), }); - const resolveItemOrdinal = Effect.fnUntraced(function* ( - context: ActiveClaudeTurnContext, - nativeItemId: string, - ) { - const existing = (yield* Ref.get(itemOrdinals)).get(nativeItemId); - if (existing !== undefined) { - return existing; - } - - const nextWithinTurn = yield* Ref.modify(nextItemOrdinalsByTurn, (current) => { - const next = (current.get(context.nativeTurnId) ?? 0) + 1; - const updated = new Map(current); - updated.set(context.nativeTurnId, next); - return [next, updated]; - }); - const nextOrdinal = context.input.providerTurnOrdinal * 100 + nextWithinTurn; - yield* Ref.update(itemOrdinals, (current) => { - const updated = new Map(current); - updated.set(nativeItemId, nextOrdinal); - return updated; + const resolveItemOrdinal = (context: ActiveClaudeTurnContext, nativeItemId: string) => + Effect.sync(() => { + const existing = context.itemOrdinals.get(nativeItemId); + if (existing !== undefined) { + return existing; + } + const ordinal = context.input.providerTurnOrdinal * 100 + context.itemOrdinals.size + 1; + context.itemOrdinals.set(nativeItemId, ordinal); + return ordinal; }); - return nextOrdinal; - }); const providerTurnPayload = (input: { readonly context: ActiveClaudeTurnContext; @@ -6397,6 +6386,7 @@ export function makeClaudeAdapterV2( providerTurnId, providerTurnOrdinal, startedAt, + itemOrdinals: new Map(), assistant: { fallbackText: "", fallbackNativeItemId: `assistant:${turnInput.runId}`,