UNPKG

agentfootprint

Version:

The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.

87 lines • 4.41 kB
"use strict"; /** * thinkingSupport — `.thinking({ budget })` checked at BUILD against what each * provider declares for the model it will call (`LLMProvider.thinkingMode`). * * Every (provider, model) pair the agent's thinking request can reach is * asked: the declared reliability list (or the agent's own pair), each * per-skill brain, the escalation brain. A * model that cannot think (`'none'`) is refused here, by name, with an * `UnsupportedThinkingError` — rather than on the first call, or on the call * a fallback serves. An `'adaptive'` model takes no budget, and dev mode says * so once per model: configured and silently ignored must not look like * configured and working. * * Not checked here: a model `.configure()` picks at run time. The adapter * asks the same declaration on every request and refuses before sending. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.checkThinkingSupport = void 0; const footprintjs_1 = require("footprintjs"); const errors_js_1 = require("../../thinking/errors.js"); const thinkingModeFor_js_1 = require("../../thinking/thinkingModeFor.js"); const providerTargets_js_1 = require("./providerTargets.js"); /** Models already told that adaptive thinking takes no budget — once per model per process. */ const adaptiveWarned = new Set(); /** * Refuse `.thinking()` for any reachable model whose provider declares it * cannot honor thinking for it; dev-warn for one that thinks adaptively (no budget). * * @throws UnsupportedThinkingError (`reason: 'no-thinking'`) * @throws TypeError when a provider's `thinkingMode` declaration is malformed */ function checkThinkingSupport(args) { for (const target of thinkingTargets(args)) { const mode = (0, thinkingModeFor_js_1.thinkingModeFor)(target.provider, target.model); if (mode === 'none') { throw new errors_js_1.UnsupportedThinkingError({ provider: target.provider.name, model: target.model, reason: 'no-thinking', detail: `this provider cannot honor thinking for this model, so .thinking({ budget: ${args.budget} }) ` + `cannot be honoured for ${target.site}. Choose a provider/model pair that supports thinking, or drop .thinking().`, }); } if (mode === 'adaptive') warnBudgetNotSent(target, args.budget); } } exports.checkThinkingSupport = checkThinkingSupport; /** Selected transport pairs, then each brain's — a brain inherits what it leaves out. */ function thinkingTargets(args) { const targets = [ ...(0, providerTargets_js_1.providerTargets)(args.provider, args.model, args.reliabilityProviders), ]; for (const [skillId, brain] of args.brains?.bySkill ?? []) { targets.push({ provider: brain.provider ?? args.provider, model: brain.model ?? args.model, site: `skill '${skillId}'`, }); } const escalation = args.brains?.escalation; if (escalation !== undefined) { targets.push({ provider: escalation.provider, model: escalation.model ?? args.model, site: 'the escalation brain', }); } return targets.filter((t, i) => targets.findIndex((u) => u.provider === t.provider && u.model === t.model) === i); } function warnBudgetNotSent(target, budget) { const key = JSON.stringify([target.provider.name, target.model]); if (adaptiveWarned.has(key) || !(0, footprintjs_1.isDevMode)()) return; if (adaptiveWarned.size < 500) adaptiveWarned.add(key); // eslint-disable-next-line no-console console.warn(`agentfootprint Agent: .thinking({ budget: ${budget} }) — '${target.model}' on ` + `'${target.provider.name}' thinks adaptively, which takes no budget: the model decides ` + `whether and how much to think, and the budget is not sent. The built-in Anthropic ` + `adapters still keep max_tokens above it, so a long think has room. They also read an ` + `id they do not know as adaptive: if '${target.model}' is an alias, a deployment name ` + `or a profile ARN for a model that needs a budget (Claude 4.5 and earlier), declare it ` + `with the adapter's thinkingMode option. This warning fires once per model per process.`); } //# sourceMappingURL=thinkingSupport.js.map