agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
54 lines • 2.67 kB
JavaScript
;
/**
* ids — every id the AG-UI adapter mints, from ONE grammar.
*
* <run>/<kind>/<n>/<address>
*
* run the AG-UI `runId`, through `encodeIdentityField` — `%` and `/`
* escaped, so it holds no `/`;
* kind one of {@link AgUiIdKind} — no `/`;
* n a decimal ordinal — no `/`;
* address the agentfootprint `runtimeStageId` of the event that opened the
* entity (`call-llm#18`, `step-p/x/tool-calls#97`) — any string.
*
* INJECTIVE by construction: the first three `/` end the three segments that
* cannot hold one, so two different (run, kind, n, address) tuples never spell
* the same id. `test/ag-ui/ids.test.ts` pins it with a property test.
*
* WHY THE ADDRESS, NOT THE PROVIDER'S ID. A model's tool-call id is not unique
* in a run: a provider may reuse it across iterations, and two parallel branches
* routinely mint the same one (`call_1`, `c1`). An AG-UI client finds a tool
* call by its id across the WHOLE conversation, so a reused id would land a new
* call's arguments on an old message. And under a redaction policy the record
* serves every id as the placeholder. The address — the stage execution that
* produced the entity, unique within a run — is unique, survives redaction (it
* is the record's own key, never a value a policy selects) and lines up with the
* recording; the run segment makes it unique across the thread. The provider's
* id, as the record serves it, rides `metadata.agentfootprint.toolCallId`.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.agUiIdMinter = exports.agUiId = void 0;
const encode_js_1 = require("../memory/identity/encode.js");
/** Spell one id. Exported for the property test; the minter is the only caller. */
function agUiId(runId, kind, n, address) {
return `${(0, encode_js_1.encodeIdentityField)(runId)}/${kind}/${n}/${address}`;
}
exports.agUiId = agUiId;
/** A minter for the AG-UI run `runId`. Refuses an empty run id: it would mint `_` ids. */
function agUiIdMinter(runId) {
if (typeof runId !== 'string' || runId.length === 0) {
throw new TypeError('AG-UI: `runId` must be a non-empty string — every id the run mints is under it.');
}
const counts = new Map();
return {
next(kind, address) {
const key = `${kind}\u0000${address}`;
const n = counts.get(key) ?? 0;
counts.set(key, n + 1);
return { id: agUiId(runId, kind, n, address), n };
},
at: (kind, n, address) => agUiId(runId, kind, n, address),
};
}
exports.agUiIdMinter = agUiIdMinter;
//# sourceMappingURL=ids.js.map