@arnilo/prism 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/CHANGELOG.md +79 -5
  2. package/README.md +12 -11
  3. package/dist/agent-approval.d.ts +4 -0
  4. package/dist/agent-approval.js +5 -1
  5. package/dist/agent-definitions.js +1 -0
  6. package/dist/agent-run-lifecycle.js +39 -4
  7. package/dist/agent-run-state.d.ts +18 -0
  8. package/dist/agent-run-state.js +39 -9
  9. package/dist/agent-session/helpers.js +6 -1
  10. package/dist/agent-session/session/assemble.js +159 -7
  11. package/dist/agent-session/session/persist.d.ts +16 -0
  12. package/dist/agent-session/session/persist.js +64 -4
  13. package/dist/agent-session/session/provider-round.d.ts +3 -3
  14. package/dist/agent-session/session/provider-round.js +12 -6
  15. package/dist/agent-session/session/tool-round.js +5 -1
  16. package/dist/agent-session/session/types.d.ts +22 -1
  17. package/dist/agent-session/session.d.ts +16 -0
  18. package/dist/agent-session/session.js +42 -3
  19. package/dist/artifacts.d.ts +39 -1
  20. package/dist/artifacts.js +73 -0
  21. package/dist/attention-compiler.d.ts +121 -0
  22. package/dist/attention-compiler.js +479 -0
  23. package/dist/checkpoints.js +7 -11
  24. package/dist/cli-init.js +20 -6
  25. package/dist/context-budget.d.ts +20 -1
  26. package/dist/context-budget.js +10 -1
  27. package/dist/contracts-core/agent.d.ts +7 -0
  28. package/dist/contracts-core/attention.d.ts +66 -0
  29. package/dist/contracts-core/attention.js +2 -0
  30. package/dist/contracts-core/compaction.d.ts +59 -0
  31. package/dist/contracts-core/compaction.js +77 -1
  32. package/dist/contracts-core/content.d.ts +5 -0
  33. package/dist/contracts-core/loop.d.ts +42 -0
  34. package/dist/contracts-core/provider.d.ts +4 -0
  35. package/dist/contracts-core/run-limits.d.ts +2 -0
  36. package/dist/contracts-core.d.ts +1 -0
  37. package/dist/contracts-core.js +1 -0
  38. package/dist/contracts-protocol.d.ts +44 -3
  39. package/dist/contracts-run-state.d.ts +32 -5
  40. package/dist/evidence-grounding.d.ts +29 -0
  41. package/dist/evidence-grounding.js +162 -0
  42. package/dist/host-composition.d.ts +91 -0
  43. package/dist/host-composition.js +279 -0
  44. package/dist/index.d.ts +13 -6
  45. package/dist/index.js +7 -4
  46. package/dist/input.d.ts +13 -1
  47. package/dist/input.js +40 -1
  48. package/dist/provider-events.d.ts +3 -1
  49. package/dist/provider-events.js +2 -2
  50. package/dist/providers/transport.d.ts +3 -1
  51. package/dist/providers/transport.js +36 -0
  52. package/dist/redaction.js +18 -2
  53. package/dist/run-bundle.d.ts +89 -0
  54. package/dist/run-bundle.js +149 -0
  55. package/dist/secure-agent.d.ts +2 -0
  56. package/dist/secure-agent.js +6 -1
  57. package/dist/testing/state-concurrency-conformance.js +5 -12
  58. package/dist/tool-result-fold.d.ts +12 -0
  59. package/dist/tool-result-fold.js +13 -6
  60. package/dist/tools.d.ts +10 -0
  61. package/dist/tools.js +41 -0
  62. package/docs/acp-agent.md +42 -11
  63. package/docs/acp.md +2 -1
  64. package/docs/ag-ui.md +10 -3
  65. package/docs/agent-definitions.md +9 -1
  66. package/docs/agent-events.md +4 -1
  67. package/docs/agent-loops.md +33 -0
  68. package/docs/agent-session-runtime.md +8 -7
  69. package/docs/attention-compiler.md +272 -0
  70. package/docs/cli-rpc.md +4 -2
  71. package/docs/coding-agent-tools.md +1 -1
  72. package/docs/coding-security.md +6 -3
  73. package/docs/coding-tools.md +0 -1
  74. package/docs/coding-workspaces.md +22 -0
  75. package/docs/compaction-and-retry.md +36 -4
  76. package/docs/compaction-observational-memory.md +63 -10
  77. package/docs/connected-apps.md +116 -0
  78. package/docs/context-and-skills.md +17 -2
  79. package/docs/conversations.md +1 -1
  80. package/docs/core.md +1 -1
  81. package/docs/dev-inspector.md +4 -0
  82. package/docs/device-adapters.md +1 -0
  83. package/docs/diagrams.md +6 -6
  84. package/docs/document-reader.md +18 -10
  85. package/docs/documents.md +40 -11
  86. package/docs/durable-runs.md +87 -0
  87. package/docs/enterprise-postgres-state.md +6 -2
  88. package/docs/evaluations.md +168 -4
  89. package/docs/execution-timeline.md +186 -0
  90. package/docs/guardrails.md +33 -0
  91. package/docs/history/0.7.0-primitive-review.md +254 -0
  92. package/docs/history/079-messaging-primitive-review.md +391 -0
  93. package/docs/history/080-messaging-followon-primitive-review.md +234 -0
  94. package/docs/history/081-connected-apps-primitive-review.md +74 -0
  95. package/docs/history/083-prism-work-primitive-review.md +84 -0
  96. package/docs/history/084-primitive-review.md +96 -0
  97. package/docs/history/085-honesty-and-cut-primitive-review.md +91 -0
  98. package/docs/history/README.md +5 -0
  99. package/docs/history/migration-0.0.md +2 -2
  100. package/docs/history/release-handoffs.md +75 -1
  101. package/docs/host-compositions.md +149 -0
  102. package/docs/host-security.md +2 -2
  103. package/docs/hosted-sandboxes.md +94 -0
  104. package/docs/index.md +82 -45
  105. package/docs/input-and-prompt-assembly.md +1 -0
  106. package/docs/knowledge-sync.md +84 -0
  107. package/docs/language-intelligence.md +1 -1
  108. package/docs/live-testing.md +8 -3
  109. package/docs/mcp-tools.md +3 -1
  110. package/docs/memory-fabric.md +416 -0
  111. package/docs/messaging-channel-operations.md +166 -0
  112. package/docs/messaging-channels.md +150 -0
  113. package/docs/migrate-to-0.5.md +1 -1
  114. package/docs/migrate-to-0.6.md +1 -0
  115. package/docs/migrate-to-0.7.md +345 -0
  116. package/docs/migrate-to-0.8.md +124 -0
  117. package/docs/migration.md +43 -1
  118. package/docs/model-registry.md +12 -2
  119. package/docs/model-routing.md +79 -4
  120. package/docs/multi-agent-patterns.md +20 -6
  121. package/docs/observability.md +52 -1
  122. package/docs/openapi-tools.md +1 -1
  123. package/docs/operations.md +14 -4
  124. package/docs/options-index.md +47 -3
  125. package/docs/peer-dependencies.md +12 -10
  126. package/docs/postgres-persistence.md +1 -1
  127. package/docs/process-sessions.md +3 -1
  128. package/docs/prompt-registry.md +1 -1
  129. package/docs/provider-caching.md +4 -2
  130. package/docs/provider-conformance.md +1 -1
  131. package/docs/provider-layer.md +2 -2
  132. package/docs/provider-packages.md +22 -22
  133. package/docs/providers/bedrock.md +71 -7
  134. package/docs/providers/neuralwatt.md +5 -1
  135. package/docs/providers/openai.md +1 -1
  136. package/docs/rag.md +24 -8
  137. package/docs/realtime-voice.md +87 -0
  138. package/docs/release-and-install.md +53 -45
  139. package/docs/run-bundle.md +92 -0
  140. package/docs/runs-and-usage.md +17 -2
  141. package/docs/server.md +7 -3
  142. package/docs/sheets.md +9 -9
  143. package/docs/signal-channel.md +112 -0
  144. package/docs/speech.md +7 -1
  145. package/docs/sqlite-persistence.md +1 -1
  146. package/docs/supervisors.md +33 -5
  147. package/docs/telegram-channel.md +157 -0
  148. package/docs/testing.md +2 -2
  149. package/docs/thinking-and-reasoning.md +3 -1
  150. package/docs/tools.md +6 -5
  151. package/docs/web-tools.md +2 -1
  152. package/docs/wiki.md +1 -1
  153. package/docs/work-artifacts-and-review.md +14 -4
  154. package/docs/work-connectors.md +12 -10
  155. package/docs/work-sandbox.md +115 -0
  156. package/docs/work-tools.md +50 -18
  157. package/docs/workflows.md +69 -1
  158. package/docs/working-and-semantic-memory.md +25 -14
  159. package/package.json +5 -3
  160. package/templates/README.md +2 -0
  161. package/templates/business-worker/README.md.tmpl +19 -0
  162. package/templates/business-worker/env.example.tmpl +1 -0
  163. package/templates/business-worker/gitignore.tmpl +11 -0
  164. package/templates/business-worker/manifest.json +12 -0
  165. package/templates/business-worker/package.json.tmpl +23 -0
  166. package/templates/business-worker/src/agent.ts.tmpl +92 -0
  167. package/templates/business-worker/src/index.ts.tmpl +13 -0
  168. package/templates/business-worker/src/tests/agent.test.ts.tmpl +77 -0
  169. package/templates/business-worker/tsconfig.json.tmpl +15 -0
  170. package/templates/personal-assistant/README.md.tmpl +18 -0
  171. package/templates/personal-assistant/env.example.tmpl +1 -0
  172. package/templates/personal-assistant/gitignore.tmpl +11 -0
  173. package/templates/personal-assistant/manifest.json +11 -0
  174. package/templates/personal-assistant/package.json.tmpl +23 -0
  175. package/templates/personal-assistant/src/agent.ts.tmpl +65 -0
  176. package/templates/personal-assistant/src/index.ts.tmpl +13 -0
  177. package/templates/personal-assistant/src/tests/agent.test.ts.tmpl +28 -0
  178. package/templates/personal-assistant/tsconfig.json.tmpl +15 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,77 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.8.0] - 2026-09-18 (messaging channels, connected apps, work family, durable runs, honesty gates)
4
+
5
+ > **Eleven publishable packages.** `@arnilo/prism-channels` is new; `@arnilo/prism-work` replaces `@arnilo/prism-office`. Predecessor published line is **0.7.0**. Registry/tag writes stay operator-authorized.
6
+
7
+ ### Added
8
+ - **Messaging channels.** `@arnilo/prism-channels` ships the transport-neutral runtime (deny-by-default sender authorization, owned session binding, serialized turns, current-run replies, one-use durable approvals, bounded attachment refs), official Telegram (private DMs, opt-in granted groups/topics, private-chat drafts, bounded media, optional voice transcription/synthesis, opt-in notices to one already-bound pair), and experimental pinned signal-cli Signal. See [docs/messaging-channels.md](docs/messaging-channels.md), [docs/telegram-channel.md](docs/telegram-channel.md), [docs/signal-channel.md](docs/signal-channel.md), [docs/messaging-channel-operations.md](docs/messaging-channel-operations.md).
9
+ - **Connected apps and work HTTP.** Identity-bound MCP connected-app sessions admit host-selected transports and register prefixed tools. Google Workspace and Microsoft 365 HTTP adapters live under `@arnilo/prism-work/connectors`. Slack MCP wrap and Open Connector sidecar stay examples. See [docs/connected-apps.md](docs/connected-apps.md), [docs/work-connectors.md](docs/work-connectors.md).
10
+ - **Durable runs, turn-boundary stops, and run-bundle snapshots.** `AgentRunStateOptions.checkpointPolicy: "every-turn"` checkpoints a run at the provider-turn boundary so a crashed worker resumes with the host-only `decision: "continue"` action (never reachable from AG-UI or the server boundary, and rejected while any approval or ready tool call is pending). `RunOptions.turnPolicy` (`TurnPolicyOptions`) stops a run synchronously at a turn boundary and reports `stopReason: "host_policy"` with a redacted, bounded `stopDetail` on the result, the ledger row, the `agent_finished` event, and the execution timeline; a host-policy stop stays resumable. `snapshotRunBundle` returns a `RunBundleSnapshot` — a frozen, redacted digest projection of the effective run bundle with zero store or network reads. `createClaimGroundingGuardrail` (stage `"output"`) blocks or flags numeric claims that no tool result or host evidence supports. `ErrorInfo.failureClass` (`ProviderFailureClass`) types provider failures as `quota` / `rate_limited` / `auth` / `transient` / `permanent` / `unknown`; `ModelCapabilities.toolCallStrictness` adds advisory tool-call reliability. See [docs/durable-runs.md](docs/durable-runs.md), [docs/run-bundle.md](docs/run-bundle.md), [docs/guardrails.md](docs/guardrails.md).
11
+ - **Work sandbox and vendored skills.** `@arnilo/prism-work/sandbox` plus `createWorkComposition` run office/exec in an injected Docker sandbox; connectors stay on the host. The package ships `docx`, `xlsx`, `powerpoint`, `pdf` skills.
12
+
13
+ ### Changed
14
+ - **Lockstep `0.7.0` → `0.8.0`.** All eleven publishable manifests move together with `^0.8.0` internal ranges; the lockfile, the `src/index.ts` version constant, the docs index banner, the release-workflow tag lists, and the generated package-truth artifact agree (enforced by `scripts/version-literal-gate.test.mjs`).
15
+ - **Work family rename.** `@arnilo/prism-office` is replaced by `@arnilo/prism-work` (connectors, documents, sheets, diagrams, document-reader, sandbox, skills, tools). No pre-1.0 shim. See [docs/migrate-to-0.8.md](docs/migrate-to-0.8.md).
16
+ - **AG-UI input authority is opt-in server-side.** `CreateAgUiHandlerOptions.inputPolicy.clientState: "ignore"` validates then discards client-supplied AG-UI state and tools before projection, and stops advertising client-provided tools; the default `"honor"` path is byte-identical to 0.7.0.
17
+ - **Observational-memory workers are tool-only.** Text/thinking/done-only turns are successful no-ops. Limit and unknown-tool failures throw `MemoryError` / `MemoryLimitError` rather than matching an English message prefix.
18
+ - **Channel lease release is fail-closed.** In-memory `route.lease` clears only after the store acknowledges; a failed release retries on idle/`stop`. TTL remains the cross-process backstop.
19
+ - **This-tree Postgres evidence.** `release:gate` reports `test:postgres` as pass only when `scripts/postgres-evidence.json` matches current `git rev-parse HEAD`. A stale phase baseline is blocked.
20
+ - **Compat baselines regenerated** at 0.8.0. Inherited 083 `@arnilo/prism-office` → `@arnilo/prism-work` removals (and `prism-core` / `prism-coding-tools` moves) are listed separately from 085 additions. This cut's own Tasks 1–6 add no public removals.
21
+ - **Migration guide for 0.7.0 hosts**: [docs/migrate-to-0.8.md](docs/migrate-to-0.8.md), indexed from [docs/migration.md](docs/migration.md) and [docs/index.md](docs/index.md).
22
+
23
+ ### Fixed
24
+ - **Portable work-idempotency error codes survived the work-family move.** The enterprise PostgreSQL `IdempotencyStore` adapter keeps `ERR_PRISM_WORK_IDEMPOTENCY` / `ERR_PRISM_WORK_IDEMPOTENCY_CONFLICT`; only the error class changed (`EnterprisePostgresError`).
25
+ - **Stale ownership assertions in the protected PostgreSQL leg:** a foreign checkpoint scope is a miss plus a generic CAS conflict, and a foreign agent-run status read is indistinguishable from a missing run (`ERR_PRISM_AGENT_RUN_STATE`).
26
+ - **Wiki isolation nested-runner flake.** The wiki scratch gate spawns `node --test --test-isolation=none` (still strips `NODE_TEST_CONTEXT` / `NODE_TEST_WORKER_ID`) so worker IPC deserialization cannot fail the gate under `npm test` load.
27
+ - **Coverage artifact names.** Package keys in `scripts/coverage-summary.json` must equal live workspace manifests (`@arnilo/prism-work`, not `@arnilo/prism-office`).
28
+ - **Alibaba video `fetchUrl`.** Declared `fetchUrl` now downloads generated video bytes; unused OpenAI speech `_bearerHeaders` deleted.
29
+
30
+ ### Security
31
+ - **Numeric claims must be grounded or they fail closed.** The claim-grounding guardrail blocks by default, bounds every reported span, caps evidence collection (4,096 figures, 16 levels, 128 KiB), and treats a missing evidence set as ungrounded rather than passing silently.
32
+ - **Crash recovery cannot bypass approval gates.** `"continue"` resumes only a running checkpoint with no pending decision or ready call, and keeps the recorded fingerprint, revision, ownership/fencing, and CAS-version gates.
33
+ - **Failed channel lease release is not success.** This process does not treat the binding as free until the store acknowledges; TTL is the other-process backstop.
34
+ - **Postgres release pass cannot be inherited.** Missing or stale this-tree evidence is blocked, never a pass from a previous commit's counts.
35
+
36
+ ## [0.7.0] - 2026-09-15 (extended line: plans 072, 073, 074, 075, 077, 078)
37
+
38
+ > **Channels are not in this cut.** Plan 079 (Telegram/Signal adapters) was reassigned to **0.8.0** so the 0.7.0 cut stops waiting on it; nothing in this release mentions or ships a channel adapter.
39
+
40
+ ### Added
41
+ - **Execution timeline (plan 072).** `@arnilo/prism-core/governance/observability` ships one frozen, JSON-serializable view-model for what a run did: `projectAgentTimeline` (live `AgentEvent[]`), `projectTraceTimeline` (persisted `EvaluationTrace`), `projectWorkflowTimeline` (workflow events plus optional checkpoint), incremental `createTimelineFolder` / `createWorkflowTimelineFolder` folders for SSE/cockpit updates, and `summarizeTimeline` / `summarizeSession` rollups (tool counts capped at 64, no double counting across runs). See [docs/execution-timeline.md](docs/execution-timeline.md).
42
+ - **Workflow graph view-model (plan 072).** `serializeWorkflowGraph`, `workflowGraphToMermaid`, `workflowGraphToDot`, `projectWorkflowGraphRun`, and `createWorkflowGraphRunFolder` render a workflow DAG and overlay live or checkpoint run state (`WorkflowGraphRunView`) without executing it.
43
+ - **Trajectory and outcome evals (plan 072).** Scorers (`defineScorer`, pairwise preferences, model-judge budgets), `runScenario`, `runExperiment`, `runWorkflowExperiment`, dataset items with expected trajectories, trials, manifests, comparisons, and thresholds — with `runComparison` / `datasetFromRuns` curation over recorded runs.
44
+ - **Eval primitives match their contracts (plan 073 Tasks 30–31).** Injection/timeline holes closed, deterministic `mulberry32` sampling, `collectWhileRunning`, and host-activity eval packs (coding, browser, memory, voice invariants) over the true primitives.
45
+ - **Attention compiler (plan 074, opt-in).** `createAttentionCompiler` / `resolveInputCap` / `compileAttention` / `createAttentionTruncationTrigger`: a per-turn gate that measures the assembled input against a host ratio of the model input cap and, only past the ratio, mutates a **history clone** oldest thinking blocks first, then fold-eligible tool results — keeping cache prefixes, the session store, and the observational-memory ledger untouched, and raising `AttentionBudgetError` rather than silently dropping context. Wired through `AgentConfig`, `AgentDefinition`, and `RunOptions` (run overlay narrows), plus `attention_compiled` telemetry and an `attention` timeline step; sticky frontier persists through `persistSessionState`. See [docs/attention-compiler.md](docs/attention-compiler.md).
46
+ - **Memory fabric subpath (plan 075, opt-in).** `@arnilo/prism-memory/fabric` adds typed notes (`fact`, `procedure`, `file`, `working`, `episode`) with links, validity windows, time/tool recall, conversation search, and opt-in consolidation/linker/evolution workers over the stores a host already configured. Inert until `fabric.attach(session)`; no new package, provider, database, or mandatory dependency. See [docs/memory-fabric.md](docs/memory-fabric.md).
47
+ - **Work-scope memory index (plan 077, opt-in).** `createWorkScopeController` appends `om.scope.*` entries to one observational-memory ledger; `foldWorkScopeMap`, `projectWorkMemory`, and `withWorkScope` project the outline to a host-selected working set (leaf `self+ancestors` by default), auto-bind new observations to the leaf, and skip the observation dropper while any host scope exists. Caps fail closed (256 scopes, depth 8, 4,096 binds, 512-char labels). See [docs/compaction-observational-memory.md](docs/compaction-observational-memory.md).
48
+ - **Host-owned subagent spawn (plan 078, opt-in).** `createSpawnAgentTool` turns the supervisor's host-owned child catalog into a non-exclusive `spawn_agent` whose closed schema exposes only allow-listed child ids, input, an optional thread id, and `mode: "sync" | "async"`; `createWaitAgentTool` / `createCancelAgentTool` join or abort async handles from `delegateAsync()`. Child identity narrows from the parent, results and errors are redacted, child slots are reserved atomically (after a before-hook narrows limits), and parent-run abort cancels running children. `createWorktreeChildFactory` gives each child its own linked git worktree and cleans it up on every terminal outcome (including a suspended child that later resumes), while `observeSupervisorLifecycle` bridges `delegation_*` events to redacted coding `subagent_started` / `subagent_stopped` lifecycle events. See [docs/supervisors.md](docs/supervisors.md).
49
+ - **Governed host completeness (plan 073).** Governed provider invocation with aggregate task/tenant accounting across every paid work kind (enterprise migration `006_aggregate_budgets`); durable business-action drafts with editable approvals; Docker process sessions and coherent workspace recovery; incremental Drive knowledge synchronization; snapshot/reconnect lifecycle with a hosted E2B sandbox; fair worker admission and operator routes; cross-layer memory lineage with correction and revocation; semantic artifact review with evidence-backed citations; import-fidelity reports with optional OCR; monotonic per-run tool narrowing with remote invalidation; native Bedrock `Converse`/`ConverseStream`; and governed realtime voice orchestration. New pages: [docs/execution-timeline.md](docs/execution-timeline.md), [docs/host-compositions.md](docs/host-compositions.md), [docs/hosted-sandboxes.md](docs/hosted-sandboxes.md), [docs/knowledge-sync.md](docs/knowledge-sync.md), [docs/realtime-voice.md](docs/realtime-voice.md), [docs/attention-compiler.md](docs/attention-compiler.md), [docs/memory-fabric.md](docs/memory-fabric.md).
50
+ - **Examples.** Runnable demos for the new surfaces: `examples/execution-timeline.ts`, `examples/behavior-evaluation.ts`, `examples/coding-browser-evaluation.ts`, `examples/attention-compiler.ts`, `examples/memory-fabric.ts`, `examples/work-scopes-coding-loop.ts`, `examples/spawn-agent-tool.ts`, `examples/governed-provider.ts`, `examples/docker-process-session.ts`, `examples/drive-rag-sync.ts`, `examples/hosted-sandbox.ts`, `examples/scanned-document-rag.ts`, and `examples/realtime-voice-host.ts`.
51
+
52
+ ### Changed
53
+ - **Lockstep `0.6.0` → `0.7.0`.** All ten publishable manifests move together with `^0.7.0` internal ranges; the lockfile, the `src/index.ts` version constant, the docs index banner, the release-workflow tag lists, and the generated package-truth artifact agree (enforced by `scripts/version-literal-gate.test.mjs`).
54
+ - **Compat baselines regenerated** (`--update-baseline`): **469 added declarations, zero removals**. The additions are the new subpath APIs above plus members added to existing declaration groups; no export was renamed or dropped.
55
+ - **Release budgets rebaselined with recorded reasons**: root packed/unpacked/fileCount moved for the new dist modules, templates, and docs pages, and per-package export ceilings carry the 0.7.0 addition list. Startup and timing ceilings are unchanged.
56
+ - **Migration guide for 0.6.0 hosts**: [docs/migrate-to-0.7.md](docs/migrate-to-0.7.md) (per-item actions for the ACP/model-router refusals, every tightening, the opt-in activation steps, and rollback), indexed from [docs/migration.md](docs/migration.md) and [docs/index.md](docs/index.md).
57
+ - **Options index and peer matrix** cover the new surfaces: [docs/options-index.md](docs/options-index.md) routes `AttentionCompilerOptions`/`AttentionInputCapOptions`/`AttentionCompileOptions`/`AttentionTruncationTriggerOptions`, the fabric and work-scope option objects, and the supervisor/spawn/worktree/lifecycle options to their owning pages (gated by `scripts/live-doc-check.test.mjs`).
58
+
59
+ ### Fixed
60
+ - **Task-scoped enterprise budgets failed on their first insert.** Migration `006_aggregate_budgets`' insert bound one JavaScript `Date` to both a `timestamptz` column and interval arithmetic, so PostgreSQL refused the statement with `42P08 inconsistent types deduced for parameter $8`; the parameter is now explicitly `::timestamptz` (found by the protected PostgreSQL leg, not by hermetic doubles).
61
+ - **A serialization failure inside the budget upsert was swallowed.** The read-then-insert path caught *every* error from the `SELECT … FOR UPDATE` probe and then issued SQL against an aborted transaction (`25P02`), which defeated the retry loop; only a genuinely missing row is recoverable by inserting now.
62
+ - **Serializable retry policy was too small for concurrent writers.** Budget/rate rewrites on one row now retry up to 12 times with full-jitter exponential backoff (capped at 250 ms), so a 16-client burst converges instead of exhausting three near-instant attempts with `ERR_PRISM_ENTERPRISE_POSTGRES_RETRYABLE`.
63
+ - **Integration tests were stale against migration 006** (expected five migrations) and `scripts/phase27-release.test.mjs` still asserted that no `006_` migration existed; both now check the append-only list including `006_aggregate_budgets`.
64
+
65
+ ### Security
66
+ - **ACP MCP destination matching (Trap A).** `mcp.allow` entries now match by WHATWG origin plus path-segment subtree: origin lookalikes (`mcp.example.com.attacker.invalid`) and sibling path prefixes (`/mcp-other`) no longer match, and allow entries carrying userinfo, query, fragment, or ambiguous encoded path forms fail `ConfigError` at parse time.
67
+ - **Model-router facade fails closed (Trap B).** `router.providerSource(model)` throws `ERR_PRISM_MODEL_ROUTER_ASYNC_REQUIRED` / `ERR_PRISM_MODEL_ROUTER_ASYNC_STATE` instead of handing back a provider that bypasses budgets, rate limits, circuits, fallbacks, selection policies, or durable state; `isProviderSourceEligible` lets a host check first.
68
+ - **ACP launcher requires a real provider (Trap C/R05).** No silent `createMockProvider()` fallback; mock mode is an explicit opt-in.
69
+ - **Per-run tool narrowing is monotonic (R11)** and remote invalidation is honored; child agents cannot widen the tenant, account, user, or scopes of the parent identity (`narrowIdentity` + `assertIdentityPropagation`).
70
+
71
+ ### Notes
72
+ - **Protected PostgreSQL leg now green on 0.7.0 code**: `PRISM_TEST_POSTGRES_URL=… npm run test:postgres` passes core (72), memory (457), and the phase conformance legs (11) against `pgvector/pgvector:pg16`, the same image the release workflow uses. The three fixes above are what that leg caught.
73
+ - **Node floor is unchanged** at `>=22` (Node 22/24 supported).
74
+
1
75
  ## [0.6.0] - 2026-09-12 (plans 070, 071)
2
76
 
3
77
  > **0.5.7 was never published.** This release folds that cut's content (durable concurrent tool rounds, strict-provider tool results, host-tunable knobs, peer/options truth, the dependency refresh, and the module splits) together with the 0.6.0 changes below, so a host on 0.5.6 upgrades once. See [docs/migrate-to-0.6.md](docs/migrate-to-0.6.md).
@@ -129,27 +203,27 @@
129
203
  ### Added
130
204
  - **OKF adoption (`@arnilo/prism-wiki`)**: wiki-init/refresh/lint emit and validate
131
205
  OKF v0.2 bundles (Karpathy prompt retained). See `docs/wiki.md`.
132
- - **DOCS-1 (Clay integration findings)**: three integrator contracts, in place on
206
+ - **DOCS-1 (integration findings)**: three integrator contracts, in place on
133
207
  the pages that own them — resume-aware workflow nodes (`ctx.resume` or silent
134
208
  re-suspend) in `docs/workflows.md`; supervisor child factories return `Agent`
135
209
  not `AgentSession` (`SupervisorError: child "<id>" factory must return an
136
210
  Agent, got <type>`) plus durable-store nested approvals in `docs/supervisors.md`;
137
211
  task-boundary `session.compact()` fails closed during an active run in
138
212
  `docs/compaction-and-retry.md`. Each block links `examples/autonomous-coding-loop.ts`.
139
- - **FEATURE-2 (Clay integration findings)**: documented bounded iterate-until-done
213
+ - **FEATURE-2 (integration findings)**: documented bounded iterate-until-done
140
214
  host-loop pattern in `docs/workflows.md` — one `runWorkflow` per iteration,
141
215
  iteration state in workflow inputs, explicit termination predicate and budgets,
142
216
  typed `BudgetExhaustedError` (fail-closed, never a hang), `replayWorkflow` per
143
217
  iteration run id. Seeded by `examples/autonomous-coding-loop.ts`. Plan 045 `loop`
144
218
  node remains the future in-graph primitive; this intake ships the docs+example
145
219
  minimum only.
146
- - **FEATURE-6 (Clay integration findings)**: composite `examples/autonomous-coding-loop.ts`
220
+ - **FEATURE-6 (integration findings)**: composite `examples/autonomous-coding-loop.ts`
147
221
  conformance reference — goal → roadmap → per-task supervisor children (per-child
148
222
  models) → `runCodingGoalVerify`-style validation → observational-memory attach +
149
223
  task-boundary compact + recall → human gate with simulated restart → host-side
150
224
  bounded iterate-until-done with deterministic budget exhaustion. Mock providers
151
225
  only; no credentials or network.
152
- - **FEATURE-3 (Clay integration findings)**: host-opt-in command driver hooks.
226
+ - **FEATURE-3 (integration findings)**: host-opt-in command driver hooks.
153
227
  `CommandExecutionContext` gains an optional `drivers?: CommandDrivers`
154
228
  (`startRun` / `startWorkflow` / `steer` — typed minimal handles returning
155
229
  `AgentRunResult`-shaped results / workflow run id + status) so a contributed
@@ -159,7 +233,7 @@
159
233
  the context shape unchanged (no key, no allocation). Drivers are
160
234
  host-injected capabilities, never package-supplied.
161
235
  ### Fixed
162
- - **FEATURE-1 (Clay integration findings)**: `resolveAgentDefinition` no longer
236
+ - **FEATURE-1 (integration findings)**: `resolveAgentDefinition` no longer
163
237
  throws `Agent "<name>" has no model` when the declarative definition omits
164
238
  `model` but `context.overrides.model` supplies one — the fallback is a
165
239
  single `??` at `buildBaseConfig`, the `create()` path is unchanged, and a
package/README.md CHANGED
@@ -158,20 +158,21 @@ printf '{"id":"1","command":"prompt","params":{"input":"Hi"}}\n' \
158
158
  ## Packages
159
159
 
160
160
  <!-- generated:package-truth:inventory begin -->
161
- **10 publishable manifests** — root `@arnilo/prism` plus 9 workspace packages (3 `prism-*` family packages, 6 capability packages). Generated by `node scripts/package-truth.mjs --emit-docs` — do not hand-edit.
161
+ **11 publishable manifests** — root `@arnilo/prism` plus 10 workspace packages (4 `prism-*` family packages, 6 capability packages). Generated by `node scripts/package-truth.mjs --emit-docs` — do not hand-edit.
162
162
 
163
163
  | package | version | notes |
164
164
  | --- | --- | --- |
165
- | `@arnilo/prism` | 0.6.0 | core — runtime, CLI/RPC, templates, docs |
166
- | `@arnilo/prism-coding-tools` | 0.6.0 | family — /agent, /security, /document-reader, /openapi, /computer-use-linux, /dev, /caveman, /ponytail, /impeccable subpaths |
167
- | `@arnilo/prism-core` | 0.6.0 | family — /runtime, /sessions, /governance, /credentials, /enterprise, /work, /validation subpaths |
168
- | `@arnilo/prism-providers` | 0.6.0 | family — all provider adapters as `/<adapter>` subpaths |
169
- | `@arnilo/prism-acp-agent` | 0.6.0 | capability — ACP adapter |
170
- | `@arnilo/prism-ag-ui` | 0.6.0 | capability — AG-UI/A2A/A2UI adapter |
171
- | `@arnilo/prism-mcp` | 0.6.0 | capability — MCP client/server/OAuth interop |
172
- | `@arnilo/prism-memory` | 0.6.0 | capability — memory plus /rag, /compaction/*, /graft, /wiki subpaths |
173
- | `@arnilo/prism-office` | 0.6.0 | capability — /documents, /sheets, /diagrams subpaths |
174
- | `@arnilo/prism-web-tools` | 0.6.0 | capability — Brave/Exa/Firecrawl plus peer-gated /browser and /obscura subpaths |
165
+ | `@arnilo/prism` | 0.8.0 | core — runtime, CLI/RPC, templates, docs |
166
+ | `@arnilo/prism-channels` | 0.8.0 | family — transport-neutral messaging runtime, durable journal, pairing and one-use approvals; official /telegram (private DMs, opt-in granted groups/topics) and experimental pinned signal-cli /signal |
167
+ | `@arnilo/prism-coding-tools` | 0.8.0 | family — /agent, /security, /openapi, /computer-use-linux, /dev, /caveman, /ponytail, /impeccable subpaths |
168
+ | `@arnilo/prism-core` | 0.8.0 | family — /runtime, /sessions, /governance, /credentials, /enterprise, /validation subpaths |
169
+ | `@arnilo/prism-providers` | 0.8.0 | family — all provider adapters as `/<adapter>` subpaths |
170
+ | `@arnilo/prism-acp-agent` | 0.8.0 | capability — ACP adapter |
171
+ | `@arnilo/prism-ag-ui` | 0.8.0 | capability — AG-UI/A2A/A2UI adapter |
172
+ | `@arnilo/prism-mcp` | 0.8.0 | capability — MCP client/server/OAuth interop |
173
+ | `@arnilo/prism-memory` | 0.8.0 | capability — memory plus /rag, /compaction/*, /fabric, /graft, /wiki subpaths |
174
+ | `@arnilo/prism-web-tools` | 0.8.0 | capability — Brave/Exa/Firecrawl plus peer-gated /browser and /obscura subpaths |
175
+ | `@arnilo/prism-work` | 0.8.0 | capability — /connectors, /documents, /sheets, /diagrams, /document-reader, /sandbox, /skills, /tools subpaths |
175
176
  <!-- generated:package-truth:inventory end -->
176
177
 
177
178
  ## Scripts
@@ -10,6 +10,10 @@ export declare function pendingDecisionsOf(state: StoredAgentRunState): readonly
10
10
  * crash with raw TypeErrors. State-dependent checks (foreign/stale/duplicate ids, scope,
11
11
  * schema, policy) stay in {@link resolveRunDecisions}. Errors never include tool arguments,
12
12
  * elicitation payloads, credentials, or foreign approval details.
13
+ *
14
+ * The legacy `decision` accepts `continue` (plan 084 Task 1) in addition to `approve`/`deny`;
15
+ * it is a crash-recovery action for running-state checkpoints and is resolved in
16
+ * `prepareAgentRunResume`, never as an approval outcome.
13
17
  */
14
18
  export declare function assertValidAgentRunResume(resume: AgentRunResume): void;
15
19
  interface ResolvedRunDecisions {
@@ -28,6 +28,10 @@ export function pendingDecisionsOf(state) {
28
28
  * crash with raw TypeErrors. State-dependent checks (foreign/stale/duplicate ids, scope,
29
29
  * schema, policy) stay in {@link resolveRunDecisions}. Errors never include tool arguments,
30
30
  * elicitation payloads, credentials, or foreign approval details.
31
+ *
32
+ * The legacy `decision` accepts `continue` (plan 084 Task 1) in addition to `approve`/`deny`;
33
+ * it is a crash-recovery action for running-state checkpoints and is resolved in
34
+ * `prepareAgentRunResume`, never as an approval outcome.
31
35
  */
32
36
  export function assertValidAgentRunResume(resume) {
33
37
  const invalid = (message) => new AgentDecisionError("ERR_PRISM_DECISION_INVALID", message);
@@ -45,7 +49,7 @@ export function assertValidAgentRunResume(resume) {
45
49
  if (!hasDecision && !hasDecisions)
46
50
  throw invalid("Resume requires a decision or decisions");
47
51
  if (hasDecision) {
48
- if (resume.decision !== "approve" && resume.decision !== "deny") {
52
+ if (resume.decision !== "approve" && resume.decision !== "deny" && resume.decision !== "continue") {
49
53
  throw invalid("Unknown legacy decision");
50
54
  }
51
55
  return;
@@ -34,6 +34,7 @@ function buildBaseConfig(def, context) {
34
34
  ...(def.context !== undefined && { context: resolveContextProviders(def.name, def.context, context) }),
35
35
  ...(def.systemPrompt !== undefined && { systemPrompt: def.systemPrompt }),
36
36
  ...(def.instructions !== undefined && { instructions: def.instructions }),
37
+ ...(def.attentionCompiler !== undefined && { attentionCompiler: def.attentionCompiler }),
37
38
  ...(def.loop !== undefined && { loop: def.loop }),
38
39
  ...(def.metadata !== undefined && { metadata: def.metadata }),
39
40
  };
@@ -1,6 +1,7 @@
1
1
  import { assertValidAgentRunResume, pendingDecisionsOf, resolveRunDecisions } from "./agent-approval.js";
2
2
  import { agentFingerprint, loadAgentRunState, publicState, saveAgentRunState } from "./agent-run-state.js";
3
3
  import { RuntimeAgentSession, throwIfAbortedSignal } from "./agent-session.js";
4
+ import { parseAttentionStickyFrontier } from "./attention-compiler.js";
4
5
  import { AgentRunStateError } from "./contracts.js";
5
6
  function assertAgentId(actual, expected) {
6
7
  if (expected !== undefined && actual !== expected)
@@ -27,6 +28,7 @@ export function createAgentRunLifecycle(options) {
27
28
  ownership: request.ownership,
28
29
  fencingToken: options.fencingToken,
29
30
  definitionRevision: resolved.definitionRevision,
31
+ signal: request.signal,
30
32
  persistSessionState: request.persistSessionState,
31
33
  includeSkillBodies: request.includeSkillBodies,
32
34
  });
@@ -54,7 +56,8 @@ export function createAgentRunLifecycle(options) {
54
56
  // Resume free functions moved from agents.ts at 0.1.4 (verbatim; the barrel re-exports the two public ones).
55
57
  /** Resume a persisted built-in run. A claimed/dispatched tool is never replayed automatically. */
56
58
  export async function resumeAgentRun(agent, ref, resume, options) {
57
- return executePreparedAgentRunResume(await prepareAgentRunResume(agent, ref, resume, options));
59
+ throwIfAbortedSignal(options.signal);
60
+ return executePreparedAgentRunResume(await prepareAgentRunResume(agent, ref, resume, options, options.signal), options.signal);
58
61
  }
59
62
  /** Subscribe before resuming one durable run. Early consumer return aborts that resumed execution. */
60
63
  export async function* resumeAgentRunStream(agent, ref, resume, options) {
@@ -80,22 +83,44 @@ export async function* resumeAgentRunStream(agent, ref, resume, options) {
80
83
  }
81
84
  }
82
85
  }
86
+ /**
87
+ * A `continue` resume needs a run whose frontier is intact: a crash-recovery checkpoint
88
+ * (`status: "running"`) or a turn-policy stop, which writes a terminal state that still carries
89
+ * the frontier (plan 084 Task 2). Every other terminal state is final — a naturally finished run
90
+ * must never be resurrected.
91
+ */
92
+ function isContinuableState(state) {
93
+ return state.status === "running" || (state.status === "succeeded" && state.stopReason === "host_policy");
94
+ }
83
95
  async function prepareAgentRunResume(agent, ref, resume, options, signal) {
84
96
  throwIfAbortedSignal(signal);
85
97
  // Plan 020 Task 2: one shared shape assertion before any checkpoint read/write, agent
86
98
  // resolution, subscription, or tool execution. Unknown legacy decisions (e.g. "sideways")
87
99
  // and malformed untyped batches fail closed here instead of falling through to approval.
88
100
  assertValidAgentRunResume(resume);
101
+ const continuing = resume.decision === "continue";
89
102
  const { record, state } = await loadAgentRunState(options.checkpoints, ref, options.ownership);
90
103
  if (state.definitionRevision !== options.definitionRevision ||
91
104
  state.agentId !== (agent.config.id ?? agent.config.name) ||
92
105
  state.fingerprint !== agentFingerprint(agent, options.definitionRevision)) {
93
106
  throw new AgentRunStateError("Agent definition revision or fingerprint mismatch on resume");
94
107
  }
95
- if (record.version !== resume.expectedVersion || state.status !== "suspended") {
96
- throw new AgentRunStateError("Stale or non-suspended agent run resume");
108
+ if (record.version !== resume.expectedVersion || !(continuing ? isContinuableState(state) : state.status === "suspended")) {
109
+ throw new AgentRunStateError(continuing ? "Stale or non-running agent run resume" : "Stale or non-suspended agent run resume");
110
+ }
111
+ // Crash recovery never bypasses a gate: only a running checkpoint with no unresolved work may
112
+ // continue. A suspended state (tool approval, elicitation, input guardrail) requires a decision.
113
+ if (continuing) {
114
+ const pending = pendingDecisionsOf(state);
115
+ const awaitingDispatch = state.pending?.status === "ready" || state.pendingCalls?.some((entry) => entry.status === "ready") === true;
116
+ if (state.interruption !== undefined || (pending?.length ?? 0) > 0 || awaitingDispatch) {
117
+ throw new AgentRunStateError("Continue resume requires a running checkpoint with no pending decisions");
118
+ }
97
119
  }
98
120
  const session = new RuntimeAgentSession({ agent, id: state.sessionId, leafId: state.leafId });
121
+ // Plan 078 Task 7: hand the reconstructed session to an observer (supervisor child-event pump)
122
+ // before any event flows. Called for every resume outcome; a throw fails closed.
123
+ options.onSession?.(session);
99
124
  // Opt-in session-state restore (plan 015 Task 4): names only; bodies re-resolve from
100
125
  // the live registry the next time the model (re)loads them via load_skill.
101
126
  if (options.persistSessionState && state.sessionState?.loadedSkillNames) {
@@ -105,6 +130,13 @@ async function prepareAgentRunResume(agent, ref, resume, options, signal) {
105
130
  if (options.persistSessionState && state.sessionState?.activatedToolNames) {
106
131
  session.restoreActivatedTools(state.sessionState.activatedToolNames);
107
132
  }
133
+ // Plan 074 P3: restore sticky attention mutations (already validated at load) so the first
134
+ // turn after a resume keeps its stubs instead of re-deciding them from the ratio.
135
+ if (options.persistSessionState && state.sessionState?.attentionSticky) {
136
+ const frontier = parseAttentionStickyFrontier(state.sessionState.attentionSticky);
137
+ if (frontier)
138
+ session.restoreAttentionSticky(frontier);
139
+ }
108
140
  // Plan 018 Task 6 (closeout `checkpoint-bodies`): restore exact instructions so the
109
141
  // resumed session renders them registry-independently (no load_skill round-trip).
110
142
  if (options.persistSessionState && options.includeSkillBodies && state.sessionState?.loadedSkillBodies) {
@@ -239,7 +271,7 @@ async function prepareAgentRunResume(agent, ref, resume, options, signal) {
239
271
  fencingToken: options.fencingToken,
240
272
  });
241
273
  return {
242
- kind: "approve",
274
+ kind: "claim",
243
275
  session,
244
276
  state: claimed.state,
245
277
  decisions: resolved?.decisionsById,
@@ -250,6 +282,9 @@ async function prepareAgentRunResume(agent, ref, resume, options, signal) {
250
282
  interruptBeforeTool: state.interruptBeforeTool,
251
283
  fencingToken: options.fencingToken,
252
284
  resumeNestedRun: options.resumeNestedRun,
285
+ // The checkpoint records its own cadence (plan 084 Task 1), so a continued run keeps writing
286
+ // turn checkpoints without the host repeating the option on resume.
287
+ ...(state.checkpointPolicy ? { checkpointPolicy: state.checkpointPolicy } : {}),
253
288
  },
254
289
  };
255
290
  }
@@ -1,3 +1,4 @@
1
+ import { type PersistedAttentionStickyFrontier } from "./attention-compiler.js";
1
2
  import type { Agent, AgentRunInterruption, AgentRunRef, AgentRunState, AgentRunStateOptions, CheckpointRecord, CheckpointStore, JsonValue, Message, ModelConfig, NestedRunRef, OwnershipScope, RunDecision, RunLimitCounters, StickyDecision, ToolCallContent } from "./contracts.js";
2
3
  import type { SecretRedactor } from "./redaction.js";
3
4
  import { type LoadedSkillBodiesEntry } from "./skill-load.js";
@@ -46,7 +47,24 @@ export interface StoredAgentRunState extends AgentRunState {
46
47
  readonly loadedSkillBodies?: readonly LoadedSkillBodiesEntry[];
47
48
  /** Plan 041: tools activated via `search_tools` (names only; inert for absent tools on restore). */
48
49
  readonly activatedToolNames?: readonly string[];
50
+ /** Plan 074 P3: sticky attention mutations (thinking hashes + tool-call ids), so a durable
51
+ * resume keeps its stubs instead of re-deciding on the first turn. Validated on load. */
52
+ readonly attentionSticky?: PersistedAttentionStickyFrontier;
49
53
  };
54
+ /** Per-run allow-list (Task 21). Absent = full registered set (legacy checkpoints). */
55
+ readonly toolNames?: readonly string[];
56
+ /**
57
+ * Recorded checkpoint cadence (plan 084 Task 1). Present only for `"every-turn"` runs, so
58
+ * default checkpoints stay byte-identical. A resume of such a state keeps checkpointing each
59
+ * turn without the host repeating the option.
60
+ */
61
+ readonly checkpointPolicy?: "every-turn";
62
+ /**
63
+ * Set when a terminal state was written by a `RunOptions.turnPolicy` stop (plan 084 Task 2):
64
+ * the run succeeded cleanly but its frontier is intact, so `decision: "continue"` may resume
65
+ * it. Absent on every other state — a naturally finished run is never continuable.
66
+ */
67
+ readonly stopReason?: "host_policy";
50
68
  }
51
69
  /** Session-state caps (plan 015 Task 4): bounded names charged against the run-state byte budget. */
52
70
  export declare const MAX_PERSISTED_SKILL_NAMES = 64;
@@ -1,6 +1,8 @@
1
1
  import { createHash } from "node:crypto";
2
+ import { parseAttentionStickyFrontier } from "./attention-compiler.js";
2
3
  import { AgentLoopStateError, AgentRunStateError } from "./contracts.js";
3
4
  import { validateLoadedSkillBodies } from "./skill-load.js";
5
+ import { HARD_RUN_TOOL_NAMES } from "./tools.js";
4
6
  export const AGENT_RUN_STATE_NAMESPACE = "prism.agent-run";
5
7
  export const AGENT_RUN_STATE_SCHEMA_VERSION = 1;
6
8
  export const DEFAULT_MAX_AGENT_RUN_STATE_BYTES = 256 * 1024;
@@ -100,6 +102,9 @@ export function validateRunStateOptions(options) {
100
102
  if (!Number.isSafeInteger(bytes) || bytes < 1 || bytes > HARD_MAX_AGENT_RUN_STATE_BYTES) {
101
103
  throw new AgentRunStateError(`maxStateBytes must be a positive safe integer at most ${HARD_MAX_AGENT_RUN_STATE_BYTES}`);
102
104
  }
105
+ if (options.checkpointPolicy !== undefined && options.checkpointPolicy !== "decision" && options.checkpointPolicy !== "every-turn") {
106
+ throw new AgentRunStateError('checkpointPolicy must be "decision" or "every-turn"');
107
+ }
103
108
  }
104
109
  export async function loadAgentRunState(checkpoints, ref, ownership) {
105
110
  const record = await checkpoints.loadCheckpoint({ namespace: AGENT_RUN_STATE_NAMESPACE, key: ref.runId, ...ownership });
@@ -128,7 +133,7 @@ export async function saveAgentRunState(input) {
128
133
  return { record, state: { ...bounded, version: record.version } };
129
134
  }
130
135
  export function publicState(state) {
131
- const { input: _input, pending: _pending, pendingCalls: _pendingCalls, nestedRuns: _nestedRuns, interruptBeforeTool: _interruptBeforeTool, counters: _counters, deadlineAt: _deadlineAt, ...publicValue } = state;
136
+ const { input: _input, pending: _pending, pendingCalls: _pendingCalls, nestedRuns: _nestedRuns, interruptBeforeTool: _interruptBeforeTool, counters: _counters, deadlineAt: _deadlineAt, toolNames: _toolNames, checkpointPolicy: _checkpointPolicy, stopReason: _stopReason, ...publicValue } = state;
132
137
  return publicValue;
133
138
  }
134
139
  export function initialAgentRunState(input) {
@@ -150,6 +155,7 @@ export function initialAgentRunState(input) {
150
155
  interruptBeforeTool: input.interruptBeforeTool,
151
156
  counters: input.counters,
152
157
  deadlineAt: input.deadlineAt,
158
+ ...(input.options.checkpointPolicy === "every-turn" ? { checkpointPolicy: "every-turn" } : {}),
153
159
  };
154
160
  }
155
161
  export function parseAgentRunState(value, version) {
@@ -203,6 +209,22 @@ export function parseAgentRunState(value, version) {
203
209
  !("snapshot" in state.loopState))) {
204
210
  throw new AgentRunStateError("Malformed agent run loop state");
205
211
  }
212
+ if (state.toolNames !== undefined) {
213
+ if (!Array.isArray(state.toolNames) || state.toolNames.length > HARD_RUN_TOOL_NAMES) {
214
+ throw new AgentRunStateError(`Run toolNames exceed ${HARD_RUN_TOOL_NAMES} entries`);
215
+ }
216
+ for (const name of state.toolNames) {
217
+ if (typeof name !== "string" || name.length === 0 || name.length > MAX_PERSISTED_SKILL_NAME_CHARS) {
218
+ throw new AgentRunStateError("Malformed agent run toolNames");
219
+ }
220
+ }
221
+ }
222
+ if (state.checkpointPolicy !== undefined && state.checkpointPolicy !== "every-turn") {
223
+ throw new AgentRunStateError("Malformed agent run checkpoint policy");
224
+ }
225
+ if (state.stopReason !== undefined && state.stopReason !== "host_policy") {
226
+ throw new AgentRunStateError("Malformed agent run stop reason");
227
+ }
206
228
  // Load bounds against the hard cap, not the default: the configured maxStateBytes is a
207
229
  // save-side policy knob, while the load-side bound is only a DoS ceiling. States saved
208
230
  // with a raised maxStateBytes must remain resumable.
@@ -261,15 +283,23 @@ function validateSessionState(sessionState) {
261
283
  }
262
284
  }
263
285
  const activated = sessionState.activatedToolNames;
264
- if (activated === undefined)
265
- return;
266
- if (!Array.isArray(activated) || activated.length > MAX_PERSISTED_ACTIVATED_TOOL_NAMES) {
267
- throw new AgentRunStateError(`Activated-tool names exceed ${MAX_PERSISTED_ACTIVATED_TOOL_NAMES} entries`);
268
- }
269
- for (const name of activated) {
270
- if (typeof name !== "string" || name.length > MAX_PERSISTED_SKILL_NAME_CHARS) {
271
- throw new AgentRunStateError(`Activated-tool name exceeds ${MAX_PERSISTED_SKILL_NAME_CHARS} chars`);
286
+ if (activated !== undefined) {
287
+ if (!Array.isArray(activated) || activated.length > MAX_PERSISTED_ACTIVATED_TOOL_NAMES) {
288
+ throw new AgentRunStateError(`Activated-tool names exceed ${MAX_PERSISTED_ACTIVATED_TOOL_NAMES} entries`);
272
289
  }
290
+ for (const name of activated) {
291
+ if (typeof name !== "string" || name.length > MAX_PERSISTED_SKILL_NAME_CHARS) {
292
+ throw new AgentRunStateError(`Activated-tool name exceeds ${MAX_PERSISTED_SKILL_NAME_CHARS} chars`);
293
+ }
294
+ }
295
+ }
296
+ const attention = sessionState.attentionSticky;
297
+ if (attention === undefined)
298
+ return;
299
+ // Both arrays are capped by the parser, and a malformed frontier is dropped rather than
300
+ // failing the resume: re-deciding a mutation is safe, refusing to resume is not.
301
+ if (parseAttentionStickyFrontier(attention) === undefined) {
302
+ throw new AgentRunStateError("Malformed agent run attention frontier");
273
303
  }
274
304
  }
275
305
  //# sourceMappingURL=agent-run-state.js.map
@@ -53,7 +53,12 @@ export function finalAssistantMessage(history) {
53
53
  return { content: [], text: "" };
54
54
  }
55
55
  export function errorFromInfo(error) {
56
- return Object.assign(new Error(error.message), { name: error.name ?? "Error", cause: error.cause, code: error.code });
56
+ return Object.assign(new Error(error.message), {
57
+ name: error.name ?? "Error",
58
+ cause: error.cause,
59
+ code: error.code,
60
+ failureClass: error.failureClass,
61
+ });
57
62
  }
58
63
  export class ProviderTurnFailure extends Error {
59
64
  info;