UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

68 lines (67 loc) • 2.73 kB
import { DEFAULT_CHARS_PER_TOKEN } from "../../internal/harness.js"; import { TOOL_SEARCH_DEFAULT_THRESHOLD_PERCENT, describeRejectedValue, resolveToolSearch } from "../tool-search-setting.js"; export const DEFER_THRESHOLD_FRACTION = TOOL_SEARCH_DEFAULT_THRESHOLD_PERCENT / 100; const CHARS_PER_TOKEN = DEFAULT_CHARS_PER_TOKEN; function inlinedChars(t) { let schema = ""; try { schema = JSON.stringify(t.parameters) ?? ""; } catch { schema = ""; } return t.name.length + t.description.length + schema.length; } export const DEFER_MODE_INVALID_CODE = "config.defer_mode_invalid"; export function deferralGate(opts) { if (opts.deferMode !== undefined && opts.deferMode !== "auto") { const e = new Error(`RunnerDeps.deferMode: invalid value ${describeRejectedValue(opts.deferMode)} — expected "auto" or omitted; a bad value refuses loudly, nothing falls back to a default.`); e.code = DEFER_MODE_INVALID_CODE; throw e; } const toolSearch = resolveToolSearch(opts.toolSearch); const pinned = new Set(opts.alwaysLoadNames ?? []); for (const s of opts.specs) { if (s.alwaysLoad === true) pinned.add(s.name); } const explicit = new Set(); for (const name of opts.callerDeferNames ?? []) if (!pinned.has(name)) explicit.add(name); const gated = new Set(); const select = (name) => { if (!pinned.has(name) && !explicit.has(name)) gated.add(name); }; for (const s of opts.specs) if (s.defer === true || opts.deferMode === "auto") select(s.name); for (const name of opts.protocolToolNames) select(name); for (const name of opts.builtinDeferNames ?? []) select(name); let gatedChars = 0; for (const t of opts.fullTools) if (gated.has(t.name)) gatedChars += inlinedChars(t); const windowTokens = Math.max(0, opts.model.contextTokens ?? opts.model.contextWindow ?? 0); const thresholdTokens = windowTokens * toolSearch.fraction; const thresholdChars = Number.isFinite(thresholdTokens) ? Math.floor(thresholdTokens) * CHARS_PER_TOKEN : toolSearch.fraction === 0 ? 0 : Number.POSITIVE_INFINITY; return { explicit, gated, gatedChars, thresholdChars, open: gatedChars >= thresholdChars, toolSearch }; } export function classifyDeferred(opts) { return classifyDeferredWithGate(opts).deferred; } export function classifyDeferredWithGate(opts) { const gate = deferralGate(opts); const deferred = new Set(gate.explicit); if (gate.open) for (const n of gate.gated) deferred.add(n); return { deferred, gate }; }