@arnilo/prism 0.3.0 → 0.3.1
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 +27 -0
- package/README.md +3 -1
- package/dist/agent-loops.js +45 -8
- package/dist/agent-session/helpers.js +2 -2
- package/dist/cache-helpers.d.ts +11 -0
- package/dist/cache-helpers.js +29 -5
- package/dist/cli-provider-add.js +2 -1
- package/dist/context-budget.js +9 -6
- package/dist/contracts-core/agent.d.ts +2 -0
- package/dist/contracts-core/provider.d.ts +2 -0
- package/dist/event-multiplexer.js +0 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.js +5 -3
- package/dist/input.js +19 -11
- package/dist/node/session-store-jsonl.js +7 -3
- package/dist/providers/openai-compatible.js +2 -1
- package/dist/providers/openai-primitives.js +2 -1
- package/dist/providers/schema.d.ts +7 -0
- package/dist/providers/schema.js +25 -0
- package/dist/testing/provider-conformance.d.ts +10 -0
- package/dist/testing/provider-conformance.js +37 -0
- package/dist/trim-trailing-slashes.d.ts +8 -0
- package/dist/trim-trailing-slashes.js +14 -0
- package/docs/0.1.0-readiness.md +1 -1
- package/docs/acp.md +1 -0
- package/docs/ag-ui.md +1 -0
- package/docs/agent-loops.md +3 -0
- package/docs/agent-session-runtime.md +1 -0
- package/docs/browser-automation.md +1 -0
- package/docs/database-persistence.md +1 -1
- package/docs/graft.md +125 -0
- package/docs/host-security.md +3 -1
- package/docs/index.md +11 -9
- package/docs/input-and-prompt-assembly.md +11 -6
- package/docs/instruction-injection.md +1 -1
- package/docs/mcp-tools.md +1 -0
- package/docs/migration.md +10 -0
- package/docs/node-jsonl-session-store.md +1 -1
- package/docs/obscura.md +175 -0
- package/docs/observability.md +21 -1
- package/docs/performance.md +58 -4
- package/docs/ponytail.md +1 -1
- package/docs/provider-caching.md +13 -11
- package/docs/provider-conformance.md +6 -0
- package/docs/provider-packages.md +1 -1
- package/docs/provider-primitives.md +15 -2
- package/docs/providers/ai-sdk.md +1 -1
- package/docs/providers/anthropic.md +1 -1
- package/docs/providers/azure.md +1 -0
- package/docs/providers/bedrock.md +1 -0
- package/docs/providers/kimi.md +2 -1
- package/docs/providers/openai.md +19 -7
- package/docs/providers/opencode-go.md +3 -1
- package/docs/providers/openrouter.md +4 -3
- package/docs/providers/vertex.md +1 -0
- package/docs/public-contracts.md +2 -1
- package/docs/rag.md +55 -8
- package/docs/release-and-install.md +45 -7
- package/docs/server.md +1 -0
- package/docs/supervisors.md +3 -2
- package/docs/system-prompts.md +1 -1
- package/docs/tools.md +1 -1
- package/docs/web-tools.md +2 -0
- package/docs/wiki.md +140 -0
- package/docs/workflows.md +4 -3
- package/docs/working-and-semantic-memory.md +20 -0
- package/package.json +12 -5
- package/docs/api-page-template.md +0 -32
- package/docs/release-0.2.7-evidence.md +0 -514
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { reconstructToolCallDeltas } from "../provider-events.js";
|
|
2
|
+
import { canonicalizeJsonSchema } from "../providers/schema.js";
|
|
2
3
|
export async function collectProviderEvents(provider, request) {
|
|
3
4
|
const events = [];
|
|
4
5
|
for await (const event of provider.generate(request))
|
|
@@ -63,6 +64,12 @@ export function assertSerializedRequestCoversContent(request, body, options = {}
|
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
66
|
}
|
|
67
|
+
export function assertCanonicalToolParameters(serialized, original) {
|
|
68
|
+
const expected = canonicalizeJsonSchema(original ?? { type: "object" });
|
|
69
|
+
if (JSON.stringify(serialized) !== JSON.stringify(expected)) {
|
|
70
|
+
throw new Error("Tool parameters were not canonicalized");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
66
73
|
export function assertProviderOwnedHeadersWin(captured, options) {
|
|
67
74
|
const ownedLower = {};
|
|
68
75
|
for (const [name, expected] of Object.entries(options.owned))
|
|
@@ -89,6 +96,36 @@ export function assertNoSecretLeak(events, secrets) {
|
|
|
89
96
|
throw new Error(`Secret leaked into provider events: ${secret.slice(0, 8)}...`);
|
|
90
97
|
}
|
|
91
98
|
}
|
|
99
|
+
/** Known cache wire fields across protocols; any of these in a request body is an explicit cache control. */
|
|
100
|
+
const CACHE_WIRE_FIELDS = [
|
|
101
|
+
"cache_control",
|
|
102
|
+
"prompt_cache_key",
|
|
103
|
+
"prompt_cache_retention",
|
|
104
|
+
"prompt_cache_options",
|
|
105
|
+
"prompt_cache_breakpoint",
|
|
106
|
+
"cachedContent",
|
|
107
|
+
"cachePoint",
|
|
108
|
+
];
|
|
109
|
+
/**
|
|
110
|
+
* Implicit/none-cache providers must serialize no foreign cache fields: implicit
|
|
111
|
+
* caching works by byte-stable prefix reuse, not request payloads. `allowed` names
|
|
112
|
+
* fields the provider documents for that route (e.g. `cachedContent` via the host
|
|
113
|
+
* `extra.cachedContent` escape hatch on Gemini).
|
|
114
|
+
*/
|
|
115
|
+
export function assertNoForeignCacheFields(body, allowed = []) {
|
|
116
|
+
const bodyText = JSON.stringify(body);
|
|
117
|
+
for (const field of CACHE_WIRE_FIELDS) {
|
|
118
|
+
if (allowed.includes(field))
|
|
119
|
+
continue;
|
|
120
|
+
if (bodyText.includes(field))
|
|
121
|
+
throw new Error(`Serialized request carries foreign cache field "${field}"`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** Provider construction and setup must perform zero network calls; discovery and streams are caller-gated. */
|
|
125
|
+
export function assertNoFetches(calls) {
|
|
126
|
+
if (calls.length > 0)
|
|
127
|
+
throw new Error(`Provider fetched ${calls.length} time(s) outside caller-gated discovery/stream`);
|
|
128
|
+
}
|
|
92
129
|
export function assertUsageAccounting(events, expected) {
|
|
93
130
|
const usage = [...events].reverse().find((event) => (event.type === "done" && event.usage) || event.type === "usage");
|
|
94
131
|
const actual = usage?.type === "usage" ? usage.usage : usage?.usage;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trims trailing "/" characters with a linear index scan.
|
|
3
|
+
*
|
|
4
|
+
* Shared replacement for `value.replace(/\/+$/, "")` (CodeQL js/polynomial-redos):
|
|
5
|
+
* no regex is evaluated, so hostile long inputs cannot backtrack. Semantics are
|
|
6
|
+
* identical — only trailing "/" characters (U+002F) are removed; "" and "/" stay "".
|
|
7
|
+
*/
|
|
8
|
+
export declare function trimTrailingSlashes(value: string): string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trims trailing "/" characters with a linear index scan.
|
|
3
|
+
*
|
|
4
|
+
* Shared replacement for `value.replace(/\/+$/, "")` (CodeQL js/polynomial-redos):
|
|
5
|
+
* no regex is evaluated, so hostile long inputs cannot backtrack. Semantics are
|
|
6
|
+
* identical — only trailing "/" characters (U+002F) are removed; "" and "/" stay "".
|
|
7
|
+
*/
|
|
8
|
+
export function trimTrailingSlashes(value) {
|
|
9
|
+
let end = value.length;
|
|
10
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47)
|
|
11
|
+
end -= 1;
|
|
12
|
+
return value.slice(0, end);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=trim-trailing-slashes.js.map
|
package/docs/0.1.0-readiness.md
CHANGED
|
@@ -20,7 +20,7 @@ Historical release lines (0.0.16 floor → 0.0.27 Phase 10 ACP interop → 0.1.0
|
|
|
20
20
|
keep their per-phase evidence in the pages above; this page records the 0.2.6
|
|
21
21
|
snapshot (plan 026) with the 0.1.x tables below as the historical record.
|
|
22
22
|
|
|
23
|
-
## Current line (0.3.
|
|
23
|
+
## Current line (0.3.1)
|
|
24
24
|
|
|
25
25
|
| Item | Status |
|
|
26
26
|
|---|---|
|
package/docs/acp.md
CHANGED
|
@@ -164,3 +164,4 @@ const agent = createPrismAcpAgent({
|
|
|
164
164
|
- [Host security guide](host-security.md): fail-closed checklist rows for ACP boundaries (authorize, ownership, redaction, untrusted MCP).
|
|
165
165
|
- [Migration guide](migration.md): 0.0.26 → 0.0.27 advertise/surface changes for hosts that parsed the old `initialize`.
|
|
166
166
|
- [AG-UI adoption evaluation](ag-ui-adoption.md): the underlying input/event/capability matrix.
|
|
167
|
+
- [Obscura browser engine](obscura.md): optional binary-backed generic tools behind the session prompt loop.
|
package/docs/ag-ui.md
CHANGED
|
@@ -221,6 +221,7 @@ Defaults / hard caps: request 64 KiB / 1 MiB; input 128 / 1024 messages, 32 / 25
|
|
|
221
221
|
- [A2A interoperability](a2a.md): remote agent-to-agent tasks, not frontend protocol mapping.
|
|
222
222
|
- [AG-UI adoption evaluation](ag-ui-adoption.md): official 0.0.57 event/input matrix and shipped explicit MCP/MCP Apps/A2A handshakes.
|
|
223
223
|
- [ACP coding-host interop](acp.md): the full ACP reference — seam-based capability advertisement, session modes/config, MCP select, fs/terminal adapters, lifecycle mapping, elicitation, and caps.
|
|
224
|
+
- [Obscura browser engine](obscura.md): optional binary-backed generic tools selectable through the MCP adapter.
|
|
224
225
|
- [MCP bridge/server](mcp-tools.md): `mcpApps` negotiation, bounded resources, and remote tool trust.
|
|
225
226
|
- [A2A interoperability](a2a.md): verified rich task client and remote task lifecycle.
|
|
226
227
|
- [Host security guide](host-security.md): authorization, ownership, redaction, and credential boundaries.
|
package/docs/agent-loops.md
CHANGED
|
@@ -128,6 +128,8 @@ Optional steer hooks on `LoopContext` (0.0.11): `hasPendingSteers?()` / `applyPe
|
|
|
128
128
|
|
|
129
129
|
The snapshot is stored as `loopState: { name, revision, snapshot }` on the durable run state and cleared when the run reaches a terminal status. On resume, a name/revision mismatch between the stored `loopState` and the resolved strategy fails closed (`ERR_PRISM_LOOP_REVISION`), and the fingerprint check independently rejects any loop drift. Suspension occurs only before an input provider call or immediately before a tool side effect; completed provider turns remain in `SessionStore` history and are not repeated after `resumeAgentRun()`.
|
|
130
130
|
|
|
131
|
+
A strategy returned by `generateValidateReviseLoop()` is safe to reuse across sequential runs. Its built-in state is scoped to `(sessionId, runId)`; a new non-restored run resets attempts, artifact phase, saved schema, and pending repair messages, while a restored run keeps the checkpointed state. Arbitrary custom strategies are not cloned or reset automatically.
|
|
132
|
+
|
|
131
133
|
## Outputs / response / events
|
|
132
134
|
|
|
133
135
|
`AgentLoopStrategy.run(ctx)` returns `Promise<Usage | undefined>` as a fallback for custom loops. Core runtime independently accumulates every usage-bearing provider turn in O(turns), persists scoped turn/run rows, and emits `agent_finished` with the aggregate.
|
|
@@ -231,6 +233,7 @@ await session.run(input, { loop: twoShotLoop });
|
|
|
231
233
|
- `ArtifactValidation.errors[].message` may echo model text — `artifact_*` event payloads flow through the same `redactAgentEvent` path as other `AgentEvent`s (see [Agent events](agent-events.md)).
|
|
232
234
|
- `generateValidateReviseLoop` makes at most `1 + maxRevisions + maxToolRounds` provider turns when bounded tools are enabled (otherwise `maxRevisions + 1`); it cannot loop forever. Each revision costs one provider turn plus one store append.
|
|
233
235
|
- Bounded artifact tool calls run sequentially through `dispatchToolCall` (permission + validation + execute); their assistant call and result are persisted before the next provider request. `singleShotLoop` retains its bounded parallel worker pool and original call-order transcript behavior.
|
|
236
|
+
- In a parallel single-shot batch, the worker pool stops claiming calls after the first dispatch error or abort, waits for every already-claimed worker with `Promise.allSettled`, appends no buffered tool-result rows for a failed batch, then rethrows the first failure. Already-claimed side effects may finish and are not rolled back; successful batches still append results in original call order. The round-level `chargeToolRound` approval gate runs before workers, so approval suspension starts no worker.
|
|
234
237
|
- The loop is a plain object/factory; no class hierarchy, no background work, no extra dependencies. `LoopContext` is a single object literal of bound arrows built once per run.
|
|
235
238
|
- The host-domain-free boundary is guarded by tests: `src/` imports no host-domain package, and the `Artifact*`/`AgentLoop*`/`LoopContext` contracts contain no `workflow`/`node`/`step` field names. Hosts supply their own schema; no host domain type is imported by `src/`.
|
|
236
239
|
|
|
@@ -221,6 +221,7 @@ Per-run options may narrow `limits` and append `guardrails`; they cannot replace
|
|
|
221
221
|
- [Session stores and branching](session-stores-and-branching.md): `SessionStore`, memory store, branch helpers, and context rebuild.
|
|
222
222
|
- [Compaction and retry policies](compaction-and-retry.md): compaction strategy/config APIs used by `session.compact()` and auto-compaction, plus retry policy/config APIs.
|
|
223
223
|
- [Tools](tools.md): host-owned tool harness used by the bounded runtime tool loop.
|
|
224
|
+
- [Obscura browser engine](obscura.md): optional binary-backed tool array that composes into `createAgent({ tools })` with no host branch.
|
|
224
225
|
- [Middleware hooks](middleware-hooks.md): hooks that configured assembly/runtime can run.
|
|
225
226
|
- [CLI/RPC](cli-rpc.md): terminal and JSONL adapters over this runtime.
|
|
226
227
|
- [Workflows](workflows.md): optional DAG orchestration that calls `AgentSession.run()` for agent nodes.
|
|
@@ -122,6 +122,7 @@ Default tests use fake Playwright APIs only. Protected live gate: `PRISM_LIVE_PL
|
|
|
122
122
|
|
|
123
123
|
## Related APIs
|
|
124
124
|
|
|
125
|
+
- [Obscura browser engine](obscura.md): optional host-installed Obscura headless browser connected with `chromium.connectOverCDP` through `connectObscuraCdp` — its returned browser plugs directly into `createBrowserTools`/`createBrowserManager` as the host-supplied Playwright browser; pages on one Obscura worker share one V8 isolate, and screenshots/PDF need a render-enabled build.
|
|
125
126
|
- [Tools](tools.md): registry, exclusive dispatch, validation, and ledger.
|
|
126
127
|
- [Web search, fetch, and extraction](web-tools.md): preferred non-interactive retrieval path.
|
|
127
128
|
- [Guardrails](guardrails.md): untrusted external content handling.
|
|
@@ -389,7 +389,7 @@ For document or wide-column stores, map the relational tables above to the store
|
|
|
389
389
|
- **Branches:** In document stores, a branch can be a lightweight document keyed by `leaf_entry_id` that points to the session and root. Rebuild still walks `parent_id` links in entries.
|
|
390
390
|
- **Retention:** Use TTL columns or scheduled map-reduce/streaming jobs. TTL on `expires_at` or entry timestamps is the simplest NoSQL implementation.
|
|
391
391
|
|
|
392
|
-
The Node JSONL session store is a single-process development adapter. It has no cross-process locking, no migrations, no retention enforcement, and no tenant isolation. Do not use it as a production multi-writer store.
|
|
392
|
+
The Node JSONL session store is a single-process development adapter. It has no cross-process locking, no migrations, no retention enforcement, and no tenant isolation. Do not use it as a production multi-writer store. Appends serialize per instance; a rejected append (conflict, duplicate, corrupt file) does not poison later appends on that instance. The rejected write is not committed.
|
|
393
393
|
|
|
394
394
|
## Request/response example
|
|
395
395
|
|
package/docs/graft.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Graft context-graph integration
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
`@arnilo/prism-graft` is an optional package that wires [nanonets/graft](https://github.com/nanonets/graft) — a repository context-graph CLI (`graft/` directory, INDEX.md orientation, symbol-level wiring graph) — into Prism contribution contracts.
|
|
6
|
+
|
|
7
|
+
It registers six pull tools backed by the graft CLI (`--json`, argv-safe), a push-mode retrieval-pack context provider plus first-turn orientation injector carried on the `graft` skill, commands (`graft`, `graft-build`, `graft-check`, `graft-viz`), and an edit-watch middleware that computes blast radius after mutating tool calls. Import is inert; a missing graft CLI fails closed at `setup` with a bounded redacted error.
|
|
8
|
+
|
|
9
|
+
## When to use it
|
|
10
|
+
|
|
11
|
+
Use it when a host wants agents to locate code by architecture, callers, and coupling before grep-spelunking. Three modes:
|
|
12
|
+
|
|
13
|
+
- `"pull"` (default) — register the tools; the agent decides when to query.
|
|
14
|
+
- `"push"` — per-turn retrieval pack (pointers only) + first-turn orientation, injected automatically.
|
|
15
|
+
- `"both"` — everything.
|
|
16
|
+
|
|
17
|
+
Install optional peer `@nanonets/graft@^0.13.0` **or** pass `packageRoot`/`cliPath` explicitly. Pair with progressive disclosure: the `graft` skill body stays small; tool schemas carry the details. Graft complements indexed code search (`repository_search`): graph/semantic locators vs literal search — neither replaces the other.
|
|
18
|
+
|
|
19
|
+
Zero-code alternative (L0): hosts can skip this package entirely and let agents call `graft <command> --json` through their shell tool, optionally seeding context with graft's own generated instruction files. This package exists for native-tool ergonomics, budgeted subprocesses, session persistence, and push mode.
|
|
20
|
+
|
|
21
|
+
## Inputs / request
|
|
22
|
+
|
|
23
|
+
`createGraftExtension(options)`:
|
|
24
|
+
|
|
25
|
+
| Field | Type | Required | Purpose |
|
|
26
|
+
| --- | --- | --- | --- |
|
|
27
|
+
| `cliPath` / `packageRoot` | `string` | no | Explicit stub/binary or checkout root with a manifest-declared bin; default resolves optional peer `@nanonets/graft`. Relative paths rejected; explicit paths existence-checked at resolve time. |
|
|
28
|
+
| `mode` | `"pull" \| "push" \| "both"` | no | Surface selection. Default `pull`. |
|
|
29
|
+
| `projectDir` | `string` | no | Directory graft operates on. Default `process.cwd()` at setup. |
|
|
30
|
+
| `retrievalBudgetMs` | `number` | no | Wall-clock budget per CLI child call (default 8000). |
|
|
31
|
+
| `maxResultBytes` | `number` | no | Stdout cap before parsing (default 512 KiB). |
|
|
32
|
+
| `maxPromptChars` | `number` | no | Prompts longer than this never become ask argv (default 4096). |
|
|
33
|
+
| `allowUpstreamTelemetry` | `boolean` | no | Default false → children run with `DO_NOT_TRACK=1`. |
|
|
34
|
+
| `providerEnv` | `Record<string, string>` | no | Explicit graft provider settings (`GRAFT_API_KEY`, …). Never inherited from host env; only `GRAFT_*` keys reach the child. |
|
|
35
|
+
| `editToolNames` | `readonly string[]` | no | Tools triggering blast-radius lookup. Default `write`, `edit`, `move`. |
|
|
36
|
+
| `quietStartup`, `hideStatus` | `boolean` | no | Suppress startup status events / status reporting. |
|
|
37
|
+
| `appendEntry` | `(entry, opts?) => Promise<void>` | yes | Host session append (OM attach pattern). |
|
|
38
|
+
| `getEntries` | `() => readonly SessionEntry[] \| Promise<...>` | yes | Current branch entries for state restore. |
|
|
39
|
+
|
|
40
|
+
Pull tools (mode includes `pull`): `graft_ask`, `graft_grep`, `graft_callers`, `graft_skeleton`, `graft_map`, `graft_blast`.
|
|
41
|
+
|
|
42
|
+
Push surfaces (mode includes `push`): skill `graft` carrying context provider `graft-context` (per-turn pointers-only pack, gated: ≥12-char prompt, dedup by seen node ids, 32 KiB block ceiling) and instruction injector `graft-orient` (`first_turn`, byte-capped INDEX.md cut + staleness banner).
|
|
43
|
+
|
|
44
|
+
Registered commands: `graft` (`status` \| `build` \| `check` \| `viz` dispatch), plus `graft-build`, `graft-check`, `graft-viz` aliases.
|
|
45
|
+
|
|
46
|
+
## Outputs / response / events
|
|
47
|
+
|
|
48
|
+
| Export | Purpose |
|
|
49
|
+
| --- | --- |
|
|
50
|
+
| `createGraftExtension(options)` | Returns an inert `Extension` until `kernel.load([...])`; emits `graft:loaded` on setup. |
|
|
51
|
+
| `resolveGraftCli(options)` | Fail-closed CLI resolution (`explicit` → command+argv, `peer-bin` → node + manifest bin). |
|
|
52
|
+
| `runGraftJson(cli, argv, options)` / `childEnv(options)` / `childTimeoutMs` / `DEFAULT_MAX_RESULT_BYTES` | Shared budgeted JSON runner for hosts building custom surfaces. |
|
|
53
|
+
| `readBoundedFile` / `redactPaths` / `GraftResolveError` | Bounded-read and redaction helpers. |
|
|
54
|
+
|
|
55
|
+
Events: `graft:status` (check/build outcomes), `graft:dirty` (post-edit, repo-relative path + optional `staleCountEstimate`), `graft:loaded` (mode + cliKind metadata).
|
|
56
|
+
|
|
57
|
+
Session custom entry shape (`data.type === "graft-state"`, CAS via `expectedParentId`):
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{ "kind": "custom", "data": { "type": "graft-state", "freshness": { "checkedAt": "...", "fresh": true }, "seen": ["node-a"], "savedTokensApprox": 120 } }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The graph never rebuilds itself mid-session (no auto-rebuild): after edits, ask/grep results may lag one turn; graft self-refreshes on the next indexed query, or run `/graft build` for an immediate refresh. The skill text states this contract to the agent.
|
|
64
|
+
|
|
65
|
+
## Request/response example
|
|
66
|
+
|
|
67
|
+
Tool call (pull):
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{ "name": "graft_ask", "arguments": { "query": "where is auth handled?", "count": 3 } }
|
|
71
|
+
→ { "nodes": [{ "id": "auth-guard", "title": "requireAuth", "path": "src/auth.ts", "line": 41 }] }
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Status event:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{ "type": "graft:status", "extension": "@arnilo/prism-graft", "metadata": { "fresh": true, "missing": 0, "stale": 2 } }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Implementation example
|
|
81
|
+
|
|
82
|
+
See [`examples/graft-extension.ts`](../examples/graft-extension.ts) — network-free demo against the package fixture stub: one pull-tool call, one push turn with pack injection + dedup, one simulated edit producing blast radius, and the `DO_NOT_TRACK` child-env guard.
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { createExtensionKernel, createMemorySessionStore } from "@arnilo/prism";
|
|
86
|
+
import { createGraftExtension } from "@arnilo/prism-graft";
|
|
87
|
+
|
|
88
|
+
const store = createMemorySessionStore();
|
|
89
|
+
const kernel = createExtensionKernel({ errorPolicy: "throw" });
|
|
90
|
+
await kernel.load([
|
|
91
|
+
createGraftExtension({
|
|
92
|
+
packageRoot: "./vendor/graft-checkout",
|
|
93
|
+
mode: "both",
|
|
94
|
+
quietStartup: true,
|
|
95
|
+
appendEntry: async (entry, options) => store.append(entry, options),
|
|
96
|
+
getEntries: async () => store.list("s1"),
|
|
97
|
+
}),
|
|
98
|
+
]);
|
|
99
|
+
// Pull: dispatch graft_ask/… tools. Push: runs assemble the skill-carried
|
|
100
|
+
// provider + graft-orient injector. Edits: middleware emits graft:dirty.
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Extension and configuration notes
|
|
104
|
+
|
|
105
|
+
- Import alone registers nothing (`sideEffects: false`); no timers, watchers, or network. The only child processes are budgeted graft CLI calls.
|
|
106
|
+
- Retrieval happens in-process via Prism primitives (context provider, injector, tool_result middleware) — no external hook shims.
|
|
107
|
+
- Ask result shape is parsed tolerantly (`nodes|results|matches|hits`) because graft is pre-1.0; formatters emit pointers (`title` + `file:line` + `[[wikilink]]`), never source bodies.
|
|
108
|
+
- Not included in `@arnilo/prism-code`, `@arnilo/prism-sdk`, or the `prism-all` umbrella (deliberate opt-out, like Caveman/Ponytail) — opt-in install only.
|
|
109
|
+
- Multi-repo layouts work as upstream graft defines them (workspaces, submodules with `--follow-submodules`, sibling repos); point `projectDir` at the graft root that owns the target repo.
|
|
110
|
+
|
|
111
|
+
## Security and performance notes
|
|
112
|
+
|
|
113
|
+
- Telemetry default-off: children always get `DO_NOT_TRACK=1` unless `allowUpstreamTelemetry` is true; child env is fixed-base — host env vars are never inherited, and only explicit `GRAFT_*` keys from `providerEnv` pass through. Route secrets like `GRAFT_API_KEY` through the host's credential resolution when populating `providerEnv`.
|
|
114
|
+
- Upstream output is untrusted: stdout capped (`maxResultBytes`), prompts capped (`maxPromptChars`), injected packs bounded (32 KiB), orientation cut byte-capped (8 KiB); error paths are logged redacted (absolute paths/home dirs).
|
|
115
|
+
- Every CLI call is wall-clock-budgeted (`retrievalBudgetMs`, minus fixed overhead for the timeout math) and every failure degrades silently: pull tools return structured errors, the push pack contributes nothing, edit-watch passes the tool result through untouched.
|
|
116
|
+
- No background workers; state persists through two CAS appends per turn at most (freshness patch, seen-set/saved-tokens update).
|
|
117
|
+
|
|
118
|
+
## Related APIs
|
|
119
|
+
|
|
120
|
+
- [Ponytail behavior integration](ponytail.md): same adapter pattern (optional peer/upstream path, fail-closed setup, session custom entries).
|
|
121
|
+
- [Caveman behavior integration](caveman.md): complementary terse-communication mode package.
|
|
122
|
+
- [Indexed code search](indexed-code-search.md): literal `repository_search` seam — complement, not overlap.
|
|
123
|
+
- [Context and skills](context-and-skills.md): progressive catalog + `load_skill`; skill-carried context providers.
|
|
124
|
+
- [Instruction injection](instruction-injection.md): injector seams (`graft-orient` rides `first_turn`).
|
|
125
|
+
- [Extension kernel and event bus](extensions.md): explicit `kernel.load`, extension events.
|
package/docs/host-security.md
CHANGED
|
@@ -155,6 +155,7 @@ Wire those values where they matter: provider adapters receive the resolved cred
|
|
|
155
155
|
- Optional `@arnilo/prism-browser` requires a host-supplied Playwright Browser (`playwright-core@1.61.0` peer). Import is inert. One non-persistent context belongs to one run; actions serialize; refs are snapshot-scoped; CSS/evaluate/CDP/persistent profiles are denied. Context routing + `serviceWorkers: "block"` deny file/data/blob/devtools/private/loopback by default and require contained-proxy attestation for external egress (Playwright routing is defense in depth, not DNS containment). Uploads are realpath-rooted; downloads quarantine with hash/MIME until host `approveRelease`; screenshots return bounded `ImageContent`. Observation vs mutation/high-impact actions map to `ExecutionPolicy`. Treat snapshot/page text as untrusted external content. Close contexts with `browser_close` or `manager.closeRun(runId)` on abort/terminal. Browser control endpoint, binary/image pin, and real egress firewall/proxy remain host-owned. Shared sandbox: `createSharedSandboxBrowserOptions()` + `assertBrowserSandboxNetwork()`.
|
|
156
156
|
- Browser verified-state checkpoints (0.0.14, `createBrowserCheckpointLedger()`) store URL + domain-state hash + host data refs only — never serialized browser internals (cookies/storage/contexts). After any resume/interruption the ledger fails closed (`assertVerifiedBeforeSideEffect`) until the host reloads + verifies, so side effects never replay on stale state.
|
|
157
157
|
- Device adapters (0.0.14, `resolveDevicePolicy`/`assertDeviceAdmit`) are deny-by-default: admission fails closed without explicit `enabled`, an explicit sandbox, approval (when required), an under-budget session count, and shared `RunLimits`. Stream chunks over the frozen cap are dropped with a marker; telemetry is redacted before emit/persist. No vendor voice/desktop package ships in 0.0.14 (demand-gated 0.1.x); device adapters cannot broaden consent/memory/network/file/browser/connector/tool permissions (gate 8).
|
|
158
|
+
- Optional `@arnilo/prism-wiki` tools treat agent-supplied input as untrusted at the first-party `.wiki/` filesystem boundary. `wiki_read_page` enforces lexical containment (`path.relative` with separator-aware `..`/absolute checks) plus `fs.realpath` containment for the wiki root and every successfully read file, so sibling-prefix (`.wiki-evil`), `..`, absolute, alternate-separator, and symlink escapes are denied before content is returned; missing contained pages report `found: false` while denied paths throw an access-denied error (never mapped to not-found). `wiki_record_insight` rejects empty titles/content, caps titles at 200 characters and content at 65,536 bytes, and collapses control characters and newlines in titles to single-line display text before any page/frontmatter/index/log write, so titles cannot inject Markdown headings, index entries, or log entries; slugs are allow-listed to `[a-z0-9-_]` with a non-empty fallback. See [LLM Wiki](wiki.md).
|
|
158
159
|
- `@arnilo/prism-credentials-node` rejects oversized/malformed envelopes and excessive scrypt work before KDF allocation, uses async scrypt, and requires restrictive existing/new Unix vault modes. Keep vault ownership and parent-directory access host-controlled; review before `chmod 600`, never auto-weaken a file policy. Keychain calls use abort-aware native async work with finite timeout/payload caps and sanitized errors. OS prompts, service availability, and whether a native backend promptly honors cancellation remain host/platform boundaries; no plaintext fallback is attempted.
|
|
159
160
|
- LLM compaction always sends finite summary `maxTokens`, retains bounded deltas/events, and bounds/redacts provider/factory/policy error detail. Observational-memory workers cap turns, calls, arguments, results, transcript, and surfaced errors; unknown tools fail before execution, while invalid results can only be rejected after a host tool returns and may therefore follow side effects. Pass all known provider/credential/tool secrets into compaction/runtime options; exact replacement is not secret discovery.
|
|
160
161
|
- Default remote-media loading resolves every DNS answer, rejects the hostname if any address is non-public, and pins one validated address through the request. Explicit `allowedHostnames` can trust private destinations. A host-supplied `fetch` owns DNS/rebinding/proxy/redirect safety; a custom `requestUrl` must connect to its supplied validated address.
|
|
@@ -172,7 +173,7 @@ Wire those values where they matter: provider adapters receive the resolved cred
|
|
|
172
173
|
- License inventory: 160 locked third-party packages; all declare permissive MIT, ISC, BSD, Apache-2.0, or compatible dual licenses. No GPL, AGPL, SSPL, or missing lockfile license metadata.
|
|
173
174
|
- Install scripts: only `better-sqlite3@12.11.1` runs an install script (`prebuild-install || node-gyp rebuild --release`), required by the explicitly installed SQLite adapter. Core and other optional packages add no install hook.
|
|
174
175
|
- Secret scan: source, tests, docs, workflow files, package metadata, built tests, packed-install canary, and tarball deny-list checks found no private-key block or common live-token prefix. Runtime redaction fixtures cover requests, events, ledgers, stores, checkpoints, provider/OAuth errors, and credential ciphertext.
|
|
175
|
-
- Threat suites pass for parameterized SQL/tenant isolation, HTTP URL/SSRF rejection, realpath/symlink containment, shell-metacharacter approval, schema prototype-pollution/remote-reference bounds, OAuth polling/abort/redaction, credential tamper/wrong-key/KDF floors, MCP result bounds/timeouts, and coding approval/path policy.
|
|
176
|
+
- Threat suites pass for parameterized SQL/tenant isolation, HTTP URL/SSRF rejection, realpath/symlink containment, shell-metacharacter approval, schema prototype-pollution/remote-reference bounds, OAuth polling/abort/redaction, credential tamper/wrong-key/KDF floors, MCP result bounds/timeouts, and coding approval/path policy. `security:threat-suites` also gates CodeQL-remediation regressions (plan 038): linear `trimTrailingSlashes`/parsers with no environment regex evaluation, single-pass HTML sanitization, crypto (not `Math.random`) fixture identifiers, and no clear-text error logging on password-handling paths.
|
|
176
177
|
|
|
177
178
|
PostgreSQL TLS/network policy, MCP endpoint trust/credentials and egress policy beyond package origin/DNS pinning, provider base URLs, OS keychain availability, process sandboxing, workflow tenant identity, and ANSI/control-sequence sanitization in any host terminal renderer remain host boundaries. Prism 0.0.4 ships JSON-line RPC, not an interactive TUI; hosts must render untrusted model/tool text safely. Credential-gated PostgreSQL/provider/keychain tests are separate operator/CI gates, not silently replaced by mocks.
|
|
178
179
|
|
|
@@ -213,6 +214,7 @@ PostgreSQL TLS/network policy, MCP endpoint trust/credentials and egress policy
|
|
|
213
214
|
- **Named threat-suites leg.** `npm run security:threat-suites` aggregates the Phase 8–11 conformance suites (durable-loop/HITL approval, coding sandbox/egress/forge, ACP protocol, OIDC/OPA/MCP-OAuth/OpenAPI/artifact) into one named 0.1.0 security evidence leg — same scripts as `npm test`, no rewrite; the Phase 7 tenant-isolation suite is its protected counterpart under `npm run test:postgres` (missing `PRISM_TEST_POSTGRES_URL` is a named blocked gate).
|
|
214
215
|
- **Supply-chain negative fixtures.** `scripts/release-gate.test.mjs` verifies the tarball deny list rejects tampered content (plans/reviews/maps/tests), unexpected file types and credential material (native binaries, `.pem`/`.key`/`.p12`), and that a provenance flag suppressed in CI is detectable in the `release.mjs` publish dry-run arguments (`--provenance` mandatory under `GITHUB_ACTIONS`, never claimed on local OIDC-less publishes).
|
|
215
216
|
- **Mandatory gate stack.** CodeQL/SAST, PR dependency review (fail on high), secret scan (source + unpacked tarballs), SPDX SBOM + license policy, tarball allow/deny content checks, and provenance (npm OIDC + GitHub build attestations on tarballs and SBOM) all run in `security.yml`/`release.yml`; evidence for the 0.1.0 tree is recorded in [0.1.0 readiness](0.1.0-readiness.md).
|
|
217
|
+
- **CodeQL query suite.** `.github/codeql/codeql-config.yml` selects the `security-extended` suite for `javascript-typescript` (with the default suite) on push/PR/schedule in `security.yml` (10-minute job bound; measured runtime ~3m22s on the audited SHA, last successful main run `33059128198`). The ignore list covers only generated `dist`, `node_modules`, and release/security artifact directories — first-party packages, threat suites, and fixtures that ship or execute are always scanned, so new alerts enter the same plan-038 ledger/remediation loop (config + guardrails asserted in `scripts/phase38-codeql-regression.test.mjs`). Local Task 6 gates (typecheck/lint/format/threat suites/audit/secret scan/SBOM) pass on the remediations; GitHub `state=open` stays non-zero until those remediations are the analyzed head. Groups G (`js/insufficient-password-hash` on RFC 7636 S256) and H (`js/incomplete-url-substring-sanitization` on a negative docs assertion) are maintainer-reviewed false positives queued for narrow dismissal after that analyze, not code changes.
|
|
216
218
|
- **Live canaries are blocked gates, not skips.** The `live-canaries` and `sandbox-browser` workflows always set their gate env (`PRISM_LIVE_CANARIES=1`), so absent credentials fail the job loudly with a named owner (the workflow + dispatching operator) and retained `canary-report.json` evidence; the local silent-skip path exists only when the gate env is not set.
|
|
217
219
|
|
|
218
220
|
## Distributed events and tool effects
|
package/docs/index.md
CHANGED
|
@@ -24,7 +24,7 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
|
|
|
24
24
|
- [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.
|
|
25
25
|
- [Guardrails](guardrails.md): typed fail-closed input/output/tool checks with buffered provider output and redacted decision records.
|
|
26
26
|
- [Agent events](agent-events.md): live `session.subscribe` plus durable `AgentEventSource` page/subscribe/resume for cross-replica reconnect; message/progress deltas never create spans. Durable sources: PostgreSQL `LISTEN`/`NOTIFY` (reference, `@arnilo/prism-session-store-postgres` root export) and NATS JetStream (`@arnilo/prism-session-store-nats`, FR-5) with restart-stable durable consumer identity (`prism_<hmac16>`) for cursor resume across crash/restart.
|
|
27
|
-
- [Observability](observability.md): OTel GenAI agent/provider/tool hierarchy, host context parenting, bounded trace linkage, safe evaluation events, controlled metrics, and exporter isolation.
|
|
27
|
+
- [Observability](observability.md): OTel GenAI agent/provider/tool hierarchy, RAG span tree (`createRagTelemetry()`), host context parenting, bounded trace linkage, safe evaluation events, controlled metrics, and exporter isolation.
|
|
28
28
|
- [Operations runbook](operations.md): the high-availability/failover runbook for plan 027 Task 6 — LeaseStore/CheckpointStore fencing model, local-registry limitations, uncertain-commit replay rules, the recorded two-replica drill (`scripts/phase27-ha.test.mjs`, evidence in `docs/_evidence/phase27-ha-evidence.json`), failover ceiling, and the prohibition on manual lease unlocks.
|
|
29
29
|
- [Disaster recovery and backup operations](disaster-recovery.md): the plan 027 Task 7 runbook — standard-tool backup/restore/migration-rollback/PITR/DR drill (`scripts/phase27-dr.test.mjs`), guarded commands, app-level verification, the rollback decision tree, and measured RPO/RTO in `docs/_evidence/phase27-dr-evidence.json`.
|
|
30
30
|
- [Data classification and field-level redaction](data-classification.md): the plan 027 Task 8 contract — `applyFieldPolicy` walking JSON-like values with allow/redact/tokenize/deny decisions, the fail-closed protected default, per-boundary `labelFor` hints (no auto-discovery), sparse-copy overhead, and the ERP-T9 leak matrix incl. egress/audit/telemetry seams.
|
|
@@ -37,14 +37,14 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
|
|
|
37
37
|
- [Compaction and retry policies](compaction-and-retry.md): summarize branch history and retry transient provider failures with host-replaceable policies.
|
|
38
38
|
- [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.
|
|
39
39
|
- [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-only settings** (pre-0.0.19 flat keys and top-level `workerProvider`/`workerModel` aliases removed in 0.1.5; removed keys fail closed naming the nested replacement), branch-isolated `appendEntry`, secrets redaction, and inert import/extension.
|
|
40
|
-
- [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.
|
|
40
|
+
- [Working and semantic memory](working-and-semantic-memory.md): optional `@arnilo/prism-memory` working-memory store, semantic recall, finite Embedder/VectorStore contracts (incl. embedder identity + generation pointers), PostgreSQL/pgvector path (`createPostgresVectorStore` standalone, HNSW/fts DDL on the host knowledge database), consent lifecycle, identity-bound redacted export, and resumable bounded rebuild.
|
|
41
41
|
- [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.
|
|
42
42
|
- [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, atomic metadata via version/CAS (`metadata_conflict` on stale writes), and legal-hold-aware deletion.
|
|
43
43
|
- [Work artifacts and review](work-artifacts-and-review.md): durable artifact co-work review — authorized attach (MIME/hash/version, producer run, citations, preview metadata), revision compare, approve/reject with last-validated recovery, and authorized expiring delivery links; records persist as versioned checkpoints, never file bodies. 0.0.28 adds the core `ArtifactBodyStore` contract (put/get/delete/presign by opaque ownership-scoped ref, hash/size/MIME verification, legal-hold-aware idempotent delete) and the reference `@arnilo/prism-server/artifact-bodies` S3-compatible adapter (hand-rolled SigV4, native fetch + WebCrypto, optional host KMS callback); delivery links resolve through `bodies.presign` when wired.
|
|
44
44
|
- [Session stores and branching](session-stores-and-branching.md): detailed branch semantics and helper reference (kept for compatibility; links back to the canonical atomic append / branch-handle sections).
|
|
45
45
|
- [Database persistence](database-persistence.md): production persistence contracts, shared checksummed migration/full-shape catalog primitives (`@arnilo/prism/testing/persistence-schema`), conditional append, indexes, `readBranchPath`, reference relational schema, retention/legal-hold/quota lifecycle (`lifecycle`), and NoSQL mapping. `appendSession` gains version/CAS (migration `008_session_version`); durable adapters must pass `assertStateConcurrencyConforms` (`@arnilo/prism/testing/state-concurrency-conformance`: approval/checkpoint-CAS/cursor/idempotency/reservation/conversation-metadata/unknown-outcome probes; memory leg in `npm test`, durable legs in `test:postgres`/`test:nats`, `scripts/phase22-conformance.test.mjs` gate accounting).
|
|
46
46
|
- [SQLite persistence](sqlite-persistence.md): optional `better-sqlite3` adapter with session/run storage, checkpoints/leases, feedback, FTS `searchSessions` (migration-v4), and transactionally verified/backfilled migration metadata.
|
|
47
|
-
- [PostgreSQL persistence](postgres-persistence.md): optional pooled `pg` adapter with session/run/checkpoint/lease/feedback storage, FTS `searchSessions` (migration-v4), advisory-locked checksummed/full-shape migrations, and opt-in live conformance.
|
|
47
|
+
- [PostgreSQL persistence](postgres-persistence.md): optional pooled `pg` adapter with session/run/checkpoint/lease/feedback storage, FTS `searchSessions` (migration-v4), advisory-locked checksummed/full-shape migrations, and opt-in live conformance. Semantic vectors live in `@arnilo/prism-memory`'s pgvector path (`createPostgresVectorStore`, documented on the working-and-semantic-memory page); RAG durable storage uses that store, never this session-store adapter.
|
|
48
48
|
- [Enterprise PostgreSQL state](enterprise-postgres-state.md): optional `@arnilo/prism-enterprise-postgres` composition for durable policy/evaluation/work-idempotency/model-router/`toolEffects` state, transactional ERP outbox/inbox messaging, and multi-party approval records (`createPostgresApprovalStore`, migration 005 — one locked row per request, revision-checked terminal transitions, caller-transaction grant consumption), exact tenant ownership, checksummed migrations (001-005; 003 adds router budget reservation slots; 004 adds bounded at-least-once dispatch), and explicit cleanup.
|
|
49
49
|
- [Migration guide](migration.md): **0.1.4 → 0.1.5** documented breaking cut — deprecated-option removal (the inert provider request knobs, `maxToolRounds` alias, observational-memory flat keys/worker aliases, `autoResizeImages`, `INIT_PROVIDERS`) with exact replacement table, before/after examples, and fail-closed refusal behavior; **0.0.28 → 0.1.0** release-candidate hardening (no migration); **0.0.17 → 0.1.0 upgrade matrix** (store compatibility per release line: compatible / tested migration / tested refusal, plus breaking-default callouts); **0.0.27** ACP coding-host interop (capability advertise-when, session modes/config, MCP select, lifecycle events, elicitation); **0.0.26** coding intelligence, managed processes, forge, and safe egress; **0.0.25** durable custom loops and shared human-in-the-loop decisions; **0.0.24** distributed events and recoverable tool effects; **0.0.23** enterprise PostgreSQL state adapters (async router and work reconciliation); **0.0.22** third-party behavior integrations (Caveman, Ponytail); **0.0.21** coding-tool capability gaps (`outputMode`, glob, read-before-write, delete/move, aggregator 9/4); **0.0.20** progressive skill disclosure, empty registry default, `load_skill`, priority budget demotion, optional tool-result fold; **0.0.19** observational memory lifecycle; **0.0.15** OpenAI hosted tools/continuation/Realtime, exact AI SDK v4 matrix, RAG lifecycle/reranking/trust/status, and memory export/rebuild; **0.0.14** conversations, memory consent/lifecycle, artifact co-work review, AG-UI co-work events, scoped M365/GWS OAuth connectors, browser checkpoints, device contracts, and Alibaba/Ollama providers; plus prior release migrations.
|
|
50
50
|
- [Node JSONL session store](node-jsonl-session-store.md): development-only JSONL file adapter for single-process Node hosts; no cross-process safety; `searchSessions` throws `SessionSearchUnsupportedError`.
|
|
@@ -71,7 +71,8 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
|
|
|
71
71
|
- [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`.
|
|
72
72
|
- [Instruction injection](instruction-injection.md): register package injectors that layer redacted instructions/context blocks without granting tools, permissions, or resource escapes.
|
|
73
73
|
- [Context and skills](context-and-skills.md): resolve ordered context providers; progressive skill catalog (`skillsDisclosure`, default catalog-only), `load_skill` on-demand bodies, fail-closed registry activation (`activateAllSkills` migration opt-in), `toolNames` fail closed before provider turns, priority-aware budget demotion, and optional `toolResultFold`.
|
|
74
|
-
- [
|
|
74
|
+
- [LLM Wiki](wiki.md): optional `@arnilo/prism-wiki` automated Karpathy-style knowledge compiler, incremental Merkle change tracking, on-device `qmd` hybrid search, and Context7-style clickable line navigation for codebases and PKM.
|
|
75
|
+
- [Retrieval-augmented generation](rag.md): optional bounded source lifecycle, document adapters, ATX heading-stack chunk metadata, hybrid vector+lexical retrieval with RRF fusion, multi-scope retrieve (one embed / one RRF / one rerank), embedder-identity drift guards, content-hash skip, generation visibility, host reranking, ingestion status (plus an in-cluster TEI adapter), attributable citations, telemetry seam, and inert context injection.
|
|
75
76
|
|
|
76
77
|
## Tools
|
|
77
78
|
- [Recoverable tool effects](tool-effects.md): optional effect declarations, `ToolEffectStore` claim/CAS, unknown reconciliation (not exactly-once), and adapter classifications.
|
|
@@ -80,12 +81,13 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
|
|
|
80
81
|
- [Tool execution primitives](tool-execution-primitives.md): finite JSON Schema LRU validation, exclusive-aware bounded parallel dispatch, MCP bridge mapping, coding execution policy, and image-read bounds.
|
|
81
82
|
- [Tool validator JSON Schema package](../packages/tool-validator-json-schema/README.md): optional `@arnilo/prism-tool-validator-json-schema` adapter for `tool.parameters`.
|
|
82
83
|
- [MCP client bridge and server exposure](mcp-tools.md): SDK-1.30.0 bounded tools/resources/prompts, host-owned roots/sampling/elicitation, exact-origin DNS-pinned client transport, and principal-bound opt-in Streamable HTTP sessions. 0.0.28 adds MCP OAuth: `createMcpOAuthTransport`/`createMcpOAuthFetch`/`createMcpClientAuth` (RFC 9728/8414 discovery, PKCE, RFC 8707 audience binding, RFC 7009 revocation, host-owned bounded state) and server `protectedResource` metadata + `WWW-Authenticate` challenges; 0.2.1 re-routes the client transport through the shared core DNS-pinned fetch primitive.
|
|
83
|
-
- [Web search, fetch, and extraction](web-tools.md): optional host-selected Brave/Exa discovery and Firecrawl Markdown/schema tools with native fetch, stable citations, late credentials, finite limits, and explicit untrusted-content boundaries.
|
|
84
|
+
- [Web search, fetch, and extraction](web-tools.md): optional host-selected Brave/Exa discovery and Firecrawl Markdown/schema tools with native fetch, stable citations, late credentials, finite limits, and explicit untrusted-content boundaries; the optional Obscura package (`@arnilo/prism-obscura`) adds a CLI-backed browser search/fetch adapter (`provider: "obscura"`) plus native `obscura_fetch`/`obscura_scrape` without API credentials.
|
|
84
85
|
- [Work tools](work-tools.md): optional `@arnilo/prism-work-tools` identity-scoped M365 + GWS connectors (hard-coded CLI argv, draft-then-approve, state-machine idempotency, shared result shapes); 0.0.14 adds a late-bound per-identity `tokenProvider` (env-only, fail-closed); 0.2.0 plan 020 Task 3 provides an isolated subprocess environment (fixed allow-listed base + explicit env + late-bound token env, forced `HOME`/telemetry controls, 64-name/64-KiB caps) and requires host-pinned **absolute** binary/configDir paths.
|
|
85
86
|
- [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.
|
|
86
87
|
- [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.
|
|
87
88
|
- [Device adapters](device-adapters.md): deny-by-default realtime voice / desktop-control contract + conformance (0.0.14); the first vendor package is the optional Linux-only `@arnilo/prism-computer-use-linux` wrapper, while admission still fails closed without explicit consent+sandbox+approval, stream bounds, shared `RunLimits`, and redacted telemetry.
|
|
88
89
|
- [Linux desktop control](computer-use-linux.md): optional `@arnilo/prism-computer-use-linux` over a host-owned `computer-use-linux` MCP binary — doctor-first skill, target-window guidance, setup tools off by default, DeviceAdapter admission, high-risk mutator approval, serialized input, bounded untrusted screenshots/app state, and host redaction.
|
|
90
|
+
- [Obscura browser engine](obscura.md): optional `@arnilo/prism-obscura` over a host-installed Obscura headless browser — fail-closed `spawnObscuraProcess` lifecycle (absolute shell-free command, Docker argv, bounded readiness, group close), `createObscuraMcpTools` bridging the complete advertised MCP surface (reads effect-free, mutations and unknown future tools exclusive/serialized, `obscura_` prefix, loopback-default HTTP), and `connectObscuraCdp` managed/external CDP + Playwright `connectOverCDP` composition feeding `@arnilo/prism-browser` tools directly; `browser_search` is in-page text search, not web search; omitted from umbrellas (binary not supplied by install).
|
|
89
91
|
- [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). 0.2.6 adds the optional [Indexed code search](indexed-code-search.md) seam: host-owned incremental index (`update/remove/search/status/dispose`) with explicit `indexed_literal`/`semantic` modes behind `createIndexedRepositoryOperations`, literal remains the default, stale/failed/unsupported indexes fail closed with `ERR_PRISM_INDEX_*` and results are labeled `untrusted_index`. 0.2.6 also adds [Coding workspaces](coding-workspaces.md) (plan 026 Task 3): `createCodingWorkspaceLifecycle` registers host repositories and creates/lists/locks/removes linked worktrees with CheckpointStore CAS records, LeaseStore fencing, credential-free remote fingerprints, and a cleanup policy that refuses dirty/locked/unowned/mismatched trees unless the host allows it. 0.2.6 adds [Coding review and diagnostics](coding-review-and-diagnostics.md) (plan 026 Task 6): bounded patch-review manifests (`createCodingPatchReviewManifest` + `assertCodingPatchAccepted`, pending/accepted/rejected/superseded bound to patch digest + artifact revision + repository/worktree/base/head identity, composed over the server ArtifactService, never applying/committing automatically), normalized LSP/check diagnostics with deterministic added/removed/unchanged deltas, and opt-in LSP document synchronization (`syncDocument`, pull diagnostics with resultId reuse, stale-version guards). Limits do not sandbox host access—gate with permission/trust policy and `@arnilo/prism-coding-security`.
|
|
90
92
|
- [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.
|
|
91
93
|
- [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; host-selected PTY (`pty: true` delegates only to the host `ptyBackend`, fails closed as unsupported when absent, bounded resize/TERM/attach caps). Durable process recovery (plan 026 Task 5): with `checkpoints`+`leases`+`ownerId`, intent is persisted before spawn and transitions are CAS/fence-written; `recover()` is attach-if-attested via a host `recoveryBackend`, otherwise starting/running records atomically become `unknown` (no fabricated exit, no PID probing), fenced so two replicas cannot both own a process.
|
|
@@ -136,16 +138,16 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
|
|
|
136
138
|
- [Compaction conformance](compaction-conformance.md): assert any `CompactionStrategy` returns a non-empty redacted summary and observes abort from `@arnilo/prism/testing/compaction-conformance`.
|
|
137
139
|
- [Tool conformance](tool-conformance.md): assert the tool-dispatch blocked-reason matrix (unknown/denied/invalid/permission/validator) and success path from `@arnilo/prism/testing/tool-conformance`.
|
|
138
140
|
- [Extension conformance](extension-conformance.md): assert an `Extension` setup runs, contributions stay inert, and setup errors are redacted or rethrown from `@arnilo/prism/testing/extension-conformance`.
|
|
139
|
-
- `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/ag-ui-a2ui.ts`](../examples/ag-ui-a2ui.ts), [`examples/ag-ui-mcp-apps.ts`](../examples/ag-ui-mcp-apps.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/enterprise-postgres-state.ts`](../examples/enterprise-postgres-state.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/provider-deepseek.ts`](../examples/provider-deepseek.ts), [`examples/provider-xai.ts`](../examples/provider-xai.ts), [`examples/provider-xai-oauth.ts`](../examples/provider-xai-oauth.ts), [`examples/provider-clinepass.ts`](../examples/provider-clinepass.ts), [`examples/impeccable.ts`](../examples/impeccable.ts), [`examples/coding-compaction.ts`](../examples/coding-compaction.ts), [`examples/acp-coding-host.ts`](../examples/acp-coding-host.ts), [`examples/caveman-ponytail.ts`](../examples/caveman-ponytail.ts), stores/branching, structured-output/artifact-loop, CLI, RPC, workflow orchestration).
|
|
141
|
+
- `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/ag-ui-a2ui.ts`](../examples/ag-ui-a2ui.ts), [`examples/ag-ui-mcp-apps.ts`](../examples/ag-ui-mcp-apps.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/enterprise-postgres-state.ts`](../examples/enterprise-postgres-state.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/provider-deepseek.ts`](../examples/provider-deepseek.ts), [`examples/provider-xai.ts`](../examples/provider-xai.ts), [`examples/provider-xai-oauth.ts`](../examples/provider-xai-oauth.ts), [`examples/provider-clinepass.ts`](../examples/provider-clinepass.ts), [`examples/impeccable.ts`](../examples/impeccable.ts), [`examples/coding-compaction.ts`](../examples/coding-compaction.ts), [`examples/acp-coding-host.ts`](../examples/acp-coding-host.ts), [`examples/caveman-ponytail.ts`](../examples/caveman-ponytail.ts), [`examples/graft-extension.ts`](../examples/graft-extension.ts), stores/branching, structured-output/artifact-loop, CLI, RPC, workflow orchestration).
|
|
140
142
|
|
|
141
143
|
## Third-party integrations
|
|
142
144
|
- [Caveman behavior integration](caveman.md): optional `@arnilo/prism-caveman` — upstream Caveman skills/commands, `caveman-mode` injector, session `caveman-level` persistence, progressive catalog + `load_skill`; requires host `upstreamPath` and session attach callbacks; inert until `kernel.load`.
|
|
143
145
|
- [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).
|
|
146
|
+
- [Graft context-graph integration](graft.md): optional `@arnilo/prism-graft` — six graft CLI pull tools (`graft_ask`/`grep`/`callers`/`skeleton`/`map`/`blast`), push-mode retrieval-pack context provider + first-turn orientation, edit blast-radius middleware with `graft:dirty`, session `graft-state` persistence; resolves peer `@nanonets/graft@^0.13.0` or `packageRoot`/`cliPath`; opt-in (not in code/sdk profiles or the `prism-all` umbrella).
|
|
144
147
|
- [Impeccable behavior integration](impeccable.md): optional `@arnilo/prism-impeccable` — host `upstreamPath` to compiled Impeccable `SKILL.md`, skill + `/impeccable` → `load_skill`; no detector CLI, no live browser, not in code/sdk/all.
|
|
145
148
|
|
|
146
149
|
## Release and install
|
|
147
|
-
- [0.2.7 Task 0 scope evidence](release-0.2.7-evidence.md): frozen ERP primitives, demand decisions, threat mappings, budgets, protected-gate policy, and API ownership; not a production-readiness claim.
|
|
148
|
-
- [Release and install](release-and-install.md): current **0.3.0** 57-package graph (root + 56 workspace packages) — plan 030 last-lockstep cut and independent `^0.3.0` publication; plan 029 **0.2.9** provider adoption (DeepSeek, xAI SuperGrok OAuth, ClinePass), `@arnilo/prism-impeccable`, Ponytail 4.9.0, Caveman v2.1 extras; then plan 028 **0.2.8** ACP adoption fixes; then plan 026 the fully-featured coding-agent-readiness cut: **host-selected PTY** (`pty: true` delegates only to the host `ptyBackend`, fails closed as unsupported when absent, bounded resize/TERM/attach caps), **indexed code search** (host-owned incremental index seam with explicit `indexed_literal`/`semantic` modes, literal remains the default, stale/failed/untrusted indexes fail closed `ERR_PRISM_INDEX_*`, results labeled `untrusted_index`), **coding workspaces** (`createCodingWorkspaceLifecycle`: durable CheckpointStore CAS records + LeaseStore fencing, locked worktrees, credential-free fingerprints, cleanup refusal matrix), **durable recovery** (process intent/ACP `activeRun` refs over Postgres/SQLite stores with attach-if-attested `recover()` and durable fence-checked cancellation, never fabricated exits), **patch review and diagnostics** (`createCodingPatchReviewManifest` + `assertCodingPatchAccepted` with pending/accepted/rejected/superseded bound to digest + revision + identity, opt-in LSP `syncDocument`/`diagnosticDelta`), and the **protected real coding journey** (packed consumer through real provider/Docker/Postgres/GitHub/Playwright/PTY services with retained evidence report; forge breadth GitLab/Bitbucket stays demand-gated); then plan 025 the maintainability-and-bounded-performance cut: **god-module splits** (the six remaining implementation monoliths — `src/contracts-core.ts` 1,719 L, `src/agent-session.ts` 2,049 L, `workflows/src/run.ts` 1,227 L, `server/src/handler.ts` 1,005 L, `coding-agent/src/repository.ts` 974 L, `ag-ui/src/acp/agent.ts` 836 L — split into cohesive family files behind preserved barrels, compat-preserving with zero breaking deltas, no `exports`-map subpath, `RuntimeAgentSession` kept as one class with a recorded reason), **persistence-mechanics dedup** (21 pure ownership/cursor/checkpoint/lifecycle/search helpers moved into the dependency-free `session-store-codecs`; postgres/sqlite adapters shrank 273 lines; SQL dialect stays per-adapter; no schema/shape change; cross-store conformance green), **bounded accumulation removed** (per-push `Buffer.concat` in language framing + tar parsing → chunk-array readers; framing ~100–200× faster at 4,000 chunks, tar linear at 8 MiB, caps fail-closed byte-identical; CLI `collectOutput` audited already linear), **dead-code cleanup internal-only** (62 candidates triaged: 2 internal removals + 60 allow-listed in `docs/_evidence/phase25-dead-exports-triage.md`), and **coverage close** (76 behavior-backed regressions; core 90.53/84.20/90.54 → 91.43/84.80/91.60); additive-only compat (105 helper exports), no migration; then plan 024 the package-documentation-and-compatibility-truth cut: **umbrella wording matches manifests** (`@arnilo/prism-providers` installs 11 of 14 provider adapters — Azure/Bedrock/Vertex are added separately by `prism-all`; `prism-all` installs 20 direct / 43 transitive packages and omits document-reader, OpenAPI tools, NATS, Caveman, Ponytail; membership unchanged in 0.2.x), **manifest-derived package truth** (`scripts/package-truth.mjs` → `scripts/package-truth.json` is the single source for counts, provider membership, and closures; docs literals regenerate from it and drift fails the gates), **peer-version policy Decision A** (exact `@arnilo/prism: 0.2.4` pins, atomic-upgrade rule, ERESOLVE refusal for partial upgrades, `^1.0.0` widening at 1.x), and **current-line truth** (`docs/0.1.0-readiness.md` at the 0.2.x line with 0.1.7 as the terminal 0.1.x baseline); no runtime contract delta (compat gate at 0.2.4: version literal only), no migration; then plan 023 the build-coverage-and-release-evidence-integrity cut: **build serialization** (dependency-free `scripts/with-build-lock.mjs` — one O_EXCL lockfile at `node_modules/.prism-build.lock` serializing every emit/test leaf so concurrent compilers can never expose a partial live `dist/`, stale-PID reclaim, env-overridable `PRISM_BUILD_LOCK_TIMEOUT_MS`, fail-closed; documented direct-`tsc` caveat), **corrected workspace coverage denominators** (package-local `--test-coverage-include=dist/**` so imported core `dist` no longer pollutes workspace rows — `mcp` 45.47→90.25, `rag` 19.70→94.82; evidence-based per-package thresholds in `scripts/coverage-thresholds.json` with `protectedException` for durable-leg packages shown separately, machine-readable `scripts/coverage-summary.json`), **machine-auditable release skip manifest** (`scripts/release-skip-manifest.mjs` → `scripts/release-evidence.json`: every surface recorded `pass`/`skip`/`blocked`/`protected` with reason and required env; the 33 protected/live skips named; a required surface without evidence records `blocked` and fails the release gate fail-closed — missing credentials/services can never convert into a green release), and **stabilized quality gates** (Biome 2.x `preset` config migration with zero lint diagnostics, the racy 150ms MCP bridge timing assert replaced by a deterministic barrier, load-sensitive guards carry documented `ponytail:` ceilings, machine-readable `lint-report.sarif` + `unused-report.json` retained by CI); no runtime contract delta (compat gate at 0.2.3: version literal only), no migration; then plan 022 the concurrent-state-and-durability-integrity cut: atomic model-budget reservation (`ModelRouterStateStore.reserveBudget`/`commitBudget`/`releaseBudget` with fencing tokens, `reservationTtlMs` expiry and unknown-usage reconciliation, rate/budget key-map caps with LRU eviction that never drops a held reservation), atomic conversation metadata (`SessionRecord.version` + `appendSession` `expectedVersion` CAS across Postgres/SQLite — create-only `0`, exact-version `N>0`, legacy last-write-wins when omitted; `SessionMetadataConflictError` `metadata_conflict` with versions only, HTTP 409; concurrent create/branch/archive single-statement with branch caps inside the CAS, archive wins, deleted rows never resurrect), single-consumer `EventMultiplexer` (`EventMultiplexerError` `ERR_PRISM_EVENT_MULTIPLEXER_SINGLE_CONSUMER` instead of silent queue sharing), restart-stable NATS durable consumer identity (`prism_<hmac16>` with no random suffix — crash-resumed subscribe continues from the last ack, orphaned 0.2.1 consumers reclaimed on clean stop), and bounded non-durable active-run registries (sweep + fail-closed 512 cap `ERR_PRISM_WORKFLOW_RUN_REGISTRY_OVERFLOW`); new regression surface `scripts/phase22-security.test.mjs` (4 blockers + gate accounting over built public entrypoints) + packed plain-JS `security22.mjs` consumer + the `@arnilo/prism/testing/state-concurrency-conformance` harness (7 probes across memory/Postgres/SQLite/NATS legs, no timing-only sleeps) + the `scripts/phase22-conformance.test.mjs` gate; additive-only compat (new exports only, no removals); forward-only migrations 008 (`prism_sessions.version`) and 003 (`prism_model_router_budgets.reservations`); migration `0.2.1 → 0.2.2`; then plan 021 the provider-completion-and-outbound-trust-boundaries cut: strict stream completion is the shared OpenAI-compatible default (truncated streams fail `incomplete_delta`, explicit `strictCompletion: false` opt-out), bounded success bodies via `readBoundedResponseJson` on all discovery/quota/embeddings/upload/OAuth JSON endpoints (65,536-byte ceiling, depth/property/shape caps), DNS-pinned OIDC JWKS/OPA/content fetches through the core `pinnedFetch` primitive with 3xx redirects rejected outright (private/metadata answers fail closed `ssrf_denied`), shared bounded OAuth device/token polling (`pollDeviceCodeToken`) across provider-openai and credentials-node, and the four edge fixes (Azure/Vertex credential-once, Bedrock duplicate-case/repeated-query SigV4 canonicalization, OpenAI upload failed-DELETE retention, cache `__overflow__` tokens-only); public-entrypoint threat-suite `scripts/phase21-security.test.mjs` + packed plain-JS consumer; additive-only compat (MCP transport helpers re-exported from core, no removals); migration `0.2.0 → 0.2.1`; then plan 020 the fail-closed runtime-and-sandbox-security cut on the 0.2.x review-remediation line: durable-resume decision validation in core (`assertValidAgentRunResume` — unknown decisions/malformed batches fail closed with `ERR_PRISM_DECISION_*` before any state claim, checkpoint write, or tool execution; server parser remains defense in depth), isolated work-tool subprocess environments (`@arnilo/prism-work-tools` — fixed base allow-list + explicit env + forced HOME/telemetry + late-bound per-identity tokens, 64-name/64-KiB caps, absolute binary/configDir, linear output capture), and explicit sandbox capabilities (`@arnilo/prism-coding-security` — `SandboxAdapter.capabilities` with omission-is-false fail-closed resolution, `SandboxCodingComposition.capabilities` from verified wiring, `containmentClaim` deprecated as the conservative projection; Docker reports only verified controls, native reports filesystem/process/privilege `false`); public-entrypoint security conformance (`scripts/phase20-security.test.mjs`, wired into `security:threat-suites`), packed plain-JS consumer regressions, and the sandbox-browser workflow's fail-loud Docker/native capability evidence gate — 0.2.0 never ships while a blocker is skipped; migration and rollback notes in `docs/migration.md` `0.1.7 → 0.2.0`, store-compatible with 0.1.7 in both directions; 0.1.7 was 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. 0.2.6 (plan 026 Task 7) adds the protected coding journey: `scripts/phase26-coding-journey.test.mjs` runs a packed consumer through real provider calls, a digest-pinned Docker sandbox, the durable Postgres worktree lifecycle, provider-driven ACP edits with policy approval, named checks with `diagnosticDelta`, patch review over the server ArtifactService, cross-replica process recovery, durable cancellation, real GitHub PR push/reconcile/cleanup, host Playwright inspection, and the host PTY adapter (frozen profile) — the retained `scripts/phase26-coding-journey-report.json` gates release evidence (pass/blocked/protected, never a passing skip).
|
|
150
|
+
- [Release and install](release-and-install.md): current **0.3.1** 60-package graph (root + 59 workspace packages) — plan 030 last-lockstep cut and independent `^0.3.0` publication; plan 029 **0.2.9** provider adoption (DeepSeek, xAI SuperGrok OAuth, ClinePass), `@arnilo/prism-impeccable`, Ponytail 4.9.0, Caveman v2.1 extras; then plan 028 **0.2.8** ACP adoption fixes; then plan 026 the fully-featured coding-agent-readiness cut: **host-selected PTY** (`pty: true` delegates only to the host `ptyBackend`, fails closed as unsupported when absent, bounded resize/TERM/attach caps), **indexed code search** (host-owned incremental index seam with explicit `indexed_literal`/`semantic` modes, literal remains the default, stale/failed/untrusted indexes fail closed `ERR_PRISM_INDEX_*`, results labeled `untrusted_index`), **coding workspaces** (`createCodingWorkspaceLifecycle`: durable CheckpointStore CAS records + LeaseStore fencing, locked worktrees, credential-free fingerprints, cleanup refusal matrix), **durable recovery** (process intent/ACP `activeRun` refs over Postgres/SQLite stores with attach-if-attested `recover()` and durable fence-checked cancellation, never fabricated exits), **patch review and diagnostics** (`createCodingPatchReviewManifest` + `assertCodingPatchAccepted` with pending/accepted/rejected/superseded bound to digest + revision + identity, opt-in LSP `syncDocument`/`diagnosticDelta`), and the **protected real coding journey** (packed consumer through real provider/Docker/Postgres/GitHub/Playwright/PTY services with retained evidence report; forge breadth GitLab/Bitbucket stays demand-gated); then plan 025 the maintainability-and-bounded-performance cut: **god-module splits** (the six remaining implementation monoliths — `src/contracts-core.ts` 1,719 L, `src/agent-session.ts` 2,049 L, `workflows/src/run.ts` 1,227 L, `server/src/handler.ts` 1,005 L, `coding-agent/src/repository.ts` 974 L, `ag-ui/src/acp/agent.ts` 836 L — split into cohesive family files behind preserved barrels, compat-preserving with zero breaking deltas, no `exports`-map subpath, `RuntimeAgentSession` kept as one class with a recorded reason), **persistence-mechanics dedup** (21 pure ownership/cursor/checkpoint/lifecycle/search helpers moved into the dependency-free `session-store-codecs`; postgres/sqlite adapters shrank 273 lines; SQL dialect stays per-adapter; no schema/shape change; cross-store conformance green), **bounded accumulation removed** (per-push `Buffer.concat` in language framing + tar parsing → chunk-array readers; framing ~100–200× faster at 4,000 chunks, tar linear at 8 MiB, caps fail-closed byte-identical; CLI `collectOutput` audited already linear), **dead-code cleanup internal-only** (62 candidates triaged: 2 internal removals + 60 allow-listed in `docs/_evidence/phase25-dead-exports-triage.md`), and **coverage close** (76 behavior-backed regressions; core 90.53/84.20/90.54 → 91.43/84.80/91.60); additive-only compat (105 helper exports), no migration; then plan 024 the package-documentation-and-compatibility-truth cut: **umbrella wording matches manifests** (`@arnilo/prism-providers` installs 11 of 14 provider adapters — Azure/Bedrock/Vertex are added separately by `prism-all`; `prism-all` installs 20 direct / 43 transitive packages and omits document-reader, OpenAPI tools, NATS, Caveman, Ponytail; membership unchanged in 0.2.x), **manifest-derived package truth** (`scripts/package-truth.mjs` → `scripts/package-truth.json` is the single source for counts, provider membership, and closures; docs literals regenerate from it and drift fails the gates), **peer-version policy Decision A** (exact `@arnilo/prism: 0.2.4` pins, atomic-upgrade rule, ERESOLVE refusal for partial upgrades, `^1.0.0` widening at 1.x), and **current-line truth** (`docs/0.1.0-readiness.md` at the 0.2.x line with 0.1.7 as the terminal 0.1.x baseline); no runtime contract delta (compat gate at 0.2.4: version literal only), no migration; then plan 023 the build-coverage-and-release-evidence-integrity cut: **build serialization** (dependency-free `scripts/with-build-lock.mjs` — one O_EXCL lockfile at `node_modules/.prism-build.lock` serializing every emit/test leaf so concurrent compilers can never expose a partial live `dist/`, stale-PID reclaim, env-overridable `PRISM_BUILD_LOCK_TIMEOUT_MS`, fail-closed; documented direct-`tsc` caveat), **corrected workspace coverage denominators** (package-local `--test-coverage-include=dist/**` so imported core `dist` no longer pollutes workspace rows — `mcp` 45.47→90.25, `rag` 19.70→94.82; evidence-based per-package thresholds in `scripts/coverage-thresholds.json` with `protectedException` for durable-leg packages shown separately, machine-readable `scripts/coverage-summary.json`), **machine-auditable release skip manifest** (`scripts/release-skip-manifest.mjs` → `scripts/release-evidence.json`: every surface recorded `pass`/`skip`/`blocked`/`protected` with reason and required env; the 33 protected/live skips named; a required surface without evidence records `blocked` and fails the release gate fail-closed — missing credentials/services can never convert into a green release), and **stabilized quality gates** (Biome 2.x `preset` config migration with zero lint diagnostics, the racy 150ms MCP bridge timing assert replaced by a deterministic barrier, load-sensitive guards carry documented `ponytail:` ceilings, machine-readable `lint-report.sarif` + `unused-report.json` retained by CI); no runtime contract delta (compat gate at 0.2.3: version literal only), no migration; then plan 022 the concurrent-state-and-durability-integrity cut: atomic model-budget reservation (`ModelRouterStateStore.reserveBudget`/`commitBudget`/`releaseBudget` with fencing tokens, `reservationTtlMs` expiry and unknown-usage reconciliation, rate/budget key-map caps with LRU eviction that never drops a held reservation), atomic conversation metadata (`SessionRecord.version` + `appendSession` `expectedVersion` CAS across Postgres/SQLite — create-only `0`, exact-version `N>0`, legacy last-write-wins when omitted; `SessionMetadataConflictError` `metadata_conflict` with versions only, HTTP 409; concurrent create/branch/archive single-statement with branch caps inside the CAS, archive wins, deleted rows never resurrect), single-consumer `EventMultiplexer` (`EventMultiplexerError` `ERR_PRISM_EVENT_MULTIPLEXER_SINGLE_CONSUMER` instead of silent queue sharing), restart-stable NATS durable consumer identity (`prism_<hmac16>` with no random suffix — crash-resumed subscribe continues from the last ack, orphaned 0.2.1 consumers reclaimed on clean stop), and bounded non-durable active-run registries (sweep + fail-closed 512 cap `ERR_PRISM_WORKFLOW_RUN_REGISTRY_OVERFLOW`); new regression surface `scripts/phase22-security.test.mjs` (4 blockers + gate accounting over built public entrypoints) + packed plain-JS `security22.mjs` consumer + the `@arnilo/prism/testing/state-concurrency-conformance` harness (7 probes across memory/Postgres/SQLite/NATS legs, no timing-only sleeps) + the `scripts/phase22-conformance.test.mjs` gate; additive-only compat (new exports only, no removals); forward-only migrations 008 (`prism_sessions.version`) and 003 (`prism_model_router_budgets.reservations`); migration `0.2.1 → 0.2.2`; then plan 021 the provider-completion-and-outbound-trust-boundaries cut: strict stream completion is the shared OpenAI-compatible default (truncated streams fail `incomplete_delta`, explicit `strictCompletion: false` opt-out), bounded success bodies via `readBoundedResponseJson` on all discovery/quota/embeddings/upload/OAuth JSON endpoints (65,536-byte ceiling, depth/property/shape caps), DNS-pinned OIDC JWKS/OPA/content fetches through the core `pinnedFetch` primitive with 3xx redirects rejected outright (private/metadata answers fail closed `ssrf_denied`), shared bounded OAuth device/token polling (`pollDeviceCodeToken`) across provider-openai and credentials-node, and the four edge fixes (Azure/Vertex credential-once, Bedrock duplicate-case/repeated-query SigV4 canonicalization, OpenAI upload failed-DELETE retention, cache `__overflow__` tokens-only); public-entrypoint threat-suite `scripts/phase21-security.test.mjs` + packed plain-JS consumer; additive-only compat (MCP transport helpers re-exported from core, no removals); migration `0.2.0 → 0.2.1`; then plan 020 the fail-closed runtime-and-sandbox-security cut on the 0.2.x review-remediation line: durable-resume decision validation in core (`assertValidAgentRunResume` — unknown decisions/malformed batches fail closed with `ERR_PRISM_DECISION_*` before any state claim, checkpoint write, or tool execution; server parser remains defense in depth), isolated work-tool subprocess environments (`@arnilo/prism-work-tools` — fixed base allow-list + explicit env + forced HOME/telemetry + late-bound per-identity tokens, 64-name/64-KiB caps, absolute binary/configDir, linear output capture), and explicit sandbox capabilities (`@arnilo/prism-coding-security` — `SandboxAdapter.capabilities` with omission-is-false fail-closed resolution, `SandboxCodingComposition.capabilities` from verified wiring, `containmentClaim` deprecated as the conservative projection; Docker reports only verified controls, native reports filesystem/process/privilege `false`); public-entrypoint security conformance (`scripts/phase20-security.test.mjs`, wired into `security:threat-suites`), packed plain-JS consumer regressions, and the sandbox-browser workflow's fail-loud Docker/native capability evidence gate — 0.2.0 never ships while a blocker is skipped; migration and rollback notes in `docs/migration.md` `0.1.7 → 0.2.0`, store-compatible with 0.1.7 in both directions; 0.1.7 was 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. 0.2.6 (plan 026 Task 7) adds the protected coding journey: `scripts/phase26-coding-journey.test.mjs` runs a packed consumer through real provider calls, a digest-pinned Docker sandbox, the durable Postgres worktree lifecycle, provider-driven ACP edits with policy approval, named checks with `diagnosticDelta`, patch review over the server ArtifactService, cross-replica process recovery, durable cancellation, real GitHub PR push/reconcile/cleanup, host Playwright inspection, and the host PTY adapter (frozen profile) — the retained `scripts/phase26-coding-journey-report.json` gates release evidence (pass/blocked/protected, never a passing skip).
|
|
149
151
|
- [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.2.5** current line; 0.1.7 terminal 0.1.x baseline), signed-publication/live-canary prerequisites for 1.0, and Phase 12 demand-evidence entry criteria.
|
|
150
|
-
- [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.
|
|
152
|
+
- [Review coverage archive](_evidence/): per-phase evidence freezes (plans 067–079, releases 0.0.4–0.0.16, 0.2.7 ERP evidence) — traceability matrices, provider validation, capability/primitive/limit matrices, benchmark budgets, and artifact-diet findings; tarball-excluded, kept in-repo for audit.
|
|
151
153
|
|
|
@@ -61,7 +61,7 @@ Useful exported types:
|
|
|
61
61
|
- `DefaultInputBuildContext`: optional input layout, instructions, history, summaries, attachments, resource loader/URIs, tool results, middleware, ids, metadata, and abort signal.
|
|
62
62
|
- `InputAttachment`: already-loaded text/content blocks (including `audio`, `file`, and `document`) or an explicit URI loaded through a caller-provided `ResourceLoader`.
|
|
63
63
|
- `PromptInstruction`: labeled system instruction text.
|
|
64
|
-
- `DefaultPromptBuilder`: the default `PromptBuilder
|
|
64
|
+
- `DefaultPromptBuilder`: the default `PromptBuilder`; cache-aware by default and legacy-preserving when `inputLayout: "legacy"` is passed in its request.
|
|
65
65
|
- `AssembleProviderInputOptions`: model, input, optional builders, context providers, selected skills, active tools, generic provider options, metadata, signal, and optional `contextBudget` (`maxInputTokens` / `maxInputBytes` / `reportOmissions`).
|
|
66
66
|
- `applyContextBudget` / `getContextBudgetReport` / `resolveContextBudget`: deterministic eviction + omission report helpers (estimate = UTF-16 code units ÷ 4).
|
|
67
67
|
- `PromptTemplateOptions`: missing-variable behavior for `renderPromptTemplate()`.
|
|
@@ -79,7 +79,12 @@ The builder returns `readonly Message[]`.
|
|
|
79
79
|
| `legacy` | instructions → summaries → history → current input → attachments/resources → tool results |
|
|
80
80
|
| `cache_aware` | instructions → attachments/resources → summaries → history → tool results → current input |
|
|
81
81
|
|
|
82
|
-
The default prompt builder
|
|
82
|
+
The default prompt builder preserves one composition path while honoring layout:
|
|
83
|
+
|
|
84
|
+
- `cache_aware` (default): leading system messages from input assembly → resolved context blocks → selected/progressively disclosed skills → text tool declarations for text-only/unknown models → remaining input-builder messages (attachments/resources → summaries → history → tool results → current input).
|
|
85
|
+
- `legacy`: context blocks → skills → text tool declarations → all input-builder messages (instructions → summaries → history → current input → attachments/resources → tool results).
|
|
86
|
+
|
|
87
|
+
In cache-aware mode, leading system instructions form the stable boundary before dynamic context and skills. The provider `tools` field remains the host-supplied schema list; text declarations are only a fallback for models without declared tool support. Changing only current input changes the final suffix; changing context, loaded skills, resources, summaries, history, attachments, or tools changes that boundary or a later suffix. A stable prefix persists only while those stable inputs stay byte-stable; provider cache hits remain best-effort.
|
|
83
88
|
- History is prepended before current input.
|
|
84
89
|
- Instructions and summaries are system messages; compacted branch summaries from `rebuildSessionContext()` use the same path.
|
|
85
90
|
- Text attachments and explicit text resources are user messages; inline `audio`/`file`/`document` blocks pass through unchanged on attachments with `content`.
|
|
@@ -112,8 +117,8 @@ The default prompt builder still prepends context, selected skills, and tool dec
|
|
|
112
117
|
```json
|
|
113
118
|
[
|
|
114
119
|
{ "role": "system", "content": [{ "type": "text", "text": "System instruction:\nAnswer briefly." }] },
|
|
115
|
-
{ "role": "user", "content": [{ "type": "text", "text": "
|
|
116
|
-
{ "role": "user", "content": [{ "type": "text", "text": "
|
|
120
|
+
{ "role": "user", "content": [{ "type": "text", "text": "Attachment notes.md:\nRemember the release date." }] },
|
|
121
|
+
{ "role": "user", "content": [{ "type": "text", "text": "Hello" }] }
|
|
117
122
|
]
|
|
118
123
|
```
|
|
119
124
|
|
|
@@ -139,7 +144,7 @@ const messages = await createDefaultInputBuilder().build(prompt, {
|
|
|
139
144
|
await session.run("Explain this", { inputLayout: "cache_aware" });
|
|
140
145
|
```
|
|
141
146
|
|
|
142
|
-
Cache-aware mode is
|
|
147
|
+
Cache-aware mode is the default. Set `inputLayout: "legacy"` when compatibility with the prior whole-prompt order is required.
|
|
143
148
|
|
|
144
149
|
## Extension and configuration notes
|
|
145
150
|
|
|
@@ -163,7 +168,7 @@ const request = await assembleProviderInput({
|
|
|
163
168
|
|
|
164
169
|
## Security and performance notes
|
|
165
170
|
|
|
166
|
-
-
|
|
171
|
+
- Input grouping and default prompt composition are linear in supplied messages, attachments, resources, context blocks, skills, and tools. Layout selection is one branch over already-built groups; no message sorting or canonicalization is performed.
|
|
167
172
|
- Template expansion is dependency-free string replacement over `{{name}}` variables. It does not evaluate expressions, filters, loops, partials, JavaScript, globals, or prototype properties.
|
|
168
173
|
- It performs no provider calls, tool execution, credential resolution, package discovery, filesystem scan, network access, timers, or watchers.
|
|
169
174
|
- URI attachments/resources load only through the caller-provided `ResourceLoader`. Binary media uses `resolveMediaContentBlock()` / `loadBinaryResource()` with bounded bytes, SSRF checks for URLs, and MIME magic validation — see [Multimodal content](multimodal-content.md).
|
|
@@ -63,7 +63,7 @@ Only `instructions` and `contextBlocks` are honored from a contribution; other f
|
|
|
63
63
|
|
|
64
64
|
Injectors do not emit events. Their output is folded into the assembled `ProviderRequest`:
|
|
65
65
|
|
|
66
|
-
- **Instructions** layer via `composeSystemPrompt(injectorContributions, { base: systemInstructions })` as `source: "package"`, `mode: "append"`. Host base instructions come first, then injector package instructions appended. This keeps a single prompt-composition code path (no parallel prompt code in the assembler).
|
|
66
|
+
- **Instructions** layer via `composeSystemPrompt(injectorContributions, { base: systemInstructions })` as `source: "package"`, `mode: "append"`. Host base instructions come first, then injector package instructions appended. This keeps a single prompt-composition code path (no parallel prompt code in the assembler). In the default `cache_aware` layout, that composed leading system message stays before dynamic context, skills, history, tool results, and current input; explicit `legacy` keeps prior whole-prompt ordering.
|
|
67
67
|
- **Context blocks** merge via `resolveContextProviders`, appended after host+skill provider blocks, before the context middleware hook runs. `ponytail:` the assembler threads `injectedBlocks` into `resolveContextProviders` so the existing context middleware flow is untouched and the diff stays minimal.
|
|
68
68
|
|
|
69
69
|
`runInstructionInjectors(injectors, ctx)` runs each selected injector against a turn-local `InstructionContext`, returning `{ instructions: SystemPromptContribution[]; contextBlocks: ContextBlock[] }`. It aborts on `ctx.signal`.
|
package/docs/mcp-tools.md
CHANGED
|
@@ -77,6 +77,7 @@ const handleMcp = await createPrismMcpWebHandler(server, {
|
|
|
77
77
|
## When to use it
|
|
78
78
|
|
|
79
79
|
- **Integrate external MCP tool servers** (filesystem, databases, SaaS adapters) without reimplementing JSON-RPC transports in your app.
|
|
80
|
+
- **Bridge a specific upstream server through a reviewed adapter** — e.g. the optional [`@arnilo/prism-obscura`](obscura.md) wraps `connectMcpTools` with Obscura-specific command validation and conservative effect classification for the complete advertised tool surface.
|
|
80
81
|
- **Keep core dispatch gates** — register returned tools and let `dispatchToolCall` enforce permission, JSON Schema validation (`ToolValidator`), middleware, abort, and parallel execution (Plan 055 Tasks 1–2).
|
|
81
82
|
- **Explicit lifecycle** — connect, refresh on `notifications/tools/list_changed`, and `close()` when the session ends.
|
|
82
83
|
- **Expose selected capabilities** — register a reviewed tool/command allow-list for MCP clients without a custom JSON-RPC server.
|