@arnilo/prism 0.0.3 → 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 +22 -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 +41 -7
- 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 -12
- 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 -25
- 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 +39 -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 +33 -5
|
@@ -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.
|