UNPKG

agentfootprint

Version:

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

74 lines • 3.72 kB
/** * stampConversation — put the bundle's evidence in the archive contract, or * say in one sentence why it could not be. * * The repo has ONE archive contract (`RecordingEnvelope`) and several * presentations over it. This bundle used to be an exception: it packed a bare * `recording.json` plus an `environment.json` that repeated the producer facts * the envelope already stamps, so the same two versions were written by two * different pieces of code with no relationship between them. This is the fold * — the envelope is BUILT here, never re-implemented, so every rule it enforces * (identity is never invented, `droppedEvents` is proven or refused, an * incomplete recording gets no `endedAt`) arrives whole. * * ## Why a refusal is a return value here, not a throw * * `persistRecording` throws when a run fact is indeterminate, and it is right * to: its caller asked for an ARCHIVE, and an archive stamped with a guess is * worse than none. A bug report's caller asked for something else — the * evidence, in a zip, so a maintainer can open it. Throwing would leave that * person with no bundle at all because the library could not name a start time. * * So the refusal travels instead of stopping the export: this returns the * REASON, the bundle carries the bare recording under its own honest name, and * the manifest states which fact was missing and the one line that supplies it. * Nothing is stamped that was not known — which is the rule the throw exists to * keep — and the report still gets filed. * * @internal Not a public export; `exportBugReport` is the door. */ import { buildRecordingEnvelope, IndeterminateRunFactError, } from '../recorders/observability/recordingEnvelope.js'; /** * Envelope every recording of one conversation. * * @param sources the conversation's recordings, in order, each with whether it * can prove its own drop count. * @param facts what the reporter stated. `undefined` — the default, since * `run` is optional on both entry points — is itself a refusal * reason, and a named one. */ export function stampConversation(sources, facts) { if (facts === undefined || typeof facts.complete !== 'boolean') { return { field: 'complete', refusal: 'run.complete was not stated. Nothing in a frozen recording says whether it captured ' + 'the run through to its end — a crash-handler snapshot and a finished run look ' + 'identical — so the library asks rather than guessing, and defaulting it would make ' + 'every partial recording claim to be whole. Pass run: { complete: true } (or false) ' + 'to exportBugReport.', }; } const envelopes = []; for (const entry of sources) { try { envelopes.push(buildRecordingEnvelope(entry.source, { run: { complete: facts.complete, // A count the library can CHECK is never overridden by one it // cannot: a live handle knows what the cap discarded, so a stated // number is only offered for the sources that carry no count. ...(!entry.countsDrops && facts.droppedEvents !== undefined && { droppedEvents: facts.droppedEvents }), }, })); } catch (error) { if (error instanceof IndeterminateRunFactError) { return { refusal: error.message, field: error.field }; } throw error; } } return { envelopes }; } //# sourceMappingURL=envelope.js.map