Q22: cap every tool result and bound connector responses
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4d6c74a21e
commit
8e8b66fed4
5 files changed
+79
-5
No files matched your search
@@ -6,7 +6,7 @@ import { executeWorkspaceTool, isWorkspaceTool, WORKSPACE_TOOLS } from "./agent-
|
||||
import { canonicalMentionHandle } from "../../shared/mention-handles";
|
||||
import type { AgentTurnMessage, ToolDefinition } from "./provider-tool-turn";
|
||||
import { isComposioTool, executeComposioTool } from "./composio/composio-tool-bridge";
|
||||
import { compactToolHistory } from "./run-context-compaction";
|
||||
import { capToolOutput, compactToolHistory } from "./run-context-compaction";
|
||||
import { fitContextBudget } from "./context-budget";
|
||||
|
||||
const MAX_ITERATIONS = 12;
|
||||
@@ -114,7 +114,7 @@ export async function runAgentLoop(deps: AgentRunLoopDeps, input: AgentRunLoopIn
|
||||
announceTaskAssignments: shouldAnnounceTaskAssignment(call, turn.toolCalls),
|
||||
});
|
||||
}
|
||||
results.push({ toolCallId: call.id, toolName: call.name, output });
|
||||
results.push({ toolCallId: call.id, toolName: call.name, output: capToolOutput(call.name, output) });
|
||||
}
|
||||
const followUp = input.pollNewMessages?.();
|
||||
messages.push(followUp ? { role: "tool", results, followUp } : { role: "tool", results });
|
||||
|
||||
@@ -33,6 +33,8 @@ export interface ComposioToolExecutionResult {
|
||||
error: string | null;
|
||||
}
|
||||
|
||||
const MAX_RESPONSE_BYTES = 2_000_000;
|
||||
|
||||
export class ComposioClient {
|
||||
constructor(private readonly apiKey: string) {}
|
||||
|
||||
@@ -155,10 +157,24 @@ export class ComposioClient {
|
||||
request.setHeader("Accept", "application/json");
|
||||
if (body) request.setHeader("Content-Type", "application/json");
|
||||
|
||||
let responseData = "";
|
||||
const chunks: Buffer[] = [];
|
||||
let received = 0;
|
||||
let aborted = false;
|
||||
request.on("response", (response) => {
|
||||
response.on("data", (chunk) => { responseData += chunk.toString(); });
|
||||
response.on("data", (chunk) => {
|
||||
if (aborted) return;
|
||||
received += chunk.length;
|
||||
if (received > MAX_RESPONSE_BYTES) {
|
||||
aborted = true;
|
||||
request.abort();
|
||||
reject(new Error(`Composio API ${method} ${url} returned more than ${MAX_RESPONSE_BYTES} bytes; ask for fewer items or narrower fields.`));
|
||||
return;
|
||||
}
|
||||
chunks.push(chunk);
|
||||
});
|
||||
response.on("end", () => {
|
||||
if (aborted) return;
|
||||
const responseData = Buffer.concat(chunks).toString("utf8");
|
||||
if (response.statusCode === 404 && options?.tolerateNotFound) {
|
||||
resolve({});
|
||||
return;
|
||||
|
||||
@@ -3,6 +3,14 @@ import type { AgentTurnMessage } from "./provider-tool-turn";
|
||||
const KEEP_RECENT_TOOL_TURNS = 3;
|
||||
const ELIDE_ABOVE_CHARS = 600;
|
||||
const PREVIEW_CHARS = 300;
|
||||
const TOOL_RESULT_CHAR_LIMIT = 26_000;
|
||||
|
||||
/** One tool result never exceeds the per-result cap. */
|
||||
export function capToolOutput(toolName: string, output: string): string {
|
||||
if (output.length <= TOOL_RESULT_CHAR_LIMIT) return output;
|
||||
console.warn(`[run-loop] ${toolName} returned ${output.length} chars; cut to ${TOOL_RESULT_CHAR_LIMIT}`);
|
||||
return `${output.slice(0, TOOL_RESULT_CHAR_LIMIT)}\n\n[result of ${toolName} cut at ${TOOL_RESULT_CHAR_LIMIT} of ${output.length} characters; ask for less (filters, pagination, fewer fields)]`;
|
||||
}
|
||||
|
||||
/** Older tool results shrink to a preview; the latest turns stay verbatim. */
|
||||
export function compactToolHistory(messages: AgentTurnMessage[], keepRecent = KEEP_RECENT_TOOL_TURNS): { messages: AgentTurnMessage[]; elided: number } {
|
||||
|
||||
Reference in new issue
Block a user