agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
104 lines • 5.68 kB
JavaScript
;
/**
* artifacts/types — the claim-check shapes and the five-verb port.
*
* A tool stores its result under a REFERENCE and hands the model a claim
* ticket; the model routes tickets instead of hauling data. These are the
* shapes that make that sentence true: the ref (an opaque minted string),
* the metadata a consumer decides from (never the bytes), and the store
* port every backend implements.
*
* ── The constitution this port inherits (from `MemoryStore`) ────────────────
* 1. **Scope is always the first argument.** Every call takes an
* {@link ArtifactScope} — the same tenant/principal/conversation tuple
* memory scopes on — so stores enforce isolation at the boundary. A ref
* alone opens NOTHING; a wrong scope surfaces as "no data", never as a
* cross-tenant read.
* 2. **`get` returns `null` for missing OR expired.** Deliberate ambiguity:
* "no data" is the only actionable fact, and distinguishing the two would
* let a caller reason about another scope's contents.
* 3. **Reads return cursors, not unbounded arrays.** `list` pages.
* 4. **Methods return Promises uniformly**, so sync adapters can become
* async ones without breaking a caller.
*
* ── Five verbs, no more ─────────────────────────────────────────────────────
* `put · head · get · delete · list`. The moment this port grows `query()` or
* `transform()` we are building a database — compute belongs to the code leg,
* and that refusal is written here so a future round can be refused by
* citation.
*
* `head` earns its place because it IS the render-by-ref decision: a consumer
* picks what to do from `kind` and `bytes` without paying for the payload.
*
* ── …and two OPTIONAL ones (9.25.0) ─────────────────────────────────────────
* `putStream?` / `getStream?` are feature-detected members, not a sixth and
* seventh verb: a store that cannot move a payload without holding it whole
* LEAVES THEM ABSENT, and a consumer that calls one it did not detect gets a
* type error rather than a runtime surprise. An adapter must never fake a
* stream over bytes it already holds — a fake stream is an accepted-and-
* silently-wrong promise about memory. See {@link ArtifactStreamPutInput} for
* the two things streaming costs you (a stated `bytes`, and no digest).
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.InvalidArtifactError = exports.ArtifactIntegrityError = exports.UnknownParentRefError = void 0;
// ─── Refusals ────────────────────────────────────────────────────────
/**
* A `put` named a parent that does not resolve in the same scope — a foreign
* key that would dangle at birth. Refused at mint, because a derivation fact
* that points at nothing is worse than no fact: every later consumer would
* inherit the lie.
*/
class UnknownParentRefError extends Error {
code = 'ERR_UNKNOWN_PARENT_REF';
/** The parents that failed to resolve. */
unresolved;
constructor(unresolved) {
super(`[artifacts] put refused: parentRefs ${unresolved.map((r) => `'${r}'`).join(', ')} ` +
`do not resolve in this scope. parentRefs are derivation FACTS validated at mint — ` +
`a parent must exist (and not be expired) in the same scope when the child is born. ` +
`Store the parent first, or drop it from parentRefs; head(ref) tells you what resolves.`);
this.name = 'UnknownParentRefError';
this.unresolved = unresolved;
}
}
exports.UnknownParentRefError = UnknownParentRefError;
/**
* A stored payload no longer matches the digest minted with it. Thrown by
* `get` instead of returning the bytes — corrupt data delivered as whole data
* is the accepted-and-silently-wrong failure, and the one thing a claim check
* must never do is honor a ticket with someone else's parcel.
*/
class ArtifactIntegrityError extends Error {
code = 'ERR_ARTIFACT_INTEGRITY';
ref;
/** The digest minted at put. */
expected;
/** The digest of what the store actually holds now. */
actual;
constructor(ref, expected, actual) {
super(`[artifacts] get('${ref}') refused: the stored payload no longer matches its minted ` +
`digest (expected ${expected}, computed ${actual}). The bytes changed after put — ` +
`a corrupted file, an external edit, or a store bug — and returning them as if whole ` +
`would be silent corruption. Re-create the artifact from its source; the meta ` +
`(head) is still readable.`);
this.name = 'ArtifactIntegrityError';
this.ref = ref;
this.expected = expected;
this.actual = actual;
}
}
exports.ArtifactIntegrityError = ArtifactIntegrityError;
/**
* A `put` this store cannot honor as stated — a payload JSON cannot carry, a
* blank `kind`, a payload larger than the whole scope budget. Refused by name
* at the door: storing an approximation would be accepted-and-silently-wrong.
*/
class InvalidArtifactError extends Error {
code = 'ERR_INVALID_ARTIFACT';
constructor(detail) {
super(`[artifacts] put refused: ${detail}`);
this.name = 'InvalidArtifactError';
}
}
exports.InvalidArtifactError = InvalidArtifactError;
//# sourceMappingURL=types.js.map