@dereekb/openrouter 13.37.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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +195 -0
  3. package/firebase/index.cjs.default.js +1 -0
  4. package/firebase/index.cjs.js +666 -0
  5. package/firebase/index.cjs.mjs +2 -0
  6. package/firebase/index.d.ts +1 -0
  7. package/firebase/index.esm.js +626 -0
  8. package/firebase/package.json +25 -0
  9. package/firebase/src/index.d.ts +1 -0
  10. package/firebase/src/lib/index.d.ts +4 -0
  11. package/firebase/src/lib/openrouter.api.d.ts +226 -0
  12. package/firebase/src/lib/openrouter.id.d.ts +56 -0
  13. package/firebase/src/lib/openrouter.model.d.ts +609 -0
  14. package/firebase/src/lib/openrouter.query.d.ts +121 -0
  15. package/firebase-server/index.cjs.default.js +1 -0
  16. package/firebase-server/index.cjs.js +4520 -0
  17. package/firebase-server/index.cjs.mjs +2 -0
  18. package/firebase-server/index.d.ts +1 -0
  19. package/firebase-server/index.esm.js +4466 -0
  20. package/firebase-server/package.json +38 -0
  21. package/firebase-server/src/index.d.ts +1 -0
  22. package/firebase-server/src/lib/index.d.ts +10 -0
  23. package/firebase-server/src/lib/openrouter.action.server.d.ts +196 -0
  24. package/firebase-server/src/lib/openrouter.broadcast.d.ts +93 -0
  25. package/firebase-server/src/lib/openrouter.call.inline.d.ts +57 -0
  26. package/firebase-server/src/lib/openrouter.file.attachment.d.ts +97 -0
  27. package/firebase-server/src/lib/openrouter.module.d.ts +65 -0
  28. package/firebase-server/src/lib/openrouter.prompt.service.d.ts +109 -0
  29. package/firebase-server/src/lib/openrouter.runtask.handle.d.ts +56 -0
  30. package/firebase-server/src/lib/openrouter.runtask.service.d.ts +380 -0
  31. package/firebase-server/src/lib/openrouter.runtask.sweep.d.ts +170 -0
  32. package/firebase-server/src/lib/openrouter.state.accessor.d.ts +106 -0
  33. package/firebase-server/src/test/openrouter.fake.d.ts +134 -0
  34. package/index.cjs.default.js +1 -0
  35. package/index.cjs.js +1867 -0
  36. package/index.cjs.mjs +2 -0
  37. package/index.d.ts +1 -0
  38. package/index.esm.js +1771 -0
  39. package/package.json +32 -0
  40. package/src/index.d.ts +1 -0
  41. package/src/lib/index.d.ts +10 -0
  42. package/src/lib/openrouter.call.d.ts +268 -0
  43. package/src/lib/openrouter.config.d.ts +314 -0
  44. package/src/lib/openrouter.embedding.d.ts +87 -0
  45. package/src/lib/openrouter.generation.d.ts +46 -0
  46. package/src/lib/openrouter.input.d.ts +238 -0
  47. package/src/lib/openrouter.prompt.d.ts +79 -0
  48. package/src/lib/openrouter.request.d.ts +91 -0
  49. package/src/lib/openrouter.sdk.d.ts +37 -0
  50. package/src/lib/openrouter.tool.d.ts +99 -0
  51. package/src/lib/openrouter.type.d.ts +125 -0
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@dereekb/openrouter",
3
+ "version": "13.37.0",
4
+ "exports": {
5
+ "./firebase": {
6
+ "module": "./firebase/index.esm.js",
7
+ "types": "./firebase/index.d.ts",
8
+ "import": "./firebase/index.cjs.mjs",
9
+ "default": "./firebase/index.cjs.js"
10
+ },
11
+ "./firebase-server": {
12
+ "module": "./firebase-server/index.esm.js",
13
+ "types": "./firebase-server/index.d.ts",
14
+ "import": "./firebase-server/index.cjs.mjs",
15
+ "default": "./firebase-server/index.cjs.js"
16
+ },
17
+ "./package.json": "./package.json",
18
+ ".": {
19
+ "module": "./index.esm.js",
20
+ "types": "./index.d.ts",
21
+ "import": "./index.cjs.mjs",
22
+ "default": "./index.cjs.js"
23
+ }
24
+ },
25
+ "peerDependencies": {
26
+ "@dereekb/util": "13.37.0",
27
+ "@openrouter/sdk": "^1.2.26"
28
+ },
29
+ "module": "./index.esm.js",
30
+ "main": "./index.cjs.js",
31
+ "types": "./index.d.ts"
32
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './lib';
@@ -0,0 +1,10 @@
1
+ export * from './openrouter.call';
2
+ export * from './openrouter.config';
3
+ export * from './openrouter.embedding';
4
+ export * from './openrouter.generation';
5
+ export * from './openrouter.input';
6
+ export * from './openrouter.prompt';
7
+ export * from './openrouter.request';
8
+ export * from './openrouter.sdk';
9
+ export * from './openrouter.tool';
10
+ export * from './openrouter.type';
@@ -0,0 +1,268 @@
1
+ import { type Maybe } from '@dereekb/util';
2
+ import { type CallModelInput, type OpenResponsesResult, type OpenRouterCore, type RequestOptions, type StateAccessor, type Tool, ModelResult } from './openrouter.sdk';
3
+ import { type OpenRouterHostedToolConfig, type OpenRouterModelConfig } from './openrouter.config';
4
+ import { type OpenRouterPromptRequest } from './openrouter.request';
5
+ import { type OpenRouterGenerationId, type OpenRouterRunError, type OpenRouterRunUsage } from './openrouter.type';
6
+ /**
7
+ * A model config split into the part that goes on the request and the part that controls how the
8
+ * request is executed.
9
+ */
10
+ export interface OpenRouterSplitModelConfig {
11
+ /**
12
+ * The parameters to spread onto the request.
13
+ */
14
+ readonly requestConfig: Record<string, unknown>;
15
+ /**
16
+ * Ceiling on tool-call steps, when the config set one.
17
+ */
18
+ readonly maxSteps?: Maybe<number>;
19
+ /**
20
+ * Per-request wall-clock timeout, when the config set one.
21
+ */
22
+ readonly requestTimeoutMs?: Maybe<number>;
23
+ }
24
+ /**
25
+ * Splits a model config into request parameters and execution controls.
26
+ *
27
+ * Forwarding one of ours is not harmless: OpenRouter validates the request body, so leaving `maxSteps` on
28
+ * it risks a 400 on the whole call. Which keys are ours is expressed by naming them in a rest-destructure
29
+ * rather than in a list of strings, so TypeScript checks the names against
30
+ * {@link OpenRouterModelConfig} and a rename cannot leave a stale entry behind.
31
+ *
32
+ * @param config - The merged model config.
33
+ * @returns The split config.
34
+ */
35
+ export declare function splitOpenRouterModelConfig(config: Maybe<OpenRouterModelConfig>): OpenRouterSplitModelConfig;
36
+ /**
37
+ * The hosted (server-executed) tool entries a config carries, e.g. `file_search`, `web_search`, `mcp`.
38
+ *
39
+ * These are NOT client tools and must never be handed to `callModel`: it destructures `tools` off the
40
+ * request and runs every entry through `convertToolsToAPIFormat`, which reads `tool.function.name` — so
41
+ * a hosted entry is dropped outright when no client tools are present and throws a
42
+ * `Cannot read properties of undefined` from inside the SDK when they are. They are dispatched instead
43
+ * by {@link sendOpenRouterResponsesRequest} or merged in after conversion by
44
+ * {@link openRouterModelResultForRequest}.
45
+ *
46
+ * @param config - The merged model config.
47
+ * @returns The hosted tool entries, or an empty array.
48
+ *
49
+ * @__NO_SIDE_EFFECTS__
50
+ */
51
+ export declare function openRouterHostedTools(config: Maybe<OpenRouterModelConfig>): OpenRouterHostedToolConfig[];
52
+ /**
53
+ * A normalized result of one OpenRouter call.
54
+ *
55
+ * Deliberately flat and provider-agnostic: this is what a run task stores and what a caller reads,
56
+ * so it must not require the caller to walk the SDK's response union.
57
+ */
58
+ export interface OpenRouterCallResult {
59
+ /**
60
+ * The output text.
61
+ */
62
+ readonly outputText?: Maybe<string>;
63
+ /**
64
+ * The output parsed as JSON, when it parsed as an object.
65
+ */
66
+ readonly outputJson?: Maybe<Record<string, unknown>>;
67
+ /**
68
+ * Generation ids produced by the call, for auditing via `getGeneration` / `listGenerationContent`.
69
+ *
70
+ * OpenRouter can reload a generation's output later, keyed by generation id — but that surface is
71
+ * tied to account logging settings (nothing is retained under ZDR / logging-disabled) and its
72
+ * retention is undocumented. Treat it as audit/debug, never the system of record.
73
+ */
74
+ readonly generationIds: OpenRouterGenerationId[];
75
+ /**
76
+ * Token/cost usage.
77
+ */
78
+ readonly usage?: Maybe<OpenRouterRunUsage>;
79
+ /**
80
+ * The model that actually served the request.
81
+ */
82
+ readonly model?: Maybe<string>;
83
+ /**
84
+ * The error reported by OpenRouter, when the response carried one.
85
+ */
86
+ readonly error?: Maybe<OpenRouterRunError>;
87
+ /**
88
+ * The raw response, for anything the normalized shape drops.
89
+ */
90
+ readonly response: OpenResponsesResult;
91
+ }
92
+ /**
93
+ * Params for {@link openRouterCallModelInput}.
94
+ */
95
+ export interface OpenRouterCallModelInputParams<TTools extends readonly Tool[] = readonly Tool[]> {
96
+ /**
97
+ * The built request.
98
+ */
99
+ readonly request: OpenRouterPromptRequest;
100
+ /**
101
+ * Client-side tools to make available.
102
+ */
103
+ readonly tools?: Maybe<TTools>;
104
+ /**
105
+ * Conversation state backend, for a multi-step or deferred-tool run.
106
+ */
107
+ readonly state?: Maybe<StateAccessor<TTools>>;
108
+ }
109
+ /**
110
+ * Converts a built request into the `/responses` request body.
111
+ *
112
+ * This is the whole wire body minus the SDK-only keys (`tools`/`state`/`stopWhen` on the `callModel`
113
+ * path), so both dispatch paths assemble the request the same way and cannot drift.
114
+ *
115
+ * @param request - The built request.
116
+ * @returns The request body, in the SDK's camelCase request surface.
117
+ */
118
+ export declare function openRouterResponsesRequestBody(request: OpenRouterPromptRequest): Record<string, unknown>;
119
+ /**
120
+ * Converts a built request into the `callModel` input.
121
+ *
122
+ * Any hosted tools on the config are STRIPPED here rather than passed through: `callModel` owns the
123
+ * `tools` key and converts every entry as a client function tool. Hosted entries are re-attached after
124
+ * that conversion by {@link openRouterModelResultForRequest}.
125
+ *
126
+ * @param params - The request, tools, and state accessor.
127
+ * @returns The `callModel` input.
128
+ */
129
+ export declare function openRouterCallModelInput<TTools extends readonly Tool[] = readonly Tool[]>(params: OpenRouterCallModelInputParams<TTools>): CallModelInput<TTools>;
130
+ /**
131
+ * Params for {@link callModelForOpenRouterRequest}.
132
+ */
133
+ export interface CallModelForOpenRouterRequestParams<TTools extends readonly Tool[] = readonly Tool[]> extends OpenRouterCallModelInputParams<TTools> {
134
+ /**
135
+ * The OpenRouter client.
136
+ */
137
+ readonly client: OpenRouterCore;
138
+ /**
139
+ * Additional request options, merged under the config's `requestTimeoutMs`.
140
+ */
141
+ readonly options?: Maybe<RequestOptions>;
142
+ }
143
+ /**
144
+ * Header `callModel` stamps on every request it dispatches, so OpenRouter can tell an agent-loop request
145
+ * apart from a plain one. Replicated on the merged hosted-tool path, which is a `callModel` request in
146
+ * everything but the entry point.
147
+ */
148
+ export declare const OPENROUTER_CALL_MODEL_HEADER = "x-openrouter-callmodel";
149
+ /**
150
+ * Params for {@link sendOpenRouterResponsesRequest}.
151
+ */
152
+ export interface SendOpenRouterResponsesRequestParams {
153
+ /**
154
+ * The OpenRouter client.
155
+ */
156
+ readonly client: OpenRouterCore;
157
+ /**
158
+ * The built request.
159
+ */
160
+ readonly request: OpenRouterPromptRequest;
161
+ /**
162
+ * Additional request options, merged under the config's `requestTimeoutMs`.
163
+ */
164
+ readonly options?: Maybe<RequestOptions>;
165
+ }
166
+ /**
167
+ * Sends a built request straight to `/responses`, bypassing `callModel` entirely.
168
+ *
169
+ * This is the path hosted (server-executed) tools take. `callModel` cannot carry them — it converts
170
+ * every `tools` entry as a client function tool — and there is nothing for its loop to do on a run whose
171
+ * tools are executed upstream anyway. Going direct also keeps the response VERBATIM: the request is
172
+ * non-streaming, so the returned `OpenResponsesResult` is the body OpenRouter sent rather than one
173
+ * reassembled from stream events, which is what preserves hosted-tool output items such as a
174
+ * `file_search_call` and the chunks `include: ['file_search_call.results']` asked for.
175
+ *
176
+ * @param params - The client, request, and options.
177
+ * @returns The response.
178
+ * @throws {Error} When the request fails, or when a streaming response comes back for a non-streaming request.
179
+ */
180
+ export declare function sendOpenRouterResponsesRequest(params: SendOpenRouterResponsesRequestParams): Promise<OpenResponsesResult>;
181
+ /**
182
+ * Starts a call for a built request and returns the SDK's `ModelResult` without consuming it.
183
+ *
184
+ * Use this when the caller needs the streaming / tool-event surface. Most callers want
185
+ * {@link callModelForOpenRouterRequest}, which consumes the result into a normalized value.
186
+ *
187
+ * Hosted tools and client tools are NOT mutually exclusive here. When a config carries hosted tools this
188
+ * assembles the `ModelResult` itself — client tools converted to API format exactly as `callModel` would,
189
+ * with the hosted entries appended after that conversion — so a run can search a vector store AND drive
190
+ * the client-side tool loop. `callModel` cannot express that: it owns the `tools` key and there is no
191
+ * seam between its conversion and dispatch. Everything else about the run is unchanged, including the
192
+ * `x-openrouter-callmodel` header and the `stopWhen` step ceiling.
193
+ *
194
+ * @param params - The client, request, tools, state, and options.
195
+ * @returns The in-flight model result.
196
+ */
197
+ export declare function openRouterModelResultForRequest<TTools extends readonly Tool[] = readonly Tool[]>(params: CallModelForOpenRouterRequestParams<TTools>): ModelResult<TTools>;
198
+ /**
199
+ * Runs a built request to completion and normalizes the response.
200
+ *
201
+ * Routes to the direct `/responses` path for a hosted-tool run that needs no client-side tool loop, and
202
+ * to `ModelResult` otherwise. The caller does not choose: which transport a request needs is a property
203
+ * of the request, and making it a parameter would only create a way to get it wrong.
204
+ *
205
+ * @param params - The client, request, tools, state, and options.
206
+ * @returns The normalized call result.
207
+ */
208
+ export declare function callModelForOpenRouterRequest<TTools extends readonly Tool[] = readonly Tool[]>(params: CallModelForOpenRouterRequestParams<TTools>): Promise<OpenRouterCallResult>;
209
+ /**
210
+ * Normalizes an OpenRouter response into an {@link OpenRouterCallResult}.
211
+ *
212
+ * @param response - The response to normalize.
213
+ * @returns The normalized result.
214
+ */
215
+ export declare function openRouterCallResultFromResponse(response: OpenResponsesResult): OpenRouterCallResult;
216
+ /**
217
+ * Reads the assistant text out of a response.
218
+ *
219
+ * The convenience `output_text` field is NOT populated by OpenRouter's `/responses` API — verified live,
220
+ * on both a streaming and a non-streaming request: the body carries `output` items (`reasoning`, then
221
+ * `message`) and no `output_text` at all. Reading that field alone therefore returns undefined for every
222
+ * real call, so a run task would store an empty `o` on a call that answered perfectly well and was
223
+ * charged for.
224
+ *
225
+ * Text is concatenated across ALL message items rather than just the first, since nothing guarantees a
226
+ * response is limited to one.
227
+ *
228
+ * @param response - The response.
229
+ * @returns The output text, or undefined when the response carried none.
230
+ */
231
+ export declare function openRouterOutputTextFromResponse(response: OpenResponsesResult): Maybe<string>;
232
+ /**
233
+ * Flattens the SDK's nested usage object.
234
+ *
235
+ * A measurement the response did not report is OMITTED rather than carried as `undefined` or `null`.
236
+ *
237
+ * @param usage - The SDK usage object.
238
+ * @returns The flattened usage.
239
+ *
240
+ * @__NO_SIDE_EFFECTS__
241
+ */
242
+ export declare function openRouterRunUsageFromResponseUsage(usage: NonNullable<OpenResponsesResult['usage']>): OpenRouterRunUsage;
243
+ /**
244
+ * Flattens the error an OpenRouter response reports in its body.
245
+ *
246
+ * Named rather than inlined at the one call site for the same reason
247
+ * {@link openRouterRunUsageFromResponseUsage} is: a library that exports `OpenRouterRunError` as a type
248
+ * should let a caller holding a raw `OpenResponsesResult` produce one without transcribing its shape.
249
+ *
250
+ * `code` goes through `String()` because OpenRouter reports a NUMERIC code here (the HTTP status), while
251
+ * `OpenRouterRunError.code` is a string — the same field an SDK-thrown error fills with `ECONNRESET`.
252
+ *
253
+ * @param error - The error reported on the response.
254
+ * @returns The flattened error.
255
+ *
256
+ * @__NO_SIDE_EFFECTS__
257
+ */
258
+ export declare function openRouterRunErrorFromResponseError(error: NonNullable<OpenResponsesResult['error']>): OpenRouterRunError;
259
+ /**
260
+ * Parses model output as a JSON object.
261
+ *
262
+ * Returns undefined rather than throwing on anything that is not a JSON object: a model asked for
263
+ * text can and will return prose, and that is not an error.
264
+ *
265
+ * @param outputText - The output text.
266
+ * @returns The parsed object, or undefined when the output is not a JSON object.
267
+ */
268
+ export declare function parseOpenRouterJsonOutput(outputText: Maybe<string>): Maybe<Record<string, unknown>>;
@@ -0,0 +1,314 @@
1
+ import { type Maybe } from '@dereekb/util';
2
+ import { type OpenRouterModelId } from './openrouter.type';
3
+ /**
4
+ * Reasoning effort accepted by OpenRouter's `reasoning.effort`.
5
+ */
6
+ export type OpenRouterReasoningEffort = 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
7
+ /**
8
+ * Reasoning mode accepted by OpenRouter's `reasoning.mode`.
9
+ */
10
+ export type OpenRouterReasoningMode = 'standard' | 'pro';
11
+ /**
12
+ * Reasoning summary verbosity accepted by OpenRouter's `reasoning.summary`.
13
+ */
14
+ export type OpenRouterReasoningSummary = 'auto' | 'concise' | 'detailed';
15
+ /**
16
+ * Output verbosity accepted by OpenRouter's `text.verbosity`.
17
+ *
18
+ * This is the OpenAI-dashboard "Verbosity" control.
19
+ */
20
+ export type OpenRouterVerbosity = 'low' | 'medium' | 'high' | 'xhigh' | 'max';
21
+ /**
22
+ * Reasoning configuration. Replaces the OpenAI dashboard's reasoning mode / effort / summary
23
+ * controls.
24
+ */
25
+ export interface OpenRouterReasoningConfig {
26
+ readonly enabled?: Maybe<boolean>;
27
+ readonly effort?: Maybe<OpenRouterReasoningEffort>;
28
+ readonly mode?: Maybe<OpenRouterReasoningMode>;
29
+ readonly summary?: Maybe<OpenRouterReasoningSummary>;
30
+ /**
31
+ * Named `max_tokens` on the wire — the SDK does not camelCase this one.
32
+ */
33
+ readonly max_tokens?: Maybe<number>;
34
+ }
35
+ /**
36
+ * A JSON-schema output format, replacing the OpenAI dashboard's structured-output setting.
37
+ */
38
+ export interface OpenRouterJsonSchemaFormat {
39
+ readonly type: 'json_schema';
40
+ readonly name: string;
41
+ readonly strict?: Maybe<boolean>;
42
+ readonly schema: Record<string, unknown>;
43
+ }
44
+ /**
45
+ * Output format, replacing the OpenAI dashboard's "Text format" setting.
46
+ */
47
+ export type OpenRouterTextFormat = {
48
+ readonly type: 'text';
49
+ } | {
50
+ readonly type: 'json_object';
51
+ } | OpenRouterJsonSchemaFormat;
52
+ /**
53
+ * Text/output configuration — OpenRouter's `text` object.
54
+ */
55
+ export interface OpenRouterTextConfig {
56
+ readonly format?: Maybe<OpenRouterTextFormat>;
57
+ readonly verbosity?: Maybe<OpenRouterVerbosity>;
58
+ }
59
+ /**
60
+ * Provider routing configuration — OpenRouter's `provider` object.
61
+ *
62
+ * Pinning matters more than it looks: without `requireParameters`, OpenRouter's docs state
63
+ * "providers will receive only the parameters they support, and ignore the rest", so an unpinned
64
+ * call can silently drop a parameter and return a confidently wrong answer with no error.
65
+ */
66
+ export interface OpenRouterProviderConfig {
67
+ readonly only?: Maybe<string[]>;
68
+ readonly order?: Maybe<string[]>;
69
+ readonly ignore?: Maybe<string[]>;
70
+ readonly allowFallbacks?: Maybe<boolean>;
71
+ readonly requireParameters?: Maybe<boolean>;
72
+ readonly dataCollection?: Maybe<'allow' | 'deny'>;
73
+ readonly sort?: Maybe<string | Record<string, unknown>>;
74
+ readonly quantizations?: Maybe<string[]>;
75
+ readonly zdr?: Maybe<boolean>;
76
+ readonly maxPrice?: Maybe<Record<string, string>>;
77
+ }
78
+ /**
79
+ * PDF parsing engine for the `file-parser` plugin.
80
+ *
81
+ * - `native` — the model provider parses the PDF itself (OpenAI, on our BYOK key), billed as input
82
+ * tokens, with no image cap. ONLY valid on a model with native file input: OpenRouter forwards the
83
+ * raw file part upstream, and a text-only model rejects the whole request with a 400
84
+ * (`Provider returned error`, wrapping the provider's own `Unknown part type: file`). Verified live
85
+ * against `nvidia/nemotron-nano-9b-v2:free`.
86
+ * - `pdf-text` — OpenRouter extracts the PDF's embedded text itself. Free, and valid on EVERY model
87
+ * because the model only ever sees text. Yields nothing for a scanned/image-only PDF, so the model
88
+ * answers ungrounded with no error — which is why it is not the default.
89
+ * - `mistral-ocr` — Mistral's OCR service, billed by OpenRouter per page, capped at 8 images per PDF
90
+ * with the surplus silently dropped.
91
+ * - `cloudflare-ai` — Cloudflare Workers AI, free, PDF to markdown.
92
+ */
93
+ export type OpenRouterPdfParserEngine = 'native' | 'pdf-text' | 'mistral-ocr' | 'cloudflare-ai';
94
+ /**
95
+ * The `file-parser` plugin. Replaces OpenAI's code-interpreter/file-upload path for PDF input.
96
+ */
97
+ export interface OpenRouterFileParserPluginConfig {
98
+ readonly id: 'file-parser';
99
+ readonly enabled?: Maybe<boolean>;
100
+ readonly pdf?: Maybe<{
101
+ readonly engine?: Maybe<OpenRouterPdfParserEngine>;
102
+ }>;
103
+ }
104
+ /**
105
+ * Any OpenRouter plugin entry. Only `file-parser` is modeled precisely; the rest are passed through.
106
+ */
107
+ export type OpenRouterPluginConfig = OpenRouterFileParserPluginConfig | ({
108
+ readonly id: string;
109
+ } & Record<string, unknown>);
110
+ /**
111
+ * A hosted (server-executed) tool entry, e.g. a `file_search` or `mcp` tool.
112
+ */
113
+ export type OpenRouterHostedToolConfig = {
114
+ readonly type: string;
115
+ } & Record<string, unknown>;
116
+ /**
117
+ * The hosted `file_search` tool.
118
+ *
119
+ * Field names are CAMELCASE, matching the SDK's request surface rather than the wire. That is not a
120
+ * style choice: `@openrouter/sdk` validates the request body against a closed schema that names this
121
+ * field `vectorStoreIds` and remaps it to `vector_store_ids` on the way out — so a config authored with
122
+ * the wire name is dropped during serialization, and the call goes out with a `file_search` tool that
123
+ * searches nothing. OpenRouter answers it anyway, confidently and ungrounded, with no error.
124
+ */
125
+ export interface OpenRouterFileSearchToolConfig {
126
+ readonly type: 'file_search';
127
+ /**
128
+ * The OpenAI vector stores to search. A `vs_…` id resolves only for the org that owns it, so this
129
+ * works only where OpenRouter authenticates upstream with a BYOK key from that org.
130
+ *
131
+ * The passthrough itself is verified: OpenRouter forwards the tool to OpenAI, which resolves the id.
132
+ * See `openrouter.filesearch.spike.spec.ts`.
133
+ */
134
+ readonly vectorStoreIds: string[];
135
+ readonly maxNumResults?: Maybe<number>;
136
+ readonly rankingOptions?: Maybe<{
137
+ readonly ranker?: Maybe<string>;
138
+ readonly scoreThreshold?: Maybe<number>;
139
+ }>;
140
+ readonly filters?: Maybe<Record<string, unknown>>;
141
+ /**
142
+ * Passthrough for anything the hosted tool grows that this interface does not yet name.
143
+ */
144
+ readonly [key: string]: unknown;
145
+ }
146
+ /**
147
+ * Builds a hosted `file_search` tool entry with the field names the SDK actually forwards.
148
+ *
149
+ * @param vectorStoreIds - The `vs_…` ids to search.
150
+ * @param maxNumResults - Optional cap on returned chunks.
151
+ * @returns The hosted tool entry.
152
+ *
153
+ * @__NO_SIDE_EFFECTS__
154
+ */
155
+ export declare function openRouterFileSearchTool(vectorStoreIds: string[], maxNumResults?: Maybe<number>): OpenRouterFileSearchToolConfig;
156
+ /**
157
+ * The default PDF parser engine this package pins.
158
+ *
159
+ * Pinned because the alternative is silent: with no engine named, OpenRouter downgrades any model it
160
+ * believes lacks native file support to `mistral-ocr`, inheriting its 8-image cap and per-page billing with
161
+ * no error — which on a multi-page document quietly truncates content.
162
+ *
163
+ * `native` rather than the equally-free `pdf-text` because it fails LOUDLY. It requires a model with
164
+ * native file input and 400s on one without, where `pdf-text` would hand a scanned PDF to the model as
165
+ * empty text and let it answer ungrounded. A caller on a text-only model wants
166
+ * `openRouterFileParserPlugin('pdf-text')` — see {@link OpenRouterPdfParserEngine}.
167
+ */
168
+ export declare const DEFAULT_OPENROUTER_PDF_PARSER_ENGINE: OpenRouterPdfParserEngine;
169
+ /**
170
+ * The `file-parser` plugin entry with the PDF engine pinned.
171
+ *
172
+ * @param engine - Engine to pin. Defaults to {@link DEFAULT_OPENROUTER_PDF_PARSER_ENGINE}.
173
+ * @returns The plugin config entry.
174
+ *
175
+ * @__NO_SIDE_EFFECTS__
176
+ */
177
+ export declare function openRouterFileParserPlugin(engine?: OpenRouterPdfParserEngine): OpenRouterFileParserPluginConfig;
178
+ /**
179
+ * A provider config that pins routing to a single provider with fallbacks off and parameter support
180
+ * required — the configuration that makes a BYOK request actually reach the intended upstream with
181
+ * every parameter intact.
182
+ *
183
+ * @param provider - The provider slug to pin to (e.g. `openai`).
184
+ * @returns The provider routing config.
185
+ *
186
+ * @__NO_SIDE_EFFECTS__
187
+ */
188
+ export declare function openRouterProviderPinnedTo(provider: string): OpenRouterProviderConfig;
189
+ /**
190
+ * Model configuration for an OpenRouter prompt version, or a per-run override of one.
191
+ *
192
+ * Field names follow the `@openrouter/sdk` request surface (camelCase), because a merged config is
193
+ * spread directly into `callModel`. The SDK converts them to the wire's snake_case names.
194
+ *
195
+ * This interface exists for autocomplete and optional call-time validation ONLY — the persisted
196
+ * value is passthrough JSON, deliberately not a strict Firestore converter. OpenRouter's parameter
197
+ * surface moves fast (the previously pinned `0.12.79` SDK was already missing several params present
198
+ * in `1.2.x`), and a strict converter would silently drop unknown fields on every release. Strict
199
+ * types in code, loose storage: hence the index signature.
200
+ *
201
+ * Concepts with no OpenRouter equivalent are deliberately absent. OpenAI's "Store logs" is one —
202
+ * OpenRouter is stateless and `store` is type-pinned to `false`.
203
+ */
204
+ export interface OpenRouterModelConfig {
205
+ /**
206
+ * Primary model to route to.
207
+ */
208
+ readonly model?: Maybe<OpenRouterModelId>;
209
+ /**
210
+ * Fallback chain, tried in order when the primary model is unavailable.
211
+ */
212
+ readonly models?: Maybe<OpenRouterModelId[]>;
213
+ /**
214
+ * Output format + verbosity.
215
+ */
216
+ readonly text?: Maybe<OpenRouterTextConfig>;
217
+ /**
218
+ * Reasoning mode / effort / summary.
219
+ */
220
+ readonly reasoning?: Maybe<OpenRouterReasoningConfig>;
221
+ /**
222
+ * Provider routing — where BYOK pinning goes.
223
+ */
224
+ readonly provider?: Maybe<OpenRouterProviderConfig>;
225
+ /**
226
+ * Plugins: `file-parser`, `web`, `context-compression`.
227
+ */
228
+ readonly plugins?: Maybe<OpenRouterPluginConfig[]>;
229
+ /**
230
+ * Hosted (server-executed) tools, e.g. `file_search`, `mcp`, `web_search`.
231
+ *
232
+ * A config carrying any of these is dispatched off the `callModel` path — `callModel` converts every
233
+ * `tools` entry as a client function tool — and goes either straight to `/responses` or through a
234
+ * `ModelResult` that appends them after client-tool conversion. See `openRouterHostedTools`.
235
+ */
236
+ readonly tools?: Maybe<OpenRouterHostedToolConfig[]>;
237
+ readonly toolChoice?: Maybe<unknown>;
238
+ readonly parallelToolCalls?: Maybe<boolean>;
239
+ readonly maxToolCalls?: Maybe<number>;
240
+ /**
241
+ * Extra response parts to include, e.g. `file_search_call.results`.
242
+ */
243
+ readonly include?: Maybe<string[]>;
244
+ readonly maxOutputTokens?: Maybe<number>;
245
+ readonly temperature?: Maybe<number>;
246
+ readonly topP?: Maybe<number>;
247
+ readonly topK?: Maybe<number>;
248
+ readonly seed?: Maybe<number>;
249
+ readonly stop?: Maybe<string | string[]>;
250
+ readonly frequencyPenalty?: Maybe<number>;
251
+ readonly presencePenalty?: Maybe<number>;
252
+ readonly promptCacheKey?: Maybe<string>;
253
+ readonly truncation?: Maybe<string>;
254
+ readonly user?: Maybe<string>;
255
+ /**
256
+ * Ceiling on tool-call steps, passed to the Agent SDK's `stopWhen`.
257
+ *
258
+ * NOTE: this bounds the number of tool-call rounds, NOT the duration of one inference. A single
259
+ * inference is atomic and cannot be interrupted — use {@link requestTimeoutMs} for that.
260
+ */
261
+ readonly maxSteps?: Maybe<number>;
262
+ /**
263
+ * Per-request wall-clock timeout in milliseconds.
264
+ *
265
+ * The one bound on a single inference. Required in practice for the run-task sweeper: without it,
266
+ * one unusually slow call can overrun the sweep's time budget and delay every other workload
267
+ * sharing the runner.
268
+ */
269
+ readonly requestTimeoutMs?: Maybe<number>;
270
+ /**
271
+ * Passthrough for parameters this interface does not yet name.
272
+ */
273
+ readonly [key: string]: unknown;
274
+ }
275
+ /**
276
+ * Merges model configs left-to-right, so the last input wins.
277
+ *
278
+ * Merging is SHALLOW by key: an override that supplies `provider` replaces the whole provider object
279
+ * rather than merging into it. That is the behaviour a caller wants — a half-overridden `provider`
280
+ * (say, `only` from the override and `allowFallbacks` from the version) is a configuration nobody
281
+ * wrote down and nobody can reason about.
282
+ *
283
+ * `undefined` values do not overwrite; an explicit `null` does (it is how a caller clears a value
284
+ * the version set).
285
+ *
286
+ * @param configs - Configs to merge, lowest priority first.
287
+ * @returns The merged config.
288
+ */
289
+ export declare function mergeOpenRouterModelConfig(configs: Maybe<OpenRouterModelConfig>[]): OpenRouterModelConfig;
290
+ /**
291
+ * Result of validating an {@link OpenRouterModelConfig}.
292
+ */
293
+ export interface OpenRouterModelConfigValidation {
294
+ /**
295
+ * Whether the config is usable as-is.
296
+ */
297
+ readonly valid: boolean;
298
+ /**
299
+ * Problems that make the config unusable.
300
+ */
301
+ readonly errors: string[];
302
+ /**
303
+ * Problems that do not prevent the call but will very likely produce a wrong result.
304
+ */
305
+ readonly warnings: string[];
306
+ }
307
+ /**
308
+ * Validates a merged model config, catching the misconfigurations that fail silently at runtime
309
+ * rather than loudly.
310
+ *
311
+ * @param config - The merged config to check.
312
+ * @returns The validation result.
313
+ */
314
+ export declare function validateOpenRouterModelConfig(config: Maybe<OpenRouterModelConfig>): OpenRouterModelConfigValidation;