fix(agent): counted Anthropic server-tool blocks in token estimate
estimateTokens now charges for serialized anthropicServerTool blocks so context maintenance sees the server-tool payload replayed on the wire; excluded from the compaction floor like other encrypted reasoning.
This commit is contained in:
@@ -427,6 +427,14 @@ function computeMessageTokens(message: AgentMessage, options?: { excludeEncrypte
|
||||
// Encrypted reasoning blob the provider still bills for on replay;
|
||||
// excluded from the compaction floor for the same reason as above.
|
||||
if (!options?.excludeEncryptedReasoning) fragments.push(block.data);
|
||||
} else if (block.type === "anthropicServerTool") {
|
||||
// Native Anthropic server-tool call/result replayed verbatim on the
|
||||
// wire (server_tool_use input, web_search_tool_result
|
||||
// encrypted_content). Opaque provider-replay state the provider still
|
||||
// bills for on same-provider replay; excluded from the compaction
|
||||
// floor like other encrypted reasoning because its local byte size
|
||||
// diverges from provider billing.
|
||||
if (!options?.excludeEncryptedReasoning) fragments.push(stringifyJson(block.block) ?? "null");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -110,6 +110,34 @@ describe("estimate cache option split", () => {
|
||||
expect(estimateTokens(msg as AgentMessage)).toBe(withBlob);
|
||||
expect(estimateTokens(msg as AgentMessage, { excludeEncryptedReasoning: true })).toBe(floored);
|
||||
});
|
||||
|
||||
test("counts native server-tool blocks by default and drops them from the compaction floor", () => {
|
||||
const encrypted = "cipher".repeat(4000);
|
||||
const msg: AssistantMessage = {
|
||||
...settledAssistant("with search"),
|
||||
content: [
|
||||
{ type: "text", text: "answer" },
|
||||
{
|
||||
type: "anthropicServerTool",
|
||||
block: {
|
||||
type: "web_search_tool_result",
|
||||
tool_use_id: "srvtoolu_1",
|
||||
content: [{ type: "web_search_result", encrypted_content: encrypted }],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
const textOnly = estimateTokens({
|
||||
...settledAssistant("x"),
|
||||
content: [{ type: "text", text: "answer" }],
|
||||
} as AgentMessage);
|
||||
const withServerTool = estimateTokens(msg as AgentMessage);
|
||||
const floored = estimateTokens(msg as AgentMessage, { excludeEncryptedReasoning: true });
|
||||
// Default estimate charges for the serialized server-tool payload…
|
||||
expect(withServerTool).toBeGreaterThan(floored + 500);
|
||||
// …while the compaction floor ignores the opaque encrypted blob entirely.
|
||||
expect(floored).toBe(textOnly);
|
||||
});
|
||||
});
|
||||
|
||||
describe("estimate cache invalidation seams", () => {
|
||||
|
||||
Reference in New Issue
Block a user