| ... | @@ -14,7 +14,6 @@ import { | ... | @@ -14,7 +14,6 @@ import { |
| 14 | type PermissionResult, | 14 | type PermissionResult, |
| 15 | type PermissionUpdate, | 15 | type PermissionUpdate, |
| 16 | type SDKMessage, | 16 | type SDKMessage, |
| 17 | type SDKControlGetContextUsageResponse, | | |
| 18 | type SDKResultMessage, | 17 | type SDKResultMessage, |
| 19 | type SettingSource, | 18 | type SettingSource, |
| 20 | type SDKUserMessage, | 19 | type SDKUserMessage, |
| ... | @@ -69,7 +68,6 @@ import * as Effect from "effect/Effect"; | ... | @@ -69,7 +68,6 @@ import * as Effect from "effect/Effect"; |
| 69 | import * as Exit from "effect/Exit"; | 68 | import * as Exit from "effect/Exit"; |
| 70 | import * as FileSystem from "effect/FileSystem"; | 69 | import * as FileSystem from "effect/FileSystem"; |
| 71 | import * as Fiber from "effect/Fiber"; | 70 | import * as Fiber from "effect/Fiber"; |
| 72 | import * as Option from "effect/Option"; | | |
| 73 | import * as Path from "effect/Path"; | 71 | import * as Path from "effect/Path"; |
| 74 | import * as Queue from "effect/Queue"; | 72 | import * as Queue from "effect/Queue"; |
| 75 | import * as Ref from "effect/Ref"; | 73 | import * as Ref from "effect/Ref"; |
| ... | @@ -145,6 +143,8 @@ interface ClaudeTurnState { | ... | @@ -145,6 +143,8 @@ interface ClaudeTurnState { |
| 145 | readonly assistantTextBlocks: Map<number, AssistantTextBlockState>; | 143 | readonly assistantTextBlocks: Map<number, AssistantTextBlockState>; |
| 146 | readonly assistantTextBlockOrder: Array<AssistantTextBlockState>; | 144 | readonly assistantTextBlockOrder: Array<AssistantTextBlockState>; |
| 147 | readonly capturedProposedPlanKeys: Set<string>; | 145 | readonly capturedProposedPlanKeys: Set<string>; |
| | 146 | latestAssistantUsage: unknown | undefined; |
| | 147 | compactedSinceLatestAssistantUsage: boolean; |
| 148 | nextSyntheticAssistantBlockIndex: number; | 148 | nextSyntheticAssistantBlockIndex: number; |
| 149 | } | 149 | } |
| 150 | | 150 | |
| ... | @@ -321,7 +321,6 @@ interface ClaudeQueryRuntime extends AsyncIterable<SDKMessage> { | ... | @@ -321,7 +321,6 @@ interface ClaudeQueryRuntime extends AsyncIterable<SDKMessage> { |
| 321 | readonly setModel: (model?: string) => Promise<void>; | 321 | readonly setModel: (model?: string) => Promise<void>; |
| 322 | readonly setPermissionMode: (mode: PermissionMode) => Promise<void>; | 322 | readonly setPermissionMode: (mode: PermissionMode) => Promise<void>; |
| 323 | readonly setMaxThinkingTokens: (maxThinkingTokens: number | null) => Promise<void>; | 323 | readonly setMaxThinkingTokens: (maxThinkingTokens: number | null) => Promise<void>; |
| 324 | readonly getContextUsage?: () => Promise<SDKControlGetContextUsageResponse>; | | |
| 325 | readonly close: () => void; | 324 | readonly close: () => void; |
| 326 | } | 325 | } |
| 327 | | 326 | |
| ... | @@ -608,20 +607,6 @@ function normalizeClaudeActiveTokenUsage( | ... | @@ -608,20 +607,6 @@ function normalizeClaudeActiveTokenUsage( |
| 608 | }); | 607 | }); |
| 609 | } | 608 | } |
| 610 | | 609 | |
| 611 | function normalizeClaudeContextUsageApiSnapshot( | | |
| 612 | value: SDKControlGetContextUsageResponse, | | |
| 613 | totalProcessedTokens?: number, | | |
| 614 | ): ThreadTokenUsageSnapshot | undefined { | | |
| 615 | const autoCompactThreshold = finitePositiveInteger(value.autoCompactThreshold); | | |
| 616 | return makeClaudeTokenUsageSnapshot({ | | |
| 617 | activeTokens: value.totalTokens, | | |
| 618 | contextWindow: value.maxTokens, | | |
| 619 | ...(totalProcessedTokens !== undefined ? { totalProcessedTokens } : {}), | | |
| 620 | compactsAutomatically: value.isAutoCompactEnabled, | | |
| 621 | ...(autoCompactThreshold !== undefined ? { autoCompactThreshold } : {}), | | |
| 622 | }); | | |
| 623 | } | | |
| 624 | | | |
| 625 | function compactBoundaryTokenUsageSnapshot( | 610 | function compactBoundaryTokenUsageSnapshot( |
| 626 | message: Record<string, unknown>, | 611 | message: Record<string, unknown>, |
| 627 | contextWindow?: number, | 612 | contextWindow?: number, |
| ... | @@ -2133,29 +2118,6 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -2133,29 +2118,6 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 2133 | }); | 2118 | }); |
| 2134 | }); | 2119 | }); |
| 2135 | | 2120 | |
| 2136 | const queryCurrentContextUsage = Effect.fn("queryCurrentContextUsage")(function* ( | | |
| 2137 | context: ClaudeSessionContext, | | |
| 2138 | totalProcessedTokens?: number, | | |
| 2139 | ) { | | |
| 2140 | if (!context.query.getContextUsage) { | | |
| 2141 | return undefined; | | |
| 2142 | } | | |
| 2143 | | | |
| 2144 | const usage = yield* Effect.promise(async () => { | | |
| 2145 | try { | | |
| 2146 | return await context.query.getContextUsage?.(); | | |
| 2147 | } catch { | | |
| 2148 | return undefined; | | |
| 2149 | } | | |
| 2150 | }).pipe(Effect.timeoutOption("1 second")); | | |
| 2151 | if (Option.isNone(usage) || !usage.value) { | | |
| 2152 | return undefined; | | |
| 2153 | } | | |
| 2154 | | | |
| 2155 | context.lastKnownContextWindow = usage.value.maxTokens; | | |
| 2156 | return normalizeClaudeContextUsageApiSnapshot(usage.value, totalProcessedTokens); | | |
| 2157 | }); | | |
| 2158 | | | |
| 2159 | const emitProposedPlanCompleted = Effect.fn("emitProposedPlanCompleted")(function* ( | 2121 | const emitProposedPlanCompleted = Effect.fn("emitProposedPlanCompleted")(function* ( |
| 2160 | context: ClaudeSessionContext, | 2122 | context: ClaudeSessionContext, |
| 2161 | input: { | 2123 | input: { |
| ... | @@ -2256,10 +2218,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -2256,10 +2218,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 2256 | context.lastKnownTotalProcessedTokens = accumulatedTotalProcessedTokens; | 2218 | context.lastKnownTotalProcessedTokens = accumulatedTotalProcessedTokens; |
| 2257 | } | 2219 | } |
| 2258 | | 2220 | |
| 2259 | const contextUsageSnapshot = yield* queryCurrentContextUsage( | 2221 | // Avoid getContextUsage because its token-count fallback can make extra model requests. |
| 2260 | context, | | |
| 2261 | accumulatedTotalProcessedTokens ?? context.lastKnownTotalProcessedTokens, | | |
| 2262 | ); | | |
| 2263 | const resultUsageRecord = | 2222 | const resultUsageRecord = |
| 2264 | result?.usage && typeof result.usage === "object" && !Array.isArray(result.usage) | 2223 | result?.usage && typeof result.usage === "object" && !Array.isArray(result.usage) |
| 2265 | ? (result.usage as Record<string, unknown>) | 2224 | ? (result.usage as Record<string, unknown>) |
| ... | @@ -2281,24 +2240,31 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -2281,24 +2240,31 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 2281 | accumulatedTotalProcessedTokens ?? context.lastKnownTotalProcessedTokens, | 2240 | accumulatedTotalProcessedTokens ?? context.lastKnownTotalProcessedTokens, |
| 2282 | ) | 2241 | ) |
| 2283 | : undefined; | 2242 | : undefined; |
| | 2243 | const latestAssistantSnapshot = normalizeClaudeActiveTokenUsage( |
| | 2244 | context.turnState?.latestAssistantUsage, |
| | 2245 | maxTokens, |
| | 2246 | accumulatedTotalProcessedTokens ?? context.lastKnownTotalProcessedTokens, |
| | 2247 | ); |
| 2284 | const lastGoodUsage = context.lastKnownTokenUsage; | 2248 | const lastGoodUsage = context.lastKnownTokenUsage; |
| 2285 | const usageSnapshot: ThreadTokenUsageSnapshot | undefined = | 2249 | const usageSnapshot: ThreadTokenUsageSnapshot | undefined = |
| 2286 | contextUsageSnapshot ?? | 2250 | latestAssistantSnapshot ?? |
| 2287 | (resultTotalOnly && lastGoodUsage | 2251 | (context.turnState?.compactedSinceLatestAssistantUsage |
| 2288 | ? { | 2252 | ? undefined |
| 2289 | ...lastGoodUsage, | 2253 | : resultTotalOnly && lastGoodUsage |
| 2290 | ...(typeof maxTokens === "number" && Number.isFinite(maxTokens) && maxTokens > 0 | 2254 | ? { |
| 2291 | ? { maxTokens } | 2255 | ...lastGoodUsage, |
| 2292 | : {}), | 2256 | ...(typeof maxTokens === "number" && Number.isFinite(maxTokens) && maxTokens > 0 |
| 2293 | ...(typeof accumulatedTotalProcessedTokens === "number" && | 2257 | ? { maxTokens } |
| 2294 | Number.isFinite(accumulatedTotalProcessedTokens) && | 2258 | : {}), |
| 2295 | accumulatedTotalProcessedTokens > lastGoodUsage.usedTokens | 2259 | ...(typeof accumulatedTotalProcessedTokens === "number" && |
| 2296 | ? { | 2260 | Number.isFinite(accumulatedTotalProcessedTokens) && |
| 2297 | totalProcessedTokens: accumulatedTotalProcessedTokens, | 2261 | accumulatedTotalProcessedTokens > lastGoodUsage.usedTokens |
| 2298 | } | 2262 | ? { |
| 2299 | : {}), | 2263 | totalProcessedTokens: accumulatedTotalProcessedTokens, |
| 2300 | } | 2264 | } |
| 2301 | : resultIterationSnapshot) ?? | 2265 | : {}), |
| | 2266 | } |
| | 2267 | : resultIterationSnapshot) ?? |
| 2302 | (lastGoodUsage | 2268 | (lastGoodUsage |
| 2303 | ? { | 2269 | ? { |
| 2304 | ...lastGoodUsage, | 2270 | ...lastGoodUsage, |
| ... | @@ -2950,6 +2916,8 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -2950,6 +2916,8 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 2950 | assistantTextBlocks: new Map(), | 2916 | assistantTextBlocks: new Map(), |
| 2951 | assistantTextBlockOrder: [], | 2917 | assistantTextBlockOrder: [], |
| 2952 | capturedProposedPlanKeys: new Set(), | 2918 | capturedProposedPlanKeys: new Set(), |
| | 2919 | latestAssistantUsage: undefined, |
| | 2920 | compactedSinceLatestAssistantUsage: false, |
| 2953 | nextSyntheticAssistantBlockIndex: -1, | 2921 | nextSyntheticAssistantBlockIndex: -1, |
| 2954 | }; | 2922 | }; |
| 2955 | context.session = { | 2923 | context.session = { |
| ... | @@ -3010,6 +2978,16 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -3010,6 +2978,16 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 3010 | | 2978 | |
| 3011 | if (context.turnState) { | 2979 | if (context.turnState) { |
| 3012 | context.turnState.items.push(message.message); | 2980 | context.turnState.items.push(message.message); |
| | 2981 | if ( |
| | 2982 | normalizeClaudeActiveTokenUsage( |
| | 2983 | message.message.usage, |
| | 2984 | context.lastKnownContextWindow, |
| | 2985 | context.lastKnownTotalProcessedTokens, |
| | 2986 | ) |
| | 2987 | ) { |
| | 2988 | context.turnState.latestAssistantUsage = message.message.usage; |
| | 2989 | context.turnState.compactedSinceLatestAssistantUsage = false; |
| | 2990 | } |
| 3013 | yield* backfillAssistantTextBlocksFromSnapshot(context, message); | 2991 | yield* backfillAssistantTextBlocksFromSnapshot(context, message); |
| 3014 | } | 2992 | } |
| 3015 | | 2993 | |
| ... | @@ -3174,6 +3152,10 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -3174,6 +3152,10 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 3174 | }); | 3152 | }); |
| 3175 | return; | 3153 | return; |
| 3176 | case "compact_boundary": | 3154 | case "compact_boundary": |
| | 3155 | if (context.turnState) { |
| | 3156 | context.turnState.latestAssistantUsage = undefined; |
| | 3157 | context.turnState.compactedSinceLatestAssistantUsage = true; |
| | 3158 | } |
| 3177 | yield* emitThreadTokenUsage( | 3159 | yield* emitThreadTokenUsage( |
| 3178 | context, | 3160 | context, |
| 3179 | compactBoundaryTokenUsageSnapshot( | 3161 | compactBoundaryTokenUsageSnapshot( |
| ... | @@ -4576,6 +4558,8 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -4576,6 +4558,8 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 4576 | assistantTextBlocks: new Map(), | 4558 | assistantTextBlocks: new Map(), |
| 4577 | assistantTextBlockOrder: [], | 4559 | assistantTextBlockOrder: [], |
| 4578 | capturedProposedPlanKeys: new Set(), | 4560 | capturedProposedPlanKeys: new Set(), |
| | 4561 | latestAssistantUsage: undefined, |
| | 4562 | compactedSinceLatestAssistantUsage: false, |
| 4579 | nextSyntheticAssistantBlockIndex: -1, | 4563 | nextSyntheticAssistantBlockIndex: -1, |
| 4580 | }; | 4564 | }; |
| 4581 | | 4565 | |