agentfootprint 9.77.0 → 9.79.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.
- package/CHANGELOG.md +189 -0
- package/CLAUDE.md +2 -1
- package/dist/artifacts/recordingArtifact.js +5 -1
- package/dist/artifacts/recordingArtifact.js.map +1 -1
- package/dist/core/Agent.js +50 -0
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/agent/stages/callLLM.js +14 -0
- package/dist/core/agent/stages/callLLM.js.map +1 -1
- package/dist/core/agent/stages/toolCalls.js +107 -0
- package/dist/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/core/runbook/index.js +3 -1
- package/dist/core/runbook/index.js.map +1 -1
- package/dist/core/runbook/recording.js +178 -0
- package/dist/core/runbook/recording.js.map +1 -0
- package/dist/core/runbook/runbookAsTool.js +45 -2
- package/dist/core/runbook/runbookAsTool.js.map +1 -1
- package/dist/core/tools.js +9 -1
- package/dist/core/tools.js.map +1 -1
- package/dist/esm/artifacts/recordingArtifact.d.ts +9 -0
- package/dist/esm/artifacts/recordingArtifact.js +5 -1
- package/dist/esm/artifacts/recordingArtifact.js.map +1 -1
- package/dist/esm/core/Agent.d.ts +7 -0
- package/dist/esm/core/Agent.js +50 -0
- package/dist/esm/core/Agent.js.map +1 -1
- package/dist/esm/core/agent/stages/callLLM.d.ts +11 -0
- package/dist/esm/core/agent/stages/callLLM.js +14 -0
- package/dist/esm/core/agent/stages/callLLM.js.map +1 -1
- package/dist/esm/core/agent/stages/toolCalls.d.ts +20 -0
- package/dist/esm/core/agent/stages/toolCalls.js +107 -0
- package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/esm/core/agent/types.d.ts +63 -0
- package/dist/esm/core/runbook/index.d.ts +2 -1
- package/dist/esm/core/runbook/index.js +1 -0
- package/dist/esm/core/runbook/index.js.map +1 -1
- package/dist/esm/core/runbook/recording.d.ts +123 -0
- package/dist/esm/core/runbook/recording.js +172 -0
- package/dist/esm/core/runbook/recording.js.map +1 -0
- package/dist/esm/core/runbook/runbookAsTool.d.ts +5 -1
- package/dist/esm/core/runbook/runbookAsTool.js +45 -2
- package/dist/esm/core/runbook/runbookAsTool.js.map +1 -1
- package/dist/esm/core/runbook/types.d.ts +88 -0
- package/dist/esm/core/tools.d.ts +63 -0
- package/dist/esm/core/tools.js +17 -0
- package/dist/esm/core/tools.js.map +1 -1
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.js +17 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/integrity/column-types/check.d.ts +156 -0
- package/dist/esm/integrity/column-types/check.js +363 -0
- package/dist/esm/integrity/column-types/check.js.map +1 -0
- package/dist/esm/integrity/column-types/types.d.ts +121 -0
- package/dist/esm/integrity/column-types/types.js +107 -0
- package/dist/esm/integrity/column-types/types.js.map +1 -0
- package/dist/esm/integrity/disposition/lifecycle.d.ts +16 -1
- package/dist/esm/integrity/disposition/lifecycle.js +30 -1
- package/dist/esm/integrity/disposition/lifecycle.js.map +1 -1
- package/dist/esm/integrity/finding/types.d.ts +14 -2
- package/dist/esm/integrity/finding/types.js.map +1 -1
- package/dist/esm/lib/mcp/toolExtras.d.ts +17 -2
- package/dist/esm/lib/mcp/toolExtras.js +5 -2
- package/dist/esm/lib/mcp/toolExtras.js.map +1 -1
- package/dist/esm/lib/trace-toolpack/traceToolpack.js +2 -0
- package/dist/esm/lib/trace-toolpack/traceToolpack.js.map +1 -1
- package/dist/index.js +23 -3
- package/dist/index.js.map +1 -1
- package/dist/integrity/column-types/check.js +368 -0
- package/dist/integrity/column-types/check.js.map +1 -0
- package/dist/integrity/column-types/types.js +112 -0
- package/dist/integrity/column-types/types.js.map +1 -0
- package/dist/integrity/disposition/lifecycle.js +30 -1
- package/dist/integrity/disposition/lifecycle.js.map +1 -1
- package/dist/integrity/finding/types.js.map +1 -1
- package/dist/lib/mcp/toolExtras.js +4 -1
- package/dist/lib/mcp/toolExtras.js.map +1 -1
- package/dist/lib/trace-toolpack/traceToolpack.js +2 -0
- package/dist/lib/trace-toolpack/traceToolpack.js.map +1 -1
- package/dist/types/artifacts/recordingArtifact.d.ts +9 -0
- package/dist/types/artifacts/recordingArtifact.d.ts.map +1 -1
- package/dist/types/core/Agent.d.ts +7 -0
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/core/agent/stages/callLLM.d.ts +11 -0
- package/dist/types/core/agent/stages/callLLM.d.ts.map +1 -1
- package/dist/types/core/agent/stages/toolCalls.d.ts +20 -0
- package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
- package/dist/types/core/agent/types.d.ts +63 -0
- package/dist/types/core/agent/types.d.ts.map +1 -1
- package/dist/types/core/runbook/index.d.ts +2 -1
- package/dist/types/core/runbook/index.d.ts.map +1 -1
- package/dist/types/core/runbook/recording.d.ts +124 -0
- package/dist/types/core/runbook/recording.d.ts.map +1 -0
- package/dist/types/core/runbook/runbookAsTool.d.ts +5 -1
- package/dist/types/core/runbook/runbookAsTool.d.ts.map +1 -1
- package/dist/types/core/runbook/types.d.ts +88 -0
- package/dist/types/core/runbook/types.d.ts.map +1 -1
- package/dist/types/core/tools.d.ts +63 -0
- package/dist/types/core/tools.d.ts.map +1 -1
- package/dist/types/index.d.ts +3 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/integrity/column-types/check.d.ts +157 -0
- package/dist/types/integrity/column-types/check.d.ts.map +1 -0
- package/dist/types/integrity/column-types/types.d.ts +122 -0
- package/dist/types/integrity/column-types/types.d.ts.map +1 -0
- package/dist/types/integrity/disposition/lifecycle.d.ts +16 -1
- package/dist/types/integrity/disposition/lifecycle.d.ts.map +1 -1
- package/dist/types/integrity/finding/types.d.ts +14 -2
- package/dist/types/integrity/finding/types.d.ts.map +1 -1
- package/dist/types/lib/mcp/toolExtras.d.ts +17 -2
- package/dist/types/lib/mcp/toolExtras.d.ts.map +1 -1
- package/dist/types/lib/trace-toolpack/traceToolpack.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,195 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [9.79.0] - 2026-08-30
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`walk: { recording }` — file the runbook's inner chart as a recording, so
|
|
15
|
+
the walk can actually be DRAWN.** A consumer wired the flow components of
|
|
16
|
+
the lens family to a runbook's answer and could not mount anything, and they
|
|
17
|
+
were right not to try. `runbookAsTool` files its walk as
|
|
18
|
+
`recording/chart-walk`, whose payload is a **row projection** — 129 rows of
|
|
19
|
+
`{step, type, depth, stage, stage_id, runtime_stage_id, subflow, text}`. A
|
|
20
|
+
step graph cannot be inferred from sentences about steps; a consumer handed
|
|
21
|
+
those rows can only correctly REFUSE to guess at the edges. The one piece
|
|
22
|
+
that makes a walk drawable is `structure`, the chart's build-time graph —
|
|
23
|
+
which a finished run does not leave behind and no snapshot carries.
|
|
24
|
+
|
|
25
|
+
Everything needed was already in the file, a few lines apart: the bridge
|
|
26
|
+
builds a fresh inner executor and ATTACHES RECORDERS (the run was recorded,
|
|
27
|
+
it simply was not filed), `recordingPutInput` was already the mint for the
|
|
28
|
+
agent's own run, `mintWalk` was already the guarded side effect that files
|
|
29
|
+
and never fails the answer, and `WalkDescriptor` was already where the spine
|
|
30
|
+
states what it filed. This connects them.
|
|
31
|
+
|
|
32
|
+
Declare `walk: { recording: true }` (or `{ label, maxBytes }`) and the inner
|
|
33
|
+
chart's own **`{ snapshot, events, structure }`** — the `recordRun` contract
|
|
34
|
+
exactly, the shape `observeRecording()` mounts — is filed under the existing
|
|
35
|
+
kind `recording/run`, and its ref rides the SAME spine descriptor as
|
|
36
|
+
`result.walk.recording_ref` beside `recording_kind`, `recording_bytes` and
|
|
37
|
+
`recording_note`. The wire ops that already redeem the walk redeem this with
|
|
38
|
+
**zero new operations**.
|
|
39
|
+
|
|
40
|
+
**OPT-IN, and that is the honest default.** A walk carries *sentences about*
|
|
41
|
+
what happened and no payload from it — values are off by construction
|
|
42
|
+
(`narrative({ includeValues: false })`). A recording is the run: shared
|
|
43
|
+
state, the whole commit log, every attached recorder's data — **whatever the
|
|
44
|
+
chart wrote**. Filing one is a materially bigger promise, so it is declared,
|
|
45
|
+
never begun on an operator's behalf. Unset, nothing extra runs — no second
|
|
46
|
+
snapshot, no bytes measured, no store call — and the envelope is
|
|
47
|
+
byte-identical to 9.78.0, pinned by a test that asserts no `recording_*` key
|
|
48
|
+
exists at all. A reader who never asked for a recording does not even get a
|
|
49
|
+
sentence explaining its absence.
|
|
50
|
+
|
|
51
|
+
**Redaction means the same for both artifacts.** The recording's snapshot is
|
|
52
|
+
read from the REDACTED MIRROR (`getSnapshot({ redact: true })`), never the
|
|
53
|
+
raw working memory — so the `redact` policy that scrubs the walk scrubs the
|
|
54
|
+
recording by the same rule at the same moment, and a redacted key travels as
|
|
55
|
+
`REDACTED` rather than vanishing (a reader sees that a value existed and was
|
|
56
|
+
scrubbed). With no policy configured the flag is a documented no-op.
|
|
57
|
+
|
|
58
|
+
**Size has a declared failure mode, and it is a refusal.** Over
|
|
59
|
+
`walk.recording.maxBytes` (default `DEFAULT_RECORDING_MAX_BYTES` =
|
|
60
|
+
5,000,000 — a walk is tens of KB, this package's own measured `recordRun`
|
|
61
|
+
bundle was 2.76 MB, a fleet sweep is unbounded) the recording is **not filed
|
|
62
|
+
and not truncated**, and `recording_note` names what it measured, the
|
|
63
|
+
ceiling it broke, and the option that raises it. The asymmetry with the
|
|
64
|
+
walk's row cap is the point: walk rows are independently meaningful so a
|
|
65
|
+
projection of them is still true, but `{ snapshot, events, structure }` is
|
|
66
|
+
one bundle — half a commit log under a whole chart draws a picture nobody
|
|
67
|
+
can check.
|
|
68
|
+
|
|
69
|
+
**The absence is always SPOKEN.** No store, an over-size refusal, an
|
|
70
|
+
unserializable snapshot, a store that threw — each costs the REF and lands a
|
|
71
|
+
named reason in `recording_note`, following `mintWalk`'s own law. A missing
|
|
72
|
+
ref with no sentence would leave a reader guessing, which is the one thing
|
|
73
|
+
the spine exists to prevent.
|
|
74
|
+
|
|
75
|
+
**`events` is empty by construction, and says so.** It is the typed
|
|
76
|
+
*agentfootprint* stream, fired by an agent turn; what ran here is a
|
|
77
|
+
footprintjs chart on its own executor, which fires none. All three keys are
|
|
78
|
+
present (that is what a viewer reads), the empty array is the honest count,
|
|
79
|
+
and the note states it so nobody reads it as a dropped stream — the walk's
|
|
80
|
+
own story rides `snapshot`, where the narrative recorder's data already
|
|
81
|
+
lives.
|
|
82
|
+
|
|
83
|
+
- **`recordingPutInput` accepts `toolCallId`** — stamped on `origin.toolCallId`
|
|
84
|
+
the way `chartWalkPutInput` already did. A walk and the recording it projects
|
|
85
|
+
are two views of ONE tool call, so they carry the same join key, and either
|
|
86
|
+
joins back to the call the model made. Absent for an agent's own run
|
|
87
|
+
recording, which is a whole turn and belongs to no single call.
|
|
88
|
+
|
|
89
|
+
## [9.78.0] - 2026-08-30
|
|
90
|
+
|
|
91
|
+
### Added
|
|
92
|
+
|
|
93
|
+
- **`Tool.resultColumns` + `checkColumnTypes` — the column-type contract: a
|
|
94
|
+
tool declares what its rows contain, and the library checks the rows against
|
|
95
|
+
it at the boundary.** Three recorded failures, and they are one shape — *a
|
|
96
|
+
number became something else, and nothing noticed at the seam*:
|
|
97
|
+
|
|
98
|
+
1. A mapping report wrote `str(m.get("logical_unit_number") or "")`. **LUN 0
|
|
99
|
+
is falsy**, so LUN 0 was stored as an EMPTY STRING on 2,094 mappings, and
|
|
100
|
+
a host group missing the LUN an initiator probes first became
|
|
101
|
+
indistinguishable from one that had it.
|
|
102
|
+
2. A capacity view rendered `round(mib / 1024, 1)`, so an 8 MiB disk came out
|
|
103
|
+
as `0.0 GB` — which reads as NO DISK, a provisioning failure, during a
|
|
104
|
+
live incident.
|
|
105
|
+
3. A whole family of tools returned their numbers as quoted strings
|
|
106
|
+
(`"1240"`), which silently blanked every chart, because nothing downstream
|
|
107
|
+
could tell a measure from a label.
|
|
108
|
+
|
|
109
|
+
Every rail passed, honestly, in all three: nothing errored, nothing was
|
|
110
|
+
ungrounded. The library already lets a tool declare what its result IS
|
|
111
|
+
(`resultKind`, 9.70.0); it did not let a tool declare what its result
|
|
112
|
+
CONTAINS, so a rowset had nothing to be wrong against — and every consumer
|
|
113
|
+
downstream was left SNIFFING types out of the data, where one stray `''`
|
|
114
|
+
demotes a numeric column to text in silence.
|
|
115
|
+
|
|
116
|
+
`resultColumns` is the sibling declaration: a column-name → type map, on
|
|
117
|
+
`Tool` beside `resultKind`. Types are `number` / `string` / `boolean` /
|
|
118
|
+
`date` — **the vocabulary this ecosystem's rowset consumers already sniff
|
|
119
|
+
their way to**, not a new one. The one word deliberately left behind is
|
|
120
|
+
`'unknown'`: a sniffer needs it ("I could not tell"), a declaration has no
|
|
121
|
+
use for it. A column maps to a bare word or to `{ type, nullable }` (the
|
|
122
|
+
`CostBudget` two-spellings pattern, normalized once).
|
|
123
|
+
|
|
124
|
+
**THE CEILING**, exported as `COLUMN_TYPE_CEILING` and quoted verbatim into
|
|
125
|
+
every finding, the `EMPTY_LOOKUP_CEILING` law: *"This judges TYPE, never
|
|
126
|
+
MEANING — it can see that a column declared `number` holds a string, and it
|
|
127
|
+
can never see that the string should have been 0, or that a 0.0 should have
|
|
128
|
+
been an 8; a column whose every value has its declared type passes here and
|
|
129
|
+
can still be wrong."* Failures 1 and 3 are caught. **Failure 2 is not, and
|
|
130
|
+
never will be** — `0.0` is a perfectly good number — and the check says so
|
|
131
|
+
out loud rather than letting a green row imply otherwise.
|
|
132
|
+
|
|
133
|
+
**TWO finding kinds, because the field bug turned on the difference.** New
|
|
134
|
+
`ContextErrorKind`s at the **write seam**: **`column-type-mismatch`** (the
|
|
135
|
+
column is THERE and holds the wrong thing) and **`missing-column`** (the
|
|
136
|
+
declared column is in NONE of the rows). *"The value is not what it should
|
|
137
|
+
be"* sends a person to the mapping code; *"the column was never delivered"*
|
|
138
|
+
sends them to the query. A checker that said only "something is off with
|
|
139
|
+
logical_unit_number" would have helped with neither. Each finding names the
|
|
140
|
+
column, the offending value quoted, the rows affected of the rows read, and
|
|
141
|
+
the tool.
|
|
142
|
+
|
|
143
|
+
**OPEN, never closed.** A declaration is a promise about what it NAMES — an
|
|
144
|
+
unlisted column is allowed and never judged. A closed schema would punish the
|
|
145
|
+
wrong party the day a backend adds a column, and it is the rule the
|
|
146
|
+
neighbouring boundary (`toolArgsValidation`) already keeps.
|
|
147
|
+
|
|
148
|
+
**`nullable`, and what "no value" means.** `null`, `undefined` and a key not
|
|
149
|
+
set on a row are one idea with three spellings, and by default all three are
|
|
150
|
+
violations; `nullable: true` legitimizes them and every finding about an
|
|
151
|
+
absence names that one-word fix in its own message. `nullable` is a promise
|
|
152
|
+
about VALUES, not about the column's existence: a declared column in no row
|
|
153
|
+
at all is `missing-column` regardless.
|
|
154
|
+
|
|
155
|
+
**The dial: `AgentOptions.checkColumnTypes`, default `'off'`** —
|
|
156
|
+
`'off'` | `'warn'` | `'enforce'`. **The three words are borrowed, not
|
|
157
|
+
minted:** this boundary is the MIRROR of `toolArgsValidation` (arguments in,
|
|
158
|
+
against `inputSchema`; rows out, against `resultColumns`), and two validators
|
|
159
|
+
at one seam grading themselves in different vocabularies would be a worse
|
|
160
|
+
defect than either could catch — so there is no new `assist`/`guard`/`rails`
|
|
161
|
+
trio here and no new `observe`/`warn`/`refuse` one either. `'warn'` files
|
|
162
|
+
findings and the model reads the rows **exactly** as the tool returned them.
|
|
163
|
+
`'enforce'` REFUSES in the library's own refusal idiom — the `resultCeiling`
|
|
164
|
+
teaching sentence ("…Fix the tool so the column holds what it declares, or
|
|
165
|
+
change the declaration. No data was returned."), the whole payload on every
|
|
166
|
+
channel, delivered status `'invalid'`, never a thrown stack trace.
|
|
167
|
+
|
|
168
|
+
**What it refuses to judge** (`readRowset`): a result is read only when it is
|
|
169
|
+
an ARRAY OF PLAIN OBJECTS with at least one row. Prose, a `null`, a bespoke
|
|
170
|
+
`{ rows: [...] }` wrapper, a claim ticket — and the **zero-row** result,
|
|
171
|
+
which has no columns to be wrong about and is `empty-lookup`'s subject next
|
|
172
|
+
door — all file an explicit `not-applicable` ROW and no finding. Filing
|
|
173
|
+
`missing-column` for every declared column of an empty answer would turn one
|
|
174
|
+
honest emptiness into a pile of false accusations.
|
|
175
|
+
|
|
176
|
+
**Armed by two halves**: the dial off `'off'` **and** at least one tool
|
|
177
|
+
declaring `resultColumns`. Absent either, the run is byte-identical — no
|
|
178
|
+
finding, no event, nothing on the wire, and a declaring tool with the dial
|
|
179
|
+
off runs byte-for-byte the run it ran before the declaration existed. The one
|
|
180
|
+
visible difference is the two registered rows in the disposition report,
|
|
181
|
+
filed `not-applicable`: registered-but-unarmed is a ROW, never silence.
|
|
182
|
+
|
|
183
|
+
**Travels MCP `_meta`** like the library's other tool declarations, both
|
|
184
|
+
directions — a remote catalogue is exactly where a numeric column arriving as
|
|
185
|
+
text goes unnoticed, and leaving the declaration behind would arm the check
|
|
186
|
+
for local tools while leaving every MCP tool a second-class citizen of it. A
|
|
187
|
+
malformed declaration from a foreign server is warned about once and dropped;
|
|
188
|
+
the tool still registers.
|
|
189
|
+
|
|
190
|
+
Exports: `COLUMN_TYPE_CEILING`, `COLUMN_TYPES`, `readRowset`,
|
|
191
|
+
`assertResultColumns`, and the types `ColumnType`, `ColumnDeclaration`,
|
|
192
|
+
`ToolResultColumns`, `ColumnCheckMode`, `ColumnViolation`, `RowsetReading`.
|
|
193
|
+
Docs: `docs-next` → Monitor → Column Types, which also names the three
|
|
194
|
+
existing consumers this declaration feeds (chart axis pickers that sniff, the
|
|
195
|
+
panel deciding table-vs-chart by inference, and `compute` staging rows blind)
|
|
196
|
+
— none of those integrations are built here, they are named so the next
|
|
197
|
+
person does not add an eighth sniffer.
|
|
198
|
+
|
|
10
199
|
## [9.77.0] - 2026-08-29
|
|
11
200
|
|
|
12
201
|
### Added
|
package/CLAUDE.md
CHANGED
|
@@ -17,7 +17,7 @@ not in this table, search `src/index.ts` for the nearest noun before writing cod
|
|
|
17
17
|
|
|
18
18
|
| If you are about to build… | It is | Where | Since |
|
|
19
19
|
|---|---|---|---|
|
|
20
|
-
| turning a written operational procedure (a runbook, a triage playbook) into ONE agent tool whose every answer is EVIDENCE — coverage folded up from the inner tools it calls, rule name+version, verdict rows with GENERATED meanings, and the recorded walk as an artifact ticket, never bytes | `runbookAsTool` — dials: `procedure` (factory, invoked per call with `ctx.tools`) + `resultKind` (`'verdict/*'` arms the rowset projection; anything else ships spine + the chart's `report`) + `rules {name, version}` (default absent ⇒ `rule_version: 'undeclared'`) + `verdicts {decider, maxRows}` (default 50) + `walk {cap}` (default 500; over-cap ⇒ control-flow projection, declared) + `composedOf` (drift-checked at agent BUILD) + kept `recorders`/`keepRecord`/`keepRecordLimit`/`redact`; reserved state keys `verdicts`/`coverage`/`report` (the `report` bag lands BESIDE the spine, never over it — a report field spelling `af_coverage`/`af_provenance`/`rule_version`/`walk`/`report_note` or a live projection key is discarded and NAMED in `result.report_note`; precedence is explicit in `report.ts`, never spread order); inner `absent()` passes through VERBATIM unless the call said `allowAbsent`; walk kind `recording/chart-walk` + `walk_segment` discriminant | `src/core/runbook/` | 9.76.0 |
|
|
20
|
+
| turning a written operational procedure (a runbook, a triage playbook) into ONE agent tool whose every answer is EVIDENCE — coverage folded up from the inner tools it calls, rule name+version, verdict rows with GENERATED meanings, and the recorded walk as an artifact ticket, never bytes | `runbookAsTool` — dials: `procedure` (factory, invoked per call with `ctx.tools`) + `resultKind` (`'verdict/*'` arms the rowset projection; anything else ships spine + the chart's `report`) + `rules {name, version}` (default absent ⇒ `rule_version: 'undeclared'`) + `verdicts {decider, maxRows}` (default 50) + `walk {cap, recording}` (cap default 500; over-cap ⇒ control-flow projection, declared · `recording: true` or `{label, maxBytes}`, default OFF — ALSO files the inner chart's own `{snapshot, events, structure}` under `recording/run` and puts its ref on the spine as `walk.recording_ref`, because the ROW projection cannot be drawn; snapshot read from the REDACTED mirror so one `redact` means the same for both; over `maxBytes` (`DEFAULT_RECORDING_MAX_BYTES` = 5,000,000) it is REFUSED not truncated; every absence — no store / over size / unserializable / store threw — is STATED in `walk.recording_note`, and the four `recording_*` fields are absent entirely when the dial is off) + `composedOf` (drift-checked at agent BUILD) + kept `recorders`/`keepRecord`/`keepRecordLimit`/`redact`; reserved state keys `verdicts`/`coverage`/`report` (the `report` bag lands BESIDE the spine, never over it — a report field spelling `af_coverage`/`af_provenance`/`rule_version`/`walk`/`report_note` or a live projection key is discarded and NAMED in `result.report_note`; precedence is explicit in `report.ts`, never spread order); inner `absent()` passes through VERBATIM unless the call said `allowAbsent`; walk kind `recording/chart-walk` + `walk_segment` discriminant | `src/core/runbook/` | 9.76.0, recording 9.79.0 |
|
|
21
21
|
| calling ANOTHER registered tool from inside a tool's `execute` — composition over the agent's own dispatch map instead of importing the module and building a second query stack | `agentToolDispatch` + `ctx.tools` (ToolDispatch has/call) — sees static and skill-carried tools, NEVER ToolProvider-delivered ones (no build-time list, the 9.72.0 caveat); inner calls get the outer facts with hasArtifacts false and a derived toolCallId, `needs` resolved fail-closed non-interactively, `checkIn` and `wants` tools refused by name, no nested dispatch; declare ingredients via `composedOf` (and `gates` for a pausing procedure) — both travel MCP `_meta` | `src/core/agent/toolDispatch.ts` | 9.76.0 |
|
|
22
22
|
| a tool returning numbers WITH the caveats that make them honest — interval/aggregation grain, is-it-a-counter, when the world was measured, which ground was NOT covered — as typed data the model reads compactly and the record keeps whole | `semantic()` + `tools.semantics_declared` (model sees `semanticsForModel` projection; `coverage` field absorbed by the coverage()/absent() channel) | `src/lib/semantics/` | 9.53.0 |
|
|
23
23
|
| a build gate that refuses a triage/inventory tool that forgot its caveats, by tool name and field name | `checkSemantics` + `defineTool({ resultClass })` (`'triage'`/`'inventory'`, the closed set) + bin `agentfootprint-check-semantics` | `src/lib/semantics/check.ts` | 9.53.0 |
|
|
@@ -52,6 +52,7 @@ not in this table, search `src/index.ts` for the nearest noun before writing cod
|
|
|
52
52
|
| the model inventing an id or a reading that no tool ever returned — a deterministic fabrication detector on the final answer, with a posture for how hard it pushes back | `.namesAndNumbersFromEvidence()` + `posture` (`'assist'` record+flag, the default / `'guard'` one revision then ship flagged / `'rails'` refuse instead) + `shapes` + `exempt` + `minDigits` (default 4) + `nudge` (default off) | `src/core/agent/evidence/` | 9.35.0 |
|
|
53
53
|
| counting a HUMAN-VERIFIED value as ground for the choice-seam check — the person clicked a row, the app verified the cells against the artifact, and the id the model takes from that selection is not fabricated; the source label travels onto the record | `externalGrounds` + `ExternalGround` + `external_ground_used` | `src/integrity/unsupported-argument/check.ts` | 9.72.0 |
|
|
54
54
|
| a lookup tool that answers "nothing found" for EVERY id because a filter broke, and an agent reporting that absence as fact — the run itself produced the id, the lookup came back empty, and that PAIR is worth a look | `noticeEmptyLookups` + `readLookupResult` + `EMPTY_LOOKUP_CEILING` (dial default OFF and needs a tool declaring `argumentsFrom` too — two halves; kind `empty-lookup` at seam `write`, always `advisory: true`; empty = a zero-length ARRAY or an `absent()` envelope, every other shape files `not-applicable` and no finding; the ceiling is quoted verbatim into every message) | `src/integrity/empty-lookup/` | 9.77.0 |
|
|
55
|
+
| a tool's ROWS quietly disagreeing with what the tool promised — a LUN 0 stored as `""` because it is falsy, a numeric column arriving as quoted strings, a declared column present in no row at all | `Tool.resultColumns` + `checkColumnTypes` + `COLUMN_TYPE_CEILING` + `readRowset` (dial `'off'` (default) / `'warn'` (file findings, model reads the rows unchanged) / `'enforce'` (refuse the rows, `resultCeiling`'s teaching-sentence idiom, delivered status `'invalid'`) — the `toolArgsValidation` trio, this seam's mirror; needs a tool declaring `resultColumns` too — two halves; types `number`/`string`/`boolean`/`date`, bare word or `{type, nullable}`, deliberately NO `'unknown'`; OPEN — unlisted columns allowed and unjudged; TWO kinds at seam `write` — `column-type-mismatch` (there, wrong type) vs `missing-column` (declared, in no row); rowset = an ARRAY OF PLAIN OBJECTS with ≥1 row, everything else incl. the ZERO-ROW result files `not-applicable` (empty is `empty-lookup`'s subject); travels MCP `_meta`; the ceiling is quoted verbatim into every message) | `src/integrity/column-types/` | 9.78.0 |
|
|
55
56
|
| a model head-mathing a total from tool-result numbers while a compute tool sits unused on the wire — a LATE line each iteration naming the staged refs and the `wants` tool that spends them (recency working FOR the instruction), plus the revise correction naming the same route | `nudge: true` (default off) + `stagedRefsNudgeLine` + `findStagedRefs` + `grounding_nudged` | `src/core/agent/stagedRefs.ts` | 9.75.0 |
|
|
56
57
|
| a tool answering "I looked and found nothing", routably | `absent` + `looked_for` + `checked`/`not_checked`/`cannot_cover` + `tryInstead` (delivered status `'absent'`, routable by `onToolStatus`) | `src/core/agent/coverage/absent.ts` | 9.43.0 |
|
|
57
58
|
| stating what a clean answer does NOT rule out | `coverage` + the declaration `{ checked, not_checked?, cannot_cover? }` | `src/core/agent/coverage/ledger.ts` | 9.43.0 |
|
|
@@ -84,12 +84,16 @@ function recordingPutInput(recording, facts = {}) {
|
|
|
84
84
|
if (text === '') {
|
|
85
85
|
throw new UnserializableRecordingError('it serializes to nothing');
|
|
86
86
|
}
|
|
87
|
+
const origin = {
|
|
88
|
+
...(facts.runId !== undefined && { runId: facts.runId }),
|
|
89
|
+
...(facts.toolCallId !== undefined && { toolCallId: facts.toolCallId }),
|
|
90
|
+
};
|
|
87
91
|
return {
|
|
88
92
|
kind: exports.RECORDING_ARTIFACT_KIND,
|
|
89
93
|
mediaType: exports.RECORDING_MEDIA_TYPE,
|
|
90
94
|
data: text,
|
|
91
95
|
label: facts.label ?? (facts.runId !== undefined ? `run ${facts.runId}` : 'run recording'),
|
|
92
|
-
...(
|
|
96
|
+
...(Object.keys(origin).length > 0 && { origin }),
|
|
93
97
|
};
|
|
94
98
|
}
|
|
95
99
|
exports.recordingPutInput = recordingPutInput;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recordingArtifact.js","sourceRoot":"","sources":["../../src/artifacts/recordingArtifact.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;;;AAIH;oEACoE;AACvD,QAAA,uBAAuB,GAAG,eAAe,CAAC;AAEvD;;;;;;GAMG;AACU,QAAA,wBAAwB,GAAG,sBAAsB,CAAC;AAE/D,iDAAiD;AACpC,QAAA,oBAAoB,GAAG,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"recordingArtifact.js","sourceRoot":"","sources":["../../src/artifacts/recordingArtifact.ts"],"names":[],"mappings":"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"}
|
package/dist/core/Agent.js
CHANGED
|
@@ -315,6 +315,13 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
315
315
|
/** See AgentOptions.noticeEmptyLookups (9.77.0). Default false — absent is
|
|
316
316
|
* byte-identical, save for the registered not-applicable ledger row. */
|
|
317
317
|
noticeEmptyLookups = false;
|
|
318
|
+
/** Set at chart build: whether any tool in the FULL declared catalog
|
|
319
|
+
* declared `resultColumns` (9.78.0) — the other half of the column-type
|
|
320
|
+
* contract's arming. */
|
|
321
|
+
integrityColumnsPresent = false;
|
|
322
|
+
/** See AgentOptions.checkColumnTypes (9.78.0). Default 'off' — absent is
|
|
323
|
+
* byte-identical, save for the registered not-applicable ledger rows. */
|
|
324
|
+
checkColumnTypes = 'off';
|
|
318
325
|
/** See AgentOptions.externalGrounds (9.72.0). Absent = door closed,
|
|
319
326
|
* byte-identical behavior. */
|
|
320
327
|
externalGrounds;
|
|
@@ -675,6 +682,22 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
675
682
|
}
|
|
676
683
|
this.noticeEmptyLookups = opts.noticeEmptyLookups;
|
|
677
684
|
}
|
|
685
|
+
// The column-type contract's dial (9.78.0) — refused at construction for
|
|
686
|
+
// the same reason as the postures above, and with one more: `'enforce'`
|
|
687
|
+
// REFUSES tool results, so a misspelling silently downgraded to off would
|
|
688
|
+
// leave an operator believing a boundary is held that nothing is holding.
|
|
689
|
+
if (opts.checkColumnTypes !== undefined) {
|
|
690
|
+
if (opts.checkColumnTypes !== 'off' &&
|
|
691
|
+
opts.checkColumnTypes !== 'warn' &&
|
|
692
|
+
opts.checkColumnTypes !== 'enforce') {
|
|
693
|
+
throw new Error(`Agent: checkColumnTypes must be 'off', 'warn' or 'enforce', got ` +
|
|
694
|
+
`${JSON.stringify(opts.checkColumnTypes)}. It reads each tool's declared ` +
|
|
695
|
+
`\`resultColumns\` and judges the rows it returns: 'warn' files findings and ` +
|
|
696
|
+
`changes nothing the model reads; 'enforce' refuses the rows and hands the model a ` +
|
|
697
|
+
`teaching sentence instead. Omit it (or pass 'off') and nothing is ever measured.`);
|
|
698
|
+
}
|
|
699
|
+
this.checkColumnTypes = opts.checkColumnTypes;
|
|
700
|
+
}
|
|
678
701
|
// The claim-check seam (9.21.0). One store per agent, attached at
|
|
679
702
|
// construction — idempotent by shape: there is no second door to attach a
|
|
680
703
|
// competing one through, so "one per agent" is a fact of the type rather
|
|
@@ -2362,6 +2385,10 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
2362
2385
|
// TWO HALVES (9.77.0): the operator's dial AND a declaration to arm
|
|
2363
2386
|
// on. Either alone leaves a registered `not-applicable` row.
|
|
2364
2387
|
emptyLookup: this.noticeEmptyLookups && this.integrityDanglingPresent,
|
|
2388
|
+
// TWO HALVES (9.78.0), the same law: the operator's dial off `'off'`
|
|
2389
|
+
// AND a tool declaring `resultColumns`. Either alone leaves two
|
|
2390
|
+
// registered `not-applicable` rows.
|
|
2391
|
+
columnTypes: this.checkColumnTypes !== 'off' && this.integrityColumnsPresent,
|
|
2365
2392
|
}, this.integrityPosture);
|
|
2366
2393
|
}
|
|
2367
2394
|
/**
|
|
@@ -3092,6 +3119,14 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
3092
3119
|
.filter(([, tool]) => tool.argumentsFrom !== undefined)
|
|
3093
3120
|
.map(([name, tool]) => [name, tool.argumentsFrom]));
|
|
3094
3121
|
this.integrityDanglingPresent = toolGrounding.size > 0;
|
|
3122
|
+
// The column-type contract's declared half (9.78.0) — harvested from the
|
|
3123
|
+
// SAME catalog and with the same ToolProvider caveat, so an MCP-carried
|
|
3124
|
+
// `resultColumns` (which rides `_meta`) arms the check exactly as a
|
|
3125
|
+
// locally-defined one does.
|
|
3126
|
+
// `flatMap` rather than filter-then-assert: the narrowing is real here,
|
|
3127
|
+
// so the twin harvest above's non-null assertion is not inherited.
|
|
3128
|
+
const toolColumns = new Map([...registryByName.entries()].flatMap(([name, tool]) => tool.resultColumns === undefined ? [] : [[name, tool.resultColumns]]));
|
|
3129
|
+
this.integrityColumnsPresent = toolColumns.size > 0;
|
|
3095
3130
|
// The staged-refs join's other half (grounded numbers): `Tool.wants` by
|
|
3096
3131
|
// tool name, harvested the same way and with the same ToolProvider caveat.
|
|
3097
3132
|
// Consumed only by the evidence gate (the callLLM nudge and the recheck
|
|
@@ -3142,6 +3177,11 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
3142
3177
|
// runs where the result is. Value-conditional on BOTH halves, so an
|
|
3143
3178
|
// agent that never asked for it reads no new key.
|
|
3144
3179
|
...(this.noticeEmptyLookups && toolGrounding.size > 0 && { noticeEmptyLookups: true }),
|
|
3180
|
+
// The column-type contract's arming (9.78.0), same job and same
|
|
3181
|
+
// value-conditional law: this stage owns only the "no declaring tool
|
|
3182
|
+
// was called this response" not-applicable notes.
|
|
3183
|
+
...(this.checkColumnTypes !== 'off' &&
|
|
3184
|
+
toolColumns.size > 0 && { columnDeclaringTools: new Set(toolColumns.keys()) }),
|
|
3145
3185
|
integrityLedger: this.integrityLedgerHolder,
|
|
3146
3186
|
...(this.reliabilityConfig !== undefined && { reliability: this.reliabilityConfig }),
|
|
3147
3187
|
...(this.outputSchemaParser !== undefined && {
|
|
@@ -3246,6 +3286,16 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
3246
3286
|
emptyLookupGrounding: toolGrounding,
|
|
3247
3287
|
integrityLedger: this.integrityLedgerHolder,
|
|
3248
3288
|
}),
|
|
3289
|
+
// THE WRITE SEAM'S other check (9.78.0) — the column-type contract.
|
|
3290
|
+
// Value-conditional on both halves for the same reason, so an agent
|
|
3291
|
+
// that asked for neither hands the handler exactly the deps object it
|
|
3292
|
+
// always did.
|
|
3293
|
+
...(this.checkColumnTypes !== 'off' &&
|
|
3294
|
+
toolColumns.size > 0 && {
|
|
3295
|
+
columnDeclarations: toolColumns,
|
|
3296
|
+
columnCheckMode: this.checkColumnTypes,
|
|
3297
|
+
integrityLedger: this.integrityLedgerHolder,
|
|
3298
|
+
}),
|
|
3249
3299
|
...(this.externalToolProvider && { externalToolProvider: this.externalToolProvider }),
|
|
3250
3300
|
...(this.externalToolProvider && { providerToolCache }),
|
|
3251
3301
|
...(permissionChecker && { permissionChecker }),
|