UNPKG

agentfootprint

Version:

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

78 lines • 4.57 kB
/** * extractSequence — derive the in-flight tool-call sequence from * `scope.history` for `PermissionChecker.check()`. * * Pattern: Pure function over conversation history. * Role: Single source of truth — sequence is reconstructed on * demand from `LLMMessage[]` instead of maintained as * parallel state in scope. Survives `agent.resumeOnError` * correctly because the history IS the durable artifact. * Emits: N/A (pure compute). * * The sequence reads the assistant turns' `toolCalls` blocks in order. * Calls that were denied at the gate (synthetic tool_results in history * but no `tool.execute()` invocation) are NOT included — the sequence * reflects what actually dispatched, not what was attempted. Nor are the * calls a paused batch never dispatched (9.113.0): the resume settles each * with a fixed sentence and no gate ever saw it, so counting it would let a * precondition policy ("verify before transfer") be met by a call that never * ran. * * Detection of "did this call dispatch?" — the `tool` messages are read two * ways, each with the pairing its question needs: * * • IN FLIGHT or DENIED — by id (`resultsById`, the rule this file always * had): the latest RESULT for the id decides. None yet → the call is * still in flight; the synthetic deny prefix → it was refused at the * gate. A settled message is no result, so it answers neither question. * Kept by id on purpose, limits included: a call denied at the gate still * counts once a later call that runs reuses its id, and a call that ran * drops out once a later reuse of its id is denied. The in-flight check * has the same limit: a call never answered — a halt's later siblings, a * paused turn continued after `abandonPause()` — counts once a later call * that runs reuses its id, because the id then has a result. Pairing the * deny and the in-flight checks by position too would change the * sequence of runs that never met a settlement, which this release does * not do; settling those two doors with the marker is the named follow-up * (`src/core/README.md` · "Not covered yet"). * • SETTLED — by position (`settledProposals`, 9.113.0): a settled message * carries `LLMMessage.notDispatched` — the marker, never its sentence — * and it settles the ONE proposal it answers. An id alone cannot say * which proposal that is: a provider may reuse an id across turns, and * the library's own fallback ids are minted per provider INSTANCE * (`adapters/llm/OllamaProvider.ts` · `nextToolCallId`, and its * Foundry Local and Gemini twins), so a fresh process that resumes a * stored checkpoint mints the settled call's id again for a call that * really runs. Paired by id, that real call would bring the settled one * back into the sequence — a "verify before transfer" policy met by a * verify that never ran — and a settled reuse would drop a call that * did run. Paired by position, each proposal is judged by its own answer. * * A history without a settled message pairs exactly as before 9.113.0. */ import type { LLMMessage, ToolCallEntry } from '../provider-contract/types.js'; /** Prefix the framework writes on synthetic deny tool_results. Used to * distinguish "denied but in history" from "actually dispatched". */ export declare const SYNTHETIC_DENY_PREFIX = "[permission denied:"; export interface ExtractSequenceOptions { /** * Resolver: tool name → providerId. When the tool was registered via * `staticTools(...)` / `.tool(...)`, returns `'local'` (or the resolver's * choice). When registered via a `discoveryProvider`, returns the * provider's `id`. Lets policies match cross-hub patterns. */ readonly resolveProviderId?: (toolName: string) => string | undefined; } /** * Walk `history` in order, collect each dispatched tool call into the * sequence. Only calls that produced a non-denied tool_result are * included. * * @param history Conversation history at check time. * @param iteration Current ReAct iteration (used to tag the proposed * call's iteration if you append it). * @param options Optional resolver for `providerId`. * @returns The dispatched-call sequence, in chronological order. */ export declare function extractSequence(history: readonly LLMMessage[], iteration: number, options?: ExtractSequenceOptions): ToolCallEntry[]; //# sourceMappingURL=extractSequence.d.ts.map