@arnilo/prism 0.7.0 → 0.9.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 +73 -0
- package/README.md +12 -11
- package/dist/agent-approval.d.ts +15 -2
- package/dist/agent-approval.js +5 -1
- package/dist/agent-event-source.d.ts +9 -1
- package/dist/agent-event-source.js +10 -3
- package/dist/agent-loops.js +7 -4
- package/dist/agent-run-lifecycle.d.ts +15 -1
- package/dist/agent-run-lifecycle.js +91 -10
- package/dist/agent-run-state.d.ts +34 -2
- package/dist/agent-run-state.js +68 -6
- package/dist/agent-session/helpers.js +20 -1
- package/dist/agent-session/session/assemble.js +250 -27
- package/dist/agent-session/session/persist.d.ts +27 -0
- package/dist/agent-session/session/persist.js +94 -12
- package/dist/agent-session/session/provider-round.d.ts +14 -4
- package/dist/agent-session/session/provider-round.js +197 -25
- package/dist/agent-session/session/tool-round.js +24 -2
- package/dist/agent-session/session/types.d.ts +36 -2
- package/dist/agent-session/session.d.ts +40 -4
- package/dist/agent-session/session.js +78 -5
- package/dist/attention-compiler.d.ts +51 -2
- package/dist/attention-compiler.js +282 -21
- package/dist/cache-helpers.d.ts +4 -2
- package/dist/cache-helpers.js +8 -6
- package/dist/checkpoint-restore.d.ts +45 -0
- package/dist/checkpoint-restore.js +54 -0
- package/dist/checkpoints.js +7 -11
- package/dist/context-budget.d.ts +2 -1
- package/dist/context-budget.js +24 -2
- package/dist/contracts-core/agent.d.ts +30 -0
- package/dist/contracts-core/attention.d.ts +95 -0
- package/dist/contracts-core/content.d.ts +15 -0
- package/dist/contracts-core/guardrail-packs.d.ts +41 -0
- package/dist/contracts-core/guardrail-packs.js +2 -0
- package/dist/contracts-core/loop.d.ts +42 -0
- package/dist/contracts-core/provider.d.ts +25 -0
- package/dist/contracts-core/run-limits.d.ts +21 -0
- package/dist/contracts-core/session.d.ts +23 -5
- package/dist/contracts-core/session.js +21 -2
- package/dist/contracts-core/usage.d.ts +40 -0
- package/dist/contracts-core/usage.js +8 -0
- package/dist/contracts-core.d.ts +2 -0
- package/dist/contracts-core.js +2 -0
- package/dist/contracts-protocol.d.ts +90 -4
- package/dist/contracts-run-state.d.ts +82 -6
- package/dist/evidence-grounding.d.ts +29 -0
- package/dist/evidence-grounding.js +162 -0
- package/dist/guardrail-packs/coding-standard.d.ts +3 -0
- package/dist/guardrail-packs/coding-standard.js +63 -0
- package/dist/guardrail-packs/destructive-commands.d.ts +3 -0
- package/dist/guardrail-packs/destructive-commands.js +46 -0
- package/dist/guardrail-packs/errors.d.ts +7 -0
- package/dist/guardrail-packs/errors.js +9 -0
- package/dist/guardrail-packs/index.d.ts +4 -0
- package/dist/guardrail-packs/index.js +15 -0
- package/dist/guardrail-packs/secrets-hygiene.d.ts +3 -0
- package/dist/guardrail-packs/secrets-hygiene.js +23 -0
- package/dist/guardrail-packs/types.d.ts +16 -0
- package/dist/guardrail-packs/types.js +2 -0
- package/dist/guardrail-packs/validation-respect.d.ts +3 -0
- package/dist/guardrail-packs/validation-respect.js +53 -0
- package/dist/guardrails.d.ts +20 -1
- package/dist/guardrails.js +268 -0
- package/dist/host-composition.d.ts +13 -0
- package/dist/host-composition.js +33 -2
- package/dist/index.d.ts +19 -10
- package/dist/index.js +11 -6
- package/dist/input.d.ts +8 -1
- package/dist/input.js +68 -6
- package/dist/middleware.d.ts +37 -2
- package/dist/middleware.js +41 -0
- package/dist/node/session-store-jsonl.js +18 -3
- package/dist/observability.js +6 -0
- package/dist/provider-events.d.ts +11 -3
- package/dist/provider-events.js +62 -4
- package/dist/providers/openai-compatible.js +6 -3
- 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 +150 -0
- package/dist/run-limits.d.ts +11 -1
- package/dist/run-limits.js +46 -0
- package/dist/session-stores.d.ts +12 -1
- package/dist/session-stores.js +21 -4
- package/dist/testing/agent-event-source-conformance.js +41 -2
- package/dist/testing/prefix-stability-conformance.d.ts +30 -0
- package/dist/testing/prefix-stability-conformance.js +104 -0
- package/dist/testing/session-store-conformance.d.ts +3 -2
- package/dist/testing/session-store-conformance.js +48 -0
- package/dist/testing/state-concurrency-conformance.js +5 -12
- package/dist/tools.d.ts +5 -0
- package/dist/tools.js +11 -3
- package/dist/usage-estimation.d.ts +29 -0
- package/dist/usage-estimation.js +79 -0
- package/docs/ag-ui.md +5 -0
- package/docs/agent-events.md +68 -1
- package/docs/agent-loops.md +33 -0
- package/docs/agent-session-runtime.md +5 -3
- package/docs/attention-compiler.md +89 -8
- package/docs/coding-agent-tools.md +1 -1
- package/docs/coding-security.md +1 -0
- package/docs/coding-tools.md +0 -1
- package/docs/compaction-and-retry.md +1 -1
- package/docs/compaction-observational-memory.md +34 -7
- package/docs/connected-apps.md +116 -0
- package/docs/context-and-skills.md +13 -0
- package/docs/core.md +1 -1
- package/docs/diagrams.md +6 -6
- package/docs/document-reader.md +9 -9
- package/docs/documents.md +32 -11
- package/docs/durable-runs.md +129 -0
- package/docs/embeddings.md +5 -0
- package/docs/enterprise-postgres-state.md +4 -0
- package/docs/evaluations.md +5 -0
- package/docs/execution-timeline.md +84 -1
- package/docs/guardrails.md +71 -2
- 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/release-handoffs.md +38 -0
- package/docs/host-compositions.md +8 -6
- package/docs/host-security.md +2 -2
- package/docs/index.md +66 -29
- package/docs/input-and-prompt-assembly.md +3 -3
- package/docs/knowledge-sync.md +4 -0
- package/docs/live-testing.md +5 -3
- package/docs/mcp-tools.md +1 -0
- package/docs/messaging-channel-operations.md +166 -0
- package/docs/messaging-channels.md +150 -0
- package/docs/middleware-hooks.md +38 -2
- package/docs/migrate-to-0.8.md +124 -0
- package/docs/migrate-to-0.9.md +210 -0
- package/docs/migration.md +43 -0
- package/docs/model-registry.md +12 -2
- package/docs/multi-agent-patterns.md +25 -2
- package/docs/node-jsonl-session-store.md +7 -1
- package/docs/observability.md +7 -3
- package/docs/openapi-tools.md +1 -1
- package/docs/operations.md +1 -3
- package/docs/options-index.md +36 -3
- package/docs/peer-dependencies.md +6 -6
- package/docs/policy-and-audit.md +13 -1
- package/docs/postgres-persistence.md +1 -1
- package/docs/prefix-stability-conformance.md +93 -0
- package/docs/provider-caching.md +4 -4
- package/docs/provider-conformance.md +16 -0
- package/docs/provider-layer.md +2 -2
- package/docs/provider-packages.md +20 -20
- package/docs/providers/neuralwatt.md +5 -1
- package/docs/public-contracts.md +2 -2
- package/docs/rag.md +102 -4
- package/docs/release-and-install.md +55 -47
- package/docs/run-bundle.md +92 -0
- package/docs/runs-and-usage.md +57 -6
- package/docs/scoped-agent-memory.md +262 -0
- package/docs/server.md +2 -0
- package/docs/session-store-conformance.md +1 -2
- package/docs/session-stores.md +17 -17
- package/docs/sheets.md +9 -9
- package/docs/signal-channel.md +112 -0
- package/docs/speech.md +5 -1
- package/docs/sqlite-persistence.md +1 -1
- package/docs/supervisors.md +32 -12
- package/docs/telegram-channel.md +157 -0
- package/docs/testing.md +2 -2
- package/docs/tools.md +17 -0
- package/docs/wiki.md +1 -1
- package/docs/work-artifacts-and-review.md +1 -1
- package/docs/work-connectors.md +9 -9
- package/docs/work-sandbox.md +115 -0
- package/docs/work-tools.md +38 -16
- package/docs/workflows.md +5 -0
- package/package.json +9 -3
- package/templates/business-worker/manifest.json +2 -1
- package/templates/business-worker/src/agent.ts.tmpl +1 -1
- package/templates/business-worker/src/tests/agent.test.ts.tmpl +1 -1
package/docs/index.md
CHANGED
|
@@ -2,21 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credentials, storage, and behavior; Prism supplies contracts, registries, events, and replaceable runtime primitives.
|
|
4
4
|
|
|
5
|
-
## Current line (0.
|
|
6
|
-
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
5
|
+
## Current line (0.9.0)
|
|
6
|
+
|
|
7
|
+
- **Attention budget axes**: `attentionCompiler.trigger` accepts one axis, a predicate, or an any-of array (`input_ratio`, `run_input_ratio`, `token_floor`), and `durable: true` keeps the fold ledger and sticky frontier in the checkpoint across a resume.
|
|
8
|
+
- **Turn traces and exhaustion attribution**: `provider_turn_finished` carries a closed `stopReason`, a `budgets` snapshot, the effective tool menu (`count` / `idsHash`), and provider cache counts; `agent_finished` carries the run outcome, and the execution timeline adds per-turn stop reasons plus `exhaustion`.
|
|
9
|
+
- **Cache-stable disclosure**: late-expanding context (skill bodies, deferred schemas, loaded references) lands at the request tail instead of rewriting the prefix, cache read/write telemetry rides usage records, and `runPrefixStabilityConformance` asserts a shared-prefix floor against a host's own assembly.
|
|
10
|
+
- **Per-turn tool narrowing**: a host callback receives the turn and the run grant and returns the effective subset; out-of-grant names are dropped and reported as `tool_narrowing_clamped`.
|
|
11
|
+
- **Usage estimation and the context meter**: labeled token estimates for providers that report no usage (reported usage always wins, and `usageEstimation: "off"` restores zero-for-no-usage), plus `session.contextMeter()` for cap and spend ratios.
|
|
12
|
+
- **Guardrail packs**: four built-in restrictive packs (`coding-standard`, `destructive-commands`, `validation-respect`, `secrets-hygiene`) compiled onto existing tool stages, each with a trajectory scorer.
|
|
13
|
+
- **Background child agents**: session-lifetime children with milestone or streamed reports, narrowed budget shares, and rate-coalesced child events.
|
|
14
|
+
- **Checkpoint sidecar metadata**: a redacted ≤4 KiB map attached to every checkpoint record without charging `maxStateBytes`, plus restore hooks that revert external layers before a resume claims the run.
|
|
15
|
+
- **Bounded session search**: `store.searchSessions(query)` over workspace/time/provider/label/kind/ownership filters, indexed at append time (SQLite FTS5, Postgres `tsvector`) with a bounded linear matcher for JSONL and memory stores.
|
|
16
|
+
- **Deterministic turns**: the `beforeProviderTurn` middleware hook answers a turn from host data with no provider request, recorded as `deterministic` on the timeline and in usage.
|
|
17
|
+
- **Shared work scopes**: explicitly granted observational-memory scopes shared across sessions, deny-by-default, audited, and revocable at the next read; session-private scopes stay the default.
|
|
18
|
+
- **Retrieval revocation and local reranking**: deletion and revocation propagate through derived vector/wiki artifacts under bounded walks, and an in-process cross-encoder reranker ships with no declared inference dependency.
|
|
19
|
+
- **Live-stream terminal semantics**: one `isTerminalAgentEventType` predicate (`agent_finished` / `agent_denied` / `error`) shared by every source, so a limit death delivers `run_limit_exceeded` → `budget_exhausted` → `error` before a stream or replay ends.
|
|
20
|
+
- **11 publishable packages** at current **0.9.0** lockstep, with the migration guide reachable from the release section below — inventory below.
|
|
21
|
+
|
|
22
|
+
### Carried from the 0.8.0 line
|
|
23
|
+
|
|
24
|
+
- **Messaging channels**: `@arnilo/prism-channels` transport-neutral runtime with deny-by-default authorization, owned bindings, one-use durable approvals, official Telegram (private DMs, opt-in granted groups/topics, drafts, bounded media/voice, opt-in notices) and experimental pinned signal-cli Signal.
|
|
25
|
+
- **Connected apps**: identity-bound MCP server sessions admit host-selected transports and register prefixed tools; Google Workspace and Microsoft 365 HTTP adapters live under `@arnilo/prism-work/connectors`.
|
|
26
|
+
- **Work family**: `@arnilo/prism-work` replaces `@arnilo/prism-office` — connectors, documents, sheets, diagrams, document-reader, sandbox, and vendored office skills. No pre-1.0 shim.
|
|
27
|
+
- **Durable long runs**: turn-boundary checkpoints with host-only `decision: "continue"`, turn-stop policy, frozen run-bundle snapshots, claim-grounding guardrail, and typed provider failure classes.
|
|
28
|
+
- **Honesty surfaces**: Postgres release evidence is this-commit, channel lease release stays held until the store acknowledges, and observational-memory workers ignore non-tool events on purpose.
|
|
29
|
+
|
|
30
|
+
### Carried from the 0.7.0 line
|
|
31
|
+
|
|
32
|
+
- **Traps closed**: ACP MCP destination matching uses WHATWG origin plus path-segment subtree rules, the ACP launcher requires a real provider (mock mode is explicit), and the model-router facade refuses governance it cannot enforce (`ERR_PRISM_MODEL_ROUTER_ASYNC_REQUIRED` / `_ASYNC_STATE`).
|
|
33
|
+
- **Governed host surfaces**: validated personal/business compositions, governed provider invocation with aggregate task/tenant accounting, durable business-action drafts with editable approvals, Docker process sessions and coherent workspace recovery, Drive knowledge synchronization, snapshot/reconnect with one hosted sandbox, fair worker admission, cross-layer memory lineage with correction/revocation, evidence-backed citations with import-fidelity/OCR reports, and monotonic per-run tool narrowing.
|
|
34
|
+
- **Evidence cockpit**: execution timeline, workflow graph, trajectory/outcome evals (scenarios, trials, manifests), cockpit aggregations, and workflow OpenTelemetry spans — with the cross-package journey matrix behind them.
|
|
35
|
+
- **Attention Compiler**: opt-in per-turn gate that mutates the transcript only after a ratio of the model input cap, with sticky thinking/tool stubs and a host-programmable compaction trigger.
|
|
36
|
+
- **Memory Fabric**: opt-in typed notes (fact/procedure/file/working/episode) with links, validity windows, and time/tool recall over the working, semantic, and observational-memory engines.
|
|
37
|
+
- **Work-scope memory index**: host-named work scopes (`open`/`bind`/`project`/`enter`) project the observational outline; unscoped attach keeps the 0.6.0 dropper.
|
|
38
|
+
- **Host-owned subagent spawn**: `spawn_agent` over the host supervisor (allow-listed children, narrowed identity, redacted results), bounded async spawn with `wait_agent`/`cancel_agent`, opt-in per-child worktree isolation, and redacted `subagent_started`/`subagent_stopped` lifecycle events.
|
|
39
|
+
- **Native Bedrock Converse and governed realtime voice**: `createBedrockConverseProvider` adds a native `Converse`/`ConverseStream` route next to the OpenAI-compatible one, with no AWS SDK dependency; realtime voice sessions stay host-governed.
|
|
16
40
|
|
|
17
41
|
### Carried from the 0.6.0 line
|
|
18
42
|
|
|
19
|
-
- **Node 22 floor**: `engines.node` is `>=22` in all
|
|
43
|
+
- **Node 22 floor**: `engines.node` is `>=22` in all eleven publishable packages, the `node20-compat` CI leg becomes `node22-compat`, and `@types/node` moves to `^22.20.0` (plan 071; Node 20 is upstream EOL since 2026-04-30).
|
|
20
44
|
- **Folded 0.5.7 content**: the 0.5.7 cut was never published — its durable-tool-round and strict-tool-result fixes, host knobs, peer/options truth, and dependency floors ship in 0.6.0 (migration guide below).
|
|
21
45
|
- **Release-truth gates**: one forward-claim version-literal gate (manifests, internal ranges, lockfile, version constant, index banner, workflow tags), a workflow-liveness gate (every script target and action reference resolves, actions SHA-pinned), and a load-tolerant startup budget ratio (plan 071).
|
|
22
46
|
- **Self-describing coverage failures**: a failing coverage child prints its redacted output tail and records `status`/`exitCode`/`tail` on its artifact row (plan 071).
|
|
@@ -35,8 +59,8 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
|
|
|
35
59
|
## Public contracts
|
|
36
60
|
|
|
37
61
|
- [Public contracts](public-contracts.md): canonical message, agent, tool, store, resource, credential, and event shapes.
|
|
38
|
-
- [Coding tools, sandboxing, and personas](coding-tools.md): `@arnilo/prism-coding-tools` family subpaths — agent, security,
|
|
39
|
-
- [Core runtime, sessions, and governance](core.md): `@arnilo/prism-core` family subpaths — runtime, sessions, governance, credentials, enterprise,
|
|
62
|
+
- [Coding tools, sandboxing, and personas](coding-tools.md): `@arnilo/prism-coding-tools` family subpaths — agent, security, openapi, computer-use-linux, dev, personas.
|
|
63
|
+
- [Core runtime, sessions, and governance](core.md): `@arnilo/prism-core` family subpaths — runtime, sessions, governance, credentials, enterprise, validation.
|
|
40
64
|
- [Configuration options index](options-index.md): every public `*Options`/`*Limits`/`*Config` surface mapped to the doc page that owns its fields.
|
|
41
65
|
|
|
42
66
|
## Identity and governance
|
|
@@ -49,6 +73,7 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
|
|
|
49
73
|
## Agent/session runtime
|
|
50
74
|
|
|
51
75
|
- [Agent/session runtime](agent-session-runtime.md): create agents/sessions, `run`/`prompt`/`steer`/`stream`, durable resume, batch approvals, per-run `toolNames` narrowing.
|
|
76
|
+
- [Durable runs](durable-runs.md): turn-boundary `checkpointPolicy: "every-turn"` checkpoints and `decision: "continue"` crash recovery for long runs.
|
|
52
77
|
- [Agent definitions](agent-definitions.md): declarative `AgentDefinition` resolution and `AGENT.md` bundle discovery, fail-closed activation.
|
|
53
78
|
- [Agent loops](agent-loops.md): replaceable loops with `limits.maxToolRounds` budgets and durable revision/restore hooks.
|
|
54
79
|
- [Guardrails](guardrails.md): typed fail-closed input/output/tool checks with redacted decision records.
|
|
@@ -70,6 +95,7 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
|
|
|
70
95
|
- [Observational memory compaction subpath](compaction-observational-memory.md): source-backed observations/reflections, an optional work-scope index for the current working set, and exact-id recall; `invalidatedIds` withhold derived injection.
|
|
71
96
|
- [Working and semantic memory](working-and-semantic-memory.md): working-memory store, semantic recall, pgvector path, consent lifecycle, lineage invalidation, parent-child share grants.
|
|
72
97
|
- [Memory fabric](memory-fabric.md): opt-in typed notes (fact/procedure/file/working/episode) with validity windows over the existing vector and working stores.
|
|
98
|
+
- [Scoped agent memory design concept](scoped-agent-memory.md): workspace-scoped persistent memory — gated writes, promotion ladder, decay-based reads; case study and research basis.
|
|
73
99
|
- [Session stores](session-stores.md): `SessionStore` contract, append options, branches, bounded search — start here for persistence.
|
|
74
100
|
- [Conversations](conversations.md): durable user-scoped threads with versioned metadata and legal-hold-aware deletion.
|
|
75
101
|
- [Work artifacts and review](work-artifacts-and-review.md): artifact attach, revision compare, evidence-bound citations, approve/reject, expiring delivery links.
|
|
@@ -111,7 +137,7 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
|
|
|
111
137
|
- [System prompts](system-prompts.md): layered system prompts plus trust-gated `AGENTS.md`/`SYSTEM.md` file auto-load.
|
|
112
138
|
- [Versioned prompt registry](prompt-registry.md): immutable content-hashed prompt assets with durable stores and bounded diff.
|
|
113
139
|
- [Instruction injection](instruction-injection.md): package injectors layer redacted instructions without granting capabilities.
|
|
114
|
-
- [Context and skills](context-and-skills.md): ordered context providers, progressive skill disclosure, fail-closed activation.
|
|
140
|
+
- [Context and skills](context-and-skills.md): ordered context providers, progressive skill disclosure, fail-closed activation. `@arnilo/prism-work` ships `docx`, `xlsx`, `powerpoint`, `pdf`.
|
|
115
141
|
- [LLM Wiki](wiki.md): optional knowledge compiler emitting OKF bundles, with `/wiki-ingest` raw staging (text, file, image, or URL via a host `fetchUrl` hook) and on-device hybrid search.
|
|
116
142
|
- [Retrieval-augmented generation](rag.md): bounded source lifecycle, hybrid retrieval, permission-trimmed query legs, reranking, evidence-backed citations, inert injection.
|
|
117
143
|
- [Knowledge synchronization](knowledge-sync.md): paged enterprise-source import with a Drive connector, checkpointed change cursors, and host-owned ACL mapping.
|
|
@@ -124,15 +150,17 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
|
|
|
124
150
|
- [Tool execution primitives](tool-execution-primitives.md): bounded JSON Schema validation, parallel dispatch, MCP bridge mapping.
|
|
125
151
|
- [Tool validator JSON Schema package](../packages/prism-core/README.md): optional `@arnilo/prism-core/validation/json-schema` adapter.
|
|
126
152
|
- [MCP client bridge and server exposure](mcp-tools.md): SDK v2 bridge and serving with OAuth transports and DNS-pinned transport.
|
|
153
|
+
- [Connected apps](connected-apps.md): identity-bound MCP server sessions that admit host-selected transports and register prefixed tools.
|
|
127
154
|
- [Web search, fetch, and extraction](web-tools.md): Brave/Exa/Firecrawl tools with finite limits, hashed web evidence snapshots, and untrusted-content boundaries.
|
|
128
|
-
- [Work tools](work-tools.md): identity-scoped M365/GWS connectors —
|
|
155
|
+
- [Work tools](work-tools.md): identity-scoped M365/GWS connectors — scanned file get, hash-bound uploads/copies, fixed Docs/Sheets/Slides updates, approvals, isolated subprocess environments.
|
|
129
156
|
- [Work connectors](work-connectors.md): connector principles, capability gates, scoped OAuth establishment, out-of-scope boundaries.
|
|
157
|
+
- [Work sandbox](work-sandbox.md): host-pinned document image and `createWorkComposition` — office/exec in an injected Docker sandbox, connectors stay on the host.
|
|
130
158
|
- [Browser automation](browser-automation.md): Playwright-backed browser tools with egress policy, caps, and verified checkpoints.
|
|
131
159
|
- [Device adapters](device-adapters.md): deny-by-default realtime voice/desktop-control contract with consent and sandbox gating.
|
|
132
160
|
- [Linux desktop control](computer-use-linux.md): optional `computer-use-linux` MCP wrapper — doctor-first, approval-gated mutators.
|
|
133
161
|
- [Obscura browser engine](obscura.md): optional host-binary browser engine adapter with fail-closed lifecycle and CDP composition.
|
|
134
162
|
- [Coding agent tools](coding-agent-tools.md): shell/read/write/edit/search toolset with caps, document reader, and optional Git awareness.
|
|
135
|
-
- [Document reader](document-reader.md): bounded PDF/DOCX text extraction behind `createReadTool({ documentReader })`; optional host-selected Mistral OCR parser (not default).
|
|
163
|
+
- [Document reader](document-reader.md): bounded PDF/DOCX/XLSX/PPTX text extraction behind `createReadTool({ documentReader })`; optional host-selected Mistral OCR parser (not default).
|
|
136
164
|
- [Indexed code search](indexed-code-search.md): host-owned incremental index seam; results labeled `untrusted_index`.
|
|
137
165
|
- [Coding workspaces](coding-workspaces.md): worktree lifecycle with CheckpointStore CAS records, LeaseStore fencing, and opt-in per-child spawn isolation.
|
|
138
166
|
- [Coding review and diagnostics](coding-review-and-diagnostics.md): bounded patch-review manifests and normalized LSP diagnostics.
|
|
@@ -159,6 +187,7 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
|
|
|
159
187
|
## Configuration/manifests
|
|
160
188
|
|
|
161
189
|
- [Configuration and manifests](configuration-and-manifests.md): layered JSON config merge with data-only manifest validation.
|
|
190
|
+
- [Effective run bundle snapshots](run-bundle.md): frozen JSON projection of the effective run bundle — prompt/skill/tool/guardrail digests, resolved limits, storage kinds, one pinning digest, zero network or store reads.
|
|
162
191
|
- [Host compositions](host-compositions.md): personal and business worker host compositions, inspection reports, storage durability truth, sandbox isolation, and fail-closed readiness enforcement.
|
|
163
192
|
- [Node filesystem config loader](node-filesystem-config.md): explicitly read caller-named JSON config files in Node.
|
|
164
193
|
- [Resource loading](resource-loading.md): decode text/JSON/binary through caller-provided loaders; RAG bridge.
|
|
@@ -201,9 +230,10 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
|
|
|
201
230
|
- [Session store conformance](session-store-conformance.md): assert append/idempotency/conflict/branch invariants for any store.
|
|
202
231
|
- [Run ledger conformance](run-ledger-conformance.md): assert durable run/usage writes and reopen survival.
|
|
203
232
|
- [Compaction conformance](compaction-conformance.md): assert redacted non-empty summaries and abort observation.
|
|
233
|
+
- [Prefix stability conformance](prefix-stability-conformance.md): assert progressive disclosure keeps the provider cache prefix stable.
|
|
204
234
|
- [Tool conformance](tool-conformance.md): assert blocked-reason matrix and success-path dispatch behavior.
|
|
205
235
|
- [Extension conformance](extension-conformance.md): assert inert contributions and redacted setup errors.
|
|
206
|
-
- `examples/`: compile-checked typed examples ([`conversation-durable-replay.ts`](../examples/conversation-durable-replay.ts), [`artifact-review-delivery.ts`](../examples/artifact-review-delivery.ts), [`enterprise-identity.ts`](../examples/enterprise-identity.ts), [`enterprise-policy-audit.ts`](../examples/enterprise-policy-audit.ts), [`enterprise-work-connectors.ts`](../examples/enterprise-work-connectors.ts), [`server-deployment-seams.ts`](../examples/server-deployment-seams.ts), [`neuralwatt-agent-run.ts`](../examples/neuralwatt-agent-run.ts), [`cache-aware-prompt-assembly.ts`](../examples/cache-aware-prompt-assembly.ts), [`ag-ui-server.ts`](../examples/ag-ui-server.ts), [`acp-coding-host.ts`](../examples/acp-coding-host.ts), and more), plus runnable mock demos.
|
|
236
|
+
- `examples/`: compile-checked typed examples ([`conversation-durable-replay.ts`](../examples/conversation-durable-replay.ts), [`artifact-review-delivery.ts`](../examples/artifact-review-delivery.ts), [`enterprise-identity.ts`](../examples/enterprise-identity.ts), [`enterprise-policy-audit.ts`](../examples/enterprise-policy-audit.ts), [`enterprise-work-connectors.ts`](../examples/enterprise-work-connectors.ts), [`connected-slack-mcp.ts`](../examples/connected-slack-mcp.ts), [`server-deployment-seams.ts`](../examples/server-deployment-seams.ts), [`neuralwatt-agent-run.ts`](../examples/neuralwatt-agent-run.ts), [`cache-aware-prompt-assembly.ts`](../examples/cache-aware-prompt-assembly.ts), [`ag-ui-server.ts`](../examples/ag-ui-server.ts), [`acp-coding-host.ts`](../examples/acp-coding-host.ts), [`telegram-agent.ts`](../examples/telegram-agent.ts), [`signal-agent.ts`](../examples/signal-agent.ts), [`messaging-agent.ts`](../examples/messaging-agent.ts), and more), plus runnable mock demos.
|
|
207
237
|
|
|
208
238
|
## Third-party integrations
|
|
209
239
|
|
|
@@ -211,10 +241,16 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
|
|
|
211
241
|
- [Ponytail behavior integration](ponytail.md): upstream Ponytail skills with injector and peer resolution; opt-in.
|
|
212
242
|
- [Graft context-graph integration](graft.md): graft CLI pull tools, retrieval-pack context provider, blast-radius middleware, and `/graft-init` / `/graft-build` / `/graft-build-deep` commands (host-configured `deepModel`).
|
|
213
243
|
- [Impeccable behavior integration](impeccable.md): upstream Impeccable skill behind `load_skill`; host supplies the compiled `SKILL.md`.
|
|
244
|
+
- [Messaging channels](messaging-channels.md): `@arnilo/prism-channels` transport-neutral runtime — deny-by-default sender authorization, owned session binding, serialized turns, current-run replies, one-use durable approvals, bounded attachment refs (images reach the model only when it declares image input), and opt-in host notices to one already-bound pair.
|
|
245
|
+
- [Telegram channel](telegram-channel.md): official `@arnilo/prism-channels/telegram` long polling and mountable webhook ingress with durable offset/lease handling, approval callbacks, opt-in granted group/topic text, bounded media with optional voice transcription/synthesis, and opt-in streaming drafts.
|
|
246
|
+
- [Signal channel (experimental)](signal-channel.md): `@arnilo/prism-channels/signal` pinned signal-cli v0.14.8 private-socket manual receive, explicit policy gate, UUID DM filtering and bounded ambiguous delivery.
|
|
247
|
+
- [Messaging channel operations](messaging-channel-operations.md): durable journal, restart and reconciliation contract, lease fencing, retention and the operator runbook.
|
|
214
248
|
|
|
215
249
|
## Release and install
|
|
216
250
|
|
|
217
251
|
- [Release and install](release-and-install.md): install rules, package graph, and deterministic resumable publication.
|
|
252
|
+
- [Migrate 0.8 → 0.9](migrate-to-0.9.md): the four behavior deltas inside existing surfaces (limit-death stream order, turn-trace metadata, cache-stable disclosure, labeled usage estimates), every new option with its sizing line, and 0.9.0 host migration steps.
|
|
253
|
+
- [Migrate 0.7 → 0.8](migrate-to-0.8.md): work-family import map, messaging channels, connected apps, durable runs, and 0.8.0 host migration steps.
|
|
218
254
|
- [Migrate 0.6 → 0.7](migrate-to-0.7.md): ACP MCP allow-list URL normalization, model router facade fail-closed governance, and 0.7.0 host migration steps.
|
|
219
255
|
- [Migrate 0.5 → 0.6](migrate-to-0.6.md): Node 22 floor, folded 0.5.7 host delta, third-party floors, and upgrade/rollback steps.
|
|
220
256
|
- [Migrate 0.5](migrate-to-0.5.md): 0.4 → 0.5 migration guide with per-release sections and rollback.
|
|
@@ -226,18 +262,19 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
|
|
|
226
262
|
The generated inventory below derives from [`scripts/package-truth.json`](../scripts/package-truth.json) — regenerate with `node scripts/package-truth.mjs --emit-docs`, never hand-edit.
|
|
227
263
|
|
|
228
264
|
<!-- generated:package-truth:inventory begin -->
|
|
229
|
-
**
|
|
265
|
+
**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.
|
|
230
266
|
|
|
231
267
|
| package | version | notes |
|
|
232
268
|
| --- | --- | --- |
|
|
233
|
-
| `@arnilo/prism` | 0.
|
|
234
|
-
| `@arnilo/prism-
|
|
235
|
-
| `@arnilo/prism-
|
|
236
|
-
| `@arnilo/prism-
|
|
237
|
-
| `@arnilo/prism-
|
|
238
|
-
| `@arnilo/prism-
|
|
239
|
-
| `@arnilo/prism-
|
|
240
|
-
| `@arnilo/prism-
|
|
241
|
-
| `@arnilo/prism-
|
|
242
|
-
| `@arnilo/prism-web-tools` | 0.
|
|
269
|
+
| `@arnilo/prism` | 0.9.0 | core — runtime, CLI/RPC, templates, docs |
|
|
270
|
+
| `@arnilo/prism-channels` | 0.9.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 |
|
|
271
|
+
| `@arnilo/prism-coding-tools` | 0.9.0 | family — /agent, /security, /openapi, /computer-use-linux, /dev, /caveman, /ponytail, /impeccable subpaths |
|
|
272
|
+
| `@arnilo/prism-core` | 0.9.0 | family — /runtime, /sessions, /governance, /credentials, /enterprise, /validation subpaths |
|
|
273
|
+
| `@arnilo/prism-providers` | 0.9.0 | family — all provider adapters as `/<adapter>` subpaths |
|
|
274
|
+
| `@arnilo/prism-acp-agent` | 0.9.0 | capability — ACP adapter |
|
|
275
|
+
| `@arnilo/prism-ag-ui` | 0.9.0 | capability — AG-UI/A2A/A2UI adapter |
|
|
276
|
+
| `@arnilo/prism-mcp` | 0.9.0 | capability — MCP client/server/OAuth interop |
|
|
277
|
+
| `@arnilo/prism-memory` | 0.9.0 | capability — memory plus /rag, /compaction/*, /fabric, /graft, /wiki subpaths |
|
|
278
|
+
| `@arnilo/prism-web-tools` | 0.9.0 | capability — Brave/Exa/Firecrawl plus peer-gated /browser and /obscura subpaths |
|
|
279
|
+
| `@arnilo/prism-work` | 0.9.0 | capability — /connectors, /documents, /sheets, /diagrams, /document-reader, /sandbox, /skills, /tools subpaths |
|
|
243
280
|
<!-- generated:package-truth:inventory end -->
|
|
@@ -62,7 +62,7 @@ Useful exported types:
|
|
|
62
62
|
- `InputAttachment`: already-loaded text/content blocks (including `audio`, `file`, and `document`) or an explicit URI loaded through a caller-provided `ResourceLoader`.
|
|
63
63
|
- `PromptInstruction`: labeled system instruction text.
|
|
64
64
|
- `DefaultPromptBuilder`: the default `PromptBuilder`; cache-aware by default and legacy-preserving when `inputLayout: "legacy"` is passed in its request.
|
|
65
|
-
- `AssembleProviderInputOptions`: model, input, optional builders, context providers, selected skills, active tools, generic provider options, metadata, signal, and optional `contextBudget` (`maxInputTokens` / `maxInputBytes` / `reportOmissions` / `tokenEstimator`).
|
|
65
|
+
- `AssembleProviderInputOptions`: model, input, optional builders, context providers, selected skills, active tools, generic provider options, metadata, signal, optional session-owned `tailSegments`, and optional `contextBudget` (`maxInputTokens` / `maxInputBytes` / `reportOmissions` / `tokenEstimator`).
|
|
66
66
|
- `applyContextBudget` / `getContextBudgetReport` / `resolveContextBudget`: deterministic eviction + omission report helpers (estimate = UTF-16 code units ÷ 4, or the host's `tokenEstimator`).
|
|
67
67
|
- `PromptTemplateOptions`: missing-variable behavior for `renderPromptTemplate()`.
|
|
68
68
|
|
|
@@ -81,10 +81,10 @@ The builder returns `readonly Message[]`.
|
|
|
81
81
|
|
|
82
82
|
The default prompt builder preserves one composition path while honoring layout:
|
|
83
83
|
|
|
84
|
-
- `cache_aware` (default): leading system messages from input assembly → resolved context blocks → selected/progressively disclosed
|
|
84
|
+
- `cache_aware` (default): leading system messages from input assembly → resolved context blocks → selected/progressively disclosed skill catalogs → text tool declarations for text-only/unknown models → remaining input-builder messages (attachments/resources → summaries → history → tool results → current input) → optional session tail.
|
|
85
85
|
- `legacy`: context blocks → skills → text tool declarations → all input-builder messages (instructions → summaries → history → current input → attachments/resources → tool results).
|
|
86
86
|
|
|
87
|
-
In cache-aware mode, leading system instructions form the stable boundary before dynamic context and
|
|
87
|
+
In cache-aware mode, leading system instructions form the stable boundary before dynamic context and skill catalogs. The provider `tools` field remains the host-supplied schema list; text declarations are only a fallback for models without declared tool support. `RuntimeAgentSession` supplies a run-owned `tailSegments` map: URI resources and loaded skill bodies move to the final tail, while their catalog rows remain in place. First insertion fixes tail order (`resource:<uri>` / `skill:<name>`); re-derivation of an id replaces only that segment's bytes, making changed source content an explicit cache-invalidation boundary. Context-budget eviction can omit a tail segment. Custom prompt builders receive the tail in `messages` plus `tailSkillBodies`; a builder that independently renders `skills` must honor that flag. A stable prefix persists only while those stable inputs stay byte-stable; provider cache hits remain best-effort.
|
|
88
88
|
- History is prepended before current input.
|
|
89
89
|
- Instructions and summaries are system messages; compacted branch summaries from `rebuildSessionContext()` use the same path.
|
|
90
90
|
- Text attachments and explicit text resources are user messages; inline `audio`/`file`/`document` blocks pass through unchanged on attachments with `content`.
|
package/docs/knowledge-sync.md
CHANGED
|
@@ -29,6 +29,10 @@ Use it when a host must keep a RAG corpus aligned with an enterprise file source
|
|
|
29
29
|
|
|
30
30
|
No tools, no watch-channel authorization, no events.
|
|
31
31
|
|
|
32
|
+
## Delete contract
|
|
33
|
+
|
|
34
|
+
A connector `delete` change calls `deleteSource()` for that source only: the connector's own chunk rows and ingestion status go away, under exact tenant/resource/corpus scope. Connector payloads are never authorization, so sync cannot reach beyond the corpus it owns — derived artifacts (summaries, observational-memory entries, compiled wiki pages, host projections) survive sync deletes by design. Removing those is a separate privileged pass through `createDeletionPropagator().propagate(sourceId)` (see [RAG deletion propagation](rag.md#deletion-propagation)), driven by the host, not by the connector.
|
|
35
|
+
|
|
32
36
|
## Request/response example
|
|
33
37
|
|
|
34
38
|
```json
|
package/docs/live-testing.md
CHANGED
|
@@ -71,13 +71,13 @@ Set only the rows you want to run; everything else skips. Least-privilege scope
|
|
|
71
71
|
| `web-tools/obscura-live` | active | `PRISM_LIVE_OBSCURA` + `PRISM_OBSCURA_BIN` | — | Local obscura CLI binary; suite fails closed if flag set without binary. | Local process, no API spend. |
|
|
72
72
|
| `memory/observational-live` | active | `PRISM_LIVE_OBSERVATIONAL_MEMORY_TESTS` + `OPENAI_API_KEY` | `PRISM_LIVE_OPENAI_MODEL` (not wired yet) | Reuses the OpenAI key as the compaction worker provider. | A few small summarization requests. |
|
|
73
73
|
| `memory/compaction-llm-live` | active | `PRISM_LIVE_COMPACTION_TESTS` | — | Stub leg today: live summary-provider checks are wired by plans/064 Task 6 (provider key + model env TBD there). | n/a until wired. |
|
|
74
|
-
| `
|
|
75
|
-
| `
|
|
74
|
+
| `work/libreoffice-golden` | active | `PRISM_TEST_LIBREOFFICE` | — | Local LibreOffice binary renders golden documents; no secret. | Local process, no API spend. |
|
|
75
|
+
| `work/drawio-live` | active | any of: `PRISM_LIVE_DRAWIO_URL` / `PRISM_TEST_DRAWIO_URL` | — | Operator-hosted drawio export service URL (not a secret). | 1-2 export requests to your own service. |
|
|
76
76
|
| `core/postgres` | active | `PRISM_TEST_POSTGRES_URL` | — | Throwaway PostgreSQL database URL (sessions + enterprise + event-source + memory vector legs). | Local/container DB, no API spend. |
|
|
77
77
|
| `core/nats` | active | `PRISM_TEST_NATS_URL` | — | NATS server URL with JetStream enabled. | Local/container server, no API spend. |
|
|
78
78
|
| `coding-tools/docker-sandbox` | active | `PRISM_TEST_DOCKER_SANDBOX` + `PRISM_TEST_DOCKER_BIN` + `PRISM_TEST_DOCKER_IMAGE` + `PRISM_TEST_DOCKER_USER` | — | Local Docker daemon + pinned minimal sandbox image; no secret. | Local containers, no API spend. |
|
|
79
79
|
| `coding-tools/e2b-sandbox-live` | active | `PRISM_TEST_E2B_API_KEY` | — | E2B API key; least privilege: one throwaway sandbox, no production templates. | 1 create + 2 exec + filesystem-only pause + connect/resume + kill. |
|
|
80
|
-
| `
|
|
80
|
+
| `work/mistral-ocr-live` | active | `PRISM_TEST_MISTRAL_API_KEY` | — | Mistral OCR API key; least privilege: one throwaway 2-page sample PDF, no Files API upload. | 1 OCR request against mistral-ocr-latest. |
|
|
81
81
|
| `core/keychain` | active | `PRISM_TEST_KEYCHAIN` | — | Real OS keychain; writes throwaway test entries only. | Local, no API spend. |
|
|
82
82
|
| `acp/client-smoke` | active | `PRISM_TEST_ACP_CLIENT` | — | Real ACP SDK client over stdio in a subprocess; sandboxed, policy never disabled. | Local process, no API spend. |
|
|
83
83
|
| `canaries/deployed` | active | `PRISM_LIVE_CANARIES`; optional: `PRISM_CANARY_TIMEOUT_MS` `PRISM_CANARY_REPORT` | — | Deployed prism provider/MCP/A2A endpoints; script itself validates all PRISM_CANARY_* URL/token vars and credential-free HTTPS. | 1-4 bounded requests (64 KiB JSON cap) against your deployments. |
|
|
@@ -104,6 +104,8 @@ Set only the rows you want to run; everything else skips. Least-privilege scope
|
|
|
104
104
|
| `coding-tools/lsp-forge` | active | — (hermetic leg) | — | LSP/language-intelligence + forge suites: real child-process spawns over the real LSP/forge wire protocols against fixture binaries. | Hermetic; no network. |
|
|
105
105
|
| `ag-ui/conformance` | active | — (hermetic leg) | — | AG-UI + ACP conformance suites: real-event replay over the acp/a2a/ag-ui protocol surfaces (fixture agents, real event-source wire semantics). | Hermetic; no network. |
|
|
106
106
|
| `prism-providers/conformance` | active | — (hermetic leg) | — | Plan-065 machine-checked thinking coverage: every first-party reasoning catalog model declares capabilities.thinkingLevels + a compat.thinkingFamily stamp and emits a legal effort field on the wire (14 catalogs walked hermetically). | free |
|
|
107
|
+
| `channels/telegram-live` | active | `PRISM_LIVE_TELEGRAM` + `TELEGRAM_BOT_TOKEN`; optional: `PRISM_LIVE_TELEGRAM_CHAT_ID` | — | Operator-owned Telegram bot token. getMe + 1s poll; send only if PRISM_LIVE_TELEGRAM_CHAT_ID names a chat you operate. Never creates contacts. | 1 getMe + 1 getWebhookInfo (+ optional 1 sendMessage). |
|
|
108
|
+
| `channels/signal-live` | active | `PRISM_LIVE_SIGNAL` + `PRISM_LIVE_SIGNAL_SOCKET` + `PRISM_LIVE_SIGNAL_ACCOUNT` + `PRISM_LIVE_SIGNAL_TERMS_VERSION`; optional: `PRISM_LIVE_SIGNAL_RECIPIENT_UUID` | — | Existing private signal-cli v0.14.8 Unix socket and account you already operate. Never registers or links. Send only to PRISM_LIVE_SIGNAL_RECIPIENT_UUID. | 1 subscribeReceive + health (+ optional 1 send). |
|
|
107
109
|
<!-- generated:live-matrix:end -->
|
|
108
110
|
|
|
109
111
|
## Strict CI workflow
|
package/docs/mcp-tools.md
CHANGED
|
@@ -305,6 +305,7 @@ The scenario stays sandboxed (read-only echo tool, authorize-gated denial, no po
|
|
|
305
305
|
|
|
306
306
|
## Related APIs
|
|
307
307
|
|
|
308
|
+
- [Connected apps](connected-apps.md): identity-bound host admission and lifecycle for a small set of MCP bridges.
|
|
308
309
|
- [Agent identity](agent-identity.md): optional verified identity on MCP authorize results
|
|
309
310
|
- [Tools](tools.md): registry, dispatch, validation
|
|
310
311
|
- [Web search, fetch, and extraction](web-tools.md): preferred direct bounded Brave/Exa/Firecrawl production path
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Messaging channel operations
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
Operational contract for the `@arnilo/prism-channels` durable journal: what is persisted, in what order, what happens across restarts, and how an operator resolves work that cannot be proven. Read this with [Messaging channels](messaging-channels.md) (authorization and execution semantics) and [Agent session runtime](agent-session-runtime.md).
|
|
6
|
+
|
|
7
|
+
Everything here is a consumer of the generic `CheckpointStore`/`LeaseStore` contracts — no channel-specific SQL schema, no background work, no automatic replay.
|
|
8
|
+
|
|
9
|
+
## When to use it
|
|
10
|
+
|
|
11
|
+
Use when a host needs restart-safe bindings, admission dedup, claims and staged replies. Without `checkpoints` the runtime is single-process and restart-unsafe.
|
|
12
|
+
|
|
13
|
+
## Implementation example
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { createMessagingRuntime } from "@arnilo/prism-channels";
|
|
17
|
+
import { createSqlitePersistence } from "@arnilo/prism-core/sessions/sqlite";
|
|
18
|
+
|
|
19
|
+
const persistence = createSqlitePersistence({ filename: "./channels.sqlite" });
|
|
20
|
+
|
|
21
|
+
const runtime = createMessagingRuntime({
|
|
22
|
+
authorize,
|
|
23
|
+
resolveAgent,
|
|
24
|
+
deliver,
|
|
25
|
+
checkpoints: persistence.checkpoints,
|
|
26
|
+
leases: persistence.leases, // optional: fencing when more than one worker can see the same binding
|
|
27
|
+
limits: { retentionDays: 7 },
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
With `checkpoints`, a restart re-reads bindings, generations, dedup records and staged replies from the store; nothing is replayed on startup.
|
|
32
|
+
|
|
33
|
+
## Inputs / request
|
|
34
|
+
|
|
35
|
+
Records live in versioned namespaces (`prism.channels.v1.*`) with a `category` for host-side filtering. Keys embed the connection and the ownership scope (`tenant`, `account`, `user`), so a lookup in another scope misses rather than colliding, and the record carries the same scope so the store itself refuses a mismatched write.
|
|
36
|
+
|
|
37
|
+
| Namespace | Record | Contents |
|
|
38
|
+
| --- | --- | --- |
|
|
39
|
+
| `prism.channels.v1.binding` | `ChannelBindingRecord` | session id, branch leaf, alias, `/new` generation, suspended marker and run/operation correlation |
|
|
40
|
+
| `prism.channels.v1.operation` | `ChannelOperationRecord` | one admitted event: kind, external ids, state, run correlation (`runId`), reply flag, attempts |
|
|
41
|
+
| `prism.channels.v1.cursor` | `ChannelCursorRecord` | per-connection admitted count and last event id (ordering evidence only) |
|
|
42
|
+
| `prism.channels.v1.reply` | `ChannelReplyRecord` | the staged reply text (the only record with payload), delivery state, attempts, message id |
|
|
43
|
+
| `prism.channels.v1.control` | pairing or approval record | SHA-256 token hash, bound ids; approval records also bind principal, agent revision, session/run, pending-decision id, checkpoint version, outcome, expiry and consumed marker |
|
|
44
|
+
|
|
45
|
+
Operation keys use the deterministic operation id (`chan-op-<sha256 prefix>` of connection + event id), so admission dedup is a create-only CAS: the second writer loses and is acknowledged as a duplicate.
|
|
46
|
+
|
|
47
|
+
## Outputs / response / events
|
|
48
|
+
|
|
49
|
+
The store exposes single-record compare-and-swap only, so the order is explicit and each step is bounded:
|
|
50
|
+
|
|
51
|
+
1. **Authorize** the event against the host grant (no record yet; denial leaves nothing behind).
|
|
52
|
+
2. **Operation record** created as `accepted` (create-only CAS). This is the durable dedup and the transport acknowledgment point.
|
|
53
|
+
3. **Cursor advance** as ordering evidence, best-effort after the operation is committed.
|
|
54
|
+
4. **Claim**: `accepted` → `executing` by CAS (with the binding lease fence when `leases` is configured) *before* any provider or tool call.
|
|
55
|
+
5. **Run** the bound `AgentSession` turn with the verified identity. An event whose attachments cannot become text or model input settles `failed` with `errorCode: "unsupported_media"` and a bounded notice; declared attachment bytes over the channel cap are denied `oversized` before a record is claimed, and an oversize body is never buffered by the adapter.
|
|
56
|
+
6. **Operation terminal state** (`succeeded`/`failed`/`cancelled`/`suspended`) with run correlation, then the binding (leaf, suspended marker) is updated.
|
|
57
|
+
7. **Reply staged** as `pending`, then `deliver`, then `delivered` / `delivery_failed` / `delivery_unknown`.
|
|
58
|
+
|
|
59
|
+
Failure semantics by state:
|
|
60
|
+
|
|
61
|
+
| State | Meaning | Automatic action |
|
|
62
|
+
| --- | --- | --- |
|
|
63
|
+
| `accepted` | Journaled, never claimed | None. A crash here is a dead-letter; the user resends |
|
|
64
|
+
| `executing` | Claimed; provider work may have happened | None. Never replayed |
|
|
65
|
+
| `succeeded` / `failed` / `cancelled` | Terminal run outcome (current-run text only is ever sent) | None |
|
|
66
|
+
| `suspended` | Awaiting a core pending decision; blocks further ordinary turns on the binding | A short-lived server-issued allow/deny control resumes one decision, or `/cancel` submits core terminal denial; `/new` cannot bypass it |
|
|
67
|
+
| `execution_unknown` | A reconciling host filed unprovable claimed work | None; it is a dead-letter record |
|
|
68
|
+
| `abandoned` | Reconciled with no effect applied | None |
|
|
69
|
+
| reply `pending` / `delivery_unknown` | The send may or may not have landed | None. Only `reconcile` with an explicit acknowledgment |
|
|
70
|
+
| reply `delivery_failed` | Known transport failure (no ambiguity) | None. `reconcile` may resend without the acknowledgment |
|
|
71
|
+
|
|
72
|
+
A host notice (`runtime.notify`) is the same journal with no provider step: authorize `action: "notify"` → resolve the one bound pair → operation record of kind `notify` (create-only CAS on the caller `notifyId`, no cursor move) → stage the notice as `pending` → `deliver` → `delivered` / `delivery_failed` / `delivery_unknown` → `succeeded`. An unbound pair, another actor's binding, a foreign ownership scope, an ungranted/revoked identity, an unresolvable binding and capacity pressure are denied before any record exists; a repeated `notifyId` settles as a duplicate without a second delivery.
|
|
73
|
+
|
|
74
|
+
Two workers that see the same event cannot both run it: the loser's create-only CAS fails and it is acknowledged as a duplicate. A worker that loses the *binding lease* to another worker (different event, same binding) drops its own unclaimed record so the event stays retryable instead of dead-lettering silently.
|
|
75
|
+
|
|
76
|
+
## Request/response example
|
|
77
|
+
|
|
78
|
+
Nothing is replayed automatically — every entry point is an authorized call that derives ownership from a verified `AgentIdentity`:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
// What still needs attention: unresolved states, plus settled operations whose reply was never confirmed.
|
|
82
|
+
await runtime.listUnresolved({ identity, limit: 100 });
|
|
83
|
+
// → [{ operationId, connectionId, state, replyState?, version, updatedAt }]
|
|
84
|
+
|
|
85
|
+
await runtime.reconcile({
|
|
86
|
+
identity,
|
|
87
|
+
connectionId,
|
|
88
|
+
operationId,
|
|
89
|
+
expectedVersion, // from listUnresolved; a stale value is rejected
|
|
90
|
+
acknowledgeDuplicateRisk: true, // required when an effect may already have happened
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`reconcile` outcomes:
|
|
95
|
+
|
|
96
|
+
- `accepted` → `abandoned` (nothing ran; recorded as a dead-letter).
|
|
97
|
+
- `executing` → `execution_unknown`, **only** with `acknowledgeDuplicateRisk`; the model is never re-invoked.
|
|
98
|
+
- `pending` / `delivery_unknown` reply → resends the persisted text (acknowledgment required) and records `delivered` or `delivery_failed`; an ambiguous resend stays `delivery_unknown`.
|
|
99
|
+
- `delivery_failed` reply → resend without the acknowledgment, because the first attempt is known to have failed.
|
|
100
|
+
- Anything already settled → `outcome: "none"` (no second message).
|
|
101
|
+
|
|
102
|
+
Results are `resolved`, `not_found` (wrong scope or unknown id — never a foreign read), `conflict` (version mismatch or missing acknowledgment, with `detail: "duplicate_risk"`), `denied` (inactive identity) or `unavailable` (no store configured or the store failed).
|
|
103
|
+
|
|
104
|
+
There is no exactly-once claim. The journal guarantees that a recorded operation is not executed twice *by this runtime* and that a reply is never lost between the run and the send; it cannot retract a side effect the platform or a dispatched tool already accepted.
|
|
105
|
+
|
|
106
|
+
## Extension and configuration notes
|
|
107
|
+
|
|
108
|
+
### Leases and fencing
|
|
109
|
+
|
|
110
|
+
When `leases` is configured, a turn acquires a lease on its binding before the claim, renews it while work is queued on the route, passes the fencing token to journal writes, and releases it when the route goes idle or the runtime stops. If release fails, the runtime keeps its in-memory lease and retries on the next idle or stop path; it never treats the binding as free. `leaseTtlMs` remains the cross-process backstop.
|
|
111
|
+
|
|
112
|
+
The Telegram and experimental Signal adapters separately hold service-owned receiver leases. Signal uses `prism.channels.v1.signal.receiver` and writes a small readiness probe under that same service scope before `subscribeReceive`; it pauses/unsubscribes on writer or lease loss. It stores no inbound text/cursor because signal-cli manual notifications have no documented application acknowledgment or replay log.
|
|
113
|
+
|
|
114
|
+
- A lease held elsewhere defers the turn: it executes nothing and drops its unclaimed record (visible as `leaseLosses` in diagnostics).
|
|
115
|
+
- A lost or unrenewable lease fails closed: the claim is never written and the turn does not run.
|
|
116
|
+
- Fences only protect stored transitions — an already-issued network call is not retracted.
|
|
117
|
+
|
|
118
|
+
### Retention and cleanup
|
|
119
|
+
|
|
120
|
+
Retention is operator-driven; there is no background timer and no idle scan.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
await runtime.prune({ identity }); // or { identity, now: "<iso>" } for a deterministic sweep
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`prune` walks one bounded page (`maxJournalPage`) per namespace in the caller's ownership scope and deletes records whose own last-transition stamp is older than `retentionDays`, except: unresolved operations (`accepted`/`executing`), unsettled replies (`pending`/`delivery_unknown`), and bindings marked suspended. Cursor and expired/consumed control records are pruned with the rest. Repeated calls make progress; the delete count is returned as `{ scanned, deleted, retained }`.
|
|
127
|
+
|
|
128
|
+
Staged reply text is the only payload kept, bounded by `maxJournalRecordBytes` and pruned after retention — do not treat the journal as an archive.
|
|
129
|
+
|
|
130
|
+
### PostgreSQL outbox composition
|
|
131
|
+
|
|
132
|
+
A host that already runs the enterprise PostgreSQL outbox can record the reply in the same transaction as its own business mutation instead of sending from inside a model turn: `deliver` opens a caller-owned `PoolClient`, `BEGIN` → `outbox.append(client, …)` → `COMMIT`, and only then calls the adapter's `send`. The row is the durable record — an external send cannot be rolled back — so a crash between commit and send leaves the host free to re-drive delivery from the outbox (`dispatcher.claim`/`acknowledge`) rather than from the channel journal, and a repeated `deliver` for the same reply appends nothing new because `append` is idempotent on `(tenant_id, message_id)`.
|
|
133
|
+
|
|
134
|
+
The payload holds correlation ids only (`connectionId`, `eventId`, `kind`), never prompt or reply text, and the tenant comes from the resolved identity's ownership scope. Nothing in `@arnilo/prism-channels` knows about PostgreSQL: the composition lives in the host. See [the example](../examples/messaging-outbox.ts) and [Enterprise PostgreSQL state](enterprise-postgres-state.md).
|
|
135
|
+
|
|
136
|
+
### Operating a deployment
|
|
137
|
+
|
|
138
|
+
- **Startup**: construct the persistence, construct the runtime, then `listUnresolved` + `reconcile` what deserves a decision. Nothing self-heals in the background.
|
|
139
|
+
- **Shutdown**: `await runtime.stop()` aborts active runs, marks queued work cancelled (durably) and releases leases within `stopDeadlineMs`; then close the persistence.
|
|
140
|
+
- **Rolling restart**: use `leases` whenever two workers can see the same binding (webhook replicas, polling + webhook overlap), otherwise serialization is per process only.
|
|
141
|
+
- **Revocation**: a revoked identity fails before provider work and before delivery; already-accepted platform effects are not retractable.
|
|
142
|
+
- **Observability**: `runtime.diagnostics()` reports bounded counters only — including `storageFailures` (journal refused or unavailable) and `leaseLosses` (deferred or fenced out). No message text, external ids, tokens or key material is ever logged.
|
|
143
|
+
|
|
144
|
+
## Security and performance notes
|
|
145
|
+
|
|
146
|
+
All journal paths are bounded by the channel limits in [Messaging channels](messaging-channels.md): `maxJournalPage` (list page, ≤ 500), `maxJournalRecordBytes` (per-record value, checked before save), `retentionDays`, `leaseTtlMs` and the input/response caps that decide what may enter or leave the journal. Durable admission is one create and (after claim) one update plus the reply records; the plan's p95 target for durable admission is < 100 ms on a reference SSD excluding network and model time. The sqlite host suite times duplicate admission (journal CAS only) and keeps a generous CI bound of 500 ms so slow runners do not flake; treat 100 ms as the operator target, not the CI gate.
|
|
147
|
+
|
|
148
|
+
Process crash injection uses `scripts/fixtures/messaging-restart-worker.mjs`: SIGKILL leaves an `executing` record for authorized `reconcile` (never a second model/tool run). `reconcile` reuses the stored checkpoint fencing token so a crashed lease holder can still be filed as `execution_unknown` without waiting out `leaseTtlMs`. Graceful shutdown is `await runtime.stop()` (host SIGTERM handler); two sqlite connections on one file defer to the binding-lease holder.
|
|
149
|
+
|
|
150
|
+
Graceful shutdown is verified end to end, not just asserted: `scripts/fixtures/messaging-restart-worker.mjs` claims a real operation on sqlite, installs a `SIGTERM` handler that awaits `runtime.stop()`, and the claimed record lands as `cancelled` — never left `executing` — when the host's own shutdown path runs. The same worker under `SIGKILL` is the contrasting case (record stays `executing` for `reconcile`), and both are asserted in the package suite.
|
|
151
|
+
|
|
152
|
+
Soaks stay an operator decision, but the runner ships: `scripts/fixtures/messaging-soak.mjs` loops admit (including repeated event ids that must dedup) → drain → `listUnresolved`/`reconcile` → `prune` against a throwaway sqlite file and a mock provider. No network, no chat accounts, no credentials.
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
node scripts/fixtures/messaging-soak.mjs --durationMs 3000 # CI smoke (bounded, seconds)
|
|
156
|
+
node scripts/fixtures/messaging-soak.mjs --durationMs 259200000 # 72h operator soak; SIGINT/SIGTERM stops it cleanly
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
It prints one JSON summary (iterations, admissions, duplicate dedup count, deliveries, prune counts, `diagnostics()`, `unresolvedAtEnd`) and exits non-zero if a turn was denied, left unresolved or unsettled, failed, or delivered twice. The loop yields to the event loop periodically, so Ctrl-C/`SIGTERM` ends a long soak promptly instead of after the deadline, and the final sweep prunes with an aged cutoff so even a three-second run exercises deletion. For a soak against real state, keep the loop and swap sqlite for the production store; do not create contacts or accounts to soak.
|
|
160
|
+
|
|
161
|
+
## Related APIs
|
|
162
|
+
|
|
163
|
+
- [Messaging channels](messaging-channels.md) — contracts, authorization, execution semantics and limits.
|
|
164
|
+
- [Signal channel (experimental)](signal-channel.md) — manual receive, policy gate and receive-to-commit loss window.
|
|
165
|
+
- [Database persistence](database-persistence.md) and [Session stores](session-stores.md) — the checkpoint/lease contracts and the SQLite/PostgreSQL adapters.
|
|
166
|
+
- [Package README](../packages/prism-channels/README.md) — package boundary and peer-only install.
|