@sema-agent/core
Version:
Stateless, task-oriented AI agent core
68 lines (67 loc) • 2.73 kB
JavaScript
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 };
}