UNPKG

agentfootprint

Version:

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

178 lines • 14.3 kB
"use strict"; /** * agentfootprint/skill-graph — the routing runtime, with no framework attached. * * A skill graph is a pure decision layer. You declare skills and the edges * between them; given one iteration's `InjectionContext` it answers three * questions — where is the cursor, what is reachable from there, which * injections are active — and it answers them with plain functions over plain * data. No model call, no loop, no scope, no flowchart. * * This door exposes exactly that layer, so a host that is NOT agentfootprint's * agent can run it: another agent framework, a server that routes prompts, a * test harness. The claim is CHECKED, not asserted — * `test/injection-engine/skill-graph-fence.test.ts` walks the transitive * import graph of everything reachable from this file and fails if any of it * reaches `footprintjs`, `core/agent/*`, `tools/tools.ts`, an adapter or a * recorder. * * WHAT A HOST OWES THE GRAPH is written down as a type: * {@link SkillGraphHost}. Five obligations, each naming the code in this * package that implements it. Read it before wiring anything. * * TWO HONEST COSTS. * * 1. `footprintjs` is still a REQUIRED peer dependency of this package. This * door never loads it — that is the whole point of the fence — but npm * will still install it beside you, because the rest of agentfootprint * needs it and the package is not split. You pay the install, not the * import. * 2. The PROVIDER LAYER is not here. `llmClassifier` and * `constrainedEnumPick` need an `LLMProvider` to make a model call, so * they genuinely depend on the adapter layer; pretending otherwise would * be a fake abstraction. Import them from `agentfootprint/context` when * you want the turn-start classifier cascade. Everything else about the * graph — declared edges, entry rules, scorers, the tie policy, the * check-up — is here. * * Also not here: the sugar factories (`defineSkill`, `defineInstruction`, …). * They resolve cache policies and validate against the framework's `Tool`, so * they live host-side, on `agentfootprint/context`. A foreign host builds * `Injection` objects directly — five fields, all data. * * THE EXAMPLE BELOW IS CHECKED, not typed out. Doc comments are emitted into * the `.d.ts`, so this block is what a consumer reads on hover — and the one * that shipped before 9.37.x could not compile three ways over (a config key * that does not exist, chaining the builder's methods off the finished graph * the object form returns, and passing ids to a `.route()` that takes skill * objects). It is now the `doc-example` region of * `examples/context-engineering/19-skill-graph-host.ts` — typechecked by * `npm run test:examples:typecheck`, RUN by `scripts/run-all-examples.sh`, and * pinned byte-for-byte to these lines by * `test/injection-engine/skill-graph-doc-example.test.ts`. Edit it there; * the test will tell you to bring this copy along. * * @example routing a turn from a host that is not our agent * ```ts * import { * readSkillDescriptor, * skillGraph, * type Injection, * type InjectionContext, * } from 'agentfootprint/skill-graph'; * * // A foreign host builds `Injection` objects directly — five fields, all data. * // (`defineSkill` and friends live host-side, on `agentfootprint/context`.) * const triage: Injection = { * id: 'triage', * flavor: 'skill', * description: 'Find the order the customer is talking about.', * trigger: { kind: 'llm-activated', viaToolName: 'read_skill' }, * inject: { systemPrompt: 'Ask for the order id, then call lookup_order.' }, * }; * const billing: Injection = { * id: 'billing', * flavor: 'skill', * description: 'Refunds, double charges, invoices.', * trigger: { kind: 'llm-activated', viaToolName: 'read_skill' }, * inject: { systemPrompt: 'Confirm the charge history before promising a refund.' }, * }; * * // The FLUENT builder takes the skill OBJECTS (not their ids) and ends in * // `.build()`. `skillGraph({ skills, start, steps })` is the OTHER door: it * // returns a finished `SkillGraph`, with nothing to chain. * const graph = skillGraph() * .entry(triage) * .route(triage, billing, { onToolReturn: 'lookup_order' }) * .build(); * * // Per iteration — ONE ctx, built once and asked every question below: a * // cursor derived from a different ctx than the triggers can disagree with * // them (obligation 1 of `SkillGraphHost`). * const ctx: InjectionContext = { * iteration: 2, * userMessage: 'I was charged twice for order 4021', * history: [{ role: 'user', content: 'I was charged twice for order 4021' }], * activatedInjectionIds: [], * currentSkillId: 'triage', * toolResults: [{ toolName: 'lookup_order', result: 'order 4021 · charged twice' }], * }; * * const move = graph.explainNextSkill(ctx); // where the cursor goes, and WHY * const offered = graph.reachableSkills(move.to); // obligation 2 — gate read_skill on this * const readSkill = readSkillDescriptor(graph.skills, { grantable: offered }); * ``` */ Object.defineProperty(exports, "__esModule", { value: true }); exports.useSkillGraphDevMode = exports.vocabularyOf = exports.checkArtifactVocabularies = exports.skillToolNames = exports.checkSkillContracts = exports.checkSkillContract = exports.SKIP_STEP_TOOL_NAME = exports.skipStepDescriptor = exports.pointerOf = exports.readSkillDescriptor = exports.listSkillsDescriptor = exports.NEAR_TIE_MARGIN = exports.MENU_SIZE = exports.DEFAULT_ROUTING_POLICY = exports.menuOutstanding = exports.decideTier2 = exports.validateIntentScores = exports.CLASSIFIER_SCORER_UNAVAILABLE = exports.CLASSIFIER_SCORER_QUESTION = exports.classifierScorer = exports.rankEntries = exports.keywordScorer = exports.embeddingScorer = exports.classifySkillTarget = exports.plainGuardCaption = exports.GUARD_HOP_KEYS = exports.SKILL_GRAPH_METADATA_KEY = exports.SKILL_GRAPH_DEFERRED_CONTRACT_KEY = exports.defineSkillMap = exports.skillGraph = exports.formatCheckup = exports.decideSkill = exports.TOOL_RESULT_STATUSES = exports.evaluateInjections = exports.toolResultsOf = exports.saidByPerson = exports.projectActiveInjection = void 0; var types_js_1 = require("../injection-engine/types.js"); Object.defineProperty(exports, "projectActiveInjection", { enumerable: true, get: function () { return types_js_1.projectActiveInjection; } }); Object.defineProperty(exports, "saidByPerson", { enumerable: true, get: function () { return types_js_1.saidByPerson; } }); Object.defineProperty(exports, "toolResultsOf", { enumerable: true, get: function () { return types_js_1.toolResultsOf; } }); var evaluator_js_1 = require("../injection-engine/evaluator.js"); Object.defineProperty(exports, "evaluateInjections", { enumerable: true, get: function () { return evaluator_js_1.evaluateInjections; } }); var toolOutcome_js_1 = require("../semantics/toolOutcome.js"); Object.defineProperty(exports, "TOOL_RESULT_STATUSES", { enumerable: true, get: function () { return toolOutcome_js_1.TOOL_RESULT_STATUSES; } }); // ─── The graph (the SkillMap — the agent that mounts it is the SkillWalker) ─ var skillGraph_js_1 = require("../injection-engine/skillGraph.js"); Object.defineProperty(exports, "decideSkill", { enumerable: true, get: function () { return skillGraph_js_1.decideSkill; } }); Object.defineProperty(exports, "formatCheckup", { enumerable: true, get: function () { return skillGraph_js_1.formatCheckup; } }); Object.defineProperty(exports, "skillGraph", { enumerable: true, get: function () { return skillGraph_js_1.skillGraph; } }); // The official vocabulary (9.51.0): `defineSkillMap` is a permanent // reference-equal alias of `skillGraph`, `SkillMap` of `SkillGraph` — both // names ship forever. There is deliberately no `SkillWalker` export: the // walker is the host that mounts the map (inside agentfootprint, the agent). Object.defineProperty(exports, "defineSkillMap", { enumerable: true, get: function () { return skillGraph_js_1.defineSkillMap; } }); Object.defineProperty(exports, "SKILL_GRAPH_DEFERRED_CONTRACT_KEY", { enumerable: true, get: function () { return skillGraph_js_1.SKILL_GRAPH_DEFERRED_CONTRACT_KEY; } }); Object.defineProperty(exports, "SKILL_GRAPH_METADATA_KEY", { enumerable: true, get: function () { return skillGraph_js_1.SKILL_GRAPH_METADATA_KEY; } }); // Guards-as-data on route edges (9.51.0). Object.defineProperty(exports, "GUARD_HOP_KEYS", { enumerable: true, get: function () { return skillGraph_js_1.GUARD_HOP_KEYS; } }); Object.defineProperty(exports, "plainGuardCaption", { enumerable: true, get: function () { return skillGraph_js_1.plainGuardCaption; } }); // A host gating its own `read_skill` needs the same four classes the // agent's gate uses — obligation 2, without re-deriving the stay rule. Object.defineProperty(exports, "classifySkillTarget", { enumerable: true, get: function () { return skillGraph_js_1.classifySkillTarget; } }); // ─── Scoring + the tie policy ────────────────────────────────────────── var entryScorer_js_1 = require("../injection-engine/entryScorer.js"); Object.defineProperty(exports, "embeddingScorer", { enumerable: true, get: function () { return entryScorer_js_1.embeddingScorer; } }); Object.defineProperty(exports, "keywordScorer", { enumerable: true, get: function () { return entryScorer_js_1.keywordScorer; } }); Object.defineProperty(exports, "rankEntries", { enumerable: true, get: function () { return entryScorer_js_1.rankEntries; } }); // 9.104.0 — the scored choice: an EntryScorer whose ranking IS a calibrated // classifier's distribution. The `Classifier` port it takes lives on // `agentfootprint/classify`; re-exported here as a type so a graph author // can spell the seam without a second import. var classifierScorer_js_1 = require("../injection-engine/classifierScorer.js"); Object.defineProperty(exports, "classifierScorer", { enumerable: true, get: function () { return classifierScorer_js_1.classifierScorer; } }); Object.defineProperty(exports, "CLASSIFIER_SCORER_QUESTION", { enumerable: true, get: function () { return classifierScorer_js_1.CLASSIFIER_SCORER_QUESTION; } }); Object.defineProperty(exports, "CLASSIFIER_SCORER_UNAVAILABLE", { enumerable: true, get: function () { return classifierScorer_js_1.CLASSIFIER_SCORER_UNAVAILABLE; } }); var intentScorer_js_1 = require("../injection-engine/intentScorer.js"); Object.defineProperty(exports, "validateIntentScores", { enumerable: true, get: function () { return intentScorer_js_1.validateIntentScores; } }); var routingPolicy_js_1 = require("../injection-engine/routingPolicy.js"); Object.defineProperty(exports, "decideTier2", { enumerable: true, get: function () { return routingPolicy_js_1.decideTier2; } }); Object.defineProperty(exports, "menuOutstanding", { enumerable: true, get: function () { return routingPolicy_js_1.menuOutstanding; } }); Object.defineProperty(exports, "DEFAULT_ROUTING_POLICY", { enumerable: true, get: function () { return routingPolicy_js_1.DEFAULT_ROUTING_POLICY; } }); Object.defineProperty(exports, "MENU_SIZE", { enumerable: true, get: function () { return routingPolicy_js_1.MENU_SIZE; } }); Object.defineProperty(exports, "NEAR_TIE_MARGIN", { enumerable: true, get: function () { return routingPolicy_js_1.NEAR_TIE_MARGIN; } }); // ─── The tools the graph DESCRIBES (the host constructs them) ────────── var skillToolDescriptors_js_1 = require("../injection-engine/skillToolDescriptors.js"); Object.defineProperty(exports, "listSkillsDescriptor", { enumerable: true, get: function () { return skillToolDescriptors_js_1.listSkillsDescriptor; } }); Object.defineProperty(exports, "readSkillDescriptor", { enumerable: true, get: function () { return skillToolDescriptors_js_1.readSkillDescriptor; } }); // ─── Declared procedures (steps-as-data) ─────────────────────────────── var skillSteps_js_1 = require("../injection-engine/skillSteps.js"); Object.defineProperty(exports, "pointerOf", { enumerable: true, get: function () { return skillSteps_js_1.pointerOf; } }); Object.defineProperty(exports, "skipStepDescriptor", { enumerable: true, get: function () { return skillSteps_js_1.skipStepDescriptor; } }); Object.defineProperty(exports, "SKIP_STEP_TOOL_NAME", { enumerable: true, get: function () { return skillSteps_js_1.SKIP_STEP_TOOL_NAME; } }); // ─── Authoring checks ────────────────────────────────────────────────── var skillContract_js_1 = require("../injection-engine/skillContract.js"); Object.defineProperty(exports, "checkSkillContract", { enumerable: true, get: function () { return skillContract_js_1.checkSkillContract; } }); Object.defineProperty(exports, "checkSkillContracts", { enumerable: true, get: function () { return skillContract_js_1.checkSkillContracts; } }); Object.defineProperty(exports, "skillToolNames", { enumerable: true, get: function () { return skillContract_js_1.skillToolNames; } }); var skillVocabulary_js_1 = require("../injection-engine/skillVocabulary.js"); Object.defineProperty(exports, "checkArtifactVocabularies", { enumerable: true, get: function () { return skillVocabulary_js_1.checkArtifactVocabularies; } }); Object.defineProperty(exports, "vocabularyOf", { enumerable: true, get: function () { return skillVocabulary_js_1.vocabularyOf; } }); // ─── Dev warnings, opt-in ────────────────────────────────────────────── // The core prints nothing unless a host hands it a dev-mode reader — it has // no engine to ask. Inside agentfootprint the binding is automatic; here it // is one line. See `devWarn.ts`. var devWarn_js_1 = require("../injection-engine/devWarn.js"); Object.defineProperty(exports, "useSkillGraphDevMode", { enumerable: true, get: function () { return devWarn_js_1.useSkillGraphDevMode; } }); //# sourceMappingURL=skill-graph.js.map