@arnilo/prism 0.0.2 → 0.0.4
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 +37 -0
- package/README.md +32 -20
- package/dist/agent-loops.d.ts +8 -1
- package/dist/agent-loops.js +57 -11
- package/dist/agents.js +70 -17
- package/dist/checkpoints.d.ts +11 -0
- package/dist/checkpoints.js +144 -0
- package/dist/compaction.js +9 -1
- package/dist/content.d.ts +102 -0
- package/dist/content.js +410 -0
- package/dist/contracts.d.ts +142 -2
- package/dist/event-multiplexer.d.ts +23 -0
- package/dist/event-multiplexer.js +136 -0
- package/dist/execution-policy.d.ts +28 -0
- package/dist/execution-policy.js +24 -0
- package/dist/index.d.ts +17 -5
- package/dist/index.js +11 -4
- package/dist/input.js +11 -1
- package/dist/leases.d.ts +8 -0
- package/dist/leases.js +111 -0
- package/dist/node/agent-definitions.js +3 -5
- package/dist/node/config.d.ts +1 -0
- package/dist/node/config.js +5 -3
- package/dist/node/contribution-discovery.js +5 -8
- package/dist/node/session-store-jsonl.js +8 -5
- package/dist/node/settings.js +2 -2
- package/dist/node/trust.js +2 -4
- package/dist/observability.d.ts +3 -0
- package/dist/observability.js +18 -0
- package/dist/providers/media.d.ts +42 -0
- package/dist/providers/media.js +116 -0
- package/dist/providers/openai-compatible.js +18 -119
- package/dist/providers/openai-primitives.d.ts +9 -0
- package/dist/providers/openai-primitives.js +129 -0
- package/dist/providers/transport.d.ts +40 -0
- package/dist/providers/transport.js +221 -0
- package/dist/redaction.js +40 -13
- package/dist/resources.d.ts +5 -0
- package/dist/resources.js +4 -0
- package/dist/structured-output.d.ts +11 -0
- package/dist/structured-output.js +59 -0
- package/dist/testing/persistence-schema.d.ts +102 -0
- package/dist/testing/persistence-schema.js +457 -0
- package/dist/testing/provider-conformance.js +10 -1
- package/dist/testing/run-ledger-conformance.d.ts +33 -0
- package/dist/testing/run-ledger-conformance.js +172 -0
- package/dist/testing/session-store-conformance.d.ts +16 -0
- package/dist/testing/session-store-conformance.js +73 -0
- package/dist/tools.d.ts +17 -0
- package/dist/tools.js +29 -2
- package/docs/agent-events.md +13 -4
- package/docs/agent-loops.md +10 -4
- package/docs/agent-session-runtime.md +1 -0
- package/docs/cli-rpc.md +3 -0
- package/docs/coding-agent-tools.md +242 -0
- package/docs/coding-security.md +84 -0
- package/docs/credential-storage.md +177 -0
- package/docs/credentials-and-redaction.md +2 -1
- package/docs/database-persistence.md +44 -2
- package/docs/host-security.md +15 -1
- package/docs/index.md +28 -11
- package/docs/input-and-prompt-assembly.md +6 -5
- package/docs/mcp-tools.md +139 -0
- package/docs/middleware-hooks.md +2 -0
- package/docs/migration.md +21 -28
- package/docs/model-registry.md +5 -3
- package/docs/multimodal-content.md +148 -0
- package/docs/observability.md +163 -0
- package/docs/performance.md +40 -1
- package/docs/persistence-credentials-multimodality-primitives.md +303 -0
- package/docs/postgres-persistence.md +141 -0
- package/docs/provider-conformance.md +17 -0
- package/docs/provider-layer.md +1 -1
- package/docs/provider-primitives.md +281 -0
- package/docs/providers/kimi.md +1 -0
- package/docs/providers/neuralwatt.md +1 -0
- package/docs/providers/openai-compatible.md +2 -1
- package/docs/providers/openai.md +8 -1
- package/docs/providers/opencode-go.md +1 -0
- package/docs/providers/openrouter.md +1 -0
- package/docs/providers/zai.md +1 -0
- package/docs/public-contracts.md +9 -2
- package/docs/release-and-install.md +209 -23
- package/docs/resource-loading.md +14 -4
- package/docs/review-coverage-2026-07-14.md +260 -0
- package/docs/run-ledger-conformance.md +96 -0
- package/docs/runs-and-usage.md +2 -0
- package/docs/session-store-conformance.md +16 -0
- package/docs/session-stores-and-branching.md +1 -0
- package/docs/settings-auth-trust-security.md +2 -1
- package/docs/sqlite-persistence.md +122 -0
- package/docs/structured-output.md +9 -0
- package/docs/tool-conformance.md +1 -0
- package/docs/tool-execution-primitives.md +374 -0
- package/docs/tools.md +40 -1
- package/docs/workflow-orchestration-primitives.md +565 -0
- package/docs/workflow-tui-primitives.md +5 -0
- package/docs/workflows.md +219 -0
- package/package.json +34 -5
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# PostgreSQL persistence
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
The optional `@arnilo/prism-session-store-postgres` package ships a production-oriented PostgreSQL adapter that implements:
|
|
6
|
+
|
|
7
|
+
- `SessionStore` — atomic `append` / `list` / `get` / `readBranchPath`
|
|
8
|
+
- `RunLedger` — durable run, event, tool-call, and usage rows
|
|
9
|
+
- `ProductionPersistenceStore` — cursor-paginated `query*` reads plus generic `checkpoints` and atomic `leases` capabilities
|
|
10
|
+
|
|
11
|
+
Factory:
|
|
12
|
+
|
|
13
|
+
- `createPostgresPersistence(options)` (async)
|
|
14
|
+
- `PostgresPersistenceOptions`
|
|
15
|
+
- `PostgresPersistence.close()` (async; ends adapter-owned pools only)
|
|
16
|
+
|
|
17
|
+
The adapter uses `pg@^8.22.0`, applies versioned migrations from the shared Plan 056 schema model inside a transaction guarded by `pg_advisory_xact_lock`, validates/quotes schema identifiers, and passes the full session-store and run-ledger conformance suites when `PRISM_TEST_POSTGRES_URL` is set.
|
|
18
|
+
|
|
19
|
+
## When to use it
|
|
20
|
+
|
|
21
|
+
Use this package when you need server-backed persistence with pooled connections and multi-writer concurrency:
|
|
22
|
+
|
|
23
|
+
- hosted SaaS agents with PostgreSQL as the system of record
|
|
24
|
+
- managed cloud databases (RDS, Cloud SQL, Neon, Supabase, etc.)
|
|
25
|
+
- CI integration tests against a real PostgreSQL service
|
|
26
|
+
|
|
27
|
+
Prefer [`@arnilo/prism-session-store-sqlite`](sqlite-persistence.md) for local CLI tools, single-writer workloads, and network-free default tests.
|
|
28
|
+
|
|
29
|
+
## Inputs / request
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { Pool } from "pg";
|
|
33
|
+
import { createPostgresPersistence } from "@arnilo/prism-session-store-postgres";
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
| Field | Type | Purpose |
|
|
37
|
+
| --- | --- | --- |
|
|
38
|
+
| `pool` | `Pool` | Existing `pg` pool (caller owns lifecycle). |
|
|
39
|
+
| `connectionString` | `string` | Create an adapter-owned bounded pool when `pool` is omitted. |
|
|
40
|
+
| `schema` | `string` | PostgreSQL schema for Prism tables. Defaults to `"prism"`. Validated and double-quoted. |
|
|
41
|
+
| `poolMax` | `number` | Maximum pool size for adapter-owned pools. Defaults to `10`. |
|
|
42
|
+
| `poolConfig` | `PoolConfig` | Additional `pg` options (TLS, idle timeout, application name, etc.). |
|
|
43
|
+
|
|
44
|
+
Hosts own TLS (`ssl` in `poolConfig`), credentials, connection limits, and backup/retention enforcement.
|
|
45
|
+
|
|
46
|
+
## Outputs / response / events
|
|
47
|
+
|
|
48
|
+
`createPostgresPersistence()` returns one object implementing the three persistence contracts plus generic checkpoints and leases:
|
|
49
|
+
|
|
50
|
+
| Method group | Behavior |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `SessionStore.append` | One transaction per append: parent existence check, idempotency dedup, duplicate-id rejection, entry insert. |
|
|
53
|
+
| `SessionStore.list` / `get` | Indexed reads by `session_id` and primary key. |
|
|
54
|
+
| `SessionStore.readBranchPath` | Recursive ancestor query from `leafId` (or latest leaf) in root→leaf order. |
|
|
55
|
+
| `RunLedger.append*` | Inserts run/event/tool/usage rows; events receive monotonic per-run `sequence` values. |
|
|
56
|
+
| `ProductionPersistenceStore.query*` | Parameterized cursor pagination on indexed columns with tenant/account/user filters. |
|
|
57
|
+
| `checkpoints` | Generic versioned `CheckpointStore` backed by `prism_checkpoints`; ownership, CAS/fencing checks, and bounded pagination. |
|
|
58
|
+
| `leases` | Atomic `LeaseStore` backed by `prism_leases`; database-clock expiry, opaque renew/release token, monotonic takeover fence. |
|
|
59
|
+
| `close()` | Ends the pool when the adapter created it from `connectionString`. |
|
|
60
|
+
|
|
61
|
+
Migrations run automatically on open and are idempotent across reopen. Concurrent setup uses per-schema advisory transaction locks.
|
|
62
|
+
|
|
63
|
+
## Request/response example
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"connectionString": "postgres://app:***@db.example.com:5432/prism",
|
|
68
|
+
"schema": "prism",
|
|
69
|
+
"poolMax": 10,
|
|
70
|
+
"poolConfig": {
|
|
71
|
+
"ssl": { "rejectUnauthorized": true }
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Implementation example
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { Pool } from "pg";
|
|
80
|
+
import { createAgentSession } from "@arnilo/prism";
|
|
81
|
+
import { createPostgresPersistence } from "@arnilo/prism-session-store-postgres";
|
|
82
|
+
import { runSessionStoreConformance } from "@arnilo/prism/testing/session-store-conformance";
|
|
83
|
+
|
|
84
|
+
const pool = new Pool({
|
|
85
|
+
connectionString: process.env.DATABASE_URL,
|
|
86
|
+
max: 10,
|
|
87
|
+
ssl: { rejectUnauthorized: true },
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const persistence = await createPostgresPersistence({ pool, schema: "prism" });
|
|
91
|
+
|
|
92
|
+
await runSessionStoreConformance(
|
|
93
|
+
async () => createPostgresPersistence({ pool, schema: "prism" }),
|
|
94
|
+
{ exerciseReadBranchPath: true, exerciseReopen: true },
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const session = createAgentSession({
|
|
98
|
+
sessionStore: persistence,
|
|
99
|
+
runLedger: persistence,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
await session.run("hello");
|
|
103
|
+
await persistence.close();
|
|
104
|
+
await pool.end();
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Live conformance and integration tests:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
PRISM_TEST_POSTGRES_URL="$DATABASE_URL" npm run test:postgres --workspace @arnilo/prism-session-store-postgres
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Extension and configuration notes
|
|
114
|
+
|
|
115
|
+
- The package is optional and workspace-local; `@arnilo/prism` core has no PostgreSQL dependency.
|
|
116
|
+
- Schema names must match `^[a-zA-Z_][a-zA-Z0-9_]*$`; the adapter quotes them and never interpolates user values into identifier positions.
|
|
117
|
+
- `SessionAppendOptions` idempotency rows are durable in `prism_session_append_idempotency` and survive reopen.
|
|
118
|
+
- Schema version **1** (`001_init`) matches `@arnilo/prism/testing/persistence-schema` — SQLite adapters share the same model with dialect-local DDL.
|
|
119
|
+
- Pass an existing `pg` `Pool` when your host already manages pooling, TLS, and credential rotation.
|
|
120
|
+
|
|
121
|
+
## Security and performance notes
|
|
122
|
+
|
|
123
|
+
- **Parameterized SQL only.** Session ids, idempotency keys, tenant ids, and JSON payloads are bound parameters (`$1`, `$2`, …).
|
|
124
|
+
- **Identifier validation.** Configurable `schema` is validated and double-quoted; table names are fixed constants in adapter SQL.
|
|
125
|
+
- **TLS and credentials.** Configure via `pg` `Pool` / `PoolConfig`; the adapter does not read environment variables unless the host passes them into `connectionString` or `poolConfig`.
|
|
126
|
+
- **Redaction upstream.** Event and tool-call payloads may contain secrets; redact before ledger writes. The adapter does not scan or rewrite row contents.
|
|
127
|
+
- **Bounded pool.** Adapter-owned pools default to `max: 10`. Hosts with heavy concurrency should supply their own pool sizing.
|
|
128
|
+
- **Indexed operations.** Append, parent validation, idempotency dedup, branch reads, and pagination use the indexes documented in [Database persistence](database-persistence.md); normal paths avoid sequential scans.
|
|
129
|
+
- **Migration locking.** `pg_advisory_xact_lock` prevents concurrent `001_init` races when multiple processes open the adapter at once.
|
|
130
|
+
- **Tenant isolation.** `tenant_id` / `account_id` / `user_id` columns participate in query filters; hosts must still scope writes correctly.
|
|
131
|
+
- **Benchmark target.** Indexed append + paginated branch read on a warm pool should stay under **50 ms p95** for local/CI-sized datasets (≤100k entries per session); measure with your pool size and hardware before production sizing.
|
|
132
|
+
|
|
133
|
+
## Related APIs
|
|
134
|
+
|
|
135
|
+
- [Database persistence](database-persistence.md): shared schema model, conditional append pattern, indexes.
|
|
136
|
+
- [SQLite persistence](sqlite-persistence.md): file-backed alternative for local/single-writer hosts.
|
|
137
|
+
- [Session store conformance](session-store-conformance.md): `assertSessionStoreConforms` / `runSessionStoreConformance`.
|
|
138
|
+
- [Run ledger conformance](run-ledger-conformance.md): `assertRunLedgerConforms` / `runRunLedgerConformance`.
|
|
139
|
+
- [Persistence, credentials, and multimodality primitives](persistence-credentials-multimodality-primitives.md): package matrix and threat model.
|
|
140
|
+
- [Workflows](workflows.md): adapt `persistence.checkpoints` and pass `persistence.leases` to `createWorkflowCoordinator()` for durable multi-process workflow execution.
|
|
141
|
+
- [Migration guide](migration.md): moving from JSONL/in-memory to database-backed persistence.
|
|
@@ -93,6 +93,22 @@ const body = JSON.parse(String(fetchInit.body));
|
|
|
93
93
|
assertSerializedRequestCoversContent(request, body, { unsupported: ["image"] });
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
+
Multimodal coverage example:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
const request = {
|
|
100
|
+
model: { provider: "openai", model: "gpt-5.1", capabilities: { input: ["text", "file", "document", "audio"] } },
|
|
101
|
+
messages: [{ role: "user", content: [
|
|
102
|
+
{ type: "file", mediaType: "application/pdf", name: "report.pdf", data: "..." },
|
|
103
|
+
{ type: "audio", mediaType: "audio/wav", data: "..." },
|
|
104
|
+
] }],
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
assertSerializedRequestCoversContent(request, body);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Pass `unsupported` only for modalities the provider deliberately omits from the wire format while still accepting the turn via another block type.
|
|
111
|
+
|
|
96
112
|
Protected header-ownership example:
|
|
97
113
|
|
|
98
114
|
```ts
|
|
@@ -127,6 +143,7 @@ The helpers are a testing subpath only. Provider packages can use them with thei
|
|
|
127
143
|
- Use fake credentials only in fixtures.
|
|
128
144
|
- The helpers collect one stream into memory; keep conformance fixtures small.
|
|
129
145
|
- Redaction remains the provider/runtime boundary's job. Use `assertNoSecretLeak()` with known fake secrets to catch regressions, not as a general secret scanner.
|
|
146
|
+
- First-party providers read SSE streams and HTTP error bodies through bounded helpers from `@arnilo/prism/providers/transport` (`readSseEvents` / `readSseData`, `readBoundedResponseText`). Oversized remote input terminates with `ProviderTransportError` instead of unbounded buffering.
|
|
130
147
|
|
|
131
148
|
## Related APIs
|
|
132
149
|
|
package/docs/provider-layer.md
CHANGED
|
@@ -129,7 +129,7 @@ const agent = createAgent({ model: { provider: own.id, model: "demo" }, provider
|
|
|
129
129
|
- Provider event helpers return plain `ProviderEvent` objects.
|
|
130
130
|
- `providerError()` converts unknown errors to redacted `ErrorInfo` through `errorToErrorInfo()` and preserves safe string/number `code` fields for retry classification.
|
|
131
131
|
- `createMockProvider()` returns an `AIProvider` whose `generate()` yields the scripted events in order and checks `request.signal?.aborted` before each event.
|
|
132
|
-
- The agent/session runtime passes its per-run abort signal as `ProviderRequest.signal`. `ProviderRequestOptions.timeoutMs`, `maxRetries`, and `maxRetryDelayMs` are deprecated inert hints in first-party providers; use `RunOptions.signal`/host abort controllers for timeouts and `AgentConfig.retry`/`RunOptions.retry` for retry.
|
|
132
|
+
- The agent/session runtime passes its per-run abort signal as `ProviderRequest.signal`. `ProviderRequestOptions.structuredOutput` requests provider-native JSON-schema output when the model declares `capabilities.structuredOutput`; unsupported models fail before fetch. `ProviderRequestOptions.timeoutMs`, `maxRetries`, and `maxRetryDelayMs` are deprecated inert hints in first-party providers; use `RunOptions.signal`/host abort controllers for timeouts and `AgentConfig.retry`/`RunOptions.retry` for retry.
|
|
133
133
|
|
|
134
134
|
## Request/response example
|
|
135
135
|
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# Provider primitives
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
This page freezes the reusable provider transport, OpenAI-style serialization, structured-output capability, and observability designs for Plan 054. It inventories duplicated helpers across `@arnilo/prism` and first-party provider packages, documents trust boundaries, and selects the generic APIs that Tasks 1–6 will implement and migrate to.
|
|
6
|
+
|
|
7
|
+
Implementation is **shipped** for transport and OpenAI serialization primitives (Plan 054 Task 1). **All first-party providers are migrated** to those primitives (Plan 054 Task 2); package-local `sse.ts`, `safeText`, `parseArgs`, and duplicate OpenAI serializers are removed. **Native structured output** (`StructuredOutputOptions`, provider mappers, capability gating) shipped in Task 4. Observability contracts remain design-only until Task 5.
|
|
8
|
+
|
|
9
|
+
## When to use it
|
|
10
|
+
|
|
11
|
+
- **Provider package authors** implementing or migrating a first-party adapter should import shared primitives from `@arnilo/prism/providers/transport` and `@arnilo/prism/providers/openai` instead of copying `sse.ts`, `safeText`, `parseArgs`, or serializers.
|
|
12
|
+
- **Host apps** choose native structured output via `ProviderRequestOptions.structuredOutput` when the model declares support; otherwise they keep the artifact generate→validate→revise loop ([Structured output](structured-output.md)).
|
|
13
|
+
- **Operators** enable observability through extended agent events and the optional OpenTelemetry adapter package ([Observability](observability.md)).
|
|
14
|
+
|
|
15
|
+
## Inventory (2026-07-14 baseline)
|
|
16
|
+
|
|
17
|
+
Static scan of root `src/providers/` and `packages/provider-*/src/` before Plan 054 implementation.
|
|
18
|
+
|
|
19
|
+
### Duplicated protocol helpers (baseline → Task 2)
|
|
20
|
+
|
|
21
|
+
| Helper | Baseline copies | Task 2 status |
|
|
22
|
+
| --- | ---: | --- |
|
|
23
|
+
| `readSseData` / SSE reader | 7 (6× `sse.ts` + inline openai-compatible) | **Migrated** — `@arnilo/prism/providers/transport`; local `sse.ts` deleted |
|
|
24
|
+
| `readNeuralWattSseFrames` | 1 | **Migrated** — thin adapter over `readSseEvents` `comments` in `provider-neuralwatt` |
|
|
25
|
+
| `safeText` | 9 | **Migrated** — `readBoundedResponseText` with optional `secrets` |
|
|
26
|
+
| `parseArgs` | 8 | **Migrated** — `parseJsonObjectArguments` (typed error on malformed JSON) |
|
|
27
|
+
| `toTool` | 7 OpenAI-style | **Migrated** — `serializeOpenAITool` where wire shape matches |
|
|
28
|
+
| `toUsage` / usage mapper | 6 | **Local** — provider-specific wire field names remain per package |
|
|
29
|
+
| Message serializer | 7 local | **Mixed** — `serializeOpenAIChatMessage` / `assertOpenAIChatMessage` where OpenAI Chat Completions; Anthropic, OpenRouter cache, OpenAI Responses, NeuralWatt `reasoning_content` stay local |
|
|
30
|
+
|
|
31
|
+
### Retry / rate-limit metadata paths
|
|
32
|
+
|
|
33
|
+
| Surface | Owner | Behavior today |
|
|
34
|
+
| --- | --- | --- |
|
|
35
|
+
| Runtime retry | `@arnilo/prism` `AgentConfig.retry` / `RunOptions.retry` | Classifies `ErrorInfo.code`; provider packages set numeric HTTP `code` on errors |
|
|
36
|
+
| `ProviderRequestOptions.maxRetries` / `timeoutMs` | Contracts | **Deprecated / inert** in first-party providers |
|
|
37
|
+
| NeuralWatt `classifyNeuralWattError` | `packages/provider-neuralwatt` | Parses `Retry-After`, `error.retry_after`, `retry_strategy`; no extra network calls |
|
|
38
|
+
| Quota endpoint throttling | `packages/provider-neuralwatt/quota.ts` | Documents 1 rps limit; caller-owned cache |
|
|
39
|
+
|
|
40
|
+
No generic core helper extracts `Retry-After` / `x-request-id` for all providers yet.
|
|
41
|
+
|
|
42
|
+
### Structured output
|
|
43
|
+
|
|
44
|
+
| Surface | Status |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| `ProviderRequestOptions` | `structuredOutput?: StructuredOutputOptions` |
|
|
47
|
+
| `ModelCapabilities` | `structuredOutput?: boolean \| "json_schema"` |
|
|
48
|
+
| Provider wire mapping | None — artifact loop is the only structured-output path |
|
|
49
|
+
| Schema validation | Host-owned via artifact `validator`; no provider-native request |
|
|
50
|
+
|
|
51
|
+
### Telemetry / observability events
|
|
52
|
+
|
|
53
|
+
| Event / hook | Owner | Payload classification |
|
|
54
|
+
| --- | --- | --- |
|
|
55
|
+
| `ProviderEvent` union | Core | Text/thinking/tool/usage/done/error — no request metadata |
|
|
56
|
+
| `AgentEvent` stream | Core | Turn/message/tool/retry — content redacted when `redactor` configured |
|
|
57
|
+
| `neuralwatt:telemetry` | `provider-neuralwatt` | Numeric energy/cost only — **safe metadata** |
|
|
58
|
+
| Middleware `provider_request` | Core | Full `ProviderRequest` — host must redact |
|
|
59
|
+
| OpenTelemetry adapter | **Not shipped** | Planned optional package |
|
|
60
|
+
|
|
61
|
+
## Chosen generic APIs (frozen for Task 1+)
|
|
62
|
+
|
|
63
|
+
Primitives are **stdlib-only**, exposed as peer-importable subpaths on `@arnilo/prism`. Provider-specific request fields, event mapping, cache/reasoning knobs, and NeuralWatt comment telemetry stay local.
|
|
64
|
+
|
|
65
|
+
### Decision table
|
|
66
|
+
|
|
67
|
+
| Concern | Option A | Option B | **Chosen** | Rationale |
|
|
68
|
+
| --- | --- | --- | --- | --- |
|
|
69
|
+
| SSE parsing | External npm SSE library | Incremental stdlib parser | **B** | Small surface; avoids dependency |
|
|
70
|
+
| Transport packaging | New `@arnilo/prism-provider-transport` package | Core subpath `@arnilo/prism/providers/transport` | **Core subpath** | Matches existing `providers/openai-compatible` pattern; one peer dep |
|
|
71
|
+
| OpenAI serializers | Duplicate per package | `@arnilo/prism/providers/openai` | **Core subpath** | Proven by ≥6 providers |
|
|
72
|
+
| NeuralWatt comments | Force into generic reader | `readSseEvents` yields optional `comments[]`; NeuralWatt maps locally | **Optional comments** | Keeps generic reader used by ≥2 providers without NeuralWatt-only branches in core |
|
|
73
|
+
| Structured output wire shape | Vendor fields in core contracts | Provider-neutral option + local mapper | **Neutral option** | Avoids leaking `response_format` into contracts |
|
|
74
|
+
| Observability | Hard OTel in core | Extended events + optional adapter package | **Events + optional pkg** | No mandatory heavyweight dep |
|
|
75
|
+
|
|
76
|
+
### `@arnilo/prism/providers/transport` — **shipped**
|
|
77
|
+
|
|
78
|
+
Import:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import {
|
|
82
|
+
readSseEvents,
|
|
83
|
+
readSseData,
|
|
84
|
+
readBoundedResponseText,
|
|
85
|
+
parseJsonObjectArguments,
|
|
86
|
+
ProviderTransportError,
|
|
87
|
+
DEFAULT_MAX_EVENT_BYTES,
|
|
88
|
+
DEFAULT_MAX_BUFFER_BYTES,
|
|
89
|
+
DEFAULT_MAX_RESPONSE_BODY_BYTES,
|
|
90
|
+
} from "@arnilo/prism/providers/transport";
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
export interface BoundedStreamLimits {
|
|
95
|
+
/** Max bytes per completed SSE event (all data: lines + field names). Default: 262_144 (256 KiB). */
|
|
96
|
+
readonly maxEventBytes?: number;
|
|
97
|
+
/** Max bytes retained for an incomplete event/buffer. Default: 524_288 (512 KiB). */
|
|
98
|
+
readonly maxBufferBytes?: number;
|
|
99
|
+
/** Max bytes read from non-streaming HTTP bodies (errors). Default: 65_536 (64 KiB). */
|
|
100
|
+
readonly maxResponseBodyBytes?: number;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface SseEvent {
|
|
104
|
+
readonly id?: string;
|
|
105
|
+
readonly event?: string;
|
|
106
|
+
/** Joined multiline `data:` payload for one SSE event. */
|
|
107
|
+
readonly data: string;
|
|
108
|
+
/** Raw `:` comment lines (without leading colon), when present. */
|
|
109
|
+
readonly comments?: readonly string[];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export class ProviderTransportError extends Error {
|
|
113
|
+
readonly code: "sse_buffer_overflow" | "sse_event_overflow" | "response_body_overflow" | "aborted";
|
|
114
|
+
readonly limitBytes?: number;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Incremental O(bytes) SSE parser. Supports LF/CRLF, comment lines, multiline data:, final partial flush, abort. */
|
|
118
|
+
export async function* readSseEvents(
|
|
119
|
+
body: ReadableStream<Uint8Array>,
|
|
120
|
+
options?: BoundedStreamLimits & { signal?: AbortSignal },
|
|
121
|
+
): AsyncGenerator<SseEvent>;
|
|
122
|
+
|
|
123
|
+
/** Read response body text with a hard byte ceiling; releases the reader. */
|
|
124
|
+
export async function readBoundedResponseText(
|
|
125
|
+
response: Response,
|
|
126
|
+
options?: BoundedStreamLimits & { secrets?: readonly (string | undefined)[] },
|
|
127
|
+
): Promise<string>;
|
|
128
|
+
|
|
129
|
+
/** Parse tool-call arguments JSON to a plain object; throws typed error on invalid/non-object input. */
|
|
130
|
+
export function parseJsonObjectArguments(
|
|
131
|
+
text: string,
|
|
132
|
+
options?: { toolName?: string; maxBytes?: number },
|
|
133
|
+
): JsonObject;
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Performance:** Single pass over chunks; retained memory is `O(min(buffer, maxBufferBytes))`, not `O(stream)`. No full-stream accumulation.
|
|
137
|
+
|
|
138
|
+
### `@arnilo/prism/providers/openai` — **shipped**
|
|
139
|
+
|
|
140
|
+
Import:
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import {
|
|
144
|
+
serializeOpenAITool,
|
|
145
|
+
serializeOpenAIChatMessage,
|
|
146
|
+
mapOpenAIChatUsage,
|
|
147
|
+
assertOpenAIChatMessage,
|
|
148
|
+
} from "@arnilo/prism/providers/openai";
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
/** OpenAI Chat Completions tool schema. */
|
|
153
|
+
export function serializeOpenAITool(tool: ToolDefinition): JsonObject;
|
|
154
|
+
|
|
155
|
+
/** OpenAI Chat Completions message wire shape with capability guards. */
|
|
156
|
+
export function serializeOpenAIChatMessage(
|
|
157
|
+
message: Message,
|
|
158
|
+
capabilities?: ModelCapabilities,
|
|
159
|
+
): JsonObject;
|
|
160
|
+
|
|
161
|
+
/** Map OpenAI `usage` object to Prism `Usage` (incl. cache fields). */
|
|
162
|
+
export function mapOpenAIChatUsage(usage: unknown): Usage | undefined;
|
|
163
|
+
|
|
164
|
+
/** Fail fast with indexed, content-free diagnostics (no payload stringify). */
|
|
165
|
+
export function assertOpenAIChatMessage(message: unknown, path: string): asserts message is Message;
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`src/providers/openai-compatible.ts` becomes a thin adapter over these helpers in Task 2.
|
|
169
|
+
|
|
170
|
+
### Structured output capability (Task 4 — **shipped**)
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
// Added to src/contracts.ts — provider-neutral host option
|
|
174
|
+
export interface StructuredOutputOptions {
|
|
175
|
+
readonly name: string;
|
|
176
|
+
readonly schema: JsonObject;
|
|
177
|
+
readonly strict?: boolean;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ProviderRequestOptions
|
|
181
|
+
readonly structuredOutput?: StructuredOutputOptions;
|
|
182
|
+
|
|
183
|
+
// ModelCapabilities
|
|
184
|
+
readonly structuredOutput?: boolean | "json_schema";
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
| Provider family | Native support (planned) | Wire mapping owner |
|
|
188
|
+
| --- | --- | --- |
|
|
189
|
+
| OpenAI / OpenAI-compatible / OpenRouter / OpenCode Go (OpenAI chat) | `response_format: { type: "json_schema", json_schema: { name, schema, strict } }` | Respective provider package |
|
|
190
|
+
| OpenAI Responses API | `text.format` / JSON schema fields per API version | `provider-openai` |
|
|
191
|
+
| Anthropic (OpenCode Go) | Documented fallback only unless API gains parity | `provider-opencode-go` |
|
|
192
|
+
| Z.AI / Kimi / NeuralWatt | Capability-gated per package docs | Local mapper or clear unsupported error |
|
|
193
|
+
| Unsupported | — | Host selects artifact loop explicitly |
|
|
194
|
+
|
|
195
|
+
**Fallback rule:** Unsupported providers **do not** silently repair. Runtime returns a clear error unless the host configured the artifact loop ([Structured output](structured-output.md)).
|
|
196
|
+
|
|
197
|
+
### Observability capability (Task 5 contract)
|
|
198
|
+
|
|
199
|
+
Core extends existing seams — no second event bus.
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
export interface ProviderTurnMetadata {
|
|
203
|
+
readonly providerId: string;
|
|
204
|
+
readonly model: ModelConfig;
|
|
205
|
+
readonly requestId?: string;
|
|
206
|
+
readonly latencyMs?: number;
|
|
207
|
+
readonly attempt?: number;
|
|
208
|
+
readonly httpStatus?: number;
|
|
209
|
+
readonly rateLimitRemaining?: number;
|
|
210
|
+
readonly rateLimitResetMs?: number;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// New AgentEvent variants (metadata only — no prompts, tool args, or credentials):
|
|
214
|
+
// - provider_turn_started { sessionId, runId, turn, metadata }
|
|
215
|
+
// - provider_turn_finished { sessionId, runId, turn, metadata, usage?, error? }
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Optional package `@arnilo/prism-observability-opentelemetry` subscribes via middleware + agent events. **Default:** content redacted/absent; high-cardinality IDs are span attributes, not metric labels. NeuralWatt `neuralwatt:telemetry` events remain package-local; the adapter may forward numeric energy/cost fields.
|
|
219
|
+
|
|
220
|
+
## Migration conformance fixtures
|
|
221
|
+
|
|
222
|
+
Every migrated provider must pass this shared matrix (implemented in Task 1 tests, run per provider in Task 2/6):
|
|
223
|
+
|
|
224
|
+
| # | Fixture | Assert |
|
|
225
|
+
| ---: | --- | --- |
|
|
226
|
+
| 1 | UTF-8 chunk split mid-codepoint | Event data reconstructs valid Unicode |
|
|
227
|
+
| 2 | CRLF and LF event delimiters | Same logical events |
|
|
228
|
+
| 3 | Multiline `data:` field | Joined payload parses as one JSON value |
|
|
229
|
+
| 4 | SSE comment lines (`:`) | Ignored by default reader; NeuralWatt reader surfaces comments |
|
|
230
|
+
| 5 | Partial final buffer without trailing blank line | Flushed on stream end |
|
|
231
|
+
| 6 | `AbortSignal` during read | `ProviderTransportError` code `aborted`; reader released |
|
|
232
|
+
| 7 | Event exceeds `maxEventBytes` | `sse_event_overflow`; stream terminated |
|
|
233
|
+
| 8 | Incomplete buffer exceeds `maxBufferBytes` | `sse_buffer_overflow` |
|
|
234
|
+
| 9 | Error body exceeds `maxResponseBodyBytes` | `response_body_overflow`; no unbounded growth |
|
|
235
|
+
| 10 | Malformed tool arguments | Typed parse error with `toolName` context |
|
|
236
|
+
| 11 | Malformed message at index *n* | `assertOpenAIChatMessage` path in error; no content echo |
|
|
237
|
+
| 12 | Secret in error body | Redacted when `secrets` passed to `readBoundedResponseText` |
|
|
238
|
+
| 13 | Caller `authorization` header | Provider-owned header wins (existing conformance) |
|
|
239
|
+
| 14 | Stream order / tool-call reconstruction | Unchanged provider conformance suite |
|
|
240
|
+
|
|
241
|
+
## Security and performance notes
|
|
242
|
+
|
|
243
|
+
### Trust boundaries
|
|
244
|
+
|
|
245
|
+
| Boundary | Rule |
|
|
246
|
+
| --- | --- |
|
|
247
|
+
| Credentials | Resolved in provider package; provider-owned `authorization` overrides caller headers |
|
|
248
|
+
| Redaction order | Secrets redacted **before** error strings, ledger rows, events, and observability metadata |
|
|
249
|
+
| Transport errors | Include limit kind and byte ceiling — never full bodies, tokens, or prompts |
|
|
250
|
+
| Structured-output schemas | JSON-safe objects only; reject `__proto__` / `prototype` / `constructor` keys; size cap enforced |
|
|
251
|
+
| OAuth (Task 3) | Device/authorization/access/refresh tokens redacted from all token-endpoint failures |
|
|
252
|
+
| Observability | Metadata-only by default; prompt/content/tool payloads opt-in and redacted |
|
|
253
|
+
|
|
254
|
+
### Performance defaults
|
|
255
|
+
|
|
256
|
+
| Limit | Default | Override |
|
|
257
|
+
| --- | ---: | --- |
|
|
258
|
+
| `maxEventBytes` | 256 KiB | Per-request `BoundedStreamLimits` |
|
|
259
|
+
| `maxBufferBytes` | 512 KiB | Per-request |
|
|
260
|
+
| `maxResponseBodyBytes` | 64 KiB | Per-request |
|
|
261
|
+
| Observability overhead (Task 5 target) | <5% vs disabled | Excludes exporter I/O |
|
|
262
|
+
|
|
263
|
+
## Related APIs
|
|
264
|
+
|
|
265
|
+
- [Provider layer](provider-layer.md): registry, mock provider, event helpers
|
|
266
|
+
- [Provider conformance](provider-conformance.md): stream order, abort, header ownership
|
|
267
|
+
- [OpenAI-compatible provider](providers/openai-compatible.md): reference adapter subpath
|
|
268
|
+
- [Structured output](structured-output.md): artifact loop fallback
|
|
269
|
+
- [Provider request policies](provider-request-policies.md): cache and request hooks
|
|
270
|
+
- [Review coverage (2026-07-14)](review-coverage-2026-07-14.md): finding → plan traceability
|
|
271
|
+
|
|
272
|
+
## Task ownership map
|
|
273
|
+
|
|
274
|
+
| Finding / capability | Plan 054 task | Primitive / doc |
|
|
275
|
+
| --- | --- | --- |
|
|
276
|
+
| R-008 Unbounded SSE/error bodies | 1, 2 | `readSseEvents`, `readBoundedResponseText` |
|
|
277
|
+
| R-009 OAuth device polling | 3 | `packages/provider-openai/src/oauth.ts` |
|
|
278
|
+
| R-010 Duplicated helpers | 1, 2 | This page + subpaths |
|
|
279
|
+
| C-002 Native structured output | 4 | `StructuredOutputOptions` |
|
|
280
|
+
| C-004 Shared resilient transport | 1, 2 | `providers/transport` |
|
|
281
|
+
| C-008 Observability hooks | 5 | `ProviderTurnMetadata`, optional OTel package |
|
package/docs/providers/kimi.md
CHANGED
|
@@ -111,6 +111,7 @@ await kernel.load([
|
|
|
111
111
|
|
|
112
112
|
## Security and performance notes
|
|
113
113
|
|
|
114
|
+
- SSE streams and HTTP error bodies use bounded `@arnilo/prism/providers/transport` helpers (`readSseData`, `readBoundedResponseText`).
|
|
114
115
|
- No network calls during import, setup, build, or default tests.
|
|
115
116
|
- No automatic environment, file, keychain, or shell credential lookup.
|
|
116
117
|
- Kimi credentials are resolved per request from caller-supplied values or resolvers
|
|
@@ -356,6 +356,7 @@ const decision = classifyNeuralWattError({ status: 429, headers: { "retry-after"
|
|
|
356
356
|
|
|
357
357
|
## Security and performance notes
|
|
358
358
|
|
|
359
|
+
- SSE streams, HTTP error bodies, and quota/model-discovery failures use bounded `@arnilo/prism/providers/transport` helpers (`readSseEvents`, `readBoundedResponseText`). NeuralWatt `: energy` / `: cost` comment frames are surfaced via `readSseEvents` `comments` and mapped locally.
|
|
359
360
|
- No network calls during import, setup, build, default tests, or generation beyond
|
|
360
361
|
the explicit Chat Completions request. `listNeuralWattModels()` is opt-in and
|
|
361
362
|
makes one `GET /v1/models` call per invocation; `getNeuralWattQuota()` is opt-in
|
|
@@ -116,8 +116,9 @@ const provider = createOpenAICompatibleProvider({
|
|
|
116
116
|
- Resolved API keys are used for the HTTP `Authorization` header and passed to error redaction; they are not stored in registries or events.
|
|
117
117
|
- Redaction only removes known values supplied to the helper. Avoid logging raw provider requests/responses.
|
|
118
118
|
- `fetch` receives the request `AbortSignal`.
|
|
119
|
+
- SSE and HTTP error bodies are read through bounded `@arnilo/prism/providers/transport` helpers (`readSseData`, `readBoundedResponseText`) with configurable byte ceilings.
|
|
119
120
|
- Tests should use injected `fetch` and never make real network calls.
|
|
120
|
-
- Tool-call arguments are accumulated as streamed text, parsed
|
|
121
|
+
- Tool-call arguments are accumulated as streamed text, parsed with `parseJsonObjectArguments` when the final tool call is emitted; empty argument text yields `{}`, malformed JSON yields an `error` event.
|
|
121
122
|
|
|
122
123
|
## Related APIs
|
|
123
124
|
|
package/docs/providers/openai.md
CHANGED
|
@@ -108,6 +108,10 @@ const challenge = computeS256Challenge(verifier);
|
|
|
108
108
|
run/model through `RunOptions` and `ModelConfig.compat`.
|
|
109
109
|
- OAuth browser/device-code flows run only when the caller explicitly invokes the
|
|
110
110
|
OAuth provider.
|
|
111
|
+
- Device-code login polls the token endpoint with server-directed `interval` and
|
|
112
|
+
`expires_in`, honors RFC 8628 `authorization_pending` / `slow_down`, and stops
|
|
113
|
+
on terminal errors or expiry. Pass `signal` on `OAuthLoginCallbacks` to abort
|
|
114
|
+
polling promptly.
|
|
111
115
|
|
|
112
116
|
### Cache behavior
|
|
113
117
|
|
|
@@ -132,11 +136,14 @@ const challenge = computeS256Challenge(verifier);
|
|
|
132
136
|
|
|
133
137
|
## Security and performance notes
|
|
134
138
|
|
|
139
|
+
- SSE streams and HTTP error bodies use bounded `@arnilo/prism/providers/transport` helpers (`readSseData`, `readBoundedResponseText`).
|
|
135
140
|
- No network calls during import, setup, build, or default tests.
|
|
136
141
|
- No automatic environment, file, keychain, or shell credential lookup; Prism never
|
|
137
142
|
reads `process.env` on its own.
|
|
138
143
|
- API keys/access tokens are resolved per request from caller-supplied values or
|
|
139
|
-
resolvers; OAuth errors redact known token values (`[REDACTED]`)
|
|
144
|
+
resolvers; OAuth errors redact known token values (`[REDACTED]`) including
|
|
145
|
+
authorization codes, PKCE verifiers, device codes, user codes, and
|
|
146
|
+
access/refresh tokens echoed in token-endpoint failures.
|
|
140
147
|
- The PKCE verifier is exchanged at the token endpoint, never sent on the authorize
|
|
141
148
|
URL.
|
|
142
149
|
- Live tests stay opt-in behind `PRISM_LIVE_PROVIDER_TESTS=1` plus fake-safe
|
|
@@ -110,6 +110,7 @@ await kernel.load([
|
|
|
110
110
|
|
|
111
111
|
## Security and performance notes
|
|
112
112
|
|
|
113
|
+
- SSE streams and HTTP error bodies use bounded `@arnilo/prism/providers/transport` helpers (`readSseData`, `readBoundedResponseText`).
|
|
113
114
|
- No network calls during import, setup, build, or default tests.
|
|
114
115
|
- No automatic environment, file, keychain, or shell credential lookup.
|
|
115
116
|
- API keys are resolved per request from caller-supplied values or resolvers and
|
|
@@ -110,6 +110,7 @@ await kernel.load([
|
|
|
110
110
|
|
|
111
111
|
## Security and performance notes
|
|
112
112
|
|
|
113
|
+
- SSE streams and HTTP error bodies use bounded `@arnilo/prism/providers/transport` helpers (`readSseData`, `readBoundedResponseText`).
|
|
113
114
|
- No catalog fetch during setup; no automatic environment, file, keychain, or shell
|
|
114
115
|
credential lookup.
|
|
115
116
|
- API keys are resolved per request from caller-supplied values or resolvers and
|
package/docs/providers/zai.md
CHANGED
|
@@ -104,6 +104,7 @@ await kernel.load([
|
|
|
104
104
|
|
|
105
105
|
## Security and performance notes
|
|
106
106
|
|
|
107
|
+
- SSE streams and HTTP error bodies use bounded `@arnilo/prism/providers/transport` helpers (`readSseData`, `readBoundedResponseText`).
|
|
107
108
|
- No network calls during import, setup, build, or default tests.
|
|
108
109
|
- No automatic environment, file, keychain, or shell credential lookup.
|
|
109
110
|
- API keys are resolved per request from caller-supplied values or resolvers and
|
package/docs/public-contracts.md
CHANGED
|
@@ -15,7 +15,7 @@ Current contract groups:
|
|
|
15
15
|
- Extensions/middleware: `ExtensionLifecycleEventName`, `ExtensionEvent`, `Extension`, `ExtensionAPI`, `MiddlewareHookName`, `Middleware`, `MiddlewareNext`, `MiddlewareRegistry`
|
|
16
16
|
- Configuration/manifests: `ConfigProvider`, `ConfigLayer`, `ConfigLoadContext`, `PrismManifest`, `ManifestContributionDeclaration`, `ManifestResourceDeclaration`, `ManifestContributionKind`
|
|
17
17
|
- Stores/resources/settings/credentials/compaction/retry/cache helpers: `SessionEntry`, `SessionStore`, `StoreFactory`, `Resource`, `ResourceLoader`, `ResourceLoadContext`, `SettingsProvider`, `CredentialRequest`, `Credential`, `CredentialResolver`, `CompactionStrategy`, `CompactionContext`, `CompactionResult`, `CompactionOptions`, `CompactionMiddlewarePayload`, `CompactionEntryData`, `DefaultCompactionStrategyOptions`, `RetryPolicy`, `RetryContext`, `RetryDecision`, `RetryOptions`, `RetryMiddlewarePayload`, `DefaultRetryPolicyOptions`, `CacheUsageReport`, `sanitizeCacheKey`, `mapCacheRetention`, `applyCacheControl`, `cacheHitRate`, `cacheSavings`, `cacheUsageReport`
|
|
18
|
-
- Production persistence (adapter-facing): `ProductionPersistenceStore`, `PersistencePage`, `PersistenceQuery`, `OwnershipScope`, `SessionRecord`, `SessionQuery`, `BranchRecord`, `BranchQuery`, `SessionEntryQuery`, `RunRecord`, `RunQuery`, `AgentEventRecord`, `AgentEventQuery`, `ToolCallRecord`, `ToolCallQuery`, `UsageRecord`, `UsageQuery`, `AgentDefinitionRecord`, `AgentDefinitionQuery`, `RetentionPolicy`, `RetentionPolicyQuery`, `MigrationRecord`, `MigrationQuery`
|
|
18
|
+
- Production persistence (adapter-facing): `ProductionPersistenceStore`, `CheckpointStore`, `CheckpointKey`, `CheckpointSaveInput`, `CheckpointRecord`, `CheckpointQuery`, `LeaseStore`, `LeaseKey`, `LeaseAcquireInput`, `LeaseClaimInput`, `LeaseRecord`, `PersistencePage`, `PersistenceQuery`, `OwnershipScope`, `SessionRecord`, `SessionQuery`, `BranchRecord`, `BranchQuery`, `SessionEntryQuery`, `RunRecord`, `RunQuery`, `AgentEventRecord`, `AgentEventQuery`, `ToolCallRecord`, `ToolCallQuery`, `UsageRecord`, `UsageQuery`, `AgentDefinitionRecord`, `AgentDefinitionQuery`, `RetentionPolicy`, `RetentionPolicyQuery`, `MigrationRecord`, `MigrationQuery`
|
|
19
19
|
|
|
20
20
|
## When to use it
|
|
21
21
|
|
|
@@ -49,6 +49,8 @@ import type {
|
|
|
49
49
|
BranchRecord,
|
|
50
50
|
CommandDefinition,
|
|
51
51
|
CacheUsageReport,
|
|
52
|
+
CheckpointStore,
|
|
53
|
+
LeaseStore,
|
|
52
54
|
CompactionStrategy,
|
|
53
55
|
ConfigLayer,
|
|
54
56
|
ConfigProvider,
|
|
@@ -140,7 +142,10 @@ Important request shapes:
|
|
|
140
142
|
| `SystemPromptContribution` | Explicit caller-selected prompt layer with source, mode, text, and metadata. |
|
|
141
143
|
| `ConfigLayer` | Named JSON config layer consumed by `mergeConfigLayers()`. |
|
|
142
144
|
| `PrismManifest` | Data-only package manifest with config defaults, contribution declarations, and resource declarations. |
|
|
143
|
-
| `ProductionPersistenceStore` | Adapter-facing interface for durable, paginated, multi-tenant storage
|
|
145
|
+
| `ProductionPersistenceStore` | Adapter-facing interface for durable, paginated, multi-tenant storage plus optional `checkpoints?: CheckpointStore` and `leases?: LeaseStore`. No SQL/ORM/host file storage/network dependency. |
|
|
146
|
+
| `CheckpointStore` | Generic versioned checkpoint capability: save/load/bounded-list/delete by namespace and key, with ownership, exact-version CAS, and lease fencing. `createMemoryCheckpointStore()` is the reference implementation. |
|
|
147
|
+
| `LeaseStore` | Atomic acquire/renew/release/get by namespace and key, with opaque claim tokens, expiry, ownership scope, and monotonically increasing takeover fences. `createMemoryLeaseStore()` is the reference implementation. |
|
|
148
|
+
| `EventMultiplexer<T>` | Generic bounded fan-in from async sources. `createEventMultiplexer()` owns queue limits, overflow policy, abort, source teardown, and close behavior. |
|
|
144
149
|
| `PersistencePage<T>` | Cursor-paginated result page: `items`, optional `nextCursor`, optional `total`. |
|
|
145
150
|
| `PersistenceQuery` | Common pagination controls: `cursor?`, `limit?`, `order?: "asc" \| "desc"`. |
|
|
146
151
|
| `OwnershipScope` | Multi-tenant scope: `tenantId?`, `accountId?`, `userId?`. Included in records and queries. |
|
|
@@ -446,5 +451,7 @@ void credentials;
|
|
|
446
451
|
- [Provider conformance](provider-conformance.md): testing subpath for network-free provider adapter checks.
|
|
447
452
|
- [Credentials and redaction](credentials-and-redaction.md): helpers for resolving host-owned credentials, explicit resolver order, OAuth refresh, env-object lookup, and redacting known secret values.
|
|
448
453
|
- [OpenAI-compatible provider](providers/openai-compatible.md): optional provider adapter implementing `AIProvider`.
|
|
454
|
+
- `@arnilo/prism/providers/transport`: bounded SSE/event parsing, bounded HTTP error-body reads, and JSON-object tool-argument parsing for provider packages.
|
|
455
|
+
- `@arnilo/prism/providers/openai`: OpenAI Chat Completions message/tool serialization, usage mapping, and indexed message validation helpers.
|
|
449
456
|
|
|
450
457
|
Phase 10 public helpers include `createStaticSettingsProvider`, `createChainedSettingsProvider`, `createMemoryCredentialStore`, `createChainedCredentialResolver`, `createStaticTrustPolicy`, `assertTrusted`, `createStaticPermissionPolicy`, `assertPermission`, and `createSecretRedactor`. Phase 11 auth/request/prompt helpers include `createExplicitCredentialResolver`, `createEnvCredentialResolver`, `refreshOAuthCredential`, `createProviderRequestPolicyChain`, `createSessionCachePolicy`, `mergeProviderRequestOptions`, `composeSystemPrompt`, and `mergeSystemPromptConfig`; they do not read env vars, persist OAuth tokens, create cache stores, discover prompt files, or load packages unless the host supplies that behavior. `@arnilo/prism/testing/provider-conformance` exports network-free provider assertion helpers. Node subpaths `@arnilo/prism/node/settings` and `@arnilo/prism/node/trust` are explicit filesystem/path helpers.
|