agentfootprint 9.95.0 → 9.97.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 +46 -0
- package/CLAUDE.md +2 -1
- package/dist/core/Agent.js +80 -7
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/RunnerBase.js +10 -0
- package/dist/core/RunnerBase.js.map +1 -1
- package/dist/core/agent/buildDynamicAgentChart.js +12 -0
- package/dist/core/agent/buildDynamicAgentChart.js.map +1 -1
- package/dist/core/agent/evidence/gate.js +13 -1
- package/dist/core/agent/evidence/gate.js.map +1 -1
- package/dist/core/agent/evidence/recovery.js +75 -0
- package/dist/core/agent/evidence/recovery.js.map +1 -0
- package/dist/core/agent/stages/callLLM.js +24 -3
- package/dist/core/agent/stages/callLLM.js.map +1 -1
- package/dist/core/agent/stages/evidenceRecheck.js +12 -22
- package/dist/core/agent/stages/evidenceRecheck.js.map +1 -1
- package/dist/core/agent/stages/seed.js +6 -1
- package/dist/core/agent/stages/seed.js.map +1 -1
- package/dist/core/agent/stages/toolCalls.js +22 -3
- package/dist/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/core/inputRequest.js +202 -0
- package/dist/core/inputRequest.js.map +1 -0
- package/dist/core/pause.js +17 -1
- package/dist/core/pause.js.map +1 -1
- package/dist/core/runCheckpoint.js +22 -1
- package/dist/core/runCheckpoint.js.map +1 -1
- package/dist/core/toolSessions.js +10 -8
- package/dist/core/toolSessions.js.map +1 -1
- package/dist/esm/core/Agent.d.ts +6 -2
- package/dist/esm/core/Agent.js +80 -7
- package/dist/esm/core/Agent.js.map +1 -1
- package/dist/esm/core/RunnerBase.d.ts +7 -0
- package/dist/esm/core/RunnerBase.js +10 -0
- package/dist/esm/core/RunnerBase.js.map +1 -1
- package/dist/esm/core/agent/buildDynamicAgentChart.js +12 -0
- package/dist/esm/core/agent/buildDynamicAgentChart.js.map +1 -1
- package/dist/esm/core/agent/evidence/gate.js +13 -1
- package/dist/esm/core/agent/evidence/gate.js.map +1 -1
- package/dist/esm/core/agent/evidence/index.d.ts +1 -1
- package/dist/esm/core/agent/evidence/recovery.d.ts +21 -0
- package/dist/esm/core/agent/evidence/recovery.js +69 -0
- package/dist/esm/core/agent/evidence/recovery.js.map +1 -0
- package/dist/esm/core/agent/evidence/types.d.ts +30 -0
- package/dist/esm/core/agent/stages/callLLM.d.ts +2 -0
- package/dist/esm/core/agent/stages/callLLM.js +24 -3
- package/dist/esm/core/agent/stages/callLLM.js.map +1 -1
- package/dist/esm/core/agent/stages/evidenceRecheck.d.ts +3 -6
- package/dist/esm/core/agent/stages/evidenceRecheck.js +13 -23
- package/dist/esm/core/agent/stages/evidenceRecheck.js.map +1 -1
- package/dist/esm/core/agent/stages/seed.d.ts +3 -0
- package/dist/esm/core/agent/stages/seed.js +6 -1
- package/dist/esm/core/agent/stages/seed.js.map +1 -1
- package/dist/esm/core/agent/stages/toolCalls.d.ts +1 -0
- package/dist/esm/core/agent/stages/toolCalls.js +22 -3
- package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/esm/core/agent/types.d.ts +6 -1
- package/dist/esm/core/inputRequest.d.ts +62 -0
- package/dist/esm/core/inputRequest.js +194 -0
- package/dist/esm/core/inputRequest.js.map +1 -0
- package/dist/esm/core/pause.d.ts +9 -0
- package/dist/esm/core/pause.js +14 -0
- package/dist/esm/core/pause.js.map +1 -1
- package/dist/esm/core/runCheckpoint.d.ts +17 -1
- package/dist/esm/core/runCheckpoint.js +22 -1
- package/dist/esm/core/runCheckpoint.js.map +1 -1
- package/dist/esm/core/toolSessions.d.ts +10 -7
- package/dist/esm/core/toolSessions.js +10 -8
- package/dist/esm/core/toolSessions.js.map +1 -1
- package/dist/esm/events/types.d.ts +1 -1
- package/dist/esm/hosting/httpHost.js +7 -2
- package/dist/esm/hosting/httpHost.js.map +1 -1
- package/dist/esm/hosting/index.d.ts +1 -1
- package/dist/esm/hosting/index.js +1 -1
- package/dist/esm/hosting/index.js.map +1 -1
- package/dist/esm/hosting/ingressRecord.js +8 -3
- package/dist/esm/hosting/ingressRecord.js.map +1 -1
- package/dist/esm/hosting/sessionWire.d.ts +7 -0
- package/dist/esm/hosting/sessionWire.js +6 -3
- package/dist/esm/hosting/sessionWire.js.map +1 -1
- package/dist/esm/hosting/standingAgent.js +70 -4
- package/dist/esm/hosting/standingAgent.js.map +1 -1
- package/dist/esm/hosting/types.d.ts +3 -0
- package/dist/esm/hosting/types.js.map +1 -1
- package/dist/esm/hosting/wireOps.d.ts +2 -0
- package/dist/esm/hosting/wireOps.js +4 -1
- package/dist/esm/hosting/wireOps.js.map +1 -1
- package/dist/esm/index.d.ts +4 -2
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/time-travel/servedView.js +5 -2
- package/dist/esm/lib/time-travel/servedView.js.map +1 -1
- package/dist/esm/recorders/core/contextEngineering.js +1 -0
- package/dist/esm/recorders/core/contextEngineering.js.map +1 -1
- package/dist/hosting/httpHost.js +6 -1
- package/dist/hosting/httpHost.js.map +1 -1
- package/dist/hosting/index.js +2 -1
- package/dist/hosting/index.js.map +1 -1
- package/dist/hosting/ingressRecord.js +7 -2
- package/dist/hosting/ingressRecord.js.map +1 -1
- package/dist/hosting/sessionWire.js +7 -4
- package/dist/hosting/sessionWire.js.map +1 -1
- package/dist/hosting/standingAgent.js +69 -3
- package/dist/hosting/standingAgent.js.map +1 -1
- package/dist/hosting/types.js.map +1 -1
- package/dist/hosting/wireOps.js +4 -1
- package/dist/hosting/wireOps.js.map +1 -1
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/lib/time-travel/servedView.js +5 -2
- package/dist/lib/time-travel/servedView.js.map +1 -1
- package/dist/recorders/core/contextEngineering.js +1 -0
- package/dist/recorders/core/contextEngineering.js.map +1 -1
- package/dist/types/core/Agent.d.ts +6 -2
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/core/RunnerBase.d.ts +7 -0
- package/dist/types/core/RunnerBase.d.ts.map +1 -1
- package/dist/types/core/agent/buildDynamicAgentChart.d.ts.map +1 -1
- package/dist/types/core/agent/evidence/gate.d.ts.map +1 -1
- package/dist/types/core/agent/evidence/index.d.ts +1 -1
- package/dist/types/core/agent/evidence/index.d.ts.map +1 -1
- package/dist/types/core/agent/evidence/recovery.d.ts +22 -0
- package/dist/types/core/agent/evidence/recovery.d.ts.map +1 -0
- package/dist/types/core/agent/evidence/types.d.ts +30 -0
- package/dist/types/core/agent/evidence/types.d.ts.map +1 -1
- package/dist/types/core/agent/stages/callLLM.d.ts +2 -0
- package/dist/types/core/agent/stages/callLLM.d.ts.map +1 -1
- package/dist/types/core/agent/stages/evidenceRecheck.d.ts +3 -6
- package/dist/types/core/agent/stages/evidenceRecheck.d.ts.map +1 -1
- package/dist/types/core/agent/stages/seed.d.ts +3 -0
- package/dist/types/core/agent/stages/seed.d.ts.map +1 -1
- package/dist/types/core/agent/stages/toolCalls.d.ts +1 -0
- package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
- package/dist/types/core/agent/types.d.ts +6 -1
- package/dist/types/core/agent/types.d.ts.map +1 -1
- package/dist/types/core/inputRequest.d.ts +63 -0
- package/dist/types/core/inputRequest.d.ts.map +1 -0
- package/dist/types/core/pause.d.ts +9 -0
- package/dist/types/core/pause.d.ts.map +1 -1
- package/dist/types/core/runCheckpoint.d.ts +17 -1
- package/dist/types/core/runCheckpoint.d.ts.map +1 -1
- package/dist/types/core/toolSessions.d.ts +10 -7
- package/dist/types/core/toolSessions.d.ts.map +1 -1
- package/dist/types/events/types.d.ts +1 -1
- package/dist/types/events/types.d.ts.map +1 -1
- package/dist/types/hosting/httpHost.d.ts.map +1 -1
- package/dist/types/hosting/index.d.ts +1 -1
- package/dist/types/hosting/index.d.ts.map +1 -1
- package/dist/types/hosting/ingressRecord.d.ts.map +1 -1
- package/dist/types/hosting/sessionWire.d.ts +7 -0
- package/dist/types/hosting/sessionWire.d.ts.map +1 -1
- package/dist/types/hosting/standingAgent.d.ts.map +1 -1
- package/dist/types/hosting/types.d.ts +3 -0
- package/dist/types/hosting/types.d.ts.map +1 -1
- package/dist/types/hosting/wireOps.d.ts +2 -0
- package/dist/types/hosting/wireOps.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/time-travel/servedView.d.ts.map +1 -1
- package/dist/types/recorders/core/contextEngineering.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,52 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [9.97.0] - 2026-09-13
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `requestInput()` pauses a collection tool with typed missing fields and a
|
|
13
|
+
runtime-stamped `awaiting_input` state. Partial replies retain accepted values
|
|
14
|
+
without model calls; complete replies resume the same tool boundary and skill
|
|
15
|
+
position through normal result validation, redaction and placement.
|
|
16
|
+
- Hosted typed replies and explicit cancellation preserve session ownership and
|
|
17
|
+
conversation history. `session-pending` reloads the pending question without
|
|
18
|
+
exposing the execution checkpoint. Application defaults remain app-owned.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- Hosted cancellation releases the paused session's run resources without
|
|
23
|
+
executing remaining tools. Run terminals preserve other paused sessions, and
|
|
24
|
+
teardown events retain the actual registration's run and session identity.
|
|
25
|
+
- Keep documentation within existing browser and export budgets: load only the
|
|
26
|
+
syntax grammars used by interactive code blocks and prepare SkillGraph demo
|
|
27
|
+
data on the server while retaining its interactive browser view.
|
|
28
|
+
|
|
29
|
+
## [9.96.1] - 2026-09-13
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- Restore publication within the existing documentation site budget: keep image
|
|
34
|
+
originals outside the static export and prune duplicate internal error pages
|
|
35
|
+
only when both public 404 copies match. Public documentation remains available.
|
|
36
|
+
- Includes the evidence recovery option and request-only correction behavior from
|
|
37
|
+
9.96.0, whose npm publication was blocked by that site budget.
|
|
38
|
+
|
|
39
|
+
## [9.96.0] - 2026-09-13
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
|
|
43
|
+
- Optional `recoveryInstruction` on `.namesAndNumbersFromEvidence()` supplies
|
|
44
|
+
bounded text or a synchronous callback for the existing evidence repair.
|
|
45
|
+
Applications can ask for missing context without suggesting invented values.
|
|
46
|
+
|
|
47
|
+
### Changed
|
|
48
|
+
|
|
49
|
+
- Evidence repair is delivered as request-only system context, with the rejected
|
|
50
|
+
draft quoted as untrusted data, instead of synthetic conversation turns.
|
|
51
|
+
Token checks, postures and the one-revision limit remain unchanged. This is
|
|
52
|
+
lexical checking, not proof of question interpretation or claim semantics.
|
|
53
|
+
|
|
8
54
|
## [9.95.0] - 2026-09-12
|
|
9
55
|
|
|
10
56
|
### Added
|
package/CLAUDE.md
CHANGED
|
@@ -17,6 +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
|
+
| guiding an evidence repair to ask for missing context without inventing values | `recoveryInstruction` + `EvidenceRecoveryContext` | `src/core/agent/evidence/` | 9.96.0 |
|
|
20
21
|
| checking a typed final answer against scoped evidence before streaming or memory delivery — optional host-authored checks with enforce/observe modes, canonical JSON and bounded read-only artifacts | `answerValidation` + `AnswerValidationError` | `src/answer-validation/` | 9.95.0 |
|
|
21
22
|
| 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; `verdict_meanings` = statically declared branches + this run's rule labels + the DEFAULT branch's label, which reaches evidence only when the chart calls `decide(s, rules, {branch, label})` — fp ≥9.16.1, the default is chosen by NO rule so nothing else can name it, and inside a generated fan-out branch the static walk is blind too; an undeclared or blank label stays ABSENT from the map, never invented from a branch id, and there is deliberately NO caller-supplied meanings map) + `presentation` (`'prose'` default = ship `table` + `VERDICT_RENDER_NOTE` "output it VERBATIM"; `'panel'` = the HOST renders the rowset, so NO `table` key at all + `PANEL_RENDER_NOTE` "the rows are already on the reader's screen — do not reproduce them"; the rowset half is byte-identical across modes, `table` stays RESERVED in both, an unknown value THROWS at definition) + `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 |
|
|
22
23
|
| speaking MCP from a BROWSER — the SDK is browser-clean (its client + streamableHttp bundle at `platform:'browser'` with zero `node:` edges and never pull in `client/stdio.js`); the one barrier was that `lazyRequire` gets CALLED there, so the fix is to let the caller supply what the loader would have found | `mcpClient({ sdk })` (`McpSdk` = the two SDK modules you imported statically; the library STILL builds the transport, so headers/fetch/gateway vending/`retryOnThrottle`/`_meta` all keep working) · `mcpClient({ connection })` (`McpConnection` = listTools/callTool/close, deliberately NO `connect` — you already did; the only arm that reaches the SDK's `jsonSchemaValidator`, i.e. CSP) + `McpConnectionOptions`; `refuseConflictingOptions` REFUSES at construction every option a transport would have consumed, naming where it moved (a knob naming a behaviour that no longer happens is the defect class); `transportUrl` resolves a relative `url` against `globalThis.location.href` (absolute takes the identical branch, Node refuses by name); `sdkLoadFailure` classifies the seven load sites so a browser is never told to install a package it has (resolution failure ⇒ byte-identical historical message); `retryingFetch` + `ThrottleFetch` promoted out of `@internal` so the connection arm keeps its 429 handling. stdio keeps `lazyRequire` FOREVER — it spawns a subprocess. ZERO packaging change: no subpath, no `browser` condition (TypeScript is blind to it), peer stays optional (no literal dynamic `import()`). Fenced by `test/lib/mcp/browserGraph.test.ts` | `src/lib/mcp/` | 9.81.0 |
|
|
@@ -144,7 +145,7 @@ Traps: `src/observability/` holds the finder IMPLEMENTATIONS (canonical home; `d
|
|
|
144
145
|
- **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.
|
|
145
146
|
- **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.
|
|
146
147
|
- **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.
|
|
147
|
-
- **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
|
|
148
|
+
- **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 names the same refs+spender whenever a `wants` tool exists, NOT gated on `nudge`. Since 9.96.0 `evidence/recovery.ts` · `buildEvidenceRecovery` composes request-only system guidance; `evidenceRecoveryPiece` carries it into the next request without synthetic conversation turns. Optional `recoveryInstruction` adds bounded synchronous guidance; `buildEvidenceCorrection` remains a legacy compatibility helper. Token extraction, exemptions and the single-revision budget are unchanged; this is not semantic validation or streaming draft suppression.
|
|
148
149
|
- **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.
|
|
149
150
|
- **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.
|
|
150
151
|
- **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".
|
package/dist/core/Agent.js
CHANGED
|
@@ -118,6 +118,7 @@ const routeTurn_js_1 = require("./agent/stages/routeTurn.js");
|
|
|
118
118
|
const outputFallback_js_1 = require("./outputFallback.js");
|
|
119
119
|
const runCheckpoint_js_1 = require("./runCheckpoint.js");
|
|
120
120
|
const conversation_js_1 = require("./conversation.js");
|
|
121
|
+
const inputRequest_js_1 = require("./inputRequest.js");
|
|
121
122
|
const outputSchema_js_1 = require("./outputSchema.js");
|
|
122
123
|
const runInput_js_1 = require("./runInput.js");
|
|
123
124
|
const outputRetry_js_1 = require("./agent/stages/outputRetry.js");
|
|
@@ -419,6 +420,8 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
419
420
|
* function restores `scope.history` from this instead of starting
|
|
420
421
|
* fresh. Cleared on first read so subsequent runs start clean. */
|
|
421
422
|
pendingResumeHistory;
|
|
423
|
+
/** Retried request's repair state; never inherited by a new human turn. */
|
|
424
|
+
pendingEvidenceRecovery;
|
|
422
425
|
/** Its sibling for the folded spans. A restored conversation that dropped
|
|
423
426
|
* them would carry summaries nobody could unpack — the evidence would be
|
|
424
427
|
* destroyed by the act of continuing, which is the one thing retention
|
|
@@ -1353,7 +1356,7 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
1353
1356
|
this.conversationOwner(),
|
|
1354
1357
|
// …and the same graph cursor (SG-C), from the same snapshot reader —
|
|
1355
1358
|
// one reader, two carriers, so neither can lose what the other keeps.
|
|
1356
|
-
this.continuityCursorOf(this.getLastSnapshot()?.sharedState));
|
|
1359
|
+
this.continuityCursorOf(this.getLastSnapshot()?.sharedState), this.evidenceRecoveryOf(this.getLastSnapshot()?.sharedState));
|
|
1357
1360
|
throw new runCheckpoint_js_1.RunCheckpointError(cause, checkpoint);
|
|
1358
1361
|
}
|
|
1359
1362
|
throw cause;
|
|
@@ -1375,6 +1378,7 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
1375
1378
|
this.pendingResumeHistory = undefined;
|
|
1376
1379
|
this.pendingResumeFolded = undefined;
|
|
1377
1380
|
this.pendingResumeSkillCursor = undefined;
|
|
1381
|
+
this.pendingEvidenceRecovery = undefined;
|
|
1378
1382
|
}
|
|
1379
1383
|
}
|
|
1380
1384
|
/**
|
|
@@ -1601,6 +1605,38 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
1601
1605
|
const gate = (0, pause_js_1.pauseDemandsDecision)(checkpoint.pauseData);
|
|
1602
1606
|
if (gate && !(0, checkin_js_1.isCheckInDecision)(input))
|
|
1603
1607
|
throw new pause_js_1.DecisionRequiredError(gate, input);
|
|
1608
|
+
// Typed data collection is not consent. Validate before changing any run state.
|
|
1609
|
+
const awaitingInput = gate === undefined ? (0, inputRequest_js_1.readAwaitingInput)(checkpoint.pauseData) : undefined;
|
|
1610
|
+
if (awaitingInput !== undefined) {
|
|
1611
|
+
this.assertNotRunning('Agent.resume');
|
|
1612
|
+
const answered = (0, inputRequest_js_1.applyInputResponse)(awaitingInput, input);
|
|
1613
|
+
if ('cancel' in answered) {
|
|
1614
|
+
throw new TypeError('[input request] Cancel a hosted request through its host, or abandonPause() before starting another run.');
|
|
1615
|
+
}
|
|
1616
|
+
if (answered.missing.length > 0) {
|
|
1617
|
+
const copy = structuredClone(checkpoint);
|
|
1618
|
+
const pauseData = {
|
|
1619
|
+
...copy.pauseData,
|
|
1620
|
+
awaitingInput: answered,
|
|
1621
|
+
};
|
|
1622
|
+
const outcome = {
|
|
1623
|
+
paused: true,
|
|
1624
|
+
checkpoint: { ...copy, pauseData },
|
|
1625
|
+
pauseData,
|
|
1626
|
+
awaitingInput: answered,
|
|
1627
|
+
};
|
|
1628
|
+
this.recordPendingQuestion(outcome);
|
|
1629
|
+
return outcome;
|
|
1630
|
+
}
|
|
1631
|
+
input = {
|
|
1632
|
+
status: 'input_received',
|
|
1633
|
+
requestId: answered.requestId,
|
|
1634
|
+
values: answered.supplied,
|
|
1635
|
+
origins: answered.origins,
|
|
1636
|
+
origin: answered.origin,
|
|
1637
|
+
...(answered.context !== undefined && { context: answered.context }),
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1604
1640
|
// And the answer must be about the thing that was asked. Checked HERE, at
|
|
1605
1641
|
// the same door and before any state moves, because a resume that has begun
|
|
1606
1642
|
// is a resume that has already used the value.
|
|
@@ -1675,7 +1711,7 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
1675
1711
|
* Fired for the TURN, not for `currentRunContext.runId` — `resume()` mints a
|
|
1676
1712
|
* fresh run id, so a pause and its resume are one turn across two runs, and
|
|
1677
1713
|
* filtering on the id would leave everything a paused turn opened alive
|
|
1678
|
-
* forever. See `ToolSessionTier.fireRun`.
|
|
1714
|
+
* forever. Hosted turns are scoped to their session, preserving other pauses. See `ToolSessionTier.fireRun`.
|
|
1679
1715
|
*
|
|
1680
1716
|
* @param outcome what `run()`/`resume()` is about to return, or about to throw.
|
|
1681
1717
|
*/
|
|
@@ -1686,7 +1722,10 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
1686
1722
|
return;
|
|
1687
1723
|
if (outcome instanceof Error && outcome.name === 'PauseSignal')
|
|
1688
1724
|
return;
|
|
1689
|
-
|
|
1725
|
+
if (this.currentRunContext.sessionId !== undefined)
|
|
1726
|
+
await this.toolSessionTier.fireSessionRuns(this.currentRunContext.sessionId);
|
|
1727
|
+
else
|
|
1728
|
+
await this.toolSessionTier.fireRun();
|
|
1690
1729
|
}
|
|
1691
1730
|
/**
|
|
1692
1731
|
* The conversation this agent's LAST completed run leaves behind, packed as
|
|
@@ -1743,6 +1782,7 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
1743
1782
|
const folded = this.foldedSpansOf(state);
|
|
1744
1783
|
const owner = this.conversationOwner();
|
|
1745
1784
|
const skillCursor = this.continuityCursorOf(state);
|
|
1785
|
+
const evidenceRecovery = this.evidenceRecoveryOf(state);
|
|
1746
1786
|
return {
|
|
1747
1787
|
version: 1,
|
|
1748
1788
|
runId: this.currentRunContext.runId,
|
|
@@ -1761,6 +1801,20 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
1761
1801
|
// `continuity: 'conversation'`, so every other checkpoint keeps its
|
|
1762
1802
|
// exact byte shape.
|
|
1763
1803
|
...(skillCursor !== undefined && { skillCursor }),
|
|
1804
|
+
...(evidenceRecovery !== undefined && { evidenceRecovery }),
|
|
1805
|
+
};
|
|
1806
|
+
}
|
|
1807
|
+
/** Both checkpoint doors keep the repair budget separately from conversation text. */
|
|
1808
|
+
evidenceRecoveryOf(state) {
|
|
1809
|
+
if (state?.evidenceRevisionSpent !== true)
|
|
1810
|
+
return undefined;
|
|
1811
|
+
const pending = state.evidenceRecovery;
|
|
1812
|
+
return {
|
|
1813
|
+
revisionSpent: true,
|
|
1814
|
+
...(pending !== undefined &&
|
|
1815
|
+
state.evidenceRecoveryUsed !== true && {
|
|
1816
|
+
pending: { instruction: pending.instruction },
|
|
1817
|
+
}),
|
|
1764
1818
|
};
|
|
1765
1819
|
}
|
|
1766
1820
|
/**
|
|
@@ -1853,6 +1907,12 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
1853
1907
|
// continuity graph and continued on a `'turn'` one is consumed and
|
|
1854
1908
|
// ignored, exactly like a `folded` field on an agent that never folds.
|
|
1855
1909
|
this.pendingResumeSkillCursor = cp.skillCursor;
|
|
1910
|
+
// Same failed request retains its single repair budget. A new user turn
|
|
1911
|
+
// receives neither the rejected draft nor a spent retry allowance.
|
|
1912
|
+
this.pendingEvidenceRecovery =
|
|
1913
|
+
appendMessage === undefined && cp.evidenceRecovery !== undefined
|
|
1914
|
+
? structuredClone(cp.evidenceRecovery)
|
|
1915
|
+
: undefined;
|
|
1856
1916
|
}
|
|
1857
1917
|
/** One turn at a time — see `RunInFlightError`. @internal */
|
|
1858
1918
|
assertNotRunning(door) {
|
|
@@ -1957,6 +2017,7 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
1957
2017
|
*/
|
|
1958
2018
|
toolRunFacts() {
|
|
1959
2019
|
return {
|
|
2020
|
+
runContext: { ...this.currentRunContext },
|
|
1960
2021
|
runId: this.currentRunContext.runId,
|
|
1961
2022
|
...(this.currentRunContext.sessionId !== undefined && {
|
|
1962
2023
|
sessionId: this.currentRunContext.sessionId,
|
|
@@ -1974,7 +2035,7 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
1974
2035
|
if (!this.toolSessionTier) {
|
|
1975
2036
|
this.toolSessionTier = new toolSessions_js_1.ToolSessionTier({
|
|
1976
2037
|
timeoutMs: this.toolTeardownTimeoutMs,
|
|
1977
|
-
report: (report) => this.emitToolSessionReport(report),
|
|
2038
|
+
report: (report, origin) => this.emitToolSessionReport(report, origin),
|
|
1978
2039
|
});
|
|
1979
2040
|
}
|
|
1980
2041
|
return this.toolSessionTier;
|
|
@@ -1993,10 +2054,10 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
1993
2054
|
* hardcodes `runId: 'consumer-scope'`, and a teardown event stamped that way
|
|
1994
2055
|
* cannot be joined to the run that OPENED the session — the exact
|
|
1995
2056
|
* unjoinability 9.4.0 spent a release fixing for credential events. So the
|
|
1996
|
-
* meta comes from
|
|
2057
|
+
* meta comes from the registration-time run context, with a STATED pseudo-stage, the same
|
|
1997
2058
|
* move as the `'<stageId>#paused'` stamp at the pause boundary.
|
|
1998
2059
|
*/
|
|
1999
|
-
emitToolSessionReport(report) {
|
|
2060
|
+
emitToolSessionReport(report, origin) {
|
|
2000
2061
|
const type = report.kind === 'closed'
|
|
2001
2062
|
? 'agentfootprint.tools.session_closed'
|
|
2002
2063
|
: 'agentfootprint.tools.session_close_failed';
|
|
@@ -2007,7 +2068,7 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
2007
2068
|
dispatcher.dispatch({
|
|
2008
2069
|
type,
|
|
2009
2070
|
payload,
|
|
2010
|
-
meta: (0, eventMeta_js_1.buildEventMeta)({ runtimeStageId: TOOL_TEARDOWN_STAGE_ID }, this.currentRunContext),
|
|
2071
|
+
meta: (0, eventMeta_js_1.buildEventMeta)({ runtimeStageId: TOOL_TEARDOWN_STAGE_ID }, origin.runContext ?? this.currentRunContext),
|
|
2011
2072
|
});
|
|
2012
2073
|
}
|
|
2013
2074
|
openSkillIds() {
|
|
@@ -2975,6 +3036,14 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
2975
3036
|
this.pendingResumeHistory = undefined;
|
|
2976
3037
|
return h;
|
|
2977
3038
|
},
|
|
3039
|
+
...(this.evidenceGate !== undefined &&
|
|
3040
|
+
this.evidenceGate.posture !== 'assist' && {
|
|
3041
|
+
consumePendingEvidenceRecovery: () => {
|
|
3042
|
+
const recovery = this.pendingEvidenceRecovery;
|
|
3043
|
+
this.pendingEvidenceRecovery = undefined;
|
|
3044
|
+
return recovery;
|
|
3045
|
+
},
|
|
3046
|
+
}),
|
|
2978
3047
|
consumePendingResumeFolded: () => {
|
|
2979
3048
|
const f = this.pendingResumeFolded;
|
|
2980
3049
|
this.pendingResumeFolded = undefined;
|
|
@@ -3306,6 +3375,10 @@ class Agent extends RunnerBase_js_1.RunnerBase {
|
|
|
3306
3375
|
// callLLM extracted to ./agent/stages/callLLM.ts (v2.11.2). Same
|
|
3307
3376
|
// late-binding pattern as seed for toolSchemas (computed below).
|
|
3308
3377
|
const callLLM = (0, callLLM_js_1.buildCallLLMStage)({
|
|
3378
|
+
...(this.evidenceGate !== undefined &&
|
|
3379
|
+
this.evidenceGate.posture !== 'assist' && {
|
|
3380
|
+
hasEvidenceRecovery: true,
|
|
3381
|
+
}),
|
|
3309
3382
|
...(this.answerValidationConfig !== undefined && { suppressDraftTokens: true }),
|
|
3310
3383
|
// The receipt's salt (9.88.0) — read per call, like seed's own accessor.
|
|
3311
3384
|
getRunId: () => this.currentRunContext?.runId,
|