@arnilo/prism 0.0.17 → 0.0.19

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 CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.19] - 2026-07-30
4
+
5
+ ### Added
6
+ - `@arnilo/prism-compaction-observational-memory`: `createObservationalMemory()` + `attach()` lifecycle, four-layer provider context (recent exact messages, observation log, reflections, raw-source retrieval), `recallObservationalMemoryBranchPage()`, `wrapResumeRun` / `wrapResumeStream`, nested settings with legacy flat-key mapping.
7
+
8
+ ### Changed
9
+ - Observational memory: separate observer/reflector/dropper workers, domain-neutral observer default, dual coverage/eligibility fixes, full-ledger reflection recall, hard fold/render byte caps, post-run `compactAfterTokens` compaction when attached.
10
+
11
+ See [docs/migration.md](docs/migration.md) for the full 0.0.18 → 0.0.19 observational memory notes.
12
+
13
+ ## [0.0.18] - 2026-07-30
14
+
15
+ ### Changed
16
+ - Default `inputLayout` is `cache_aware` (unset `AgentConfig` / `RunOptions` use cache-stable message order); set `inputLayout: "legacy"` to restore prior ordering.
17
+ - `applyContextBudget` evicts oldest history messages first under pressure (was newest-first).
18
+ - `@arnilo/prism-mcp` pins `@modelcontextprotocol/sdk` **1.30.0** (clears moderate `@hono/node-server` path-traversal advisory on the MCP HTTP stack).
19
+
20
+ ### Breaking (minor, pre-1.0)
21
+ - `@arnilo/prism-coding-agent` `repo_search` is literal-only: `mode: "regex"` removed; `compileSearchPattern` drops the `mode` argument (ReDoS mitigation).
22
+ - Default local `write` / `edit` operations use same-directory temp + `rename` for crash-safe replacement.
23
+
24
+ See [docs/migration.md](docs/migration.md) for the full 0.0.17 → 0.0.18 notes.
25
+
3
26
  ## [0.0.17] - 2026-07-29
4
27
 
5
28
  ### Added
package/README.md CHANGED
@@ -157,6 +157,13 @@ printf '{"id":"1","command":"prompt","params":{"input":"Hi"}}\n' \
157
157
  | `@arnilo/prism-provider-neuralwatt` | NeuralWatt provider with implicit vLLM prefix caching |
158
158
  | `@arnilo/prism-provider-alibaba` | Alibaba Cloud (Model Studio / DashScope + Coding Plan) provider with dynamic discovery and explicit/implicit caching |
159
159
  | `@arnilo/prism-provider-ollama` | Ollama Cloud / local provider with dynamic discovery and implicit-only caching |
160
+ | `@arnilo/prism-provider-anthropic` | Anthropic Messages provider |
161
+ | `@arnilo/prism-provider-google` | Google Gemini provider |
162
+ | `@arnilo/prism-provider-azure` | Azure OpenAI provider |
163
+ | `@arnilo/prism-provider-bedrock` | AWS Bedrock provider |
164
+ | `@arnilo/prism-provider-vertex` | Google Vertex provider |
165
+ | `@arnilo/prism-provider-ai-sdk` | AI SDK interoperability adapter |
166
+ | `@arnilo/prism-browser` | optional host-wired Playwright browser automation (not core; not auto-activated) |
160
167
  | `@arnilo/prism-compaction-llm` | provider-backed compaction strategy |
161
168
  | `@arnilo/prism-compaction-observational-memory` | source-backed memory + recall tool |
162
169
  | `@arnilo/prism-coding-agent` | bounded shell/read/write/edit tools |
@@ -170,7 +177,7 @@ printf '{"id":"1","command":"prompt","params":{"input":"Hi"}}\n' \
170
177
  | `@arnilo/prism-credentials-node` | encrypted-file and keychain credentials |
171
178
  | `@arnilo/prism-session-store-sqlite` | SQLite persistence/checkpoints/leases/owned run feedback |
172
179
  | `@arnilo/prism-session-store-postgres` | PostgreSQL persistence/checkpoints/leases/owned run feedback |
173
- | `@arnilo/prism-providers` | family: all 11 provider adapters, including AI SDK interoperability |
180
+ | `@arnilo/prism-providers` | family: all 14 first-party provider adapters, including AI SDK interoperability |
174
181
  | `@arnilo/prism-compaction` | family: both compaction strategies |
175
182
  | `@arnilo/prism-base` | profile: core + compaction + JSON Schema validation |
176
183
  | `@arnilo/prism-code` | profile: base + coding tools/security + MCP |
@@ -189,6 +196,6 @@ printf '{"id":"1","command":"prompt","params":{"input":"Hi"}}\n' \
189
196
  ## Non-goals (v1)
190
197
 
191
198
  - Privileged tools, MCP servers, telemetry, credentials, or databases activated by install — hosts explicitly configure and register every capability.
192
- - Browser automation or interactive terminal UI — CLI/RPC and workflow control APIs only.
199
+ - Browser automation or interactive terminal UI in core — hosts may opt into `@arnilo/prism-browser` with their own Playwright lifecycle; Prism does not auto-start browsers or ship a TUI.
193
200
  - Provider, credential, extension, or package auto-discovery.
194
201
  - Core-owned database drivers, secret persistence, sandbox, or application policy — optional packages implement adapters over host-owned boundaries.
@@ -48,7 +48,7 @@ export function getContextBudgetReport(request) {
48
48
  }
49
49
  export function applyContextBudget(options) {
50
50
  const budget = resolveContextBudget(options.budget);
51
- const layout = options.layout ?? "legacy";
51
+ const layout = options.layout ?? "cache_aware";
52
52
  const groups = {
53
53
  instructions: [...options.groups.instructions],
54
54
  summaries: [...options.groups.summaries],
@@ -91,8 +91,8 @@ export function applyContextBudget(options) {
91
91
  };
92
92
  }
93
93
  function dropNext(groups, context, skills, layout) {
94
- // ponytail: drop from end of keep-stack (history/tool_results first). cache_aware keeps
95
- // attachments longer so stable prefix stays intact while budget still allows it.
94
+ // ponytail: drop droppable groups in layout order; within history, drop oldest first (shift).
95
+ // cache_aware keeps attachments longer so stable prefix stays intact while budget still allows it.
96
96
  const order = layout === "cache_aware"
97
97
  ? ["tool_results", "history", "summaries", "context", "skills", "attachments"]
98
98
  : ["tool_results", "history", "summaries", "attachments", "context", "skills"];
@@ -102,7 +102,7 @@ function dropNext(groups, context, skills, layout) {
102
102
  return omission("tool_results", message.id ?? toolResultId(message), message);
103
103
  }
104
104
  if (kind === "history" && groups.history.length > 0) {
105
- const message = groups.history.pop();
105
+ const message = groups.history.shift();
106
106
  return omission("history", message.id, message);
107
107
  }
108
108
  if (kind === "summaries" && groups.summaries.length > 0) {
package/dist/index.d.ts CHANGED
@@ -94,5 +94,5 @@ export { createToolParameterValidator, createToolRegistry, dispatchToolCall, fil
94
94
  export type { ResolvedUseCaseModel, ResolveUseCaseModelInput, UseCaseModelBinding, } from "./use-case-model.js";
95
95
  export { resolveUseCaseModel, resolveUseCaseModelBinding, useCaseCredentialProviderId, } from "./use-case-model.js";
96
96
  export declare const name = "prism";
97
- export declare const version = "0.0.17";
97
+ export declare const version = "0.0.19";
98
98
  export declare const description = "Agent harness for AI providers, agents, sessions, and tools.";
package/dist/index.js CHANGED
@@ -51,6 +51,6 @@ export { applyThinkingLevel, isThinkingLevel, normalizeThinkingLevel, THINKING_L
51
51
  export { createToolParameterValidator, createToolRegistry, dispatchToolCall, filterTools } from "./tools.js";
52
52
  export { resolveUseCaseModel, resolveUseCaseModelBinding, useCaseCredentialProviderId, } from "./use-case-model.js";
53
53
  export const name = "prism";
54
- export const version = "0.0.17";
54
+ export const version = "0.0.19";
55
55
  export const description = "Agent harness for AI providers, agents, sessions, and tools.";
56
56
  //# sourceMappingURL=index.js.map
package/dist/input.js CHANGED
@@ -11,7 +11,7 @@ export function createDefaultInputBuilder() {
11
11
  const groups = await buildDefaultInputMessageGroups(input, context);
12
12
  // `input_assembly` middleware is applied by assembleProviderInput after build(),
13
13
  // never here: builders must not be a security seam.
14
- return flattenInputGroups(groups, context.inputLayout ?? "legacy");
14
+ return flattenInputGroups(groups, context.inputLayout ?? "cache_aware");
15
15
  },
16
16
  };
17
17
  }
@@ -80,7 +80,7 @@ export async function assembleProviderInput(options) {
80
80
  ? composeSystemPrompt(injectorContribs.instructions, { base: options.systemInstructions })
81
81
  : options.systemInstructions;
82
82
  const buildContext = { ...options, ...baseContext, systemInstructions };
83
- const layout = buildContext.inputLayout ?? "legacy";
83
+ const layout = buildContext.inputLayout ?? "cache_aware";
84
84
  let messages;
85
85
  let context;
86
86
  let skills = options.skills;
@@ -1,30 +1,41 @@
1
1
  # 0.1.0 / 1.0 Readiness Gates
2
2
 
3
- Status: **0.0.16 is a 1.0 readiness review, not an automatic 1.0 release.**
4
- This page distills the Phase 11 (0.0.16) gates into one command-per-gate table
5
- so readiness is checkable, not prose. Every gate below is a runnable command
6
- with last evidence captured on 2026-07-26 (release 0.0.16, Node v24.18.0,
7
- Linux x86_64). The decision to cut 1.0 stays with the operator after the
8
- operator-gated legs run in a protected environment and the Phase 12 demand
9
- evidence exists.
3
+ Status: **0.0.19** is the current release line (Phase 2 observational memory lifecycle); **1.0** readiness remains operator-gated, not automatic.
4
+
5
+ This page distills runnable readiness gates into one command-per-gate table. The
6
+ **Last evidence** column records the 2026-07-26 **0.0.16** baseline snapshot
7
+ (Phase 11, Node v24.18.0, Linux x86_64). Treat it as historical floor evidence,
8
+ not the current release tag. Re-run each gate on the target release tree before
9
+ cutting 0.0.19 / 1.0. The decision to cut 1.0 stays with the operator after
10
+ operator-gated legs run in a protected environment and Phase 12 demand evidence
11
+ exists.
10
12
 
11
13
  Evidence trail: [`docs/review-coverage-2026-07-26-phase-11.md`](./review-coverage-2026-07-26-phase-11.md)
12
14
  (addenda 0–9), [`docs/release-and-install.md`](./release-and-install.md),
13
15
  [`docs/migration.md`](./migration.md), [`docs/performance.md`](./performance.md).
14
16
 
17
+ ## Current line (0.0.19)
18
+
19
+ | Item | Status |
20
+ |---|---|
21
+ | Published graph | **44** publishable manifests at **0.0.19** (`docs/release-and-install.md`) |
22
+ | Phase 2 observational memory | `createObservationalMemory().attach()`, four-layer context, nested settings, recall paging, hard fold/render caps |
23
+ | Docs tripwires | `node --test dist/__tests__/docs.test.js` — migration section `0.0.18 → 0.0.19 observational memory lifecycle` documents intentional breaks |
24
+ | Readiness table below | **0.0.16 measured values** — refresh evidence columns when 1.0 RC gates are recorded |
25
+
15
26
  ## Gate table
16
27
 
17
- | Gate | Command | Last evidence (2026-07-26) | Owner |
28
+ | Gate | Command | Last evidence (2026-07-26 baseline @ 0.0.16) | Owner |
18
29
  |---|---|---|---|
19
30
  | Full quality gate | `npm run sdk:ready` | RC=0: typecheck (+examples), lint 0, format clean, full test, coverage, pack, release:gate | CI |
20
- | Exact version graph | `node scripts/release.mjs check --version <v>` | 0.0.16 pass: exact versions/ranges/lockfile/access + registry-collision check, 44 manifests | CI + operator |
21
- | Frozen public API surface + compat gate | `node scripts/release.mjs gate` | 0 breaks / 0 errors vs 44 checked-in baselines (`scripts/compat-baseline/`); only additive delta is `resolveRedactor` | CI |
22
- | Migration coverage 0.0.5→0.0.16 | `node --test dist/__tests__/docs.test.js` | 112/112; `docs/migration.md` has one section per release 0.0.5→0.0.16, each tripwired | Maintainer |
31
+ | Exact version graph | `node scripts/release.mjs check --version <v>` | pass at 0.0.16: exact versions/ranges/lockfile/access + registry-collision check, 44 manifests | CI + operator |
32
+ | Frozen public API surface + compat gate | `node scripts/release.mjs gate` | 0 breaks / 0 errors vs checked-in baselines (`scripts/compat-baseline/`); only additive delta at 0.0.16 was `resolveRedactor` | CI |
33
+ | Migration coverage + docs tripwires | `node --test dist/__tests__/docs.test.js` | 112/112 at 0.0.16; `docs/migration.md` sections tripwired per release | Maintainer |
23
34
  | Deterministic artifact budget | `node --test dist/__tests__/budget-gate.test.mjs` | root 579.2 kB / 2.1 MB / 270 files within +5% of baseline; startup 38 ms < 250 ms ceiling | CI (in `npm test`) |
24
35
  | Performance benchmark medians | `node scripts/benchmark-0.0.16.mjs` | 6 network-free scenarios within ±25%; 0 backpressure / 0 resource-limit signals | On-demand release evidence |
25
36
  | Secret scan | `node scripts/scan-secrets.mjs` | 3095 files / 0 findings | CI |
26
37
  | License / SBOM | `node scripts/verify-sbom.mjs` | 188 packages / 8 licenses, all allow-listed | CI |
27
- | Dependency audit | `npm audit --audit-level=high` | rc=0 (2 moderate, 0 high) | CI |
38
+ | Dependency audit | `npm audit --audit-level=high` | rc=0 (2 moderate, 0 high) at 0.0.16 | CI |
28
39
  | Whitespace hygiene | `git diff --check` | clean | CI |
29
40
  | Publish order + tarball validation | `node scripts/release.mjs publish --version <v> --dry-run --allow-dirty --allow-untagged` | 44/44 packages `dry-run`, deterministic dependency order, no failures | Operator (dry-run), CI |
30
41
  | Node 20 compatibility | CI `node20-compat` (build + public-import smoke) | all 21 root exports import cleanly on Node 20.20.2 | CI |
@@ -48,12 +59,15 @@ Regenerate only after review with `node scripts/release.mjs gate --update-baseli
48
59
  having first confirmed zero removed exports (the gate's order-sensitive
49
60
  signatures can drift on a TypeScript bump without any real API change).
50
61
 
51
- ## Migration coverage 0.0.5 → 0.0.16
62
+ ## Migration coverage
52
63
 
53
- `docs/migration.md` carries one section per release from 0.0.5 through 0.0.16;
54
- `docs.test.ts` tripwires each section heading and key phrase, so a missing or
55
- gutted migration section fails the suite. 0.0.16's only user-facing change is
56
- the additive `resolveRedactor` export (no breaking changes).
64
+ `docs/migration.md` carries release migration sections tripwired by
65
+ `docs.test.ts` (headings and key phrases). A missing or gutted section fails
66
+ the suite. **0.0.19** adds observational-memory lifecycle and nested settings in
67
+ `@arnilo/prism-compaction-observational-memory` — see `0.0.18 → 0.0.19 observational memory lifecycle`.
68
+ **0.0.18** adds intentional pre-1.0 breaks (`repo_search` literal-only,
69
+ `cache_aware` default layout, oldest-first history eviction, atomic write/edit
70
+ durability, MCP SDK bump) — see `0.0.17 → 0.0.18 restore integrity`.
57
71
 
58
72
  ## Budget table
59
73
 
@@ -95,13 +109,13 @@ protected environment, never faked.
95
109
 
96
110
  ## Security matrix
97
111
 
98
- | Control | Command / source | 0.0.16 status |
112
+ | Control | Command / source | 0.0.16 baseline |
99
113
  |---|---|---|
100
114
  | Secret scan | `node scripts/scan-secrets.mjs` | 3095 files / 0 findings |
101
115
  | License / SBOM | `node scripts/verify-sbom.mjs` | 188 packages / 8 licenses, allow-listed |
102
116
  | Dependency audit | `npm audit --audit-level=high` | 0 high (2 moderate) |
103
117
  | SAST | GitHub CodeQL workflow | CI-gated |
104
- | Sandbox / protocol / tenant threat suites | `npm test` (coding-security, MCP, policy, guardrail suites) | green |
118
+ | Sandbox / protocol / tenant threat suites | `npm test` (coding-security, MCP, policy, guardrail suites) | green at 0.0.16 |
105
119
  | Signed deterministic publication | `release.mjs publish` on clean tagged tree | operator-gated |
106
120
 
107
121
  ## Remaining for 1.0 (operator / protected environment)
@@ -121,6 +135,8 @@ Exact prerequisites that must be satisfied before cutting 1.0:
121
135
  checked-in baseline.
122
136
  7. **Phase 12 demand evidence** (below) recorded for any capability that 1.0
123
137
  is expected to anchor.
138
+ 8. **0.0.19+ lifecycle gates green** on the release candidate (docs suite,
139
+ MCP SDK advisory cleared, coding-tool durability fixes, layout/eviction defaults).
124
140
 
125
141
  ## Phase 12 demand-evidence entry criteria
126
142
 
@@ -135,5 +151,5 @@ alone. Each candidate must present, before it becomes a numbered plan:
135
151
  - then the pipeline: demand evidence → primitive review → threat model →
136
152
  optional package/service → conformance → release gate.
137
153
 
138
- The 0.0.16 readiness gates above are the stable API/compat/budget/security
139
- floor that Phase 12 capabilities must consume and must not regress.
154
+ The readiness gates above are the stable API/compat/budget/security floor that
155
+ Phase 12 capabilities must consume and must not regress.
@@ -49,7 +49,7 @@ string | Message | readonly Message[]
49
49
 
50
50
  `AgentConfig.limits` sets run ceilings; `RunOptions.limits` may only narrow configured agent values. Limits cover turns, provider attempts, tool rounds/calls, wall time, request/response bytes, tokens, and optional single-currency cost. A breach emits one `run_limit_exceeded` event and throws `AgentRunError` with `result.limit`; see [Runs and usage ledger](runs-and-usage.md#run-limits).
51
51
 
52
- `RunOptions.model` can override the request model for a run. Model overrides append a `model_change` entry. `AgentConfig.inputLayout` selects the default input assembly layout (`"legacy"` by default, or opt-in `"cache_aware"`); `RunOptions.inputLayout` wins for one run. `AgentConfig.providerOptions`/`RunOptions.providerOptions` supply generic provider request options; `timeoutMs`, `maxRetries`, and `maxRetryDelayMs` are deprecated inert provider-level hints in first-party providers. Use `RunOptions.signal`/host abort controllers for timeouts and `AgentConfig.retry`/`RunOptions.retry` for retry. `AgentConfig.providerRequestPolicies`/`RunOptions.providerRequestPolicies` run before `AIProvider.generate()` and before `provider_request` middleware. `AgentConfig.systemPrompt` and `RunOptions.systemPrompt` add explicit layered system prompt contributions; `RunOptions.systemPrompt: false` disables configured prompt layers for that run while keeping `AgentConfig.instructions` as the base path. `RunOptions.compaction` can enable auto-compaction for that run or use `false` to disable configured auto-compaction. `RunOptions.retry` can enable provider-turn retry for that run or use `false` to disable configured retry. `RunOptions.metadata` is merged with agent/session metadata for assembly, provider requests, and tool contexts. Deprecated `RunOptions.maxToolRounds` narrows `limits.maxToolRounds`. `RunOptions.signal` is bridged into the per-run abort signal passed to assembly, providers, tools, auto-compaction, and retry backoff.
52
+ `RunOptions.model` can override the request model for a run. Model overrides append a `model_change` entry. `AgentConfig.inputLayout` selects the default input assembly layout (`"cache_aware"` by default, or opt-in `"legacy"`); `RunOptions.inputLayout` wins for one run. `AgentConfig.providerOptions`/`RunOptions.providerOptions` supply generic provider request options; `timeoutMs`, `maxRetries`, and `maxRetryDelayMs` are deprecated inert provider-level hints in first-party providers. Use `RunOptions.signal`/host abort controllers for timeouts and `AgentConfig.retry`/`RunOptions.retry` for retry. `AgentConfig.providerRequestPolicies`/`RunOptions.providerRequestPolicies` run before `AIProvider.generate()` and before `provider_request` middleware. `AgentConfig.systemPrompt` and `RunOptions.systemPrompt` add explicit layered system prompt contributions; `RunOptions.systemPrompt: false` disables configured prompt layers for that run while keeping `AgentConfig.instructions` as the base path. `RunOptions.compaction` can enable auto-compaction for that run or use `false` to disable configured auto-compaction. `RunOptions.retry` can enable provider-turn retry for that run or use `false` to disable configured retry. `RunOptions.metadata` is merged with agent/session metadata for assembly, provider requests, and tool contexts. Deprecated `RunOptions.maxToolRounds` narrows `limits.maxToolRounds`. `RunOptions.signal` is bridged into the per-run abort signal passed to assembly, providers, tools, auto-compaction, and retry backoff.
53
53
 
54
54
  ## Outputs / response / events
55
55
 
@@ -11,7 +11,7 @@
11
11
  | `createWriteTool(cwd, options?)` | `write` tool: create or overwrite a file, creating parent directories. |
12
12
  | `createEditTool(cwd, options?)` | `edit` tool: precise exact-then-fuzzy text replacement in an existing file. |
13
13
  | `createRepoListTool(cwd, options?)` | `repo_list` tool: bounded deterministic repository listing. |
14
- | `createRepoSearchTool(cwd, options?)` | `repo_search` tool: bounded literal/regex text search. |
14
+ | `createRepoSearchTool(cwd, options?)` | `repo_search` tool: bounded literal text search. |
15
15
  | `createCodingTools(cwd, options?)` | Default six tools (`shell`, `read`, `write`, `edit`, `repo_list`, `repo_search`). |
16
16
  | `createReadOnlyTools(cwd, options?)` | Read-only subset: `read`, `repo_list`, `repo_search`. |
17
17
  | `createAllTools(cwd, options?)` | Identical to `createCodingTools` (Git tools remain opt-in via `createGitTools`). |
@@ -152,6 +152,8 @@ Create or overwrite a file, creating parent directories as needed.
152
152
 
153
153
  **Outputs:** a `TextContent` confirmation naming the **absolute path** with UTF-8 byte and line counts (e.g. `Successfully wrote 42 bytes (3 lines) to /abs/path.txt`). `maxInputBytes` defaults to 8 MiB (64 MiB hard cap); oversized UTF-8 input fails before policy evaluation, directory creation, or write. Write failures and abort are error results. Empty `content` is valid.
154
154
 
155
+ Default local `writeFile` uses same-directory temp + `rename` so a crash mid-write cannot truncate the target; custom `WriteOperations` should provide equivalent durability.
156
+
155
157
  `write` result `metadata`: `{ bytes, lines, path }` (absolute path). Concurrent writes to the same path serialize through `withFileMutationQueue`; writes to different paths run in parallel.
156
158
 
157
159
  ### `edit`
@@ -165,7 +167,7 @@ Precise text replacement in an existing file via exact-then-fuzzy matching.
165
167
  | `path` | `string` | Path to the file to edit. Required. |
166
168
  | `edits` | `Array<{ oldText: string, newText: string }>` | Targeted replacements, each matched against the **original** file (not incrementally). No overlapping/nested edits. Required, non-empty. |
167
169
 
168
- Each `edits[].oldText` must match a unique, non-overlapping region of the original file. Matching is exact first, then fuzzy (unicode normalization / whitespace collapse). A BOM is stripped before matching and re-prepended on write; original line endings are restored. Defaults reject targets over 8 MiB, aggregate old/new UTF-8 input over 2 MiB, or more than 100 edits (hard caps: 64 MiB, 16 MiB, and 1,000). Stat and bounded read checks run before matching or mutation.
170
+ Each `edits[].oldText` must match a unique, non-overlapping region of the original file. Matching is exact first, then fuzzy (unicode normalization / whitespace collapse). **Fuzzy matching can apply a wrong region when `oldText` is slightly off** — tradeoff for imprecise models; prefer exact `oldText` when possible. A BOM is stripped before matching and re-prepended on write; original line endings are restored. Defaults reject targets over 8 MiB, aggregate old/new UTF-8 input over 2 MiB, or more than 100 edits (hard caps: 64 MiB, 16 MiB, and 1,000). Stat and bounded read checks run before matching or mutation. Default local `writeFile` uses same-directory temp + `rename` (crash-safe replace).
169
171
 
170
172
  **Outputs:** a `TextContent` confirmation (`Successfully replaced N block(s) in {path}.`) plus `metadata`. Any failure — missing/unreadable file, no match, duplicate (non-unique) match, overlap, empty `oldText`, no-op edit, or abort — is an error result, and the file is left **unchanged** (the match runs before the write).
171
173
 
@@ -189,15 +191,15 @@ List repository entries with deterministic relative paths. Uses Node `opendir`/`
189
191
 
190
192
  ### `repo_search`
191
193
 
192
- Search text files under the workspace. Default mode is literal substring match; `mode: "regex"` enables length-bounded regular expressions. Binary files (NUL in a bounded prefix) and oversize files are skipped. Aggregate scanned bytes, matches, line bytes, pattern bytes, and wall time are finite.
194
+ Search text files under the workspace using literal substring match. Binary files (NUL in a bounded prefix) and oversize files are skipped. Aggregate scanned bytes, matches, line bytes, pattern bytes, and wall time are finite.
193
195
 
194
196
  **Inputs:**
195
197
 
196
198
  | Field | Type | Purpose |
197
199
  | --- | --- | --- |
198
- | `query` | `string` | Literal or regex pattern (required). |
200
+ | `query` | `string` | Literal substring (required). |
199
201
  | `path` | `string` | Workspace-relative start path. |
200
- | `mode` | `"literal" \| "regex"` | Default `literal`. |
202
+ | `mode` | `"literal"` | Literal only (default). `regex` removed in 0.0.18. |
201
203
  | `caseSensitive` | `boolean` | Default false. |
202
204
  | `includeHidden` | `boolean` | Default false. |
203
205
  | `context` | `number` | Context lines before/after each match (default 5, hard 20). |
@@ -410,7 +412,7 @@ const remoteWrite = createWriteTool("/repo", {
410
412
  | Shell total stdout+stderr | 64 MiB | 1 GiB | process-tree kill; spill removal |
411
413
  | Repo depth / entries / files / page | 32 / 10,000 / 10,000 / 1,000 | 128 / 100,000 / 100,000 / 10,000 | before descending/retaining next entry |
412
414
  | Search scan / file / matches | 64 MiB / 8 MiB / 1,000 | 1 GiB / 64 MiB / 10,000 | before next file/match retention |
413
- | Search pattern / line / context / time | 512 B / 50 KiB / 5 / 30 s | 4 KiB / 1 MiB / 20 / 300 s | before regex compile / line retain / deadline |
415
+ | Search pattern / line / context / time | 512 B / 50 KiB / 5 / 30 s | 4 KiB / 1 MiB / 20 / 300 s | before pattern compile / line retain / deadline |
414
416
  | Git paths / refs / message | 1,000 / 1 KiB / 64 KiB | 10,000 / 4 KiB / 256 KiB | before process/temp-file creation |
415
417
  | Git output / diff lines / changed files / patch | 4 MiB / 10,000 / 1,000 / 16 MiB | 64 MiB / 100,000 / 10,000 / 64 MiB | stream before retain; artifact spill optional |
416
418
  | Worktrees | 4 | 16 | before add |
@@ -8,6 +8,21 @@ Current status: ledger/projection/render/recall utilities, explicit worker runti
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
+ ## Four-layer provider context
12
+
13
+ Observational memory composes four independent layers for long sessions (Mastra-style):
14
+
15
+ | Layer | What it holds | How it is produced |
16
+ | --- | --- | --- |
17
+ | **Recent exact messages** | Last `context.recentMessages` user/assistant/tool entries in branch order (optional `recentMessageMaxTokens` trim, oldest first) | `buildObservationalMemoryContextBlocks()` → `recent-messages` ContextBlock; aligned with compaction `keepRecentEntries` |
18
+ | **Observation log** | Source-backed facts with 12-hex ids and `sourceEntryIds` | Observer worker on eligible unscanned `message` entries after `observation.messageTokens`; coverage advances even on empty passes |
19
+ | **Reflections** | Higher-level summaries over observation ids | Reflector worker on observations after last reflection coverage when `reflection.observationTokens` met |
20
+ | **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
+
22
+ Activation is explicit: `createObservationalMemory().attach()` coordinates post-run observe/reflect/drop and `context.compactAfterTokens` compaction. 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
+
24
+ See `examples/observational-memory-lifecycle.ts` for attach → turn → projection/recall/page without live credentials.
25
+
11
26
  ## When to use it
12
27
 
13
28
  Use it when a host wants to opt in to long-session memory that records observations/reflections as session custom entries, renders prepared memory during compaction, and supports exact-id recall.
@@ -20,7 +35,7 @@ Memory records use `SessionEntry.kind: "custom"` with `entry.data.type` markers:
20
35
 
21
36
  | Type | Payload |
22
37
  | --- | --- |
23
- | `om.observations.recorded` | `{ observations, coversUpToId? }` |
38
+ | `om.observations.recorded` | `{ observations, coversUpToId? }` — successful observer runs append coverage even when `observations` is empty. |
24
39
  | `om.reflections.recorded` | `{ reflections, coversUpToId? }` |
25
40
  | `om.observations.dropped` | `{ observationIds, coversUpToId? }` |
26
41
  | `om.folded` | Compaction `data.memory` folded details. |
@@ -38,6 +53,10 @@ Worker limits are finite positive safe integers:
38
53
  | `maxWorkerResultBytes` | 64 KiB | 1 MiB | Full tool result and replayed value/error payload |
39
54
  | `maxWorkerMessageBytes` | 1 MiB | 8 MiB | System/prompt plus assistant-call/tool-result transcript |
40
55
  | `maxWorkerErrorBytes` | 1 KiB | 8 KiB | Provider/tool/runtime error text after exact known-secret redaction |
56
+ | Rendered memory projection | — | 256 KiB | `renderObservationalMemory()` / context block text |
57
+ | Folded compaction payload | — | 512 KiB | `data.memory` JSON; strategy trims lowest-relevance observations before failing |
58
+ | Recent-message window | — | 512 KiB | `renderRecentMessageWindow()` hard cap |
59
+ | Recall page size | 20 | 100 | `retrieval.pageLimit` / recall tool `limit` |
41
60
 
42
61
  Direct `runObserver()` / `runReflector()` / `runDropper()` calls retain required `maxTurns` and accept the corresponding shorter worker fields (`maxToolCalls`, `maxResultBytes`, etc.). Named default/hard constants and `resolveMemoryWorkerLimits()` are exported.
43
62
 
@@ -48,20 +67,26 @@ Key exports:
48
67
  | Export | Purpose |
49
68
  | --- | --- |
50
69
  | `foldObservationalMemoryLedger()` | Fold custom memory entries into observations, reflections, drops, and coverage markers. |
70
+ | `isEligibleObservationSourceEntry()` / `eligibleObservationSources()` | Select user/assistant/tool `message` entries for observer input. |
71
+ | `unscannedEntries()` / `observationsUncoveredByReflection()` | Dual coverage helpers for observation scan and reflection windows. |
51
72
  | `buildObservationalMemoryProjection()` | Build active/full/folded projections from current branch entries. |
73
+ | `buildObservationalMemoryContextBlocks()` | Render observational-memory + recent-messages context blocks for provider input. |
74
+ | `selectRecentMessageEntries()` / `renderRecentMessageWindow()` | Bounded exact recent-message suffix; count via `keepRecentEntries`, optional token trim via `estimateEntryTokens`. |
52
75
  | `createFoldedMemoryDetails()` | Create JSON details for compaction `data.memory`. |
53
76
  | `renderObservationalMemory()` | Render reflections and observations into a prepared memory summary. |
54
77
  | `recallObservationalMemory()` | Recover source evidence for a known observation/reflection id from supplied current-branch entries. |
78
+ | `recallObservationalMemoryBranchPage()` | Page eligible user/assistant/tool messages around a cursor entry id (`forward`/`backward`, optional `detail: summary|full`). |
55
79
  | `createMemoryId()` / `isMemoryId()` | Create/check 12-character ids. |
56
80
  | `resolveObservationalMemorySettings()` | Merge `observational-memory` settings with defaults and overrides. |
57
- | `createObservationalMemoryRuntime()` | Explicitly run observer/reflector/dropper workers for a supplied session, owned append callback, and provider. |
81
+ | `createObservationalMemory()` / `attach()` | One activation wires post-run observe/reflect/drop and `compactAfterTokens` compaction; returns proxied session, runtime, context provider, and strategy. |
82
+ | `createObservationalMemoryRuntime()` | Low-level explicit flush for advanced hosts or tests. |
58
83
  | `createObservationalMemoryCompactionStrategy()` | Render existing folded memory as a standard Prism compaction summary with `data.memory`. |
59
84
  | `createObservationalMemoryExtension()` | Inert extension helper that registers the strategy contribution unless disabled. |
60
- | `createRecallMemoryTool()` | Optional exact-id `recall` tool factory backed by host-supplied current-branch entries. |
85
+ | `createRecallMemoryTool()` | Optional `recall` tool factory: exact id lookup or current-branch message paging via host-supplied entries. |
61
86
  | `createMemoryStatusCommand()` / `createMemoryViewCommand()` | Optional `om:status` and `om:view` command factories. |
62
87
  | `createObservationalMemoryCommands()` | Convenience factory returning status and view commands. |
63
88
 
64
- Pure utilities create no events, workers, tools, commands, credentials, or provider requests. `createObservationalMemoryRuntime()` runs workers only when the host explicitly constructs it and calls `flush()`. The compaction strategy is O(n) over supplied entries and makes no provider call. Tool and command factories are inert until a host registers/selects them.
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. Tool and command factories are inert until a host registers/selects them.
65
90
 
66
91
  ## Request/response example
67
92
 
@@ -74,6 +99,7 @@ Pure utilities create no events, workers, tools, commands, credentials, or provi
74
99
  ```ts
75
100
  import {
76
101
  buildObservationalMemoryProjection,
102
+ createObservationalMemory,
77
103
  createObservationalMemoryCompactionStrategy,
78
104
  createObservationalMemoryExtension,
79
105
  createObservationalMemoryCommands,
@@ -83,6 +109,18 @@ import {
83
109
  renderObservationalMemory,
84
110
  } from "@arnilo/prism-compaction-observational-memory";
85
111
 
112
+ const om = createObservationalMemory({
113
+ observation: { provider: observerProvider, model: observerModel, messageTokens: 10_000 },
114
+ reflection: { provider: reflectorProvider, model: reflectorModel, observationTokens: 20_000 },
115
+ context: { compactAfterTokens: 81_000, recentMessages: 8 },
116
+ retrieval: { pageLimit: 20 },
117
+ });
118
+ const attached = om.attach(session, {
119
+ appendEntry: (entry, options) => store.append(entry, options),
120
+ sessionModel: agent.config.model,
121
+ });
122
+ await attached.session.run("Continue from prior work");
123
+
86
124
  const entries = await session.entries();
87
125
  const projection = buildObservationalMemoryProjection(entries);
88
126
  const summary = renderObservationalMemory(projection.reflections, projection.observations);
@@ -111,13 +149,19 @@ await kernel.load([createObservationalMemoryExtension({ recallTool: { getEntries
111
149
 
112
150
  ## Extension and configuration notes
113
151
 
114
- Settings are read from the `observational-memory` key only when a host calls `resolveObservationalMemorySettings()` or `runtime.flush()`. Defaults are `observeAfterTokens: 10000`, `reflectAfterTokens: 20000`, `compactAfterTokens: 81000`, `observationsPoolMaxTokens: 20000`, `observationsPoolTargetTokens: 10000`, `agentMaxTurns: 16`, `passive: false`, and `debugLog: false`. `agentMaxTurns` now rejects non-integer/non-finite/out-of-range input (hard 64) instead of flooring/falling back. Runtime `maxWorkerTurns` takes precedence.
152
+ Settings resolve to nested `observation` / `reflection` / `dropper` / `context` / `retrieval` groups via `resolveObservationalMemorySettings()`. Defaults: `observation.messageTokens: 10000`, `reflection.observationTokens: 20000`, `context.compactAfterTokens: 81000`, `context.recentMessages: 8`, `context.observationsPoolMaxTokens: 20000`, `dropper.targetTokens: 10000` (from `context.observationsPoolTargetTokens`), `retrieval.pageLimit: 20`, `agentMaxTurns: 16`, `passive: false`, `debugLog: false`. Optional `context.recentMessageMaxTokens` trims the recent-message context window (oldest first) after the count limit.
153
+
154
+ Legacy flat keys still map for pre-1.0 hosts (`observeAfterTokens` → `observation.messageTokens`, `reflectAfterTokens` → `reflection.observationTokens`, `compactAfterTokens` → `context.compactAfterTokens`, `keepRecentEntries` → `context.recentMessages`, flat `workerModel` → all workers when nested models absent). Conflicting flat+nested values throw.
155
+
156
+ Observer/reflector/dropper may use separate providers, models, instructions, thinking levels, credentials, and `requireExplicitModel`. `dropper.policy: "lowest-relevance"` drops deterministically without a model call; default is `"model"`. Top-level `workerProvider` / `workerModel` remain as deprecated aliases.
157
+
158
+ Token counting uses `estimateEntryTokens()` / `estimateMessageTokens()`.
115
159
 
116
- The runtime requires host-supplied `session`, an `appendEntry` callback bound to that session's owning store/branch, and `workerProvider`. Model selection uses [use-case model selection](use-case-model-selection.md): pass optional `workerModel` (or settings `workerModel`) to override, and `sessionModel: agent.config.model` so workers fall back to the session model when no worker model is configured. `requireExplicitModel: true` restores the historical `missing_model` skip when no explicit worker model is set. It no longer accepts a separate `store` option because mismatched session/store pairs can append memory entries outside the active branch. After each memory append, the runtime checks the appended entry is visible at the session leaf and fails closed/restores the previous checkout if the callback points elsewhere. Optional credential resolution is explicit; missing requested credentials skip worker execution. Default credential requests use the **resolved** model's provider id.
160
+ The runtime requires host-supplied `session`, an `appendEntry` callback bound to that session's owning store/branch, and at least one worker provider (`observation.provider` or legacy `workerProvider`). Model selection uses [use-case model selection](use-case-model-selection.md): pass per-worker `model` (or settings `observation.model` / `reflection.model` / `dropper.model`) to override, and `sessionModel: agent.config.model` so workers fall back to the session model when no worker model is configured. `requireExplicitModel: true` restores the historical `missing_model` skip when no explicit worker model is set. It no longer accepts a separate `store` option because mismatched session/store pairs can append memory entries outside the active branch. After each memory append, the runtime checks the appended entry is visible at the session leaf and fails closed/restores the previous checkout if the callback points elsewhere. Optional credential resolution is explicit; missing requested credentials skip worker execution. Default credential requests use the **resolved** model's provider id.
117
161
 
118
- `createObservationalMemoryCompactionStrategy()` keeps recent message entries like the default compaction strategy, renders existing observations/reflections as the summary, and returns a standard Prism compaction entry. Its `data` includes `throughEntryId`, `keepEntryIds`, `strategy`, `trigger`, and `memory: { type: "om.folded", version: 1, fullFold, observations, reflections, droppedObservationIds }`. When active observations exceed `observationsPoolMaxTokens`, it performs a full fold into `data.memory`.
162
+ `createObservationalMemoryCompactionStrategy()` keeps recent message entries like the default compaction strategy, renders existing observations/reflections as the summary, and returns a standard Prism compaction entry. Its `data` includes `throughEntryId`, `keepEntryIds`, `strategy`, `trigger`, and `memory: { type: "om.folded", version: 1, fullFold, observations, reflections, droppedObservationIds }`. When active observations exceed `context.observationsPoolMaxTokens`, it performs a full fold and synchronously trims lowest-relevance observations until the folded payload fits hard byte/token caps (or throws a typed error).
119
163
 
120
- `createRecallMemoryTool()` requires `args.id` to match `^[a-f0-9]{12}$`; invalid ids fail before entry lookup. Recall returns text and structured details for observations/reflections, dropped observations, supporting observations, source entries, and missing source ids. It does not search by topic.
164
+ `createRecallMemoryTool()` accepts either `{ id }` for exact memory recall or `{ cursor, limit?, direction?, detail? }` for current-branch raw-message paging (default limit 20, hard cap 100). Reflection recall resolves supporting observations from the full ledger and reports `droppedSupportingObservationIds` / `missingSupportingObservationIds`; dropped supports still return available raw sources. Invalid ids, ambiguous requests, wrong `sessionId`, missing cursors, non-message cursors, and oversized pages fail closed. It does not search by topic.
121
165
 
122
166
  `createMemoryStatusCommand()` reports recorded/dropped/active/visible observations, recorded/visible reflections, pool token counts, and optional runtime in-flight/last-error state. `createMemoryViewCommand()` renders visible memory by default or full active recorded memory with `{ mode: "full" }`; other modes return `Usage: /om:view [full]`.
123
167
 
package/docs/index.md CHANGED
@@ -25,7 +25,7 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
25
25
  ## Compaction/session memory
26
26
  - [Compaction and retry policies](compaction-and-retry.md): summarize branch history and retry transient provider failures with host-replaceable policies.
27
27
  - [LLM compaction package](compaction-llm.md): optional provider-backed strategy with finite summary/reserve/error caps, bounded redacted streaming retention, mandatory finite post-policy `model.parameters.maxTokens`, and `createCodingCompactionStrategy()` for coding handoff focus.
28
- - [Observational memory compaction package](compaction-observational-memory.md): optional source-backed memory with owned append callback, finite turn/call/argument/result/transcript/error worker limits, redacted provider-valid transcripts, fast compaction, recall, and status/view commands; worker model falls back to host-supplied `sessionModel`.
28
+ - [Observational memory compaction package](compaction-observational-memory.md): optional source-backed memory with explicit `attach()` lifecycle — **Recent exact messages**, **Observation log**, **Reflections**, **Raw-source retrieval** (exact-id recall + cursor paging); dual coverage, nested settings with legacy map, branch-isolated `appendEntry`, secrets redaction, and inert import/extension.
29
29
  - [Working and semantic memory](working-and-semantic-memory.md): optional `@arnilo/prism-memory` working-memory store, semantic recall, finite Embedder/VectorStore contracts, PostgreSQL/pgvector path, consent lifecycle, identity-bound redacted export, and resumable bounded rebuild.
30
30
  - [Session stores](session-stores.md): `SessionStore` contract, `SessionAppendOptions`, `SessionAppendConflictError`, branch handles, `readBranchPath`, optional bounded `searchSessions` / `SessionIndex` (memory linear|unsupported), and dev-vs-production branch reads — start here for session persistence.
31
31
  - [Conversations](conversations.md): durable user-scoped conversation threads (create/list/continue/branch/archive/export/delete) on session + event-ledger seams, thread-bound reconnectable replay, frozen caps, and legal-hold-aware deletion.
@@ -54,7 +54,7 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
54
54
 
55
55
  ## Input, prompt, and context assembly
56
56
  - [SDK customization guide](customization.md): map provider resolution, middleware, context, builders, injectors, loops, compaction, retry, stores, and skills to explicit host-wired APIs.
57
- - [Input and prompt assembly](input-and-prompt-assembly.md): render tiny prompt templates and turn common host input, history, attachments, explicit resources, summaries, and tool results into messages with replaceable builders, provider-input assembly, legacy default order, opt-in cache-aware ordering, and optional `contextBudget` eviction + omission reports. Audio/file/document `ContentBlock` types and capability checks are documented there.
57
+ - [Input and prompt assembly](input-and-prompt-assembly.md): render tiny prompt templates and turn common host input, history, attachments, explicit resources, summaries, and tool results into messages with replaceable builders, provider-input assembly, cache-aware default order, opt-in legacy ordering, and optional `contextBudget` eviction + omission reports. Audio/file/document `ContentBlock` types and capability checks are documented there.
58
58
  - [Multimodal content](multimodal-content.md): complete-request media resolution and aggregate bounds, DNS-classified/address-pinned URLs, SSRF/MIME policy, `ModelCapabilities.input` tags, and first-party content-type mapping.
59
59
  - [System prompts](system-prompts.md): compose explicit user/package/app/run system prompt layers, auto-load the standard `AGENTS.md` (workspace) / `SYSTEM.md` prompt files via the Node `loadSystemPromptFiles` loader (trust-gated for `AGENTS.md`), and append `SYSTEM.md` → per-agent `AGENT.md` body → repo `AGENTS.md` layers from a discovered agent bundle via `resolveAgentBundle`.
60
60
  - [Instruction injection](instruction-injection.md): register package injectors that layer redacted instructions/context blocks without granting tools, permissions, or resource escapes.
@@ -117,8 +117,8 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
117
117
  - `examples/`: compile-checked typed examples and runnable mock demos (SDK basics, provider registration, auth, tools, [`examples/ag-ui-server.ts`](../examples/ag-ui-server.ts), [`examples/enterprise-identity.ts`](../examples/enterprise-identity.ts), [`examples/enterprise-policy-audit.ts`](../examples/enterprise-policy-audit.ts), [`examples/enterprise-work-connectors.ts`](../examples/enterprise-work-connectors.ts), [`examples/conversation-durable-replay.ts`](../examples/conversation-durable-replay.ts), [`examples/artifact-review-delivery.ts`](../examples/artifact-review-delivery.ts), [`examples/server-deployment-seams.ts`](../examples/server-deployment-seams.ts), cache-aware prompt assembly, NeuralWatt agent run ([`examples/neuralwatt-agent-run.ts`](../examples/neuralwatt-agent-run.ts)), [`examples/coding-compaction.ts`](../examples/coding-compaction.ts), stores/branching, structured-output/artifact-loop, CLI, RPC, workflow orchestration).
118
118
 
119
119
  ## Release and install
120
- - [Release and install](release-and-install.md): current **0.0.17** 44-package graph (code-review hardening release; plan 081), exact-peer/install/tarball rules, deterministic resumable publication and publish dry-run, pinned supply-chain gates, offline tests, the 0.0.15 provider/AI-SDK/RAG/memory protected live-canary matrix (still standing for 0.0.16), and sandbox-browser Docker/Playwright gates.
121
- - [0.1.0 / 1.0 readiness gates](0.1.0-readiness.md): command-per-gate 1.0 readiness table — frozen API surface + compat gate, migration coverage 0.0.5→0.0.16, budget table, live-suite matrix, security matrix, the signed-publication/live-canary prerequisites remaining for 1.0, and the Phase 12 demand-evidence entry criteria.
120
+ - [Release and install](release-and-install.md): current **0.0.19** 44-package graph (Phase 2 observational memory lifecycle; plan 002), exact-peer/install/tarball rules, deterministic resumable publication and publish dry-run, pinned supply-chain gates, offline tests, the 0.0.15 provider/AI-SDK/RAG/memory protected live-canary matrix, and sandbox-browser Docker/Playwright gates.
121
+ - [0.1.0 / 1.0 readiness gates](0.1.0-readiness.md): command-per-gate 1.0 readiness table — frozen API surface + compat gate, migration/docs tripwires, budget table, live-suite matrix, security matrix, current-line status (**0.0.19** published target), signed-publication/live-canary prerequisites for 1.0, and Phase 12 demand-evidence entry criteria.
122
122
  - [Review coverage (2026-07-26 Phase 11)](review-coverage-2026-07-26-phase-11.md): Plan 079 evidence freeze — baseline size/startup/benchmark budgets, hotspot domain extraction table, confirmed duplication survivors (redactor/cleanJson/row-codecs/checkpoints/exec-runner/approval/ownership), profile adoption recommendations, and tarball artifact-diet findings for 0.0.16.
123
123
  - [Review coverage (2026-07-26 Phase 10)](review-coverage-2026-07-26-phase-10.md): Plan 078 evidence freeze — OpenAI hosted tools/continuation/realtime, AI SDK version matrix, remaining provider metadata parity, RAG replaceSource/loaders/parsers/reranker/provenance/ingestion-status, memory export/rebuild/conformance, and 0.0.15 (43 → 43 manifests; no new package) release gates.
124
124
  - [Review coverage (2026-07-25 Phase 9)](review-coverage-2026-07-25-phase-9.md): Plan 077 evidence freeze — conversation service, memory consent/lifecycle, artifact co-work review, AG-UI co-work events, scoped M365/GWS OAuth, browser checkpoint composition, and deny-by-default device contracts for 0.0.14 (41 → 43 manifests; only the two provider packages are new).
@@ -18,7 +18,6 @@ Do not use it for tool execution, provider calls, file discovery, credential loo
18
18
  import { createDefaultInputBuilder } from "@arnilo/prism";
19
19
 
20
20
  const messages = await createDefaultInputBuilder().build("Summarize", {
21
- inputLayout: "legacy", // default; "cache_aware" passes the cache-aware layout preference
22
21
  systemInstructions: "Be accurate.",
23
22
  developerInstructions: "Cite supplied context only.",
24
23
  history,
@@ -58,7 +57,7 @@ Useful exported types:
58
57
 
59
58
  - `AgentInput`: `string | Message | readonly Message[]`.
60
59
  - `DefaultInputBuilder`: the default `InputBuilder` with typed default context.
61
- - `InputAssemblyLayout`: `"legacy" | "cache_aware"`; legacy is default.
60
+ - `InputAssemblyLayout`: `"legacy" | "cache_aware"`; `cache_aware` is default.
62
61
  - `DefaultInputBuildContext`: optional input layout, instructions, history, summaries, attachments, resource loader/URIs, tool results, middleware, ids, metadata, and abort signal.
63
62
  - `InputAttachment`: already-loaded text/content blocks (including `audio`, `file`, and `document`) or an explicit URI loaded through a caller-provided `ResourceLoader`.
64
63
  - `PromptInstruction`: labeled system instruction text.
@@ -73,7 +72,7 @@ The builder returns `readonly Message[]`.
73
72
 
74
73
  - String input becomes one user text message.
75
74
  - `Message` and `Message[]` input are preserved.
76
- - Legacy layout is the default. Set `inputLayout: "cache_aware"` on the default builder, `assembleProviderInput()`, `AgentConfig`, or `RunOptions` to pass the cache-aware layout preference without replacing the builder.
75
+ - `cache_aware` layout is the default. Set `inputLayout: "legacy"` on the default builder, `assembleProviderInput()`, `AgentConfig`, or `RunOptions` to restore the prior order.
77
76
 
78
77
  | Layout | Input message order |
79
78
  | --- | --- |
@@ -87,8 +86,7 @@ The default prompt builder still prepends context, selected skills, and tool dec
87
86
  - Tool results are tool messages containing `tool_result` content; the agent/session runtime uses this to feed dispatched tool results into the next provider turn, placing the assistant `tool_call` and the matching role `tool` `tool_result` before any final assistant content. Cache-aware layout keeps tool results before the current user suffix so it does not split tool transcripts.
88
87
  - Middleware runs only when `middleware` is supplied in the context.
89
88
  - `assembleProviderInput()` returns a `ProviderRequest` with the caller's model/tools/provider options/metadata/signal and composed messages/context. It also calls `assertMessagesSupportModelCapabilities()` so unsupported `audio`/`file`/`document`/`image` blocks fail with `UnsupportedModalityError` when the model declares `capabilities.input`.
90
- - Optional `contextBudget` (at least one of `maxInputTokens` / `maxInputBytes`) runs after default message groups are built and before final flatten. Eviction drops droppable sections first (toolResults → history → summaries → context → skills → attachments; layout-aware). Protected instructions + current user `input` (+ tools catalog) fail closed with `ContextBudgetError` if they alone exceed the budget. When `reportOmissions: true`, attach `ProviderRequest.metadata[CONTEXT_BUDGET_REPORT_METADATA_KEY]` and read via `getContextBudgetReport(request)` (kinds/ids/sizes only — no secrets). Raw session store entries are never deleted.
91
- - Optional `contextBudget` (at least one of `maxInputTokens` / `maxInputBytes`) runs after default message groups are built and before final flatten. Eviction drops droppable sections first (toolResults → history → summaries → context → skills → attachments; layout-aware). Protected instructions + current user `input` (+ tools catalog) fail closed with `ContextBudgetError` if they alone exceed the budget. When `reportOmissions: true`, attach `ProviderRequest.metadata[CONTEXT_BUDGET_REPORT_METADATA_KEY]` and read via `getContextBudgetReport(request)` (kinds/ids/sizes only — no secrets). Raw session store entries are never deleted.
89
+ - Optional `contextBudget` (at least one of `maxInputTokens` / `maxInputBytes`) runs after default message groups are built and before final flatten. Eviction drops droppable sections first (toolResults → history → summaries → context → skills → attachments; layout-aware). Within `history`, oldest messages drop first. Protected instructions + current user `input` (+ tools catalog) fail closed with `ContextBudgetError` if they alone exceed the budget. When `reportOmissions: true`, attach `ProviderRequest.metadata[CONTEXT_BUDGET_REPORT_METADATA_KEY]` and read via `getContextBudgetReport(request)` (kinds/ids/sizes only — no secrets). Raw session store entries are never deleted.
92
90
  - `renderPromptTemplate()` replaces top-level `{{name}}` variables with caller-supplied JSON-compatible values. Strings are inserted directly; numbers, booleans, `null`, arrays, and objects are stringified deterministically with sorted object keys. Missing variables throw by default or stay unchanged with `{ missing: "preserve" }`.
93
91
 
94
92
  ## Request/response example
package/docs/mcp-tools.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- `@arnilo/prism-mcp` has two explicit directions. Its client bridge connects hosts to remote [Model Context Protocol](https://modelcontextprotocol.io) servers and maps discovered tools to ordinary `ToolDefinition`s. Its server API registers selected Prism `ToolDefinition` and `CommandDefinition` values on the official SDK `McpServer`, with required authorization and a bounded optional Web-standard Streamable HTTP handler. The package pins `@modelcontextprotocol/sdk` **1.29.0** (MCP protocol negotiation remains SDK-owned) and adds no MCP branch to core Prism.
5
+ `@arnilo/prism-mcp` has two explicit directions. Its client bridge connects hosts to remote [Model Context Protocol](https://modelcontextprotocol.io) servers and maps discovered tools to ordinary `ToolDefinition`s. Its server API registers selected Prism `ToolDefinition` and `CommandDefinition` values on the official SDK `McpServer`, with required authorization and a bounded optional Web-standard Streamable HTTP handler. The package pins `@modelcontextprotocol/sdk` **1.30.0** (MCP protocol negotiation remains SDK-owned) and adds no MCP branch to core Prism.
6
6
 
7
7
  Primary API:
8
8
 
@@ -33,7 +33,7 @@ await bridge.listResources();
33
33
  await bridge.getPrompt("review", { topic: "security" });
34
34
  ```
35
35
 
36
- Server capability matrix for SDK 1.29.0: tools/resources/prompts and their list-change notifications are supported through official registrations; roots/sampling/form+URL elicitation are supported as explicit client callbacks. Missing server resources/prompts throw `McpUnsupportedCapabilityError` with `ERR_PRISM_MCP_UNSUPPORTED_CAPABILITY`. Resource/prompt results and sampling/elicitation inputs/results are bounded JSON. Accepted form/URL elicitation requires host-only `humanInteraction: true`; bridge strips marker before protocol output and fails closed when absent. Automatic root discovery/consent, model selection, credential resolution, URL navigation, generic command proxying, and custom JSON-RPC are unsupported.
36
+ Server capability matrix for SDK 1.30.0: tools/resources/prompts and their list-change notifications are supported through official registrations; roots/sampling/form+URL elicitation are supported as explicit client callbacks. Missing server resources/prompts throw `McpUnsupportedCapabilityError` with `ERR_PRISM_MCP_UNSUPPORTED_CAPABILITY`. Resource/prompt results and sampling/elicitation inputs/results are bounded JSON. Accepted form/URL elicitation requires host-only `humanInteraction: true`; bridge strips marker before protocol output and fails closed when absent. Automatic root discovery/consent, model selection, credential resolution, URL navigation, generic command proxying, and custom JSON-RPC are unsupported.
37
37
 
38
38
  Server direction:
39
39
 
@@ -61,7 +61,7 @@ const handleMcp = await createPrismMcpWebHandler(server, {
61
61
  });
62
62
  ```
63
63
 
64
- `McpServer.connect(transport)` remains available for SDK stdio or in-memory transports. The helper uses SDK `WebStandardStreamableHTTPServerTransport`; it does not start a listener. Default remains bounded stateless JSON-response mode. Supplying `sessionIdGenerator` enables SDK `MCP-Session-Id` POST/GET/DELETE/SSE lifecycle and requires exact `allowedOrigins` plus host `resolveIdentity`. Every request re-authenticates, and a different principal receives non-disclosing 404. SDK owns protocol-version/session headers and SSE semantics. SDK 1.29.0's in-memory event store is not enabled, so `Last-Event-ID` replay is explicitly unsupported; reconnect starts only through SDK-supported active session GET.
64
+ `McpServer.connect(transport)` remains available for SDK stdio or in-memory transports. The helper uses SDK `WebStandardStreamableHTTPServerTransport`; it does not start a listener. Default remains bounded stateless JSON-response mode. Supplying `sessionIdGenerator` enables SDK `MCP-Session-Id` POST/GET/DELETE/SSE lifecycle and requires exact `allowedOrigins` plus host `resolveIdentity`. Every request re-authenticates, and a different principal receives non-disclosing 404. SDK owns protocol-version/session headers and SSE semantics. SDK 1.30.0's in-memory event store is not enabled, so `Last-Event-ID` replay is explicitly unsupported; reconnect starts only through SDK-supported active session GET.
65
65
 
66
66
  ## When to use it
67
67
 
package/docs/migration.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Migration guide
2
2
 
3
+ ## 0.0.18 → 0.0.19 observational memory lifecycle (small intentional breaks)
4
+
5
+ Release **0.0.19** completes Phase 2 observational memory in `@arnilo/prism-compaction-observational-memory` only; core `@arnilo/prism` runtime behavior is unchanged.
6
+
7
+ 1. **Preferred host path: `createObservationalMemory().attach()`.** Post-run observe/reflect/drop and `compactAfterTokens` compaction run automatically after proxied `run`/`prompt`/`stream`/`compact` (and via `wrapResumeRun` / `wrapResumeStream`). Manual `createObservationalMemoryRuntime().flush()` remains on `attached.runtime` for advanced hosts.
8
+ 2. **Nested settings replace flat keys.** Use `observation` / `reflection` / `dropper` / `context` / `retrieval` groups from `resolveObservationalMemorySettings()`. Legacy flat keys still map (`observeAfterTokens` → `observation.messageTokens`, `reflectAfterTokens` → `reflection.observationTokens`, `compactAfterTokens` → `context.compactAfterTokens`, `keepRecentEntries` → `context.recentMessages`, flat `workerModel` → all workers when nested models absent). **Throw** if flat and nested values conflict.
9
+ 3. **Separate observer/reflector/dropper models.** Pass per-worker `provider` / `model` / `instruction` / `thinkingLevel` under `observation`, `reflection`, and `dropper`. `dropper.policy: "lowest-relevance"` drops without a model; default is `"model"`.
10
+ 4. **Reflection recall reads the full ledger.** Supporting observations dropped from the active pool still resolve in `recallObservationalMemory()` with `dropped` / `missingSourceEntryIds` status instead of being invisible.
11
+ 5. **Recall tool adds current-branch paging.** `createRecallMemoryTool()` accepts either `{ id }` or `{ cursor, limit?, direction?, detail? }` (default limit 20, hard cap 100). Both `id` and `cursor` together fail closed.
12
+ 6. **Coverage and eligibility fixes.** Observer input is eligible `user`/`assistant`/`tool` messages only; bookkeeping/compaction/custom OM entries advance scan coverage without entering the prompt. Empty observer passes still append `coversUpToId`. Compaction `fullFold` actively trims lowest-relevance observations to hard byte caps.
13
+
14
+ Example: `node examples/observational-memory-lifecycle.ts` (network-free). Live worker canary: `PRISM_LIVE_OBSERVATIONAL_MEMORY_TESTS=1` (Task 7 gate).
15
+
16
+ ## 0.0.17 → 0.0.18 restore integrity (small intentional break)
17
+
18
+ Release **0.0.18** removes model-facing regex from `repo_search`:
19
+
20
+ 1. **`repo_search` literal only.** The tool schema no longer advertises `mode: "regex"`. Passing `mode: "regex"` returns a bounded tool error. `compileSearchPattern(query, caseSensitive, maxPatternBytes)` dropped the `mode` argument; hosts calling it with the old signature must update imports. Use literal substring search or a host-owned search backend for regex needs.
21
+ 2. **`write` / `edit` crash-safe replace.** Default local operations write to a same-directory `.prism-write-*` temp file then `rename` onto the target, so a crash mid-write cannot truncate the original. Happy-path ToolResult shape unchanged. Custom `WriteOperations` / `EditOperations` should provide equivalent durability.
22
+ 3. **`contextBudget` history eviction.** Under pressure, `applyContextBudget` drops oldest history messages first (not newest). Hosts that relied on newest-first history retention under budget should revisit eviction expectations.
23
+ 4. **Default `inputLayout` is `cache_aware`.** Unset `AgentConfig.inputLayout` / `RunOptions.inputLayout` now use cache-stable ordering (attachments/resources and tool results before current input). Set `inputLayout: "legacy"` to restore the prior order.
24
+ 5. **`@arnilo/prism-mcp` SDK bump.** `@modelcontextprotocol/sdk` is pinned to **1.30.0** (from 1.29.0), clearing the moderate `@hono/node-server` path-traversal advisory on the MCP HTTP transport. No Prism MCP public API signature changes; hosts pinning the SDK independently should align to 1.30.0+.
25
+
26
+ Docs-only: README provider inventory (14 adapters), optional `@arnilo/prism-browser` wording, and `docs/0.1.0-readiness.md` current-line status were corrected; no runtime behavior change beyond the items above.
27
+
3
28
  ## 0.0.16 → 0.0.17 code-review hardening (small intentional breaks)
4
29
 
5
30
  Release **0.0.17** implements the 2026-07-29 full implementation review (plan 081): twenty fixes across durable runs, guardrails, retry, extension lifecycle, CLI, and provider plumbing. Most changes are additive or internal; four intentionally change existing behavior:
@@ -55,7 +80,7 @@ Realtime is opt-in through `createOpenAIRealtimeSession({ model, ownerId, apiKey
55
80
 
56
81
  ## 0.0.14 → 0.0.15 AI SDK adapter matrix (additive, pre-release)
57
82
 
58
- `@arnilo/prism-provider-ai-sdk` now pins and verifies `@ai-sdk/provider@4.0.3` at setup rather than accepting any v4 minor. Upgrade the peer package to the documented matrix entry. An unlisted installed version fails with typed `AiSdkProviderError` code `unsupported_version`; add a tested matrix row before changing it.
83
+ `@arnilo/prism-provider-ai-sdk` now pins and verifies `@ai-sdk/provider@4.0.4` at setup (matrix also lists `4.0.3`) rather than accepting any v4 minor. Upgrade the peer package to the documented matrix entry. An unlisted installed version fails with typed `AiSdkProviderError` code `unsupported_version`; add a tested matrix row before changing it.
59
84
 
60
85
  Stream output now maps `response-metadata.id` to `message_start`, preserves `providerExecuted` tool authority as `"provider-hosted"`, and rejects unsupported output parts or `structuredOutput.strict` with `unsupported_mapping` rather than dropping them. Pass `redactor` when using the adapter directly; agents retain their existing active-redactor behavior.
61
86
 
@@ -66,7 +66,7 @@ Cache helpers return plain data:
66
66
 
67
67
  Provider events do not change. Cache accounting stays in normalized `Usage.cacheReadTokens` and `Usage.cacheWriteTokens`.
68
68
 
69
- For stable-prefix payloads, set `inputLayout: "cache_aware"` on the default input builder, `assembleProviderInput()`, `AgentConfig`, or `RunOptions`. The default prompt builder already places context, selected skills, and tool declarations before input messages; cache-aware input ordering then places attachments/resources, summaries, prior history, and pending tool results before the current user suffix. The prefix is byte-stable only when those stable inputs are unchanged; Prism still does not guarantee provider cache hits.
69
+ For stable-prefix payloads, `inputLayout: "cache_aware"` is the default on the default input builder, `assembleProviderInput()`, `AgentConfig`, and `RunOptions`; set `inputLayout: "legacy"` to restore the prior order. The default prompt builder already places context, selected skills, and tool declarations before input messages; cache-aware input ordering then places attachments/resources, summaries, prior history, and pending tool results before the current user suffix. The prefix is byte-stable only when those stable inputs are unchanged; Prism still does not guarantee provider cache hits.
70
70
 
71
71
  ## Request/response example
72
72
 
@@ -28,7 +28,7 @@ Offline conformance is mandatory for every package; credentialed probes are not
28
28
  | Package | Required offline evidence | Restricted live evidence |
29
29
  | --- | --- | --- |
30
30
  | OpenAI | Responses serialization/stream ordering, provider-hosted authority, continuation cap/cursor, Realtime fake WebSocket caps | Standard API-key smoke; separate protected hosted-tool/Realtime entitlement probe |
31
- | AI SDK | Exact 4.0.3/V4 gate; every mapped stream part; authority, cache usage, redaction, unsupported mapping | Host-created V4 model only; no Prism credential fixture |
31
+ | AI SDK | Exact 4.0.4/V4 gate (`4.0.3` also listed); every mapped stream part; authority, cache usage, redaction, unsupported mapping | Host-created V4 model only; no Prism credential fixture |
32
32
  | Anthropic | Messages serialization, cache/thinking/tools, header/redaction/abort assertions | Protected `ANTHROPIC_API_KEY` smoke |
33
33
  | Google | `generateContent` serialization, complete tool calls, media/abort/redaction assertions | Protected `GOOGLE_API_KEY` or `GEMINI_API_KEY` smoke |
34
34
  | Kimi | Coding/Moonshot route fixtures, thinking/tool reconstruction, headers/redaction | Protected `KIMI_API_KEY` smoke |
@@ -89,7 +89,7 @@ Every package remains explicit, setup-zero-fetch, and late-credential-bound. `Mo
89
89
  | Package | Protocol / model source | Content mapping | Stream, tools, and reasoning | Cache / canary |
90
90
  | --- | --- | --- | --- | --- |
91
91
  | OpenAI | Responses; featured or caller-gated `listOpenAIModels` | text, image, audio, file, document | Host and provider-hosted tools; 8-hop continuation; Realtime seam; Responses reasoning | `openai_key`; checked-in standard smoke + protected hosted/Realtime probe |
92
- | AI SDK | Host `LanguageModelV4`; no Prism catalog | declared text/image/audio/file/document prompt parts (role-limited) | v4 mapping; provider-executed tool authority; host-owned reasoning | host-owned; exact 4.0.3 matrix; protected host integration |
92
+ | AI SDK | Host `LanguageModelV4`; no Prism catalog | declared text/image/audio/file/document prompt parts (role-limited) | v4 mapping; provider-executed tool authority; host-owned reasoning | host-owned; exact 4.0.4 matrix (`4.0.3` also listed); protected host integration |
93
93
  | Anthropic | Messages; caller-gated list | text, image, PDF document/file | tool deltas, thinking | `cache_control`; protected API-key smoke |
94
94
  | Google | Gemini `generateContent`; caller-gated list | text, image, audio, document/file | complete tool calls, thinking | no Prism cache marker; protected API-key smoke |
95
95
  | Kimi | Coding Messages or opt-in Moonshot; caller-gated list | text, image, PDF document/file by route/model | tool deltas, route-native thinking replay | implicit / optional Anthropic markers; protected API-key smoke |
@@ -11,6 +11,7 @@ Core `@arnilo/prism` does not depend on the AI SDK.
11
11
  | `@ai-sdk/provider` | `LanguageModel` ABI | Status |
12
12
  | --- | --- | --- |
13
13
  | `4.0.3` | `LanguageModelV4`, `specificationVersion: "v4"` | Supported and offline-tested |
14
+ | `4.0.4` | `LanguageModelV4`, `specificationVersion: "v4"` | Supported and offline-tested |
14
15
 
15
16
  The peer dependency is intentionally exact. `createAiSdkProvider()` reads its resolved `@ai-sdk/provider/package.json` version during setup and throws typed `AiSdkProviderError { code: "unsupported_version" }` for an unlisted version; it does not infer compatibility from a matching `"v4"` string.
16
17
 
@@ -143,7 +144,7 @@ Official evidence: [Custom providers / LanguageModelV4](https://ai-sdk.dev/provi
143
144
 
144
145
  ## Extension and configuration notes
145
146
 
146
- - Peer dependency: `@ai-sdk/provider@4.0.3`. Upgrade policy adds a matrix row and offline conformance fixture before accepting any new version.
147
+ - Peer dependency: `@ai-sdk/provider@4.0.4` (matrix also lists `4.0.3`). Upgrade policy adds a matrix row and offline conformance fixture before accepting any new version.
147
148
  - First-party HTTP providers remain independent; this adapter is available directly, through `@arnilo/prism-providers`, or through `@arnilo/prism-all`. Installation does not select a model or invoke AI SDK.
148
149
  - `options.compat` / `options.extra` pass through as AI SDK `providerOptions.prism`.
149
150
  - Export helpers `toAiSdkCallOptions`, `toAiSdkPrompt`, and `mapAiSdkStream` for tests and custom hosts.
@@ -122,7 +122,7 @@ Important request shapes:
122
122
  | `ToolRegistry` | Host active tool registry shape: `register()`, `get()`, `resolve()`, and `list()`. |
123
123
  | `ToolExecutionContext` | Host tool execution context: session/run ids, tool call id, optional abort signal, metadata, and progress callback. |
124
124
  | `ContextResolutionContext` | Context provider input: messages plus optional session/run ids, metadata, and signal. |
125
- | `InputAssemblyLayout` | Default input layout selector: `"legacy"` (default) or opt-in `"cache_aware"`. |
125
+ | `InputAssemblyLayout` | Default input layout selector: `"cache_aware"` (default) or opt-in `"legacy"`. |
126
126
  | `DefaultInputBuildContext` | Optional default input assembly context: input layout, instructions, history, summaries, attachments, explicit resources, tool results, middleware, ids, metadata, and signal. |
127
127
  | `ResolveContextOptions` | Ordered context resolution input: selected providers, messages, ids, metadata, signal, and optional middleware. |
128
128
  | `AssembleProviderInputOptions` | Provider input assembly input: model, input, optional builders, selected context providers/skills, active tools, metadata, and signal. |
@@ -8,7 +8,7 @@ Core package:
8
8
 
9
9
  - `@arnilo/prism` — the runtime, contracts, registries, streaming events, CLI (including `prism init`), and the `/docs` hub. `files`: `dist` (with `!dist/__tests__` and `!dist/**/*.map` negations), `docs`, `templates`, `CHANGELOG.md`. `bin`: `prism` -> `dist/cli.js`. `sideEffects`: `["dist/cli.js"]`.
10
10
 
11
- First-party workspace packages (each has non-optional `@arnilo/prism@0.0.17` peer and `sideEffects: false`; RAG also peers on memory, and server also peers on workflows):
11
+ First-party workspace packages (each has non-optional `@arnilo/prism@0.0.19` peer and `sideEffects: false`; RAG also peers on memory, and server also peers on workflows):
12
12
 
13
13
  - `@arnilo/prism-provider-anthropic`, `@arnilo/prism-provider-google`, `@arnilo/prism-provider-openai`, `@arnilo/prism-provider-openrouter`, `@arnilo/prism-provider-kimi`, `@arnilo/prism-provider-zai`, `@arnilo/prism-provider-opencode-go`, `@arnilo/prism-provider-neuralwatt` — provider adapters.
14
14
  - `@arnilo/prism-provider-azure`, `@arnilo/prism-provider-bedrock`, `@arnilo/prism-provider-vertex` — optional enterprise-cloud adapters (Entra/IAM/ADC; separate from consumer Anthropic/Google).
@@ -36,7 +36,7 @@ First-party workspace packages (each has non-optional `@arnilo/prism@0.0.17` pee
36
36
 
37
37
  ### 0.0.12 AG-UI package boundary
38
38
 
39
- `@arnilo/prism-ag-ui` is a publishable optional code package with root AG-UI exports and stable `./acp` sibling, peer `@arnilo/prism@0.0.17`, pinned `@ag-ui/core@0.0.57` / `@agentclientprotocol/sdk@1.3.0`, and no import-time network/listener/run. It is included by `@arnilo/prism-all` only—not `@arnilo/prism-code` or `@arnilo/prism-sdk`—so coding and SDK profiles stay free of UI protocol dependencies.
39
+ `@arnilo/prism-ag-ui` is a publishable optional code package with root AG-UI exports and stable `./acp` sibling, peer `@arnilo/prism@0.0.19`, pinned `@ag-ui/core@0.0.57` / `@agentclientprotocol/sdk@1.3.0`, and no import-time network/listener/run. It is included by `@arnilo/prism-all` only—not `@arnilo/prism-code` or `@arnilo/prism-sdk`—so coding and SDK profiles stay free of UI protocol dependencies.
40
40
 
41
41
  Family/profile packages (pure manifests, no code or `dist`; ship `README.md` and `CHANGELOG.md`; use exact hard `dependencies`):
42
42
 
@@ -78,9 +78,9 @@ Consumers install the core package for the runtime and add first-party packages
78
78
  | Run the default (network-free) test suite | `npm test` |
79
79
  | Dry-run pack core + every package | `npm run pack:dry-run` |
80
80
  | Local mirror of the release verify gate | `npm run release:dry-run` |
81
- | Validate clean tag/version/ranges and reject registry collisions | `npm run release:check -- --version 0.0.17` |
82
- | Preview deterministic publish order | `npm run release:publish -- --version 0.0.17 --dry-run --allow-dirty --allow-untagged` |
83
- | Resume interrupted tagged publication | `npm run release:publish -- --version 0.0.17 --resume --report release-artifacts/publish-report.json` |
81
+ | Validate clean tag/version/ranges and reject registry collisions | `npm run release:check -- --version 0.0.19` |
82
+ | Preview deterministic publish order | `npm run release:publish -- --version 0.0.19 --dry-run --allow-dirty --allow-untagged` |
83
+ | Resume interrupted tagged publication | `npm run release:publish -- --version 0.0.19 --resume --report release-artifacts/publish-report.json` |
84
84
  | Full SDK readiness gate (typecheck + offline tests + pack) | `npm run sdk:ready` |
85
85
 
86
86
  Public core import specifiers (from the root `exports` map):
@@ -117,7 +117,7 @@ A packed tarball contains only public compiled output and release files:
117
117
  - Code packages ship `README.md`, `LICENSE`, and `CHANGELOG.md`; family/profile packages ship `README.md` and `CHANGELOG.md`.
118
118
  - The core tarball additionally ships the full `docs/` directory (the docs hub) and `templates/init/` used by `prism init`.
119
119
  - `dist/cli.js` and the `bin` link in core.
120
- - **Tarball filenames.** npm strips the `@scope/` prefix, so the core package `@arnilo/prism` produces a tarball named `arnilo-prism-0.0.17.tgz`; first-party packages produce `arnilo-prism-provider-<name>-0.0.17.tgz` / `arnilo-prism-compaction-<name>-0.0.17.tgz` / `arnilo-prism-coding-agent-0.0.17.tgz`; family/profile packages produce `arnilo-prism-{providers,compaction,base,code,sdk,all}-0.0.17.tgz`. The CLI bin name `prism` is unaffected by the package name (`npx prism` still works; npm allows the bin field to differ from the package name).
120
+ - **Tarball filenames.** npm strips the `@scope/` prefix, so the core package `@arnilo/prism` produces a tarball named `arnilo-prism-0.0.19.tgz`; first-party packages produce `arnilo-prism-provider-<name>-0.0.19.tgz` / `arnilo-prism-compaction-<name>-0.0.19.tgz` / `arnilo-prism-coding-agent-0.0.19.tgz`; family/profile packages produce `arnilo-prism-{providers,compaction,base,code,sdk,all}-0.0.19.tgz`. The CLI bin name `prism` is unaffected by the package name (`npx prism` still works; npm allows the bin field to differ from the package name).
121
121
 
122
122
  Excluded from every tarball by `files` negation:
123
123
 
@@ -136,9 +136,9 @@ Excluded from every tarball by `files` negation:
136
136
  "name": "host-app",
137
137
  "type": "module",
138
138
  "dependencies": {
139
- "@arnilo/prism": "0.0.17",
140
- "@arnilo/prism-provider-openai": "0.0.17",
141
- "@arnilo/prism-compaction-observational-memory": "0.0.17"
139
+ "@arnilo/prism": "0.0.19",
140
+ "@arnilo/prism-provider-openai": "0.0.19",
141
+ "@arnilo/prism-compaction-observational-memory": "0.0.19"
142
142
  }
143
143
  }
144
144
  ```
@@ -181,11 +181,11 @@ For SDK readiness, run the same one-command gate directly. It composes existing
181
181
  npm run sdk:ready
182
182
  ```
183
183
 
184
- Release publication derives all **44** manifests from the workspace once, validates exact `0.0.16` manifest/lockfile/internal ranges, then uses deterministic dependency order. `release:check` requires a clean commit tagged `v0.0.16` and rejects any existing registry version. `release:publish --resume` skips only registry versions whose internal dependency fingerprint matches the local manifest; conflicting versions fail closed. Each attempted package is written immediately to the JSON report, so a failed job can rerun safely. `--dry-run` performs registry availability checks and invokes `npm publish --dry-run` with explicit public access, provenance, and `latest` tag, but does not publish.
184
+ Release publication derives all **44** manifests from the workspace once, validates exact `0.0.19` manifest/lockfile/internal ranges, then uses deterministic dependency order. `release:check` requires a clean commit tagged `v0.0.19` and rejects any existing registry version. `release:publish --resume` skips only registry versions whose internal dependency fingerprint matches the local manifest; conflicting versions fail closed. Each attempted package is written immediately to the JSON report, so a failed job can rerun safely. `--dry-run` performs registry availability checks and invokes `npm publish --dry-run` with explicit public access, provenance, and `latest` tag, but does not publish.
185
185
 
186
186
  ```bash
187
- npm run release:check -- --version 0.0.17
188
- npm run release:publish -- --version 0.0.17 --dry-run --allow-dirty --allow-untagged
187
+ npm run release:check -- --version 0.0.19
188
+ npm run release:publish -- --version 0.0.19 --dry-run --allow-dirty --allow-untagged
189
189
  ```
190
190
 
191
191
  `--allow-dirty` and `--allow-untagged` exist only for local preview; real publication and CI never pass them. npm registry calls occur only in these release preflight/publication commands, never build/test/package discovery.
@@ -196,6 +196,48 @@ Optional live smoke tests stay separate from SDK readiness because they require
196
196
  PRISM_LIVE_PROVIDER_TESTS=1 npm run test --workspaces --if-present
197
197
  ```
198
198
 
199
+ ### 0.0.19 publish handoff
200
+
201
+ **Decision: GO after protected operator prerequisites below.** Release **0.0.19** (Phase 2 observational memory lifecycle, plan 002) ships `@arnilo/prism-compaction-observational-memory` attach lifecycle, four-layer provider context, nested settings with legacy map, source-faithful recall/paging, and hard fold/render caps. Core `@arnilo/prism` runtime is unchanged. The exact graph stays **44 publishable manifests**; no package added or retired. Intentional pre-1.0 breaks are documented in [migration](migration.md) under `0.0.18 → 0.0.19 observational memory lifecycle`.
202
+
203
+ ```bash
204
+ git diff --check
205
+ npm ci
206
+ npm run sdk:ready
207
+ node --test scripts/budget-gate.test.mjs
208
+ node scripts/scan-secrets.mjs && node scripts/verify-sbom.mjs
209
+ npm audit --audit-level=moderate
210
+ npm run release:gate
211
+ npm run release:check -- --version 0.0.19 --allow-dirty --allow-untagged --report /tmp/prism-0.0.19-preflight.json
212
+ npm run release:publish -- --version 0.0.19 --dry-run --allow-dirty --allow-untagged --report /tmp/prism-0.0.19-dry-run.json
213
+ git tag -s v0.0.19 -m "Prism 0.0.19"
214
+ git verify-tag v0.0.19
215
+ git push origin v0.0.19
216
+ ```
217
+
218
+ The dry-run checks every registry collision and executes npm's non-publishing tarball validation for each dependency-ordered manifest. The protected tag workflow alone publishes through `npm run release:publish -- --version "${GITHUB_REF_NAME#v}" --resume --report release-artifacts/publish-report.json`; re-run a failed job for the same tag. `npm audit signatures --json --include-attestations` and artifact checksums remain post-publish checks.
219
+
220
+ ### 0.0.18 publish handoff
221
+
222
+ **Decision: GO after protected operator prerequisites below.** Release **0.0.18** (Phase 1 restore integrity, plan 001) hardens coding tools and release trust without adding packages: `repo_search` is literal-only (ReDoS mitigation), default `write`/`edit` use temp+`rename`, `applyContextBudget` evicts oldest history first, default `inputLayout` is `cache_aware`, `@arnilo/prism-mcp` pins `@modelcontextprotocol/sdk` **1.30.0** (clears moderate `@hono/node-server` advisory), and README/readiness docs match the 14-adapter / optional-browser inventory. The exact graph stays **44 publishable manifests**; no package added or retired. Intentional pre-1.0 breaks are documented in [migration](migration.md) under `0.0.17 → 0.0.18 restore integrity`.
223
+
224
+ ```bash
225
+ git diff --check
226
+ npm ci
227
+ npm run sdk:ready
228
+ node --test scripts/budget-gate.test.mjs
229
+ node scripts/scan-secrets.mjs && node scripts/verify-sbom.mjs
230
+ npm audit --audit-level=moderate
231
+ npm run release:gate
232
+ npm run release:check -- --version 0.0.18 --allow-dirty --allow-untagged --report /tmp/prism-0.0.18-preflight.json
233
+ npm run release:publish -- --version 0.0.18 --dry-run --allow-dirty --allow-untagged --report /tmp/prism-0.0.18-dry-run.json
234
+ git tag -s v0.0.18 -m "Prism 0.0.18"
235
+ git verify-tag v0.0.18
236
+ git push origin v0.0.18
237
+ ```
238
+
239
+ The dry-run checks every registry collision and executes npm's non-publishing tarball validation for each dependency-ordered manifest. The protected tag workflow alone publishes through `npm run release:publish -- --version "${GITHUB_REF_NAME#v}" --resume --report release-artifacts/publish-report.json`; re-run a failed job for the same tag. `npm audit signatures --json --include-attestations` and artifact checksums remain post-publish checks.
240
+
199
241
  ### 0.0.17 publish handoff
200
242
 
201
243
  **Decision: GO after protected operator prerequisites below.** Release 0.0.17 implements the 2026-07-29 full implementation review (plan 081, twenty fixes): durable run-state load bound, explicit resume-as-approval, unconditional `input_assembly` middleware, same-session parent enforcement, jitter + `Retry-After`-aware retries with provider error wiring, O(n) context-budget eviction, fingerprint coverage of instructions/system prompt/skills, stage-named guardrail interrupts with `metadata.error`, `steer_rejected`, middleware double-`next()` detection, parked-consumer sorted multiplexer delivery, checkpoint-store bounds, strict credential opt-in, extension `unregister`/dispose handles with failed-setup unwind, loud CLI rejection of inert flags, capability-conditional tool listing, and the C8 nit bundle. The exact graph stays **44 publishable manifests**; no package added or retired. Intentional pre-1.0 breaks are documented in [migration](migration.md): inert CLI flags rejected (`CliOptions` dead fields removed) and `ExtensionKernel.load()` now resolves to `LoadedExtension[]`. The compat baseline was refreshed with `--allow-break` + migration note. Provider HTTP errors now carry numeric codes and `Retry-After` hints across anthropic/google/kimi/openai/opencode-go and the shared OpenAI-compatible transport — wire behavior is additive (more retries of genuinely transient failures), so the 0.0.15 protected live-canary matrix below still applies and no new live row is introduced.
@@ -253,7 +295,7 @@ Default `npm test`, `npm run sdk:ready`, and `benchmark-0.0.15` are network-free
253
295
  | --- | --- | --- | --- |
254
296
  | OpenAI Responses baseline | `PRISM_LIVE_PROVIDER_TESTS=1` + `OPENAI_API_KEY` | `npm test -w @arnilo/prism-provider-openai` | Bounded text/tool/abort smoke; key never enters events. |
255
297
  | OpenAI hosted tools + Realtime | `OPENAI_API_KEY`; protected release harness additionally supplies host-owned safety identifier and hosted-tool entitlement | No generic fixture; record result with the release evidence | Provider-hosted `web_search`/similar execution and Realtime audio/interruption need account-specific availability, so fake transport coverage remains default gate. |
256
- | AI SDK adapter | Host-selected AI SDK v4 model factory plus its provider credential | No generic fixture; run host integration in protected release environment | Exact `@ai-sdk/provider@4.0.3` mapping/version check; Prism does not own upstream model credentials. |
298
+ | AI SDK adapter | Host-selected AI SDK v4 model factory plus its provider credential | No generic fixture; run host integration in protected release environment | Exact `@ai-sdk/provider@4.0.4` mapping/version check; Prism does not own upstream model credentials. |
257
299
  | Kimi / Moonshot | `PRISM_LIVE_PROVIDER_TESTS=1` + `KIMI_API_KEY` | `npm test -w @arnilo/prism-provider-kimi` | Coding route; Moonshot entitlement is account-specific. |
258
300
  | Z.AI | `PRISM_LIVE_PROVIDER_TESTS=1` + `ZAI_API_KEY` | `npm test -w @arnilo/prism-provider-zai` | GLM stream/tool/reasoning smoke. |
259
301
  | OpenRouter | `PRISM_LIVE_PROVIDER_TESTS=1` + `OPENROUTER_API_KEY` | `npm test -w @arnilo/prism-provider-openrouter` | Routed stream/model metadata smoke; host chooses permitted route. |
@@ -772,7 +814,7 @@ npm publication is not transactional and published versions are immutable. Parti
772
814
 
773
815
  ## Extension and configuration notes
774
816
 
775
- - **Required `@arnilo/prism` peer.** Every first-party code package declares a non-optional `@arnilo/prism@0.0.17` peer (`peerDependenciesMeta` must not mark `@arnilo/prism` optional; other peers such as `playwright-core` may be optional). The range stays pinned to `0.0.17` for the current 0.x release and will widen to `^1.0.0` at the 1.x stable release. Inside the workspace each package also declares `"@arnilo/prism": "file:../.."` in `devDependencies` so `npm install` resolves the peer locally; that devDependency is stripped from consumer installs and is not a runtime dependency.
817
+ - **Required `@arnilo/prism` peer.** Every first-party code package declares a non-optional `@arnilo/prism@0.0.19` peer (`peerDependenciesMeta` must not mark `@arnilo/prism` optional; other peers such as `playwright-core` may be optional). The range stays pinned to `0.0.19` for the current 0.x release and will widen to `^1.0.0` at the 1.x stable release. Inside the workspace each package also declares `"@arnilo/prism": "file:../.."` in `devDependencies` so `npm install` resolves the peer locally; that devDependency is stripped from consumer installs and is not a runtime dependency.
776
818
  - **Public access.** All 43 manifests (37 code packages + 6 family/profile packages) declare `"publishConfig": { "access": "public" }`; the publisher also passes `--access public` explicitly because scoped packages otherwise default to restricted on first publish.
777
819
  - **Map retention knob.** Source maps are emitted locally but stripped from tarballs by `!dist/**/*.map`. Removing that `files` negation ships maps in releases (larger tarballs, better consumer stack traces).
778
820
  - **Release workflow.** `.github/workflows/release.yml` has six jobs. `verify` runs network-free SDK readiness on Node 24; `node20-compat` builds/imports every public root `exports` default target on Node 20 for declared `engines.node >=20` (docs examples need Node >=22.6 native TypeScript stripping); `postgres-integration` uses `pgvector/pgvector:pg16`; `supply-chain` runs high-severity audit, SPDX/license policy, and tracked-source secret scanning; and tag-only `codeql-release` runs SAST. Tag-only `publish` needs all five gates, preserves clean exact-tag/version/topological publication, and alone receives `NPM_TOKEN`, `id-token: write`, and `attestations: write`. Before npm publish it packs all current tarballs, generates checksums plus SPDX, scans unpacked public artifacts, creates GitHub attestations for tarballs and SBOM, then retains artifacts for 30 days. Registry state remains the resumable journal. Local `npm run release:dry-run` remains network-free SDK readiness; local PostgreSQL coverage is `PRISM_TEST_POSTGRES_URL=... npm run test:postgres`.
@@ -794,7 +836,7 @@ npm publication is not transactional and published versions are immutable. Parti
794
836
  - `PRISM_TEST_DOCKER_SANDBOX=1` — gates `@arnilo/prism-coding-security` protected Docker matrix. Requires host-preloaded digest-pinned `PRISM_TEST_DOCKER_IMAGE` and absolute `PRISM_TEST_DOCKER_BIN` (optional `PRISM_TEST_DOCKER_USER`). Prism never pulls/builds the image during default tests. Missing prerequisites fail closed when the gate is enabled; disabled gate skips safely.
795
837
  - `PRISM_LIVE_CANARIES=1` — gates `scripts/live-canary.mjs`, used only by scheduled/manual `.github/workflows/live-canaries.yml` in protected `live-canaries` environment. It requires provider endpoint/key/model, MCP endpoint/token, A2A endpoint/token, and Brave token environment entries; performs four probes plus at most one MCP session DELETE; caps provider output at one token, each response at 64 KiB, each request at 15 seconds (30 seconds hard), and emits only aggregate kind/status/code/duration. Disabled gate skips before network; enabled but incomplete configuration fails closed.
796
838
  - `PRISM_LIVE_COMPACTION_TESTS=1` — gates `@arnilo/prism-compaction-llm`'s live summary-provider smoke test (placeholder).
797
- - `PRISM_LIVE_OBSERVATIONAL_MEMORY_TESTS=1` — gates `@arnilo/prism-compaction-observational-memory`'s live worker/provider checks (placeholder).
839
+ - `PRISM_LIVE_OBSERVATIONAL_MEMORY_TESTS=1` — gates `@arnilo/prism-compaction-observational-memory`'s live observer/reflector worker canary. Requires `OPENAI_API_KEY`; gate enabled without key fails closed.
798
840
  - `PRISM_TEST_POSTGRES_URL` — gates `@arnilo/prism-session-store-postgres` and `@arnilo/prism-memory` integration tests against a real database (memory path requires pgvector). Local: `PRISM_TEST_POSTGRES_URL=... npm run test:postgres`. CI: `postgres-integration` job with `pgvector/pgvector:pg16`.
799
841
  - `PRISM_TEST_KEYCHAIN=1` — gates `@arnilo/prism-credentials-node` system-keychain round-trips (requires a working OS keychain backend; skipped by default).
800
842
  - Provider live tests read the API key from the env only when both gates are set; the key is used as a bearer token and never logged. `assertNoSecretLeak` verifies the key value does not appear in any streamed event. The compaction placeholders still carry no real credentials.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arnilo/prism",
3
- "version": "0.0.17",
3
+ "version": "0.0.19",
4
4
  "description": "Agent harness for AI providers, agents, sessions, and tools.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",