@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.
- package/CHANGELOG.md +33 -1
- package/README.md +23 -20
- package/dist/agent-run-state.d.ts +1 -2
- package/dist/agent-run-state.js +0 -3
- package/dist/agent-session/session/assemble.d.ts +6 -0
- package/dist/agent-session/session/assemble.js +391 -0
- package/dist/agent-session/session/persist.d.ts +28 -0
- package/dist/agent-session/session/persist.js +166 -0
- package/dist/agent-session/session/provider-round.d.ts +6 -0
- package/dist/agent-session/session/provider-round.js +231 -0
- package/dist/agent-session/session/tool-round.d.ts +31 -0
- package/dist/agent-session/session/tool-round.js +473 -0
- package/dist/agent-session/session/types.d.ts +115 -0
- package/dist/agent-session/session/types.js +5 -0
- package/dist/agent-session/session.d.ts +49 -43
- package/dist/agent-session/session.js +11 -1177
- package/dist/capture.d.ts +63 -0
- package/dist/capture.js +67 -0
- package/dist/cli-init.d.ts +18 -2
- package/dist/cli-init.js +2 -7
- package/dist/cli-runner.d.ts +2 -2
- package/dist/cli-runner.js +45 -9
- package/dist/content.d.ts +3 -3
- package/dist/content.js +3 -1
- package/dist/contracts-core/agent.d.ts +2 -0
- package/dist/contracts-core/batch.d.ts +97 -0
- package/dist/contracts-core/batch.js +65 -0
- package/dist/contracts-core/content.d.ts +72 -1
- package/dist/contracts-core/embeddings.d.ts +30 -0
- package/dist/contracts-core/embeddings.js +17 -0
- package/dist/contracts-core/images.d.ts +60 -0
- package/dist/contracts-core/images.js +17 -0
- package/dist/contracts-core/moderation.d.ts +46 -0
- package/dist/contracts-core/moderation.js +34 -0
- package/dist/contracts-core/speech.d.ts +39 -0
- package/dist/contracts-core/speech.js +17 -0
- package/dist/contracts-core/transcription.d.ts +48 -0
- package/dist/contracts-core/transcription.js +17 -0
- package/dist/contracts-core/video.d.ts +61 -0
- package/dist/contracts-core/video.js +17 -0
- package/dist/contracts-core.d.ts +7 -0
- package/dist/contracts-core.js +7 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.js +4 -3
- package/dist/node/agent-definitions.d.ts +1 -8
- package/dist/node/agent-definitions.js +0 -34
- package/dist/node/settings.d.ts +0 -1
- package/dist/node/settings.js +0 -5
- package/dist/pinned-fetch.js +29 -3
- package/dist/provider-events.js +3 -4
- package/dist/providers/media.d.ts +1 -2
- package/dist/providers/media.js +1 -4
- package/dist/rpc.d.ts +1 -1
- package/dist/rpc.js +4 -4
- package/dist/testing/provider-conformance.d.ts +114 -5
- package/dist/testing/provider-conformance.js +342 -0
- package/dist/testing/tool-effect-store-conformance.d.ts +0 -1
- package/dist/testing/tool-effect-store-conformance.js +0 -3
- package/dist/thinking.d.ts +48 -9
- package/dist/thinking.js +134 -8
- package/docs/0.1.0-readiness.md +3 -3
- package/docs/a2a.md +2 -2
- package/docs/acp.md +3 -3
- package/docs/ag-ui-adoption.md +1 -1
- package/docs/ag-ui.md +1 -2
- package/docs/agent-definitions.md +1 -1
- package/docs/agent-events.md +5 -5
- package/docs/agent-identity.md +13 -2
- package/docs/audit-export.md +3 -3
- package/docs/batch-jobs.md +120 -0
- package/docs/cli-rpc.md +20 -9
- package/docs/coding-agent-tools.md +19 -19
- package/docs/coding-review-and-diagnostics.md +2 -2
- package/docs/coding-security.md +4 -4
- package/docs/coding-workspaces.md +2 -2
- package/docs/computer-use-linux.md +13 -2
- package/docs/context-and-skills.md +1 -1
- package/docs/conversations.md +4 -4
- package/docs/credential-storage.md +11 -7
- package/docs/credentials-and-redaction.md +1 -1
- package/docs/data-classification.md +1 -1
- package/docs/database-persistence.md +4 -4
- package/docs/dev-inspector.md +6 -6
- package/docs/device-adapters.md +2 -2
- package/docs/diagrams.md +1 -1
- package/docs/document-reader.md +6 -6
- package/docs/documents.md +5 -4
- package/docs/embeddings.md +112 -0
- package/docs/enterprise-postgres-state.md +7 -7
- package/docs/evaluations.md +8 -8
- package/docs/extensions.md +3 -3
- package/docs/forge-integration.md +3 -3
- package/docs/graft.md +2 -2
- package/docs/guardrails.md +1 -1
- package/docs/host-security.md +15 -15
- package/docs/image-generation.md +129 -0
- package/docs/impeccable.md +5 -3
- package/docs/index.md +60 -33
- package/docs/indexed-code-search.md +2 -2
- package/docs/language-intelligence.md +4 -4
- package/docs/live-testing.md +126 -0
- package/docs/mcp-tools.md +43 -12
- package/docs/middleware-hooks.md +1 -1
- package/docs/migrate-to-0.4.md +3 -3
- package/docs/migrate-to-0.5.md +122 -0
- package/docs/migration.md +29 -1
- package/docs/model-registry.md +38 -0
- package/docs/model-routing.md +5 -5
- package/docs/moderation.md +117 -0
- package/docs/multi-agent-patterns.md +4 -4
- package/docs/multimodal-content.md +26 -2
- package/docs/obscura.md +2 -2
- package/docs/observability.md +32 -7
- package/docs/openapi-tools.md +13 -3
- package/docs/operations.md +11 -0
- package/docs/performance.md +7 -7
- package/docs/persistence-credentials-multimodality-primitives.md +6 -6
- package/docs/policy-and-audit.md +17 -7
- package/docs/ponytail.md +1 -1
- package/docs/postgres-persistence.md +5 -5
- package/docs/process-sessions.md +2 -2
- package/docs/prompt-registry.md +7 -7
- package/docs/provider-caching.md +4 -0
- package/docs/provider-conformance.md +23 -1
- package/docs/provider-packages.md +39 -3
- package/docs/provider-primitives.md +1 -1
- package/docs/provider-request-policies.md +1 -1
- package/docs/providers/ai-sdk.md +15 -3
- package/docs/providers/alibaba.md +5 -1
- package/docs/providers/anthropic.md +4 -0
- package/docs/providers/azure.md +17 -1
- package/docs/providers/bedrock.md +15 -0
- package/docs/providers/clinepass.md +4 -0
- package/docs/providers/commandcode.md +253 -0
- package/docs/providers/deepseek.md +4 -0
- package/docs/providers/google.md +4 -0
- package/docs/providers/hyper.md +284 -0
- package/docs/providers/kimi.md +4 -0
- package/docs/providers/neuralwatt.md +4 -0
- package/docs/providers/ollama.md +15 -0
- package/docs/providers/openai-compatible.md +4 -0
- package/docs/providers/openai.md +4 -0
- package/docs/providers/opencode-go.md +4 -0
- package/docs/providers/openrouter.md +5 -1
- package/docs/providers/vertex.md +16 -0
- package/docs/providers/xai.md +4 -0
- package/docs/providers/zai.md +4 -0
- package/docs/rag.md +26 -4
- package/docs/release-and-install.md +103 -46
- package/docs/resource-loading.md +1 -1
- package/docs/runs-and-usage.md +14 -2
- package/docs/server.md +5 -5
- package/docs/settings-auth-trust-security.md +7 -5
- package/docs/sheets.md +2 -2
- package/docs/speech.md +126 -0
- package/docs/sqlite-persistence.md +4 -4
- package/docs/supervisors.md +3 -3
- package/docs/thinking-and-reasoning.md +93 -60
- package/docs/tool-conformance.md +1 -1
- package/docs/tool-execution-primitives.md +8 -8
- package/docs/tools.md +4 -4
- package/docs/web-tools.md +1 -1
- package/docs/wiki.md +1 -1
- package/docs/work-artifacts-and-review.md +17 -6
- package/docs/work-connectors.md +4 -4
- package/docs/work-tools.md +5 -5
- package/docs/workflow-orchestration-primitives.md +11 -11
- package/docs/workflows.md +5 -5
- package/package.json +11 -8
- package/templates/init/providers.json +24 -8
- 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
|
|
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:
|
|
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
|
|
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`: `
|
|
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
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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" });
|
package/docs/supervisors.md
CHANGED
|
@@ -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
|
|
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
|
|
10
|
-
- Use-case workers (LLM compaction, observational memory): pass `thinkingLevel`;
|
|
11
|
-
-
|
|
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
|
-
##
|
|
14
|
+
## Inputs / request
|
|
14
15
|
|
|
15
|
-
|
|
|
16
|
-
| --- | --- |
|
|
17
|
-
|
|
|
18
|
-
|
|
|
19
|
-
|
|
|
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
|
-
|
|
24
|
-
import { applyThinkingLevel, thinkingCompatFor, thinkingFamilyForModel } from "@arnilo/prism";
|
|
22
|
+
## Outputs / response / events
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
//
|
|
37
|
+
// Per-turn override on a session run
|
|
32
38
|
await session.run(input, {
|
|
33
|
-
providerOptions:
|
|
34
|
-
// → { reasoning: { effort: "low" } }
|
|
39
|
+
providerOptions: applyThinkingLevelForModel(base, "high", model),
|
|
35
40
|
});
|
|
36
41
|
|
|
37
|
-
//
|
|
38
|
-
const
|
|
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
|
|
53
|
-
| `thinking_type` | `{ thinking: { type: "enabled" \| "disabled" } }` | Z.AI `thinking.type`; Kimi K2.x
|
|
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
|
-
|
|
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
|
-
###
|
|
73
|
+
### First-party packages
|
|
59
74
|
|
|
60
|
-
| Package |
|
|
61
|
-
| --- | --- |
|
|
62
|
-
| `@arnilo/prism-providers/openai` | `openai_reasoning
|
|
63
|
-
| `@arnilo/prism-providers/openrouter` | `openai_reasoning
|
|
64
|
-
| `@arnilo/prism-providers/
|
|
65
|
-
| `@arnilo/prism-providers/
|
|
66
|
-
| `@arnilo/prism-providers/
|
|
67
|
-
| `@arnilo/prism-providers/
|
|
68
|
-
| `@arnilo/prism-providers/
|
|
69
|
-
| `@arnilo/prism-providers/
|
|
70
|
-
| `@arnilo/prism-providers/
|
|
71
|
-
| `@arnilo/prism-providers/
|
|
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
|
-
|
|
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
|
-
|
|
98
|
+
Snap semantics (`snapThinkingLevel`, applied by the adapter and by provider resolvers when the model declares a set):
|
|
76
99
|
|
|
77
|
-
1.
|
|
78
|
-
2. `
|
|
79
|
-
3.
|
|
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
|
-
|
|
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
|
-
##
|
|
108
|
+
## Extension and configuration notes
|
|
84
109
|
|
|
85
|
-
|
|
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
|
-
-
|
|
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
|
|
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
|
-
-
|
|
101
|
-
-
|
|
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)
|
package/docs/tool-conformance.md
CHANGED
|
@@ -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-
|
|
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-
|
|
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-
|
|
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-
|
|
181
|
+
Optional package `@arnilo/prism-core/validation/json-schema`:
|
|
182
182
|
|
|
183
183
|
```ts
|
|
184
|
-
import { createJsonSchemaToolArgumentValidator } from "@arnilo/prism-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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, {
|