Skip to content

Commit ab5445a

Browse files
committed
fix(context): use normalized prompt size for usage meter
Upgrade the Qoder Agent SDK to 1.0.51 so the runtime can provide authoritative context usage. Keep the stream fallback accurate by treating input_tokens as the complete prompt size rather than adding cache detail fields that are already subsets.
1 parent cded85e commit ab5445a

6 files changed

Lines changed: 28 additions & 51 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ version with its date and start a fresh empty `[Unreleased]` above it.
1111

1212
## [Unreleased]
1313

14+
### Fixed
15+
16+
- The context usage meter no longer counts cached prompt tokens twice, so its
17+
percentage now reflects the actual occupied portion of the selected context
18+
window.
19+
1420
## [1.0.17] - 2026-10-10
1521

1622
### Changed

‎package-lock.json‎

Lines changed: 4 additions & 35 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
"@codemirror/state": "^6.5.0",
5757
"@codemirror/view": "^6.38.6",
5858
"@modelcontextprotocol/sdk": "~1.32.1",
59-
"@qoder-ai/qoder-agent-sdk": "^1.0.45",
59+
"@qoder-ai/qoder-agent-sdk": "^1.0.51",
6060
"tslib": "^2.8.1"
6161
},
6262
"overrides": {

‎src/core/types/chat.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,8 @@ export type StreamChunk =
165165
/**
166166
* Context window usage information.
167167
*
168-
* `contextTokens` is the Qoder-computed total token count in the context window:
169-
* `inputTokens + cacheCreationInputTokens + cacheReadInputTokens`.
168+
* `contextTokens` is the complete prompt size reported by Qoder. Cache creation
169+
* and cache read counts are subsets of `inputTokens`, not additional context.
170170
*
171171
* Cache token fields are optional for older Qoder CLI responses. Feature code
172172
* should use `contextTokens` for display, not recompute from the breakdown.

‎src/qoder/stream/transform-qoder-message.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,9 @@ function toPromptUsageSnapshot(usage: MessageUsage): PromptUsageSnapshot {
311311
inputTokens,
312312
cacheCreationInputTokens,
313313
cacheReadInputTokens,
314-
contextTokens: inputTokens + cacheCreationInputTokens + cacheReadInputTokens,
314+
// qodercli normalizes input_tokens to the complete prompt size. Cache read
315+
// and creation counts are subsets used for billing detail, not extra context.
316+
contextTokens: inputTokens,
315317
};
316318
}
317319

@@ -327,7 +329,7 @@ function mergePromptUsage(
327329
inputTokens,
328330
cacheCreationInputTokens,
329331
cacheReadInputTokens,
330-
contextTokens: inputTokens + cacheCreationInputTokens + cacheReadInputTokens,
332+
contextTokens: inputTokens,
331333
};
332334
}
333335

‎tests/unit/qoder/stream/transform-qoder-message.test.ts‎

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,17 +1522,17 @@ describe('transformSDKMessage', () => {
15221522
});
15231523

15241524
describe('assistant message usage extraction', () => {
1525-
it('yields usage info from main agent assistant message', () => {
1525+
it('does not double-count cache details toward context occupancy', () => {
15261526
const message = msg({
15271527
type: 'assistant',
15281528
parent_tool_use_id: null, // Main agent
15291529
message: {
15301530
content: [{ type: 'text', text: 'Hello' }],
15311531
usage: {
1532-
input_tokens: 1000,
1532+
input_tokens: 100_000,
15331533
output_tokens: 500,
1534-
cache_creation_input_tokens: 300,
1535-
cache_read_input_tokens: 200,
1534+
cache_creation_input_tokens: 10_000,
1535+
cache_read_input_tokens: 90_000,
15361536
},
15371537
},
15381538
});
@@ -1543,12 +1543,12 @@ describe('transformSDKMessage', () => {
15431543
expect(usageResults).toHaveLength(1);
15441544

15451545
const usage = (usageResults[0] as any).usage;
1546-
expect(usage.inputTokens).toBe(1000);
1547-
expect(usage.cacheCreationInputTokens).toBe(300);
1548-
expect(usage.cacheReadInputTokens).toBe(200);
1549-
expect(usage.contextTokens).toBe(1500); // 1000 + 300 + 200
1550-
expect(usage.contextWindow).toBe(200000); // Standard context window
1551-
expect(usage.percentage).toBe(1); // 1500 / 200000 * 100 rounded
1546+
expect(usage.inputTokens).toBe(100_000);
1547+
expect(usage.cacheCreationInputTokens).toBe(10_000);
1548+
expect(usage.cacheReadInputTokens).toBe(90_000);
1549+
expect(usage.contextTokens).toBe(100_000);
1550+
expect(usage.contextWindow).toBe(200_000);
1551+
expect(usage.percentage).toBe(50);
15521552
});
15531553

15541554
it('yields usage from assistant message when usage state has no stream prompt usage', () => {
@@ -1580,7 +1580,7 @@ describe('transformSDKMessage', () => {
15801580
cacheCreationInputTokens: 300,
15811581
cacheReadInputTokens: 200,
15821582
contextWindow: 200000,
1583-
contextTokens: 1500,
1583+
contextTokens: 1000,
15841584
percentage: 1,
15851585
});
15861586
});

0 commit comments

Comments
 (0)