@arnilo/prism 0.4.0 → 0.5.0

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.
Files changed (171) hide show
  1. package/CHANGELOG.md +33 -1
  2. package/README.md +23 -20
  3. package/dist/agent-run-state.d.ts +1 -2
  4. package/dist/agent-run-state.js +0 -3
  5. package/dist/agent-session/session/assemble.d.ts +6 -0
  6. package/dist/agent-session/session/assemble.js +391 -0
  7. package/dist/agent-session/session/persist.d.ts +28 -0
  8. package/dist/agent-session/session/persist.js +166 -0
  9. package/dist/agent-session/session/provider-round.d.ts +6 -0
  10. package/dist/agent-session/session/provider-round.js +231 -0
  11. package/dist/agent-session/session/tool-round.d.ts +31 -0
  12. package/dist/agent-session/session/tool-round.js +473 -0
  13. package/dist/agent-session/session/types.d.ts +115 -0
  14. package/dist/agent-session/session/types.js +5 -0
  15. package/dist/agent-session/session.d.ts +49 -43
  16. package/dist/agent-session/session.js +11 -1177
  17. package/dist/capture.d.ts +63 -0
  18. package/dist/capture.js +67 -0
  19. package/dist/cli-init.d.ts +18 -2
  20. package/dist/cli-init.js +2 -7
  21. package/dist/cli-runner.d.ts +2 -2
  22. package/dist/cli-runner.js +45 -9
  23. package/dist/content.d.ts +3 -3
  24. package/dist/content.js +3 -1
  25. package/dist/contracts-core/agent.d.ts +2 -0
  26. package/dist/contracts-core/batch.d.ts +97 -0
  27. package/dist/contracts-core/batch.js +65 -0
  28. package/dist/contracts-core/content.d.ts +72 -1
  29. package/dist/contracts-core/embeddings.d.ts +30 -0
  30. package/dist/contracts-core/embeddings.js +17 -0
  31. package/dist/contracts-core/images.d.ts +60 -0
  32. package/dist/contracts-core/images.js +17 -0
  33. package/dist/contracts-core/moderation.d.ts +46 -0
  34. package/dist/contracts-core/moderation.js +34 -0
  35. package/dist/contracts-core/speech.d.ts +39 -0
  36. package/dist/contracts-core/speech.js +17 -0
  37. package/dist/contracts-core/transcription.d.ts +48 -0
  38. package/dist/contracts-core/transcription.js +17 -0
  39. package/dist/contracts-core/video.d.ts +61 -0
  40. package/dist/contracts-core/video.js +17 -0
  41. package/dist/contracts-core.d.ts +7 -0
  42. package/dist/contracts-core.js +7 -0
  43. package/dist/index.d.ts +5 -3
  44. package/dist/index.js +4 -3
  45. package/dist/node/agent-definitions.d.ts +1 -8
  46. package/dist/node/agent-definitions.js +0 -34
  47. package/dist/node/settings.d.ts +0 -1
  48. package/dist/node/settings.js +0 -5
  49. package/dist/pinned-fetch.js +29 -3
  50. package/dist/provider-events.js +3 -4
  51. package/dist/providers/media.d.ts +1 -2
  52. package/dist/providers/media.js +1 -4
  53. package/dist/rpc.d.ts +1 -1
  54. package/dist/rpc.js +4 -4
  55. package/dist/testing/provider-conformance.d.ts +114 -5
  56. package/dist/testing/provider-conformance.js +342 -0
  57. package/dist/testing/tool-effect-store-conformance.d.ts +0 -1
  58. package/dist/testing/tool-effect-store-conformance.js +0 -3
  59. package/dist/thinking.d.ts +48 -9
  60. package/dist/thinking.js +134 -8
  61. package/docs/0.1.0-readiness.md +3 -3
  62. package/docs/a2a.md +2 -2
  63. package/docs/acp.md +3 -3
  64. package/docs/ag-ui-adoption.md +1 -1
  65. package/docs/ag-ui.md +1 -2
  66. package/docs/agent-definitions.md +1 -1
  67. package/docs/agent-events.md +5 -5
  68. package/docs/agent-identity.md +13 -2
  69. package/docs/audit-export.md +3 -3
  70. package/docs/batch-jobs.md +120 -0
  71. package/docs/cli-rpc.md +20 -9
  72. package/docs/coding-agent-tools.md +19 -19
  73. package/docs/coding-review-and-diagnostics.md +2 -2
  74. package/docs/coding-security.md +4 -4
  75. package/docs/coding-workspaces.md +2 -2
  76. package/docs/computer-use-linux.md +13 -2
  77. package/docs/context-and-skills.md +1 -1
  78. package/docs/conversations.md +4 -4
  79. package/docs/credential-storage.md +11 -7
  80. package/docs/credentials-and-redaction.md +1 -1
  81. package/docs/data-classification.md +1 -1
  82. package/docs/database-persistence.md +4 -4
  83. package/docs/dev-inspector.md +6 -6
  84. package/docs/device-adapters.md +2 -2
  85. package/docs/diagrams.md +1 -1
  86. package/docs/document-reader.md +6 -6
  87. package/docs/documents.md +5 -4
  88. package/docs/embeddings.md +112 -0
  89. package/docs/enterprise-postgres-state.md +7 -7
  90. package/docs/evaluations.md +8 -8
  91. package/docs/extensions.md +3 -3
  92. package/docs/forge-integration.md +3 -3
  93. package/docs/graft.md +2 -2
  94. package/docs/guardrails.md +1 -1
  95. package/docs/host-security.md +15 -15
  96. package/docs/image-generation.md +129 -0
  97. package/docs/impeccable.md +5 -3
  98. package/docs/index.md +60 -33
  99. package/docs/indexed-code-search.md +2 -2
  100. package/docs/language-intelligence.md +4 -4
  101. package/docs/live-testing.md +126 -0
  102. package/docs/mcp-tools.md +43 -12
  103. package/docs/middleware-hooks.md +1 -1
  104. package/docs/migrate-to-0.4.md +3 -3
  105. package/docs/migrate-to-0.5.md +122 -0
  106. package/docs/migration.md +29 -1
  107. package/docs/model-registry.md +38 -0
  108. package/docs/model-routing.md +5 -5
  109. package/docs/moderation.md +117 -0
  110. package/docs/multi-agent-patterns.md +4 -4
  111. package/docs/multimodal-content.md +26 -2
  112. package/docs/obscura.md +2 -2
  113. package/docs/observability.md +32 -7
  114. package/docs/openapi-tools.md +13 -3
  115. package/docs/operations.md +11 -0
  116. package/docs/performance.md +7 -7
  117. package/docs/persistence-credentials-multimodality-primitives.md +6 -6
  118. package/docs/policy-and-audit.md +17 -7
  119. package/docs/ponytail.md +1 -1
  120. package/docs/postgres-persistence.md +5 -5
  121. package/docs/process-sessions.md +2 -2
  122. package/docs/prompt-registry.md +7 -7
  123. package/docs/provider-caching.md +4 -0
  124. package/docs/provider-conformance.md +23 -1
  125. package/docs/provider-packages.md +39 -3
  126. package/docs/provider-primitives.md +1 -1
  127. package/docs/provider-request-policies.md +1 -1
  128. package/docs/providers/ai-sdk.md +15 -3
  129. package/docs/providers/alibaba.md +5 -1
  130. package/docs/providers/anthropic.md +4 -0
  131. package/docs/providers/azure.md +17 -1
  132. package/docs/providers/bedrock.md +15 -0
  133. package/docs/providers/clinepass.md +4 -0
  134. package/docs/providers/commandcode.md +253 -0
  135. package/docs/providers/deepseek.md +4 -0
  136. package/docs/providers/google.md +4 -0
  137. package/docs/providers/hyper.md +284 -0
  138. package/docs/providers/kimi.md +4 -0
  139. package/docs/providers/neuralwatt.md +4 -0
  140. package/docs/providers/ollama.md +15 -0
  141. package/docs/providers/openai-compatible.md +4 -0
  142. package/docs/providers/openai.md +4 -0
  143. package/docs/providers/opencode-go.md +4 -0
  144. package/docs/providers/openrouter.md +5 -1
  145. package/docs/providers/vertex.md +16 -0
  146. package/docs/providers/xai.md +4 -0
  147. package/docs/providers/zai.md +4 -0
  148. package/docs/rag.md +26 -4
  149. package/docs/release-and-install.md +103 -46
  150. package/docs/resource-loading.md +1 -1
  151. package/docs/runs-and-usage.md +14 -2
  152. package/docs/server.md +5 -5
  153. package/docs/settings-auth-trust-security.md +7 -5
  154. package/docs/sheets.md +2 -2
  155. package/docs/speech.md +126 -0
  156. package/docs/sqlite-persistence.md +4 -4
  157. package/docs/supervisors.md +3 -3
  158. package/docs/thinking-and-reasoning.md +93 -60
  159. package/docs/tool-conformance.md +1 -1
  160. package/docs/tool-execution-primitives.md +8 -8
  161. package/docs/tools.md +4 -4
  162. package/docs/web-tools.md +1 -1
  163. package/docs/wiki.md +1 -1
  164. package/docs/work-artifacts-and-review.md +17 -6
  165. package/docs/work-connectors.md +4 -4
  166. package/docs/work-tools.md +5 -5
  167. package/docs/workflow-orchestration-primitives.md +11 -11
  168. package/docs/workflows.md +5 -5
  169. package/package.json +11 -8
  170. package/templates/init/providers.json +24 -8
  171. package/docs/antigravity-agent.md +0 -207
package/docs/server.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- `@arnilo/prism-server` exposes explicitly selected agents and workflows through one framework-free `(Request) => Promise<Response>` handler. It supports direct agent results, bounded agent/workflow SSE, cross-replica durable agent-event reconnect, opt-in durable agent status/resume, durable workflow start/enqueue/status/cancel/resume/replay, ownership-scoped schedules, host authorization, ownership propagation, redaction, resource ceilings, and optional deployment seams (health/readiness, drain, host rate-limit adapter, ownership-scoped event replay, worker/coordinator lease election).
5
+ `@arnilo/prism-core/runtime/server` exposes explicitly selected agents and workflows through one framework-free `(Request) => Promise<Response>` handler. It supports direct agent results, bounded agent/workflow SSE, cross-replica durable agent-event reconnect, opt-in durable agent status/resume, durable workflow start/enqueue/status/cancel/resume/replay, ownership-scoped schedules, host authorization, ownership propagation, redaction, resource ceilings, and optional deployment seams (health/readiness, drain, host rate-limit adapter, ownership-scoped event replay, worker/coordinator lease election).
6
6
 
7
7
  No listener starts on import. Empty `agents`/`workflows` maps expose nothing. Authentication, authorization, route selection, durable stores, TLS, distributed rate limiting, queues, and framework/serverless adaptation remain host-owned.
8
8
 
@@ -82,7 +82,7 @@ Errors use `{ "error": { "code", "message" } }`. Unknown routes/capabilities are
82
82
 
83
83
  ```ts
84
84
  import { createAgent, createMockProvider, providerDone, providerTextDelta } from "@arnilo/prism";
85
- import { createPrismHandler } from "@arnilo/prism-server";
85
+ import { createPrismHandler } from "@arnilo/prism-core/runtime/server";
86
86
 
87
87
  const agent = createAgent({
88
88
  model: { provider: "mock", model: "offline" },
@@ -183,7 +183,7 @@ const valid = request.headers.get("x-prism-signature") === `sha256=${expected}`;
183
183
 
184
184
  ```ts
185
185
  import { createSecretRedactor, type AgentSession } from "@arnilo/prism";
186
- import { createWebhookNotifier } from "@arnilo/prism-server";
186
+ import { createWebhookNotifier } from "@arnilo/prism-core/runtime/server";
187
187
 
188
188
  const notifier = createWebhookNotifier({
189
189
  targets: [{ url: "https://ops.example.test/prism", events: ["run.failed", "workflow.suspended"] }],
@@ -228,7 +228,7 @@ Compose beside `createPrismHandler` — Prism starts no listener, container orch
228
228
  | `rateLimit` on handler | Host adapter after authorize, before session create. Return denial `{ retryAfterMs, code, message }` → `429` + optional `Retry-After`. `createMemoryRateLimiter` is single-process only. |
229
229
  | `createPrismAgentEventReplay` | Shared `AgentEventSource` page/follow semantics for exact-owned runs. |
230
230
  | `createPrismEventReplay` / `createPrismReplayHandler` | Compatible ownership-scoped legacy `queryEvents` pages (`redacted: true`). Does not re-run work. Unauthorized replay denies. |
231
- | `createPrismDeploymentLease` | Lease election under `prism.server.deployment`. Coordinator replica holds `key: "coordinator"` before schedule ticks; workers run `@arnilo/prism-workflows` `createWorkflowCoordinator` for queued runs (fencing tokens). |
231
+ | `createPrismDeploymentLease` | Lease election under `prism.server.deployment`. Coordinator replica holds `key: "coordinator"` before schedule ticks; workers run `@arnilo/prism-core/runtime/workflows` `createWorkflowCoordinator` for queued runs (fencing tokens). |
232
232
  | `createConversationService` / `createConversationHandler` | Durable user-scoped conversation threads (create/list/continue/branch/archive/export/delete) over session + event-ledger seams, with thread-bound reconnectable replay. Mounts beside the handler; see [Conversations](conversations.md). |
233
233
  | `createArtifactService` / `createArtifactHandler` | Durable artifact co-work review (attach/revise/compare/approve/reject/last-validated/delivery-link + authorized download) over the versioned checkpoint store; records persist metadata/revisions/approvals only, never file bodies. Mounts beside the handler; see [Work artifacts and review](work-artifacts-and-review.md). |
234
234
 
@@ -251,7 +251,7 @@ Network-free demo: [`examples/server-deployment-seams.ts`](../examples/server-de
251
251
  - Schedule routes never accept ownership from JSON. Services carry mandatory ownership and explicit workflow/calculator registries; route authorization cannot broaden either. Replay applies workflow ownership/hash/approval checks.
252
252
  - Agent status/resume routes exist only for keys in `agentRuns`. Supply one core `createAgentRunLifecycle({ checkpoints, resolveAgent })` capability per selected agent; its resolver returns current `{ agent, definitionRevision }`. It reuses core checkpoint parsing/CAS/fingerprint checks, returns only public state/version, and needs a durable `SessionStore` as well as checkpoints for restart-safe resume. Empty/default configuration adds no agent lifecycle route, polling, or server cache.
253
253
 
254
- A2A routes are not added to `createPrismHandler()`. Install `@arnilo/prism-supervisor` and explicitly mount `createA2AHandler()` when protocol interoperability is required; this keeps cards and remote invoke absent from ordinary Prism servers.
254
+ A2A routes are not added to `createPrismHandler()`. Install `@arnilo/prism-core/runtime/supervisor` and explicitly mount `createA2AHandler()` when protocol interoperability is required; this keeps cards and remote invoke absent from ordinary Prism servers.
255
255
 
256
256
  ## Related APIs
257
257
 
@@ -34,11 +34,13 @@ console.log(await settings.get("demo.enabled"));
34
34
  ## Implementation example
35
35
  ```ts
36
36
  import { createAgent, createMemoryCredentialStore, createSecretRedactor, resolveCredentialValue } from "@arnilo/prism";
37
- import { loadSettingsFiles, defaultUserSettingsPath } from "@arnilo/prism/node/settings";
37
+ import { loadSettingsFiles } from "@arnilo/prism/node/settings";
38
38
  import { createPathTrustPolicy } from "@arnilo/prism/node/trust";
39
+ import { homedir } from "node:os";
40
+ import { join } from "node:path";
39
41
 
40
42
  const settings = await loadSettingsFiles([
41
- { name: "user", path: defaultUserSettingsPath(), optional: true },
43
+ { name: "user", path: join(homedir(), ".config", "prism", "settings.json"), optional: true },
42
44
  ]);
43
45
  const credentials = createMemoryCredentialStore();
44
46
  credentials.set({ name: "api", provider: "demo", credential: { type: "api_key", value: "token-value" } });
@@ -57,7 +59,7 @@ void agent;
57
59
  ```
58
60
 
59
61
  ## Extension and configuration notes
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. For Node.js hosts, [`@arnilo/prism-credentials-node`](credential-storage.md) provides encrypted-file and system-keychain backends. Pass concrete settings values or credential resolvers to the provider/request edge that needs them; do not place them on `AgentConfig`.
62
+ 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. For Node.js hosts, [`@arnilo/prism-core/credentials/node`](credential-storage.md) provides encrypted-file and system-keychain backends. Pass concrete settings values or credential resolvers to the provider/request edge that needs them; do not place them on `AgentConfig`.
61
63
 
62
64
  ## Security and performance notes
63
65
  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.
@@ -81,8 +83,8 @@ Boundary hardening summary:
81
83
  - `createMemoryCredentialStore`, `createChainedCredentialResolver`, `createExplicitCredentialResolver`, `createEnvCredentialResolver`, `refreshOAuthCredential`, `resolveCredentialValue`
82
84
  - `createStaticTrustPolicy`, `assertTrusted`, `isTrusted`, `TrustDeniedError`
83
85
  - `createStaticPermissionPolicy`, `assertPermission`, `checkPermission`, `PermissionDeniedError`
84
- - `ExecutionPolicy`, `assertExecutionAllowed`, `checkExecution`, `ExecutionDeniedError` (core); `@arnilo/prism-coding-security` for coding-tool approval adapters — see [Coding execution approval and sandboxing](coding-security.md)
86
+ - `ExecutionPolicy`, `assertExecutionAllowed`, `checkExecution`, `ExecutionDeniedError` (core); `@arnilo/prism-coding-tools/security` for coding-tool approval adapters — see [Coding execution approval and sandboxing](coding-security.md)
85
87
  - `createSecretRedactor`, `redactMessage`, `redactAgentEvent`, `redactSessionEntry`, `redactProviderRequest`
86
- - `@arnilo/prism/node/settings`: `defaultUserSettingsPath`, `readSettingsFile`, `loadSettingsFiles`
88
+ - `@arnilo/prism/node/settings`: `readSettingsFile`, `loadSettingsFiles` (`defaultUserSettingsPath` was removed in 0.5.0 — build the path with `node:os`/`node:path`)
87
89
  - `@arnilo/prism/node/trust`: `createPathTrustPolicy`, `isPathInside`, `isPathInsideReal`
88
90
  - [Contribution discovery (workspace)](contribution-discovery.md): `createPathTrustPolicy` + `isPathInsideReal` gate workspace contribution roots fail-closed.
package/docs/sheets.md CHANGED
@@ -225,5 +225,5 @@ const telemetry: SheetsTelemetry = {
225
225
  ## Related APIs
226
226
 
227
227
  - [`@arnilo/prism-office/documents`](./documents.md): Specification-compliant OpenXML document generation, parsing, patching, and preview rendering for DOCX, XLSX, and PPTX.
228
- - [`@arnilo/prism-document-reader`](./document-reader.md): Bounded literal text extraction from PDF and DOCX documents for coding agent tools.
229
- - [`@arnilo/prism-observability-opentelemetry`](./observability.md): OpenTelemetry instrumentation and trace adapters.
228
+ - [`@arnilo/prism-coding-tools/document-reader`](./document-reader.md): Bounded literal text extraction from PDF and DOCX documents for coding agent tools.
229
+ - [`@arnilo/prism-core/governance/observability`](./observability.md): OpenTelemetry instrumentation and trace adapters.
package/docs/speech.md ADDED
@@ -0,0 +1,126 @@
1
+ # Speech synthesis and transcription
2
+
3
+ ## What it does
4
+
5
+ `SpeechProvider` is the provider-neutral speech contract: text→audio via
6
+ `synthesize` (full bytes) and `synthesizeStream` (first chunk as soon as the
7
+ provider responds). `TranscriptionProvider` is audio→text via `transcribe`
8
+ (one-shot) and `transcribeStream` (partial `TranscriptDelta` events, then one
9
+ `done`), sharing the Realtime `transcript_delta` event naming. Adapters ship in
10
+ [`@arnilo/prism-providers/openai`](providers/openai.md) (`/v1/audio/speech`,
11
+ `/v1/audio/transcriptions`); offline conformance runs via `runSpeechConformance`
12
+ and `runTranscriptionConformance` from `@arnilo/prism/testing/provider-conformance`.
13
+
14
+ ## When to use it
15
+
16
+ Use it for one-shot voice output and batch/stream transcription where the host
17
+ owns playback, capture, and audio storage. Do not use it for interactive
18
+ bidirectional voice — that is the Realtime session contract
19
+ ([`RealtimeSession`](public-contracts.md)), which keeps its own
20
+ `audio_delta`/`transcript_delta` events. Streaming here is one-directional:
21
+ synthesis streams audio out, transcription streams text in.
22
+
23
+ ## Inputs / request
24
+
25
+ | Field | Type | Meaning |
26
+ | --- | --- | --- |
27
+ | `model` | `string` | Speech model (`tts-1`, `gpt-4o-mini-tts`) or transcription model (`whisper-1`, `gpt-4o-transcribe`). |
28
+ | `input` | `string` (speech) | Text to speak; non-empty, within the provider input cap (OpenAI: 4,096 chars). |
29
+ | `audio` | `Uint8Array` (transcription) | Audio bytes; non-empty, within the provider cap (OpenAI: 25 MiB). |
30
+ | `voice` / `format` / `speed` | `string?` / `string?` / `number?` (speech) | Voice id, audio container (`mp3`, `wav`, `opus`), playback speed. Adapter defaults when omitted. |
31
+ | `format` / `language` / `prompt` | `string?` | Audio container hint (maps to the upload filename), ISO-639-1 hint, spelling hint. |
32
+ | `signal` | `AbortSignal?` | Cancellation; observed by the adapter transport. |
33
+
34
+ Adapter options: `apiKey` (`CredentialValueSource` — the existing credential
35
+ seam, resolved per call and redacted from errors), `baseUrl`, `fetch` (inject a
36
+ fake transport for offline tests), `headers`, provider defaults
37
+ (`voice`/`format`), and `maxAudioBytes` (response ceiling for synthesis,
38
+ input ceiling for transcription).
39
+
40
+ ## Outputs / response / events
41
+
42
+ | Field | Type | Meaning |
43
+ | --- | --- | --- |
44
+ | `audio` | `Uint8Array` / `ReadableStream<Uint8Array>` | Full synthesized bytes, or chunks in order — the first chunk is available as soon as the provider responds. |
45
+ | `format` | `string` | Actual audio container (request value or provider default). |
46
+ | `text` | `string` | Transcript; `TranscriptDone.text` is the final full text. |
47
+ | `usage` | `Usage?` | Transcription token usage (streaming `done` reports it; one-shot when the provider includes it). |
48
+
49
+ Streaming transcription yields `TranscriptDelta` (`{ type: "transcript_delta",
50
+ text }`, naming aligned with `RealtimeEvent.transcript_delta` — no `role`) then
51
+ exactly one `TranscriptDone`.
52
+
53
+ Failures throw `SpeechError` / `TranscriptionError` with a stable `code`:
54
+ `empty_input` (no text / no audio), `input_too_large` (speech text over the
55
+ provider cap), `audio_too_large` (transcription audio over the cap),
56
+ `request_failed` (non-2xx or stream error, secret-redacted message),
57
+ `response_malformed` (missing text, over-ceiling audio bytes),
58
+ `unsupported_model` (via `assertSpeechSupported` / `assertTranscriptionSupported`
59
+ when the host checks `ModelCapabilities.speech` / `transcription`).
60
+
61
+ ## Request/response example
62
+
63
+ ```json
64
+ { "model": "tts-1", "input": "hello", "voice": "alloy", "response_format": "mp3" }
65
+ ```
66
+
67
+ ## Implementation example
68
+
69
+ ```ts
70
+ import { createOpenAISpeechProvider, createOpenAITranscriptionProvider } from "@arnilo/prism-providers/openai";
71
+ import { runSpeechConformance, runTranscriptionConformance } from "@arnilo/prism/testing/provider-conformance";
72
+
73
+ const speech = createOpenAISpeechProvider({ apiKey: process.env.OPENAI_API_KEY });
74
+ const { audio } = await speech.synthesize({ model: "tts-1", input: "hi", voice: "alloy" });
75
+ const streamed = await speech.synthesizeStream({ model: "tts-1", input: "hi" });
76
+ // streamed.audio is a ReadableStream<Uint8Array>; first chunk resolves at first response bytes
77
+
78
+ const transcription = createOpenAITranscriptionProvider({ apiKey: process.env.OPENAI_API_KEY });
79
+ const { text } = await transcription.transcribe({ model: "whisper-1", audio, format: "mp3" });
80
+ for await (const event of transcription.transcribeStream({ model: "whisper-1", audio })) {
81
+ if (event.type === "transcript_delta") process.stdout.write(event.text);
82
+ }
83
+
84
+ // Offline conformance (fake transport, no network):
85
+ await runSpeechConformance({
86
+ provider: createOpenAISpeechProvider({ apiKey: "sk-test", fetch: fakeFetch }),
87
+ model: "tts-1",
88
+ maxInputChars: 4096,
89
+ sample: { input: "hi", voice: "alloy" },
90
+ });
91
+ ```
92
+
93
+ ## Extension and configuration notes
94
+
95
+ - Implement `SpeechProvider` / `TranscriptionProvider` for other vendors; the
96
+ contracts are structural — no base class, no registry.
97
+ - Models declare support with `capabilities.speech` / `capabilities.transcription`;
98
+ hosts gate with the `modelSupports*` / `assert*Supported` guards, mirroring the
99
+ structured-output and embeddings guard pattern.
100
+ - `synthesizeStream` returns a Web `ReadableStream` and `transcribeStream` an
101
+ `AsyncIterable` — the repo's streaming conventions; no Node-only stream types.
102
+ - Adapters never truncate: over-cap inputs and responses reject with typed
103
+ errors, so callers own splitting long text or large audio.
104
+
105
+ ## Security and performance notes
106
+
107
+ - API keys resolve through the existing `CredentialValueSource` seam and are
108
+ redacted from every thrown error (`redactSecrets`); no new secret paths.
109
+ - Synthesized audio is consumed under a byte ceiling
110
+ (`DEFAULT_SPEECH_MAX_AUDIO_BYTES`, 25 MiB; `maxAudioBytes` override) — the
111
+ stream errors instead of buffering without bound; transcription input is
112
+ capped before any network I/O.
113
+ - Audio content and transcript text are never logged; error messages carry
114
+ status and a redacted body only.
115
+ - One HTTP request per call; streaming paths forward provider chunks as they
116
+ arrive (first byte at provider RTT, no full-response buffering).
117
+
118
+ ## Related APIs
119
+
120
+ - [Realtime sessions](public-contracts.md): `RealtimeSession` for interactive
121
+ bidirectional voice; `RealtimeEvent.transcript_delta` is this contract's
122
+ naming anchor.
123
+ - [Provider conformance](provider-conformance.md): `runSpeechConformance` /
124
+ `runTranscriptionConformance` and the offline conformance matrix.
125
+ - [Provider packages](provider-packages.md): subpath import rules for
126
+ `@arnilo/prism-providers/openai`.
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- The optional `@arnilo/prism-session-store-sqlite` package ships a production-oriented SQLite adapter that implements:
5
+ The optional `@arnilo/prism-core/sessions/sqlite` package ships a production-oriented SQLite adapter that implements:
6
6
 
7
7
  - `SessionStore` — atomic `append` / `list` / `get` / `readBranchPath` / bounded `searchSessions` / bounded `searchSessions`
8
8
  - `RunLedger` — durable run, event, tool-call, and usage rows
@@ -24,12 +24,12 @@ Use this package when you want a small, file-backed persistence layer on Node wi
24
24
  - single-writer or low-concurrency deployments
25
25
  - integration tests that need durable reopen semantics
26
26
 
27
- Do **not** use it as a substitute for PostgreSQL when you need heavy multi-writer concurrency, server-side pooling, or managed TLS. See [`@arnilo/prism-session-store-postgres`](postgres-persistence.md) for that path.
27
+ Do **not** use it as a substitute for PostgreSQL when you need heavy multi-writer concurrency, server-side pooling, or managed TLS. See [`@arnilo/prism-core/sessions/postgres`](postgres-persistence.md) for that path.
28
28
 
29
29
  ## Inputs / request
30
30
 
31
31
  ```ts
32
- import { createSqlitePersistence } from "@arnilo/prism-session-store-sqlite";
32
+ import { createSqlitePersistence } from "@arnilo/prism-core/sessions/sqlite";
33
33
  ```
34
34
 
35
35
  | Field | Type | Purpose |
@@ -73,7 +73,7 @@ Migrations run automatically on open and are idempotent across reopen. Under the
73
73
 
74
74
  ```ts
75
75
  import { createAgentSession } from "@arnilo/prism";
76
- import { createSqlitePersistence } from "@arnilo/prism-session-store-sqlite";
76
+ import { createSqlitePersistence } from "@arnilo/prism-core/sessions/sqlite";
77
77
  import { runSessionStoreConformance } from "@arnilo/prism/testing/session-store-conformance";
78
78
 
79
79
  const persistence = createSqlitePersistence({ filename: "./prism.db" });
@@ -2,11 +2,11 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- `@arnilo/prism-supervisor` adds optional runtime-selected delegation to an explicit local child allow-list. It returns normal `AgentRunResult` values and does not modify core `createAgent()` or deterministic workflows.
5
+ `@arnilo/prism-core/runtime/supervisor` adds optional runtime-selected delegation to an explicit local child allow-list. It returns normal `AgentRunResult` values and does not modify core `createAgent()` or deterministic workflows.
6
6
 
7
7
  ## When to use it
8
8
 
9
- Use a supervisor when a host or agent must choose a child dynamically. Use `@arnilo/prism-workflows` for known DAGs, durable checkpoints, schedules, replay, or human suspension.
9
+ Use a supervisor when a host or agent must choose a child dynamically. Use `@arnilo/prism-core/runtime/workflows` for known DAGs, durable checkpoints, schedules, replay, or human suspension.
10
10
 
11
11
  ## Inputs / request
12
12
 
@@ -36,7 +36,7 @@ Use a supervisor when a host or agent must choose a child dynamically. Use `@arn
36
36
  ## Implementation example
37
37
 
38
38
  ```ts
39
- import { createSupervisor } from "@arnilo/prism-supervisor";
39
+ import { createSupervisor } from "@arnilo/prism-core/runtime/supervisor";
40
40
 
41
41
  const supervisor = createSupervisor({
42
42
  ownership: { tenantId: "tenant", userId: "user" },
@@ -2,100 +2,133 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- Prism keeps thinking/reasoning **provider-owned on the wire** while giving hosts one portable way to set effort per turn. Model defaults live on `ModelConfig.compat` (and `capabilities.reasoning` where declared). Per-turn overrides live on `ProviderRequestOptions.compat` and win through existing `mergeProviderRequestOptions`. Shared helpers map a portable `ThinkingLevel` into the official compat fields each family already reads — they do **not** invent a second options tree.
5
+ Prism gives hosts one portable way to set thinking/reasoning effort per model and per turn, and guarantees the level actually reaches the wire on every provider Prism ships. The single entry point is **`applyThinkingLevelForModel`**: it resolves the model's compat family, snaps the requested level to the model's **declared levels** (`capabilities.thinkingLevels`), and merges the family's compat patch into your base options. Every first-party provider catalog stamps the family and declares the per-model level set; provider resolvers translate the patch into official wire fields. Model defaults live on `ModelConfig.compat`; per-turn overrides live on `ProviderRequestOptions.compat` and win through the existing `mergeProviderRequestOptions` merge.
6
6
 
7
7
  ## When to use it
8
8
 
9
- - Session runs: pass `providerOptions.compat` (or `applyThinkingLevel`) on `RunOptions`.
10
- - Use-case workers (LLM compaction, observational memory): pass `thinkingLevel`; packages map it into `compat` via the shared helpers.
11
- - Provider authors: keep reading official fields from `options.compat` / `model.compat`; add package-local escape hatches only when the official API has unique knobs.
9
+ - Session runs: pass `providerOptions` from `applyThinkingLevelForModel` on `RunOptions` — one call, no per-provider branching.
10
+ - Use-case workers (LLM compaction, observational memory): pass `thinkingLevel`; workers call `applyThinkingLevelForModel` with the bound model.
11
+ - Hosts building UI: read `model.capabilities.thinkingLevels` (when declared) to render a legal level picker; `isSupportedThinkingLevel` tells you whether a value is declared before sending.
12
+ - Provider authors: read official wire fields from the compat patches below; keep unique knobs package-local.
12
13
 
13
- ## Contract
14
+ ## Inputs / request
14
15
 
15
- | Layer | Surface |
16
- | --- | --- |
17
- | Model default | `ModelConfig.compat` (+ `capabilities.reasoning` when the model can reason) |
18
- | Per-turn override | `ProviderRequestOptions.compat` (request wins over model via merge) |
19
- | Portable level | `ThinkingLevel`: `none` \| `minimal` \| `low` \| `medium` \| `high` \| `xhigh` \| `max` |
20
- | Helpers | `thinkingCompatFor`, `applyThinkingLevel`, `thinkingFamilyForModel`, `isThinkingLevel`, `normalizeThinkingLevel`, `THINKING_LEVELS` |
21
- | Not used | Inert `options.extra.thinkingLevel` — providers do not read `extra` for effort |
16
+ | Input | Type | Notes |
17
+ | --- | --- | --- |
18
+ | `base` | `ProviderRequestOptions \| undefined` | Existing options; the patch is merged on top |
19
+ | `level` | `string \| undefined` | Portable `ThinkingLevel` (`none` \| `minimal` \| `low` \| `medium` \| `high` \| `xhigh` \| `max`) or an opaque provider-specific string (forward-compat passthrough) |
20
+ | `model` | `Pick<ModelConfig, "provider" \| "compat" \| "capabilities">` | Model view used for family resolution, declared levels, and reasoning gating |
22
21
 
23
- ```ts
24
- import { applyThinkingLevel, thinkingCompatFor, thinkingFamilyForModel } from "@arnilo/prism";
22
+ ## Outputs / response / events
25
23
 
26
- // Per-turn override on a session run (OpenAI / OpenRouter family)
27
- await session.run(input, {
28
- providerOptions: applyThinkingLevel(undefined, "low", "openai_reasoning"),
29
- });
24
+ Returns the merged `ProviderRequestOptions` (a new object when a patch applies; `base` unchanged when there is nothing to do — non-reasoning model, `noop` family, or `level` undefined).
25
+
26
+ ## Request/response example
27
+
28
+ ```json
29
+ { "compat": { "reasoning_effort": "high" } }
30
+ ```
31
+
32
+ ## Implementation example
33
+
34
+ ```ts
35
+ import { applyThinkingLevelForModel } from "@arnilo/prism";
30
36
 
31
- // Equivalent explicit compat
37
+ // Per-turn override on a session run
32
38
  await session.run(input, {
33
- providerOptions: { compat: thinkingCompatFor("openai_reasoning", "low") },
34
- // → { reasoning: { effort: "low" } }
39
+ providerOptions: applyThinkingLevelForModel(base, "high", model),
35
40
  });
36
41
 
37
- // Use-case worker: family from model metadata (or pass an explicit family)
38
- const family = thinkingFamilyForModel(model);
39
- await runObserver({
40
- ...,
41
- providerOptions: applyThinkingLevel(base, "low", family === "noop" ? "reasoning_effort" : family),
42
- });
42
+ // Declared-level-aware UI
43
+ const levels = model.capabilities?.thinkingLevels; // e.g. ["low","medium","high","xhigh","max"]
43
44
  ```
44
45
 
46
+ ## Contract
47
+
48
+ | Layer | Surface |
49
+ | --- | --- |
50
+ | Adapter (use this) | `applyThinkingLevelForModel(base, level, model)` — family resolution + snap + merge in one call |
51
+ | Model default | `ModelConfig.compat` (+ `capabilities.reasoning`, `capabilities.thinkingLevels` when declared) |
52
+ | Per-turn override | `ProviderRequestOptions.compat` (request wins over model via merge) |
53
+ | Portable level | `ThinkingLevel`: `none` \| `minimal` \| `low` \| `medium` \| `high` \| `xhigh` \| `max` |
54
+ | Parse / validate | `parseThinkingLevel` (known level → canonical; other non-empty string → opaque passthrough; empty/non-string → `undefined`), `isSupportedThinkingLevel(model, level)`, `thinkingLevelsForModel(model)`, `snapThinkingLevel(model, level)` |
55
+ | Legacy helpers | `thinkingCompatFor`, `applyThinkingLevel`, `thinkingFamilyForModel`, `isThinkingLevel`, `normalizeThinkingLevel`, `THINKING_LEVELS` (still exported; prefer the adapter) |
56
+ | Not used | Inert `options.extra.thinkingLevel` — providers do not read `extra` for effort |
57
+
45
58
  ## Compat families
46
59
 
47
- Core maps only shapes shared by ≥2 packages (or an explicit no-op). Unique knobs stay package-local.
60
+ Core maps only shapes shared by ≥2 packages (or an explicit no-op). Unique knobs stay package-local. Family inference is **stamp-first**: `compat.thinkingFamily` set by the catalog wins, then compat-shape heuristics, then provider-id heuristics, then `capabilities.reasoning`.
48
61
 
49
- | Family | Compat patch | Used by (official fields) |
62
+ | Family | Compat patch | Used by (official wire fields) |
50
63
  | --- | --- | --- |
51
64
  | `openai_reasoning` | `{ reasoning: { effort } }` | OpenAI Responses `reasoning.effort`; OpenRouter `reasoning.effort` |
52
- | `reasoning_effort` | `{ reasoning_effort }` | Z.AI `reasoning_effort`; NeuralWatt `reasoning_effort`; Kimi K3 `reasoning_effort`; DeepSeek `reasoning_effort`; ClinePass `reasoning_effort` |
53
- | `thinking_type` | `{ thinking: { type: "enabled" \| "disabled" } }` | Z.AI `thinking.type`; Kimi K2.x `thinking.type` (`none` → `disabled`); DeepSeek `thinking.type` |
65
+ | `reasoning_effort` | `{ reasoning_effort }` | Z.AI, NeuralWatt, Kimi K3, DeepSeek, xAI, ClinePass, Hyper, Ollama, gateways (OpenAI routes) |
66
+ | `thinking_type` | `{ thinking: { type: "enabled" \| "disabled" } }` | Z.AI `thinking.type`; Kimi K2.x; DeepSeek toggle; Qwen `enable_thinking` (via `alibabaEnableThinking`) |
67
+ | `google` | `{ thinkingLevel }` | Google `generationConfig.thinkingConfig.thinkingLevel` (3.x) / `thinkingBudget` (2.5) |
68
+ | `output_config_effort` | `{ output_config: { effort } }` | Anthropic Messages `output_config.effort`; DeepSeek anthropic-format endpoint |
54
69
  | `noop` | `{}` | AI SDK / host-owned adapters — effort is host-model settings |
55
70
 
56
- `applyThinkingLevel` defaults `family` to `reasoning_effort` when omitted. For `openai_reasoning`, an existing `compat.reasoning.summary` (or other reasoning keys) is preserved when merging `effort`.
71
+ **Removed guidance:** do not use the `thinking_type` family to carry effort on Anthropic-routed providers — `thinking.type` is a toggle, and `enabled` without `budget_tokens` is rejected by current Anthropic APIs. Anthropic effort travels in `output_config.effort` (`output_config_effort` family).
57
72
 
58
- ### Recommended family by first-party package
73
+ ### First-party packages
59
74
 
60
- | Package | Recommended family | Notes |
61
- | --- | --- | --- |
62
- | `@arnilo/prism-providers/openai` | `openai_reasoning` | First-class body `reasoning` from model + per-turn compat merge; `summary`/`mode`/`context` via compat |
63
- | `@arnilo/prism-providers/openrouter` | `openai_reasoning` | First-class `resolveOpenRouterReasoning` merge; prefer `reasoning` object over legacy `reasoning_effort` shorthand; `preserveThinking` replays as body `reasoning` |
64
- | `@arnilo/prism-providers/zai` | `reasoning_effort` (+ optional `thinking_type`) | Official `thinking` / `reasoning_effort` / `tool_stream` / `clear_thinking`; Preserved Thinking via `reasoning_content` |
65
- | `@arnilo/prism-providers/neuralwatt` | `reasoning_effort` | Budgets / `preserve_thinking` / `clear_thinking` / `chat_template_kwargs` stay package-local on `compat` |
66
- | `@arnilo/prism-providers/kimi` | K3: `reasoning_effort`; K2.x: `thinking_type` | K2.7-code thinking is always on; do not send conflicting `thinking` + `reasoning_effort` |
67
- | `@arnilo/prism-providers/opencode-go` | Anthropic route: thinking blocks (`thinking_type` family); OpenAI route: `reasoning_content` preserve + optional `thinking`/`reasoning_effort`/`reasoning` passthrough | Official dual endpoints; MiniMax/Qwen → Anthropic, others → OpenAI |
68
- | `@arnilo/prism-providers/ai-sdk` | `noop` | Host `LanguageModelV4` owns reasoning settings |
69
- | `@arnilo/prism-providers/deepseek` | `thinking_type` + `reasoning_effort` | Thinking on by default (`high`). `cacheRetention: "none"` or `thinking: false` disables. Tool turns must replay `reasoning_content` or the API returns 400. |
70
- | `@arnilo/prism-providers/xai` | replay only | Featured Completions do not send `reasoning_effort`. Reasoning models must replay `reasoning_content` or the prefix cache breaks. Do not flatten thinking into text. |
71
- | `@arnilo/prism-providers/clinepass` | `reasoning_effort` | Per-model `compat.thinkingLevelMap`. GLM `xhigh` passthrough (never send `max`). K3 `high` → `max`. Unsupported slots omit the field. |
75
+ | Package | Family / behavior |
76
+ | --- | --- |
77
+ | `@arnilo/prism-providers/openai` | `openai_reasoning`; per-family effort tables, Responses-side clamp, `summary` preserved |
78
+ | `@arnilo/prism-providers/openrouter` | `openai_reasoning`; API-derived `supported_efforts` levels; `preserveThinking` replays as body `reasoning` / `reasoning_content` |
79
+ | `@arnilo/prism-providers/anthropic` | `output_config_effort`; generation-aware `adaptive`/legacy thinking |
80
+ | `@arnilo/prism-providers/google` | `google`; 3.x `thinkingLevel` sets, 2.5 budget ranges |
81
+ | `@arnilo/prism-providers/zai` | `reasoning_effort` (GLM-5.2/5.3 snap tables) + `thinking_type` toggle; Preserved Thinking via `reasoning_content` |
82
+ | `@arnilo/prism-providers/kimi` | K3: `reasoning_effort` (`low/high/max`); K2.x: `thinking_type` |
83
+ | `@arnilo/prism-providers/deepseek` | `reasoning_effort` (`low/high/max`) + `thinking_type` toggle; thinking on by default; tool turns must replay `reasoning_content` or the API returns 400 |
84
+ | `@arnilo/prism-providers/xai` | `reasoning_effort` with declared per-model ladders; `reasoning_content` replay still required |
85
+ | `@arnilo/prism-providers/clinepass` | `reasoning_effort` through per-model slot maps (`compat.thinkingLevelMap`); GLM `xhigh` passthrough, never `max` |
86
+ | `@arnilo/prism-providers/neuralwatt` | `reasoning_effort` (`low/medium/high/max`); budgets + preserve/clear thinking stay package-local |
87
+ | `@arnilo/prism-providers/hyper` | `reasoning_effort` derived from live `effort_levels`; snap instead of drop; Anthropic route emits `output_config.effort` |
88
+ | `@arnilo/prism-providers/commandcode` / `@arnilo/prism-providers/opencode-go` | Gateway level tables (`claude-*` → `output_config_effort`, `gpt-5.6*` → `openai_reasoning`, K3/DeepSeek/GLM → `reasoning_effort`, K2.x/MiniMax/Qwen → `thinking_type`) |
89
+ | `@arnilo/prism-providers/alibaba` | `thinking_type` mapped onto Qwen `enable_thinking` (toggle, no effort levels) |
90
+ | `@arnilo/prism-providers/ollama` | `reasoning_effort`; `gpt-oss*` declares `low/medium/high`; native `think` field never mixed in |
91
+ | `@arnilo/prism-providers/azure` / `.../vertex` / `.../bedrock` | OpenAI-compat sanitized forwarder (`reasoning_effort` / `reasoning` object), snapped to declared levels |
92
+ | `@arnilo/prism-providers/ai-sdk` | `noop` — host `LanguageModelV4` owns reasoning settings |
93
+
94
+ ## Declared levels and snapping
72
95
 
73
- `thinkingFamilyForModel` infers family from existing `compat` shape, then safe provider heuristics (`openai*` → `openai_reasoning`, `neuralwatt` → `reasoning_effort`), then `capabilities.reasoning` → `reasoning_effort`, else `noop`. Docs and packages may map other provider ids explicitly; core avoids provider-specific literals beyond those heuristics.
96
+ Every reasoning-capable model in a first-party catalog declares its legal level set (`capabilities.thinkingLevels`) and, where meaningful, a `compat.thinkingFamily` stamp. The source of truth is the [thinking coverage evidence matrix](_evidence/thinking-coverage-2026-09-05.md) — generated from the compiled catalogs, with per-model source (API-derived vs doc-pinned) and the wire/live test that pins each row.
74
97
 
75
- ## Merge order
98
+ Snap semantics (`snapThinkingLevel`, applied by the adapter and by provider resolvers when the model declares a set):
76
99
 
77
- 1. `ModelConfig.compat` / model defaults inside the provider
78
- 2. `ProviderRequestOptions.compat` from agent / session policies
79
- 3. Per-turn `RunOptions.providerOptions` or use-case `applyThinkingLevel` patch (wins)
100
+ 1. The requested level is in the declared set → forwarded unchanged.
101
+ 2. Below the declared minimum (typically `none`/`minimal` on a set without them) → snaps **up** to the minimum.
102
+ 3. Otherwise → nearest declared level by ladder distance, **ties breaking up**.
103
+ 4. Provider-documented tables (DeepSeek, Z.AI GLM-5.2/5.3, ClinePass slot maps, Kimi K3) are wire authority and take precedence over the generic rule.
104
+ 5. Undeclared levels (opaque strings) on a reasoning-capable model → passthrough (forward compat); a non-reasoning model → options unchanged.
80
105
 
81
- Providers already prefer `request.options.compat.*` over `request.model.compat.*`.
106
+ OpenRouter and Hyper derive their sets from each provider's models API (`supported_efforts` / `effort_levels`); all other catalogs are doc-pinned because those upstreams expose no enumeration API.
82
107
 
83
- ## Use-case workers
108
+ ## Extension and configuration notes
84
109
 
85
- LLM compaction and observational memory accept `thinkingLevel?: string`. They call `applyThinkingLevel` into `compat` (not `extra.thinkingLevel`). When model inference returns `noop`, an explicit `thinkingLevel` still falls back to `reasoning_effort` so the host setting is never inert. Model selection for those workers (including session-model fallback) is documented in [Use-case model selection](use-case-model-selection.md).
110
+ - `thinkingFamilyForModel(model)` resolves a family without applying it; hosts that build their own options can use `thinkingCompatFor(family, level)` directly. `compat.thinkingFamily` on a model or request overrides all heuristics.
111
+ - For `openai_reasoning`, an existing `compat.reasoning.summary` (or other reasoning keys) is preserved when merging `effort`.
112
+ - Package-local knobs (`thinking_budget`, `thinking_token_budget`, `chat_template_kwargs`, `cacheRetention`-coupled switches) remain on `compat` — see each provider page.
113
+
114
+ ## Security and performance notes
115
+
116
+ - Declared levels prevent 400s from illegal effort values on strict upstreams; snapping is deterministic and ladder-based, never a silent drop.
117
+ - `none` semantics are provider-specific (off, or minimum effort where off is unsupported — e.g. Anthropic Opus 5 cannot disable thinking at `xhigh`/`max`, GLM-5.3 cannot disable thinking at all); the per-provider pages call these out.
118
+ - No secrets or credentials flow through any helper here; patches are plain compat objects.
86
119
 
87
120
  ## Non-reasoning models
88
121
 
89
- - Helper with `noop`: returns options unchanged — no invented body fields.
90
- - Helper with a real family on a model that rejects the field: provider/API error — hosts should gate on `capabilities.reasoning` or package docs.
122
+ - The adapter returns options unchanged — no invented body fields.
91
123
  - `thinking_type` + `none` sets `{ type: "disabled" }`; other levels set `{ type: "enabled" }` without encoding effort (compose with `reasoning_effort` when the API supports both).
92
124
 
93
- ## Related pages
125
+ ## Related APIs
94
126
 
95
- - [Use-case model selection](use-case-model-selection.md) — session vs worker/summary model binding
96
- - [Provider packages](provider-packages.md) — package boundaries and discovery
97
127
  - [Provider caching](provider-caching.md) — cache retention can disable thinking on some providers (e.g. Z.AI / DeepSeek when `cacheRetention: "none"`)
98
128
  - [Provider request policies](provider-request-policies.md) — `mergeProviderRequestOptions`
129
+ - [Use-case model selection](use-case-model-selection.md) — session vs worker/summary model binding (workers take `thinkingLevel`)
99
130
  - [Agent/session runtime](agent-session-runtime.md) — prior-reasoning preservation across turns
100
- - Per-provider pages under [docs/providers](providers/)
101
- - Evidence matrix: [Review coverage (2026-07-17 provider validation)](_evidence/review-coverage-2026-07-17-provider-validation.md)
131
+ - [Provider packages](provider-packages.md) — package boundaries and discovery
132
+ - Per-provider pages under [docs/providers](providers/) — declared levels, wire field, and snapping per provider
133
+ - [Thinking coverage evidence matrix](_evidence/thinking-coverage-2026-09-05.md) — per-model legality, source, and test pins
134
+ - [Review coverage (2026-07-17 provider validation)](_evidence/review-coverage-2026-07-17-provider-validation.md)
@@ -101,7 +101,7 @@ await assertToolDispatchConforms(createToolRegistry(), {
101
101
  ## Security and performance notes
102
102
 
103
103
  - No credentials, no network required.
104
- - Supply `validate` to exercise your policy; use `createJsonSchemaToolArgumentValidator()` from `@arnilo/prism-tool-validator-json-schema` for standards-based `parameters` validation.
104
+ - Supply `validate` to exercise your policy; use `createJsonSchemaToolArgumentValidator()` from `@arnilo/prism-core/validation/json-schema` for standards-based `parameters` validation.
105
105
  - The helper uses an allow-all permission policy by default; supply `permission` to validate your fail-closed policy.
106
106
  - Blocked calls are proven not to execute by the absence of `tool_execution_started`.
107
107
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- This page freezes the reusable tool validation, parallel dispatch, MCP bridge, and coding execution-policy designs for Plan 055. It inventories existing `@arnilo/prism` tool harness seams, `@arnilo/prism-coding-agent` behavior, extension/contribution boundaries, and the MCP mapping surface Tasks 1–6 will implement against.
5
+ This page freezes the reusable tool validation, parallel dispatch, MCP bridge, and coding execution-policy designs for Plan 055. It inventories existing `@arnilo/prism` tool harness seams, `@arnilo/prism-coding-tools/agent` behavior, extension/contribution boundaries, and the MCP mapping surface Tasks 1–6 will implement against.
6
6
 
7
7
  Implementation is **shipped** for JSON Schema tool argument validation (Plan 055 Task 1), parallel single-shot tool dispatch (Task 2), the MCP client bridge (Task 3), coding execution policy (Task 4), and bounded image reads (Task 5). Task 6 verification evidence is recorded in [review coverage](_evidence/review-coverage-2026-07-14.md).
8
8
 
@@ -40,7 +40,7 @@ All paths converge on normal `ToolResult` values and `tool_execution_*` events.
40
40
 
41
41
  ```ts
42
42
  import { createAgent } from "@arnilo/prism";
43
- import { createJsonSchemaToolArgumentValidator } from "@arnilo/prism-tool-validator-json-schema";
43
+ import { createJsonSchemaToolArgumentValidator } from "@arnilo/prism-core/validation/json-schema";
44
44
 
45
45
  const agent = createAgent({
46
46
  model,
@@ -123,7 +123,7 @@ Package performs **no** `PermissionPolicy`, `ToolValidator`, or trust checks of
123
123
  | --- | --- |
124
124
  | `ToolDefinition.parameters` | Stored and forwarded to providers; **not validated** by core |
125
125
  | `ToolValidator` | Host function hook; Phase 25 threads through agent runtime |
126
- | Standards-based schema validation | Optional `@arnilo/prism-tool-validator-json-schema`; host wires it through `ToolValidator` |
126
+ | Standards-based schema validation | Optional `@arnilo/prism-core/validation/json-schema`; host wires it through `ToolValidator` |
127
127
  | Schema compile cache | Adapter-owned finite LRU; core never compiles schemas |
128
128
 
129
129
  ### MCP mapping (shipped — Task 3)
@@ -178,10 +178,10 @@ export function createToolParameterValidator(
178
178
  ): ToolValidator;
179
179
  ```
180
180
 
181
- Optional package `@arnilo/prism-tool-validator-json-schema`:
181
+ Optional package `@arnilo/prism-core/validation/json-schema`:
182
182
 
183
183
  ```ts
184
- import { createJsonSchemaToolArgumentValidator } from "@arnilo/prism-tool-validator-json-schema";
184
+ import { createJsonSchemaToolArgumentValidator } from "@arnilo/prism-core/validation/json-schema";
185
185
 
186
186
  createAgent({ model, validator: createJsonSchemaToolArgumentValidator() });
187
187
  ```
@@ -271,7 +271,7 @@ export async function assertExecutionAllowed(
271
271
  ): Promise<ExecutionAction>;
272
272
  ```
273
273
 
274
- `@arnilo/prism-coding-agent` tools call `executionPolicy.check()` **inside** `execute` before side effects (after dispatch permission + argument validation). Optional `@arnilo/prism-coding-security` supplies `createCodingApprovalPolicy({ roots, approve, readOnly, commandRules })` with realpath containment, default deny patterns, metacharacter approval, approval caching, and `createSandboxBashOperations()` for pluggable sandbox backends.
274
+ `@arnilo/prism-coding-tools/agent` tools call `executionPolicy.check()` **inside** `execute` before side effects (after dispatch permission + argument validation). Optional `@arnilo/prism-coding-tools/security` supplies `createCodingApprovalPolicy({ roots, approve, readOnly, commandRules })` with realpath containment, default deny patterns, metacharacter approval, approval caching, and `createSandboxBashOperations()` for pluggable sandbox backends.
275
275
 
276
276
  **Permission vs execution policy:** `PermissionPolicy` remains `tool:<name>:execute` at dispatch. `ExecutionPolicy` adds command/path context for coding tools only — no MCP-specific branches in core.
277
277
 
@@ -366,9 +366,9 @@ Core remains dependency-free: validators, MCP bridges, coding policy, sandboxes,
366
366
 
367
367
  | Finding / capability | Plan 055 task | Primitive / doc |
368
368
  | --- | --- | --- |
369
- | C-001 JSON Schema tool validation | 1 | **shipped** — `ToolArgumentValidator`, `createToolParameterValidator`, `@arnilo/prism-tool-validator-json-schema` |
369
+ | C-001 JSON Schema tool validation | 1 | **shipped** — `ToolArgumentValidator`, `createToolParameterValidator`, `@arnilo/prism-core/validation/json-schema` |
370
370
  | C-003 MCP client bridge | 3 | **shipped** — `@arnilo/prism-mcp` |
371
- | C-006 Approval/sandbox for coding tools | 4 | **shipped** — `ExecutionPolicy`, `@arnilo/prism-coding-security` |
371
+ | C-006 Approval/sandbox for coding tools | 4 | **shipped** — `ExecutionPolicy`, `@arnilo/prism-coding-tools/security` |
372
372
  | C-007 Parallel tool execution | 2 | **shipped** — `toolConcurrency`, `dispatchToolCallsInOrder`, `resolveToolConcurrency` |
373
373
  | R-011 Image size / resize option | 5 | **shipped** — `maxImageBytes`, `transformImage`, `DEFAULT_MAX_IMAGE_BYTES` on read tool |
374
374
  | Phase verification | 6 | **verified** — `npm run sdk:ready` + audit + threat-model fixtures; evidence in review coverage |
package/docs/tools.md CHANGED
@@ -198,11 +198,11 @@ Core exposes schema-agnostic adapters that wrap into the same `ToolValidator` se
198
198
  - `ToolArgumentValidator` — `validate(schema, value)` with structured errors
199
199
  - `createToolParameterValidator(adapter, { missingSchema?: "allow" | "reject" })` — maps `tool.parameters` through the adapter
200
200
 
201
- For standards-based validation install `@arnilo/prism-tool-validator-json-schema`:
201
+ For standards-based validation install `@arnilo/prism-core/validation/json-schema`:
202
202
 
203
203
  ```ts
204
204
  import { createAgent } from "@arnilo/prism";
205
- import { createJsonSchemaToolArgumentValidator } from "@arnilo/prism-tool-validator-json-schema";
205
+ import { createJsonSchemaToolArgumentValidator } from "@arnilo/prism-core/validation/json-schema";
206
206
 
207
207
  const agent = createAgent({
208
208
  model,
@@ -242,7 +242,7 @@ await session.run(input, {
242
242
 
243
243
  ## JSON Schema validator limits
244
244
 
245
- Core stores `ToolDefinition.parameters` but does not compile schemas. Hosts that install `@arnilo/prism-tool-validator-json-schema` receive pre-Ajv schema limits: 256 KiB bytes, depth 64, 10,000 properties/keywords, 128 refs, and a 256-entry LRU compiled cache by default. All reject invalid values and have finite hard ceilings. Only fragment-local `$ref` values are accepted; non-local refs, cycles, forbidden keys, and non-finite schema numbers fail before tool execution.
245
+ Core stores `ToolDefinition.parameters` but does not compile schemas. Hosts that install `@arnilo/prism-core/validation/json-schema` receive pre-Ajv schema limits: 256 KiB bytes, depth 64, 10,000 properties/keywords, 128 refs, and a 256-entry LRU compiled cache by default. All reject invalid values and have finite hard ceilings. Only fragment-local `$ref` values are accepted; non-local refs, cycles, forbidden keys, and non-finite schema numbers fail before tool execution.
246
246
 
247
247
  ```ts
248
248
  createJsonSchemaToolArgumentValidator({
@@ -275,7 +275,7 @@ Limits (mirroring the skill-disclosure DEFAULT/HARD cap pattern):
275
275
  - `search_tools({ query, k? })` returns inert `name: short description [matched: …]` lines — no schemas or tool bodies — and marks returned tools active for the session. Activation is names-only in run persistence (`sessionState.activatedToolNames`, capped at 128 names) and inert for tools absent from the current registry; a host can reset it with `session.clearActivatedTools()`.
276
276
  - Fail closed: any index or scoring error discloses the full input list — never zero tools, never wider than the input list. Exhausting the frozen 1024-tool index cap is surfaced the same way.
277
277
  - Disclosure never grants access: dispatch re-checks registry membership and allow/deny (`unknown_tool` / `tool_denied`) on every call regardless of what was described. Search results are intersected with the disclosed list structurally — searched tools are only ever selected from that list, never widened.
278
- - Scoring is BM25-lite lexical (name tokens weigh ×3, IDF from the registry): bounded, dependency-free, deterministic tie-breaks. ponytail ceiling: embedder-backed scoring via `@arnilo/prism-rag` if accuracy fixtures fall short.
278
+ - Scoring is BM25-lite lexical (name tokens weigh ×3, IDF from the registry): bounded, dependency-free, deterministic tie-breaks. ponytail ceiling: embedder-backed scoring via `@arnilo/prism-memory/rag` if accuracy fixtures fall short.
279
279
  - Cross-link: skills apply the same discipline to prompt text — see [Context and skills](context-and-skills.md).
280
280
 
281
281
  ## Guardrails
package/docs/web-tools.md CHANGED
@@ -44,7 +44,7 @@ Fetch returns bounded Markdown and selected attribution. Extract validates host
44
44
 
45
45
  ```ts
46
46
  import { createEnvCredentialResolver } from "@arnilo/prism";
47
- import { createJsonSchemaArgumentValidator } from "@arnilo/prism-tool-validator-json-schema";
47
+ import { createJsonSchemaArgumentValidator } from "@arnilo/prism-core/validation/json-schema";
48
48
  import { createBraveSearch, createFirecrawlExtractor, createFirecrawlFetch, createWebTools } from "@arnilo/prism-web-tools";
49
49
 
50
50
  const credentials = createEnvCredentialResolver(process.env, {