mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-27 05:07:50 +00:00
fix(agents): exclude tool result details from guard budget (#75525)
Merged via squash.
Prepared head SHA: 4efe094507
Co-authored-by: zqchris <4436110+zqchris@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
This commit is contained in:
@@ -1414,6 +1414,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Agents/compaction: cap summarization output reserve tokens to the selected model's `maxTokens` so 1M-context Anthropic compactions do not request more output than the API permits. Fixes #54383.
|
||||
- Control UI/login: replace raw connection failures with structured, actionable login guidance for auth, pairing, insecure HTTP, origin, protocol, and transport failures. Thanks @BunsDev.
|
||||
- Agents/tools: fail `exec host=node` before `system.run` when the selected node is known to be disconnected, with an actionable reconnect message instead of a raw node invoke failure. Thanks @BunsDev.
|
||||
- Agents/tool-result guard: ignore internal tool-result `details` when estimating model-visible context, so large diagnostic metadata no longer triggers unnecessary truncation or compaction even though the provider boundary already strips `details` before model conversion. (#75525) Thanks @zqchris.
|
||||
- Agents/models: accept legacy `anthropic-cli/*` model refs as Claude CLI runtime refs instead of failing model resolution with `Unknown model`. Thanks @BunsDev.
|
||||
- Agents/tools: keep restrictive-profile tool-section warnings scoped to the configured sections whose tools are still missing from `alsoAllow`, so already re-allowed filesystem tools do not make exec-only fixes look broader than they are. Thanks @BunsDev.
|
||||
- Agents/tools: avoid warning messaging-only agents about inherited global `tools.exec` or `tools.fs` sections when the agent profile did not configure those tool sections itself. Thanks @BunsDev.
|
||||
|
||||
@@ -125,10 +125,9 @@ function estimateMessageChars(msg: AgentMessage): number {
|
||||
}
|
||||
|
||||
if (isToolResultMessage(msg)) {
|
||||
// `details` is stripped before provider conversion; estimate only visible content.
|
||||
const content = getToolResultContent(msg);
|
||||
let chars = estimateContentBlockChars(content);
|
||||
const details = (msg as { details?: unknown }).details;
|
||||
chars += estimateUnknownChars(details);
|
||||
const chars = estimateContentBlockChars(content);
|
||||
const weightedChars = Math.ceil(
|
||||
chars * (CHARS_PER_TOKEN_ESTIMATE / TOOL_RESULT_CHARS_PER_TOKEN_ESTIMATE),
|
||||
);
|
||||
|
||||
@@ -371,6 +371,36 @@ describe("installToolResultContextGuard", () => {
|
||||
expect((err as MidTurnPrecheckSignal).request.route).toBe("compact_only");
|
||||
}
|
||||
});
|
||||
it("does not count tool-result details toward the context budget", async () => {
|
||||
const agent = makeGuardableAgent();
|
||||
const contextForNextCall = [
|
||||
makeToolResultWithDetails("call_small_text", "x".repeat(100), "d".repeat(50_000)),
|
||||
makeToolResultWithDetails("call_another", "y".repeat(120), "e".repeat(80_000)),
|
||||
];
|
||||
|
||||
const transformed = (await applyGuardToContext(agent, contextForNextCall)) as AgentMessage[];
|
||||
|
||||
expect(transformed).toBe(contextForNextCall);
|
||||
expect(getToolResultText(transformed[0])).toBe("x".repeat(100));
|
||||
expect(getToolResultText(transformed[1])).toBe("y".repeat(120));
|
||||
expect((contextForNextCall[0] as { details?: unknown }).details).toBeDefined();
|
||||
expect((contextForNextCall[1] as { details?: unknown }).details).toBeDefined();
|
||||
});
|
||||
|
||||
it("ignores large tool-result details when deciding preemptive overflow", async () => {
|
||||
const agent = makeGuardableAgent();
|
||||
const contextForNextCall = [
|
||||
makeUser("small user prompt"),
|
||||
makeToolResultWithDetails("call_1", "a".repeat(50), "d".repeat(30_000)),
|
||||
makeToolResultWithDetails("call_2", "b".repeat(50), "d".repeat(30_000)),
|
||||
makeToolResultWithDetails("call_3", "c".repeat(50), "d".repeat(30_000)),
|
||||
makeToolResultWithDetails("call_4", "e".repeat(50), "d".repeat(30_000)),
|
||||
];
|
||||
|
||||
const transformed = (await applyGuardToContext(agent, contextForNextCall)) as AgentMessage[];
|
||||
|
||||
expect(transformed).toBe(contextForNextCall);
|
||||
});
|
||||
});
|
||||
|
||||
type MockedEngine = ContextEngine & {
|
||||
|
||||
Reference in New Issue
Block a user