/** * artifacts/capability — `ctx.artifacts`, the scope-bound door a tool gets. * * Shaped exactly like `ctx.credentials`: * • ALWAYS present — with no store attached every method is a teaching * refusal naming how to attach one, so a tool can never silently * optional-chain past a store that is not there; * • fail-closed — the refusal throws; `ctx.hasArtifacts` is the fact to * branch on for an intentional degraded mode; * • scope composed by the FRAMEWORK from the run's identity/session — the * capability closes over it, so a tool cannot name, widen or replace the * scope it resolves under. The five verbs here take no scope argument on * purpose: that argument was already answered by whoever built the * context. * * Every hop lands on the record AS IT HAPPENS: this module reports facts to a * neutral sink (a plain callback), and the tool-dispatch layer adapts that * sink onto the typed event channel. Neutral so this folder never imports the * event system or the agent — core wires artifacts, never the reverse. */ import { type ArtifactListOptions, type ArtifactListResult, type ArtifactMeta, type ArtifactOrigin, type ArtifactRecord, type ArtifactRef, type ArtifactScope, type ArtifactStore, type PutArtifactInput, type SweptArtifact } from './types.js'; /** A tool's `put` — everything the caller owns EXCEPT `origin`, which the * framework stamps from the run's own facts (never invented, never spoofed). */ export type ToolArtifactPutInput = Omit; /** * The capability on `ctx.artifacts` — the store's five verbs with the scope * already answered. */ export interface ToolArtifacts { /** Store a payload under this run's scope; returns the claim ticket. */ put(input: ToolArtifactPutInput): Promise; /** The ticket without the payload. `null` for missing-or-expired. */ head(ref: ArtifactRef): Promise; /** Ticket + payload. `null` for missing-or-expired; a digest mismatch throws. */ get(ref: ArtifactRef): Promise; /** Remove one artifact this scope holds. */ delete(ref: ArtifactRef): Promise; /** Page through this scope's tickets, newest first. */ list(options?: ArtifactListOptions): Promise; } /** Which door a refusal happened at — the five verbs, plus `'dispatch'`: * the framework's own resolution of a tool's declared `wants` (and the * `present` tool's argument checks) BEFORE execute. Not a sixth store verb * — a dispatch refusal is the tool-calls stage declining to run a tool * whose declared data could not be delivered. */ export type ArtifactOp = 'put' | 'head' | 'get' | 'delete' | 'list' | 'dispatch'; /** Why a verb refused (or answered "no data" on the record). */ export type ArtifactRefusalReason = 'no-store' | 'missing-or-expired' | 'unknown-parent' | 'digest-mismatch' | 'invalid-input' /** A `wants` ref resolved, but to the wrong kind — the wrong parcel for * this ticket window (dispatch resolution only). */ | 'kind-mismatch'; /** One thing that happened at this door — meta only, never payloads. */ export type ArtifactEventFact = { readonly type: 'minted'; readonly meta: ArtifactMeta; } | { readonly type: 'resolved'; readonly ref: ArtifactRef; readonly via: 'head' | 'get'; readonly kind: string; readonly bytes: number; } | { readonly type: 'expired'; readonly swept: SweptArtifact; } | { readonly type: 'refused'; readonly op: ArtifactOp; readonly reason: ArtifactRefusalReason; readonly ref?: ArtifactRef; readonly detail?: string; }; /** Where facts go. The dispatch layer adapts this onto the typed events. */ export type ArtifactEventSink = (fact: ArtifactEventFact) => void; /** What `bindArtifacts` needs beyond the store and the scope. */ export interface BindArtifactsOptions { /** Stamped onto every mint — the run's own facts, absent when unknown. */ readonly origin?: ArtifactOrigin; /** Fact sink. Absent = silent binding (raw store semantics, no record). */ readonly onEvent?: ArtifactEventSink; } /** * Bind a store to one run's scope — the framework's move, made where the * scope is known and a tool cannot reach. */ export declare function bindArtifacts(store: ArtifactStore, scope: ArtifactScope, options?: BindArtifactsOptions): ToolArtifacts; /** * The fail-closed capability used when NO store is attached. Every verb * throws the same teaching refusal — loud, named, and on the record — so * `ctx.artifacts` is never `undefined` and a missing store can never read as * an empty one. Branch on `ctx.hasArtifacts` for an intentional no-store * mode. (The `unconfiguredCredentialProvider` law, verb for verb.) */ export declare function unconfiguredArtifacts(onEvent?: ArtifactEventSink): ToolArtifacts;