@arnilo/prism 0.1.5 → 0.1.7
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 +10 -0
- package/dist/agent-run-lifecycle.d.ts +2 -0
- package/dist/agent-run-lifecycle.js +7 -0
- package/dist/agent-run-state.d.ts +2 -0
- package/dist/agent-run-state.js +10 -0
- package/dist/agent-session.d.ts +7 -0
- package/dist/agent-session.js +25 -2
- package/dist/cache-telemetry.d.ts +58 -0
- package/dist/cache-telemetry.js +102 -0
- package/dist/cli-provider-add.d.ts +37 -0
- package/dist/cli-provider-add.js +293 -0
- package/dist/cli-runner.d.ts +5 -1
- package/dist/cli-runner.js +13 -1
- package/dist/contracts-run-state.d.ts +13 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.js +3 -2
- package/dist/skill-load.d.ts +23 -0
- package/dist/skill-load.js +74 -0
- package/docs/acp.md +2 -2
- package/docs/agent-session-runtime.md +1 -1
- package/docs/cli-rpc.md +33 -0
- package/docs/coding-agent-tools.md +12 -7
- package/docs/coding-security.md +3 -0
- package/docs/context-and-skills.md +2 -2
- package/docs/document-reader.md +85 -0
- package/docs/index.md +8 -8
- package/docs/model-routing.md +45 -0
- package/docs/provider-caching.md +63 -0
- package/docs/provider-packages.md +2 -0
- package/docs/release-and-install.md +54 -4
- package/package.json +3 -2
- package/templates/provider/CHANGELOG.md.tmpl +5 -0
- package/templates/provider/README.md.tmpl +41 -0
- package/templates/provider/docs/providers/NAME.md.tmpl +61 -0
- package/templates/provider/package.json.tmpl +49 -0
- package/templates/provider/src/cache.ts.tmpl +20 -0
- package/templates/provider/src/index.ts.tmpl +33 -0
- package/templates/provider/src/models.ts.tmpl +16 -0
- package/templates/provider/src/provider.ts.tmpl +23 -0
- package/templates/provider/src/tests/provider.test.ts.tmpl +104 -0
- package/templates/provider/tsconfig.json.tmpl +16 -0
|
@@ -12,8 +12,8 @@
|
|
|
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
14
|
| `createRepoSearchTool(cwd, options?)` | `repo_search` tool: bounded literal text search (`outputMode`: content / files_with_matches / count). |
|
|
15
|
-
| `createGlobTool(cwd, options?)` | `glob` tool: bounded filename-pattern match (`*` / `?` / `**`;
|
|
16
|
-
| `createDeleteTool(cwd, options?)` | `delete` tool: high-risk delete of a file
|
|
15
|
+
| `createGlobTool(cwd, options?)` | `glob` tool: bounded filename-pattern match (`*` / `?` / `**`; opt-in bounded `{a,b}` brace expansion via `braceExpansion`). |
|
|
16
|
+
| `createDeleteTool(cwd, options?)` | `delete` tool: high-risk delete of a file, empty directory, or (opt-in `recursive: true`) a directory tree (no trash). |
|
|
17
17
|
| `createMoveTool(cwd, options?)` | `move` tool: high-risk rename/move within the workspace (`overwrite` default false). |
|
|
18
18
|
| `createReadPathSet()` | Session-scoped path set for optional `requireReadBeforeWrite` soft guard. |
|
|
19
19
|
| `createCodingTools(cwd, options?)` | Default nine tools (`shell`, `read`, `write`, `edit`, `repo_list`, `repo_search`, `glob`, `delete`, `move`). |
|
|
@@ -101,8 +101,8 @@ These are **out of scope** for the 0.0.21 package baseline (see roadmap Phase 9
|
|
|
101
101
|
- **LSP language-server tools** — not in default aggregators; optional `createLanguageIntelligence` is Phase 9 (see [Language intelligence](language-intelligence.md)).
|
|
102
102
|
- **Managed process sessions** — not in default aggregators; optional `createProcessSessions` is Phase 9 (see [Process sessions](process-sessions.md)).
|
|
103
103
|
- **GitHub forge adapter** — not in default aggregators; optional `createGitHubForge` is Phase 9 (see [Forge integration](forge-integration.md)); no octokit dependency, no multi-forge abstraction.
|
|
104
|
-
- **No recursive directory delete** — `delete` refuses non-empty directories.
|
|
105
|
-
- **No brace-expansion globs** — `glob` supports only `*`, `?`, and
|
|
104
|
+
- **No recursive directory delete by default** — `delete` refuses non-empty directories unless the per-call `recursive: true` flag is set (plan 018 closeout `delete-glob`; bounded fan-out, symlink children unlinked but never followed).
|
|
105
|
+
- **No brace-expansion globs by default** — `glob` supports only `*`, `?`, and `**`; `{a,b}` expansion is opt-in (`braceExpansion`) and bounded (max 128 alternatives / 4096 expanded bytes, fail-closed).
|
|
106
106
|
|
|
107
107
|
## Inputs / request
|
|
108
108
|
|
|
@@ -153,6 +153,7 @@ Read a text or image file.
|
|
|
153
153
|
| `transformImage` | — | Host callback `( { buffer, mimeType } ) => Promise<Buffer>` run after read, before base64. |
|
|
154
154
|
| `maxLines` / `maxBytes` | 2000 / 50 KiB | Text page display limits (hard: 100,000 / 1 MiB). |
|
|
155
155
|
| `maxScanBytes` | 64 MiB | Raw bytes scanned to reach one page (hard: 1 GiB). |
|
|
156
|
+
| `documentReader` | — | Optional host-selected `DocumentReader` (see [Document reader](document-reader.md)): after the image sniff and before the text page, supported PDF/DOCX files are extracted as literal text with `metadata.document = { format, pages, truncatedBy }`. Additive; absent reader = unchanged 0.1.5 behavior. |
|
|
156
157
|
| `operations` | local fs | Pluggable bounded `ReadOperations` backend. |
|
|
157
158
|
| `executionPolicy` | — | Structured pre-execution policy (see [Coding security](coding-security.md)). |
|
|
158
159
|
|
|
@@ -171,6 +172,7 @@ const read = createReadTool(cwd, {
|
|
|
171
172
|
| --- | --- | --- |
|
|
172
173
|
| `truncation` | text reads | `TruncationResult`. |
|
|
173
174
|
| `image` | image reads | `{ mimeType, resized, bytes }`. `resized` is `true` when `transformImage` ran. |
|
|
175
|
+
| `document` | document reads | `{ format, pages, truncatedBy }` when a `documentReader` extracted the file. |
|
|
174
176
|
|
|
175
177
|
> `autoResizeImages` was removed in 0.1.5; untyped callers now fail closed with a `TypeError` naming `transformImage` before any filesystem access.
|
|
176
178
|
|
|
@@ -299,7 +301,7 @@ Metadata includes `matches`, `truncated`, scan/skip counts; non-content modes al
|
|
|
299
301
|
|
|
300
302
|
### `glob`
|
|
301
303
|
|
|
302
|
-
Find workspace files by filename pattern without shell `find`. Hand-rolled matcher: `*` (one path segment), `?` (one char), `**` (directories). Brace expansion (`{a,b}`) is **rejected
|
|
304
|
+
Find workspace files by filename pattern without shell `find`. Hand-rolled matcher: `*` (one path segment), `?` (one char), `**` (directories). Brace expansion (`{a,b}`) is **rejected by default**; set `braceExpansion: true` (per call or as the host option) for bounded expansion — max 128 alternatives and 4096 total expanded bytes, unbalanced/nested/empty braces and overflow fail closed. Expansion is textual only (never touches the filesystem) and result patterns still match workspace-relative full paths under the same exclude/hidden/depth/page/time caps. Patterns match workspace-relative full paths (e.g. `src/util/a.ts`). Returns **files only** (directories traversed but not listed). Same exclude/hidden/depth/page/time caps as `repo_list`.
|
|
303
305
|
|
|
304
306
|
**Inputs:**
|
|
305
307
|
|
|
@@ -308,6 +310,7 @@ Find workspace files by filename pattern without shell `find`. Hand-rolled match
|
|
|
308
310
|
| `pattern` | `string` | Glob pattern (required). |
|
|
309
311
|
| `path` | `string` | Workspace-relative start directory (default root). |
|
|
310
312
|
| `includeHidden` | `boolean` | Default false. |
|
|
313
|
+
| `braceExpansion` | `boolean` | Opt-in bounded `{a,b}` expansion (default: host option `createGlobTool(cwd, { braceExpansion })`, else false). |
|
|
311
314
|
| `maxDepth` | `number` | Depth cap (default 32, hard 128). |
|
|
312
315
|
| `maxResults` | `number` | Page size (default 1,000, hard 10,000). |
|
|
313
316
|
| `offset` | `number` | Matches to skip (default 0). |
|
|
@@ -316,13 +319,15 @@ Find workspace files by filename pattern without shell `find`. Hand-rolled match
|
|
|
316
319
|
|
|
317
320
|
### `delete`
|
|
318
321
|
|
|
319
|
-
High-risk: permanently delete a **single file or empty directory
|
|
322
|
+
High-risk: permanently delete a **single file or empty directory**, or — with the per-call opt-in `recursive: true` — a whole directory tree. Non-empty directories fail closed without the flag. The recursive walk never follows symlinks: symlink children are unlinked as links, so a link pointing outside the workspace root can never drag the deletion out (the outside target is untouched). Every entry counts against a per-call fan-out cap (`maxEntries`, default 10,000, hard 100,000); exceeding it stops with an error naming the cap (partial deletion is reported, never silent). **No trash daemon** — host undo is not automatic; gate with approval policy.
|
|
320
323
|
|
|
321
324
|
**Inputs:**
|
|
322
325
|
|
|
323
326
|
| Field | Type | Purpose |
|
|
324
327
|
| --- | --- | --- |
|
|
325
|
-
| `path` | `string` | File or
|
|
328
|
+
| `path` | `string` | File, empty directory, or (with `recursive: true`) directory tree to delete. Required. |
|
|
329
|
+
| `recursive` | `boolean` | Per-call opt-in recursive directory delete (default false). |
|
|
330
|
+
| `maxEntries` | `number` | Per-call fan-out cap for recursive deletes (default 10,000, hard 100,000). |
|
|
326
331
|
|
|
327
332
|
**Outputs:** confirmation with absolute path, or error (missing, non-empty dir, escape, abort).
|
|
328
333
|
|
package/docs/coding-security.md
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
| `createSandboxCodingTools` / `createSandboxReadOnlyTools` | Thin wrappers that return `tools` only (compat); still require `workspaceMode`. |
|
|
14
14
|
| `createSandboxFilesystemOperations` / `createSandboxRepositoryOperations` | Optional execFile-backed FS/list/search backends for a disposable sandbox tree. |
|
|
15
15
|
| `createDockerSandbox(options)` | Creates one disposable non-root Docker container with read-only root/source, bounded tmpfs workspace, typed `execFile`, import/export, and stop/kill/cleanup. |
|
|
16
|
+
| `createNativeSandbox(options)` | Linux-only network-free backend: every command runs in a fresh network namespace (`unshare`), POSIX `ulimit` hard caps, cwd-in-root containment; fails closed at creation on platforms/privileges that cannot deny egress. Docker remains the stronger, documented reference backend. |
|
|
16
17
|
| `SandboxProcessHandle` | Optional long-running process handle (`write`/`signal`/`kill`/`release`/`wait`) returned by `DisposableSandbox.startProcess?`. |
|
|
17
18
|
| `createEgressPolicy(options)` | Deny-all allow-list policy: exact host/port/protocol rules plus frozen `npm-registry` / `github` presets; SHA-256 fingerprint. |
|
|
18
19
|
| `createAllowListEgressProxy(options)` | HTTP forward proxy + CONNECT tunnel enforcing the policy: pinned DNS (rebinding defense), private/metadata IP denial, redirect re-validation + hop cap, byte/time caps, per-decision audit, attestation for sandbox composition. |
|
|
@@ -33,6 +34,8 @@ Use this package when coding tools need path scoping, human approval, command ru
|
|
|
33
34
|
|
|
34
35
|
Use `createDockerSandbox()` when the host wants a production-reference containment boundary. Prism does **not** claim OS-level isolation unless the host constructs this adapter (or supplies an equivalent custom `DisposableSandbox`). Default policy denies shell/write/edit/delete/move without an `approve` callback and rejects paths outside configured roots. Coding shell definitions are marked `exclusive: true`, matching the approval policy's shell decision, so a single-shot turn containing shell work runs sequentially even when `toolConcurrency > 1`. Non-shell turns retain configured parallelism.
|
|
35
36
|
|
|
37
|
+
Use `createNativeSandbox()` when the host has no container runtime and needs network-free containment (0.1.6, plan 018 closeout `native-sandbox`). Linux only; creation fails closed with a documented error on other platforms or when the OS cannot create a network namespace (no root/CAP_SYS_ADMIN and no unprivileged user namespaces). Every command runs in a fresh netns — **loopback is down**, so even localhost connections fail; hosts that need loopback keep the Docker backend. Containment is egress denial + `ulimit` hard caps (address space from `memoryBytes`, CPU-time wall backstop, fd count from `maxFds`) + cwd-inside-root (`assertPathInsideRoots`, symlink-aware). The native backend does **not** isolate the filesystem: commands run as the invoking OS user with full host-tree access, so pair it with `createSandboxCodingComposition`/`createSandboxFilesystemOperations` (per-op `assertSandboxPath`) and the approval policy, exactly as with any custom `DisposableSandbox`. Host env is never inherited; `env` is an exact allow-list (PATH only by default). No `startProcess` (ProcessSessions fails closed with `ERR_PRISM_PROCESS_UNSUPPORTED`), no CPU-rate/pids/fs-size caps (cgroup-only). Secrets passed as `secrets` are redacted from surfaced errors. See `docs/_evidence/phase18-primitive-review.md` for the full threat model.
|
|
38
|
+
|
|
36
39
|
Use `createEgressPolicy()` + `createAllowListEgressProxy()` when a coding agent needs outbound network access under an explicit allow list: package installs, forge API calls, or source fetches — never unrestricted egress. The proxy is inert until `start()`; nothing binds or resolves on import or construction.
|
|
37
40
|
|
|
38
41
|
## Allow-list egress composition
|
|
@@ -170,7 +170,7 @@ Catalog caps: **64** entries default / **256** hard; descriptions **512 B** defa
|
|
|
170
170
|
```ts
|
|
171
171
|
import { assembleProviderInput, createLoadedSkillSet } from "@arnilo/prism";
|
|
172
172
|
|
|
173
|
-
const loaded = createLoadedSkillSet(); // session-owned; opt-in checkpoint-persisted via runState.persistSessionState (names
|
|
173
|
+
const loaded = createLoadedSkillSet(); // session-owned; opt-in checkpoint-persisted via runState.persistSessionState (names since 0.1.3, + includeSkillBodies exact instructions since 0.1.6)
|
|
174
174
|
const request = await assembleProviderInput({
|
|
175
175
|
model,
|
|
176
176
|
input: "Hi",
|
|
@@ -256,7 +256,7 @@ Use `activateAllCapabilities: true` only as a temporary all-skills/all-tools com
|
|
|
256
256
|
- Skill registry lookup is `Map`-backed, and selection is linear in requested skills plus active tools. Strict duplicate mode adds one O(1) `Map.has()` check during registration only.
|
|
257
257
|
- Progressive catalog render is O(active skills) with byte/count caps; `load_skill` lookup is O(1). Budget eviction over context/skills is O(n log n) worst case.
|
|
258
258
|
- `load_skill` cannot grant tools; loaded instructions are untrusted text bounded by hard caps. `toolResultFold` summarizer output is untrusted and capped; failures keep raw tool results.
|
|
259
|
-
- Loaded-skill names are session-scoped. Since 0.1.3 (plan 015 Task 4) a durable run may opt in to persistence with `runState.persistSessionState: true` (and the same flag on resume options): the name catalog rides the run-state checkpoint (≤64 names, ≤256 chars each, charged against `maxStateBytes`) and is restored into the session `LoadedSkillSet` on resume, so progressive disclosure survives restart. **Bodies are never persisted** — they re-resolve from the live skill registry the next time the model loads the skill. Default off: checkpoint shape is identical to 0.1.
|
|
259
|
+
- Loaded-skill names are session-scoped. Since 0.1.3 (plan 015 Task 4) a durable run may opt in to persistence with `runState.persistSessionState: true` (and the same flag on resume options): the name catalog rides the run-state checkpoint (≤64 names, ≤256 chars each, charged against `maxStateBytes`) and is restored into the session `LoadedSkillSet` on resume, so progressive disclosure survives restart. **Bodies are never persisted by default** — they re-resolve from the live skill registry the next time the model loads the skill. Since 0.1.6 (plan 018 closeout `checkpoint-bodies`), `runState.includeSkillBodies: true` on both run and resume options persists the exact loaded-skill instructions (`{name, instructions}` pairs, redacted at rest like all checkpoint state, ≤64 bodies / ≤256-char names / ≤262144-byte bodies / ≤1 MiB total) and resume re-renders them registry-independently with no `load_skill` round-trip; the `maxStateBytes` ceiling refuses oversize bodies with a recorded error (never truncates). Default off: checkpoint shape is identical to 0.1.3.
|
|
260
260
|
- These helpers perform no provider calls, tool execution, resource loading, package discovery, filesystem/network access, retries, timers, or watchers by themselves.
|
|
261
261
|
- Context and skill output is host/extension data. Do not include secrets unless the host explicitly accepts that prompt exposure.
|
|
262
262
|
- Active tools remain host-supplied; skills and middleware do not activate tools or grant permissions. Use `duplicate: "error"` when loading third-party skills to prevent silent name shadowing.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Document reader (`@arnilo/prism-document-reader`)
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
Optional bounded literal-text extraction for PDF and DOCX files, consumed by the coding `read` tool (plan 018 closeout `doc-reader`, 0.1.6). `createDocumentReader()` returns a `DocumentReader` that the host wires into `createReadTool(cwd, { documentReader })`; the read tool then extracts text from supported documents instead of falling back to the raw text page.
|
|
6
|
+
|
|
7
|
+
## When to use it
|
|
8
|
+
|
|
9
|
+
Use when coding agents must read PDF/Office files (specs, requirements docs, reports) as literal text. Do **not** use it when embedded content execution, macro evaluation, or external resource fetching is required — this adapter never does any of those by construction, and the optional peer parsers (`pdf-parse`, `mammoth`) are the only parsing code involved. Docker-less hosts that need document reads pair this with the network-free native sandbox backend (`@arnilo/prism-coding-security` `createNativeSandbox`) for the surrounding tool execution.
|
|
10
|
+
|
|
11
|
+
Activation is explicit: no file-extension sniffing anywhere enables parsing. Absent `documentReader` option = exactly the 0.1.5 read behavior.
|
|
12
|
+
|
|
13
|
+
## Inputs / request
|
|
14
|
+
|
|
15
|
+
`createDocumentReader(options?)`:
|
|
16
|
+
|
|
17
|
+
| Option | Meaning | Default | Ceiling |
|
|
18
|
+
| --- | --- | --- | --- |
|
|
19
|
+
| `maxBytes` | Hard input size cap; oversize files refuse before loading | 32 MiB | 512 MiB |
|
|
20
|
+
| `maxPages` | Page cap for formats that report pages; over-page documents refuse | 1000 | 10 000 |
|
|
21
|
+
| `maxTextBytes` | Extracted-literal-text cap; over-cap results truncate (`truncatedBy: "bytes"`) | 2 MiB | 64 MiB |
|
|
22
|
+
| `parsers` | Host-selected `DocumentParser[]`; default wiring loads the optional peers | `[pdf, docx]` | — |
|
|
23
|
+
| `redactor` | Optional `SecretRedactor` applied to extracted text at the adapter boundary | none | — |
|
|
24
|
+
|
|
25
|
+
Format gating is magic-byte based: PDF header (`%PDF-`); DOCX zip container + `word/document.xml` part marker. Unsupported buffers return `null` and the read falls through to its text path.
|
|
26
|
+
|
|
27
|
+
## Outputs / response / events
|
|
28
|
+
|
|
29
|
+
`DocumentReader.extract({ buffer, path, signal })` resolves to `{ text, format, pages, truncatedBy }` or `null`. The read tool returns the text as a normal text content block with `metadata.document = { format, pages, truncatedBy }`.
|
|
30
|
+
|
|
31
|
+
Errors: `DocumentReaderError` with code `ERR_PRISM_DOCUMENT_READER` for missing peers (at creation), over-page/oversize refusal, and parser output beyond `maxTextBytes`. Invalid caps throw `RangeError` at creation.
|
|
32
|
+
|
|
33
|
+
## Request/response example
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { createReadTool } from "@arnilo/prism-coding-agent";
|
|
37
|
+
import { createDocumentReader } from "@arnilo/prism-document-reader";
|
|
38
|
+
|
|
39
|
+
const documentReader = await createDocumentReader({
|
|
40
|
+
maxBytes: 32 * 1024 * 1024,
|
|
41
|
+
maxPages: 1000,
|
|
42
|
+
redactor: hostRedactor, // optional
|
|
43
|
+
});
|
|
44
|
+
const read = createReadTool(cwd, { documentReader });
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
A `read` of `spec.pdf` yields text content extracted from the PDF (up to 2 MiB of literal text) with `metadata.document = { format: "pdf", pages, truncatedBy }`.
|
|
48
|
+
|
|
49
|
+
## Implementation example
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import { createDocumentReader, createPdfParser, type DocumentParser } from "@arnilo/prism-document-reader";
|
|
53
|
+
|
|
54
|
+
// Host-selected parser wiring: swap in a different PDF backend without touching bounds.
|
|
55
|
+
const myPdfParser: DocumentParser = {
|
|
56
|
+
format: "pdf",
|
|
57
|
+
detect: (buffer) => buffer.toString("latin1", 0, 5) === "%PDF-",
|
|
58
|
+
extract: async (buffer, { maxPages, maxTextBytes }) => {
|
|
59
|
+
// ... host parser (must honor caps, never fetch, never execute)
|
|
60
|
+
return { text, pages, truncatedBy: null };
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
const reader = await createDocumentReader({ parsers: [myPdfParser, await createPdfParser()] });
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Extension and configuration notes
|
|
67
|
+
|
|
68
|
+
- Default parser wiring uses the optional peer dependencies `pdf-parse` (PDF) and `mammoth` (DOCX raw text). Both are declared optional (`peerDependenciesMeta`); `createDocumentReader` fails closed with a documented error at creation when a selected format's peer is absent — never at read time. Hosts pin parser versions (their CVE surface is the host's responsibility; parser advisory is reviewed at ship time).
|
|
69
|
+
- DOCX has no page concept in raw text: `pages` is always `1` and the page cap applies to PDF only; the text cap governs DOCX output.
|
|
70
|
+
- The read tool re-checks `maxTextBytes` on results (parity with its text-page bounds check) and refuses reader output beyond it.
|
|
71
|
+
- The adapter truncates over-cap text at a UTF-8 byte boundary (never splits a code point).
|
|
72
|
+
|
|
73
|
+
## Security and performance notes
|
|
74
|
+
|
|
75
|
+
- No embedded-script execution, no macro evaluation, no external resource fetching — the peer raw-text surfaces are pure extractors, and the no-fetch property is enforced by an egress tripwire test.
|
|
76
|
+
- Decompression/size-bomb protection: the read tool stats and refuses files above `maxBytes` before loading; output is capped at `maxTextBytes`.
|
|
77
|
+
- Extraction envelope (recorded in `scripts/budgets.json` `docReader`, measured 2026-08-11): a max-cap 1000-page PDF (288 KB) extracts in ~162 ms with ~17 MB heap delta; the gate asserts completion within the ceiling or documented refusal.
|
|
78
|
+
- Parser code never receives a buffer whose format gate failed; random binaries never reach a parser.
|
|
79
|
+
|
|
80
|
+
## Related APIs
|
|
81
|
+
|
|
82
|
+
- `createReadTool` / `DocumentReader` / `DocumentReaderResult` (`@arnilo/prism-coding-agent`)
|
|
83
|
+
- `SecretRedactor` (`@arnilo/prism` redaction)
|
|
84
|
+
- `docs/_evidence/phase18-primitive-review.md` (doc-reader threat model D1–D8)
|
|
85
|
+
- `docs/coding-security.md` (native sandbox backend for surrounding execution containment)
|
package/docs/index.md
CHANGED
|
@@ -8,10 +8,10 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
|
|
|
8
8
|
## Identity and governance
|
|
9
9
|
- [Agent identity](agent-identity.md): host-verified `Principal` / `AgentIdentity`, delegation narrowing, ownership projection, and redacted telemetry refs for enterprise runs/tools/MCP/A2A/workflows; optional OIDC/JWKS verifier adapter (`@arnilo/prism-credentials-node/oidc` — pinned issuer/audience/JWKS, bounded claims, fail closed).
|
|
10
10
|
- [Policy and audit](policy-and-audit.md): optional `@arnilo/prism-policy` decision ledger (allow/deny/modify/approval), evidence refs only, cursor-paginated WORM export, and durable PostgreSQL composition; 0.0.28 adds the OPA REST evaluator (`@arnilo/prism-policy/opa` — pinned SSRF-checked endpoint, redacted input, fail-closed deny, optional bundle-revision pin).
|
|
11
|
-
- [Model routing](model-routing.md): optional `@arnilo/prism-model-router` allow-list/residency/budget/rate/circuit/fallback governance with redacted diagnostics; durable state requires awaited identity-scoped calls.
|
|
11
|
+
- [Model routing](model-routing.md): optional `@arnilo/prism-model-router` allow-list/residency/budget/rate/circuit/fallback governance with redacted diagnostics; durable state requires awaited identity-scoped calls; host-configurable selection policies (reference cost/latency policy ranks by `ModelCost` then in-memory latency EMA fed from `recordOutcome`).
|
|
12
12
|
|
|
13
13
|
## Agent/session runtime
|
|
14
|
-
- [Agent/session runtime](agent-session-runtime.md): create explicit or opt-in secure agents/sessions, get direct `AgentRunResult` values from `run`/`prompt`, mid-run `steer` (turn-boundary or softInterrupt), use integrated `stream()`/`resumeAgentRunStream()`, shared batch pending-decisions / sticky run-scope approvals, subscribe to normalized events, and expose opted-in durable lifecycle capabilities.
|
|
14
|
+
- [Agent/session runtime](agent-session-runtime.md): create explicit or opt-in secure agents/sessions, get direct `AgentRunResult` values from `run`/`prompt`, mid-run `steer` (turn-boundary or softInterrupt), use integrated `stream()`/`resumeAgentRunStream()`, shared batch pending-decisions / sticky run-scope approvals, subscribe to normalized events, and expose opted-in durable lifecycle capabilities (0.1.6 plan 018 closeout `checkpoint-bodies`: optional `includeSkillBodies` persists the exact loaded-skill instructions with the names-only `persistSessionState`, so resume re-renders bodies registry-independently; ≤64 bodies, `maxStateBytes` refuses oversize).
|
|
15
15
|
- [Agent definitions](agent-definitions.md): resolve declarative `AgentDefinition` values via `resolveAgentDefinition`, and turn app-config `<configRoot>/agents/<name>/AGENT.md` bundles into runnable agents via `discoverAgentBundles` / `resolveAgentBundle` (explicit tool/skill activation by name, fail-closed omitted capabilities, migration-only `activateAllCapabilities`, strict duplicate scope checks, configurable prompt layers, no auto-discovery).
|
|
16
16
|
- [Agent loops](agent-loops.md): replaceable per-run control loops — `singleShotLoop` default, opt-in bounded artifact-loop tool rounds, and durable custom-loop `revision`/`snapshot`/`restore` hooks with fail-closed resume.
|
|
17
17
|
- [Guardrails](guardrails.md): typed fail-closed input/output/tool checks with buffered provider output and redacted decision records.
|
|
@@ -43,7 +43,7 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
|
|
|
43
43
|
- [Provider primitives](provider-primitives.md): shared bounded transport and OpenAI serialization helpers — migrated across first-party providers; native structured-output and observability contracts.
|
|
44
44
|
- [Provider layer](provider-layer.md): register and resolve host-owned providers/models, choose replace-or-error duplicate policy, create provider events, stream/reconstruct tool-call deltas, use generic provider request options, and test with the mock provider; deprecated provider-level timeout/retry hints point to runtime abort/retry.
|
|
45
45
|
- [Model registry](model-registry.md): register and resolve `ModelConfig` records with capabilities, limits, cost, cache support metadata, compat data, and duplicate policy.
|
|
46
|
-
- [Provider caching](provider-caching.md): use `PromptCacheHints`, `PromptCacheBreakpoint`, `ModelCacheCapabilities`, cache-aware stable-prefix guidance, and shared cache diagnostics helpers; includes the complete per-provider explicit/implicit cache matrix plus no-Prism-cache entries (including Anthropic, Google, Alibaba, Ollama, cloud adapters, and host-owned AI SDK); cache hints are best-effort and cache keys are never secrets.
|
|
46
|
+
- [Provider caching](provider-caching.md): use `PromptCacheHints`, `PromptCacheBreakpoint`, `ModelCacheCapabilities`, cache-aware stable-prefix guidance, and shared cache diagnostics helpers; includes the complete per-provider explicit/implicit cache matrix plus no-Prism-cache entries (including Anthropic, Google, Alibaba, Ollama, cloud adapters, and host-owned AI SDK); cache hints are best-effort and cache keys are never secrets; `createCacheTelemetry()` aggregates per-provider/model hit rate and cache-token totals from the `usage` event stream for tuning the `cache_aware` layout.
|
|
47
47
|
- [Thinking and reasoning](thinking-and-reasoning.md): portable `ThinkingLevel` helpers (`applyThinkingLevel` / `thinkingCompatFor`) map per-turn effort into provider `compat` fields; model defaults stay on `ModelConfig.compat`; no second options tree.
|
|
48
48
|
- [Use-case model selection](use-case-model-selection.md): bind `{ model?, provider?, thinkingLevel? }` for observational memory, LLM compaction, and other non-session LLM jobs with explicit session-model fallback via `resolveUseCaseModel`.
|
|
49
49
|
- [Provider request policies](provider-request-policies.md): chain `ProviderRequestPolicy` hooks, use `createSessionCachePolicy`, and merge legacy/structured cache options safely.
|
|
@@ -74,11 +74,11 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
|
|
|
74
74
|
- [Work connectors](work-connectors.md): connector principles, capability gates, scoped OAuth establishment (0.0.14), and out-of-scope boundaries (Slack/Teams channels not shipped) for Microsoft 365 / Google Workspace.
|
|
75
75
|
- [Browser automation](browser-automation.md): optional `@arnilo/prism-browser` with host-supplied Playwright contexts, AI-mode snapshots/refs, ordered `browser_open`/`browser_snapshot`/`browser_act`/`browser_close` plus (0.1.4) `browser_evaluate`/`browser_observe` and CDP `block_urls`/`unblock_urls`/`throttle`/`emulate` act actions on Chromium hosts, egress/side-effect/upload/download/screenshot policy, finite page/action/snapshot/network/artifact caps, and 0.0.14 verified-state checkpoints with reload/verify-before-side-effect.
|
|
76
76
|
- [Device adapters](device-adapters.md): deny-by-default realtime voice / desktop-control contract + conformance (0.0.14); no vendor package — admission fails closed without explicit consent+sandbox+approval, stream bounds, shared `RunLimits`, redacted telemetry.
|
|
77
|
-
- [Coding agent tools](coding-agent-tools.md): optional `shell`, `read`, `write`, `edit`, `repo_list`, `repo_search`, `glob`, `delete`, and `move` definitions plus opt-in `createGitTools()` / `coding_check`, opt-in `createAskUserDecisionTool` (single/multi/free-text + durable suspend glue), and `runCodingGoalVerify`; durable plan/todo Markdown helpers with workflow `state.coding` checkpoint metadata; streamed text pages, `repo_search` `outputMode`, bounded glob, optional read-before-write, optional Git-aware (`createGitAwareRepositoryOperations`) ignore-aware enumeration with native fallback, finite Git/check/plan/ask caps, bounded image/edit reads and write/edit payloads, finite shell wall/total-output limits, secure host-owned spill cleanup, pluggable bounded operation contracts, per-path mutation serialization, and optional `ExecutionPolicy`. No PDF/trash/PTY in the 0.0.21 baseline; Phase 9 adds optional language intelligence (separate page). Limits do not sandbox host access—gate with permission/trust policy and `@arnilo/prism-coding-security`.
|
|
77
|
+
- [Coding agent tools](coding-agent-tools.md): optional `shell`, `read`, `write`, `edit`, `repo_list`, `repo_search`, `glob`, `delete`, and `move` definitions plus opt-in `createGitTools()` / `coding_check`, opt-in `createAskUserDecisionTool` (single/multi/free-text + durable suspend glue), and `runCodingGoalVerify`; durable plan/todo Markdown helpers with workflow `state.coding` checkpoint metadata; streamed text pages, `repo_search` `outputMode`, bounded glob, optional read-before-write, optional Git-aware (`createGitAwareRepositoryOperations`) ignore-aware enumeration with native fallback, finite Git/check/plan/ask caps, bounded image/edit reads and write/edit payloads, finite shell wall/total-output limits, secure host-owned spill cleanup, pluggable bounded operation contracts, per-path mutation serialization, and optional `ExecutionPolicy`. 0.1.6 adds the optional [document reader](document-reader.md) slot (`@arnilo/prism-document-reader`, plan 018 closeout `doc-reader`): bounded PDF/DOCX literal-text extraction behind `createReadTool({ documentReader })` with magic-byte format gating, input/page/text caps, fail-closed optional peer parsers, and no embedded-content execution or external fetching. 0.1.6 also adds opt-in recursive `delete` (`recursive: true`, bounded fan-out, symlink children never followed) and bounded `{a,b}` glob expansion (`braceExpansion`, max 128 alternatives / 4096 bytes, fail-closed) behind plan 018 closeout `delete-glob`. No PDF/trash/PTY in the 0.0.21 baseline (0.1.6's document reader is the demand-gated optional exception); Phase 9 adds optional language intelligence (separate page). Limits do not sandbox host access—gate with permission/trust policy and `@arnilo/prism-coding-security`.
|
|
78
78
|
- [Language intelligence](language-intelligence.md): optional host-activated `createLanguageIntelligence` — bounded in-package LSP 3.17 JSON-RPC client (Content-Length framing), host-selected server command/args per language, workspace symbols/definitions/references/diagnostics/hover/rename; lazy spawn; URI root confinement; rename gated by `ExecutionPolicy` + atomic write/mutation queue; frozen message/diagnostic/pending/result/timeout/server caps. No `vscode-languageserver-protocol` dependency.
|
|
79
79
|
- [Process sessions](process-sessions.md): optional host-activated `createProcessSessions` — long-running process registry (start/cursor-paged output/input/wait/signal/kill/release), native or sandbox `startProcess` backend (fail closed when absent), ownership/identity + expiry sweep on access, `reconcile` / sandbox-loss → `unknown` (never fabricates exitCode), durable command fingerprint metadata, `CodingProcessEvent` host sink, `ExecutionPolicy` before spawn and on mutate, frozen session/input/lifetime/output caps; PTY fails closed as unsupported.
|
|
80
80
|
- [Forge integration](forge-integration.md): optional host-activated `createGitHubForge` — reference GitHub adapter (issue context, authenticated push via `BoundGitRunner` + `GIT_CONFIG_*` credential injection, PR create/update, review comments, check/status retrieval, bounded `reconcileHandoff`), every mutation gated by `ExecutionPolicy` and recorded in `ToolEffectStore` (retry never duplicates PRs/comments), typed `ForgeError` codes (auth/API/stale/rate-limit/limit/ownership), frozen page/payload/comment/concurrency/timeout caps, no octokit dependency, tokens never in argv/logs/events.
|
|
81
|
-
- [Coding execution approval and sandboxing](coding-security.md): path/command approval, identity-scoped caching, shell-turn exclusivity, required `workspaceMode` (`host`/`sandbox`) with fail-closed mixed wiring, `createSandboxCodingComposition()` containment metadata, disposable Docker/OCI sandbox reference with bounded workspace import/export, optional `DisposableSandbox.startProcess` / `SandboxProcessHandle` for process-session backends, and allow-list egress (`createEgressPolicy` deny-all exact rules + frozen presets, `createAllowListEgressProxy` HTTP/CONNECT proxy with pinned-DNS rebinding defense, private/metadata IP denial, redirect re-validation + hop cap, byte/time caps, per-decision audit, `composeEgressSandboxNetwork` attestation recorded as `prism.egress.*` labels; TLS pass-through, no interception).
|
|
81
|
+
- [Coding execution approval and sandboxing](coding-security.md): path/command approval, identity-scoped caching, shell-turn exclusivity, required `workspaceMode` (`host`/`sandbox`) with fail-closed mixed wiring, `createSandboxCodingComposition()` containment metadata, disposable Docker/OCI sandbox reference with bounded workspace import/export (0.1.6 adds the Linux-only network-free `createNativeSandbox` backend — fresh netns per command via `unshare`, `ulimit` hard caps, cwd containment, fails closed where egress denial is impossible), optional `DisposableSandbox.startProcess` / `SandboxProcessHandle` for process-session backends, and allow-list egress (`createEgressPolicy` deny-all exact rules + frozen presets, `createAllowListEgressProxy` HTTP/CONNECT proxy with pinned-DNS rebinding defense, private/metadata IP denial, redirect re-validation + hop cap, byte/time caps, per-decision audit, `composeEgressSandboxNetwork` attestation recorded as `prism.egress.*` labels; TLS pass-through, no interception).
|
|
82
82
|
|
|
83
83
|
## Extensions/plugins
|
|
84
84
|
- [Contribution discovery (workspace)](contribution-discovery.md): opt-in, realpath-contained directory scanner turning `SKILL.md`/`manifest.json` into inert `DiscoveredContribution` envelopes the host registers — no `import()`, no auto-activate, no provider scanning. Per-agent bundles remain app-controlled and are documented under Agent/session runtime.
|
|
@@ -99,11 +99,11 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
|
|
|
99
99
|
- [Supervisor delegation](supervisors.md): optional explicit child allow-list, derived memory scopes, narrowing-only permissions, lifecycle hooks, nested delegation, cancellation, finite budgets, host-projected delegation telemetry, and separate A2A durable adapter boundary.
|
|
100
100
|
- [A2A interoperability](a2a.md): A2A 1.0 JSON-RPC/HTTPS cards plus host-owned durable task get/list/cancel/subscribe, shared `AgentEventSource` task adapter, bounded rich parts/replay, principal-scoped push configs, exact-origin verified client, rich stream seam for explicit AG-UI fronting, and server-side `createAgUiA2AServer` exposure of a local AG-UI agent (0.0.26).
|
|
101
101
|
- [Frontend interoperability (AG-UI and ACP)](ag-ui.md): optional `@arnilo/prism-ag-ui` full AG-UI 0.0.57 input/event/capability mapper, authorized Web handler/distributed source follow, opt-in A2UI painting middleware, explicit hardened MCP/MCP Apps/remote A2A adapters, a framework-free reference renderer subpath (`@arnilo/prism-ag-ui/renderer`, 0.0.26), and stable ACP sibling over shared redacted event and durable-approval seams; 0.0.14 adds reconnectable co-work events.
|
|
102
|
-
- [ACP coding-host interop](acp.md): stable ACP v1 `createPrismAcpAgent()`/`createAcpEventMapper()` over `@agentclientprotocol/sdk@1.3.0` — capability advertisement is a pure function of host seams (sessions load/list/delete/resume/dirs, close always, prompt media/embedded, MCP http/sse), client fs/terminal adapters, modes and config options as host overlays, `CodingLifecycleEvent` mapping, four-outcome approvals with elicitation, and frozen caps (0.0.27); 0.1.1 adds ownership-scoped persistence guidance for host-persisted modes/config (plan 013 Task 5 — the agent never persists them).
|
|
102
|
+
- [ACP coding-host interop](acp.md): stable ACP v1 `createPrismAcpAgent()`/`createAcpEventMapper()` over `@agentclientprotocol/sdk@1.3.0` — capability advertisement is a pure function of host seams (sessions load/list/delete/resume/dirs, close always, prompt media/embedded, MCP http/sse), client fs/terminal adapters, modes and config options as host overlays, `CodingLifecycleEvent` mapping, four-outcome approvals with elicitation, and frozen caps (0.0.27); 0.1.1 adds ownership-scoped persistence guidance for host-persisted modes/config (plan 013 Task 5 — the agent never persists them); 0.1.6 adds the optional host-owned `AcpSessionStore` durability seam — live registry (modes/config/cwd/ownership) survives agent restart, restore is ownership-scoped and fail-closed (plan 018 Task 2).
|
|
103
103
|
- [AG-UI adoption evaluation](ag-ui-adoption.md): official 0.0.57 input/event/capability matrix and shipped hardened MCP/MCP Apps/A2A handshake boundaries.
|
|
104
104
|
|
|
105
105
|
## CLI/RPC
|
|
106
|
-
- [CLI/RPC](cli-rpc.md): Run print/json modes and LF-delimited RPC over the public AgentSession runtime, including mid-run `steer`, branch-handle results, fixed `forkSession`, and `checkout`. `prism init` scaffolds a tiny TypeScript project with one selected provider and an offline mock test.
|
|
106
|
+
- [CLI/RPC](cli-rpc.md): Run print/json modes and LF-delimited RPC over the public AgentSession runtime, including mid-run `steer`, branch-handle results, fixed `forkSession`, and `checkout`. `prism init` scaffolds a tiny TypeScript project with one selected provider and an offline mock test; `prism providers add <name>` scaffolds an OpenAI-compatible provider package (manifest, provider, models, cache helpers, conformance test, docs stub).
|
|
107
107
|
- [Workflows](workflows.md): optional `@arnilo/prism-workflows` typed bounded DAG orchestration — explicit recursive definition revisions, exact-owner cancellation/active identity, finite hard limits, durable human suspend/resume, schedules/background execution, revocable proactive schedule capability tokens, nested workflows, replay, coordination, events, and optional RPC/Web bindings. Compose coding plans/checkpoints via workspace Markdown + `state.coding` without a second runtime. Interactive TUI (C-012) deferred.
|
|
108
108
|
- [Workflow orchestration primitives](workflow-orchestration-primitives.md): architecture inventory — workflow adapters consume core `CheckpointStore`, `LeaseStore`, and bounded `EventMultiplexer`; run control and optional RPC commands stay package-local.
|
|
109
109
|
- [Workflow/TUI scope](workflow-tui-primitives.md): records why 0.0.5 ships workflow APIs/RPC control but no interactive terminal UI.
|
|
@@ -129,7 +129,7 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
|
|
|
129
129
|
- [Ponytail behavior integration](ponytail.md): optional `@arnilo/prism-ponytail` — upstream Ponytail skills/commands, `ponytail-mode` injector, session `ponytail-mode` persistence; resolves peer `@dietrichgebert/ponytail` or `upstreamPath`; opt-in (not in code/sdk profiles).
|
|
130
130
|
|
|
131
131
|
## Release and install
|
|
132
|
-
- [Release and install](release-and-install.md): current **0.1.
|
|
132
|
+
- [Release and install](release-and-install.md): current **0.1.7** 50-package graph (root + 49 workspace packages, including the plan 018 optional `@arnilo/prism-document-reader` — the graph grew 49 → 50 because its doc-reader closeout was demanded; plan 019 the performance-and-DX patch — dependency-free `createCacheTelemetry()` per-provider/model cache hit/miss aggregator (bounded cardinality with `__overflow__`, token counters/rates only, host-activated), host-configurable `ModelRouterSelectionPolicy` on `createModelRouter` with the reference `createCostLatencySelection` (ModelCost rank then in-memory latency EMA, default ordered behavior byte-identical), `prism providers add <name>` OpenAI-compatible provider scaffold (manifest/provider/models/cache/conformance test/docs stub, npm-name + traversal + symlink-escape validation, placeholders only), and the async `AgUiProjection` verification closeout (plan 009 Task 15 evidence recorded, no new code); plan 017 the documented breaking cut — deprecated-option removal with `docs/migration.md` `0.1.4 → 0.1.5` section and reviewed compat-baseline regeneration via `--allow-break` then `--update-baseline`: the inert provider request knobs, `RunOptions.maxToolRounds`, observational-memory flat settings keys + top-level worker aliases, `ReadToolOptions.autoResizeImages`, `INIT_PROVIDERS`; all removals fail closed naming their replacement; plan 016 internal god-module split — `agents.ts`/`contracts.ts` reorganized behind barrel re-exports with a byte-identical public entry surface, measured tree-shaking improvement in `scripts/phase16-baseline.json`, and additive `@arnilo/prism-browser` Chrome DevTools Protocol capabilities — `browser_evaluate`/`browser_observe` and `block_urls`/`unblock_urls`/`throttle`/`emulate` act actions; plan 015 dead-code and deprecation hygiene on the frozen 0.1.x line — parameterized benchmark runner `scripts/benchmark.mjs` absorbing the per-version runners, archived review-coverage evidence in `docs/_evidence/`, non-blocking unused-code sweep `npm run sweep:unused`, opt-in checkpoint persistence for loaded-skill names and read-path sets; plan 014 Alibaba provider enrichment — embeddings, video input, verified compatible-mode surface decision table; plan 013 post-release hardening — build single-flight, MCP SSE relay test, combined coverage summary, canonical manifest-count narrative, ACP modes/config persistence guidance; Phase 12 release-candidate hardening; plan 012 — freeze manifest, compatibility matrix, upgrade matrix, packed-install e2e journeys, restart-recovery evidence, capacity envelopes, security policy), exact-peer/install/tarball rules, deterministic resumable publication and publish dry-run, frozen 0.1.x compatibility and support matrix (Node/PostgreSQL/platform/provider/protocol pins and unsupported combinations, machine-checked against `scripts/phase12-freeze-manifest.json`), protected PostgreSQL gate, 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.
|
|
133
133
|
- [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.23** published target), signed-publication/live-canary prerequisites for 1.0, and Phase 12 demand-evidence entry criteria.
|
|
134
134
|
- [Review coverage archive](_evidence/): per-phase evidence freezes (plans 067–079, releases 0.0.4–0.0.16) — traceability matrices, provider validation, capability/primitive/limit matrices, benchmark budgets, and artifact-diet findings; tarball-excluded, kept in-repo for audit.
|
|
135
135
|
|
package/docs/model-routing.md
CHANGED
|
@@ -91,6 +91,51 @@ await enterprise.close();
|
|
|
91
91
|
|
|
92
92
|
Router is optional. Chain returned `providerRequestPolicy` with other `ProviderRequestPolicy` values. Wire `onDiagnostics` to `@arnilo/prism-policy` when audit export is required. OpenRouter package behavior is unchanged; routing metadata participates only when this gate allows it.
|
|
93
93
|
|
|
94
|
+
### Selection policies (0.1.7)
|
|
95
|
+
|
|
96
|
+
By default the router tries candidates in input order: the primary model, then
|
|
97
|
+
`fallbacks` in order. A host can instead supply a `selection` policy on
|
|
98
|
+
`createModelRouter` to rank the candidates before the governance checks run:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import { createCostLatencySelection, createModelRouter } from "@arnilo/prism-model-router";
|
|
102
|
+
|
|
103
|
+
const router = createModelRouter({
|
|
104
|
+
resolver,
|
|
105
|
+
selection: createCostLatencySelection({ latencyWeight: 0.5 }),
|
|
106
|
+
fallbacks: [cheaperModel],
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// host-measured provider-call latency feeds the policy's EMA:
|
|
110
|
+
await router.recordOutcome({ identity, provider, model, success: true, latencyMs: 412 });
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`ModelRouterSelectionPolicy` is `{ name, rank(candidates, request), observe? }`:
|
|
114
|
+
|
|
115
|
+
- `rank` must return a **permutation** of the input candidates. Any other
|
|
116
|
+
result (added, dropped, or duplicated candidates) fails closed with
|
|
117
|
+
`ERR_PRISM_MODEL_ROUTER_POLICY` — a policy can never widen the allow-list,
|
|
118
|
+
residency, or budget decisions, because those checks still run per candidate
|
|
119
|
+
after ranking.
|
|
120
|
+
- `observe` receives outcome feedback from `router.recordOutcome`, including
|
|
121
|
+
the host-supplied `latencyMs` (validated finite non-negative).
|
|
122
|
+
- The policy name is recorded in selection diagnostics (the redaction cap
|
|
123
|
+
still applies). Absent `selection`, behavior is identical to 0.1.6.
|
|
124
|
+
|
|
125
|
+
`createCostLatencySelection()` is the reference policy:
|
|
126
|
+
|
|
127
|
+
- Ranks by unit price first: `ModelCost.input` + `output` + `cacheRead`,
|
|
128
|
+
normalized by the cost unit (`per_million_tokens` vs per-token). Models
|
|
129
|
+
without valid cost metadata rank after all priced models, preserving their
|
|
130
|
+
relative input order.
|
|
131
|
+
- Breaks cost ties by recent measured latency — an in-memory per-
|
|
132
|
+
provider/model EMA fed from `recordOutcome` `latencyMs`. Cold start (no
|
|
133
|
+
samples) is pure cost order.
|
|
134
|
+
- `latencyWeight` (default 0.5) is the EMA smoothing factor: 0 keeps the
|
|
135
|
+
first sample, 1 tracks only the latest. `ponytail:` the EMA is in-memory and
|
|
136
|
+
process-local; durable latency statistics would require a
|
|
137
|
+
`ModelRouterStateStore` contract change and are demand-gated.
|
|
138
|
+
|
|
94
139
|
## Security and performance notes
|
|
95
140
|
|
|
96
141
|
- Allow-list and residency denies never call the underlying resolver.
|
package/docs/provider-caching.md
CHANGED
|
@@ -220,6 +220,69 @@ Static featured catalogs remain offline bootstrap and must **not** invent pricin
|
|
|
220
220
|
- Cache usage reports contain only usage counts and optional pricing/currency; they do not include prompt text, cache keys, headers, credentials, or provider payloads.
|
|
221
221
|
- `applyCacheControl()` returns new message objects for stamped anchors and does not mutate input messages.
|
|
222
222
|
|
|
223
|
+
## Cache telemetry
|
|
224
|
+
|
|
225
|
+
### What it does
|
|
226
|
+
|
|
227
|
+
`createCacheTelemetry()` is a dependency-free aggregator that turns the per-call
|
|
228
|
+
`Usage.cacheReadTokens`/`cacheWriteTokens` counters into per-provider/model
|
|
229
|
+
statistics hosts can use to tune the `cache_aware` input layout: request count,
|
|
230
|
+
cache-read/write token totals, hit rate, and an estimated read-token savings
|
|
231
|
+
when the model carries cost metadata.
|
|
232
|
+
|
|
233
|
+
### When to use it
|
|
234
|
+
|
|
235
|
+
Use it when you want to observe cache effectiveness per provider/model over a
|
|
236
|
+
session, a day, or a run ledger. It is opt-in by construction: importing the
|
|
237
|
+
module never collects anything — the host explicitly wires `record()` to its
|
|
238
|
+
`usage` `ProviderEvent` stream or to run-ledger usage records.
|
|
239
|
+
|
|
240
|
+
### Inputs / request
|
|
241
|
+
|
|
242
|
+
| Input | Meaning |
|
|
243
|
+
| --- | --- |
|
|
244
|
+
| `usage` (`Usage`) | One usage record: `cacheReadTokens`, `cacheWriteTokens`, `inputTokens` are validated (non-negative safe integers; a violation throws `CacheTelemetryError` and mutates nothing). |
|
|
245
|
+
| `model` (`ModelConfig?`) | Attribution key (`provider` + `model`). Omit it for provider-only aggregation into the `unknown` bucket. Cost metadata (`ModelCost.input`/`cacheRead`) enables `estimatedSavings`. |
|
|
246
|
+
| `options.maxKeys` | Distinct provider/model keys before excess keys collapse into the `__overflow__` bucket (default `DEFAULT_CACHE_TELEMETRY_CAP` = 256). |
|
|
247
|
+
|
|
248
|
+
### Outputs / response / events
|
|
249
|
+
|
|
250
|
+
`report()` returns `{ samples, overflowed, totalRequests, totalCacheReadTokens,
|
|
251
|
+
totalCacheWriteTokens }`. Each sample carries `provider`, `model`, `requests`,
|
|
252
|
+
`cacheReadTokens`, `cacheWriteTokens`, `inputTokens`, `hitRate` (total reads /
|
|
253
|
+
total input — the same math as `cacheHitRate()`), and `estimatedSavings` with
|
|
254
|
+
`currency` only when the model has cost metadata. Samples are sorted by
|
|
255
|
+
provider then model. `reset()` clears all samples; `size` reports the current
|
|
256
|
+
distinct-key count.
|
|
257
|
+
|
|
258
|
+
### Request/response example
|
|
259
|
+
|
|
260
|
+
```ts
|
|
261
|
+
import { createCacheTelemetry } from "@arnilo/prism";
|
|
262
|
+
|
|
263
|
+
const telemetry = createCacheTelemetry();
|
|
264
|
+
for await (const event of provider.generate(request)) {
|
|
265
|
+
if (event.type === "usage") telemetry.record(event.usage, request.model);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const report = telemetry.report();
|
|
269
|
+
for (const sample of report.samples) {
|
|
270
|
+
console.log(sample.provider, sample.model, sample.hitRate, sample.cacheReadTokens);
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Security and performance notes
|
|
275
|
+
|
|
276
|
+
- Reports carry token counters, rates, currency, and provider/model names only
|
|
277
|
+
— never prompt content, cache keys, headers, credentials, or identity fields
|
|
278
|
+
(redaction-safe by construction).
|
|
279
|
+
- Cardinality is bounded: beyond `maxKeys` distinct provider/model keys, excess
|
|
280
|
+
keys accumulate in a single `__overflow__` bucket; memory cannot grow with
|
|
281
|
+
hostile model names (`ponytail:` ceiling — upgrade to host-configurable caps
|
|
282
|
+
or LRU eviction only if a real deployment exceeds it).
|
|
283
|
+
- `record()` is O(1) per usage event; `report()` is O(keys). No secrets or
|
|
284
|
+
cache keys are accepted or stored.
|
|
285
|
+
|
|
223
286
|
## Related APIs
|
|
224
287
|
|
|
225
288
|
- [Input and prompt assembly](input-and-prompt-assembly.md): opt-in cache-aware ordering for stable provider payload prefixes.
|
|
@@ -74,6 +74,8 @@ First-party providers map generic `ModelConfig.parameters.maxTokens` to real out
|
|
|
74
74
|
|
|
75
75
|
## First-party provider package skeletons
|
|
76
76
|
|
|
77
|
+
Scaffold new OpenAI-compatible provider packages with `prism providers add <name>` (see [CLI/RPC](cli-rpc.md#prism-providers-add-017)): it generates the manifest, provider (`createOpenAICompatibleProvider`), starter models, cache-hint helpers, an offline conformance test, and a docs stub — mirroring the first-party skeleton conventions below. Scaffold output is host-chosen and never auto-registered.
|
|
78
|
+
|
|
77
79
|
Phase 12 adds explicit npm workspaces for [`@arnilo/prism-provider-openai`](providers/openai.md), [`@arnilo/prism-provider-opencode-go`](providers/opencode-go.md), [`@arnilo/prism-provider-openrouter`](providers/openrouter.md), [`@arnilo/prism-provider-zai`](providers/zai.md), [`@arnilo/prism-provider-kimi`](providers/kimi.md), and [`@arnilo/prism-provider-neuralwatt`](providers/neuralwatt.md). Each package starts with a side-effect-free `create*ProviderPackage()` export, README, TypeScript build, network-free default tests, and real opt-in live smoke tests.
|
|
78
80
|
|
|
79
81
|
Phase 6 also adds optional [`@arnilo/prism-provider-ai-sdk`](providers/ai-sdk.md), which adapts a host-owned AI SDK `LanguageModelV4` to Prism's `AIProvider`. It joins `@arnilo/prism-providers` as the seventh adapter while remaining independent from the six HTTP implementations.
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## What it does
|
|
4
4
|
|
|
5
|
-
Prism is published as **
|
|
5
|
+
Prism is published as **50 publishable manifests**: the root `@arnilo/prism` core package plus **49 workspace packages** — 14 provider adapters, 9 `prism-*` family/profile packages, and 26 capability packages. (Regenerate the counts: `ls packages/*/package.json | wc -l` = 49 workspace; `ls -d packages/provider-*/ | wc -l` = 14; `ls -d packages/prism-*/ | wc -l` = 9; capability = 49 − 14 − 9 = 26; publishable = root + 49 = 50.) The 50th manifest is the 0.1.6 plan 018 optional `@arnilo/prism-document-reader` package (bounded PDF/Office literal-text extraction for the coding read tool; ships only because its `doc-reader` closeout is demanded — a deferred closeout keeps the graph at 49). This page describes how they are packed, what each tarball contains, how to install them, the required `@arnilo/prism` peer dependency, the release workflow, and the offline test budget. The measurable 1.0 readiness gates (command-per-gate) live in [`0.1.0-readiness.md`](./0.1.0-readiness.md).
|
|
6
6
|
|
|
7
7
|
Core `@arnilo/prism` ships runtime, CLI, templates, and docs. Every code package has a required `@arnilo/prism@0.1.0` peer; profiles are pure manifests. Installation activates no provider, listener, database, browser, credential, or tool capability.
|
|
8
8
|
|
|
9
|
-
Current **
|
|
9
|
+
Current **50** publishable manifests (root + 49 workspace packages):
|
|
10
10
|
|
|
11
11
|
`@arnilo/prism`, `@arnilo/prism-ag-ui`, `@arnilo/prism-browser`, `@arnilo/prism-coding-agent`, `@arnilo/prism-coding-security`, `@arnilo/prism-compaction-llm`
|
|
12
12
|
`@arnilo/prism-compaction-observational-memory`, `@arnilo/prism-credentials-node`, `@arnilo/prism-enterprise-postgres`, `@arnilo/prism-evals`, `@arnilo/prism-mcp`, `@arnilo/prism-memory`
|
|
@@ -15,7 +15,7 @@ Current **49** publishable manifests (root + 48 workspace packages):
|
|
|
15
15
|
`@arnilo/prism-provider-alibaba`, `@arnilo/prism-provider-anthropic`, `@arnilo/prism-provider-azure`, `@arnilo/prism-provider-bedrock`, `@arnilo/prism-provider-google`, `@arnilo/prism-provider-kimi`
|
|
16
16
|
`@arnilo/prism-provider-neuralwatt`, `@arnilo/prism-provider-ollama`, `@arnilo/prism-provider-openai`, `@arnilo/prism-provider-opencode-go`, `@arnilo/prism-provider-openrouter`, `@arnilo/prism-provider-vertex`
|
|
17
17
|
`@arnilo/prism-provider-zai`, `@arnilo/prism-rag`, `@arnilo/prism-server`, `@arnilo/prism-session-store-codecs`, `@arnilo/prism-session-store-nats`, `@arnilo/prism-session-store-postgres`, `@arnilo/prism-session-store-sqlite`
|
|
18
|
-
`@arnilo/prism-openapi-tools`, `@arnilo/prism-supervisor`, `@arnilo/prism-tool-validator-json-schema`, `@arnilo/prism-web-tools`, `@arnilo/prism-work-tools`, `@arnilo/prism-workflows`
|
|
18
|
+
`@arnilo/prism-openapi-tools`, `@arnilo/prism-supervisor`, `@arnilo/prism-tool-validator-json-schema`, `@arnilo/prism-web-tools`, `@arnilo/prism-work-tools`, `@arnilo/prism-workflows`, `@arnilo/prism-document-reader`
|
|
19
19
|
|
|
20
20
|
Core ships `dist`, docs, templates, and `CHANGELOG.md`; code packages ship compiled output, README, license, and changelog. Family/profile packages ship manifest, README, and changelog. `@arnilo/prism-providers` includes all eleven `@arnilo/prism-provider-*` packages.
|
|
21
21
|
|
|
@@ -178,7 +178,7 @@ PRISM_LIVE_PROVIDER_TESTS=1 npm run test --workspaces --if-present
|
|
|
178
178
|
|
|
179
179
|
### 0.1.0 publish handoff (plan 012 Task 7)
|
|
180
180
|
|
|
181
|
-
**Decision: GO when the operator prerequisites below are recorded.** Release **0.1.0** (Phase 12, plan 012) is the release-candidate hardening cut of the **0.0.28** graph: no new packages, public exports, schema migrations, or runtime dependencies (freeze manifest `scripts/phase12-freeze-manifest.json`). Publishable graph stays **49** publishable manifests (root + 48 workspace packages) at exact **0.1.0**. Store compatibility with 0.0.28: **compatible, no migration** ([migration](migration.md) `0.0.28 → 0.1.0`); the full `0.0.17 → 0.1.0` upgrade matrix is in the same page. All evidence for the tree under publication is recorded in [0.1.0 readiness](0.1.0-readiness.md) (capacity envelopes, restart-recovery, e2e journeys, threat-suites leg, audit at moderate).
|
|
181
|
+
**Decision: GO when the operator prerequisites below are recorded.** Release **0.1.0** (Phase 12, plan 012) is the release-candidate hardening cut of the **0.0.28** graph: no new packages, public exports, schema migrations, or runtime dependencies (freeze manifest `scripts/phase12-freeze-manifest.json`). At this line the canonical statement read **49 publishable manifests**: the root `@arnilo/prism` core package plus **48 workspace packages** — 14 provider adapters, 9 `prism-*` family/profile packages, and 25 capability packages. Publishable graph stays **49** publishable manifests (root + 48 workspace packages) at exact **0.1.0**. Store compatibility with 0.0.28: **compatible, no migration** ([migration](migration.md) `0.0.28 → 0.1.0`); the full `0.0.17 → 0.1.0` upgrade matrix is in the same page. All evidence for the tree under publication is recorded in [0.1.0 readiness](0.1.0-readiness.md) (capacity envelopes, restart-recovery, e2e journeys, threat-suites leg, audit at moderate).
|
|
182
182
|
|
|
183
183
|
```bash
|
|
184
184
|
# Operator prerequisites (each a named blocked gate — none may be skipped):
|
|
@@ -274,6 +274,56 @@ git push origin v0.1.2 # tag push triggers release.yml publish job (prove
|
|
|
274
274
|
|
|
275
275
|
**Rollback notes.** `release:publish --version 0.1.2 --resume --report release-artifacts/publish-report.json` resumes an interrupted publication and skips only registry versions whose internal dependency fingerprint matches the local manifest. A failed package aborts the run with its status written to the report; re-run after fixing the cause. npm cannot unpublish the `0.1.2` line after 72 hours — a post-publication defect ships as a `0.1.x` patch (additive-only compat promise, `release:gate` enforced), or as a documented break in the next line with a `docs/migration.md` entry. `0.1.2` is store-compatible with `0.1.1` in **both directions** (no migration ran — same checksum-protected contract), so an operator may defer or roll back the patch without a database rollback.
|
|
276
276
|
|
|
277
|
+
### 0.1.7 publish handoff (plan 019 Task 6)
|
|
278
|
+
|
|
279
|
+
**Decision: GO when the operator prerequisites below are recorded.** Release **0.1.7** (plan 019) is the performance-and-DX patch on the frozen 0.1.x line — **additive-only** vs 0.1.6 (plain compat gate at 0.1.7 passed with 0 breaking declaration deltas; the baseline text was regenerated with `--update-baseline` for the version literal only, no `--allow-break` anywhere; freeze manifest `scripts/phase19-freeze-manifest.json` machine-checks each task's diff stayed inside its allowed files). Shipped: (1) **prompt-cache telemetry surface** — dependency-free `createCacheTelemetry()` aggregator in core, host-activated, per-provider/model request counts + aggregate hit rate + cache-read/write token totals + estimated savings, bounded cardinality (cap 256 distinct keys, `__overflow__` bucket), token counters/rates only (never prompt content, cache keys, or identity), O(1) `record()`; (2) **model-router selection policies** — additive `ModelRouterSelectionPolicy` on `createModelRouter` (default ordered behavior byte-identical) with the reference `createCostLatencySelection` ranking by `ModelCost` then in-memory latency EMA fed from `recordOutcome({ latencyMs })`, permutation-only reorder of already-allowed candidates, misbehavior fails closed `ERR_PRISM_MODEL_ROUTER_POLICY`; (3) **async AgUiProjection closeout** — plan 009 Task 15 surface verified with evidence (`asyncHooks: {verified: true, gapFound: false}` in `scripts/phase19-baseline.json`), no new code; (4) **`prism providers add <name>` scaffold** — new CLI subcommand generating an OpenAI-compatible provider package (manifest, provider via `createOpenAICompatibleProvider`, starter models, cache helpers, offline conformance test, docs stub) with npm-name/traversal/symlink-escape validation and placeholders only — never secrets; scaffold output is host-chosen and never auto-registered. Store compatibility with 0.1.6: **compatible, no migration** (additive-only; no persisted-shape change; `docs/migration.md` gains no entries). Exit gate green: npm test core + script gates (incl. phase19-freeze done-phase), `sdk:ready` exit 0, audit 0 moderate, pack dry-run 50/50 twice byte-identical, budget/benchmark gates green; evidence in `scripts/phase19-baseline.json` `exitGate`. Rollback = restore the 0.1.6 manifests/tag.
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
# Operator prerequisites recorded: clean tree at the v0.1.7 tag candidate, GPG key, npm OIDC publisher.
|
|
283
|
+
npm test # core + workspace suites + all script gates
|
|
284
|
+
npm run sdk:ready # typecheck, lint, format, test, pack, release:gate
|
|
285
|
+
node scripts/release.mjs gate --version 0.1.7 # plain additive gate, 0 breaking deltas
|
|
286
|
+
npm run pack:dry-run # twice; diff reports — deterministic
|
|
287
|
+
npm audit --audit-level=moderate
|
|
288
|
+
npm run release:check -- --version 0.1.7 --report /tmp/prism-0.1.7-preflight.json
|
|
289
|
+
npm run release:publish -- --version 0.1.7 --dry-run --allow-dirty --allow-untagged --report /tmp/prism-0.1.7-dry-run.json
|
|
290
|
+
# run the dry-run twice and diff the reports: deterministic, byte-identical
|
|
291
|
+
|
|
292
|
+
# Sign the release on the clean tagged tree (operator GPG key):
|
|
293
|
+
git tag -s v0.1.7 -m "Prism 0.1.7 — performance and DX (additive)"
|
|
294
|
+
git verify-tag v0.1.7
|
|
295
|
+
git push origin v0.1.7 # tag push triggers release.yml publish job (provenance, attestations)
|
|
296
|
+
|
|
297
|
+
# Real publication never bypasses the gates: release.mjs refuses
|
|
298
|
+
# --allow-dirty/--allow-untagged without --dry-run.
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### 0.1.6 publish handoff (plan 018 Task 7)
|
|
302
|
+
|
|
303
|
+
**Decision: GO when the operator prerequisites below are recorded.** Release **0.1.6** (plan 018) is the coding-agent capability-closeouts patch on the frozen 0.1.x line — **additive-only** vs 0.1.5 (plain compat gate at 0.1.6 passed with 0 breaking declaration deltas; the baseline text was regenerated with `--update-baseline` for the version literal only, no `--allow-break` anywhere). Five demand-gated closeouts shipped, each flipped to `demanded` by named demand evidence (operator `arn` for native-sandbox/doc-reader/delete-glob/checkpoint-bodies, user `Clay` for acp-session-store) before its task landed; the demand-gate registry (`scripts/phase18-freeze-manifest.json`) machine-checks demanded ⇒ implemented, deferred ⇒ untouched. Shipped: (1) **durable ACP session store** — `@arnilo/prism-ag-ui` `AcpSessionStore` host seam (`save`/`loadAll`/`evict`), persisted `{sessionId, ownership, modeId, configValues, cwd, additionalDirectories, updatedAt}`, lazy ownership-scoped restore, fail-closed drops, absent seam = 0.1.5 behavior; (2) **network-free native sandbox** — `createNativeSandbox` in `@arnilo/prism-coding-security` (fresh netns per command via the OS `unshare` binary, chained ulimits with `|| exit 126`, argv-only exec, cwd containment, process-group kill, env allow-list, Linux-only fail-closed); (3) **bounded PDF/Office document reader** — new optional package `@arnilo/prism-document-reader` (the 50th manifest, graph 49 → 50) with optional `pdf-parse`/`mammoth` peers fail-closed at creation, magic-byte gating, null fall-through, caps + redaction at the adapter boundary; (4) **recursive delete + brace-expanding glob** — per-call `recursive: true` with fan-out cap and symlink-unlink-not-follow, host-selected/per-call `braceExpansion` bounded to 128 alternatives / 4096 expanded bytes, fail-closed on overflow/malformed braces; (5) **checkpoint persistence for loaded-skill bodies** — opt-in `includeSkillBodies` on run + resume options (names-only stays default, 0.1.3 shapes byte-identical), ≤64 bodies / ≤256-char names / ≤262144-byte bodies / ≤1 MiB total, `maxStateBytes` refusal, redacted at rest, registry-independent resume render. Store compatibility with 0.1.5: **compatible, no migration** (additive-only; no persisted-shape change; `docs/migration.md` gains no entries). Exit gate green: npm test core 1,433/1,433 + 190 script gates (incl. phase18-freeze done-phase), `sdk:ready` exit 0, audit 0 moderate, pack dry-run 50/50 twice byte-identical, budget/benchmark gates green; evidence in `scripts/phase18-baseline.json` `exitGate`. Rollback = restore the 0.1.5 manifests/tag.
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
# Operator prerequisites recorded: clean tree at the v0.1.6 tag candidate, GPG key, npm OIDC publisher.
|
|
307
|
+
npm test # core + workspace suites + all script gates
|
|
308
|
+
npm run sdk:ready # typecheck, lint, format, test, pack, release:gate
|
|
309
|
+
node scripts/release.mjs gate --version 0.1.6 # plain additive gate, 0 breaking deltas
|
|
310
|
+
npm run pack:dry-run # twice; diff reports — deterministic
|
|
311
|
+
npm audit --audit-level=moderate
|
|
312
|
+
npm run release:check -- --version 0.1.6 --report /tmp/prism-0.1.6-preflight.json
|
|
313
|
+
npm run release:publish -- --version 0.1.6 --dry-run --allow-dirty --allow-untagged --report /tmp/prism-0.1.6-dry-run.json
|
|
314
|
+
# run the dry-run twice and diff the reports: deterministic, byte-identical
|
|
315
|
+
|
|
316
|
+
# Sign the release on the clean tagged tree (operator GPG key):
|
|
317
|
+
git tag -s v0.1.6 -m "Prism 0.1.6 — coding-agent capability closeouts (additive)"
|
|
318
|
+
git verify-tag v0.1.6
|
|
319
|
+
git push origin v0.1.6 # tag push triggers release.yml publish job (provenance, attestations)
|
|
320
|
+
|
|
321
|
+
# Real publication never bypasses the gates: release.mjs refuses
|
|
322
|
+
# --allow-dirty/--allow-untagged without --dry-run.
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**Rollback notes.** `release:publish --version 0.1.6 --resume --report release-artifacts/publish-report.json` resumes an interrupted publication and skips only registry versions whose internal dependency fingerprint matches the local manifest. A failed package aborts the run with its status written to the report; re-run after fixing the cause. npm cannot unpublish the `0.1.6` line after 72 hours — a post-publication defect ships as a `0.1.x` patch (additive-only compat promise, `release:gate` enforced), or as a documented break in the next line with a `docs/migration.md` entry. `0.1.6` is store-compatible with `0.1.5` in **both directions** (no migration ran — same checksum-protected contract), so an operator may defer or roll back the patch without a database rollback. The next line **0.1.7** continues the frozen 0.1.x additive promise; the 0.2.0 module line (delegated agents, agent-owned persistence, host-owned seam expansions) is the next documented cut.
|
|
326
|
+
|
|
277
327
|
### 0.1.5 publish handoff (plan 017 Task 4)
|
|
278
328
|
|
|
279
329
|
**Decision: GO when the operator prerequisites below are recorded.** Release **0.1.5** (plan 017) is the **documented breaking cut** on the frozen 0.1.x line — deprecated-option removal, with the removed-symbols list, replacements, before/after examples, dynamic-config refusal behavior, store compatibility, and rollback in the top `docs/migration.md` `0.1.4 → 0.1.5` section. Removed: `ProviderRequestOptions.timeoutMs`/`maxRetries`/`maxRetryDelayMs` (inert in first-party providers; abort/retry lives at the host layer — replacements `RunOptions.signal`/`AgentConfig.retry`/`RunOptions.retry`), `RunOptions.maxToolRounds` (→ `limits.maxToolRounds`; CLI `--max-tool-rounds` unchanged), `ObservationalMemorySettingsInput` pre-0.0.19 flat keys and top-level `workerProvider`/`workerModel` aliases (→ nested `observation`/`reflection`/`dropper` configs; `sessionModel` fallback unchanged), `ReadToolOptions.autoResizeImages` (→ `transformImage`), and `INIT_PROVIDERS` (→ `listInitProviders()`). Every removal **fails closed** for untyped callers with a `TypeError` naming the replacement before any provider call, tool call, filesystem access, compaction, or session append. Compat baselines were regenerated only after the reviewed `--allow-break` break report: `arnilo__prism.txt` (removed `INIT_PROVIDERS` const + `maxToolRounds`/provider-knob member lines — interface members are not baseline text, so the delta is the `INIT_PROVIDERS` line), `arnilo__prism-coding-agent.txt` (`autoResizeImages` is an interface member — baseline delta limited to statement/re-export text if any), `arnilo__prism-compaction-observational-memory.txt` (flat keys and worker aliases are interface members — no baseline line delta expected). Publishable graph stays **49** manifests (root + 48 workspace) at exact **0.1.5**. Store compatibility with 0.1.4: **compatible, no migration** (removed options were inert aliases; nested replacements resolve to the same active values; `DEFAULT_RUN_LIMITS.maxToolRounds` 8 / hard cap 64 unchanged); zero new dependencies (lockfile name-set unchanged).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arnilo/prism",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Agent harness for AI providers, agents, sessions, and tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -134,6 +134,7 @@
|
|
|
134
134
|
"packages/enterprise-postgres",
|
|
135
135
|
"packages/browser",
|
|
136
136
|
"packages/ag-ui",
|
|
137
|
+
"packages/document-reader",
|
|
137
138
|
"packages/prism-*"
|
|
138
139
|
],
|
|
139
140
|
"scripts": {
|
|
@@ -142,7 +143,7 @@
|
|
|
142
143
|
"build": "npm run build:core && npm run build --workspaces --if-present",
|
|
143
144
|
"typecheck": "npm run build && npm run typecheck --workspaces --if-present && tsc -p examples --noEmit",
|
|
144
145
|
"sweep:unused": "node scripts/sweep-unused.mjs",
|
|
145
|
-
"test": "npm run build && node --test dist/__tests__/*.test.js && node --test scripts/release-gate.test.mjs scripts/tooling-gate.test.mjs scripts/budget-gate.test.mjs scripts/phase8-conformance.test.mjs scripts/phase9-conformance.test.mjs scripts/phase10-conformance.test.mjs scripts/phase11-conformance.test.mjs scripts/phase11-freeze.test.mjs scripts/phase12-freeze.test.mjs scripts/phase13-freeze.test.mjs scripts/phase14-freeze.test.mjs scripts/phase15-freeze.test.mjs scripts/phase16-freeze.test.mjs scripts/phase17-freeze.test.mjs scripts/benchmark-0.1.0.test.mjs scripts/sweep-unused.test.mjs scripts/e2e-enterprise-journey.test.mjs scripts/e2e-coding-journey.test.mjs && npm run test --workspaces --if-present",
|
|
146
|
+
"test": "npm run build && node --test dist/__tests__/*.test.js && node --test scripts/release-gate.test.mjs scripts/tooling-gate.test.mjs scripts/budget-gate.test.mjs scripts/phase8-conformance.test.mjs scripts/phase9-conformance.test.mjs scripts/phase10-conformance.test.mjs scripts/phase11-conformance.test.mjs scripts/phase11-freeze.test.mjs scripts/phase12-freeze.test.mjs scripts/phase13-freeze.test.mjs scripts/phase14-freeze.test.mjs scripts/phase15-freeze.test.mjs scripts/phase16-freeze.test.mjs scripts/phase17-freeze.test.mjs scripts/phase18-freeze.test.mjs scripts/phase19-freeze.test.mjs scripts/benchmark-0.1.0.test.mjs scripts/sweep-unused.test.mjs scripts/e2e-enterprise-journey.test.mjs scripts/e2e-coding-journey.test.mjs && npm run test --workspaces --if-present",
|
|
146
147
|
"test:coverage": "node --test --experimental-test-coverage --test-coverage-lines=60 --test-coverage-functions=70 --test-coverage-branches=75 --test-coverage-exclude='**/__tests__/**' --test-coverage-exclude='**/node_modules/**' --test-coverage-exclude='**/scripts/**' --test-coverage-exclude='**/packages/**' --test-coverage-exclude='**/examples/**' dist/__tests__/*.test.js && node scripts/coverage-summary.mjs",
|
|
147
148
|
"coverage:summary": "node scripts/coverage-summary.mjs",
|
|
148
149
|
"lint": "biome lint .",
|