Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions packages/cli/src/ui/commands/contextCommand.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1097,6 +1097,23 @@ describe('collectContextData (contextCommand)', () => {
).toBeGreaterThan(estimateContextTextTokens(JSON.stringify(declared)));
expect(data.breakdown.messages).toBe(300);
expect(sumRows(data.breakdown)).toBe(total);

// `/context detail` lists the MCP tools under the mcp row, so they must
// add up to it on both paths.
const mcpDetailSum = (
item: Awaited<ReturnType<typeof collectContextData>>,
) => item.mcpTools.reduce((sum, tool) => sum + tool.tokens, 0);
for (const options of [
{ total: 0, tools, declared, history },
{ total: 0, tools, declared: [], history },
{ total, tools, declared, history },
]) {
const detailed = await collectContextData(
makeChatConfig(options),
true,
);
expect(mcpDetailSum(detailed)).toBe(detailed.breakdown.mcpTools);
}
});

it('bills a path-activation envelope folded into a tool response as messages (#12235)', async () => {
Expand Down
29 changes: 17 additions & 12 deletions packages/cli/src/ui/commands/contextCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,19 @@ export async function collectContextData(
0,
allToolsTokens - skillToolDefinitionTokens - clampedMcpTools,
);
// The MCP detail rows sit under the mcp row, so they carry its deficit too.
const mcpDetailShare =
mcpToolsTotalTokens > 0 ? clampedMcpTools / mcpToolsTotalTokens : 1;
const scaleTokens = <T extends { tokens: number }>(
items: T[],
factor: number,
): T[] =>
factor < 1
? items.map((item) => ({
...item,
tokens: Math.round(item.tokens * factor),
}))
: items;

if (!hasTokenCount) {
totalTokens = 0;
Expand All @@ -650,7 +663,7 @@ export async function collectContextData(
messagesTokens = conversationTokens;
freeSpace = Math.max(0, contextWindowSize - rawContent - autocompactBuffer);
detailBuiltinTools = builtinTools;
detailMcpTools = mcpTools;
detailMcpTools = scaleTokens(mcpTools, mcpDetailShare);
detailMemoryFiles = memoryFiles;
detailSkills = skills;
} else {
Expand Down Expand Up @@ -717,17 +730,9 @@ export async function collectContextData(
contextWindowSize - totalTokens - autocompactBuffer,
);

const scaleDetail = <T extends { tokens: number }>(items: T[]): T[] =>
scale < 1
? items.map((item) => ({
...item,
tokens: Math.round(item.tokens * scale),
}))
: items;

detailBuiltinTools = scaleDetail(builtinTools);
detailMcpTools = scaleDetail(mcpTools);
detailMemoryFiles = scaleDetail(memoryFiles);
detailBuiltinTools = scaleTokens(builtinTools, scale);
detailMcpTools = scaleTokens(mcpTools, scale * mcpDetailShare);
detailMemoryFiles = scaleTokens(memoryFiles, scale);
detailSkills =
scale < 1
? skills.map((item) => ({
Expand Down
Loading