UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

39 lines (38 loc) • 2.39 kB
import { deliverEngineNotice } from "../engine-notice.js"; import { providerToolCallId, toolCallFoldReason } from "../../brain/tool-call-id.js"; function isCall(block) { return typeof block === "object" && block !== null && block.type === "toolCall" && typeof block.id === "string"; } const REASON_CLAUSE = { charset: () => "named a tool call with an id outside the shape the engine keys calls under (a control byte, a space, a non-ASCII character or a `~`)", length: (wireId) => `named a tool call with an id outside the shape the engine keys calls under (${wireId.length} characters, over 128)`, duplicate: () => "gave two tool calls in one response the same id, and every provider requires a request's call ids to be unique", }; export function createToolCallIdFoldSeat(onNotice, ids) { let announced = false; return { observe(message) { if (announced || !Array.isArray(message.content)) return; for (const call of message.content.filter(isCall)) { const reason = toolCallFoldReason(call); if (reason === undefined) continue; announced = true; const wireId = providerToolCallId(call); deliverEngineNotice(onNotice, { code: "route.tool_call_id_folded", message: `The provider ${REASON_CLAUSE[reason](wireId)}. ` + (reason === "duplicate" ? `The engine keys the later call as "${call.id}" on every face — frames, cards, transcript, park rows — and hands ` + `the provider a distinct id for it and its result, so both calls run and both results reach the model. ` : `The engine keys it as "${call.id}" on every face — frames, cards, transcript, park rows — and hands the ` + `provider its own id back for the call and its result, so the run is unchanged. `) + `Once per run; later calls with such ids are folded the same way without another notice.`, detail: { toolCallId: call.id, ...(reason === "duplicate" ? {} : { rawLength: wireId.length }), reason, sessionId: ids.sessionId, runId: ids.runId }, }); return; } }, }; }