@arnilo/prism 0.0.4 → 0.0.6
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 +46 -1
- package/README.md +34 -10
- package/dist/agent-loops.d.ts +1 -0
- package/dist/agent-loops.js +26 -16
- package/dist/agents.js +147 -21
- package/dist/cli-init.d.ts +41 -0
- package/dist/cli-init.js +390 -0
- package/dist/cli-runner.d.ts +7 -1
- package/dist/cli-runner.js +13 -1
- package/dist/content.d.ts +19 -0
- package/dist/content.js +197 -69
- package/dist/contracts.d.ts +96 -9
- package/dist/contracts.js +8 -0
- package/dist/feedback.d.ts +48 -0
- package/dist/feedback.js +230 -0
- package/dist/ids.d.ts +2 -0
- package/dist/ids.js +6 -0
- package/dist/index.d.ts +10 -4
- package/dist/index.js +6 -3
- package/dist/providers/media.d.ts +3 -1
- package/dist/providers/media.js +11 -1
- package/dist/session-stores.js +2 -3
- package/dist/testing/feedback.d.ts +6 -0
- package/dist/testing/feedback.js +37 -0
- package/dist/testing/persistence-schema.d.ts +48 -10
- package/dist/testing/persistence-schema.js +166 -22
- package/dist/testing/run-ledger-conformance.js +7 -1
- package/dist/thinking.d.ts +42 -0
- package/dist/thinking.js +92 -0
- package/dist/tools.js +2 -3
- package/dist/use-case-model.d.ts +63 -0
- package/dist/use-case-model.js +52 -0
- package/docs/a2a.md +75 -0
- package/docs/agent-events.md +14 -21
- package/docs/agent-loops.md +12 -9
- package/docs/agent-session-runtime.md +14 -16
- package/docs/cli-rpc.md +35 -7
- package/docs/coding-agent-tools.md +35 -14
- package/docs/coding-security.md +7 -3
- package/docs/compaction-llm.md +17 -7
- package/docs/compaction-observational-memory.md +30 -4
- package/docs/context-and-skills.md +1 -0
- package/docs/credential-storage.md +58 -9
- package/docs/credentials-and-redaction.md +3 -3
- package/docs/database-persistence.md +17 -9
- package/docs/evaluations.md +122 -0
- package/docs/extensions.md +2 -2
- package/docs/host-security.md +26 -5
- package/docs/index.md +43 -28
- package/docs/mcp-tools.md +74 -13
- package/docs/migration.md +177 -3
- package/docs/multimodal-content.md +14 -6
- package/docs/node-filesystem-config.md +1 -0
- package/docs/node-jsonl-session-store.md +5 -4
- package/docs/observability.md +14 -6
- package/docs/performance.md +209 -0
- package/docs/postgres-persistence.md +8 -6
- package/docs/provider-caching.md +16 -4
- package/docs/provider-conformance.md +40 -1
- package/docs/provider-packages.md +62 -3
- package/docs/providers/ai-sdk.md +149 -0
- package/docs/providers/kimi.md +124 -61
- package/docs/providers/neuralwatt.md +19 -13
- package/docs/providers/openai.md +56 -13
- package/docs/providers/opencode-go.md +118 -30
- package/docs/providers/openrouter.md +105 -35
- package/docs/providers/zai.md +94 -45
- package/docs/public-contracts.md +6 -5
- package/docs/rag.md +113 -0
- package/docs/release-and-install.md +100 -79
- package/docs/review-coverage-2026-07-15.md +193 -0
- package/docs/review-coverage-2026-07-17-provider-validation.md +192 -0
- package/docs/runs-and-usage.md +42 -5
- package/docs/server.md +139 -0
- package/docs/settings-auth-trust-security.md +5 -5
- package/docs/sqlite-persistence.md +6 -5
- package/docs/structured-output.md +1 -1
- package/docs/supervisors.md +71 -0
- package/docs/thinking-and-reasoning.md +98 -0
- package/docs/tool-execution-primitives.md +3 -3
- package/docs/tools.md +15 -0
- package/docs/use-case-model-selection.md +109 -0
- package/docs/workflow-orchestration-primitives.md +20 -3
- package/docs/workflows.md +114 -33
- package/docs/working-and-semantic-memory.md +170 -0
- package/package.json +13 -3
- package/templates/init/README.md.tmpl +28 -0
- package/templates/init/env.example.tmpl +1 -0
- package/templates/init/gitignore.tmpl +11 -0
- package/templates/init/optional/evals-example.ts.tmpl +17 -0
- package/templates/init/optional/workflows-example.ts.tmpl +27 -0
- package/templates/init/package.json.tmpl +22 -0
- package/templates/init/providers.json +76 -0
- package/templates/init/src/agent.ts.tmpl +10 -0
- package/templates/init/src/index.ts.tmpl +12 -0
- package/templates/init/src/tests/agent.test.ts.tmpl +24 -0
- package/templates/init/tsconfig.json.tmpl +15 -0
|
@@ -2,27 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
## What it does
|
|
4
4
|
|
|
5
|
-
`@arnilo/prism-provider-opencode-go` provides explicit, side-effect-free setup for
|
|
6
|
-
OpenCode Go
|
|
7
|
-
|
|
8
|
-
cache/session headers.
|
|
5
|
+
`@arnilo/prism-provider-opencode-go` provides explicit, side-effect-free setup for
|
|
6
|
+
[OpenCode Go](https://opencode.ai/docs/go/) — a low-cost subscription gateway for
|
|
7
|
+
open coding models. The package dual-routes by `ModelConfig.compat.route`:
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
| Route | Endpoint | Official model families |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| `"openai"` (default) | `POST {baseUrl}/chat/completions` | Grok, GLM, Kimi, MiMo, DeepSeek |
|
|
12
|
+
| `"anthropic"` | `POST {baseUrl}/messages` | MiniMax, Qwen |
|
|
13
|
+
|
|
14
|
+
Default base URL is the official Go API root:
|
|
15
|
+
|
|
16
|
+
```txt
|
|
17
|
+
https://opencode.ai/zen/go/v1
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Session stickiness uses the sanitized `x-opencode-session` header. Anthropic-route
|
|
21
|
+
models may emit selected `cache_control` breakpoints; OpenAI-route models use
|
|
22
|
+
implicit caching and never receive Anthropic cache fields.
|
|
12
23
|
|
|
13
24
|
## When to use it
|
|
14
25
|
|
|
15
|
-
Use it when a host app wants
|
|
16
|
-
|
|
17
|
-
|
|
26
|
+
Use it when a host app wants OpenCode Go models through Prism's `AgentSession`
|
|
27
|
+
runtime with dual-route serialization, per-request session headers, and optional
|
|
28
|
+
caller-gated model discovery.
|
|
18
29
|
|
|
19
|
-
Do not use it for automatic credential discovery, catalog fetches, or
|
|
30
|
+
Do not use it for automatic credential discovery, setup-time catalog fetches, or
|
|
20
31
|
real-network tests.
|
|
21
32
|
|
|
22
33
|
## Inputs / request
|
|
23
34
|
|
|
24
35
|
```ts
|
|
25
|
-
import {
|
|
36
|
+
import {
|
|
37
|
+
createOpenCodeGoProviderPackage,
|
|
38
|
+
listOpenCodeGoModels,
|
|
39
|
+
} from "@arnilo/prism-provider-opencode-go";
|
|
26
40
|
|
|
27
41
|
createOpenCodeGoProviderPackage(options: OpenCodeGoProviderPackageOptions): ProviderPackage
|
|
28
42
|
```
|
|
@@ -31,57 +45,126 @@ createOpenCodeGoProviderPackage(options: OpenCodeGoProviderPackageOptions): Prov
|
|
|
31
45
|
| --- | --- | --- |
|
|
32
46
|
| `apiKey` | `CredentialValueSource` | Direct/callback/resolver API-key source. |
|
|
33
47
|
| `fetch` | `typeof fetch` | Optional fetch implementation for tests/hosts. |
|
|
34
|
-
| `baseUrl` | `string` | Overrides
|
|
35
|
-
| `models` | `readonly ModelConfig[]` | Overrides `openCodeGoModels` defaults. |
|
|
48
|
+
| `baseUrl` | `string` | Overrides official `https://opencode.ai/zen/go/v1`. |
|
|
49
|
+
| `models` | `readonly ModelConfig[]` | Overrides featured `openCodeGoModels` defaults. |
|
|
36
50
|
|
|
37
51
|
`ProviderRequest.options.cacheKey` (falling back to `sessionId`) maps to the
|
|
38
|
-
`x-opencode-session` header
|
|
39
|
-
`
|
|
52
|
+
`x-opencode-session` header. Anthropic-route `cache_control` breakpoints and
|
|
53
|
+
`cacheRetention` map as documented below.
|
|
40
54
|
|
|
41
55
|
## Outputs / response / events
|
|
42
56
|
|
|
43
57
|
| Surface | Behavior |
|
|
44
58
|
| --- | --- |
|
|
45
59
|
| Provider stream | Prism text, thinking, tool-call delta/final, `usage`, `done`, redacted `error`. |
|
|
46
|
-
|
|
|
60
|
+
| OpenAI thinking | `delta.reasoning_content` → thinking deltas; replay via `reasoning_content` when `preserveThinking`. |
|
|
61
|
+
| Anthropic thinking | `thinking_delta` → thinking deltas; replay via Anthropic thinking blocks when `preserveThinking`. |
|
|
62
|
+
| Session/cache | `x-opencode-session` + route-specific cache markers. |
|
|
47
63
|
| Auth method | `api_key` for `opencode-go`, credential name `apiKey`. |
|
|
48
64
|
|
|
49
65
|
## Request/response example
|
|
50
66
|
|
|
51
|
-
Example headers added before fetch:
|
|
52
|
-
|
|
53
67
|
```json
|
|
54
68
|
{
|
|
55
69
|
"Authorization": "Bearer <resolved-key>",
|
|
70
|
+
"content-type": "application/json",
|
|
56
71
|
"x-opencode-session": "<ProviderRequest.options.cacheKey ?? sessionId>"
|
|
57
72
|
}
|
|
58
73
|
```
|
|
59
74
|
|
|
75
|
+
OpenAI-route body (thinking passthrough + preserved reasoning):
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"model": "kimi-k3",
|
|
80
|
+
"stream": true,
|
|
81
|
+
"stream_options": { "include_usage": true },
|
|
82
|
+
"reasoning_effort": "high",
|
|
83
|
+
"messages": [
|
|
84
|
+
{
|
|
85
|
+
"role": "assistant",
|
|
86
|
+
"content": "calling",
|
|
87
|
+
"tool_calls": [{ "id": "call_1", "type": "function", "function": { "name": "lookup", "arguments": "{\"q\":\"x\"}" } }],
|
|
88
|
+
"reasoning_content": "plan the lookup"
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
60
94
|
## Implementation example
|
|
61
95
|
|
|
62
96
|
```ts
|
|
63
97
|
import { createExtensionKernel } from "@arnilo/prism";
|
|
64
|
-
import {
|
|
98
|
+
import {
|
|
99
|
+
createOpenCodeGoProviderPackage,
|
|
100
|
+
listOpenCodeGoModels,
|
|
101
|
+
openCodeGoModels,
|
|
102
|
+
} from "@arnilo/prism-provider-opencode-go";
|
|
65
103
|
|
|
66
104
|
const kernel = createExtensionKernel();
|
|
67
|
-
await kernel.load([createOpenCodeGoProviderPackage({ apiKey:
|
|
105
|
+
await kernel.load([createOpenCodeGoProviderPackage({ apiKey: process.env.OPENCODE_API_KEY })]);
|
|
68
106
|
```
|
|
69
107
|
|
|
70
|
-
|
|
108
|
+
Caller-gated live catalog (never runs during package setup):
|
|
71
109
|
|
|
72
110
|
```ts
|
|
73
|
-
|
|
111
|
+
const models = await listOpenCodeGoModels({ apiKey: process.env.OPENCODE_API_KEY });
|
|
112
|
+
await kernel.load([createOpenCodeGoProviderPackage({ apiKey: process.env.OPENCODE_API_KEY, models })]);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Offline bootstrap with featured docs-verified aliases:
|
|
74
116
|
|
|
117
|
+
```ts
|
|
75
118
|
await kernel.load([
|
|
76
119
|
createOpenCodeGoProviderPackage({ apiKey: "fake", models: openCodeGoModels }),
|
|
77
120
|
]);
|
|
78
121
|
```
|
|
79
122
|
|
|
123
|
+
## Featured models and routes
|
|
124
|
+
|
|
125
|
+
Featured `openCodeGoModels` mirrors the official Go docs list (open coding models
|
|
126
|
+
only — **not** Zen GPT/Claude ids). Route selection follows the official endpoint
|
|
127
|
+
table; Pi secondary metadata is used only for context/output limits when docs omit them.
|
|
128
|
+
|
|
129
|
+
| Model ID | Route | Cache kind |
|
|
130
|
+
| --- | --- | --- |
|
|
131
|
+
| `grok-4.5`, `glm-5.2`, `glm-5.1`, `kimi-k3`, `kimi-k2.7-code`, `kimi-k2.6`, `mimo-v2.5`, `mimo-v2.5-pro`, `deepseek-v4-pro`, `deepseek-v4-flash` | `openai` | `implicit` |
|
|
132
|
+
| `minimax-m3`, `minimax-m2.7`, `minimax-m2.5`, `qwen3.7-max`, `qwen3.7-plus`, `qwen3.6-plus` | `anthropic` | `cache_control` |
|
|
133
|
+
|
|
134
|
+
## Model discovery
|
|
135
|
+
|
|
136
|
+
Official list endpoint (sparse OpenAI-compatible shape):
|
|
137
|
+
|
|
138
|
+
```txt
|
|
139
|
+
GET https://opencode.ai/zen/go/v1/models
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`listOpenCodeGoModels({ apiKey?, fetch?, baseUrl?, signal?, headers? })` maps each
|
|
143
|
+
`{ id, owned_by }` entry to `ModelConfig` with route/cache heuristics from the docs
|
|
144
|
+
endpoint table. Featured metadata (pricing/limits/thinking defaults) is applied when
|
|
145
|
+
the id matches `openCodeGoModels`. Discovery is **caller-gated** — setup performs
|
|
146
|
+
zero fetches.
|
|
147
|
+
|
|
148
|
+
## Thinking / reasoning
|
|
149
|
+
|
|
150
|
+
OpenCode Go does not document gateway-owned thinking fields; Prism forwards
|
|
151
|
+
upstream-compatible compat and preserves prior reasoning for tool-call continuity:
|
|
152
|
+
|
|
153
|
+
| Surface | Behavior |
|
|
154
|
+
| --- | --- |
|
|
155
|
+
| OpenAI route stream | `reasoning_content` → thinking deltas |
|
|
156
|
+
| OpenAI route replay | thinking blocks → top-level `reasoning_content` when `preserveThinking` (default for reasoning models); never folded into text |
|
|
157
|
+
| OpenAI route body | optional `thinking` / `reasoning_effort` / `reasoning` from model + per-turn `options.compat` (request wins) |
|
|
158
|
+
| Anthropic route stream | `thinking_delta` → thinking deltas |
|
|
159
|
+
| Anthropic route replay | thinking blocks with optional `signature` when `preserveThinking` |
|
|
160
|
+
|
|
161
|
+
Owned compat keys (`route`, `thinking`, `reasoning`, `reasoning_effort`,
|
|
162
|
+
`preserveThinking`) are stripped before opaque compat spread so resolved values win.
|
|
163
|
+
|
|
80
164
|
## Extension and configuration notes
|
|
81
165
|
|
|
82
166
|
- Hosts choose base URL, model list, credential source, and `fetch` impl.
|
|
83
|
-
-
|
|
84
|
-
routes preserve `tool_use`/`tool_result` blocks.
|
|
167
|
+
- Route selection is explicit via `compat.route` (`"anthropic"` or default `"openai"`).
|
|
85
168
|
- Package contributes models via the extension `api` and an `api_key` auth method.
|
|
86
169
|
|
|
87
170
|
### Cache and session behavior
|
|
@@ -114,19 +197,24 @@ await kernel.load([
|
|
|
114
197
|
- No network calls during import, setup, build, or default tests.
|
|
115
198
|
- No automatic environment, file, keychain, or shell credential lookup.
|
|
116
199
|
- API keys are resolved per request from caller-supplied values or resolvers and
|
|
117
|
-
redacted from errors.
|
|
200
|
+
redacted from errors (including discovery failures).
|
|
118
201
|
- Caller-supplied `ProviderRequest.options.headers` can add non-owned headers, but
|
|
119
202
|
provider-owned headers (`content-type`, `x-opencode-session`, `authorization`)
|
|
120
203
|
are applied last and cannot be overridden by caller headers.
|
|
121
|
-
- Live tests stay opt-in behind `PRISM_LIVE_PROVIDER_TESTS=1` plus
|
|
122
|
-
|
|
204
|
+
- Live tests stay opt-in behind `PRISM_LIVE_PROVIDER_TESTS=1` plus `OPENCODE_API_KEY`;
|
|
205
|
+
default tests are network-free.
|
|
206
|
+
|
|
207
|
+
## Official evidence
|
|
208
|
+
|
|
209
|
+
- [OpenCode Go](https://opencode.ai/docs/go/) — model list, dual endpoints, pricing/usage, `GET /zen/go/v1/models`
|
|
210
|
+
- Pi secondary (ids/limits only): `packages/ai/src/providers/opencode-go.ts`, `opencode-go.models.ts`
|
|
123
211
|
|
|
124
212
|
## Related APIs
|
|
125
213
|
|
|
126
214
|
- [Provider packages](../provider-packages.md): `defineProviderPackage`,
|
|
127
|
-
`ModelConfig`, request/cache policies.
|
|
215
|
+
`ModelConfig`, discovery contract, request/cache policies.
|
|
216
|
+
- [Thinking and reasoning](../thinking-and-reasoning.md): per-turn `ThinkingLevel` → compat families.
|
|
128
217
|
- [Credentials and redaction](../credentials-and-redaction.md):
|
|
129
218
|
`resolveCredentialValue`, `redactSecrets`.
|
|
130
|
-
- [
|
|
131
|
-
adapter.
|
|
219
|
+
- [Provider caching](../provider-caching.md): route-specific OpenCode Go cache matrix.
|
|
132
220
|
- [Provider conformance](../provider-conformance.md): network-free adapter tests.
|
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
## What it does
|
|
4
4
|
|
|
5
5
|
`@arnilo/prism-provider-openrouter` provides explicit, side-effect-free setup for the
|
|
6
|
-
OpenRouter API-key provider with app-controlled model
|
|
7
|
-
|
|
6
|
+
OpenRouter API-key provider with **app-controlled** model registration, routing
|
|
7
|
+
passthrough, official `reasoning` controls, and Anthropic-style `cache_control`
|
|
8
|
+
(plus sticky `session_id` routing).
|
|
8
9
|
|
|
9
10
|
The package registers a provider, caller-supplied model metadata, and an
|
|
10
|
-
`api_key` auth method through `createExtensionKernel().load([...])`.
|
|
11
|
-
|
|
11
|
+
`api_key` auth method through `createExtensionKernel().load([...])`. There is
|
|
12
|
+
**no bundled mega-catalog**. Optional `listOpenRouterModels()` lets hosts fetch
|
|
13
|
+
the live official catalog and pass a filtered subset via `models:` — setup
|
|
14
|
+
itself never fetches.
|
|
12
15
|
|
|
13
16
|
## When to use it
|
|
14
17
|
|
|
@@ -16,16 +19,22 @@ Use it when a host app wants OpenRouter routing passthrough, reasoning controls,
|
|
|
16
19
|
and per-model cache policy through Prism's `AgentSession` runtime, and needs to
|
|
17
20
|
override cache behavior per model rather than accept a single hard-coded policy.
|
|
18
21
|
|
|
19
|
-
Do not use it for catalog
|
|
20
|
-
real-network tests.
|
|
22
|
+
Do not use it for automatic catalog fetch during setup, automatic credential
|
|
23
|
+
discovery, or real-network tests in CI defaults.
|
|
21
24
|
|
|
22
25
|
## Inputs / request
|
|
23
26
|
|
|
24
27
|
```ts
|
|
25
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
createOpenRouterProviderPackage,
|
|
30
|
+
defineOpenRouterModel,
|
|
31
|
+
listOpenRouterModels,
|
|
32
|
+
} from "@arnilo/prism-provider-openrouter";
|
|
26
33
|
|
|
27
34
|
createOpenRouterProviderPackage(options: OpenRouterProviderPackageOptions): ProviderPackage
|
|
28
|
-
defineOpenRouterModel(config: OpenRouterModelConfig):
|
|
35
|
+
defineOpenRouterModel(config: OpenRouterModelConfig): ModelConfig
|
|
36
|
+
listOpenRouterModels(options?: ListOpenRouterModelsOptions): Promise<ModelConfig[]>
|
|
37
|
+
mapOpenRouterModel(entry: OpenRouterModelEntry): ModelConfig
|
|
29
38
|
```
|
|
30
39
|
|
|
31
40
|
| Field | Type | Purpose |
|
|
@@ -37,25 +46,32 @@ defineOpenRouterModel(config: OpenRouterModelConfig): OpenRouterModelConfig
|
|
|
37
46
|
| `appTitle` | `string` | App title for the `X-Title` attribution header. |
|
|
38
47
|
| `models` | `readonly ModelConfig[]` | App-supplied model catalog (no default fetch). |
|
|
39
48
|
|
|
40
|
-
`OpenRouterModelConfig.compat.openRouterRouting` controls routing order
|
|
41
|
-
`data_collection
|
|
49
|
+
`OpenRouterModelConfig.compat.openRouterRouting` controls routing order /
|
|
50
|
+
`data_collection`. `compat.reasoning` carries the official OpenRouter
|
|
51
|
+
`reasoning` object (`effort`, `max_tokens`, `exclude`, …). Per-turn
|
|
52
|
+
`providerOptions.compat.reasoning` merges over model defaults (request wins
|
|
53
|
+
key-by-key). `compat.preserveThinking` replays assistant thinking as body
|
|
54
|
+
`reasoning` for tool-call continuity.
|
|
42
55
|
|
|
43
56
|
## Outputs / response / events
|
|
44
57
|
|
|
45
58
|
| Surface | Behavior |
|
|
46
59
|
| --- | --- |
|
|
47
|
-
| Provider stream | Prism text, thinking, tool-call delta/final, `usage` (with cache read/write mapped), `done`, redacted `error`. |
|
|
60
|
+
| Provider stream | Prism text, thinking (`delta.reasoning` / `reasoning_content`), tool-call delta/final, `usage` (with cache read/write mapped), `done`, redacted `error`. |
|
|
48
61
|
| Attribution | `HTTP-Referer`/`X-Title` headers sent only when `appUrl`/`appTitle` are supplied. |
|
|
49
62
|
| Auth method | `api_key` for `openrouter`, credential name `apiKey`. |
|
|
50
63
|
|
|
51
64
|
## Request/response example
|
|
52
65
|
|
|
53
|
-
Per-model routing override:
|
|
66
|
+
Per-model routing + reasoning override:
|
|
54
67
|
|
|
55
68
|
```json
|
|
56
69
|
{
|
|
57
70
|
"model": "anthropic/claude-sonnet-4",
|
|
58
|
-
"
|
|
71
|
+
"provider": { "order": ["anthropic"], "data_collection": "deny" },
|
|
72
|
+
"reasoning": { "effort": "high" },
|
|
73
|
+
"session_id": "session-with-spaces",
|
|
74
|
+
"cache_control": { "type": "ephemeral" }
|
|
59
75
|
}
|
|
60
76
|
```
|
|
61
77
|
|
|
@@ -63,58 +79,107 @@ Per-model routing override:
|
|
|
63
79
|
|
|
64
80
|
```ts
|
|
65
81
|
import { createExtensionKernel } from "@arnilo/prism";
|
|
66
|
-
import {
|
|
82
|
+
import {
|
|
83
|
+
createOpenRouterProviderPackage,
|
|
84
|
+
defineOpenRouterModel,
|
|
85
|
+
listOpenRouterModels,
|
|
86
|
+
} from "@arnilo/prism-provider-openrouter";
|
|
67
87
|
|
|
88
|
+
// App-controlled registration (default — no fetch):
|
|
68
89
|
const sonnet = defineOpenRouterModel({
|
|
69
90
|
model: "anthropic/claude-sonnet-4",
|
|
70
|
-
compat: {
|
|
91
|
+
compat: {
|
|
92
|
+
openRouterRouting: { order: ["anthropic"], data_collection: "deny" },
|
|
93
|
+
openRouterCache: true,
|
|
94
|
+
reasoning: { effort: "medium" },
|
|
95
|
+
},
|
|
71
96
|
});
|
|
72
97
|
|
|
98
|
+
// Optional live discovery — caller-gated, never run by setup:
|
|
99
|
+
const live = await listOpenRouterModels({ apiKey: process.env.OPENROUTER_API_KEY });
|
|
100
|
+
const filtered = live.filter((m) => m.model.startsWith("anthropic/"));
|
|
101
|
+
|
|
73
102
|
const kernel = createExtensionKernel();
|
|
74
103
|
await kernel.load([
|
|
75
|
-
createOpenRouterProviderPackage({
|
|
104
|
+
createOpenRouterProviderPackage({
|
|
105
|
+
apiKey: process.env.OPENROUTER_API_KEY,
|
|
106
|
+
models: filtered.length ? filtered : [sonnet],
|
|
107
|
+
}),
|
|
76
108
|
]);
|
|
77
109
|
```
|
|
78
110
|
|
|
79
111
|
## Extension and configuration notes
|
|
80
112
|
|
|
81
113
|
- Apps supply the model catalog via `models`; no catalog is fetched during setup.
|
|
114
|
+
- `listOpenRouterModels()` is the official `GET https://openrouter.ai/api/v1/models`
|
|
115
|
+
helper (auth optional for the public catalog). Map pricing/context/modalities/
|
|
116
|
+
reasoning metadata into `ModelConfig`; hosts still decide what to register.
|
|
82
117
|
- `defineOpenRouterModel` lets apps override cache policy and routing per model.
|
|
83
118
|
- Hosts choose base URL, attribution, credential source, and `fetch` impl.
|
|
84
119
|
- Package contributes models and an `api_key` auth method.
|
|
85
120
|
|
|
121
|
+
### Reasoning
|
|
122
|
+
|
|
123
|
+
- Body field is the official OpenRouter `reasoning` object
|
|
124
|
+
(`effort`: `max`/`xhigh`/`high`/`medium`/`low`/`minimal`/`none`, plus
|
|
125
|
+
`max_tokens`, `exclude`, `enabled`, `context`, `mode` as documented).
|
|
126
|
+
- Model `compat.reasoning` defaults merge with per-turn `options.compat.reasoning`
|
|
127
|
+
(request keys win). Task 4 `applyThinkingLevel(..., "openai_reasoning")` writes
|
|
128
|
+
`{ reasoning: { effort } }` into that path.
|
|
129
|
+
- Owned compat keys (`reasoning`, `openRouterRouting`, `openRouterCache`,
|
|
130
|
+
`preserveThinking`) are stripped from opaque compat spreads so resolved values
|
|
131
|
+
cannot be overwritten accidentally.
|
|
132
|
+
- When `preserveThinking` is enabled (default for reasoning-capable models),
|
|
133
|
+
assistant `thinking` blocks replay as top-level `reasoning` — not folded into
|
|
134
|
+
text — matching OpenRouter's tool-call continuity guidance.
|
|
135
|
+
|
|
86
136
|
### Cache and session behavior
|
|
87
137
|
|
|
88
138
|
- `session_id` (request body) and the `X-Session-Id` header are derived from
|
|
89
139
|
`ProviderRequestOptions.cacheKey` (falling back to `sessionId`) and sanitized
|
|
90
140
|
+ clamped to 256 characters via the shared `sanitizeCacheKey()` helper.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
`
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
141
|
+
OpenRouter uses this for provider sticky routing to maximize cache hits.
|
|
142
|
+
- **Automatic caching** (no breakpoints): when caching is enabled for an
|
|
143
|
+
explicit `cache_control` model (or `compat.openRouterCache` /
|
|
144
|
+
`cache.mode: "on"`), Prism emits a top-level
|
|
145
|
+
`cache_control: { type: "ephemeral" }` per OpenRouter's Anthropic automatic
|
|
146
|
+
caching docs. Note: top-level `cache_control` can exclude some backends
|
|
147
|
+
(e.g. Bedrock/Vertex) from routing.
|
|
148
|
+
- **Explicit breakpoints**: Anthropic-style markers are applied only to the
|
|
149
|
+
Prism `PromptCacheBreakpoint` locations the caller selects via
|
|
150
|
+
`ProviderRequestOptions.cache.breakpoints` (last content block of each
|
|
151
|
+
selected message). When breakpoints are present, top-level automatic
|
|
152
|
+
`cache_control` is omitted.
|
|
100
153
|
- Caching is enabled unless disabled (`cacheRetention: "none"` /
|
|
101
154
|
`cache.mode: "off"`) and the model opts in via `ModelConfig.cache.kind`
|
|
102
155
|
(`"cache_control"`) or the legacy `compat.openRouterCache: true` flag.
|
|
103
156
|
- `cacheRetention: "long"` (or `cache.retention: "long"`) emits
|
|
104
|
-
`
|
|
105
|
-
long retention (`ModelConfig.cache.longRetention !== false`)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
157
|
+
`ttl: "1h"` on markers / top-level automatic control when the model allows
|
|
158
|
+
long retention (`ModelConfig.cache.longRetention !== false`).
|
|
159
|
+
- Usage accounting: OpenRouter `prompt_tokens_details.cached_tokens` →
|
|
160
|
+
`Usage.cacheReadTokens`; `prompt_tokens_details.cache_write_tokens` →
|
|
161
|
+
`Usage.cacheWriteTokens`.
|
|
162
|
+
|
|
163
|
+
### Model discovery
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
const models = await listOpenRouterModels({ apiKey, fetch, signal, baseUrl });
|
|
167
|
+
createOpenRouterProviderPackage({ apiKey, models: models.filter(...) });
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`mapOpenRouterModel` converts official per-token USD pricing to
|
|
171
|
+
`ModelCost` with `unit: "per_million_tokens"`, infers `cache.kind` (`cache_control`
|
|
172
|
+
for Anthropic/Qwen/Gemini families with cache pricing; otherwise `implicit` when
|
|
173
|
+
cache-read pricing exists), and seeds `compat.reasoning.effort` from
|
|
174
|
+
`reasoning.default_effort` when present.
|
|
110
175
|
|
|
111
176
|
## Security and performance notes
|
|
112
177
|
|
|
113
178
|
- SSE streams and HTTP error bodies use bounded `@arnilo/prism/providers/transport` helpers (`readSseData`, `readBoundedResponseText`).
|
|
114
|
-
- No catalog fetch during setup;
|
|
115
|
-
|
|
179
|
+
- No catalog fetch during setup; discovery is caller-gated and bounded.
|
|
180
|
+
- No automatic environment, file, keychain, or shell credential lookup.
|
|
116
181
|
- API keys are resolved per request from caller-supplied values or resolvers and
|
|
117
|
-
redacted from errors.
|
|
182
|
+
redacted from errors (including discovery failures).
|
|
118
183
|
- Caller-supplied `ProviderRequest.options.headers` can add non-owned headers,
|
|
119
184
|
but OpenRouter-owned headers are applied last: `Authorization`,
|
|
120
185
|
`Content-Type`, `X-Session-Id`, `HTTP-Referer`, and `X-Title` cannot be
|
|
@@ -127,9 +192,14 @@ await kernel.load([
|
|
|
127
192
|
## Related APIs
|
|
128
193
|
|
|
129
194
|
- [Provider packages](../provider-packages.md): `defineProviderPackage`,
|
|
130
|
-
`ModelConfig`/`compat`, cache policy,
|
|
195
|
+
`ModelConfig`/`compat`, cache policy, caller-gated discovery.
|
|
196
|
+
- [Thinking and reasoning](../thinking-and-reasoning.md): `applyThinkingLevel`
|
|
197
|
+
/ `openai_reasoning` family for OpenRouter.
|
|
131
198
|
- [Credentials and redaction](../credentials-and-redaction.md):
|
|
132
199
|
`resolveCredentialValue`, `redactSecrets`.
|
|
133
200
|
- [Provider layer](../provider-layer.md): `ProviderRequest.options` and usage
|
|
134
201
|
mapping.
|
|
135
202
|
- [Provider conformance](../provider-conformance.md): network-free adapter tests.
|
|
203
|
+
- Official: [Models API](https://openrouter.ai/docs/api/api-reference/models/get-models),
|
|
204
|
+
[Prompt caching](https://openrouter.ai/docs/guides/best-practices/prompt-caching),
|
|
205
|
+
[Reasoning tokens](https://openrouter.ai/docs/guides/best-practices/reasoning-tokens).
|