@arnilo/prism 0.0.1 → 0.0.3
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 +19 -2
- package/README.md +17 -7
- package/dist/agent-definitions.d.ts +12 -0
- package/dist/agent-definitions.js +131 -0
- package/dist/agent-loops.d.ts +14 -0
- package/dist/agent-loops.js +161 -0
- package/dist/agents.js +263 -76
- package/dist/cache-helpers.d.ts +28 -0
- package/dist/cache-helpers.js +73 -0
- package/dist/cli-runner.d.ts +38 -2
- package/dist/cli-runner.js +167 -5
- package/dist/compaction.js +2 -0
- package/dist/config.js +47 -12
- package/dist/contracts.d.ts +581 -6
- package/dist/contracts.js +41 -1
- package/dist/contribution-parsing.d.ts +19 -0
- package/dist/contribution-parsing.js +124 -0
- package/dist/contributions.d.ts +13 -3
- package/dist/contributions.js +96 -20
- package/dist/extensions.js +3 -0
- package/dist/index.d.ts +19 -9
- package/dist/index.js +10 -4
- package/dist/input.d.ts +7 -1
- package/dist/input.js +52 -11
- package/dist/instruction-injection.d.ts +28 -0
- package/dist/instruction-injection.js +55 -0
- package/dist/manifests.d.ts +1 -1
- package/dist/manifests.js +3 -3
- package/dist/models.d.ts +4 -1
- package/dist/models.js +5 -2
- package/dist/node/agent-definitions.d.ts +98 -0
- package/dist/node/agent-definitions.js +389 -0
- package/dist/node/contribution-discovery.d.ts +17 -0
- package/dist/node/contribution-discovery.js +163 -0
- package/dist/node/instruction-injectors.d.ts +32 -0
- package/dist/node/instruction-injectors.js +72 -0
- package/dist/node/session-store-jsonl.d.ts +1 -1
- package/dist/node/session-store-jsonl.js +42 -4
- package/dist/node/system-project-prompts.d.ts +30 -0
- package/dist/node/system-project-prompts.js +53 -0
- package/dist/provider-events.d.ts +3 -1
- package/dist/provider-events.js +34 -0
- package/dist/provider-request-policy.js +15 -1
- package/dist/providers/openai-compatible.js +1 -1
- package/dist/providers.d.ts +6 -2
- package/dist/providers.js +15 -1
- package/dist/redaction.d.ts +2 -1
- package/dist/redaction.js +3 -0
- package/dist/registry-options.d.ts +5 -0
- package/dist/registry-options.js +5 -0
- package/dist/rpc.d.ts +6 -2
- package/dist/rpc.js +71 -13
- package/dist/session-stores.d.ts +3 -1
- package/dist/session-stores.js +67 -6
- package/dist/skills.d.ts +4 -1
- package/dist/skills.js +3 -1
- package/dist/system-prompts.js +6 -2
- package/dist/testing/compaction-conformance.d.ts +17 -0
- package/dist/testing/compaction-conformance.js +61 -0
- package/dist/testing/extension-conformance.d.ts +26 -0
- package/dist/testing/extension-conformance.js +55 -0
- package/dist/testing/provider-conformance.d.ts +7 -0
- package/dist/testing/provider-conformance.js +18 -31
- package/dist/testing/session-store-conformance.d.ts +20 -0
- package/dist/testing/session-store-conformance.js +92 -0
- package/dist/testing/tool-conformance.d.ts +39 -0
- package/dist/testing/tool-conformance.js +79 -0
- package/dist/tools.d.ts +7 -2
- package/dist/tools.js +50 -13
- package/docs/agent-definitions.md +251 -0
- package/docs/agent-events.md +199 -0
- package/docs/agent-loops.md +217 -0
- package/docs/agent-session-runtime.md +20 -8
- package/docs/cli-rpc.md +39 -4
- package/docs/coding-agent-tools.md +208 -0
- package/docs/compaction-and-retry.md +2 -2
- package/docs/compaction-conformance.md +76 -0
- package/docs/compaction-llm.md +6 -3
- package/docs/compaction-observational-memory.md +4 -4
- package/docs/configuration-and-manifests.md +6 -1
- package/docs/context-and-skills.md +79 -6
- package/docs/contribution-discovery.md +149 -0
- package/docs/contribution-registries.md +9 -6
- package/docs/credentials-and-redaction.md +2 -0
- package/docs/customization.md +191 -0
- package/docs/database-persistence.md +407 -0
- package/docs/extension-authoring.md +193 -0
- package/docs/extension-conformance.md +80 -0
- package/docs/extensions.md +6 -0
- package/docs/host-security.md +141 -0
- package/docs/index.md +41 -19
- package/docs/input-and-prompt-assembly.md +19 -3
- package/docs/instruction-injection.md +183 -0
- package/docs/migration.md +201 -0
- package/docs/model-registry.md +122 -0
- package/docs/node-jsonl-session-store.md +5 -4
- package/docs/performance.md +127 -0
- package/docs/provider-caching.md +206 -0
- package/docs/provider-conformance.md +32 -5
- package/docs/provider-layer.md +51 -11
- package/docs/provider-packages.md +65 -5
- package/docs/provider-request-policies.md +113 -0
- package/docs/providers/kimi.md +22 -0
- package/docs/providers/neuralwatt.md +388 -0
- package/docs/providers/openai-compatible.md +1 -0
- package/docs/providers/openai.md +21 -0
- package/docs/providers/opencode-go.md +31 -3
- package/docs/providers/openrouter.md +29 -0
- package/docs/providers/zai.md +17 -0
- package/docs/public-contracts.md +87 -12
- package/docs/release-and-install.md +79 -27
- package/docs/runs-and-usage.md +236 -0
- package/docs/session-store-conformance.md +78 -0
- package/docs/session-stores-and-branching.md +10 -6
- package/docs/session-stores.md +126 -0
- package/docs/settings-auth-trust-security.md +18 -4
- package/docs/structured-output.md +247 -0
- package/docs/system-prompts.md +104 -2
- package/docs/tool-conformance.md +87 -0
- package/docs/tools.md +65 -8
- package/package.json +36 -2
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# Runs and usage ledger
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
`RunLedger` is the host-implemented, write-only seam Prism uses to durably persist run metadata, agent events, tool calls, and usage during a `session.run()`. The runtime calls the adapter as each record becomes available; the adapter decides how to write it (SQL insert, NoSQL put, JSONL append, time-series batch, etc.).
|
|
6
|
+
|
|
7
|
+
APIs:
|
|
8
|
+
|
|
9
|
+
- `RunLedger`
|
|
10
|
+
- `RunLedgerRecord`
|
|
11
|
+
- `RunRecord` / `RunStatus`
|
|
12
|
+
- `AgentEventRecord`
|
|
13
|
+
- `ToolCallRecord` / `ToolCallStatus`
|
|
14
|
+
- `UsageRecord`
|
|
15
|
+
- `redactRunLedgerRecord()`
|
|
16
|
+
|
|
17
|
+
## When to use it
|
|
18
|
+
|
|
19
|
+
Configure `AgentConfig.runLedger` when you want every run of an agent to be persisted. Override it per run with `RunOptions.runLedger` if a single run needs a different adapter or no adapter at all. Use `runLedger` whenever you need durable observability, billing, audit replay, or run-scoped analytics.
|
|
20
|
+
|
|
21
|
+
Do not use `RunLedger` as a replacement for `SessionStore` — messages, branches, and session entries continue to go through `SessionStore.append()`. Do not use it for live streaming; subscribers still receive `AgentEvent` through `session.subscribe()`.
|
|
22
|
+
|
|
23
|
+
## Inputs / request
|
|
24
|
+
|
|
25
|
+
Set the ledger and optional ownership scope/idempotency key on the agent or the run:
|
|
26
|
+
|
|
27
|
+
| Field | Where | Purpose |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| `runLedger` | `AgentConfig` / `RunOptions` | `RunLedger` adapter. `RunOptions.runLedger` wins. |
|
|
30
|
+
| `ownership` | `AgentConfig` / `RunOptions` | `{ tenantId?, accountId?, userId? }` copied into every record. `RunOptions.ownership` wins. |
|
|
31
|
+
| `idempotencyKey` | `AgentConfig` / `RunOptions` | Optional key for run deduplication. `RunOptions.idempotencyKey` wins. |
|
|
32
|
+
|
|
33
|
+
`RunLedger` methods:
|
|
34
|
+
|
|
35
|
+
| Method | Record | When called |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| `appendRun` | `RunRecord` | After run starts (`running`) and again at finish (`succeeded`/`failed`/`aborted`). |
|
|
38
|
+
| `appendEvent` | `AgentEventRecord` | After every emitted `AgentEvent`, after redaction. |
|
|
39
|
+
| `appendToolCall` | `ToolCallRecord` | For each tool-call `started`, `progress`, `finished`, `error`, and `blocked` transition. |
|
|
40
|
+
| `appendUsage` | `UsageRecord` | For each provider `usage` event and for the final loop usage. |
|
|
41
|
+
|
|
42
|
+
All methods may be sync or async (`void | Promise<void>`). The runtime awaits them at safe boundaries, so a slow adapter blocks the run.
|
|
43
|
+
|
|
44
|
+
## Outputs / response / events
|
|
45
|
+
|
|
46
|
+
The adapter receives these record shapes:
|
|
47
|
+
|
|
48
|
+
`RunRecord`:
|
|
49
|
+
|
|
50
|
+
| Field | Purpose |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `id` | Same as `runId`. |
|
|
53
|
+
| `sessionId` | Session id. |
|
|
54
|
+
| `branchId` | Current branch leaf at run start. |
|
|
55
|
+
| `model` | Resolved model config for the run. |
|
|
56
|
+
| `provider` | Resolved provider id for the run. |
|
|
57
|
+
| `idempotencyKey` | Optional host key. |
|
|
58
|
+
| `status` | `queued` \| `running` \| `succeeded` \| `failed` \| `aborted`. |
|
|
59
|
+
| `startedAt` / `finishedAt` | ISO timestamps. |
|
|
60
|
+
| `abortReason` | Set when status is `aborted`. |
|
|
61
|
+
| `error` | `ErrorInfo` when status is `failed`. |
|
|
62
|
+
| `tenantId` / `accountId` / `userId` | From active ownership scope. |
|
|
63
|
+
|
|
64
|
+
`AgentEventRecord`:
|
|
65
|
+
|
|
66
|
+
| Field | Purpose |
|
|
67
|
+
| --- | --- |
|
|
68
|
+
| `id` | Unique ledger row id. |
|
|
69
|
+
| `runId` / `sessionId` / `entryId` | Correlation ids. |
|
|
70
|
+
| `type` | `AgentEvent["type"]` discriminator. |
|
|
71
|
+
| `timestamp` | Event emission time. |
|
|
72
|
+
| `event` | The emitted `AgentEvent`. |
|
|
73
|
+
| `redacted` | `true` when a `SecretRedactor` is active. |
|
|
74
|
+
|
|
75
|
+
`ToolCallRecord`:
|
|
76
|
+
|
|
77
|
+
| Field | Purpose |
|
|
78
|
+
| --- | --- |
|
|
79
|
+
| `id` | Unique ledger row id. |
|
|
80
|
+
| `toolCallId` / `name` | From the provider tool call. |
|
|
81
|
+
| `arguments` | JSON object passed to the tool. |
|
|
82
|
+
| `result` | `ToolResult` for `finished`/`error`/`blocked` rows. |
|
|
83
|
+
| `status` | `started` \| `finished` \| `error` \| `blocked`. Progress snapshots reuse `started` with `progress` fields. |
|
|
84
|
+
| `reason` | Block reason for `blocked` rows (`unknown_tool`, `tool_denied`, `invalid_arguments`, `permission_denied`, `validation_failed`). |
|
|
85
|
+
| `progress` / `progressMetadata` / `progressAt` | Populated on progress snapshots. |
|
|
86
|
+
| `startedAt` / `finishedAt` | Tool-call timing. |
|
|
87
|
+
| `redacted` | `true` when a `SecretRedactor` is active. |
|
|
88
|
+
|
|
89
|
+
`UsageRecord`:
|
|
90
|
+
|
|
91
|
+
| Field | Purpose |
|
|
92
|
+
| --- | --- |
|
|
93
|
+
| `id` | Unique ledger row id. |
|
|
94
|
+
| `runId` / `sessionId` / `entryId` | Correlation ids. |
|
|
95
|
+
| `usage` | `Usage` shape: input/output/total/cache tokens, cost, currency. |
|
|
96
|
+
| `recordedAt` | ISO timestamp. |
|
|
97
|
+
|
|
98
|
+
## Status transitions
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
queued ──> running ──> succeeded
|
|
102
|
+
│
|
|
103
|
+
├──────> failed
|
|
104
|
+
│
|
|
105
|
+
└──────> aborted
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
- `queued` is reserved for host scheduling and is not emitted by the runtime.
|
|
109
|
+
- `running` is written immediately after provider/model resolution and `agent_started`.
|
|
110
|
+
- `succeeded` / `failed` / `aborted` are written once in `finally`.
|
|
111
|
+
- Only the final `RunRecord` contains `finishedAt`, `abortReason`, or `error`.
|
|
112
|
+
|
|
113
|
+
## Request/response example
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"id": "run_abc",
|
|
118
|
+
"sessionId": "session_1",
|
|
119
|
+
"branchId": "branch_1",
|
|
120
|
+
"provider": "openai",
|
|
121
|
+
"model": { "provider": "openai", "model": "gpt-4o" },
|
|
122
|
+
"status": "succeeded",
|
|
123
|
+
"startedAt": "2024-01-01T00:00:00Z",
|
|
124
|
+
"finishedAt": "2024-01-01T00:00:05Z",
|
|
125
|
+
"tenantId": "tenant_a",
|
|
126
|
+
"idempotencyKey": "run-key-123"
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"id": "toolcall_def",
|
|
133
|
+
"sessionId": "session_1",
|
|
134
|
+
"runId": "run_abc",
|
|
135
|
+
"toolCallId": "call_1",
|
|
136
|
+
"name": "echo",
|
|
137
|
+
"arguments": { "text": "hi" },
|
|
138
|
+
"status": "finished",
|
|
139
|
+
"result": { "toolCallId": "call_1", "name": "echo", "value": { "text": "hi" } },
|
|
140
|
+
"startedAt": "2024-01-01T00:00:01Z",
|
|
141
|
+
"finishedAt": "2024-01-01T00:00:02Z",
|
|
142
|
+
"redacted": false
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Implementation example
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
import {
|
|
150
|
+
cacheUsageReport,
|
|
151
|
+
createAgent,
|
|
152
|
+
createMockProvider,
|
|
153
|
+
createSecretRedactor,
|
|
154
|
+
providerDone,
|
|
155
|
+
providerTextDelta,
|
|
156
|
+
type RunLedger,
|
|
157
|
+
type RunRecord,
|
|
158
|
+
type AgentEventRecord,
|
|
159
|
+
type ToolCallRecord,
|
|
160
|
+
type UsageRecord,
|
|
161
|
+
} from "@arnilo/prism";
|
|
162
|
+
|
|
163
|
+
const runs: RunRecord[] = [];
|
|
164
|
+
const events: AgentEventRecord[] = [];
|
|
165
|
+
const toolCalls: ToolCallRecord[] = [];
|
|
166
|
+
const usageRows: UsageRecord[] = [];
|
|
167
|
+
|
|
168
|
+
const ledger: RunLedger = {
|
|
169
|
+
appendRun: async (record) => { runs.push(record); },
|
|
170
|
+
appendEvent: async (record) => { events.push(record); },
|
|
171
|
+
appendToolCall: async (record) => { toolCalls.push(record); },
|
|
172
|
+
appendUsage: async (record) => { usageRows.push(record); },
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const agent = createAgent({
|
|
176
|
+
model: { provider: "mock", model: "demo" },
|
|
177
|
+
provider: createMockProvider([providerTextDelta("Hello"), providerDone()]),
|
|
178
|
+
runLedger: ledger,
|
|
179
|
+
ownership: { tenantId: "tenant_a", accountId: "account_a" },
|
|
180
|
+
idempotencyKey: "agent-key",
|
|
181
|
+
redactor: createSecretRedactor([process.env.APP_KEY!]),
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const session = agent.createSession({ id: "session_1" });
|
|
185
|
+
|
|
186
|
+
// per-run override
|
|
187
|
+
await session.run("Hello", {
|
|
188
|
+
idempotencyKey: "run-key-123",
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
console.log(runs.at(-1)?.status); // succeeded
|
|
192
|
+
console.log(cacheUsageReport(usageRows.at(-1)?.usage));
|
|
193
|
+
// { cacheReadTokens: 0, cacheWriteTokens: 0, ... } when provider usage is present
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Extension and configuration notes
|
|
197
|
+
|
|
198
|
+
### Production ledger adapter checklist
|
|
199
|
+
|
|
200
|
+
- Treat `RunLedger` as write-only from Prism's point of view; expose replay/query APIs through `ProductionPersistenceStore` or host-owned reads.
|
|
201
|
+
- Preserve ordering within each `runId`; allocate a monotonic event `sequence` before acknowledging durable writes.
|
|
202
|
+
- Store `RunRecord.idempotencyKey` for host-level run deduplication, but never put credentials or provider clients in idempotency rows.
|
|
203
|
+
- Redact before durable writes if the adapter transforms records after Prism redaction. Persist `redacted: true` when a redactor was active.
|
|
204
|
+
- Test the full persistence path with the network-free [`examples/external-app-db-backed.ts`](../examples/external-app-db-backed.ts) pattern: run, event, tool-call, usage, branch checkout/fork, and resume queries.
|
|
205
|
+
|
|
206
|
+
- `AgentConfig.runLedger` applies to every run of the agent. `RunOptions.runLedger` overrides it for a single run.
|
|
207
|
+
- `AgentConfig.ownership` is the default ownership scope; `RunOptions.ownership` overrides it per run.
|
|
208
|
+
- `AgentConfig.idempotencyKey` is the default idempotency key; `RunOptions.idempotencyKey` overrides it per run.
|
|
209
|
+
- The runtime resolves `model` and `provider` from `AgentConfig`/`RunOptions`/`AgentDefinition` before writing the start `RunRecord`.
|
|
210
|
+
- Adapters should treat appends as ordered within a `runId`: event and tool-call rows preserve emission order because the runtime drains pending appends before writing the final `RunRecord`.
|
|
211
|
+
- Adapters that need upsert semantics can use `RunRecord.id` (== `runId`) as the stable key.
|
|
212
|
+
- Use `cacheUsageReport(record.usage, model)` for cache diagnostics from normalized usage. It works when a provider reports `cacheReadTokens` without `cacheWriteTokens`; missing write tokens are reported as `0`, and unavailable hit rate/savings stay `undefined`.
|
|
213
|
+
- **Provider-specific telemetry is package-owned.** Core `Usage` carries token counts and `cost`/`currency`; it has no energy or detailed cost-breakdown fields. Providers that surface extra telemetry (e.g. `@arnilo/prism-provider-neuralwatt` exposes `neuralWattEventsWithTelemetry()`, `parseNeuralWattComment()`, and `mapNeuralWattTelemetry()` for `: energy`/`: cost` SSE comments and non-streaming top-level fields) keep that data in package-specific helpers/types. Telemetry never enters `RunLedger` usage rows unless the host explicitly copies it in; it carries usage/cost numbers only — never prompts, API keys, or headers. Account-level quota is likewise package-owned: `@arnilo/prism-provider-neuralwatt` exports an explicit `getNeuralWattQuota()` helper that the host calls on demand (never during generation); NeuralWatt rate-limits that endpoint to 1 request per second per customer, so the caller owns throttling.
|
|
214
|
+
|
|
215
|
+
## Security and performance notes
|
|
216
|
+
|
|
217
|
+
- **No credentials.** `RunLedger` records never contain `AIProvider`, `CredentialResolver`, `ProviderResolver`, provider API keys, or credential values. They store only ids, status, timestamps, and the public event/result/usage shapes.
|
|
218
|
+
- **Redaction.** The runtime calls `redactRunLedgerRecord()` and `redactAgentEvent()` with the active `SecretRedactor` before handing records to the adapter. `AgentEventRecord.redacted` and `ToolCallRecord.redacted` are set to `true` when a redactor is configured. Hosts should still redact before writing to durable storage if they perform additional transformations.
|
|
219
|
+
- **Message content stays in `SessionStore`.** `AgentEventRecord.event` may contain `message_delta` / `message_finished` payloads; these are redacted but still belong conceptually to the session store. Do not use the ledger as the source of truth for messages.
|
|
220
|
+
- **Cache diagnostics stay numeric.** `cacheUsageReport()` derives reports from `Usage` numbers and optional `ModelConfig.cost`; do not add prompt text, cache keys, headers, credentials, or provider payloads to usage rows.
|
|
221
|
+
- **Synchronous adapters block the run.** An adapter that performs network or heavy DB writes inline will slow down the agent loop. For high-throughput hosts, buffer or batch inside the adapter and return quickly; the runtime awaits the returned promise. If batching, preserve per-run order before acknowledging a batch: `appendEvent` rows should be pageable by `(runId, sequence)`, run rows by `(sessionId, startedAt, id)`, and usage rows by `(runId, recordedAt, id)`.
|
|
222
|
+
- **Idempotency is host-owned.** The runtime writes the key into `RunRecord.idempotencyKey`; enforcing unique keys and deduplicating retries is the host adapter's responsibility.
|
|
223
|
+
- **Tenant isolation.** `OwnershipScope` fields are copied from the active ownership scope, but the runtime does not enforce tenant isolation. Host adapters must apply their own access controls when querying persisted ledger rows.
|
|
224
|
+
|
|
225
|
+
## Related APIs
|
|
226
|
+
|
|
227
|
+
- [Performance limits](performance.md): batching, cursor keys, and production sizing assumptions.
|
|
228
|
+
- [Agent/session runtime](agent-session-runtime.md): `session.run()` and runtime event emission.
|
|
229
|
+
- [Agent events](agent-events.md): `AgentEvent` union and `session.subscribe()`.
|
|
230
|
+
- [Tools](tools.md): `ToolResult`, `ToolCallContent`, and `dispatchToolCall()`.
|
|
231
|
+
- [Database persistence](database-persistence.md): reference relational schema for runs, events, tool calls, and usage.
|
|
232
|
+
- [Session store conformance](session-store-conformance.md): pair ledger tests with the session-store adapter baseline.
|
|
233
|
+
- [Session stores](session-stores.md): `SessionStore` contract for session entries and branches.
|
|
234
|
+
- [Credentials and redaction](credentials-and-redaction.md): `createSecretRedactor()` and redaction helpers.
|
|
235
|
+
- [Provider caching](provider-caching.md): cache hints and `cacheUsageReport()` diagnostics.
|
|
236
|
+
- [Public contracts](public-contracts.md): full contract inventory.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Session store conformance
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
Session store conformance helpers are dependency-free assertions for `SessionStore` adapter tests. They exercise the append/idempotency/conflict/branch invariants of any `SessionStore` implementation without network or credentials.
|
|
6
|
+
|
|
7
|
+
Exported from `@arnilo/prism/testing/session-store-conformance`:
|
|
8
|
+
|
|
9
|
+
- `assertSessionStoreConforms(store, options?)`
|
|
10
|
+
- `SessionStoreConformanceOptions`
|
|
11
|
+
|
|
12
|
+
## When to use it
|
|
13
|
+
|
|
14
|
+
Use this helper when implementing a DB-backed `SessionStore` (for example, the reference pattern in `examples/external-app-db-backed.ts`). It asserts the contract that the core memory and JSONL stores already satisfy, so an adapter author does not re-derive it:
|
|
15
|
+
|
|
16
|
+
- append + `list` round-trip
|
|
17
|
+
- duplicate entry id rejection
|
|
18
|
+
- `expectedParentId` mismatch throws `SessionAppendConflictError` and writes nothing (atomic append)
|
|
19
|
+
- `idempotencyKey` deduplication of an exact retry at the same position
|
|
20
|
+
- branching from any existing entry (existence validation, not tip-CAS)
|
|
21
|
+
- distinct linear appends sharing a run-level `idempotencyKey` are not collapsed
|
|
22
|
+
- optional `readBranchPath` returns the ancestor chain in root-to-leaf order (when `exerciseReadBranchPath: true`)
|
|
23
|
+
|
|
24
|
+
## Inputs / request
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { assertSessionStoreConforms } from "@arnilo/prism/testing/session-store-conformance";
|
|
28
|
+
import type { SessionStore } from "@arnilo/prism";
|
|
29
|
+
|
|
30
|
+
await assertSessionStoreConforms(myDbBackedStore, { exerciseReadBranchPath: true });
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`SessionStoreConformanceOptions`:
|
|
34
|
+
- `sessionId?: string` — stable session id for the run (default `"conformance"`)
|
|
35
|
+
- `exerciseReadBranchPath?: boolean` — also probe `readBranchPath` when implemented
|
|
36
|
+
|
|
37
|
+
## Outputs / response / events
|
|
38
|
+
|
|
39
|
+
Returns `Promise<void>`; throws a plain `Error` on the first contract violation. No events, no runner.
|
|
40
|
+
|
|
41
|
+
## Request/response example
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { assertSessionStoreConforms } from "@arnilo/prism/testing/session-store-conformance";
|
|
45
|
+
|
|
46
|
+
await assertSessionStoreConforms(postgresBackedStore);
|
|
47
|
+
// throws if the adapter accepts a duplicate id, ignores a missing parent, or
|
|
48
|
+
// collapses distinct linear appends sharing an idempotency key.
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Implementation example
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { assertSessionStoreConforms } from "@arnilo/prism/testing/session-store-conformance";
|
|
55
|
+
import { createMemorySessionStore } from "@arnilo/prism";
|
|
56
|
+
|
|
57
|
+
// The core memory store conforms:
|
|
58
|
+
await assertSessionStoreConforms(createMemorySessionStore());
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Extension and configuration notes
|
|
62
|
+
|
|
63
|
+
- The helper writes real entries into the supplied store; use a throwaway session id or a test schema.
|
|
64
|
+
- `readBranchPath` is optional; stores that omit it skip that probe.
|
|
65
|
+
- Adapter authors should also exercise `rebuildSessionContext`/`getSessionBranchEntries` with their own fixtures for branch-rebuild behavior beyond the conformance baseline.
|
|
66
|
+
|
|
67
|
+
## Security and performance notes
|
|
68
|
+
|
|
69
|
+
- No credentials, no network, no real secrets required.
|
|
70
|
+
- The helper performs a small fixed number of appends; it is bounded and fast.
|
|
71
|
+
- It does not assert secret redaction in stored entries — pair with `createSecretRedactor` checks in your own tests when entries may carry secret text.
|
|
72
|
+
|
|
73
|
+
## Related APIs
|
|
74
|
+
|
|
75
|
+
- [Session stores and branching](session-stores-and-branching.md)
|
|
76
|
+
- [Session stores](session-stores.md)
|
|
77
|
+
- [Database persistence](database-persistence.md)
|
|
78
|
+
- [Provider conformance](provider-conformance.md)
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
# Session stores and branching
|
|
2
2
|
|
|
3
|
+
> Compatibility page: the canonical session-store overview now lives at [Session stores](session-stores.md). This page retains the detailed branch-helper reference and is kept to avoid breaking existing links.
|
|
4
|
+
|
|
3
5
|
## What it does
|
|
4
6
|
|
|
5
|
-
Session store helpers define branch-aware session entries and pure utilities for creating entries, listing branch leaves, reading a leaf path, and rebuilding provider context from a selected leaf.
|
|
7
|
+
Session store helpers define branch-aware session entries and pure utilities for creating entries, listing branch leaves, reading a leaf path, and rebuilding provider context from a selected leaf. For atomic append options, `SessionAppendConflictError`, branch handles, and production `readBranchPath` guidance, start with [Session stores](session-stores.md#atomic-append-and-branch-handles).
|
|
6
8
|
|
|
7
9
|
Public helpers:
|
|
8
10
|
|
|
9
11
|
- `createSessionEntry(options)`
|
|
10
12
|
- `createMemorySessionStore(initialEntries?)`
|
|
11
|
-
- `getSessionBranchEntries(entries, options)`
|
|
13
|
+
- `getSessionBranchEntries(entries, options)` and `getSessionBranchEntries(reader, query)`
|
|
12
14
|
- `listSessionBranches(entries)`
|
|
13
|
-
- `rebuildSessionContext(entries, options)`
|
|
15
|
+
- `rebuildSessionContext(entries, options)` and `rebuildSessionContext(reader, query)`
|
|
14
16
|
|
|
15
17
|
## When to use it
|
|
16
18
|
|
|
@@ -32,7 +34,7 @@ Do not use them as a database layer, migration system, lock service, compaction
|
|
|
32
34
|
| `runId` | Optional run id. |
|
|
33
35
|
| `message`, `event`, `model`, `previousModel`, `label`, `summary`, `data`, `metadata` | Optional payload fields for the entry kind. |
|
|
34
36
|
|
|
35
|
-
`rebuildSessionContext()` and `getSessionBranchEntries()` accept an optional `leafId`. If omitted, the last entry is used as the leaf. `createMemorySessionStore()` accepts optional initial entries.
|
|
37
|
+
`rebuildSessionContext()` and `getSessionBranchEntries()` accept an optional `leafId`. If omitted, the last entry is used as the leaf. The async reader overloads accept `SessionBranchRead { sessionId, leafId?, cursor?, limit? }` and call a `BranchReader` / `readBranchPath` implementation so database adapters can return one ancestor chain without `list(sessionId)`. `createMemorySessionStore()` accepts optional initial entries.
|
|
36
38
|
|
|
37
39
|
## Outputs / response / events
|
|
38
40
|
|
|
@@ -84,7 +86,7 @@ const context = rebuildSessionContext(await store.list("s1"), { leafId: label.id
|
|
|
84
86
|
|
|
85
87
|
## Extension and configuration notes
|
|
86
88
|
|
|
87
|
-
Stores and extensions can use these data helpers directly. Store adapters only need append/list/get behavior; branch queries are derived in memory from listed entries.
|
|
89
|
+
Stores and extensions can use these data helpers directly. Store adapters only need append/list/get behavior; branch queries are derived in memory from listed entries unless the store implements `readBranchPath`. See [Session stores](session-stores.md) for `SessionAppendOptions`, `SessionAppendConflictError`, and `(sessionId, leafId)` branch-handle guidance.
|
|
88
90
|
|
|
89
91
|
`createMemorySessionStore()` is the built-in in-memory implementation. It preserves append order per session, isolates session ids, returns entries by id in O(1), rejects duplicate entry ids, and returns deep copies from `list()` and `get()`. It is process memory only; hosts that need durability should pass another `SessionStore`.
|
|
90
92
|
|
|
@@ -102,13 +104,15 @@ Use `createDefaultCompactionStrategy()` to create compaction entries that `rebui
|
|
|
102
104
|
|
|
103
105
|
- Helpers are pure data functions: no provider calls, tool calls, settings reads, credential resolution, filesystem access, network access, timers, or dependencies.
|
|
104
106
|
- Store only host-approved session entries. Do not put provider credentials, credential resolvers, provider objects, full provider requests, or secrets in entries.
|
|
105
|
-
- Branch rebuild is linear over listed entries
|
|
107
|
+
- Branch rebuild is linear over listed entries for development stores. Production stores should implement `readBranchPath` and return one branch ancestor chain so large sessions are not fully loaded.
|
|
106
108
|
- Compaction-aware rebuild keeps raw branch entries in `entries`; only provider-context `messages`/`summaries` are reduced.
|
|
107
109
|
- Memory store lookup by id is O(1); list is O(n) for that session.
|
|
108
110
|
- Duplicate ids and missing parents fail clearly instead of guessing a branch.
|
|
109
111
|
|
|
110
112
|
## Related APIs
|
|
111
113
|
|
|
114
|
+
- [Migration guide](migration.md): moving branch-handle reads from the dev `list(sessionId)` path to a database-backed `readBranchPath`.
|
|
115
|
+
- [Session stores](session-stores.md): canonical overview for `SessionAppendOptions`, `SessionAppendConflictError`, branch handles, and dev-vs-production branch reads.
|
|
112
116
|
- [Public contracts](public-contracts.md): `SessionEntry`, `SessionStore`, `StoreFactory`, and session contracts.
|
|
113
117
|
- [Agent/session runtime](agent-session-runtime.md): runtime sessions use these branch helpers for store-backed history, checkout, fork, and clone.
|
|
114
118
|
- [Node JSONL session store](node-jsonl-session-store.md): optional Node filesystem store for caller-named JSONL files.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Session stores
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
Session stores persist `SessionEntry` records for agent sessions. The `SessionStore` contract is the runtime seam: `append(entry)`, `list(sessionId)`, and an optional `get(id)`. Everything else — branch reconstruction, compaction boundaries, redaction, pagination, retention, and multi-tenant ownership — is layered on top by the runtime or by host adapters.
|
|
6
|
+
|
|
7
|
+
This page describes the store contract, built-in helpers, and where to find the production schema reference.
|
|
8
|
+
|
|
9
|
+
## When to use it
|
|
10
|
+
|
|
11
|
+
Use `SessionStore` when you write a host adapter that keeps session entries durable across restarts. Use the built-in `createMemorySessionStore()` for tests and throwaway sessions. Use `createJsonlSessionStore()` from `@arnilo/prism/node/session-store-jsonl` only for single-process development. For production multi-tenant or multi-writer storage, implement a database-backed `SessionStore` or `ProductionPersistenceStore` using the reference schema in [Database persistence](database-persistence.md), then run [Session store conformance](session-store-conformance.md) against the adapter.
|
|
12
|
+
|
|
13
|
+
## Inputs / request
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import type { SessionStore, SessionEntry } from "@arnilo/prism";
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`SessionStore` methods:
|
|
20
|
+
|
|
21
|
+
| Method | Purpose |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| `append(entry, options?)` | Persist one `SessionEntry`. `SessionAppendOptions` can carry `expectedParentId` and an opaque `idempotencyKey`. Rejects duplicate ids within the store. |
|
|
24
|
+
| `list(sessionId)` | Return all entries for one session in stored order. Development fallback for branch reads. |
|
|
25
|
+
| `get?(id)` | Return one entry by id, if present. Optional. |
|
|
26
|
+
| `readBranchPath?(query)` | Optional DB-friendly branch read. Return one branch's ancestor chain as a `PersistencePage<SessionEntry>` so the runtime can avoid `list(sessionId)`. |
|
|
27
|
+
|
|
28
|
+
Public helpers:
|
|
29
|
+
|
|
30
|
+
| Helper | Purpose |
|
|
31
|
+
| --- | --- |
|
|
32
|
+
| `createSessionEntry(options)` | Build a `SessionEntry` with generated `id`/`timestamp` when omitted. |
|
|
33
|
+
| `createMemorySessionStore(initialEntries?)` | Built-in in-memory `SessionStore`. |
|
|
34
|
+
| `getSessionBranchEntries(entries, options)` | Return root-to-leaf entries for a leaf id (sync array path). |
|
|
35
|
+
| `getSessionBranchEntries(reader, query)` | Async overload for a `BranchReader` / `readBranchPath` implementation. |
|
|
36
|
+
| `listSessionBranches(entries)` | List every branch handle as `{ leafId, entries }`. Pair with `sessionId` for a durable `(sessionId, leafId)` branch handle. |
|
|
37
|
+
| `rebuildSessionContext(entries, options)` | Rebuild provider-context `messages` and `summaries` from a branch, honoring compaction entries (sync array path). |
|
|
38
|
+
| `rebuildSessionContext(reader, query)` | Async overload that reads one branch path without a full-session load. |
|
|
39
|
+
|
|
40
|
+
## Outputs / response / events
|
|
41
|
+
|
|
42
|
+
A `SessionStore` returns `SessionEntry` arrays. Branch helpers return deep copies. `rebuildSessionContext()` returns `{ leafId, entries, messages, summaries }` where `entries` is the raw branch, `messages` is the provider context, and `summaries` includes compaction summaries.
|
|
43
|
+
|
|
44
|
+
## Request/response example
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"id": "entry_1",
|
|
49
|
+
"sessionId": "s1",
|
|
50
|
+
"timestamp": "2024-06-15T10:00:00Z",
|
|
51
|
+
"kind": "message",
|
|
52
|
+
"message": {
|
|
53
|
+
"role": "user",
|
|
54
|
+
"content": [{ "type": "text", "text": "Hello" }]
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Implementation example
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { createMemorySessionStore, createSessionEntry } from "@arnilo/prism";
|
|
63
|
+
|
|
64
|
+
const store = createMemorySessionStore();
|
|
65
|
+
const entry = createSessionEntry({
|
|
66
|
+
sessionId: "s1",
|
|
67
|
+
kind: "message",
|
|
68
|
+
message: { role: "user", content: [{ type: "text", text: "Hello" }] },
|
|
69
|
+
});
|
|
70
|
+
await store.append(entry);
|
|
71
|
+
const entries = await store.list("s1");
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
For a database-backed store, see the reference schema and query shapes in [Database persistence](database-persistence.md). A runnable external-app reference that implements `SessionStore` + `RunLedger` + `ProductionPersistenceStore` and self-checks with `assertSessionStoreConforms(..., { exerciseReadBranchPath: true })` lives in [`examples/external-app-db-backed.ts`](../examples/external-app-db-backed.ts).
|
|
75
|
+
|
|
76
|
+
### Atomic append and branch handles
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import type { SessionAppendOptions, SessionBranchHandle } from "@arnilo/prism";
|
|
80
|
+
|
|
81
|
+
const handle: SessionBranchHandle = { sessionId: "s1", leafId: "entry_1" };
|
|
82
|
+
const options: SessionAppendOptions = {
|
|
83
|
+
expectedParentId: handle.leafId,
|
|
84
|
+
idempotencyKey: "request-42", // opaque host value; never a credential
|
|
85
|
+
};
|
|
86
|
+
await store.append(entry, options);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`SessionAppendConflictError` carries this stable shape:
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
{
|
|
93
|
+
code: "session_append_conflict";
|
|
94
|
+
expectedParentId?: string;
|
|
95
|
+
currentLeafId?: string;
|
|
96
|
+
idempotencyDuplicate?: boolean;
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Recognize it with `isSessionAppendConflict(error)`, not message text. Built-in stores reject duplicate entry ids, dangling `expectedParentId` values, and exact idempotency retries. They allow two distinct children of the same existing parent because that is a branch/fork, not parent-order corruption. Production stores may add a stricter branch-tip compare-and-swap when a host wants one-writer linear branches.
|
|
101
|
+
|
|
102
|
+
## Extension and configuration notes
|
|
103
|
+
|
|
104
|
+
- The runtime only requires `SessionStore`. Hosts opt into `ProductionPersistenceStore` for paginated reads and audit tables.
|
|
105
|
+
- Store adapters own id generation policy, ordering, duplicate detection, idempotency storage, and error handling.
|
|
106
|
+
- `AgentSession` uses `AgentSessionConfig.store` before `AgentConfig.store`; otherwise it falls back to a private memory store.
|
|
107
|
+
- Branch semantics are parent links plus a leaf id. External UIs should keep branch handles as `(sessionId, leafId)`; RPC exposes an additional `handleId` for active handles.
|
|
108
|
+
- Development stores can omit `readBranchPath`; the runtime falls back to `list(sessionId)` and the pure in-memory branch walk. Database-backed stores should implement `readBranchPath` so `entries()`, `clone()`, and context rebuild read only the selected ancestor chain.
|
|
109
|
+
|
|
110
|
+
## Security and performance notes
|
|
111
|
+
|
|
112
|
+
- Do not store provider credentials, credential resolvers, provider instances, or unredacted secrets in session entries, append options, idempotency keys, or branch records.
|
|
113
|
+
- Use `AgentConfig.redactor` or `RunOptions.redactor` to redact secrets before entries reach durable stores. Stores receive already-redacted `SessionEntry` values.
|
|
114
|
+
- `createMemorySessionStore()` keeps O(1) duplicate/idempotency/parent checks in process-local maps; it is not durable.
|
|
115
|
+
- The JSONL adapter serializes appends per store instance, has no cross-process lock, and is not suitable for production multi-writer storage.
|
|
116
|
+
- Database-backed stores should follow the indexes and retention guidance in [Database persistence](database-persistence.md). Implement `readBranchPath` as a single branch-path query (for example a recursive CTE) and avoid loading entire large sessions into memory when only one branch is needed.
|
|
117
|
+
|
|
118
|
+
## Related APIs
|
|
119
|
+
|
|
120
|
+
- [Session store conformance](session-store-conformance.md): dependency-free adapter assertions for append/idempotency/conflict/branch invariants.
|
|
121
|
+
- [Migration guide](migration.md): moving from this memory/JSONL store to a database-backed adapter.
|
|
122
|
+
- [Session stores and branching](session-stores-and-branching.md): detailed branch helpers, compaction boundaries, and runtime branch semantics.
|
|
123
|
+
- [Database persistence](database-persistence.md): reference relational schema, indexes, retention, migrations, and NoSQL mapping notes.
|
|
124
|
+
- [Node JSONL session store](node-jsonl-session-store.md): development-only file adapter.
|
|
125
|
+
- [Agent/session runtime](agent-session-runtime.md): runtime sessions use stores for history, checkout, fork, and clone.
|
|
126
|
+
- [Public contracts](public-contracts.md): `SessionEntry`, `SessionStore`, `StoreFactory`, and production persistence contracts.
|
|
@@ -18,7 +18,7 @@ Use these APIs when a host wants one explicit place to compose settings, resolve
|
|
|
18
18
|
- Node-only subpaths: `@arnilo/prism/node/settings` for caller-named JSON settings files and `@arnilo/prism/node/trust` for explicit trusted path roots with symlink-aware realpath checks.
|
|
19
19
|
|
|
20
20
|
## Outputs / response / events
|
|
21
|
-
Settings and credential helpers return existing `SettingsProvider` and `CredentialResolver` contracts. Permission denial blocks tool execution, extension setup, and resource loader calls before side effects. A configured `AgentConfig.redactor` or `RunOptions.redactor` redacts provider requests, emitted `AgentEvent` payloads,
|
|
21
|
+
Settings and credential helpers return existing `SettingsProvider` and `CredentialResolver` contracts. `AgentConfig.settings` and `AgentConfig.credentials` are host-owned metadata for compatibility; `createAgent()` / `session.run()` do not call `settings.get()` or `credentials.resolve()`. Permission denial blocks tool execution, extension setup, and resource loader calls before side effects. A configured `AgentConfig.redactor` or `RunOptions.redactor` redacts provider requests, emitted `AgentEvent` payloads, stored `SessionEntry` values, and runtime `InstructionContext` input/history seen by instruction injectors.
|
|
22
22
|
|
|
23
23
|
## Request/response example
|
|
24
24
|
```ts
|
|
@@ -47,6 +47,7 @@ const apiKey = await resolveCredentialValue(credentials, { name: "api", provider
|
|
|
47
47
|
|
|
48
48
|
const agent = createAgent({
|
|
49
49
|
model: { provider: "demo", model: "model" },
|
|
50
|
+
// host-owned metadata; runtime does not read/resolve these fields
|
|
50
51
|
settings,
|
|
51
52
|
credentials,
|
|
52
53
|
redactor: apiKey ? createSecretRedactor([apiKey]) : undefined,
|
|
@@ -56,14 +57,26 @@ void agent;
|
|
|
56
57
|
```
|
|
57
58
|
|
|
58
59
|
## Extension and configuration notes
|
|
59
|
-
Root imports stay filesystem-free. Node settings files are caller-named and read once; optional missing files are skipped. Trust storage, prompts, approval UI, OAuth token storage, environment-variable selection, and persistent credentials belong in the host or an extension package.
|
|
60
|
+
Root imports stay filesystem-free. Node settings files are caller-named and read once; optional missing files are skipped. Trust storage, prompts, approval UI, OAuth token storage, environment-variable selection, and persistent credentials belong in the host or an extension package. Passing `settings` / `credentials` on `AgentConfig` does not wire hidden runtime reads; hosts pass concrete values or resolvers to the provider/request edge that needs them.
|
|
60
61
|
|
|
61
62
|
## Security and performance notes
|
|
62
|
-
Prism does not sandbox host tools or extensions. Prism does not read environment variables, keychains, user config files, package manifests, resources, or project-local extensions unless the host explicitly wires those operations. Redaction is exact known-secret replacement only; it is not secret detection. Permission and trust checks are one operation per guarded call and add no workers, watchers, retries, network, or filesystem scans.
|
|
63
|
+
Prism does not sandbox host tools or extensions. Prism does not read environment variables, keychains, user config files, package manifests, resources, settings providers, credential resolvers, or project-local extensions unless the host explicitly wires those operations. Redaction is exact known-secret replacement only; it is not secret detection. Permission and trust checks are one operation per guarded call and add no workers, watchers, retries, network, or filesystem scans.
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
Boundary hardening summary:
|
|
66
|
+
|
|
67
|
+
| Boundary | Fail-closed rule |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| Contribution files | `SKILL.md` and `manifest.json` are realpath-checked inside the contribution directory before read. |
|
|
70
|
+
| Instruction resources | Markdown resources are realpath-contained unless host passes explicit `resourceTrust`; `permission` still gates reads. |
|
|
71
|
+
| Injector context | `InstructionContext.input` and `history` are redacted before injector `apply`; injectors grant no tools, skills, permissions, or validators. |
|
|
72
|
+
| System prompt sources | Unknown custom sources rank below app/run layers, so caller `run` policy cannot be overridden by sorting after it. |
|
|
73
|
+
| Config/manifest JSON | `__proto__`, `prototype`, and `constructor` keys are rejected at every depth before merge/clone. |
|
|
74
|
+
| Provider headers | Adapters merge caller headers first, then provider-owned auth/content/session/cache/security/attribution headers last. |
|
|
75
|
+
|
|
76
|
+
`@arnilo/prism/node/trust` resolves symlinks on both the trusted root and the target path. A path that is lexically inside a trusted root but escapes it through a symlink is rejected, and realpath failures (missing root, permission error) fail closed. Contribution discovery and discovered instruction resources reuse this check before reading entry/resource files.
|
|
65
77
|
|
|
66
78
|
## Related APIs
|
|
79
|
+
- [Host security guide](host-security.md): fail-closed checklist for wiring credentials, redaction, trust, permissions, persistence, extension loading, and tool validation in an embedding app.
|
|
67
80
|
- `createStaticSettingsProvider`, `createChainedSettingsProvider`
|
|
68
81
|
- `createMemoryCredentialStore`, `createChainedCredentialResolver`, `createExplicitCredentialResolver`, `createEnvCredentialResolver`, `refreshOAuthCredential`, `resolveCredentialValue`
|
|
69
82
|
- `createStaticTrustPolicy`, `assertTrusted`, `isTrusted`, `TrustDeniedError`
|
|
@@ -71,3 +84,4 @@ Prism does not sandbox host tools or extensions. Prism does not read environment
|
|
|
71
84
|
- `createSecretRedactor`, `redactMessage`, `redactAgentEvent`, `redactSessionEntry`, `redactProviderRequest`
|
|
72
85
|
- `@arnilo/prism/node/settings`: `defaultUserSettingsPath`, `readSettingsFile`, `loadSettingsFiles`
|
|
73
86
|
- `@arnilo/prism/node/trust`: `createPathTrustPolicy`, `isPathInside`, `isPathInsideReal`
|
|
87
|
+
- [Contribution discovery (workspace)](contribution-discovery.md): `createPathTrustPolicy` + `isPathInsideReal` gate workspace contribution roots fail-closed.
|