@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.
- package/CHANGELOG.md +79 -5
- package/README.md +12 -11
- package/dist/agent-approval.d.ts +4 -0
- package/dist/agent-approval.js +5 -1
- package/dist/agent-definitions.js +1 -0
- package/dist/agent-run-lifecycle.js +39 -4
- package/dist/agent-run-state.d.ts +18 -0
- package/dist/agent-run-state.js +39 -9
- package/dist/agent-session/helpers.js +6 -1
- package/dist/agent-session/session/assemble.js +159 -7
- package/dist/agent-session/session/persist.d.ts +16 -0
- package/dist/agent-session/session/persist.js +64 -4
- package/dist/agent-session/session/provider-round.d.ts +3 -3
- package/dist/agent-session/session/provider-round.js +12 -6
- package/dist/agent-session/session/tool-round.js +5 -1
- package/dist/agent-session/session/types.d.ts +22 -1
- package/dist/agent-session/session.d.ts +16 -0
- package/dist/agent-session/session.js +42 -3
- package/dist/artifacts.d.ts +39 -1
- package/dist/artifacts.js +73 -0
- package/dist/attention-compiler.d.ts +121 -0
- package/dist/attention-compiler.js +479 -0
- package/dist/checkpoints.js +7 -11
- package/dist/cli-init.js +20 -6
- package/dist/context-budget.d.ts +20 -1
- package/dist/context-budget.js +10 -1
- package/dist/contracts-core/agent.d.ts +7 -0
- package/dist/contracts-core/attention.d.ts +66 -0
- package/dist/contracts-core/attention.js +2 -0
- package/dist/contracts-core/compaction.d.ts +59 -0
- package/dist/contracts-core/compaction.js +77 -1
- package/dist/contracts-core/content.d.ts +5 -0
- package/dist/contracts-core/loop.d.ts +42 -0
- package/dist/contracts-core/provider.d.ts +4 -0
- package/dist/contracts-core/run-limits.d.ts +2 -0
- package/dist/contracts-core.d.ts +1 -0
- package/dist/contracts-core.js +1 -0
- package/dist/contracts-protocol.d.ts +44 -3
- package/dist/contracts-run-state.d.ts +32 -5
- package/dist/evidence-grounding.d.ts +29 -0
- package/dist/evidence-grounding.js +162 -0
- package/dist/host-composition.d.ts +91 -0
- package/dist/host-composition.js +279 -0
- package/dist/index.d.ts +13 -6
- package/dist/index.js +7 -4
- package/dist/input.d.ts +13 -1
- package/dist/input.js +40 -1
- package/dist/provider-events.d.ts +3 -1
- package/dist/provider-events.js +2 -2
- package/dist/providers/transport.d.ts +3 -1
- package/dist/providers/transport.js +36 -0
- package/dist/redaction.js +18 -2
- package/dist/run-bundle.d.ts +89 -0
- package/dist/run-bundle.js +149 -0
- package/dist/secure-agent.d.ts +2 -0
- package/dist/secure-agent.js +6 -1
- package/dist/testing/state-concurrency-conformance.js +5 -12
- package/dist/tool-result-fold.d.ts +12 -0
- package/dist/tool-result-fold.js +13 -6
- package/dist/tools.d.ts +10 -0
- package/dist/tools.js +41 -0
- package/docs/acp-agent.md +42 -11
- package/docs/acp.md +2 -1
- package/docs/ag-ui.md +10 -3
- package/docs/agent-definitions.md +9 -1
- package/docs/agent-events.md +4 -1
- package/docs/agent-loops.md +33 -0
- package/docs/agent-session-runtime.md +8 -7
- package/docs/attention-compiler.md +272 -0
- package/docs/cli-rpc.md +4 -2
- package/docs/coding-agent-tools.md +1 -1
- package/docs/coding-security.md +6 -3
- package/docs/coding-tools.md +0 -1
- package/docs/coding-workspaces.md +22 -0
- package/docs/compaction-and-retry.md +36 -4
- package/docs/compaction-observational-memory.md +63 -10
- package/docs/connected-apps.md +116 -0
- package/docs/context-and-skills.md +17 -2
- package/docs/conversations.md +1 -1
- package/docs/core.md +1 -1
- package/docs/dev-inspector.md +4 -0
- package/docs/device-adapters.md +1 -0
- package/docs/diagrams.md +6 -6
- package/docs/document-reader.md +18 -10
- package/docs/documents.md +40 -11
- package/docs/durable-runs.md +87 -0
- package/docs/enterprise-postgres-state.md +6 -2
- package/docs/evaluations.md +168 -4
- package/docs/execution-timeline.md +186 -0
- package/docs/guardrails.md +33 -0
- package/docs/history/0.7.0-primitive-review.md +254 -0
- package/docs/history/079-messaging-primitive-review.md +391 -0
- package/docs/history/080-messaging-followon-primitive-review.md +234 -0
- package/docs/history/081-connected-apps-primitive-review.md +74 -0
- package/docs/history/083-prism-work-primitive-review.md +84 -0
- package/docs/history/084-primitive-review.md +96 -0
- package/docs/history/085-honesty-and-cut-primitive-review.md +91 -0
- package/docs/history/README.md +5 -0
- package/docs/history/migration-0.0.md +2 -2
- package/docs/history/release-handoffs.md +75 -1
- package/docs/host-compositions.md +149 -0
- package/docs/host-security.md +2 -2
- package/docs/hosted-sandboxes.md +94 -0
- package/docs/index.md +82 -45
- package/docs/input-and-prompt-assembly.md +1 -0
- package/docs/knowledge-sync.md +84 -0
- package/docs/language-intelligence.md +1 -1
- package/docs/live-testing.md +8 -3
- package/docs/mcp-tools.md +3 -1
- package/docs/memory-fabric.md +416 -0
- package/docs/messaging-channel-operations.md +166 -0
- package/docs/messaging-channels.md +150 -0
- package/docs/migrate-to-0.5.md +1 -1
- package/docs/migrate-to-0.6.md +1 -0
- package/docs/migrate-to-0.7.md +345 -0
- package/docs/migrate-to-0.8.md +124 -0
- package/docs/migration.md +43 -1
- package/docs/model-registry.md +12 -2
- package/docs/model-routing.md +79 -4
- package/docs/multi-agent-patterns.md +20 -6
- package/docs/observability.md +52 -1
- package/docs/openapi-tools.md +1 -1
- package/docs/operations.md +14 -4
- package/docs/options-index.md +47 -3
- package/docs/peer-dependencies.md +12 -10
- package/docs/postgres-persistence.md +1 -1
- package/docs/process-sessions.md +3 -1
- package/docs/prompt-registry.md +1 -1
- package/docs/provider-caching.md +4 -2
- package/docs/provider-conformance.md +1 -1
- package/docs/provider-layer.md +2 -2
- package/docs/provider-packages.md +22 -22
- package/docs/providers/bedrock.md +71 -7
- package/docs/providers/neuralwatt.md +5 -1
- package/docs/providers/openai.md +1 -1
- package/docs/rag.md +24 -8
- package/docs/realtime-voice.md +87 -0
- package/docs/release-and-install.md +53 -45
- package/docs/run-bundle.md +92 -0
- package/docs/runs-and-usage.md +17 -2
- package/docs/server.md +7 -3
- package/docs/sheets.md +9 -9
- package/docs/signal-channel.md +112 -0
- package/docs/speech.md +7 -1
- package/docs/sqlite-persistence.md +1 -1
- package/docs/supervisors.md +33 -5
- package/docs/telegram-channel.md +157 -0
- package/docs/testing.md +2 -2
- package/docs/thinking-and-reasoning.md +3 -1
- package/docs/tools.md +6 -5
- package/docs/web-tools.md +2 -1
- package/docs/wiki.md +1 -1
- package/docs/work-artifacts-and-review.md +14 -4
- package/docs/work-connectors.md +12 -10
- package/docs/work-sandbox.md +115 -0
- package/docs/work-tools.md +50 -18
- package/docs/workflows.md +69 -1
- package/docs/working-and-semantic-memory.md +25 -14
- package/package.json +5 -3
- package/templates/README.md +2 -0
- package/templates/business-worker/README.md.tmpl +19 -0
- package/templates/business-worker/env.example.tmpl +1 -0
- package/templates/business-worker/gitignore.tmpl +11 -0
- package/templates/business-worker/manifest.json +12 -0
- package/templates/business-worker/package.json.tmpl +23 -0
- package/templates/business-worker/src/agent.ts.tmpl +92 -0
- package/templates/business-worker/src/index.ts.tmpl +13 -0
- package/templates/business-worker/src/tests/agent.test.ts.tmpl +77 -0
- package/templates/business-worker/tsconfig.json.tmpl +15 -0
- package/templates/personal-assistant/README.md.tmpl +18 -0
- package/templates/personal-assistant/env.example.tmpl +1 -0
- package/templates/personal-assistant/gitignore.tmpl +11 -0
- package/templates/personal-assistant/manifest.json +11 -0
- package/templates/personal-assistant/package.json.tmpl +23 -0
- package/templates/personal-assistant/src/agent.ts.tmpl +65 -0
- package/templates/personal-assistant/src/index.ts.tmpl +13 -0
- package/templates/personal-assistant/src/tests/agent.test.ts.tmpl +28 -0
- 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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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
|
-
**
|
|
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.
|
|
166
|
-
| `@arnilo/prism-
|
|
167
|
-
| `@arnilo/prism-
|
|
168
|
-
| `@arnilo/prism-
|
|
169
|
-
| `@arnilo/prism-
|
|
170
|
-
| `@arnilo/prism-
|
|
171
|
-
| `@arnilo/prism-
|
|
172
|
-
| `@arnilo/prism-
|
|
173
|
-
| `@arnilo/prism-
|
|
174
|
-
| `@arnilo/prism-web-tools` | 0.
|
|
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
|
package/dist/agent-approval.d.ts
CHANGED
|
@@ -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 {
|
package/dist/agent-approval.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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: "
|
|
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;
|
package/dist/agent-run-state.js
CHANGED
|
@@ -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
|
|
265
|
-
|
|
266
|
-
|
|
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), {
|
|
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;
|