@arnilo/prism 0.5.6 → 0.7.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 +81 -5
- package/README.md +10 -10
- package/dist/agent-approval.js +7 -6
- package/dist/agent-definitions.js +1 -0
- package/dist/agent-loops.js +51 -12
- package/dist/agent-run-lifecycle.js +11 -0
- package/dist/agent-run-state.d.ts +6 -0
- package/dist/agent-run-state.js +29 -9
- package/dist/agent-session/session/assemble.js +33 -2
- package/dist/agent-session/session/persist.js +6 -2
- package/dist/agent-session/session/tool-round.js +1 -0
- package/dist/agent-session/session/types.d.ts +10 -0
- package/dist/agent-session/session.d.ts +15 -0
- package/dist/agent-session/session.js +59 -4
- package/dist/agent-tool-dispatch.js +5 -4
- 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/cli-init.js +20 -6
- package/dist/content.d.ts +3 -16
- package/dist/content.js +9 -99
- package/dist/context-budget.d.ts +32 -2
- package/dist/context-budget.js +51 -19
- package/dist/contracts-core/agent.d.ts +18 -0
- package/dist/contracts-core/agent.js +4 -1
- 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/provider.d.ts +4 -0
- package/dist/contracts-core.d.ts +1 -0
- package/dist/contracts-core.js +1 -0
- package/dist/contracts-protocol.d.ts +29 -0
- package/dist/contracts-run-state.d.ts +6 -0
- package/dist/host-composition.d.ts +78 -0
- package/dist/host-composition.js +248 -0
- package/dist/index.d.ts +11 -8
- package/dist/index.js +6 -5
- package/dist/input.d.ts +19 -1
- package/dist/input.js +52 -2
- package/dist/media-types.d.ts +34 -0
- package/dist/media-types.js +158 -0
- package/dist/pinned-fetch.d.ts +2 -2
- package/dist/pinned-fetch.js +11 -12
- package/dist/redaction.js +74 -1
- package/dist/secure-agent.d.ts +2 -0
- package/dist/secure-agent.js +6 -1
- package/dist/session-stores.d.ts +11 -0
- package/dist/session-stores.js +23 -8
- 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 +3 -2
- package/docs/ag-ui.md +9 -5
- package/docs/agent-definitions.md +9 -1
- package/docs/agent-events.md +6 -1
- package/docs/agent-loops.md +1 -1
- package/docs/agent-session-runtime.md +9 -7
- package/docs/attention-compiler.md +272 -0
- package/docs/browser-automation.md +5 -2
- package/docs/cli-rpc.md +4 -2
- package/docs/coding-agent-tools.md +1 -1
- package/docs/coding-security.md +5 -3
- package/docs/coding-tools.md +1 -1
- package/docs/coding-workspaces.md +22 -0
- package/docs/compaction-and-retry.md +36 -4
- package/docs/compaction-observational-memory.md +62 -9
- package/docs/context-and-skills.md +4 -2
- package/docs/contributing.md +37 -0
- package/docs/conversations.md +1 -1
- package/docs/core.md +2 -0
- package/docs/dev-inspector.md +4 -0
- package/docs/device-adapters.md +1 -0
- package/docs/document-reader.md +12 -2
- package/docs/documents.md +11 -3
- package/docs/enterprise-postgres-state.md +2 -2
- package/docs/evaluations.md +168 -4
- package/docs/execution-timeline.md +180 -0
- package/docs/graft.md +3 -1
- package/docs/history/0.7.0-primitive-review.md +254 -0
- package/docs/history/migration-0.0.md +2 -2
- package/docs/history/release-handoffs.md +70 -1
- package/docs/host-compositions.md +147 -0
- package/docs/host-security.md +2 -2
- package/docs/hosted-sandboxes.md +94 -0
- package/docs/index.md +73 -41
- package/docs/input-and-prompt-assembly.md +5 -4
- package/docs/knowledge-sync.md +84 -0
- package/docs/language-intelligence.md +2 -2
- package/docs/live-testing.md +4 -1
- package/docs/mcp-tools.md +2 -1
- package/docs/memory-fabric.md +416 -0
- package/docs/migrate-to-0.5.md +8 -3
- package/docs/migrate-to-0.6.md +90 -0
- package/docs/migrate-to-0.7.md +345 -0
- package/docs/migration.md +43 -1
- package/docs/model-registry.md +1 -1
- package/docs/model-routing.md +79 -4
- package/docs/multi-agent-patterns.md +20 -6
- package/docs/multimodal-content.md +1 -1
- package/docs/obscura.md +3 -1
- package/docs/observability.md +52 -1
- package/docs/operations.md +13 -1
- package/docs/options-index.md +298 -0
- package/docs/peer-dependencies.md +96 -0
- package/docs/performance.md +34 -2
- package/docs/ponytail.md +2 -0
- package/docs/postgres-persistence.md +3 -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 +2 -2
- package/docs/provider-packages.md +23 -23
- package/docs/provider-primitives.md +2 -1
- package/docs/providers/ai-sdk.md +5 -2
- package/docs/providers/bedrock.md +71 -7
- package/docs/providers/openai.md +1 -1
- package/docs/public-contracts.md +2 -2
- package/docs/rag.md +24 -8
- package/docs/realtime-voice.md +87 -0
- package/docs/release-and-install.md +78 -56
- package/docs/runs-and-usage.md +3 -2
- package/docs/server.md +6 -4
- package/docs/session-stores.md +3 -1
- package/docs/speech.md +2 -0
- package/docs/sqlite-persistence.md +2 -0
- package/docs/supervisors.md +33 -5
- package/docs/testing.md +38 -0
- package/docs/thinking-and-reasoning.md +3 -1
- package/docs/tools.md +7 -6
- 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 +3 -1
- package/docs/work-tools.md +14 -4
- package/docs/workflows.md +69 -1
- package/docs/working-and-semantic-memory.md +25 -14
- package/package.json +5 -5
- 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 +11 -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
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
`@arnilo/prism-memory/compaction/observational-memory` is an optional subpath for source-backed observational memory and fast compaction.
|
|
6
6
|
|
|
7
|
-
Current status: ledger/projection/render/recall utilities, explicit worker runtime, fast compaction strategy, inert extension helper, recall tool, and status/view command factories are available.
|
|
7
|
+
Current status: ledger/projection/render/recall utilities, optional work-scope indexing, explicit worker runtime, fast compaction strategy, inert extension helper, recall tool, and status/view command factories are available.
|
|
8
8
|
|
|
9
9
|
This package is distinct from `@arnilo/prism-memory` working/semantic memory: observational memory compresses and recalls source-backed observations/reflections; semantic memory retrieves embeddings; working memory stores the current structured profile/state. Hosts may compose both.
|
|
10
10
|
|
|
11
|
+
This page's memory stays **episodic**: the ledger records what happened in a session, its observer/reflector/dropper workers are the only writers of observations and reflections, and nothing downstream re-observes the transcript. Typed notes that want to outlive the session (facts, procedures, file references) are a separate layer — the [memory fabric](memory-fabric.md) — which views an observation by id as an `episode` note without copying it, never wraps or replaces these workers, and keeps its own recall path. Promotion out of the ledger is an explicit host write, not a side effect of compaction.
|
|
12
|
+
|
|
11
13
|
## Four-layer provider context
|
|
12
14
|
|
|
13
15
|
Observational memory composes four independent layers for long sessions (Mastra-style):
|
|
@@ -19,7 +21,9 @@ Observational memory composes four independent layers for long sessions (Mastra-
|
|
|
19
21
|
| **Reflections** | Higher-level summaries over observation ids | Reflector worker on observations after last reflection coverage when `reflection.observationTokens` met |
|
|
20
22
|
| **Raw-source retrieval** | Exact branch messages behind a memory id or cursor page | `recallObservationalMemory()` / `recallObservationalMemoryBranchPage()` / `createRecallMemoryTool()` — exact-id or cursor paging only; no semantic search |
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
The opt-in work-scope index filters the observation and reflection layers for a host-selected working set. It is not a fifth context layer, retrieval system, or session scope.
|
|
25
|
+
|
|
26
|
+
Activation is explicit: `createObservationalMemory().attach()` coordinates post-run observe/reflect/drop and compaction — by default `context.compactAfterTokens`, or whatever host gate `trigger` / `shouldCompact` supplies. Import and extension `setup` start nothing. Recall, commands, and utilities fail closed on invalid ids, wrong `sessionId`, ambiguous tool input, or oversized pages. Pass `secrets` for exact-value redaction in render/recall/worker paths. Branch isolation: hosts supply current-branch `appendEntry` and `getEntries`; mismatched store/session pairs fail closed after append.
|
|
23
27
|
|
|
24
28
|
See `examples/observational-memory-lifecycle.ts` for attach → turn → projection/recall/page without live credentials.
|
|
25
29
|
|
|
@@ -31,6 +35,8 @@ Use `createObservationalMemoryCompactionStrategy()` when compaction should rende
|
|
|
31
35
|
|
|
32
36
|
## Inputs / request
|
|
33
37
|
|
|
38
|
+
**Option surfaces** — `appendEntry` takes `ObservationalMemoryAppendOptions` (custom observation/reflection text, trust, and metadata); `createWorkScopeController` takes `WorkScopeControllerOptions` (session, `appendEntry`, optional `secrets`).
|
|
39
|
+
|
|
34
40
|
Memory records use `SessionEntry.kind: "custom"` with `entry.data.type` markers:
|
|
35
41
|
|
|
36
42
|
| Type | Payload |
|
|
@@ -38,6 +44,9 @@ Memory records use `SessionEntry.kind: "custom"` with `entry.data.type` markers:
|
|
|
38
44
|
| `om.observations.recorded` | `{ observations, coversUpToId? }` — successful observer runs append coverage even when `observations` is empty. |
|
|
39
45
|
| `om.reflections.recorded` | `{ reflections, coversUpToId? }` |
|
|
40
46
|
| `om.observations.dropped` | `{ observationIds, coversUpToId? }` |
|
|
47
|
+
| `om.scope.opened` | `{ id, parentId?, kind?, label? }` — host-defined scope tree node. |
|
|
48
|
+
| `om.scope.closed` / `om.scope.entered` / `om.scope.left` | `{ scopeId }` for close/enter; `{}` for leave. |
|
|
49
|
+
| `om.scope.bound` / `om.scope.unbound` | `{ scopeId, refs }` — many-to-many `om:<12-hex>` or `reflection:<12-hex>` membership. |
|
|
41
50
|
| `om.folded` | Compaction `data.memory` folded details. |
|
|
42
51
|
|
|
43
52
|
Ids are known, source-backed 12-character lowercase hex strings matching `^[a-f0-9]{12}$`.
|
|
@@ -67,18 +76,21 @@ Key exports:
|
|
|
67
76
|
| Export | Purpose |
|
|
68
77
|
| --- | --- |
|
|
69
78
|
| `foldObservationalMemoryLedger()` | Fold custom memory entries into observations, reflections, drops, and coverage markers. |
|
|
79
|
+
| `foldWorkScopeMap()` / `createWorkScopeController()` | Fold the opt-in scope index or append validated open/close/enter/leave/bind/unbind entries. |
|
|
80
|
+
| `projectWorkMemory()` | Filter the folded observations/reflections through a scope query; exact-id recall stays unfiltered. |
|
|
81
|
+
| `withWorkScope()` | Open a missing scope, enter it for an async callback, and always leave without closing it. |
|
|
70
82
|
| `isEligibleObservationSourceEntry()` / `eligibleObservationSources()` | Select user/assistant/tool `message` entries for observer input. |
|
|
71
83
|
| `unscannedEntries()` / `observationsUncoveredByReflection()` | Dual coverage helpers for observation scan and reflection windows. |
|
|
72
|
-
| `buildObservationalMemoryProjection()` | Build active/full/folded projections from current branch entries. |
|
|
73
|
-
| `buildObservationalMemoryContextBlocks()` | Render observational-memory + recent-messages context blocks for provider input. |
|
|
84
|
+
| `buildObservationalMemoryProjection()` | Build active/full/folded projections from current branch entries. Optional `invalidatedIds` drops observations whose id or `sourceEntryIds` match, and reflections that rest on them. Full ledger stays for audit. |
|
|
85
|
+
| `buildObservationalMemoryContextBlocks()` | Render observational-memory + recent-messages context blocks for provider input. Same `invalidatedIds` option. |
|
|
74
86
|
| `selectRecentMessageEntries()` / `renderRecentMessageWindow()` | Bounded exact recent-message suffix; count via `keepRecentEntries`, optional token trim via `estimateEntryTokens`. |
|
|
75
87
|
| `createFoldedMemoryDetails()` | Create JSON details for compaction `data.memory`. |
|
|
76
88
|
| `renderObservationalMemory()` | Render reflections and observations into a prepared memory summary. |
|
|
77
|
-
| `recallObservationalMemory()` | Recover source evidence for a known observation/reflection id from supplied current-branch entries. |
|
|
89
|
+
| `recallObservationalMemory()` | Recover source evidence for a known observation/reflection id from supplied current-branch entries. `invalidatedIds` withholds content (`reason: "revoked"`) without injecting derived text. |
|
|
78
90
|
| `recallObservationalMemoryBranchPage()` | Page eligible user/assistant/tool messages around a cursor entry id (`forward`/`backward`, optional `detail: summary|full`). |
|
|
79
91
|
| `createMemoryId()` / `isMemoryId()` | Create/check 12-character ids. |
|
|
80
92
|
| `resolveObservationalMemorySettings()` | Merge `observational-memory` settings with defaults and overrides. |
|
|
81
|
-
| `createObservationalMemory()` / `attach()` | One activation wires post-run observe/reflect/drop and `compactAfterTokens`
|
|
93
|
+
| `createObservationalMemory()` / `attach()` | One activation wires post-run observe/reflect/drop and compaction (`compactAfterTokens`, or a host `trigger` / `shouldCompact`); returns proxied session, runtime, context provider, and strategy. |
|
|
82
94
|
| `createObservationalMemoryRuntime()` | Low-level explicit flush for advanced hosts or tests. |
|
|
83
95
|
| `createObservationalMemoryCompactionStrategy()` | Render existing folded memory as a standard Prism compaction summary with `data.memory`. |
|
|
84
96
|
| `createObservationalMemoryExtension()` | Inert extension helper that registers the strategy contribution unless disabled. |
|
|
@@ -86,7 +98,32 @@ Key exports:
|
|
|
86
98
|
| `createMemoryStatusCommand()` / `createMemoryViewCommand()` | Optional `om:status` and `om:view` command factories. |
|
|
87
99
|
| `createObservationalMemoryCommands()` | Convenience factory returning status and view commands. |
|
|
88
100
|
|
|
89
|
-
Pure utilities create no events, workers, tools, commands, credentials, or provider requests. `createObservationalMemoryExtension()` and import alone start nothing. `createObservationalMemory().attach()` runs workers only after proxied `run`/`prompt`/`stream`/`compact` complete (or after `wrapResumeRun` / `wrapResumeStream`). `createObservationalMemoryRuntime().flush()` remains for manual/advanced use. Attached `contextProvider` renders two blocks each turn: `observational-memory` (active reflections/observations aligned to the recent-message boundary) and `recent-messages` (last `keepRecentEntries` message entries in branch order, optionally trimmed by `recentMessageMaxTokens` using `estimateEntryTokens`; oldest dropped first). Compaction uses the same `keepRecentEntries` setting. Observer input includes only eligible `message` entries (`user`, `assistant`, `tool`); memory/compaction/bookkeeping entries advance `coversUpToId` scan coverage without entering the observer prompt. Successful observer/reflector runs append coverage markers even when they record zero facts. Reflection uses only active observations recorded after the last `om.reflections.recorded` entry unless `flush({ fullReflectionRebuild: true })`. Attached `flush()` skips with `run_active` while a proxied run is in flight. The compaction strategy is O(n) over supplied entries and makes no provider call.
|
|
101
|
+
Pure utilities create no events, workers, tools, commands, credentials, or provider requests. `createObservationalMemoryExtension()` and import alone start nothing. `createObservationalMemory().attach()` runs workers only after proxied `run`/`prompt`/`stream`/`compact` complete (or after `wrapResumeRun` / `wrapResumeStream`). `createObservationalMemoryRuntime().flush()` remains for manual/advanced use. Attached `contextProvider` renders two blocks each turn: `observational-memory` (active reflections/observations aligned to the recent-message boundary) and `recent-messages` (last `keepRecentEntries` message entries in branch order, optionally trimmed by `recentMessageMaxTokens` using `estimateEntryTokens`; oldest dropped first). Compaction uses the same `keepRecentEntries` setting. Observer input includes only eligible `message` entries (`user`, `assistant`, `tool`); memory/compaction/bookkeeping entries advance `coversUpToId` scan coverage without entering the observer prompt. Successful observer/reflector runs append coverage markers even when they record zero facts. Reflection uses only active observations recorded after the last `om.reflections.recorded` entry unless `flush({ fullReflectionRebuild: true })`. Attached `flush()` skips with `run_active` while a proxied run is in flight. The compaction strategy is O(n) over supplied entries and makes no provider call.
|
|
102
|
+
|
|
103
|
+
### Work-scope index (opt-in)
|
|
104
|
+
|
|
105
|
+
`WorkScope` is a host-named, append-only index over one observational-memory ledger. Without `om.scope.*` entries, the map has only its implicit `session` root, context renders the existing active pool, and the dropper keeps its existing behavior.
|
|
106
|
+
|
|
107
|
+
Use `createWorkScopeController({ session, appendEntry, secrets? })` to `open`, `close`, `enter`, `leave`, `bind`, or `unbind` scopes. Scope ids are host-defined (`[A-Za-z0-9._:/-]{1,128}`, no `..`); there are caps of 256 scopes, depth/stack 8, 4,096 binds per scope, and 512 characters for labels or kinds. Invalid ids, missing/closed parents, duplicate scopes, unknown record ids, and ownership mismatch fail closed. Labels and kinds receive the same secret redaction as observational-memory text.
|
|
108
|
+
|
|
109
|
+
`projectWorkMemory(ledger, map, { from, include, closed?, kinds? })` returns a filtered observation/reflection view plus outline. `include` is `self`, `self+ancestors`, `self+descendants`, or `lineage`; `closed: "hide"` is the default, except closed ancestors of `from` remain available. Default attached context uses the current leaf with `self+ancestors`, rendering Scope Outline, Reflections, then Observations. The compaction summary — the layer the next run's pack starts from — renders the same projection, so the full ledger never rides into the prefix; the folded payload keeps every observation, so entering another scope can still surface what that summary hid. `recallObservationalMemory()` still reads the complete current branch by exact id.
|
|
110
|
+
|
|
111
|
+
After a flush records new observations or reflections, it binds those ids once to the current leaf scope only. A host promotes relevant memory explicitly by binding it to an ancestor; a reflection whose bind sits on a **closed** scope can also graduate into durable semantic memory through the fabric's `remember({ kind: "fact" | "procedure", reflectionId })`. While any host scope exists, the runtime skips the observation dropper; the folded-payload byte cap remains a storage safety cap, not working-set garbage collection. `withWorkScope(controller, spec, fn)` opens `spec` if needed, enters it, runs `fn`, and leaves in `finally`; it never closes a scope. This index does not provide resource-scoped observational memory or budget-based dropping as a working-set mechanism.
|
|
112
|
+
|
|
113
|
+
### Compact-when override
|
|
114
|
+
|
|
115
|
+
`createObservationalMemory()` accepts a compact-when gate beside the settings: `trigger` (the same union `CompactionOptions.trigger` uses) or the `shouldCompact(context)` shorthand. When either is set it **replaces** `context.compactAfterTokens`; omitted, the token gate is unchanged.
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
const om = createObservationalMemory({
|
|
119
|
+
observation: { provider, model },
|
|
120
|
+
shouldCompact: (context) => context.entryCount > 40 || context.estimatedInputTokens / context.inputCapTokens >= 0.9,
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
- `context.entryCount` counts current-branch entries; `context.estimatedInputTokens` is this package's own `estimateEntryTokens` sum; `context.inputCapTokens` comes from `resolveInputCap` on `attach({ sessionModel })`.
|
|
125
|
+
- Both token numbers resolve lazily, so a callback that only reads counts works with a `sessionModel` that declares no `contextWindow`. Reading the cap without one throws inside the callback, and the gate then decides **false** — the sync loop reports it through the `debug` sink (`observational-memory:compaction-trigger-error`) and never compacts on a guess. `input_ratio` needs a resolvable cap and throws instead.
|
|
126
|
+
- An unknown trigger `type` or a non-function `shouldCompact` throws at `createObservationalMemory()`, before any session work. Tool and command factories are inert until a host registers/selects them.
|
|
90
127
|
|
|
91
128
|
## Request/response example
|
|
92
129
|
|
|
@@ -105,8 +142,13 @@ import {
|
|
|
105
142
|
createObservationalMemoryCommands,
|
|
106
143
|
createObservationalMemoryRuntime,
|
|
107
144
|
createRecallMemoryTool,
|
|
145
|
+
createWorkScopeController,
|
|
146
|
+
foldObservationalMemoryLedger,
|
|
147
|
+
foldWorkScopeMap,
|
|
148
|
+
projectWorkMemory,
|
|
108
149
|
recallObservationalMemory,
|
|
109
150
|
renderObservationalMemory,
|
|
151
|
+
withWorkScope,
|
|
110
152
|
} from "@arnilo/prism-memory/compaction/observational-memory";
|
|
111
153
|
|
|
112
154
|
const om = createObservationalMemory({
|
|
@@ -119,11 +161,19 @@ const attached = om.attach(session, {
|
|
|
119
161
|
appendEntry: (entry, options) => store.append(entry, options),
|
|
120
162
|
sessionModel: agent.config.model,
|
|
121
163
|
});
|
|
122
|
-
|
|
164
|
+
const scopes = createWorkScopeController({ session: attached.session, appendEntry: (entry, options) => store.append(entry, options) });
|
|
165
|
+
await scopes.open({ id: "plan:memory", kind: "plan", label: "Memory work" });
|
|
166
|
+
await withWorkScope(scopes, { id: "task:cleanup", parentId: "plan:memory", kind: "task" }, () =>
|
|
167
|
+
attached.session.run("Continue from prior work"),
|
|
168
|
+
);
|
|
123
169
|
|
|
124
170
|
const entries = await session.entries();
|
|
125
171
|
const projection = buildObservationalMemoryProjection(entries);
|
|
126
|
-
const
|
|
172
|
+
const scoped = projectWorkMemory(foldObservationalMemoryLedger(entries), foldWorkScopeMap(entries), {
|
|
173
|
+
from: "task:cleanup",
|
|
174
|
+
include: "self+ancestors",
|
|
175
|
+
});
|
|
176
|
+
const summary = renderObservationalMemory(scoped.reflections, scoped.observations, { outline: scoped.outline });
|
|
127
177
|
const evidence = recallObservationalMemory(entries, "aaaaaaaaaaaa");
|
|
128
178
|
|
|
129
179
|
const memory = createObservationalMemoryRuntime({
|
|
@@ -231,11 +281,14 @@ Ownership: funnel only within the `OwnershipScope` already on the parent agent/s
|
|
|
231
281
|
## Related APIs
|
|
232
282
|
|
|
233
283
|
- [Use-case model selection](use-case-model-selection.md): session vs worker model binding and `resolveUseCaseModel`.
|
|
284
|
+
- [Attention compiler](attention-compiler.md): opt-in per-turn shrink that runs before compaction is considered and resolves the same input cap for `input_ratio` triggers.
|
|
234
285
|
- [Thinking and reasoning](thinking-and-reasoning.md): `thinkingLevel` → provider `compat`.
|
|
235
286
|
- [Provider request policies](provider-request-policies.md): derived `om:{session.id}` on worker generate.
|
|
236
287
|
- [Compaction and retry policies](compaction-and-retry.md): replaceable compaction strategy boundary.
|
|
288
|
+
- [Workflows](workflows.md): a host may use a workflow `nodeId` as a scope id with `withWorkScope`; the workflow runner does not enter scopes itself.
|
|
237
289
|
- [LLM compaction package](compaction-llm.md): existing optional compaction-package pattern.
|
|
238
290
|
- [Session stores and branching](session-stores-and-branching.md): branch entries that observational memory reads and appends to.
|
|
291
|
+
- [Memory fabric](memory-fabric.md): optional typed notes over the same stores; `episode` notes are views of these observation ids, and the ledger stays episodic.
|
|
239
292
|
- [Supervisor delegation](supervisors.md): child sessions whose messages this page's opt-in funnel can copy onto a workspace branch.
|
|
240
293
|
- [Extensions](extensions.md): inert registration pattern for optional package contributions.
|
|
241
294
|
- [Tools](tools.md): host activation and dispatch for optional recall tool contributions.
|
|
@@ -128,7 +128,7 @@ Each active skill contributes two things the runtime wires together:
|
|
|
128
128
|
- `Skill` prompt text → rendered as system messages by `skillMessages()` / `skillPromptText()` (active set only). Default `skillsDisclosure: "progressive"` sends `Skill <name>: <description>`; full `instructions` appear only when the skill is in the session `LoadedSkillSet` or disclosure is `"eager"`.
|
|
129
129
|
- `Skill.context: ContextProvider[]` → collected across active skills (`activeSkills.flatMap(s => s.context ?? [])`), resolved through the existing `resolveContextProviders(...)`, and merged into the request's `context` **after** host `AgentConfig.context` blocks. Inactive skills contribute neither instructions nor context.
|
|
130
130
|
|
|
131
|
-
`toolNames` enforcement is live: because selection routes through `resolveActiveSkills()`, a skill demanding a host-inactive tool throws with `Skill ${name} requires inactive tool: ${missing}` **before the first provider turn** — no provider call, no store write, no partial side effect.
|
|
131
|
+
`toolNames` enforcement is live: because selection routes through `resolveActiveSkills()`, a skill demanding a host-inactive tool throws with `Skill ${name} requires inactive tool: ${missing}` **before the first provider turn** — no provider call, no store write, no partial side effect. When `RunOptions.toolNames` narrows the run, that snapshot is the host-active list — a skill cannot require a registered tool the run did not grant.
|
|
132
132
|
|
|
133
133
|
```ts
|
|
134
134
|
import { createAgent, createSkillRegistry, type ContextProvider } from "@arnilo/prism";
|
|
@@ -219,7 +219,7 @@ Under pressure on a skill with a loaded body, eviction may demote to catalog-onl
|
|
|
219
219
|
|
|
220
220
|
### Optional tool-result fold
|
|
221
221
|
|
|
222
|
-
`toolResultFold` on `AgentConfig` / `RunOptions` (run wins) is **off** unless the host supplies a `summarize` callback. When enabled, aged large tool-result messages in the **provider view** become a one-line header plus bounded summary text; session store entries stay raw. Defaults: `minAgeTurns` **2**, `minBytes` **4096**, `maxSummaryBytes` **512** (hard **4096**). Summarizer failure keeps the raw tool result (fail closed). Not a second memory system — use observational memory / compaction for durable recall.
|
|
222
|
+
`toolResultFold` on `AgentConfig` / `RunOptions` (run wins) is **off** unless the host supplies a `summarize` callback. When enabled, aged large tool-result messages in the **provider view** become a one-line header plus bounded summary text; session store entries stay raw. Defaults: `minAgeTurns` **2**, `minBytes` **4096**, `maxSummaryBytes` **512** (hard **4096**). Summarizer failure keeps the raw tool result (fail closed). Not a second memory system — use observational memory / compaction for durable recall, and remember that observational memory stays the source-backed **episodic** ledger of the session: typed, time-bounded notes that outlive a session are a separate layer ([memory fabric](memory-fabric.md)) whose provider arrives through this same inert seam.
|
|
223
223
|
|
|
224
224
|
```ts
|
|
225
225
|
await session.run("…", {
|
|
@@ -267,8 +267,10 @@ Use `activateAllCapabilities: true` only as a temporary all-skills/all-tools com
|
|
|
267
267
|
|
|
268
268
|
- [Agent/session runtime](agent-session-runtime.md): consumes host-selected context providers and skills from explicit agent config.
|
|
269
269
|
- [Input and prompt assembly](input-and-prompt-assembly.md): default prompt builder and provider-input assembly helper.
|
|
270
|
+
- [Attention compiler](attention-compiler.md): opt-in ratio gate that rewrites aged history and tool results for one request, leaving resolved context blocks and skills in place.
|
|
270
271
|
- [Instruction injection](instruction-injection.md): package injectors contribute `contextBlocks` that merge after host+skill provider blocks.
|
|
271
272
|
- [Retrieval-augmented generation](rag.md): optional retrieved citations contribute through the same explicit inert context seam.
|
|
273
|
+
- [Memory fabric](memory-fabric.md): optional typed notes whose provider contributes the same `working-memory` / `semantic-memory` blocks this seam already carries, under a host-registered name.
|
|
272
274
|
- [Public contracts](public-contracts.md): `ContextProvider`, `ContextResolutionContext`, `ContextBlock`, `Skill`, `SkillRegistry`, `PromptBuilder`, and `PromptBuildRequest`.
|
|
273
275
|
- [Middleware hooks](middleware-hooks.md): `context` and `prompt_build` hooks.
|
|
274
276
|
- [Contribution registries](contribution-registries.md): inert context provider and skill contributions.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Contribution quality budgets
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
Records the code-quality ceilings a change must not raise, and the procedure for lowering them. Three budgets exist today: the non-null assertion allowance per directory, the public export surface per package, and the benchmark/timing envelopes. All live in `scripts/budgets.json` and are enforced by in-chain gates that run as part of `npm test`.
|
|
6
|
+
|
|
7
|
+
## When to use it
|
|
8
|
+
|
|
9
|
+
Before a change that adds a `!` non-null assertion, adds a public export, or moves code between directories; and after any sweep that removes them — the recorded numbers are lowered in the same change, never later.
|
|
10
|
+
|
|
11
|
+
## Non-null assertions
|
|
12
|
+
|
|
13
|
+
`style/noNonNullAssertion` is an **error** repo-wide in `biome.json`. Directories that still carry legacy sites are switched back to `off` per directory through `overrides`, and `scripts/budgets.json` → `nonNullAssertions` records how many sites remain in each of them.
|
|
14
|
+
|
|
15
|
+
Rules:
|
|
16
|
+
|
|
17
|
+
- New code does not add `!`. Narrow the value once — a local `const` behind an explicit guard — or capture the seam in a helper (the durable-session and elicitation seams are the models). Do not trade the assertion for an `as` cast or a `??` placeholder.
|
|
18
|
+
- Keep the allowlist and the budget rows identical: the gate asserts that the `biome.json` allowlist directories and the `nonNullAssertions.byPath` keys describe the same set, so there is no ambiguity about which row an override corresponds to.
|
|
19
|
+
- A sweep lowers the directory's `byPath` number and the `ceiling` in the same change. Raising a number needs a reason in the `$comment`.
|
|
20
|
+
- When a directory reaches zero sites, delete its `overrides` entry and its `byPath` row: the gate fails on a stale zero row rather than letting the allowance rot.
|
|
21
|
+
- The clusters swept in that pass — `src/agent-approval.ts`, `src/agent-loops.ts`, `src/agent-tool-dispatch.ts`, `packages/prism-coding-tools/src/agent/{glob-match,delete,git*}.ts`, `packages/prism-coding-tools/src/agent/language/framing.ts`, and `packages/prism-coding-tools/src/security/{sandbox-tar,sandbox-fs-operations}.ts` — are re-enabled as errors by the last override in `biome.json` (the last matching override wins), so they cannot regress. The gate rejects a rename that would silently drop that enforcement.
|
|
22
|
+
- Measure locally with one pass: `node_modules/.bin/biome lint --only=style/noNonNullAssertion --reporter=json .`. `--only` reports the rule inside allowlisted directories too, which is what makes the counting gate possible; the gate also fails when a site appears outside the allowlist.
|
|
23
|
+
|
|
24
|
+
## Public export surface
|
|
25
|
+
|
|
26
|
+
`scripts/budgets.json` → `exportCounts` records a ceiling per package. Growth fails the gate and names the package and the exact delta. Prefer re-exporting an existing symbol (or documenting the host-side composition) over widening a package's surface; moving an existing internal helper between modules does not change the count, because the counter dedupes by name.
|
|
27
|
+
|
|
28
|
+
## Timing envelopes
|
|
29
|
+
|
|
30
|
+
Benchmark medians and p95 ceilings in `scripts/budgets.json` are non-flaky sanity bounds, not portable SLOs; the startup gate additionally compares a machine-relative ratio so external CPU load cannot fail the suite. `scripts/benchmark.mjs` produces the evidence-of-record numbers.
|
|
31
|
+
|
|
32
|
+
## Related APIs
|
|
33
|
+
|
|
34
|
+
- `scripts/budget-gates.mjs`: `measureNonNullAssertions()`, `evaluateNonNullBudget()`, `measureExportCounts()`, `checkExportBudget()`, and the startup helpers.
|
|
35
|
+
- `scripts/budget-gate.test.mjs`: the in-chain gate, including the negative fixtures that prove each failure mode.
|
|
36
|
+
- `scripts/run-all-tests.mjs`: the stages `npm test` runs (`gate suites` includes the budget gate).
|
|
37
|
+
- [Release and install](release-and-install.md): the release gates that re-assert these budgets before publication.
|
package/docs/conversations.md
CHANGED
|
@@ -117,7 +117,7 @@ Behavior notes:
|
|
|
117
117
|
- `create` with an explicit `id` writes with `expectedVersion: 0` (create-only): a duplicate create never overwrites the winner's metadata and returns the existing thread.
|
|
118
118
|
- `branch()` enforces `maxActiveBranches` on its read snapshot; the version guard inside the same write makes the cap exact even under concurrency (a concurrent branch cannot slip past the cap), and the marker keeps branch refs append-only.
|
|
119
119
|
- `archive()` on an already-archived thread is a no-op; a stale `branch`/`archive` racing a delete fails `not_found` (the row is gone) and the write path never re-creates a deleted thread — delete wins.
|
|
120
|
-
- Deletion purges the whole session ledger (entries, runs, events, tool calls, usage, branches, search rows) through `lifecycle.applyRetention`; legal holds block deletion and report `held: true`.
|
|
120
|
+
- Deletion purges the whole session ledger (entries, runs, events, tool calls, usage, branches, search rows) through `lifecycle.applyRetention`; legal holds block deletion and report `held: true`. Semantic-memory `forget({ hold: true })` is a separate knowledge-store hold (see [Working and semantic memory](working-and-semantic-memory.md)); conversation delete does not walk embeddings.
|
|
121
121
|
|
|
122
122
|
## Security and performance notes
|
|
123
123
|
|
package/docs/core.md
CHANGED
|
@@ -21,6 +21,8 @@ npm install pg
|
|
|
21
21
|
npm install @nats-io/jetstream @nats-io/transport-node
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
Every peer below is optional and fails closed at first use; the [optional peer dependencies](peer-dependencies.md) matrix lists the exact ranges, pins, and which of them reach the network.
|
|
25
|
+
|
|
24
26
|
## Subpaths Map
|
|
25
27
|
|
|
26
28
|
| Subpath | Description | Optional Peers |
|
package/docs/dev-inspector.md
CHANGED
|
@@ -57,6 +57,9 @@ Data-defined route table over the server seam — each route either rewrites the
|
|
|
57
57
|
| `GET /events?runId=<id>` | Durable SSE stream of normalized events. `Last-Event-ID` header reconnect and `?cursor=` are honored by the server seam; missing `runId` → `400 ERR_PRISM_DEV_ROUTE`. |
|
|
58
58
|
| `GET /runs/:id/replay?cursor=…` | Paged replay of a stored run from the durable `AgentEventSource` — **no session, no provider, no re-execution** (`createPrismAgentEventReplay` page). Returns `{ items, nextCursor?, terminal }`; unknown/foreign run ids → `404`. |
|
|
59
59
|
| `POST /runs/:runId/decisions/:decisionId` | Resumes/denies one suspended approval. Body `{ outcome: "allow_once" \| "allow_always" \| "deny", expectedVersion? }` → forwarded as a single-entry core decision batch; unknown discriminants and stale versions fail closed (`400`) at the core boundary **before any state write**. |
|
|
60
|
+
| `GET /inspect` | Returns the host composition report (`HostCompositionReport`) detailing profile, effective tools, redacted credentials, ownership, storage durability, sandbox capabilities, and governance coverage. | dev composition inspection (`inspectDevInspector`). |
|
|
61
|
+
| `GET /runs/:id/summary` | Projects durable replay events with `projectAgentTimeline({ content: "metadata" })` and returns `summarizeTimeline` (latency, cost, tool counts). No step I/O. Requires `eventSource`. Unknown run → `404`. |
|
|
62
|
+
| `POST /compare` | Body `{ left, right }` each `{ summary, aggregate?, manifest? }` — existing TimelineSummary / ExperimentAggregate fields only. Returns quality/cost/latency winners. `invariantsPassed: false` on either side sets `qualityWinner: "invariant_blocked"`. Bounded 64KiB. |
|
|
60
63
|
|
|
61
64
|
Reconnect semantics: every SSE frame carries `id: <cursor>`; a reconnecting client sends `Last-Event-ID: <cursor>` and receives exactly the post-cursor events — no duplicates, no loss (server conformance-tested). Replay pages are bounded by the deployment limits (`maxReplayEvents`, `maxReplayCursorBytes`) and ownership-scoped by the source seam itself.
|
|
62
65
|
|
|
@@ -71,6 +74,7 @@ Panels:
|
|
|
71
74
|
- **Usage** — per-run totals summed from `provider_turn_finished.usage` and the terminal `agent_finished.usage` (input/output/total tokens, cost when the model reports it).
|
|
72
75
|
- **Decisions** — `agent_suspended` renders one card per pending decision (`PendingDecision.approvalId`, tool name, redacted reason, `expectedVersion` from the event's run version). Buttons post `POST /runs/:runId/decisions/:approvalId` ({ outcome: `allow_once` | `allow_always` | `deny`, expectedVersion }); rejections show the seam's fail-closed error verbatim, and a remaining-multi-decision suspension re-renders from the response's `runState.interruption`.
|
|
73
76
|
- **Run selector** — session runs (live + loaded) with status; a durable view of any past run loads via `GET {basePath}/events?runId=…` over `EventSource` — the seam's own `Last-Event-ID` reconnect applies. Without a durable event source wired, loading by runId surfaces that fact instead of pretending to replay.
|
|
77
|
+
- **Compare** — `Compare last 2` loads `/runs/:id/summary` for the two most recent runs and `POST /compare`. Renders quality/cost/latency winners from those artifacts. A high mean score cannot beat a failed invariant. Without durable events the panel says so instead of inventing numbers.
|
|
74
78
|
|
|
75
79
|
## Request/response example
|
|
76
80
|
|
package/docs/device-adapters.md
CHANGED
|
@@ -91,6 +91,7 @@ if (chunk.accepted) emit(redactDeviceTelemetry(createSecretRedactor([token]), fr
|
|
|
91
91
|
## Related APIs
|
|
92
92
|
|
|
93
93
|
- [Browser automation](browser-automation.md): verified-state checkpoints + reload/verify-before-side-effect for browser composition.
|
|
94
|
+
- [Realtime voice](realtime-voice.md): governed OpenAI Realtime orchestration on this admission contract.
|
|
94
95
|
- [Linux desktop control](computer-use-linux.md): first-party host-owned `computer-use-linux` MCP wrapper using this contract.
|
|
95
96
|
- [Conversations](conversations.md): durable threads that own the runs device sessions bind to.
|
|
96
97
|
- [Host security](host-security.md): approval, sandbox, and egress trust boundaries device adapters compose over.
|
package/docs/document-reader.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Document reader (`@arnilo/prism-coding-tools/document-reader`)
|
|
2
2
|
|
|
3
|
+
> **Optional peer install:** `pdf-parse` and/or `mammoth` — see [Optional peer dependencies](peer-dependencies.md). OCR uses **native fetch**, not an SDK peer.
|
|
4
|
+
|
|
3
5
|
## What it does
|
|
4
6
|
|
|
5
|
-
Optional bounded literal-text extraction for PDF and DOCX files, consumed by the coding `read` tool (plan 018 closeout `doc-reader`, 0.1.6). `createDocumentReader()` returns a `DocumentReader` that the host wires into `createReadTool(cwd, { documentReader })`; the read tool then extracts text from supported documents instead of falling back to the raw text page.
|
|
7
|
+
Optional bounded literal-text extraction for PDF and DOCX files, consumed by the coding `read` tool (plan 018 closeout `doc-reader`, 0.1.6). `createDocumentReader()` returns a `DocumentReader` that the host wires into `createReadTool(cwd, { documentReader })`; the read tool then extracts text from supported documents instead of falling back to the raw text page. Scanned PDFs/images need a **host-selected** `createMistralOcrParser({ apiKey })` passed in `parsers` — default wiring never calls an external OCR service.
|
|
6
8
|
|
|
7
9
|
## When to use it
|
|
8
10
|
|
|
@@ -61,18 +63,26 @@ const myPdfParser: DocumentParser = {
|
|
|
61
63
|
},
|
|
62
64
|
};
|
|
63
65
|
const reader = await createDocumentReader({ parsers: [myPdfParser, await createPdfParser()] });
|
|
66
|
+
|
|
67
|
+
import { createMistralOcrParser } from "@arnilo/prism-coding-tools/document-reader";
|
|
68
|
+
const ocr = createMistralOcrParser({
|
|
69
|
+
apiKey: hostKey, // never read from process.env
|
|
70
|
+
recordUsage: (u) => router.recordUsage({ /* Task 7 */ tokens: 0, costUsd: hostPrice(u) }),
|
|
71
|
+
});
|
|
72
|
+
const scanned = await createDocumentReader({ parsers: [ocr] }); // not in the default parser list
|
|
64
73
|
```
|
|
65
74
|
|
|
66
75
|
## Extension and configuration notes
|
|
67
76
|
|
|
68
77
|
- Default parser wiring uses the optional peer dependencies `pdf-parse` (PDF) and `mammoth` (DOCX raw text). Both are declared optional (`peerDependenciesMeta`); `createDocumentReader` fails closed with a documented error at creation when a selected format's peer is absent — never at read time. Hosts pin parser versions (their CVE surface is the host's responsibility; parser advisory is reviewed at ship time).
|
|
78
|
+
- `createMistralOcrParser` is **not** a default parser. It POSTs `https://api.mistral.ai/v1/ocr` (`mistral-ocr-latest`) with inline `data:` URLs (`include_image_base64: false`). No Files API upload, so no remote cleanup. Host `documentUrl` values pass `assertSsrfAllowedUrl`. Extracted markdown is untrusted. Caps: 8 MiB / 32 pages / 60 s / 1 in-flight by default (hard 50 MiB / 10 000 pages / 180 s / 4). Pass `recordUsage` to admit cost through Task 7 accounting. `baseUrl` selects residency.
|
|
69
79
|
- DOCX has no page concept in raw text: `pages` is always `1` and the page cap applies to PDF only; the text cap governs DOCX output.
|
|
70
80
|
- The read tool re-checks `maxTextBytes` on results (parity with its text-page bounds check) and refuses reader output beyond it.
|
|
71
81
|
- The adapter truncates over-cap text at a UTF-8 byte boundary (never splits a code point).
|
|
72
82
|
|
|
73
83
|
## Security and performance notes
|
|
74
84
|
|
|
75
|
-
- No embedded-script execution, no macro evaluation, no external resource fetching — the peer raw-text surfaces are pure extractors, and the no-fetch property is enforced by an egress tripwire test.
|
|
85
|
+
- No embedded-script execution, no macro evaluation, no external resource fetching on the **default** parsers — the peer raw-text surfaces are pure extractors, and the no-fetch property is enforced by an egress tripwire test on `document-reader/index.js`. OCR is a separate module and only runs when the host passes that parser.
|
|
76
86
|
- Decompression/size-bomb protection: the read tool stats and refuses files above `maxBytes` before loading; output is capped at `maxTextBytes`.
|
|
77
87
|
- Extraction envelope (recorded in `scripts/budgets.json` `docReader`, measured 2026-08-11): a max-cap 1000-page PDF (288 KB) extracts in ~162 ms with ~17 MB heap delta; the gate asserts completion within the ceiling or documented refusal.
|
|
78
88
|
- Parser code never receives a buffer whose format gate failed; random binaries never reach a parser.
|
package/docs/documents.md
CHANGED
|
@@ -7,7 +7,7 @@ The `@arnilo/prism-office/documents` package provides specification-compliant, A
|
|
|
7
7
|
It operates on a canonical, typed abstract syntax tree (AST) called the **Prism Document Model** (`DocModel`, `SheetModel`, `DeckModel`):
|
|
8
8
|
- **Pure in-memory doctrine**: Functions accept `Uint8Array` container buffers or typed model objects and emit `Uint8Array` buffers or JSON models. Zero filesystem reads, zero network I/O, zero `process.env` lookups, and zero child process spawns.
|
|
9
9
|
- **Draft-07 JSON Schema validation & slicing**: Full runtime structural validation with transitive closure slicing (`getDocumentModelSchema`) allowing LLM tools and agent prompts to extract minimal, self-contained sub-schemas (e.g. `doc.paragraph`, `doc.table`).
|
|
10
|
-
- **Bidirectional round-trip fidelity**: Prism-generated documents parse back into structurally equivalent models verified against a per-kind equality specification.
|
|
10
|
+
- **Bidirectional round-trip fidelity**: Prism-generated documents parse back into structurally equivalent models verified against a per-kind equality specification. `importDocument` also reports ZIP parts the model drops (macros, comments, media, charts, OLE, pivots) instead of silently omitting them.
|
|
11
11
|
- **Typed model patch engine**: Immutably applies `set`, `insert`, `remove`, and `move` operations to document blocks, worksheet cells, and presentation slides with schema re-validation and an interactive `createPatchHistory` undo/redo stack.
|
|
12
12
|
- **Framework-neutral preview blocks & bounded HTML**: Generates structured snapshots (`PreviewBlock[]`) for native desktop/web UI grids and outline trees, as well as safe, sanitize-by-construction HTML fragments (`renderPreviewHtml`) guaranteed to contain no executable scripts, no active pseudo-protocols, and no external hyperlinks.
|
|
13
13
|
- **Boundary text redaction**: Pluggable `SecretRedactor` hook to sanitize extracted text content (paragraphs, cells, notes, tables) at the parse boundary before models are returned.
|
|
@@ -31,11 +31,13 @@ Do **not** use this package for collaborative real-time editing (OT/CRDT), macro
|
|
|
31
31
|
| --- | --- | --- |
|
|
32
32
|
| `generateDocument` | `(model: DocumentModel, options: GenerateDocumentOptions) => Promise<GenerateDocumentResult>` | Translates a typed model into spec-compliant OOXML binary bytes (PK zip container) with a SHA-256 content hash. |
|
|
33
33
|
| `parseDocument` | `(bytes: Uint8Array, options: ParseDocumentOptions) => Promise<DocumentModel>` | Verifies PK zip signature, enforces caps, translates OOXML parts, applies optional redaction, and returns a validated model. |
|
|
34
|
+
| `importDocument` | `(bytes: Uint8Array, options: ParseDocumentOptions) => Promise<ImportDocumentResult>` | Same parse plus a ZIP-name **fidelity** report of structures the Document Model drops (macros, comments, media, charts, OLE, pivots). `parseDocument` returns `.model` only. |
|
|
34
35
|
| `patchDocument` | `(model: DocumentModel, patches: readonly DocumentPatch[], options?: PatchDocumentOptions) => DocumentModel` | Clones the model, applies typed structural patch operations, and validates the resulting model against Draft-07 schemas. |
|
|
36
|
+
| `diffDocument` | `(from: DocumentModel, to: DocumentModel, options?: DiffDocumentOptions) => DocumentDiff` | Structural paragraph/table/cell/slide diff. Decimal cells compare as canonical strings. Caps report `truncated` instead of unbounded walk. |
|
|
35
37
|
| `createPatchHistory` | `(initialModel: DocumentModel) => PatchHistory` | Creates an interactive undo/redo history manager for host editing workflows. |
|
|
36
38
|
| `renderPreviewBlocks` | `(model: DocumentModel, options?: PreviewBlocksOptions) => PreviewBlock[]` | Emits framework-neutral structured blocks (document outlines, bounded sheet grid chunks, slide summaries). |
|
|
37
39
|
| `renderPreviewHtml` | `(model: DocumentModel, options?: PreviewHtmlOptions) => string` | Emits safe, bounded HTML fragments with all entities escaped and external URLs neutralized. |
|
|
38
|
-
| `
|
|
40
|
+
| `documentModelSchema` | `(kind: DocumentKind, slice?: string \| readonly string[]) => JsonSchema` | Retrieves the Draft-07 JSON Schema for a document kind, or a self-contained sliced sub-schema with resolved `$defs` (`docModelSchema` / `sheetModelSchema` / `deckModelSchema` expose the unsliced schemas). |
|
|
39
41
|
| `validateDocumentModel`| `(model: unknown) => asserts model is DocumentModel` | Validates arbitrary JSON objects against Draft-07 document schemas and structural invariants. |
|
|
40
42
|
|
|
41
43
|
### Capacity Limits and Defaults
|
|
@@ -139,6 +141,8 @@ console.log(`Generated DOCX (${bytes.byteLength} bytes, SHA-256: ${contentHash})
|
|
|
139
141
|
|
|
140
142
|
// 3. Parse OOXML bytes back to a validated model
|
|
141
143
|
const parsed = await parseDocument(bytes, { kind: "doc" });
|
|
144
|
+
const { model, fidelity } = await importDocument(bytes, { kind: "doc" });
|
|
145
|
+
// fidelity.issues[].code: macros | comments | media | … lost: dropped | approximated
|
|
142
146
|
|
|
143
147
|
// 4. Apply typed model patches
|
|
144
148
|
const patched = patchDocument(parsed, [
|
|
@@ -152,6 +156,9 @@ history.apply([{ op: "set", target: { title: true }, value: "Updated Review" }])
|
|
|
152
156
|
console.log(history.canUndo()); // true
|
|
153
157
|
const restored = history.undo(); // restored to "Executive Summary" state
|
|
154
158
|
|
|
159
|
+
import { diffDocument } from "@arnilo/prism-office/documents";
|
|
160
|
+
const diff = diffDocument(parsed, restored, { maxOps: 4096 });
|
|
161
|
+
|
|
155
162
|
// 6. Generate structured preview blocks & safe HTML
|
|
156
163
|
const blocks = renderPreviewBlocks(restored);
|
|
157
164
|
const htmlSnippet = renderPreviewHtml(restored, { maxHtmlBytes: 256 * 1024 });
|
|
@@ -208,7 +215,8 @@ Financial worksheets often require exact decimal representations that JavaScript
|
|
|
208
215
|
|
|
209
216
|
## Related APIs
|
|
210
217
|
|
|
211
|
-
- [`@arnilo/prism-coding-tools/document-reader`](./document-reader.md): Bounded literal text extraction from PDF and DOCX documents for coding agent tools.
|
|
218
|
+
- [`@arnilo/prism-coding-tools/document-reader`](./document-reader.md): Bounded literal text extraction from PDF and DOCX documents for coding agent tools; optional host-selected Mistral OCR parser.
|
|
212
219
|
- [`@arnilo/prism-core/integrations/work`](./work-tools.md): Microsoft 365 and Google Workspace identity-scoped connectors.
|
|
213
220
|
- [`@arnilo/prism-coding-tools/agent`](./coding-agent-tools.md): Coding tools and file operations.
|
|
214
221
|
- [`@arnilo/prism-core/governance/observability`](./observability.md): OpenTelemetry instrumentation and trace adapters.
|
|
222
|
+
- [Work artifacts and review](work-artifacts-and-review.md): evidence-bound artifact citations and `evidenceDigest` approvals.
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
| ERP messaging | `erpMessaging` | Transactional outbox/inbox markers plus bounded, tenant-scoped at-least-once dispatch (migration 004). |
|
|
15
15
|
| Multi-party approvals | `createPostgresApprovalStore({ pool, schema, authority })` | Immutable approval requests, role/quorum decisions, revocation, bounded delegation, and atomic grant consumption (migration 005). |
|
|
16
16
|
|
|
17
|
-
`createPostgresEnterpriseState()` opens a host-supplied or adapter-owned `pg` pool, verifies/applies checksum-protected enterprise migrations (`001_enterprise_state`, `002_tool_effects`, `003_router_reservations`, `004_erp_messaging`, `005_erp_approvals`), and returns those stores plus explicit cleanup and close operations. Importing it performs no I/O. It is separate from session/run persistence in [`@arnilo/prism-core/sessions/postgres`](postgres-persistence.md).
|
|
17
|
+
`createPostgresEnterpriseState()` opens a host-supplied or adapter-owned `pg` pool, verifies/applies checksum-protected enterprise migrations (`001_enterprise_state`, `002_tool_effects`, `003_router_reservations`, `004_erp_messaging`, `005_erp_approvals`, `006_aggregate_budgets`), and returns those stores plus explicit cleanup and close operations. Importing it performs no I/O. It is separate from session/run persistence in [`@arnilo/prism-core/sessions/postgres`](postgres-persistence.md).
|
|
18
18
|
|
|
19
19
|
## When to use it
|
|
20
20
|
|
|
@@ -90,7 +90,7 @@ Model-router state is asynchronous and owner/principal/provider/model scoped. Su
|
|
|
90
90
|
}
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
A migration creates `prism_policy_decisions`, `prism_evaluations`, `prism_work_idempotency`, three `prism_model_router_*` tables, `prism_erp_outbox`, `prism_erp_inbox`, `prism_erp_approvals`, and its separate `prism_enterprise_migrations` history. Migration `003_router_reservations` adds the nullable-by-default `reservations` JSONB column to `prism_model_router_budgets` (atomic reservation slots for router admission; 0.2.1 readers ignore it). Migration `004_erp_messaging` adds tenant/message and tenant/consumer/message primary keys plus claim, lease, and inbox indexes. Migration `005_erp_approvals` adds the one-row-per-request approval table (PK `tenant_id + id`, status check, decisions JSONB, status/created indexes). Startup serializes per-schema setup with an advisory transaction lock and rejects checksum or catalog drift rather than silently repairing it.
|
|
93
|
+
A migration creates `prism_policy_decisions`, `prism_evaluations`, `prism_work_idempotency`, three `prism_model_router_*` tables, `prism_erp_outbox`, `prism_erp_inbox`, `prism_erp_approvals`, and its separate `prism_enterprise_migrations` history. Migration `003_router_reservations` adds the nullable-by-default `reservations` JSONB column to `prism_model_router_budgets` (atomic reservation slots for router admission; 0.2.1 readers ignore it). Migration `004_erp_messaging` adds tenant/message and tenant/consumer/message primary keys plus claim, lease, and inbox indexes. Migration `005_erp_approvals` adds the one-row-per-request approval table (PK `tenant_id + id`, status check, decisions JSONB, status/created indexes). Migration `006_aggregate_budgets` adds `task_id TEXT NOT NULL DEFAULT ''` and `attributions JSONB NOT NULL DEFAULT '{}'::jsonb` to `prism_model_router_budgets` and creates partial index `prism_model_router_budgets_task_idx` on `(tenant_id, account_key, user_key, principal_id, task_id, window_ms) WHERE task_id <> ''`. Task-scoped budgets route through `provider = ':task:'` and `model = taskId`, grouping retries, fallbacks, child workers, compactions, embeddings, and paid tools into a single atomic budget ceiling with granular attributions. Startup serializes per-schema setup with an advisory transaction lock and rejects checksum or catalog drift rather than silently repairing it.
|
|
94
94
|
|
|
95
95
|
## Implementation example
|
|
96
96
|
|