UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

93 lines (92 loc) • 3.3 kB
import { engineCardTypes } from "../tool-registry.js"; import { readMember } from "../thrown-value.js"; const MAX_TOOL_END_OUTPUT_CHARS = 16384; const safeJsonLength = (v) => { try { return JSON.stringify(v)?.length; } catch { return undefined; } }; const trunc = (s) => ({ text: s.slice(0, MAX_TOOL_END_OUTPUT_CHARS) + `…[+${s.length - MAX_TOOL_END_OUTPUT_CHARS} chars truncated]`, totalChars: s.length, }); export const toolOutputFrom = (result) => { const content = result !== null && typeof result === "object" ? result.content : result; if (content === undefined) return undefined; if (typeof content === "string") { if (content.length <= MAX_TOOL_END_OUTPUT_CHARS) return { output: content, truncated: false }; const t = trunc(content); return { output: t.text, truncated: true, totalChars: t.totalChars }; } let serialized; try { serialized = JSON.stringify(content) ?? ""; } catch { return { output: "[unserializable tool output]", truncated: false }; } if (serialized.length <= MAX_TOOL_END_OUTPUT_CHARS) return { output: content, truncated: false }; let anyNonText = false; let trueChars = 0; const raw = Array.isArray(content) ? content .map((b) => { const block = b; if (block?.type === "text" && typeof block.text === "string") { trueChars += block.text.length; return block.text; } anyNonText = true; trueChars += typeof block?.data === "string" ? block.data.length : (safeJsonLength(block) ?? 0); return `[${typeof block?.type === "string" ? block.type : "block"}${typeof block?.mimeType === "string" ? `: ${block.mimeType}` : ""}]`; }) .join("\n") : serialized; const totalChars = Array.isArray(content) ? trueChars : serialized.length; if (raw.length > MAX_TOOL_END_OUTPUT_CHARS) { const t = trunc(raw); return { output: t.text, truncated: true, totalChars }; } if (!anyNonText) { return { output: raw, truncated: false }; } return { output: raw, truncated: true, totalChars }; }; const CC_DETAIL_TYPES = engineCardTypes(); export function createStructuredProjector(opts = {}) { const allowed = new Set([...CC_DETAIL_TYPES, ...(opts.declaredCards ?? [])]); const announced = new Set(); return (result) => { const details = readMember(result, "details"); if (details === null || typeof details !== "object") return undefined; const t = readMember(details, "type"); if (typeof t !== "string") return undefined; if (!allowed.has(t)) { if (opts.onUndeclared !== undefined && !announced.has(t)) { announced.add(t); opts.onUndeclared(t); } return undefined; } return boundedCard(details); }; } function boundedCard(details) { try { const serialized = JSON.stringify(details) ?? ""; if (serialized.length > MAX_TOOL_END_OUTPUT_CHARS * 4) return undefined; } catch { return undefined; } return details; }