agentfootprint 9.78.0 → 9.80.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +141 -0
  2. package/CLAUDE.md +1 -2
  3. package/dist/artifacts/recordingArtifact.js +5 -1
  4. package/dist/artifacts/recordingArtifact.js.map +1 -1
  5. package/dist/core/runbook/index.js +4 -1
  6. package/dist/core/runbook/index.js.map +1 -1
  7. package/dist/core/runbook/recording.js +178 -0
  8. package/dist/core/runbook/recording.js.map +1 -0
  9. package/dist/core/runbook/runbookAsTool.js +79 -5
  10. package/dist/core/runbook/runbookAsTool.js.map +1 -1
  11. package/dist/core/runbook/verdicts.js +24 -2
  12. package/dist/core/runbook/verdicts.js.map +1 -1
  13. package/dist/esm/artifacts/recordingArtifact.d.ts +9 -0
  14. package/dist/esm/artifacts/recordingArtifact.js +5 -1
  15. package/dist/esm/artifacts/recordingArtifact.js.map +1 -1
  16. package/dist/esm/core/runbook/index.d.ts +3 -2
  17. package/dist/esm/core/runbook/index.js +2 -1
  18. package/dist/esm/core/runbook/index.js.map +1 -1
  19. package/dist/esm/core/runbook/recording.d.ts +123 -0
  20. package/dist/esm/core/runbook/recording.js +172 -0
  21. package/dist/esm/core/runbook/recording.js.map +1 -0
  22. package/dist/esm/core/runbook/runbookAsTool.d.ts +12 -1
  23. package/dist/esm/core/runbook/runbookAsTool.js +80 -6
  24. package/dist/esm/core/runbook/runbookAsTool.js.map +1 -1
  25. package/dist/esm/core/runbook/types.d.ts +119 -2
  26. package/dist/esm/core/runbook/verdicts.d.ts +18 -1
  27. package/dist/esm/core/runbook/verdicts.js +23 -1
  28. package/dist/esm/core/runbook/verdicts.js.map +1 -1
  29. package/dist/esm/index.d.ts +1 -1
  30. package/dist/esm/index.js +6 -1
  31. package/dist/esm/index.js.map +1 -1
  32. package/dist/index.js +9 -3
  33. package/dist/index.js.map +1 -1
  34. package/dist/types/artifacts/recordingArtifact.d.ts +9 -0
  35. package/dist/types/artifacts/recordingArtifact.d.ts.map +1 -1
  36. package/dist/types/core/runbook/index.d.ts +3 -2
  37. package/dist/types/core/runbook/index.d.ts.map +1 -1
  38. package/dist/types/core/runbook/recording.d.ts +124 -0
  39. package/dist/types/core/runbook/recording.d.ts.map +1 -0
  40. package/dist/types/core/runbook/runbookAsTool.d.ts +12 -1
  41. package/dist/types/core/runbook/runbookAsTool.d.ts.map +1 -1
  42. package/dist/types/core/runbook/types.d.ts +119 -2
  43. package/dist/types/core/runbook/types.d.ts.map +1 -1
  44. package/dist/types/core/runbook/verdicts.d.ts +18 -1
  45. package/dist/types/core/runbook/verdicts.d.ts.map +1 -1
  46. package/dist/types/index.d.ts +1 -1
  47. package/dist/types/index.d.ts.map +1 -1
  48. package/package.json +1 -1
@@ -14,6 +14,13 @@
14
14
  * structured list is an invitation that gets accepted — rows come back
15
15
  * retyped with subtly wrong identifiers.
16
16
  *
17
+ * TWO SURFACES, TWO LAWS: a rowset does not always reach its reader through
18
+ * the model's prose. Where it does, the table ships pre-rendered and the model
19
+ * is told to output it verbatim (`VERDICT_RENDER_NOTE`); where the HOST draws
20
+ * the rowset itself, no table ships and the model is told the opposite
21
+ * (`PANEL_RENDER_NOTE`). The bridge cannot tell which client it is in, so the
22
+ * caller says — `presentation` on the options bag.
23
+ *
17
24
  * GENERATED MEANINGS, never hand-restated: `verdict_meanings` is composed
18
25
  * from (a) the named decider's declared branches in the chart's own structure
19
26
  * (branch description, falling back to branch name), overlaid by (b) the rule
@@ -23,13 +30,28 @@
23
30
  * covers every verdict an executed rule produced.
24
31
  */
25
32
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.composeMeanings = exports.meaningsRecorder = exports.resolveDecider = exports.renderVerdictTable = exports.verdictRowsOf = exports.DECLINED_VERDICT = exports.VERDICT_RENDER_NOTE = exports.DEFAULT_MAX_ROWS = void 0;
33
+ exports.composeMeanings = exports.meaningsRecorder = exports.resolveDecider = exports.renderVerdictTable = exports.verdictRowsOf = exports.DECLINED_VERDICT = exports.PANEL_RENDER_NOTE = exports.VERDICT_RENDER_NOTE = exports.DEFAULT_MAX_ROWS = void 0;
27
34
  /** Default cap on `verdicts` rows and the rendered table. */
28
35
  exports.DEFAULT_MAX_ROWS = 50;
29
- /** The render law, stated to the model beside every table. */
36
+ /** The render law when PROSE is the rowset's only surface (`presentation:
37
+ * 'prose'`, the default) — stated to the model beside the table. */
30
38
  exports.VERDICT_RENDER_NOTE = 'table is PRE-RENDERED over the same rows as `verdicts` — output it VERBATIM. Never ' +
31
39
  'retype an identifier from `verdicts`; a transcribed name that looks right and matches ' +
32
40
  'nothing is the failure this note exists to stop.';
41
+ /**
42
+ * The render law when the HOST renders the rowset (`presentation: 'panel'`) —
43
+ * stated to the model INSTEAD of a table, because there is none to ship.
44
+ *
45
+ * Same failure, opposite instruction. A rowset the reader can already see does
46
+ * not need retyping into prose; retyping it is how an identifier arrives
47
+ * subtly wrong beside a correct one on screen.
48
+ */
49
+ exports.PANEL_RENDER_NOTE = "the rows in `verdicts` are ALREADY on the reader's screen — this host renders the " +
50
+ 'rowset itself, so no table is shipped here. Do NOT reproduce those rows in prose in ' +
51
+ 'any form: not as a table, not as bullets, not as one sentence per row. When a finding ' +
52
+ 'names a row, quote the evidence sentence that row carries VERBATIM, and cite only the ' +
53
+ 'values the finding rests on, copied byte-for-byte. A retyped identifier that looks ' +
54
+ 'right and matches nothing is the failure this note exists to stop.';
33
55
  /** The reserved verdict word for "no classification was reached" — rows
34
56
  * carrying it are counted into the coverage ledger as not-checked ground
35
57
  * (the three-outcome honesty: reached, reached-and-clear, DECLINED). */
@@ -1 +1 @@
1
- {"version":3,"file":"verdicts.js","sourceRoot":"","sources":["../../../src/core/runbook/verdicts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"verdicts.js","sourceRoot":"","sources":["../../../src/core/runbook/verdicts.ts"],"names":[],"mappings":"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"}
@@ -50,6 +50,15 @@ export interface RecordingMintFacts {
50
50
  /** The run this recording is OF — stamped on `origin.runId`, which is the
51
51
  * join back to the trace. */
52
52
  readonly runId?: string;
53
+ /**
54
+ * The tool call this recording is OF, when a TOOL minted it (9.79.0) —
55
+ * stamped on `origin.toolCallId`, the join back to the call that produced
56
+ * it. Absent for an agent's own run recording, which is a whole turn and
57
+ * belongs to no single call. The `chartWalkPutInput` law, verbatim: a walk
58
+ * and the recording it projects are two views of ONE call, so they carry
59
+ * the same join key or a consumer cannot pair them.
60
+ */
61
+ readonly toolCallId?: string;
53
62
  /**
54
63
  * The operator's label, when they set one.
55
64
  *
@@ -80,12 +80,16 @@ export function recordingPutInput(recording, facts = {}) {
80
80
  if (text === '') {
81
81
  throw new UnserializableRecordingError('it serializes to nothing');
82
82
  }
83
+ const origin = {
84
+ ...(facts.runId !== undefined && { runId: facts.runId }),
85
+ ...(facts.toolCallId !== undefined && { toolCallId: facts.toolCallId }),
86
+ };
83
87
  return {
84
88
  kind: RECORDING_ARTIFACT_KIND,
85
89
  mediaType: RECORDING_MEDIA_TYPE,
86
90
  data: text,
87
91
  label: facts.label ?? (facts.runId !== undefined ? `run ${facts.runId}` : 'run recording'),
88
- ...(facts.runId !== undefined && { origin: { runId: facts.runId } }),
92
+ ...(Object.keys(origin).length > 0 && { origin }),
89
93
  };
90
94
  }
91
95
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"recordingArtifact.js","sourceRoot":"","sources":["../../../src/artifacts/recordingArtifact.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"recordingArtifact.js","sourceRoot":"","sources":["../../../src/artifacts/recordingArtifact.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,7 @@
4
4
  */
5
5
  export { runbookAsTool } from './runbookAsTool.js';
6
6
  export { absenceSignalOf, probeDispatch, recordingDispatch, RunbookAbsenceSignal, type InnerCallRecord, type RecordedDispatch, } from './dispatch.js';
7
- export { DECLINED_VERDICT, DEFAULT_MAX_ROWS, renderVerdictTable, VERDICT_RENDER_NOTE, verdictRowsOf, } from './verdicts.js';
7
+ export { DECLINED_VERDICT, DEFAULT_MAX_ROWS, PANEL_RENDER_NOTE, renderVerdictTable, VERDICT_RENDER_NOTE, verdictRowsOf, } from './verdicts.js';
8
8
  export { DEFAULT_WALK_CAP, projectWalk, type ProjectedWalk, type WalkRow } from './walk.js';
9
- export type { RunbookAsToolOptions, RunbookEnvelope, RunbookProcedure, RunbookRules, RunbookVerdictsOptions, RunbookWalkOptions, VerdictRow, WalkDescriptor, } from './types.js';
9
+ export { DEFAULT_RECORDING_MAX_BYTES } from './recording.js';
10
+ export type { RunbookAsToolOptions, RunbookEnvelope, RunbookPresentation, RunbookProcedure, RunbookRecordingOptions, RunbookRules, RunbookVerdictsOptions, RunbookWalkOptions, VerdictRow, WalkDescriptor, } from './types.js';
@@ -4,6 +4,7 @@
4
4
  */
5
5
  export { runbookAsTool } from './runbookAsTool.js';
6
6
  export { absenceSignalOf, probeDispatch, recordingDispatch, RunbookAbsenceSignal, } from './dispatch.js';
7
- export { DECLINED_VERDICT, DEFAULT_MAX_ROWS, renderVerdictTable, VERDICT_RENDER_NOTE, verdictRowsOf, } from './verdicts.js';
7
+ export { DECLINED_VERDICT, DEFAULT_MAX_ROWS, PANEL_RENDER_NOTE, renderVerdictTable, VERDICT_RENDER_NOTE, verdictRowsOf, } from './verdicts.js';
8
8
  export { DEFAULT_WALK_CAP, projectWalk } from './walk.js';
9
+ export { DEFAULT_RECORDING_MAX_BYTES } from './recording.js';
9
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/runbook/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EACL,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,oBAAoB,GAGrB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAoC,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/runbook/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EACL,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,oBAAoB,GAGrB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAoC,MAAM,WAAW,CAAC;AAC5F,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * runbook/recording — the inner chart's own recording, filed beside the walk.
3
+ *
4
+ * Pattern: one pure assembler (`chartRecordingOf`) + one guarded side effect
5
+ * (`mintChartRecording`, which files the artifact and NEVER fails the
6
+ * answer) — `walk.ts`'s shape, deliberately, because it is the same
7
+ * law about a different payload.
8
+ * Role: core/runbook. Opt-in via `walk: { recording }`.
9
+ * Emits: nothing (the artifact capability emits its own `artifacts.*`).
10
+ *
11
+ * WHY THIS EXISTS AT ALL
12
+ * ──────────────────────
13
+ * The walk is a ROW PROJECTION — eight declared columns per execution step,
14
+ * values off by construction. It is the right thing to hand a model and the
15
+ * wrong thing to hand a renderer: a step graph cannot be inferred from
16
+ * sentences about steps, and a consumer that tried would be guessing at edges.
17
+ * The one piece that makes a walk drawable is `structure`, the chart's
18
+ * build-time graph, which a finished run does not leave behind and no snapshot
19
+ * carries. That is the whole gap this closes, and it closes it with the shape
20
+ * the viewer side has consumed since 8.x: `{ snapshot, events, structure }`.
21
+ *
22
+ * THREE LAWS, and each one is a refusal somewhere
23
+ * ───────────────────────────────────────────────
24
+ * REDACTED AT THE SOURCE. The snapshot comes from `getSnapshot({ redact:
25
+ * true })` — the parallel redacted mirror — never the raw working memory.
26
+ * Whatever `redact` means for the walk means the same here, because it is
27
+ * the same policy read at the same moment; with no policy configured the
28
+ * flag is a documented no-op and costs nothing.
29
+ * REFUSED, NEVER TRUNCATED. Over the byte ceiling the mint does not happen
30
+ * and the descriptor says so with both numbers. A walk can be projected
31
+ * because its rows are independently meaningful; a recording is one
32
+ * bundle, and half of one draws a picture nobody can check.
33
+ * THE ABSENCE IS SPOKEN. No store, an over-size refusal, an unserializable
34
+ * snapshot, a store that 500s — every one of them costs the REF and
35
+ * returns a `recording_note` naming the reason. A failed mint has never
36
+ * been allowed to cost the answer, and this is not the feature that
37
+ * changes that.
38
+ *
39
+ * `events` IS EMPTY, BY CONSTRUCTION AND ON PURPOSE
40
+ * ────────────────────────────────────────────────
41
+ * `events` is the typed *agentfootprint* stream, and it is fired by an Agent
42
+ * turn. What ran here is a footprintjs chart on its own executor: it fires no
43
+ * agentfootprint events, so there are none to record and an empty array is the
44
+ * honest count rather than a shortfall. The three keys are all present, which
45
+ * is what `observeRecording()` reads; the walk's own story rides `snapshot`,
46
+ * where the narrative recorder's data already lives. The note says this out
47
+ * loud so nobody reads the empty array as a dropped stream.
48
+ */
49
+ import type { Recording } from '../../recorders/observability/recordRun.js';
50
+ import type { ToolExecutionContext } from '../tools.js';
51
+ /**
52
+ * The default size ceiling for a filed chart recording — 5,000,000 bytes.
53
+ *
54
+ * Chosen against measured sizes rather than taste. A walk of a real triage run
55
+ * is tens of kilobytes; this package's own field measurement of a full
56
+ * `recordRun` bundle (one retrieval turn, vectors included) was 2.76 MB. Five
57
+ * million bytes clears the realistic runbook by more than an order of
58
+ * magnitude and still refuses the pathological one — a fleet sweep whose
59
+ * commit log carries a row per subject per stage — BEFORE it lands in somebody
60
+ * else's store under a retention budget they sized for tickets.
61
+ *
62
+ * It is a declared number, not a magic one: it is named on the option, printed
63
+ * in the refusal, and raised by whoever decides the whole bundle is worth it.
64
+ */
65
+ export declare const DEFAULT_RECORDING_MAX_BYTES = 5000000;
66
+ /** The resolved recording policy — what `walk: { recording }` normalizes to. */
67
+ export interface ResolvedRecordingPolicy {
68
+ readonly maxBytes: number;
69
+ readonly label?: string;
70
+ }
71
+ /** What the recording mint needs from the call. */
72
+ export interface ChartRecordingMintFacts {
73
+ /** The runbook tool's name — names the default label. */
74
+ readonly toolName: string;
75
+ /** The OUTER tool call — `origin.toolCallId`, the join a consumer uses to
76
+ * pair this recording with the tool call that produced it (and with the
77
+ * walk minted beside it, which carries the same key). */
78
+ readonly toolCallId: string;
79
+ /** The outer run, when there is one — `origin.runId`. */
80
+ readonly runId?: string;
81
+ /** The resolved policy from `walk: { recording }`. */
82
+ readonly policy: ResolvedRecordingPolicy;
83
+ }
84
+ /**
85
+ * The recording fields spread onto the `WalkDescriptor`. `recording_note` is
86
+ * always present — this type exists to make "the absence is stated" a thing
87
+ * the compiler enforces rather than a thing a reviewer has to notice.
88
+ */
89
+ export interface RecordingDescriptorFields {
90
+ readonly recording_ref?: string;
91
+ readonly recording_kind?: string;
92
+ readonly recording_bytes?: number;
93
+ readonly recording_note: string;
94
+ }
95
+ /**
96
+ * Normalize `walk: { recording }` into a policy, or `undefined` for OFF.
97
+ *
98
+ * `undefined` and `false` are both off, and off means off: the caller must not
99
+ * take a second snapshot, measure anything, or touch the store.
100
+ */
101
+ export declare function resolveRecordingPolicy(recording: boolean | {
102
+ readonly label?: string;
103
+ readonly maxBytes?: number;
104
+ } | undefined): ResolvedRecordingPolicy | undefined;
105
+ /**
106
+ * Assemble the `{ snapshot, events, structure }` bundle for one inner chart
107
+ * run. Pure — no store, no clock, no events.
108
+ *
109
+ * @param redactedSnapshot the run snapshot read from the REDACTED mirror
110
+ * (`executor.getSnapshot({ redact: true })`). Taking the raw one here would
111
+ * file whatever the chart wrote under a policy that was supposed to scrub
112
+ * it, which is the one mistake this whole module is arranged to prevent.
113
+ * @param structure the chart's `buildTimeStructure` — the only route to a
114
+ * drawable graph, and the reason this bundle beats the row projection.
115
+ */
116
+ export declare function chartRecordingOf(redactedSnapshot: unknown, structure: unknown): Recording;
117
+ /**
118
+ * File the inner chart's recording and describe what happened.
119
+ *
120
+ * Called ONLY when `walk: { recording }` asked for one, and it never throws:
121
+ * every failure lands in `recording_note` and the answer travels unchanged.
122
+ */
123
+ export declare function mintChartRecording(ctx: ToolExecutionContext, recording: Recording, facts: ChartRecordingMintFacts): Promise<RecordingDescriptorFields>;
@@ -0,0 +1,172 @@
1
+ /**
2
+ * runbook/recording — the inner chart's own recording, filed beside the walk.
3
+ *
4
+ * Pattern: one pure assembler (`chartRecordingOf`) + one guarded side effect
5
+ * (`mintChartRecording`, which files the artifact and NEVER fails the
6
+ * answer) — `walk.ts`'s shape, deliberately, because it is the same
7
+ * law about a different payload.
8
+ * Role: core/runbook. Opt-in via `walk: { recording }`.
9
+ * Emits: nothing (the artifact capability emits its own `artifacts.*`).
10
+ *
11
+ * WHY THIS EXISTS AT ALL
12
+ * ──────────────────────
13
+ * The walk is a ROW PROJECTION — eight declared columns per execution step,
14
+ * values off by construction. It is the right thing to hand a model and the
15
+ * wrong thing to hand a renderer: a step graph cannot be inferred from
16
+ * sentences about steps, and a consumer that tried would be guessing at edges.
17
+ * The one piece that makes a walk drawable is `structure`, the chart's
18
+ * build-time graph, which a finished run does not leave behind and no snapshot
19
+ * carries. That is the whole gap this closes, and it closes it with the shape
20
+ * the viewer side has consumed since 8.x: `{ snapshot, events, structure }`.
21
+ *
22
+ * THREE LAWS, and each one is a refusal somewhere
23
+ * ───────────────────────────────────────────────
24
+ * REDACTED AT THE SOURCE. The snapshot comes from `getSnapshot({ redact:
25
+ * true })` — the parallel redacted mirror — never the raw working memory.
26
+ * Whatever `redact` means for the walk means the same here, because it is
27
+ * the same policy read at the same moment; with no policy configured the
28
+ * flag is a documented no-op and costs nothing.
29
+ * REFUSED, NEVER TRUNCATED. Over the byte ceiling the mint does not happen
30
+ * and the descriptor says so with both numbers. A walk can be projected
31
+ * because its rows are independently meaningful; a recording is one
32
+ * bundle, and half of one draws a picture nobody can check.
33
+ * THE ABSENCE IS SPOKEN. No store, an over-size refusal, an unserializable
34
+ * snapshot, a store that 500s — every one of them costs the REF and
35
+ * returns a `recording_note` naming the reason. A failed mint has never
36
+ * been allowed to cost the answer, and this is not the feature that
37
+ * changes that.
38
+ *
39
+ * `events` IS EMPTY, BY CONSTRUCTION AND ON PURPOSE
40
+ * ────────────────────────────────────────────────
41
+ * `events` is the typed *agentfootprint* stream, and it is fired by an Agent
42
+ * turn. What ran here is a footprintjs chart on its own executor: it fires no
43
+ * agentfootprint events, so there are none to record and an empty array is the
44
+ * honest count rather than a shortfall. The three keys are all present, which
45
+ * is what `observeRecording()` reads; the walk's own story rides `snapshot`,
46
+ * where the narrative recorder's data already lives. The note says this out
47
+ * loud so nobody reads the empty array as a dropped stream.
48
+ */
49
+ import { RECORDING_ARTIFACT_KIND, recordingPutInput } from '../../artifacts/recordingArtifact.js';
50
+ import { measureArtifactBytes } from '../../artifacts/payload.js';
51
+ /**
52
+ * The default size ceiling for a filed chart recording — 5,000,000 bytes.
53
+ *
54
+ * Chosen against measured sizes rather than taste. A walk of a real triage run
55
+ * is tens of kilobytes; this package's own field measurement of a full
56
+ * `recordRun` bundle (one retrieval turn, vectors included) was 2.76 MB. Five
57
+ * million bytes clears the realistic runbook by more than an order of
58
+ * magnitude and still refuses the pathological one — a fleet sweep whose
59
+ * commit log carries a row per subject per stage — BEFORE it lands in somebody
60
+ * else's store under a retention budget they sized for tickets.
61
+ *
62
+ * It is a declared number, not a magic one: it is named on the option, printed
63
+ * in the refusal, and raised by whoever decides the whole bundle is worth it.
64
+ */
65
+ export const DEFAULT_RECORDING_MAX_BYTES = 5_000_000;
66
+ /**
67
+ * Normalize `walk: { recording }` into a policy, or `undefined` for OFF.
68
+ *
69
+ * `undefined` and `false` are both off, and off means off: the caller must not
70
+ * take a second snapshot, measure anything, or touch the store.
71
+ */
72
+ export function resolveRecordingPolicy(recording) {
73
+ if (recording === undefined || recording === false)
74
+ return undefined;
75
+ if (recording === true)
76
+ return { maxBytes: DEFAULT_RECORDING_MAX_BYTES };
77
+ return {
78
+ maxBytes: recording.maxBytes ?? DEFAULT_RECORDING_MAX_BYTES,
79
+ ...(recording.label !== undefined && { label: recording.label }),
80
+ };
81
+ }
82
+ /**
83
+ * Assemble the `{ snapshot, events, structure }` bundle for one inner chart
84
+ * run. Pure — no store, no clock, no events.
85
+ *
86
+ * @param redactedSnapshot the run snapshot read from the REDACTED mirror
87
+ * (`executor.getSnapshot({ redact: true })`). Taking the raw one here would
88
+ * file whatever the chart wrote under a policy that was supposed to scrub
89
+ * it, which is the one mistake this whole module is arranged to prevent.
90
+ * @param structure the chart's `buildTimeStructure` — the only route to a
91
+ * drawable graph, and the reason this bundle beats the row projection.
92
+ */
93
+ export function chartRecordingOf(redactedSnapshot, structure) {
94
+ return { snapshot: redactedSnapshot, events: [], structure };
95
+ }
96
+ /** The standing sentence: what a FILED recording contains that the walk's row
97
+ * projection does not. This is the sentence that justifies the opt-in. */
98
+ const RECORDING_NOTE = "The inner chart's own recording — `{ snapshot, events, structure }`, the shape a viewer " +
99
+ 'mounts — so this walk can be drawn as the flowchart it actually ran. It carries what the ' +
100
+ 'row projection cannot: the chart STRUCTURE (the only route to a drawable graph; a finished ' +
101
+ "run does not leave it behind), the run's shared state, its whole commit log, and every " +
102
+ "attached recorder's data — that is, whatever the chart WROTE, scrubbed by this call's " +
103
+ '`redact` policy and by nothing else. `events` is empty by construction: a chart run is not ' +
104
+ 'an agent turn and fires no agentfootprint events, so there are none to record.';
105
+ /**
106
+ * File the inner chart's recording and describe what happened.
107
+ *
108
+ * Called ONLY when `walk: { recording }` asked for one, and it never throws:
109
+ * every failure lands in `recording_note` and the answer travels unchanged.
110
+ */
111
+ export async function mintChartRecording(ctx, recording, facts) {
112
+ if (!ctx.hasArtifacts) {
113
+ return {
114
+ recording_note: RECORDING_NOTE +
115
+ ' No artifact store is attached to this run, so the recording was assembled but not ' +
116
+ 'filed — attach one with `Agent.create({ ..., artifacts })` to get a ref here.',
117
+ };
118
+ }
119
+ // Serialize FIRST, then measure, then put: the mint is where an
120
+ // unserializable snapshot must fail (the `recordingPutInput` law), and the
121
+ // ceiling is judged on the bytes that would actually be stored rather than
122
+ // on a guess about them.
123
+ let input;
124
+ try {
125
+ input = recordingPutInput(recording, {
126
+ toolCallId: facts.toolCallId,
127
+ ...(facts.runId !== undefined && { runId: facts.runId }),
128
+ ...(facts.policy.label !== undefined
129
+ ? { label: facts.policy.label }
130
+ : { label: `${facts.toolName} recording` }),
131
+ });
132
+ }
133
+ catch (err) {
134
+ return {
135
+ recording_note: RECORDING_NOTE +
136
+ ` This one could not be serialized (${err instanceof Error ? err.message : String(err)}), ` +
137
+ 'so it was not filed — a recording JSON cannot carry could not cross any wire either. ' +
138
+ 'The failure cost the ref, never the answer.',
139
+ };
140
+ }
141
+ const bytes = measureArtifactBytes(input.data);
142
+ if (bytes > facts.policy.maxBytes) {
143
+ return {
144
+ recording_bytes: bytes,
145
+ recording_note: RECORDING_NOTE +
146
+ ` This one measured ${bytes} bytes, over the declared \`walk.recording.maxBytes\` ` +
147
+ `ceiling of ${facts.policy.maxBytes}, so it was NOT filed. It is refused rather than ` +
148
+ 'truncated on purpose: the walk can be projected because its rows are independently ' +
149
+ 'meaningful, but a recording is one bundle — half a commit log under a whole chart ' +
150
+ 'draws a picture nobody can check. Raise `walk.recording.maxBytes` if the whole thing ' +
151
+ 'is what you need. The walk above is unaffected.',
152
+ };
153
+ }
154
+ try {
155
+ const meta = await ctx.artifacts.put(input);
156
+ return {
157
+ recording_ref: meta.ref,
158
+ recording_kind: RECORDING_ARTIFACT_KIND,
159
+ recording_bytes: meta.bytes,
160
+ recording_note: RECORDING_NOTE,
161
+ };
162
+ }
163
+ catch (err) {
164
+ return {
165
+ recording_bytes: bytes,
166
+ recording_note: RECORDING_NOTE +
167
+ ` This one could not be filed (${err instanceof Error ? err.message : String(err)}) — ` +
168
+ 'the mint failure cost the ref, never the answer.',
169
+ };
170
+ }
171
+ }
172
+ //# sourceMappingURL=recording.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recording.js","sourceRoot":"","sources":["../../../../src/core/runbook/recording.ts"],"names":[],"mappings":"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"}
@@ -19,7 +19,11 @@
19
19
  * - `result.walk` — the recorded walk's descriptor. The walk itself
20
20
  * ships as an artifact ticket (kind `recording/chart-walk`), never as
21
21
  * bytes; when it does not fit, the CONTROL FLOW survives and the
22
- * projection is declared.
22
+ * projection is declared. Opt into `walk: { recording: true }` and the
23
+ * inner chart's own `{ snapshot, events, structure }` is filed beside
24
+ * it (kind `recording/run`) and its ref rides the SAME descriptor as
25
+ * `walk.recording_ref` — the row projection cannot be drawn, and this
26
+ * is what makes the walk mountable as the flowchart it ran.
23
27
  *
24
28
  * THE OPTIONAL PROJECTION (selected by `resultKind: 'verdict/*'`):
25
29
  * verdict rows off the chart's `verdicts` state key, capped with
@@ -27,6 +31,13 @@
27
31
  * `verdict_meanings` GENERATED from the decider's declared branches +
28
32
  * the rule labels this run's decide() evidence carried.
29
33
  *
34
+ * WHO RENDERS THE ROWSET (`presentation`, default `'prose'`): the bridge
35
+ * cannot see which client it is in, so the caller says. Under `'prose'`
36
+ * the model's words are the rowset's only surface — the table ships
37
+ * pre-rendered and is output verbatim. Under `'panel'` the host draws
38
+ * the rowset itself — no table ships, and the note says not to
39
+ * reproduce rows the reader is already looking at.
40
+ *
30
41
  * THREE OUTCOMES, honestly: a clean envelope; an inner ABSENCE passed
31
42
  * through verbatim (the framework still reads it as an absence); and
32
43
  * DECLINED rows counted into the ledger as not-checked ground.
@@ -19,7 +19,11 @@
19
19
  * - `result.walk` — the recorded walk's descriptor. The walk itself
20
20
  * ships as an artifact ticket (kind `recording/chart-walk`), never as
21
21
  * bytes; when it does not fit, the CONTROL FLOW survives and the
22
- * projection is declared.
22
+ * projection is declared. Opt into `walk: { recording: true }` and the
23
+ * inner chart's own `{ snapshot, events, structure }` is filed beside
24
+ * it (kind `recording/run`) and its ref rides the SAME descriptor as
25
+ * `walk.recording_ref` — the row projection cannot be drawn, and this
26
+ * is what makes the walk mountable as the flowchart it ran.
23
27
  *
24
28
  * THE OPTIONAL PROJECTION (selected by `resultKind: 'verdict/*'`):
25
29
  * verdict rows off the chart's `verdicts` state key, capped with
@@ -27,6 +31,13 @@
27
31
  * `verdict_meanings` GENERATED from the decider's declared branches +
28
32
  * the rule labels this run's decide() evidence carried.
29
33
  *
34
+ * WHO RENDERS THE ROWSET (`presentation`, default `'prose'`): the bridge
35
+ * cannot see which client it is in, so the caller says. Under `'prose'`
36
+ * the model's words are the rowset's only surface — the table ships
37
+ * pre-rendered and is output verbatim. Under `'panel'` the host draws
38
+ * the rowset itself — no table ships, and the note says not to
39
+ * reproduce rows the reader is already looking at.
40
+ *
30
41
  * THREE OUTCOMES, honestly: a clean envelope; an inner ABSENCE passed
31
42
  * through verbatim (the framework still reads it as an absence); and
32
43
  * DECLINED rows counted into the ledger as not-checked ground.
@@ -85,13 +96,25 @@ import { DEFAULT_INNER_RUN_LIMIT, INNER_RUN_RECORDS, innerRunStore, } from '../.
85
96
  import { defineTool } from '../tools.js';
86
97
  import { carriedProvenanceOf, chartCoverageOf, composeLedger, foldInnerCoverage, } from './coverage.js';
87
98
  import { absenceSignalOf, probeDispatch, recordingDispatch } from './dispatch.js';
99
+ import { chartRecordingOf, mintChartRecording, resolveRecordingPolicy } from './recording.js';
88
100
  import { admitReport, REPORT_NOTE_KEY, shadowedFieldsNote } from './report.js';
89
- import { composeMeanings, DECLINED_VERDICT, DEFAULT_MAX_ROWS, meaningsRecorder, renderVerdictTable, resolveDecider, VERDICT_RENDER_NOTE, verdictRowsOf, } from './verdicts.js';
101
+ import { composeMeanings, DECLINED_VERDICT, DEFAULT_MAX_ROWS, meaningsRecorder, PANEL_RENDER_NOTE, renderVerdictTable, resolveDecider, VERDICT_RENDER_NOTE, verdictRowsOf, } from './verdicts.js';
90
102
  import { DEFAULT_WALK_CAP, mintWalk, projectWalk } from './walk.js';
91
103
  /** The projection selector: a `resultKind` in the `verdict/` namespace gets
92
104
  * the rowset projection; every other kind ships the spine plus the chart's
93
105
  * own `report`. */
94
106
  const VERDICT_KIND_PREFIX = 'verdict/';
107
+ /** The presentations, as the dial spells them. */
108
+ const PRESENTATIONS = ['prose', 'panel'];
109
+ /**
110
+ * The projection's RESERVED VOCABULARY: the keys this run assembled, plus
111
+ * `table` — which `presentation: 'panel'` deliberately omits so that no table
112
+ * reaches the model at all. A `report` field spelling the freed name would put
113
+ * one straight back, so the mode's promise outranks the vacancy.
114
+ */
115
+ function reservedProjectionNames(projection) {
116
+ return projection === undefined ? [] : [...Object.keys(projection), 'table'];
117
+ }
95
118
  function bagOf(value) {
96
119
  return value !== null && typeof value === 'object' && !Array.isArray(value)
97
120
  ? value
@@ -149,10 +172,32 @@ export function runbookAsTool(opts) {
149
172
  `${String(maxRows)}.`);
150
173
  }
151
174
  }
175
+ if (opts.presentation !== undefined && !PRESENTATIONS.includes(opts.presentation)) {
176
+ throw new Error(`${label}: \`presentation\` names WHO renders the rowset — 'prose' (the default: the ` +
177
+ `model's prose is the rowset's only surface, so the pre-rendered table ships and is ` +
178
+ `output verbatim) or 'panel' (the host draws the rowset, so no table ships). Got ` +
179
+ `${JSON.stringify(opts.presentation)}.`);
180
+ }
152
181
  const cap = opts.walk?.cap;
153
182
  if (cap !== undefined && (!Number.isInteger(cap) || cap < 1)) {
154
183
  throw new Error(`${label}: \`walk.cap\` must be a whole number of rows, at least 1 — got ${String(cap)}.`);
155
184
  }
185
+ const recordingOpt = opts.walk?.recording;
186
+ if (recordingOpt !== undefined &&
187
+ typeof recordingOpt !== 'boolean' &&
188
+ (recordingOpt === null || typeof recordingOpt !== 'object' || Array.isArray(recordingOpt))) {
189
+ throw new Error(`${label}: \`walk.recording\` must be \`true\` (file the inner chart's recording with ` +
190
+ `the defaults), \`false\`/absent (do not file one), or an options bag ` +
191
+ `\`{ label?, maxBytes? }\` — got ${JSON.stringify(recordingOpt)}.`);
192
+ }
193
+ if (typeof recordingOpt === 'object' && recordingOpt !== null) {
194
+ const maxBytes = recordingOpt.maxBytes;
195
+ if (maxBytes !== undefined && (!Number.isInteger(maxBytes) || maxBytes < 1)) {
196
+ throw new Error(`${label}: \`walk.recording.maxBytes\` must be a whole number of bytes, at least 1 — ` +
197
+ `got ${String(maxBytes)}. It is the declared ceiling a recording is REFUSED over, ` +
198
+ `never truncated to.`);
199
+ }
200
+ }
156
201
  if (opts.keepRecordLimit !== undefined) {
157
202
  if (opts.keepRecord !== true) {
158
203
  throw new Error(`${label}: \`keepRecordLimit\` caps records that are never kept — add ` +
@@ -181,8 +226,14 @@ export function runbookAsTool(opts) {
181
226
  }
182
227
  const inputSchema = opts.inputSchema ?? liftInputSchema(probeChart);
183
228
  const isVerdictKind = opts.resultKind?.startsWith(VERDICT_KIND_PREFIX) === true;
229
+ const rendersItsOwnRows = opts.presentation === 'panel';
184
230
  const maxRows = opts.verdicts?.maxRows ?? DEFAULT_MAX_ROWS;
185
231
  const walkCap = opts.walk?.cap ?? DEFAULT_WALK_CAP;
232
+ // Resolved ONCE at definition. `undefined` is the whole off-switch: every
233
+ // line the recording feature adds sits behind this being defined, so an
234
+ // undeclared runbook takes no second snapshot, measures no bytes, and makes
235
+ // no store call — its envelope is byte-identical to 9.78.0.
236
+ const recordingPolicy = resolveRecordingPolicy(recordingOpt);
186
237
  const store = opts.keepRecord === true
187
238
  ? innerRunStore(opts.keepRecordLimit ?? DEFAULT_INNER_RUN_LIMIT)
188
239
  : undefined;
@@ -290,12 +341,29 @@ export function runbookAsTool(opts) {
290
341
  // ── The walk ────────────────────────────────────────────────────────
291
342
  const entries = walkRecorder.getEntries();
292
343
  const projected = projectWalk(entries, walkCap);
293
- const walk = await mintWalk(ctx, projected, {
344
+ const walkOnly = await mintWalk(ctx, projected, {
294
345
  toolName: opts.name,
295
346
  toolCallId: ctx.toolCallId,
296
347
  ...(ctx.runId !== undefined && { runId: ctx.runId }),
297
348
  stepsExecuted: walkRecorder.stepCount,
298
349
  });
350
+ // ── The recording, beside the walk (opt-in) ─────────────────────────
351
+ // The row projection cannot be drawn — `structure` is the only route to
352
+ // a drawable graph and no snapshot carries it. The snapshot here is the
353
+ // REDACTED mirror, not `raw`: the same `redact` policy that scrubs the
354
+ // walk must scrub this by the same rule, and `raw` is the live working
355
+ // memory. With no policy configured the flag is a documented no-op.
356
+ const walk = recordingPolicy === undefined
357
+ ? walkOnly
358
+ : {
359
+ ...walkOnly,
360
+ ...(await mintChartRecording(ctx, chartRecordingOf(executor.getSnapshot({ redact: true }), chart.buildTimeStructure), {
361
+ toolName: opts.name,
362
+ toolCallId: ctx.toolCallId,
363
+ ...(ctx.runId !== undefined && { runId: ctx.runId }),
364
+ policy: recordingPolicy,
365
+ })),
366
+ };
299
367
  // ── The projection (verdict kinds only) ─────────────────────────────
300
368
  let rows;
301
369
  let shown;
@@ -338,20 +406,26 @@ export function runbookAsTool(opts) {
338
406
  rule_version: opts.rules?.version ?? 'undeclared',
339
407
  walk,
340
408
  };
409
+ // The rowset half is the same in both presentations — the dial names who
410
+ // RENDERS the rows, never which rows there are. Only the surface differs:
411
+ // prose gets the pre-rendered table plus "output it verbatim"; a panel
412
+ // host gets no table and the opposite law, because the rows it would
413
+ // retype are already on the reader's screen.
341
414
  const projection = shown !== undefined && rows !== undefined
342
415
  ? {
343
416
  verdicts: shown,
344
417
  rows_shown: shown.length,
345
418
  rows_total: rows.length,
346
419
  rows_complete: shown.length === rows.length,
347
- table: renderVerdictTable(shown),
348
- render_note: VERDICT_RENDER_NOTE,
420
+ ...(rendersItsOwnRows
421
+ ? { render_note: PANEL_RENDER_NOTE }
422
+ : { table: renderVerdictTable(shown), render_note: VERDICT_RENDER_NOTE }),
349
423
  ...(meanings !== undefined && { verdict_meanings: meanings }),
350
424
  }
351
425
  : undefined;
352
426
  const report = admitReport(bagOf(state.report) ?? {}, [
353
427
  ...Object.keys(spine),
354
- ...Object.keys(projection ?? {}),
428
+ ...reservedProjectionNames(projection),
355
429
  ]);
356
430
  const envelope = {
357
431
  af_coverage: ledger,