agentfootprint 9.74.0 → 9.76.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/AGENTS.md +1 -1
- package/CHANGELOG.md +126 -0
- package/CLAUDE.md +24 -19
- package/ai-instructions/claude-code/SKILL.md +1 -1
- package/dist/artifacts/index.js +3 -1
- package/dist/artifacts/index.js.map +1 -1
- package/dist/artifacts/recordingArtifact.js +47 -1
- package/dist/artifacts/recordingArtifact.js.map +1 -1
- package/dist/core/Agent.js +53 -1
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/agent/AgentBuilder.js +12 -0
- package/dist/core/agent/AgentBuilder.js.map +1 -1
- package/dist/core/agent/evidence/gate.js +22 -3
- package/dist/core/agent/evidence/gate.js.map +1 -1
- package/dist/core/agent/stagedRefs.js +161 -0
- package/dist/core/agent/stagedRefs.js.map +1 -0
- package/dist/core/agent/stages/callLLM.js +22 -2
- package/dist/core/agent/stages/callLLM.js.map +1 -1
- package/dist/core/agent/stages/evidenceRecheck.js +21 -2
- package/dist/core/agent/stages/evidenceRecheck.js.map +1 -1
- package/dist/core/agent/stages/toolCalls.js +42 -0
- package/dist/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/core/agent/toolDispatch.js +101 -0
- package/dist/core/agent/toolDispatch.js.map +1 -0
- package/dist/core/flowchartAsTool.js +9 -2
- package/dist/core/flowchartAsTool.js.map +1 -1
- package/dist/core/runbook/coverage.js +162 -0
- package/dist/core/runbook/coverage.js.map +1 -0
- package/dist/core/runbook/dispatch.js +119 -0
- package/dist/core/runbook/dispatch.js.map +1 -0
- package/dist/core/runbook/index.js +24 -0
- package/dist/core/runbook/index.js.map +1 -0
- package/dist/core/runbook/runbookAsTool.js +358 -0
- package/dist/core/runbook/runbookAsTool.js.map +1 -0
- package/dist/core/runbook/types.js +22 -0
- package/dist/core/runbook/types.js.map +1 -0
- package/dist/core/runbook/verdicts.js +156 -0
- package/dist/core/runbook/verdicts.js.map +1 -0
- package/dist/core/runbook/walk.js +115 -0
- package/dist/core/runbook/walk.js.map +1 -0
- package/dist/core/tools.js +55 -1
- package/dist/core/tools.js.map +1 -1
- package/dist/esm/artifacts/index.d.ts +1 -1
- package/dist/esm/artifacts/index.js +1 -1
- package/dist/esm/artifacts/index.js.map +1 -1
- package/dist/esm/artifacts/recordingArtifact.d.ts +36 -0
- package/dist/esm/artifacts/recordingArtifact.js +45 -0
- package/dist/esm/artifacts/recordingArtifact.js.map +1 -1
- package/dist/esm/core/Agent.js +53 -1
- package/dist/esm/core/Agent.js.map +1 -1
- package/dist/esm/core/agent/AgentBuilder.d.ts +12 -0
- package/dist/esm/core/agent/AgentBuilder.js +12 -0
- package/dist/esm/core/agent/AgentBuilder.js.map +1 -1
- package/dist/esm/core/agent/evidence/gate.d.ts +11 -1
- package/dist/esm/core/agent/evidence/gate.js +22 -3
- package/dist/esm/core/agent/evidence/gate.js.map +1 -1
- package/dist/esm/core/agent/evidence/types.d.ts +23 -0
- package/dist/esm/core/agent/stagedRefs.d.ts +94 -0
- package/dist/esm/core/agent/stagedRefs.js +154 -0
- package/dist/esm/core/agent/stagedRefs.js.map +1 -0
- package/dist/esm/core/agent/stages/callLLM.d.ts +17 -0
- package/dist/esm/core/agent/stages/callLLM.js +22 -2
- package/dist/esm/core/agent/stages/callLLM.js.map +1 -1
- package/dist/esm/core/agent/stages/evidenceRecheck.d.ts +19 -1
- package/dist/esm/core/agent/stages/evidenceRecheck.js +21 -2
- package/dist/esm/core/agent/stages/evidenceRecheck.js.map +1 -1
- package/dist/esm/core/agent/stages/toolCalls.js +42 -0
- package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/esm/core/agent/toolDispatch.d.ts +50 -0
- package/dist/esm/core/agent/toolDispatch.js +97 -0
- package/dist/esm/core/agent/toolDispatch.js.map +1 -0
- package/dist/esm/core/flowchartAsTool.d.ts +6 -0
- package/dist/esm/core/flowchartAsTool.js +9 -2
- package/dist/esm/core/flowchartAsTool.js.map +1 -1
- package/dist/esm/core/runbook/coverage.d.ts +69 -0
- package/dist/esm/core/runbook/coverage.js +155 -0
- package/dist/esm/core/runbook/coverage.js.map +1 -0
- package/dist/esm/core/runbook/dispatch.d.ts +69 -0
- package/dist/esm/core/runbook/dispatch.js +112 -0
- package/dist/esm/core/runbook/dispatch.js.map +1 -0
- package/dist/esm/core/runbook/index.d.ts +9 -0
- package/dist/esm/core/runbook/index.js +9 -0
- package/dist/esm/core/runbook/index.js.map +1 -0
- package/dist/esm/core/runbook/runbookAsTool.d.ts +88 -0
- package/dist/esm/core/runbook/runbookAsTool.js +354 -0
- package/dist/esm/core/runbook/runbookAsTool.js.map +1 -0
- package/dist/esm/core/runbook/types.d.ts +196 -0
- package/dist/esm/core/runbook/types.js +21 -0
- package/dist/esm/core/runbook/types.js.map +1 -0
- package/dist/esm/core/runbook/verdicts.d.ts +78 -0
- package/dist/esm/core/runbook/verdicts.js +148 -0
- package/dist/esm/core/runbook/verdicts.js.map +1 -0
- package/dist/esm/core/runbook/walk.d.ts +72 -0
- package/dist/esm/core/runbook/walk.js +110 -0
- package/dist/esm/core/runbook/walk.js.map +1 -0
- package/dist/esm/core/tools.d.ts +112 -0
- package/dist/esm/core/tools.js +52 -0
- package/dist/esm/core/tools.js.map +1 -1
- package/dist/esm/events/payloads.d.ts +39 -0
- package/dist/esm/events/registry.d.ts +3 -1
- package/dist/esm/events/registry.js +2 -0
- package/dist/esm/events/registry.js.map +1 -1
- package/dist/esm/index.d.ts +4 -3
- package/dist/esm/index.js +19 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/mcp/toolExtras.d.ts +8 -0
- package/dist/esm/lib/mcp/toolExtras.js +7 -1
- package/dist/esm/lib/mcp/toolExtras.js.map +1 -1
- package/dist/events/registry.js +2 -0
- package/dist/events/registry.js.map +1 -1
- package/dist/index.js +97 -66
- package/dist/index.js.map +1 -1
- package/dist/lib/mcp/toolExtras.js +6 -0
- package/dist/lib/mcp/toolExtras.js.map +1 -1
- package/dist/types/artifacts/index.d.ts +1 -1
- package/dist/types/artifacts/index.d.ts.map +1 -1
- package/dist/types/artifacts/recordingArtifact.d.ts +36 -0
- package/dist/types/artifacts/recordingArtifact.d.ts.map +1 -1
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/core/agent/AgentBuilder.d.ts +12 -0
- package/dist/types/core/agent/AgentBuilder.d.ts.map +1 -1
- package/dist/types/core/agent/evidence/gate.d.ts +11 -1
- package/dist/types/core/agent/evidence/gate.d.ts.map +1 -1
- package/dist/types/core/agent/evidence/types.d.ts +23 -0
- package/dist/types/core/agent/evidence/types.d.ts.map +1 -1
- package/dist/types/core/agent/stagedRefs.d.ts +95 -0
- package/dist/types/core/agent/stagedRefs.d.ts.map +1 -0
- package/dist/types/core/agent/stages/callLLM.d.ts +17 -0
- package/dist/types/core/agent/stages/callLLM.d.ts.map +1 -1
- package/dist/types/core/agent/stages/evidenceRecheck.d.ts +19 -1
- package/dist/types/core/agent/stages/evidenceRecheck.d.ts.map +1 -1
- package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
- package/dist/types/core/agent/toolDispatch.d.ts +51 -0
- package/dist/types/core/agent/toolDispatch.d.ts.map +1 -0
- package/dist/types/core/flowchartAsTool.d.ts +6 -0
- package/dist/types/core/flowchartAsTool.d.ts.map +1 -1
- package/dist/types/core/runbook/coverage.d.ts +70 -0
- package/dist/types/core/runbook/coverage.d.ts.map +1 -0
- package/dist/types/core/runbook/dispatch.d.ts +70 -0
- package/dist/types/core/runbook/dispatch.d.ts.map +1 -0
- package/dist/types/core/runbook/index.d.ts +10 -0
- package/dist/types/core/runbook/index.d.ts.map +1 -0
- package/dist/types/core/runbook/runbookAsTool.d.ts +89 -0
- package/dist/types/core/runbook/runbookAsTool.d.ts.map +1 -0
- package/dist/types/core/runbook/types.d.ts +197 -0
- package/dist/types/core/runbook/types.d.ts.map +1 -0
- package/dist/types/core/runbook/verdicts.d.ts +79 -0
- package/dist/types/core/runbook/verdicts.d.ts.map +1 -0
- package/dist/types/core/runbook/walk.d.ts +73 -0
- package/dist/types/core/runbook/walk.d.ts.map +1 -0
- package/dist/types/core/tools.d.ts +112 -0
- package/dist/types/core/tools.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +39 -0
- package/dist/types/events/payloads.d.ts.map +1 -1
- package/dist/types/events/registry.d.ts +3 -1
- package/dist/types/events/registry.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/mcp/toolExtras.d.ts +8 -0
- package/dist/types/lib/mcp/toolExtras.d.ts.map +1 -1
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -524,7 +524,7 @@ files `agentfootprint.tools.coverage_declared`; with
|
|
|
524
524
|
to the final answer, which is how a limit survives a model that would rather not
|
|
525
525
|
mention it.
|
|
526
526
|
|
|
527
|
-
### Observability —
|
|
527
|
+
### Observability — 109 typed events across 24 domains
|
|
528
528
|
|
|
529
529
|
```typescript
|
|
530
530
|
agent.on('agentfootprint.context.injected', (e) =>
|
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,132 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [9.76.0] - 2026-08-28
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`runbookAsTool` — turn a written procedure into a tool whose every answer
|
|
15
|
+
is evidence.** Triage is the most-used agent job in a business: run the
|
|
16
|
+
standing procedure, come back with a verdict somebody can act on. The first
|
|
17
|
+
production tool of that shape hand-rolled ~800 lines of envelope around a
|
|
18
|
+
footprintjs chart — a coverage ledger merging every inner source's own
|
|
19
|
+
ledger, a rule-version stamp on every sentence, capped verdict rows beside a
|
|
20
|
+
pre-rendered table, and the recorded walk that lets a reader CHECK the
|
|
21
|
+
verdict instead of trusting it. `runbookAsTool` is that envelope as one
|
|
22
|
+
declaration bag; the smallest legal call is `{ name, description,
|
|
23
|
+
procedure }` and it still yields the honest spine.
|
|
24
|
+
|
|
25
|
+
**The mandatory honesty spine**, on every answer whatever the runbook's
|
|
26
|
+
shape: `af_coverage` (three lists + a sentence naming the rule set and
|
|
27
|
+
version, with every inner tool's ledger folded upward), `af_provenance`
|
|
28
|
+
re-emitted FIRST (a seeded source's confession survives composition),
|
|
29
|
+
`rule_version` (or the honest `'undeclared'`), and the recorded walk as an
|
|
30
|
+
artifact ticket — new kind **`recording/chart-walk`** beside
|
|
31
|
+
`recording/run`, with `chartWalkPutInput` beside `recordingPutInput`. The
|
|
32
|
+
walk descriptor carries truthful counters, the declared projection (over
|
|
33
|
+
the cap, the CONTROL FLOW survives — stages, forks, and every `condition`
|
|
34
|
+
entry with its decide() evidence — never a head slice that keeps four
|
|
35
|
+
hundred writes and drops every decision), and a `walk_segment` discriminant
|
|
36
|
+
(`'full'` today; the wire is ready for resumed segments before gates land).
|
|
37
|
+
A failed mint costs the ticket, never the answer.
|
|
38
|
+
|
|
39
|
+
**The optional verdict projection**, selected by `resultKind: 'verdict/*'`:
|
|
40
|
+
rows off the chart's `verdicts` state key, ONE cap for the structured list
|
|
41
|
+
and the rendered table, truthful `rows_shown/rows_total/rows_complete`, and
|
|
42
|
+
`verdict_meanings` GENERATED from the decider's declared branches plus the
|
|
43
|
+
rule labels this run's evidence carried — never hand-restated, so a rule
|
|
44
|
+
change and its meaning change on the same day. Three outcomes, honestly: a
|
|
45
|
+
clean envelope; an inner absence passed through VERBATIM (the framework
|
|
46
|
+
still reads it as an absence); and `declined` rows counted into the ledger
|
|
47
|
+
as not-checked ground.
|
|
48
|
+
|
|
49
|
+
`flowchartAsTool` stays for compatibility (its `resultMapper` users stay
|
|
50
|
+
put, byte-identical); its stale pause message now names the runbook
|
|
51
|
+
program's gate phase instead of a version that shipped years ago.
|
|
52
|
+
|
|
53
|
+
- **`ctx.tools` — a tool's body can call other registered tools through the
|
|
54
|
+
run's own dispatch.** The `procedure` factory is invoked per call with the
|
|
55
|
+
agent's dispatch (static + skill-carried tools; ToolProvider-delivered
|
|
56
|
+
tools are invisible — there is no build-time list, the stated 9.72.0
|
|
57
|
+
caveat), so stages compose registered sources instead of importing modules
|
|
58
|
+
and building a second query stack. Inner calls run with `hasArtifacts:
|
|
59
|
+
false` (one answer, one ticket — never competing chips), a derived
|
|
60
|
+
toolCallId naming the outer call, `needs` resolved on the fail-closed
|
|
61
|
+
non-interactive path, and `checkIn`/`wants` tools refused BY NAME (an inner
|
|
62
|
+
call cannot pause, and must never silently skip a consent gate).
|
|
63
|
+
|
|
64
|
+
- **`composedOf` + `gates` on `defineTool`.** A composed tool names its
|
|
65
|
+
ingredient tools; the drift gate runs at AGENT BUILD — the one moment the
|
|
66
|
+
catalog is complete — so a renamed ingredient fails the build by name, not
|
|
67
|
+
the first 3 a.m. run. `gates` declares a procedure that can raise an
|
|
68
|
+
approval gate (read by composition-time checks that must keep a gating tool
|
|
69
|
+
out of a fan-out branch). Both pass the declaration bar (consumer-side
|
|
70
|
+
rails read them; nothing governs execution) and travel the MCP `_meta` bag
|
|
71
|
+
in both directions, judged on ingest by the same exported asserts
|
|
72
|
+
`defineTool` uses.
|
|
73
|
+
|
|
74
|
+
## [9.75.0] - 2026-08-28
|
|
75
|
+
|
|
76
|
+
### Added
|
|
77
|
+
|
|
78
|
+
- **Grounded numbers: the staged-refs nudge, and a revise correction that
|
|
79
|
+
names the route.** The field failure this closes, from a consumer's recorded
|
|
80
|
+
run: four tool results carried real numbers, a compute tool that could sum
|
|
81
|
+
them was registered — with `wants` declared over the staged dataset kind —
|
|
82
|
+
and the app's prompt said to use it. The model summed the numbers in its
|
|
83
|
+
head anyway and stated the total; the evidence gate recorded *"appears in no
|
|
84
|
+
tool result"* and the answer shipped, because the posture only observed. The
|
|
85
|
+
app patched it with more prose. The library-shaped fix is two mechanisms it
|
|
86
|
+
already owns, on the one dial it already has:
|
|
87
|
+
|
|
88
|
+
**`nudge: true` on `.namesAndNumbersFromEvidence()`** — when an iteration's
|
|
89
|
+
context holds a tool result staged by reference (an `artifacts.placement`
|
|
90
|
+
ticket) AND a tool the model can currently call declares `wants` over that
|
|
91
|
+
ticket's kind, ONE short line is appended at the very END of that request,
|
|
92
|
+
naming the refs and the spender tool by its registered name: derived numbers
|
|
93
|
+
come from the tool, not from mental arithmetic. Composed entirely from
|
|
94
|
+
declarations (`Tool.resultKind`, `Tool.wants`, matched by the exact-string
|
|
95
|
+
law dispatch uses — never by tool name); no prose surface for apps. The
|
|
96
|
+
placement is the point: the measured failure was recency — the app's own
|
|
97
|
+
instruction sat at the top of a long context and the numbers at the bottom,
|
|
98
|
+
so this one sits beside the data. Request-only (never history, so it never
|
|
99
|
+
enters the gate's exempt corpus), recomposed per iteration so it exists
|
|
100
|
+
exactly while both conditions hold, judged against the tools REALLY served
|
|
101
|
+
this call (the wrap-up's withheld surface arms nothing). Each firing lands
|
|
102
|
+
as `agentfootprint.agent.grounding_nudged` (event 109) with refs and tools
|
|
103
|
+
as data — the line's one record, since the line itself is not conversation.
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
const agent = Agent.create({ provider, model, artifacts: { store, placement } })
|
|
107
|
+
.tool(exportRows) // resultKind: 'dataset/rows' — staged over the threshold
|
|
108
|
+
.tool(compute) // wants: { dataset: 'dataset/rows' } — the declared spender
|
|
109
|
+
.namesAndNumbersFromEvidence({ posture: 'guard', nudge: true })
|
|
110
|
+
.build();
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**The guarantee stays the postures the gate has had since 9.35.0** — the
|
|
114
|
+
existing value extraction is THE detector, unchanged: `'assist'` records,
|
|
115
|
+
`'guard'` allows the one bounded revision then delivers with both attempts
|
|
116
|
+
on the record, `'rails'` refuses with `UnsupportedValuesError`. What the
|
|
117
|
+
revision gains: when the flagged turn holds staged refs a served `wants`
|
|
118
|
+
tool can spend, the correction now names them — *"pass 'art_…'
|
|
119
|
+
(dataset/rows) to `compute` — compute the number there and answer with what
|
|
120
|
+
it returns"* — inside the authored frame, so the quoted values still come
|
|
121
|
+
last and the exempt-corpus fence is untouched. The `revision-asked`
|
|
122
|
+
`evidence_checked` event carries the same facts additively (`stagedRefs`,
|
|
123
|
+
`spenderTools`). Absent everything — no gate, `nudge` unset, or no
|
|
124
|
+
`wants`-declaring tool — every request, record and correction keeps its
|
|
125
|
+
exact bytes, pinned by test.
|
|
126
|
+
|
|
127
|
+
### Changed
|
|
128
|
+
|
|
129
|
+
- **A `guard`/`rails` agent that also registers a `wants`-declaring tool will
|
|
130
|
+
see its evidence correction gain the refs clause above when staged refs are
|
|
131
|
+
in context.** That is the fix, not a side effect: a correction that says
|
|
132
|
+
"call the tool that provides it" without naming WHICH tool over WHICH ref
|
|
133
|
+
leaves the model to head-math again. Agents without a `wants` tool — or
|
|
134
|
+
without staged refs in the flagged turn — keep the exact 9.35.0 sentence.
|
|
135
|
+
|
|
10
136
|
## [9.74.0] - 2026-08-27
|
|
11
137
|
|
|
12
138
|
### Added
|
package/CLAUDE.md
CHANGED
|
@@ -17,45 +17,50 @@ 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`; inner `absent()` passes through VERBATIM unless the call said `allowAbsent`; walk kind `recording/chart-walk` + `walk_segment` discriminant | `src/core/runbook/` | 9.76.0 |
|
|
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 |
|
|
20
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 |
|
|
21
|
-
| a build gate that refuses a triage/inventory tool that forgot its caveats, by tool name and field name | `checkSemantics` + `defineTool({ resultClass })` + bin `agentfootprint-check-semantics` | `src/lib/semantics/check.ts` | 9.53.0 |
|
|
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 |
|
|
22
24
|
| an agent that runs out of `maxIterations` mid-task handing back a HALF-SENTENCE as its answer — and nothing saying the budget ran out | `wrapUpAtMaxIterations` (default ON) + `WRAP_UP_INSTRUCTION` + `agent.budget_exhausted` + `stoppedEarly.wrappedUp` | `src/core/agent/stages/wrapUp.ts` | 9.56.0 |
|
|
25
|
+
| the conversation outgrowing the context window — dropping, summarizing or token-budgeting old turns, every removal on the record (the three refusal rows below all guard this window) | `.window()` + `slidingWindow` / `summarizeOldest` (= `.compaction()`) / `tokenBudget` + `keepRecentTurns` (default 6) + `thresholdTokens` (required, deliberately no default) + `retain: 'conversation'` (default) / `'discard'` | `src/core/agent/window/` | 7.17.0 |
|
|
23
26
|
| keeping the user's own request in context while the window shrinks — the task's anchor, un-droppable by every window strategy including one you wrote | `'current-request'` refusal + `currentRequestIndexOf` + `WindowStrategyInput.currentRequestIndex` | `src/core/agent/window/currentRequest.ts` | 9.55.0 |
|
|
24
|
-
| the window evicting the EVIDENCE while keeping the task — the tool result carrying the only valid ids leaves, and the model invents one that has never existed | `keepLastToolResults` (default 2) + `'last-tool-result'` refusal + `toolResultPinsOf` + `WindowRecord.observations` (what was kept, and its exact char cost) | `src/core/agent/window/lastToolResult.ts` | 9.57.0 |
|
|
27
|
+
| the window evicting the EVIDENCE while keeping the task — the tool result carrying the only valid ids leaves, and the model invents one that has never existed | `keepLastToolResults` (default 2; `0`/`false` disables) + `'last-tool-result'` refusal + `toolResultPinsOf` + `WindowRecord.observations` (what was kept, and its exact char cost) | `src/core/agent/window/lastToolResult.ts` | 9.57.0 |
|
|
25
28
|
| telling the model WHICH tools' results a drop took, so it re-calls instead of reconstructing from memory — and filing the same fact on the record even when no notice was authored | `droppedToolNames` + the notice's tool sentence + `WindowRecord.droppedObservations` | `src/core/agent/window/toolNames.ts` | 9.57.0 |
|
|
26
|
-
| an instruction that SAYS a run-time number rather than only gating on it ("you are on action 25 of 30") — with the library owning absence, so never "23 of undefined" and never a fabricated zero | `promptTemplate` + the closed `TEMPLATE_FACTS` vocabulary + `skipped: 'unknown-fact'` + `Injection.templated` | `src/lib/injection-engine/promptTemplate.ts` | 9.57.0 |
|
|
29
|
+
| an instruction that SAYS a run-time number rather than only gating on it ("you are on action 25 of 30") — with the library owning absence, so never "23 of undefined" and never a fabricated zero | `promptTemplate` + the closed `TEMPLATE_FACTS` vocabulary (`action`/`actionBudget`/`actionsRemaining`) + `skipped: 'unknown-fact'` + `Injection.templated` | `src/lib/injection-engine/promptTemplate.ts` | 9.57.0 |
|
|
27
30
|
| an injection predicate that can see how much of the action budget is left | `InjectionContext.maxIterations` / `.iterationsRemaining` + `iterationsRemainingOf` (the ONE denominator, shared with the cache decision) | `src/lib/iterationBudget.ts` | 9.57.0 |
|
|
28
31
|
| report progress from inside a tool — "hop 3 of 12 done", said mid-call while a long-running `execute` is still working (the record was otherwise atomic: tool_start, silence, tool_end) | `ctx.progress` + `agentfootprint.stream.tool_progress` | `src/core/tools.ts` | 9.52.0 |
|
|
29
|
-
| show tool progress to the user — a mid-call report reaching the live status line / chat bubble, not just the record (`message` shown verbatim, capped; otherwise an honest generic line, never a payload dump) | `selectStatus` + `progressMessageOf` + `tool.progress` templates | `src/recorders/observability/status/statusTemplates.ts` | 9.54.0 |
|
|
32
|
+
| show tool progress to the user — a mid-call report reaching the live status line / chat bubble, not just the record (`message` shown verbatim, capped at 120 chars with the cut stated; otherwise an honest generic line, never a payload dump) | `selectStatus` + `progressMessageOf` + `tool.progress` templates | `src/recorders/observability/status/statusTemplates.ts` | 9.54.0 |
|
|
30
33
|
| declaring which skills connect — the SkillMap as one named thing (the agent that mounts it is the SkillWalker; there is deliberately no walker class) | `defineSkillMap` + `SkillMap` (permanent reference-equal aliases of `skillGraph`/`SkillGraph`) | `src/lib/injection-engine/skillGraph.ts` | 9.51.0 |
|
|
31
|
-
| guarding a skill transition on state or a tool result's fields — a route condition as DATA (comparable, drawable, evidence-recorded), not an opaque predicate | `guard:` + `compileGuard` + `guard-unsatisfiable` | `src/lib/injection-engine/skillGuard.ts` | 9.51.0 |
|
|
34
|
+
| guarding a skill transition on state or a tool result's fields — a route condition as DATA (comparable, drawable, evidence-recorded), not an opaque predicate | `guard:` + `compileGuard` (ops `'eq'`/`'ne'`/`'gt'`/`'gte'`/`'lt'`/`'lte'`/`'in'`/`'notIn'`) + `guard-unsatisfiable` | `src/lib/injection-engine/skillGuard.ts` | 9.51.0 |
|
|
32
35
|
| seeing the skill map in a recording — the author's nodes + edges (guards included) as DATA, never parsed from prose or inferred from fired hops | `skill.graph_declared` + `buildSkillGraphDeclared` | `src/core/agent/skillGraphDeclared.ts` | 9.50.0 |
|
|
33
36
|
| "where could the run go next?" — the reachable skill set at every cursor move, typed on the move itself | `cursorMove.reachable` + `reachableSkills` | `src/lib/injection-engine/buildInjectionEngineSubflow.ts` | 9.50.0 |
|
|
34
37
|
| putting the ASSEMBLED system prompt in the recording — the exact string the model read (opt-in; default OFF is a privacy decision) | `recordSystemPrompt` | `src/core/agent/types.ts` | 9.50.0 |
|
|
35
|
-
| a typed HITL prompt — let a person pick from a list, choose a range, use a real control instead of typing prose | `AskComponent` | `src/core/askComponent.ts` | 9.24.0 |
|
|
36
|
-
| carrying WHAT the person chose back, with what they could see | `DecisionValue` | `src/core/checkin.ts` | 9.47.0 |
|
|
37
|
-
| archiving a finished run — filing it, attaching it to a bug report, feeding it to an analysis tool | `persistRecording` + `RecordingEnvelope` | `src/recorders/observability/recordingEnvelope.ts` | 9.48.0 |
|
|
38
|
-
| packaging a run for a HUMAN to file — a zip whose evidence is the archive envelope, plus host facts and a readable transcript | `exportBugReport` | `src/lib/bug-report/build.ts` | — |
|
|
38
|
+
| a typed HITL prompt — let a person pick from a list, choose a range, use a real control instead of typing prose | `AskComponent` + `componentId` (consumer-registered vocabulary, opaque here) + inline `props` + `propsRef` (artifact claim ticket for the big half) | `src/core/askComponent.ts` | 9.24.0 |
|
|
39
|
+
| carrying WHAT the person chose back, with what they could see | `DecisionValue` (`kind` / `value` / `from?` + `coverage {seen, total, filter?}`) | `src/core/checkin.ts` | 9.47.0 |
|
|
40
|
+
| archiving a finished run — filing it, attaching it to a bug report, feeding it to an analysis tool | `persistRecording` + `RecordingEnvelope` + `run.complete` (required) + `privacy.mode` (`'full'` today; `'structure-only'`/`'redacted'` refuse by name) | `src/recorders/observability/recordingEnvelope.ts` | 9.48.0 |
|
|
41
|
+
| packaging a run for a HUMAN to file — a zip whose evidence is the archive envelope, plus host facts and a readable transcript | `exportBugReport` + `include` (the consent seam; left-out units are counted in `manifest.excluded`) + `warnOverBytes` (default 20 MB) | `src/lib/bug-report/build.ts` | — |
|
|
39
42
|
| writing archived runs somewhere — a directory, one JSON file per run | `fileRecordingSink` + `RecordingSink` | `src/recorders/observability/fileRecordingSink.ts` | 9.48.0 |
|
|
40
43
|
| declaring an agent's whole setup as one named, versioned thing — a preset, a template, a blueprint, "the support agent we all use" | `defineAgentRecipe` + `AgentBuilder.recipe()` | `src/recipes/` | 9.48.0 |
|
|
41
44
|
| naming your own branches and nodes — which prefix is reserved, and telling framework plumbing from consumer structure in a trace | `RESERVED_SUBFLOW_PREFIX` + `isReservedSubflowSegment` | `src/conventions.ts` | 9.49.0 |
|
|
42
|
-
| keeping a large tool result out of the model's context | `artifacts` + `wants` + `placement` | `src/artifacts/` | 9.21.0 |
|
|
45
|
+
| keeping a large tool result out of the model's context | `artifacts` (bare store, or `{ store, placement: { maxInlineChars }, recordings }` — `placement` omitted ⇒ never placed; `recordings: true` / `{ label }`, default off) + `wants` + `placement` | `src/artifacts/` | 9.21.0 |
|
|
43
46
|
| the ticket placement just minted being REFUSED by your own `wants` argument as a kind mismatch — because the mint says `tool-result/<toolName>` and your consumer says `dataset/rows` | `Tool.resultKind` + `placedResultKind(toolName, declared?)` (the mint speaks the consumer's vocabulary; the exact-match matcher is untouched) | `src/artifacts/placement.ts` | 9.70.0 |
|
|
44
47
|
| letting the UI draw an artifact without the model naming a component | `registerArtifactComponent` (in the `agentfootprint-lens` package) | — | — |
|
|
45
48
|
| finding which tools the model keeps writing by hand | `agentfootprint.tools.code_run` + `codeShape` | `src/core/codeRunnerTool.ts` | 9.46.0 |
|
|
46
|
-
| a skill wrongly activated by a keyword staying loaded for the whole turn — suspending/parking a map's prompt + tools when its contribution goes unused, WITHOUT touching its cursor, and re-engaging it on evidence | `.maps()` + `advanceEngagement` + `agentfootprint.map.engaged/parked` + skip reason `'parked'` | `src/maps/` | 9.58.0 |
|
|
49
|
+
| a skill wrongly activated by a keyword staying loaded for the whole turn — suspending/parking a map's prompt + tools when its contribution goes unused, WITHOUT touching its cursor, and re-engaging it on evidence | `.maps({ renewalGrace })` (default 3) + `MountedMap.nonParkable` + `advanceEngagement` + `agentfootprint.map.engaged/parked` + skip reason `'parked'` | `src/maps/` | 9.58.0 |
|
|
47
50
|
| a value that must say how it knows itself — an unknown count that can never render as zero | `Claim<T>` (`known`/`unknown`/`notApplicable`) | `src/lib/claim/claim.ts` | 9.58.0 |
|
|
48
51
|
| asking a debugging model "what did this run contradict itself about, and why?" — the Context Integrity findings, joined to the step that filed them | `find_context_errors` | `src/lib/trace-toolpack/traceToolpack.ts` | 9.61.0 |
|
|
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 |
|
|
49
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 |
|
|
50
|
-
| a tool
|
|
51
|
-
|
|
|
54
|
+
| 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 |
|
|
55
|
+
| 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 |
|
|
56
|
+
| 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 |
|
|
52
57
|
| minting one of those shapes from a tool that is NOT JavaScript — the canonical note sentences and reserved marker keys as DATA, so a Python/Go/Rust sidecar reads a file instead of regex-scraping `dist/esm` (which a consumer really did) | `canonical-notes.json` at the package root + the `./canonical-notes.json` exports entry, GENERATED from the built barrel by `scripts/gen-canonical-notes.mjs` | `scripts/gen-canonical-notes.mjs` | 9.70.0 |
|
|
53
|
-
| proving a session store really honours the port | `runSessionLifecycleConformance` | `src/hosting/conformance/` | 9.37.0 |
|
|
58
|
+
| proving a session store really honours the port | `runSessionLifecycleConformance` + `declared` skips (by case name WITH the reason; a declared case still RUNS) + outcomes `'passed'`/`'not-applicable'`/`'declared'`/`'failed'` | `src/hosting/conformance/` | 9.37.0 |
|
|
54
59
|
| deciding who owns a contested session write | `resolveSessionOwner` | `src/hosting/sessionOwnership.ts` | 9.37.0 |
|
|
55
|
-
| making a caller-supplied id safe for a backend | `encodeIdentityField` | `src/memory/identity/encode.ts` | 9.
|
|
56
|
-
| scoping a skill's tools so they reach the model only while it is active | `toolsFromActiveSkill` | `src/core/agent/toolsFromActiveSkill.ts` | 9.
|
|
60
|
+
| making a caller-supplied id safe for a backend | `encodeIdentityField` | `src/memory/identity/encode.ts` | 9.37.0 |
|
|
61
|
+
| scoping a skill's tools so they reach the model only while it is active | `toolsFromActiveSkill` + a no-arg posture (default off) + the stamp `autoActivate: 'currentSkill'` (a default, never an override) | `src/core/agent/toolsFromActiveSkill.ts` | 9.36.0 |
|
|
57
62
|
| subscribing to every event in one domain at once | `DomainWildcard` | `src/events/dispatcher.ts` | 9.4.0 |
|
|
58
|
-
| pausing a run for a person and resuming it later | `checkInApproved` / `checkInDeclined` | `src/core/checkin.ts` |
|
|
63
|
+
| pausing a run for a person and resuming it later | `checkInApproved` / `checkInDeclined` (`{ by, note?, value? }`; a decline is NOT an abort — the model gets a "declined by human" tool result and adapts in-loop) | `src/core/checkin.ts` | 7.5.0 |
|
|
59
64
|
|
|
60
65
|
**One law before you add a mapping.** Any function turning caller data into a KEY,
|
|
61
66
|
a namespace, a filename or an index entry must be injective, and its collision
|
|
@@ -133,7 +138,7 @@ Traps: `src/observability/` holds the finder IMPLEMENTATIONS (canonical home; `d
|
|
|
133
138
|
- **Recordings as artifacts (9.26.0)**: `artifacts: { store, recordings: true | { label } }`. `Agent.startRunRecording()` calls the SAME `recordRun` (before `createExecutor` — `attach()` collects for the executor not yet built); `fileRunRecording` mints AFTER `finalizeResult`, awaited, every failure contained to `artifacts.refused`. Pure half in artifacts/recordingArtifact.ts; payload is the recording's JSON TEXT (a live snapshot handed to an in-process store would be a live view into a finished run). No new wire op — `artifact-get` serves it.
|
|
134
139
|
- **Code staging-in (9.26.0)**: `CodeSession.stageInputs?(inputs) → StagedCodeInput[]` — OPTIONAL, feature-detected via `canStageCodeInputs`, and its contract is TWO promises: the payloads are readable at the returned paths, AND every later `execute` exposes the manifest as `STAGED_INPUTS_ENV` (`AF_STAGED_INPUTS`, `name → path`). `CodeInput.name` is the MANIFEST KEY (the wants arg name, so a static description can name it) and `fileName` is the on-disk name — separate fields so the two cannot drift. `codeRunnerTool({ wants })` composes the schema properties + the description clause and refuses BY NAME on a non-staging runner. Implemented by localCodeRunner only.
|
|
135
140
|
- **Repeated-call nudge (9.26.0)**: `core/agent/repeatedCall.ts` (pure `noteRepeatedCall` + `repeatedCallLedgers()`) + the ONE batch-loop hook in toolCalls. Fingerprints (FNV-1a) of stable-stringified args and the tool's OWN delivered result — never values. **The counters are NOT tracked state**: they live in a bounded run-keyed map held by `buildToolCallsHandler` and keyed by `deps.currentRun().runId`, so a turn that repeats nothing is byte-identical in state, commit log, narrative and recordings (a scope key would have changed all four for every agent that merely upgraded); the repeat itself rides `agentfootprint.tools.repeated_call`, the emit channel per-attempt facts belong on. A resume mints a new runId ⇒ counting restarts. Fires at the SECOND identical landing, once. `AgentOptions.repeatedCallNudge: false` disables (threaded value-conditionally; ON is the default). Deliberately NOT applied on the pause-resume dispatch paths.
|
|
136
|
-
- **Evidence gate (9.35.0)** — `.namesAndNumbersFromEvidence({ posture, shapes, exempt, minDigits })`: every name/number in the final answer must appear in a `role:'tool'` result. Postures reuse the routing VOCABULARY (`assist`|`guard`|`rails`) as a SEPARATE option — routing authority ≠ evidence discipline, and overloading `skillGraphCascade.strictness` would deny "strict routing, loose evidence". Wiring is the stepNudge blast radius verbatim: `ResolvedEvidenceGate` (builder-resolved, refusals at the CALL SITE) → Agent ctor trailing param → `buildRouteDeciderStage`'s 4th arg (`judgeEvidence` runs LAST of the three judges — schema > steps > evidence — and NOT on a denied or schema-exhausted answer) → `evidenceRecheckStage` branch (`{loopTo}`, mounted only for a revising posture) → `STAGE_IDS.EVIDENCE_RECHECK` + BOUNDARY_LOCAL_IDS + milestoneFor. TWO deps flags, and the second is the one a reader misses: `evidenceRecheckStage` (branch) AND `hasEvidenceGate` (bubbles `systemPromptInjections` out of sf-llm-call in the GROUPED chart — without it the gate flags the app's own prompt). Per-check facts ride `agentfootprint.agent.evidence_checked` (emit channel); only the terminal verdict is committed (`unsupportedValues`), because the boundary raises off it. `UnsupportedValuesError` joins the TERMINAL-typed-error list in `run()`'s catch (a verdict is not a crash — no retry handle for a wall).
|
|
141
|
+
- **Evidence gate (9.35.0)** — `.namesAndNumbersFromEvidence({ posture, shapes, exempt, minDigits })`: every name/number in the final answer must appear in a `role:'tool'` result. Postures reuse the routing VOCABULARY (`assist`|`guard`|`rails`) as a SEPARATE option — routing authority ≠ evidence discipline, and overloading `skillGraphCascade.strictness` would deny "strict routing, loose evidence". Wiring is the stepNudge blast radius verbatim: `ResolvedEvidenceGate` (builder-resolved, refusals at the CALL SITE) → Agent ctor trailing param → `buildRouteDeciderStage`'s 4th arg (`judgeEvidence` runs LAST of the three judges — schema > steps > evidence — and NOT on a denied or schema-exhausted answer) → `evidenceRecheckStage` branch (`{loopTo}`, mounted only for a revising posture) → `STAGE_IDS.EVIDENCE_RECHECK` + BOUNDARY_LOCAL_IDS + milestoneFor. TWO deps flags, and the second is the one a reader misses: `evidenceRecheckStage` (branch) AND `hasEvidenceGate` (bubbles `systemPromptInjections` out of sf-llm-call in the GROUPED chart — without it the gate flags the app's own prompt). Per-check facts ride `agentfootprint.agent.evidence_checked` (emit channel); only the terminal verdict is committed (`unsupportedValues`), because the boundary raises off it. `UnsupportedValuesError` joins the TERMINAL-typed-error list in `run()`'s catch (a verdict is not a crash — no retry handle for a wall). **Grounded numbers (9.75.0)** rides the SAME dial: `nudge: true` arms the staged-refs nudge — `toolWantsOf` harvests `Tool.wants` beside the `toolGrounding` harvest in `Agent.buildChart` (same ToolProvider blindness), callLLM appends ONE request-only late line when a placed ticket's kind matches a SERVED `wants` tool (judged on `registeredToolSchemas`, so wrap-up's withheld surface arms nothing; history untouched ⇒ never in the exempt corpus), recorded as `agent.grounding_nudged`; and the recheck correction names the same refs+spender via `buildEvidenceCorrection`'s third arg — threaded whenever a `wants` tool exists, NOT gated on `nudge`, clause INSIDE the authored frame so `isLibraryAuthoredTurn`'s prefix match and values-last both hold.
|
|
137
142
|
- **Coverage primitives (this release)** — `absent()` / `coverage()`, both copied from FIELD USE. THE argument is the direction of the error: a *nothing-found* misread as an *outage* costs an investigation, an *outage* misread as *nothing-found* declares a system healthy that was never checked — so the two must not share a shape. Blast radius, and it is the `resultCeiling` radius verbatim: `readCoverageResult` called by `declareCoverage` at BOTH execute boundaries in toolCalls.ts (batch loop + `resolveCredentialAndExecute`), on the UNWRAPPED content and BEFORE the ceiling. FOUR downstream changes and no more: (1) `ToolResultStatus` gained a SEVENTH word `'absent'` — routable by `onToolStatus`, because folding it into `'failure'` is the confusion itself and into `'success'` leaves nothing to route on; (2) two events (`tools.absent`, `tools.coverage_declared`); (3) tracked `AgentState.coverageDeclared` — a limit is a fact about the ANSWER, not about an attempt, which is why it is state and the repeated-call counters are not; (4) the evidence corpus indexes an absence's COVERAGE ONLY (`coverage/evidence.ts` — a failed lookup is the cheapest laundering machine, and `absent()` would have made it cheaper: this is frames.ts's argument on the tool side). Deliberately UNCHANGED: no `error: true`, no retry, no refusal, no gate flag. Survival into the answer is `.limitsTravelWithTheAnswer()` → `attachCoverageLimits` dep → BOTH builders swap the final branch's first stage for `prepareFinalWithLimitsStage` (same id, same position). It APPENDS rather than judges: a check for "did the model state its limits?" needs a second model to decide what counts, which is what evidence/README.md forbids.
|
|
138
143
|
- **Out-of-budget wrap-up (9.56.0)** — `wrapUpAtMaxIterations` (AgentOptions, default ON, `repeatedCallNudge`'s opt-out grammar): the FOURTH Route branch, and the SchemaRetry mechanism verbatim — `STAGE_IDS.WRAP_UP` + same `{loopTo}`, so the last call is one ordinary turn with its own `iteration_start`/`llm_start`/`cost.tick`. Two things are its own: (1) the tools are WITHHELD at REQUEST ASSEMBLY in callLLM (`scope.wrapUpAsked`, the `schemaTool` seam's mirror — the schema tool still rides, so an output contract survives), which is what makes the call terminal BY CONSTRUCTION rather than by a rule, and is why it is exempt from `maxIterations`; (2) the CONDITIONAL MOUNT is on the agent having a TOOL SURFACE (`registryByName.size > 0 || externalToolProvider`) — a limit only cuts a turn short when tool calls were pending, so a toolless agent's chart must not grow a box that can never run. `decideBranch` treats a spent wrap-up as cut-short for every downstream judge (`toolCalls.length > 0 || scope.wrapUpAsked`), or a step nudge / evidence revision would loop past the limit that fired. `wrapUpAsked` is deliberately NOT seeded — a turn that finishes inside its budget commits the exact key set it always did. The record is FOUR channels: `stoppedEarly` (now with `wrappedUp`, corrected on the pass after so `answerWasEmpty` describes the answer the caller GOT), `cost.limit_hit` (unchanged), the new `agent.budget_exhausted {action: 'wrapped-up'|'cut-short'}`, and an optional `turn_end.stoppedEarly` projection.
|
|
139
144
|
- **Closed seams**: Agent chart internals (AgentChartDeps not exported — extend via injections/tools/memory/thinking, never by adding a ReAct stage); ContextSlot (3 slots fixed); ProviderKind factory; dormant ports with no consumer (ContextSourceAdapter, EmbeddingProvider, RiskDetector — adapters/types.ts only); reserved tool names under selfExplain — 8.16.0 made the list DERIVED: `TRACE_TOOL_NAMES` (traceToolpack.ts, 11 names since 9.61.0: run_overview/find_context_errors/find_in_trace/trace_node/trace_slice/backtrack/who_wrote/get_value/inspect_tool_call/inspect_tool_run/read_narrative) is what AgentBuilder.ts:~1560 reserves in inline mode (`explain_run` in delegate mode), so a NEW toolpack tool joins ONE list and the reservation follows — but it must ALSO join the lazy template's mounted set (lazyToolpack builds over `{narrative: [], events: []}` so the catalog shape is fixed at build time) and the count assertion in test/lib/trace-toolpack/selfExplainAgent.test.ts. **8.17.0 `inspect_tool_run`** is the descent THROUGH the tool boundary: `flowchartAsTool({ keepRecord: true })` files each invocation's record in a bounded LRU store (lib/trace-toolpack/innerRunRecords.ts) keyed by the executing `ctx.toolCallId`, riding the `Tool` under the `INNER_RUN_RECORDS` registry symbol; `AgentBuilder.build()` → `collectInnerRuns(registry, injections)` → `SelfExplainSource.getInnerRuns` → `TraceToolpackArtifacts.innerRuns`. The inner views are the pack ITSELF re-run over `openRecording(record.recording)` — do not add a second query implementation. Provider-delivered tools are NOT collected (no build-time list); inner runtimeStageIds are a SEPARATE namespace and only `inspect_tool_run` accepts them. **9.61.0 `find_context_errors`** is the Context Integrity read-out: it reads `agentfootprint.integrity.context_error` + `…disposition` off the artifacts' EVENT TAIL (never re-running a check), joins each finding to the step it was filed at, and mounts UNCONDITIONALLY — a tool that vanished with the tail could not say the evidence channel is ABSENT, which is the one sentence this family forbids collapsing into "no errors found".
|
|
@@ -145,7 +150,7 @@ Traps: `src/observability/` holds the finder IMPLEMENTATIONS (canonical home; `d
|
|
|
145
150
|
- **Embedder fingerprint** (8.9.0) → `Embedder.id` (optional; every shipped embedder sets one, and NONE include dims — the store appends `@<dims>` itself, so an id carrying its own size double-stamps) + `indexDocuments` defaulting `embedderId` to it + `SqliteVectorStore.reconcileFingerprint` (the only comparison site). Rule: dimensions ALWAYS decide, model ids decide only when BOTH sides named themselves — refusing on an absent name would block the majority of callers who never pass `embedderId`.
|
|
146
151
|
- **Retrieval record** (8.8.0) → FOUR stages write one object in sequence: `loadRelevant` (candidates+scores+threshold verdicts) → `pickByBudget` (re-marks admitted→over-budget/over-max-entries) → `formatDefault` (`promptFragment` + `promptPosition`) → the read mount's outputMapper lifts it to root as `retrievalEvidence_<id>`. `memoryRecallInjections` then splits ONE recall into one ActiveInjection PER CHUNK — guarded by a byte-equality check (`fragments.join('\n\n') === systemContent`) that falls back to the single injection rather than change the prompt. `rank` (score order) and `promptPosition` (picker order) are DIFFERENT and both load-bearing: joining fragments in rank order reproduces the right bytes in a sequence the model never saw.
|
|
147
152
|
- **AgentState** → all 8 stages/ files, both builders' mappers, memory-wire STRING-TYPED keys ('runIdentity'/'turnNumber'/… buildAgentChart.ts:177-180 — not refactor-safe), finalizeResult's `reliabilityFail*`/`policyHalt*` reads (rename silently kills the typed errors).
|
|
148
|
-
- **events/** →
|
|
153
|
+
- **events/** → 109 typed events across 24 domains (counts anti-drift-tested against this file — update BOTH when adding events): ALL_EVENT_TYPES exhaustiveness tests, DomainWildcard hand-list, ~42 importers (recorders, strategies, stream, commentary).
|
|
149
154
|
- **Run-configuration manifest (9.41.0)** → `agentfootprint.agent.run_configured`, the JOIN KEY that turns N runs into N labelled ARMS: one event naming the adapters/strategies in play (provider+model, reactMode, each memory's declared strategy/retrieval/embedder, window, graph posture+classifier, evidence posture, artifacts-present). Composed by the PURE `core/agent/runManifest.ts`, dispatched from `Agent.emitRunManifest()` at the END of `createExecutor` — the ONE funnel `run()` AND `resume()` share, both of which mint a fresh runId. Direct `dispatcher.dispatch` with a STATED pseudo-stage (`run-configured#0`), the `emitToolSessionReport` precedent — there is no stage yet, and `minimalMeta()` would make the one joinable-by-design event unjoinable. TWO laws, both tested: NAMES ONLY (a store is reported PRESENT and unnamed rather than identified by a directory/endpoint — `MemoryStore` and `ArtifactStore` declare no id), and ABSENT means "not configured", never a guessed `'default'`. Graph presence is read off `skillGraphNextSkill`, NOT `skillGraphCascade` (a 9.16-style mount sets no cascade and would read as "no graph"). `MemoryDefinition` gained `strategy`/`retrieval`/`embedderId` for it — declared names the compiled pipeline had closed over, the `store`-in-the-open precedent.
|
|
150
155
|
- **adapters/types.ts LLMMessage/LLMRequest** → 62 importers: tool_use round-trip (toolCalls.ts:115-135), wire assembly (callLLM.ts:150-160), providers, cache strategies, security/extractSequence, reliability loop.
|
|
151
156
|
- **Cache** → strategy registration is a MODULE SIDE EFFECT (src/index.ts:15-17); an entry point skipping that import silently falls back to NoOp. Resolved once per Agent at construction (Agent.ts:347).
|
|
@@ -252,7 +252,7 @@ const agent = Agent.create({ provider, model })
|
|
|
252
252
|
agent.on('agentfootprint.context.evaluated', (e) => console.log(e.payload.activeIds));
|
|
253
253
|
```
|
|
254
254
|
|
|
255
|
-
**
|
|
255
|
+
**109 typed events across 24 domains.** Two subscription shapes and no third:
|
|
256
256
|
`'*'` (every event) and `'agentfootprint.<domain>.*'` (one domain). **`'agentfootprint.*'`
|
|
257
257
|
is not a pattern** — TypeScript rejects it, and at runtime it would match nothing.
|
|
258
258
|
|
package/dist/artifacts/index.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* this folder for the one-job map and the import direction.
|
|
12
12
|
*/
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.placedToolResult = exports.placedResultKind = exports.isPlacedToolResult = exports.assertArtifactPlacement = exports.runArtifactStoreConformance = exports.runArtifactStoreCase = exports.formatArtifactStoreReport = exports.artifactStoreConformance = exports.UnserializableRecordingError = exports.RECORDING_MEDIA_TYPE = exports.RECORDING_ARTIFACT_KIND = exports.recordingPutInput = exports.presentArtifact = exports.PRESENT_TOOL_NAME = exports.wantsNeedsStoreRefusal = exports.resolveToolWants = exports.assertToolWants = exports.unconfiguredArtifacts = exports.bindArtifacts = exports.collectStream = exports.canStreamArtifacts = exports.canPutArtifactStream = exports.canGetArtifactStream = exports.bytesAsStream = exports.assertStreamBytes = exports.gcsArtifacts = exports.s3Artifacts = exports.UnreadableArtifactStoreError = exports.sqliteArtifacts = exports.UnreadableArtifactFileError = exports.fileArtifacts = exports.DEFAULT_IN_MEMORY_ARTIFACT_RETENTION = exports.inMemoryArtifacts = exports.mintArtifactRef = exports.isArtifactRef = exports.ARTIFACT_REF_PREFIX = exports.UnknownParentRefError = exports.InvalidArtifactError = exports.ArtifactIntegrityError = void 0;
|
|
14
|
+
exports.placedToolResult = exports.placedResultKind = exports.isPlacedToolResult = exports.assertArtifactPlacement = exports.runArtifactStoreConformance = exports.runArtifactStoreCase = exports.formatArtifactStoreReport = exports.artifactStoreConformance = exports.UnserializableRecordingError = exports.chartWalkPutInput = exports.CHART_WALK_ARTIFACT_KIND = exports.RECORDING_MEDIA_TYPE = exports.RECORDING_ARTIFACT_KIND = exports.recordingPutInput = exports.presentArtifact = exports.PRESENT_TOOL_NAME = exports.wantsNeedsStoreRefusal = exports.resolveToolWants = exports.assertToolWants = exports.unconfiguredArtifacts = exports.bindArtifacts = exports.collectStream = exports.canStreamArtifacts = exports.canPutArtifactStream = exports.canGetArtifactStream = exports.bytesAsStream = exports.assertStreamBytes = exports.gcsArtifacts = exports.s3Artifacts = exports.UnreadableArtifactStoreError = exports.sqliteArtifacts = exports.UnreadableArtifactFileError = exports.fileArtifacts = exports.DEFAULT_IN_MEMORY_ARTIFACT_RETENTION = exports.inMemoryArtifacts = exports.mintArtifactRef = exports.isArtifactRef = exports.ARTIFACT_REF_PREFIX = exports.UnknownParentRefError = exports.InvalidArtifactError = exports.ArtifactIntegrityError = void 0;
|
|
15
15
|
var types_js_1 = require("./types.js");
|
|
16
16
|
Object.defineProperty(exports, "ArtifactIntegrityError", { enumerable: true, get: function () { return types_js_1.ArtifactIntegrityError; } });
|
|
17
17
|
Object.defineProperty(exports, "InvalidArtifactError", { enumerable: true, get: function () { return types_js_1.InvalidArtifactError; } });
|
|
@@ -54,6 +54,8 @@ var recordingArtifact_js_1 = require("./recordingArtifact.js");
|
|
|
54
54
|
Object.defineProperty(exports, "recordingPutInput", { enumerable: true, get: function () { return recordingArtifact_js_1.recordingPutInput; } });
|
|
55
55
|
Object.defineProperty(exports, "RECORDING_ARTIFACT_KIND", { enumerable: true, get: function () { return recordingArtifact_js_1.RECORDING_ARTIFACT_KIND; } });
|
|
56
56
|
Object.defineProperty(exports, "RECORDING_MEDIA_TYPE", { enumerable: true, get: function () { return recordingArtifact_js_1.RECORDING_MEDIA_TYPE; } });
|
|
57
|
+
Object.defineProperty(exports, "CHART_WALK_ARTIFACT_KIND", { enumerable: true, get: function () { return recordingArtifact_js_1.CHART_WALK_ARTIFACT_KIND; } });
|
|
58
|
+
Object.defineProperty(exports, "chartWalkPutInput", { enumerable: true, get: function () { return recordingArtifact_js_1.chartWalkPutInput; } });
|
|
57
59
|
Object.defineProperty(exports, "UnserializableRecordingError", { enumerable: true, get: function () { return recordingArtifact_js_1.UnserializableRecordingError; } });
|
|
58
60
|
// The battery a store must pass to CLAIM the port, exported beside the port
|
|
59
61
|
// itself so an out-of-tree store imports the check the same way it imports the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/artifacts/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAEH,uCAkBoB;AAjBlB,kHAAA,sBAAsB,OAAA;AACtB,gHAAA,oBAAoB,OAAA;AACpB,iHAAA,qBAAqB,OAAA;AAgBvB,yCAAkF;AAAzE,gHAAA,mBAAmB,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,4GAAA,eAAe,OAAA;AAE5D,+DAKgC;AAJ9B,yHAAA,iBAAiB,OAAA;AACjB,4IAAA,oCAAoC,OAAA;AAItC,uDAI4B;AAH1B,iHAAA,aAAa,OAAA;AACb,+HAAA,2BAA2B,OAAA;AAG7B,2DAK8B;AAJ5B,qHAAA,eAAe,OAAA;AACf,kIAAA,4BAA4B,OAAA;AAI9B,mDAAwE;AAA/D,6GAAA,WAAW,OAAA;AACpB,qDAA2E;AAAlE,+GAAA,YAAY,OAAA;AACrB,+CAUwB;AATtB,iHAAA,iBAAiB,OAAA;AACjB,6GAAA,aAAa,OAAA;AACb,oHAAA,oBAAoB,OAAA;AACpB,oHAAA,oBAAoB,OAAA;AACpB,kHAAA,kBAAkB,OAAA;AAClB,6GAAA,aAAa,OAAA;AAKf,iDAUyB;AATvB,8GAAA,aAAa,OAAA;AACb,sHAAA,qBAAqB,OAAA;AASvB,uCAOoB;AANlB,2GAAA,eAAe,OAAA;AACf,4GAAA,gBAAgB,OAAA;AAChB,kHAAA,sBAAsB,OAAA;AAKxB,2CAMsB;AALpB,+GAAA,iBAAiB,OAAA;AACjB,6GAAA,eAAe,OAAA;AAKjB,+
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/artifacts/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAEH,uCAkBoB;AAjBlB,kHAAA,sBAAsB,OAAA;AACtB,gHAAA,oBAAoB,OAAA;AACpB,iHAAA,qBAAqB,OAAA;AAgBvB,yCAAkF;AAAzE,gHAAA,mBAAmB,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,4GAAA,eAAe,OAAA;AAE5D,+DAKgC;AAJ9B,yHAAA,iBAAiB,OAAA;AACjB,4IAAA,oCAAoC,OAAA;AAItC,uDAI4B;AAH1B,iHAAA,aAAa,OAAA;AACb,+HAAA,2BAA2B,OAAA;AAG7B,2DAK8B;AAJ5B,qHAAA,eAAe,OAAA;AACf,kIAAA,4BAA4B,OAAA;AAI9B,mDAAwE;AAA/D,6GAAA,WAAW,OAAA;AACpB,qDAA2E;AAAlE,+GAAA,YAAY,OAAA;AACrB,+CAUwB;AATtB,iHAAA,iBAAiB,OAAA;AACjB,6GAAA,aAAa,OAAA;AACb,oHAAA,oBAAoB,OAAA;AACpB,oHAAA,oBAAoB,OAAA;AACpB,kHAAA,kBAAkB,OAAA;AAClB,6GAAA,aAAa,OAAA;AAKf,iDAUyB;AATvB,8GAAA,aAAa,OAAA;AACb,sHAAA,qBAAqB,OAAA;AASvB,uCAOoB;AANlB,2GAAA,eAAe,OAAA;AACf,4GAAA,gBAAgB,OAAA;AAChB,kHAAA,sBAAsB,OAAA;AAKxB,2CAMsB;AALpB,+GAAA,iBAAiB,OAAA;AACjB,6GAAA,eAAe,OAAA;AAKjB,+DASgC;AAR9B,yHAAA,iBAAiB,OAAA;AACjB,+HAAA,uBAAuB,OAAA;AACvB,4HAAA,oBAAoB,OAAA;AACpB,gIAAA,wBAAwB,OAAA;AACxB,yHAAA,iBAAiB,OAAA;AACjB,oIAAA,4BAA4B,OAAA;AAI9B,4EAA4E;AAC5E,+EAA+E;AAC/E,6EAA6E;AAC7E,mCAAmC;AACnC,mDAagC;AAZ9B,oHAAA,wBAAwB,OAAA;AACxB,qHAAA,yBAAyB,OAAA;AACzB,gHAAA,oBAAoB,OAAA;AACpB,uHAAA,2BAA2B,OAAA;AAU7B,+CAOwB;AANtB,uHAAA,uBAAuB,OAAA;AACvB,kHAAA,kBAAkB,OAAA;AAClB,gHAAA,gBAAgB,OAAA;AAChB,gHAAA,gBAAgB,OAAA"}
|
|
@@ -33,10 +33,18 @@
|
|
|
33
33
|
* than at whatever reads it next.
|
|
34
34
|
*/
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.recordingPutInput = exports.UnserializableRecordingError = exports.RECORDING_MEDIA_TYPE = exports.RECORDING_ARTIFACT_KIND = void 0;
|
|
36
|
+
exports.chartWalkPutInput = exports.recordingPutInput = exports.UnserializableRecordingError = exports.RECORDING_MEDIA_TYPE = exports.CHART_WALK_ARTIFACT_KIND = exports.RECORDING_ARTIFACT_KIND = void 0;
|
|
37
37
|
/** The consumer vocabulary a run recording is stored under. One kind, exact
|
|
38
38
|
* match — the same rule every `wants` declaration is judged by. */
|
|
39
39
|
exports.RECORDING_ARTIFACT_KIND = 'recording/run';
|
|
40
|
+
/**
|
|
41
|
+
* The consumer vocabulary a chart WALK is stored under (9.76.0) — one row per
|
|
42
|
+
* execution step of a runbook's inner chart, with the decider evidence
|
|
43
|
+
* sentences in the `condition` rows. Namespaced by what it IS (`recording/…`,
|
|
44
|
+
* beside `recording/run`), never by what produced it: a walk is a recording
|
|
45
|
+
* projection, not a dataset that happens to mention stages.
|
|
46
|
+
*/
|
|
47
|
+
exports.CHART_WALK_ARTIFACT_KIND = 'recording/chart-walk';
|
|
40
48
|
/** The media type a recording is minted with. */
|
|
41
49
|
exports.RECORDING_MEDIA_TYPE = 'application/json';
|
|
42
50
|
/**
|
|
@@ -85,4 +93,42 @@ function recordingPutInput(recording, facts = {}) {
|
|
|
85
93
|
};
|
|
86
94
|
}
|
|
87
95
|
exports.recordingPutInput = recordingPutInput;
|
|
96
|
+
/**
|
|
97
|
+
* Turn one chart walk into the `put` input that stores it under
|
|
98
|
+
* {@link CHART_WALK_ARTIFACT_KIND}.
|
|
99
|
+
*
|
|
100
|
+
* Pure, and serialized to JSON TEXT at the mint for exactly the reasons the
|
|
101
|
+
* run recording is (see the file header): a walk row must never be a live
|
|
102
|
+
* view into engine memory, and a walk JSON cannot carry could not cross any
|
|
103
|
+
* wire either.
|
|
104
|
+
*
|
|
105
|
+
* @throws UnserializableRecordingError when the rows cannot be
|
|
106
|
+
* JSON-serialized. Walk rows are projected to plain data upstream, so this
|
|
107
|
+
* firing means the projection let a live value through — fail at the mint,
|
|
108
|
+
* loudly.
|
|
109
|
+
*/
|
|
110
|
+
function chartWalkPutInput(rows, facts = {}) {
|
|
111
|
+
let text;
|
|
112
|
+
try {
|
|
113
|
+
text = JSON.stringify(rows) ?? '';
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
throw new UnserializableRecordingError(err instanceof Error ? err.message : String(err));
|
|
117
|
+
}
|
|
118
|
+
if (text === '') {
|
|
119
|
+
throw new UnserializableRecordingError('it serializes to nothing');
|
|
120
|
+
}
|
|
121
|
+
const origin = {
|
|
122
|
+
...(facts.runId !== undefined && { runId: facts.runId }),
|
|
123
|
+
...(facts.toolCallId !== undefined && { toolCallId: facts.toolCallId }),
|
|
124
|
+
};
|
|
125
|
+
return {
|
|
126
|
+
kind: exports.CHART_WALK_ARTIFACT_KIND,
|
|
127
|
+
mediaType: exports.RECORDING_MEDIA_TYPE,
|
|
128
|
+
data: text,
|
|
129
|
+
label: facts.label ?? (facts.toolName !== undefined ? `${facts.toolName} walk` : 'chart walk'),
|
|
130
|
+
...(Object.keys(origin).length > 0 && { origin }),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
exports.chartWalkPutInput = chartWalkPutInput;
|
|
88
134
|
//# sourceMappingURL=recordingArtifact.js.map
|
|
@@ -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,iDAAiD;AACpC,QAAA,oBAAoB,GAAG,kBAAkB,CAAC;AAoBvD;;;;;GAKG;AACH,MAAa,4BAA6B,SAAQ,KAAK;IAC5C,IAAI,GAAG,8BAAuC,CAAC;IAExD,YAAY,MAAc;QACxB,KAAK,CACH,0DAA0D,MAAM,mBAAmB;YACjF,kFAAkF;YAClF,oFAAoF;YACpF,kFAAkF,CACrF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC;IAC7C,CAAC;CACF;AAZD,oEAYC;AAED;;;;;;;;GAQG;AACH,SAAgB,iBAAiB,CAC/B,SAAkB,EAClB,QAA4B,EAAE;IAE9B,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IACzC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,4BAA4B,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3F,CAAC;IACD,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QAChB,MAAM,IAAI,4BAA4B,CAAC,0BAA0B,CAAC,CAAC;IACrE,CAAC;IACD,OAAO;QACL,IAAI,EAAE,+BAAuB;QAC7B,SAAS,EAAE,4BAAoB;QAC/B,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC;QAC1F,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;KACrE,CAAC;AACJ,CAAC;AApBD,8CAoBC"}
|
|
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;AAoBvD;;;;;GAKG;AACH,MAAa,4BAA6B,SAAQ,KAAK;IAC5C,IAAI,GAAG,8BAAuC,CAAC;IAExD,YAAY,MAAc;QACxB,KAAK,CACH,0DAA0D,MAAM,mBAAmB;YACjF,kFAAkF;YAClF,oFAAoF;YACpF,kFAAkF,CACrF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC;IAC7C,CAAC;CACF;AAZD,oEAYC;AAED;;;;;;;;GAQG;AACH,SAAgB,iBAAiB,CAC/B,SAAkB,EAClB,QAA4B,EAAE;IAE9B,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IACzC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,4BAA4B,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3F,CAAC;IACD,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QAChB,MAAM,IAAI,4BAA4B,CAAC,0BAA0B,CAAC,CAAC;IACrE,CAAC;IACD,OAAO;QACL,IAAI,EAAE,+BAAuB;QAC7B,SAAS,EAAE,4BAAoB;QAC/B,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC;QAC1F,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;KACrE,CAAC;AACJ,CAAC;AApBD,8CAoBC;AAgBD;;;;;;;;;;;;;GAaG;AACH,SAAgB,iBAAiB,CAC/B,IAAwB,EACxB,QAA4B,EAAE;IAE9B,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,4BAA4B,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3F,CAAC;IACD,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QAChB,MAAM,IAAI,4BAA4B,CAAC,0BAA0B,CAAC,CAAC;IACrE,CAAC;IACD,MAAM,MAAM,GAAG;QACb,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;QACxD,GAAG,CAAC,KAAK,CAAC,UAAU,KAAK,SAAS,IAAI,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC;KACxE,CAAC;IACF,OAAO;QACL,IAAI,EAAE,gCAAwB;QAC9B,SAAS,EAAE,4BAAoB;QAC/B,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,QAAQ,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC;QAC9F,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;KAClD,CAAC;AACJ,CAAC;AAxBD,8CAwBC"}
|
package/dist/core/Agent.js
CHANGED
|
@@ -105,6 +105,7 @@ const skillTools_js_1 = require("../lib/injection-engine/skillTools.js");
|
|
|
105
105
|
const skillSteps_js_1 = require("../lib/injection-engine/skillSteps.js");
|
|
106
106
|
const stepNudge_js_1 = require("./agent/stages/stepNudge.js");
|
|
107
107
|
const evidenceRecheck_js_1 = require("./agent/stages/evidenceRecheck.js");
|
|
108
|
+
const stagedRefs_js_1 = require("./agent/stagedRefs.js");
|
|
108
109
|
const wrapUp_js_1 = require("./agent/stages/wrapUp.js");
|
|
109
110
|
const gate_js_1 = require("./agent/evidence/gate.js");
|
|
110
111
|
const errors_js_2 = require("./agent/evidence/errors.js");
|
|
@@ -2901,6 +2902,36 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
2901
2902
|
}
|
|
2902
2903
|
}
|
|
2903
2904
|
}
|
|
2905
|
+
// The composedOf drift gate (9.76.0), judged HERE and not at defineTool —
|
|
2906
|
+
// the one moment the catalog is complete. A tool that declares its
|
|
2907
|
+
// ingredients (`composedOf`, the runbookAsTool law) whose ingredient was
|
|
2908
|
+
// renamed or never registered fails the BUILD by name, instead of failing
|
|
2909
|
+
// its first run inside a stage. Tools delivered by a ToolProvider are
|
|
2910
|
+
// invisible to this check (no build-time list — the 9.72.0 caveat), so
|
|
2911
|
+
// with a provider configured an unmatched name is a dev-mode heads-up
|
|
2912
|
+
// rather than a refusal: the ingredient may genuinely arrive at dispatch.
|
|
2913
|
+
for (const [composedName, registered] of registryByName) {
|
|
2914
|
+
for (const ingredient of registered.composedOf ?? []) {
|
|
2915
|
+
if (registryByName.has(ingredient))
|
|
2916
|
+
continue;
|
|
2917
|
+
if (this.externalToolProvider !== undefined) {
|
|
2918
|
+
if ((0, footprintjs_2.isDevMode)()) {
|
|
2919
|
+
// eslint-disable-next-line no-console
|
|
2920
|
+
console.warn(`[agentfootprint] tool '${composedName}' declares composedOf ingredient ` +
|
|
2921
|
+
`'${ingredient}', which is not in the static catalog. A ToolProvider is ` +
|
|
2922
|
+
`configured, so it may arrive at dispatch — but provider-delivered tools ` +
|
|
2923
|
+
`cannot be drift-checked at build. If '${ingredient}' is static, this is ` +
|
|
2924
|
+
`the rename the check exists to catch.`);
|
|
2925
|
+
}
|
|
2926
|
+
continue;
|
|
2927
|
+
}
|
|
2928
|
+
throw new Error(`Agent: tool '${composedName}' declares composedOf ingredient '${ingredient}', ` +
|
|
2929
|
+
`but no tool of that name is registered on this agent. The declaration names ` +
|
|
2930
|
+
`the tools its procedure calls through ctx.tools, and an ingredient that is ` +
|
|
2931
|
+
`not in the dispatch map fails at its first inner call — refused at build ` +
|
|
2932
|
+
`instead. Register '${ingredient}' (or fix the name in composedOf).`);
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2904
2935
|
// Late-bind toolSchemas into the seed stage's deps (the factory was
|
|
2905
2936
|
// built earlier with a getter; this resolves the actual value).
|
|
2906
2937
|
toolSchemasResolved = toolSchemas;
|
|
@@ -3041,6 +3072,11 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
3041
3072
|
.filter(([, tool]) => tool.argumentsFrom !== undefined)
|
|
3042
3073
|
.map(([name, tool]) => [name, tool.argumentsFrom]));
|
|
3043
3074
|
this.integrityDanglingPresent = toolGrounding.size > 0;
|
|
3075
|
+
// The staged-refs join's other half (grounded numbers): `Tool.wants` by
|
|
3076
|
+
// tool name, harvested the same way and with the same ToolProvider caveat.
|
|
3077
|
+
// Consumed only by the evidence gate (the callLLM nudge and the recheck
|
|
3078
|
+
// correction), so an agent without the gate never reads it.
|
|
3079
|
+
const toolWants = (0, stagedRefs_js_1.toolWantsOf)(registryByName);
|
|
3044
3080
|
const toolsSubflow = (0, buildToolsSlot_js_1.buildToolsSlot)({
|
|
3045
3081
|
tools: toolSchemas,
|
|
3046
3082
|
...(toolOwners.size > 0 && { toolOwners }),
|
|
@@ -3074,6 +3110,10 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
3074
3110
|
// The declared argument-ground edges (9.60.0) — value-conditional, so
|
|
3075
3111
|
// an agent whose tools declare none runs the exact bytes it always did.
|
|
3076
3112
|
...(toolGrounding.size > 0 && { toolGrounding }),
|
|
3113
|
+
// The staged-refs nudge (grounded numbers) — armed only when the dial
|
|
3114
|
+
// is ON and a registered tool declares `wants`; otherwise the stage
|
|
3115
|
+
// reads nothing new and every request keeps its exact bytes.
|
|
3116
|
+
...(this.evidenceGate?.nudge === true && toolWants.size > 0 && { toolWants }),
|
|
3077
3117
|
// The external-ground door (9.72.0) — value-conditional for the same
|
|
3078
3118
|
// reason: no provider, no key, byte-identical corpus assembly.
|
|
3079
3119
|
...(this.externalGrounds !== undefined && { externalGrounds: this.externalGrounds }),
|
|
@@ -3319,7 +3359,19 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
3319
3359
|
...(this.evidenceGate !== undefined && {
|
|
3320
3360
|
hasEvidenceGate: true,
|
|
3321
3361
|
...(this.evidenceGate.posture !== 'assist' && {
|
|
3322
|
-
evidenceRecheckStage: (0, evidenceRecheck_js_1.buildEvidenceRecheckStage)(this.evidenceGate
|
|
3362
|
+
evidenceRecheckStage: (0, evidenceRecheck_js_1.buildEvidenceRecheckStage)(this.evidenceGate,
|
|
3363
|
+
// The staged-refs join (grounded numbers) — the correction names
|
|
3364
|
+
// the refs and the spender when the run declared both. Threaded
|
|
3365
|
+
// whenever a `wants` tool exists (not gated on `nudge`: a
|
|
3366
|
+
// revision that cannot say HOW to compute leaves the model to
|
|
3367
|
+
// head-math again); absent for every agent without one, so the
|
|
3368
|
+
// correction keeps its exact bytes.
|
|
3369
|
+
toolWants.size > 0
|
|
3370
|
+
? {
|
|
3371
|
+
toolWants,
|
|
3372
|
+
staticToolNames: () => toolSchemasResolved.map((t) => t.name),
|
|
3373
|
+
}
|
|
3374
|
+
: undefined),
|
|
3323
3375
|
}),
|
|
3324
3376
|
}),
|
|
3325
3377
|
// Escalation (9.19.0): the grouped chart threads `skillEscalated`
|