@namzu/openrouter 2.1.0 → 2.2.1
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 +49 -0
- package/README.md +46 -61
- package/dist/client.d.ts +24 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +48 -0
- package/dist/client.js.map +1 -1
- package/package.json +2 -2
- package/src/client.ts +55 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,54 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 5394981: Make each driver's README an npm package page rather than its manual.
|
|
8
|
+
|
|
9
|
+
Every driver README carried its full reference — configuration tables, capability matrices, error surfaces — between 167 and 392 lines of it. That is a reasonable shape for a single-package repository, where the README _is_ the documentation, and the wrong one for a package in a monorepo that has a `docs/` tree: it duplicates what the docs say, and nothing checks that the two agree.
|
|
10
|
+
|
|
11
|
+
The README is now what a reader needs in the first minute — what the driver is, install, one working example, links. The reference moved to `docs/providers/<name>.md`, whole, and its code samples are now compiled against the built SDK by the doc-fence gate on every CI run. They never were before; several did not compile.
|
|
12
|
+
|
|
13
|
+
No API change.
|
|
14
|
+
|
|
15
|
+
## 2.2.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- 70f23bb: A driver can now say how large a model's context window is, and the kernel
|
|
20
|
+
ranks that above its hand-maintained table.
|
|
21
|
+
|
|
22
|
+
That table was the only source below an explicit host config, and its own
|
|
23
|
+
header records what it cost: every Claude entry carried 200k including the
|
|
24
|
+
1M-window models, so those runs compacted at roughly 14% full and threw
|
|
25
|
+
away the prompt-cache prefix to do it. Every model release drifts it again
|
|
26
|
+
until somebody edits it — while the OpenRouter driver was already parsing
|
|
27
|
+
the vendor's real `context_length` and discarding it, because there was no
|
|
28
|
+
member to return it through.
|
|
29
|
+
|
|
30
|
+
`LLMProvider.resolveContextWindow?(model, signal)` is three-state like
|
|
31
|
+
`effortLevelsFor`: absent means this driver cannot answer, a resolved
|
|
32
|
+
`undefined` means it asked and does not know, a number is the answer. A
|
|
33
|
+
driver resolving `undefined` falls through to the TABLE, not to the
|
|
34
|
+
assumed default — asking must never be worse than not asking.
|
|
35
|
+
|
|
36
|
+
Resolved once per run, at the door. Both consumers are synchronous and in
|
|
37
|
+
the hot loop, so this can never become an await inside it. A driver that
|
|
38
|
+
rejects or hangs does not fail the run: the window is an optimisation over
|
|
39
|
+
a working default.
|
|
40
|
+
|
|
41
|
+
`ResolvedContextWindow['source']` and the `windowSource` on
|
|
42
|
+
`token_usage_updated` gain `'provider'`, ranked between `'config'` and
|
|
43
|
+
`'model-table'`, so a host can see which route a number came from.
|
|
44
|
+
|
|
45
|
+
Also fixes a hole this exposed: `withProviderRetry` and
|
|
46
|
+
`withProviderFallback` forwarded `listModels`, `healthCheck` and
|
|
47
|
+
`doctorCheck` but not `effortLevelsFor`. A dropped optional member does not
|
|
48
|
+
fail — it reads as "this driver cannot answer" — and retry is on by
|
|
49
|
+
default, so a driver's declared effort levels were invisible on
|
|
50
|
+
essentially every run.
|
|
51
|
+
|
|
3
52
|
## 2.1.0
|
|
4
53
|
|
|
5
54
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
|
-
|
|
1
|
+
<!-- okf
|
|
2
|
+
type: Reference
|
|
3
|
+
title: "@namzu/openrouter"
|
|
4
|
+
description: >-
|
|
5
|
+
Implements the kernel's `LLMProvider` interface over OpenRouter, which
|
|
6
|
+
fronts many vendors behind one key and one wire format.
|
|
7
|
+
tags: [readme, package, provider, openrouter]
|
|
8
|
+
timestamp: 2026-08-17T00:00:00Z
|
|
9
|
+
status: active
|
|
10
|
+
diataxis: reference
|
|
11
|
+
-->
|
|
2
12
|
|
|
3
|
-
|
|
13
|
+
<div align="center">
|
|
14
|
+
|
|
15
|
+
<h1>@namzu/openrouter</h1>
|
|
16
|
+
|
|
17
|
+
**The OpenRouter model driver for [Namzu](https://github.com/cogitave/namzu).**
|
|
18
|
+
|
|
19
|
+
[](https://www.npmjs.com/package/@namzu/openrouter)
|
|
20
|
+
[](https://github.com/cogitave/namzu/actions/workflows/ci.yml)
|
|
21
|
+
[](https://github.com/cogitave/namzu/blob/main/LICENSE.md)
|
|
22
|
+
|
|
23
|
+
[Install](#install) · [Usage](#usage) · [Documentation](#documentation)
|
|
24
|
+
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
Implements the kernel's `LLMProvider` interface over OpenRouter, which
|
|
30
|
+
fronts many vendors behind one key and one wire format. Installed only if
|
|
31
|
+
you use it — the kernel has no preferred vendor and no driver is a
|
|
32
|
+
dependency of it.
|
|
4
33
|
|
|
5
34
|
## Install
|
|
6
35
|
|
|
@@ -8,7 +37,7 @@ OpenRouter LLM provider for [`@namzu/sdk`](https://www.npmjs.com/package/@namzu/
|
|
|
8
37
|
pnpm add @namzu/sdk @namzu/openrouter
|
|
9
38
|
```
|
|
10
39
|
|
|
11
|
-
`@namzu/
|
|
40
|
+
`@namzu/sdk` is a peer dependency. Install both.
|
|
12
41
|
|
|
13
42
|
## Usage
|
|
14
43
|
|
|
@@ -16,76 +45,32 @@ pnpm add @namzu/sdk @namzu/openrouter
|
|
|
16
45
|
import { ProviderRegistry } from '@namzu/sdk'
|
|
17
46
|
import { registerOpenRouter } from '@namzu/openrouter'
|
|
18
47
|
|
|
19
|
-
//
|
|
20
|
-
registerOpenRouter()
|
|
48
|
+
registerOpenRouter() // once, at startup
|
|
21
49
|
|
|
22
|
-
|
|
23
|
-
const { provider, capabilities } = ProviderRegistry.create({
|
|
50
|
+
const { provider } = ProviderRegistry.create({
|
|
24
51
|
type: 'openrouter',
|
|
25
|
-
apiKey: process.env.OPENROUTER_API_KEY
|
|
26
|
-
siteUrl: 'https://
|
|
27
|
-
siteName: '
|
|
52
|
+
apiKey: process.env.OPENROUTER_API_KEY ?? '',
|
|
53
|
+
siteUrl: 'https://example.com', // optional
|
|
54
|
+
siteName: 'Example', // optional
|
|
28
55
|
})
|
|
29
56
|
|
|
30
|
-
const response = await provider.chat({
|
|
31
|
-
model: 'anthropic/claude-sonnet-4',
|
|
32
|
-
messages: [{ role: 'user', content: 'Hello' }],
|
|
33
|
-
})
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Streaming:
|
|
37
|
-
|
|
38
|
-
```ts
|
|
39
57
|
for await (const chunk of provider.chatStream({
|
|
40
|
-
model: '
|
|
41
|
-
messages: [{ role: 'user', content: '
|
|
58
|
+
model: 'anthropic/claude-opus-5',
|
|
59
|
+
messages: [{ role: 'user', content: 'Hello' }],
|
|
42
60
|
})) {
|
|
43
61
|
if (chunk.delta.content) process.stdout.write(chunk.delta.content)
|
|
44
62
|
}
|
|
45
63
|
```
|
|
46
64
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
## Models
|
|
52
|
-
|
|
53
|
-
OpenRouter exposes 200+ models from every major vendor under one unified API. See the [OpenRouter model catalog](https://openrouter.ai/models) for the full list and current pricing. Identifiers follow the `vendor/model-name` pattern:
|
|
54
|
-
|
|
55
|
-
- `anthropic/claude-sonnet-4`
|
|
56
|
-
- `anthropic/claude-haiku-4`
|
|
57
|
-
- `openai/gpt-4o`
|
|
58
|
-
- `openai/gpt-4o-mini`
|
|
59
|
-
- `meta-llama/llama-3.3-70b-instruct`
|
|
60
|
-
- `mistralai/mixtral-8x22b-instruct`
|
|
61
|
-
- `google/gemini-pro-1.5`
|
|
62
|
-
|
|
63
|
-
Pricing is per-million tokens on OpenRouter's catalog — the provider's `listModels()` returns live pricing pulled from the `/models` endpoint.
|
|
64
|
-
|
|
65
|
-
## Base URL override
|
|
66
|
-
|
|
67
|
-
The OpenRouter endpoint defaults to `https://openrouter.ai/api/v1`. Override via the `baseUrl` config field or the `OPENROUTER_BASE_URL` environment variable — useful for OpenRouter-compatible self-hosted gateways.
|
|
68
|
-
|
|
69
|
-
## Capabilities
|
|
70
|
-
|
|
71
|
-
```ts
|
|
72
|
-
import { OPENROUTER_CAPABILITIES } from '@namzu/openrouter'
|
|
73
|
-
|
|
74
|
-
// {
|
|
75
|
-
// supportsTools: true,
|
|
76
|
-
// supportsStreaming: true,
|
|
77
|
-
// supportsFunctionCalling: true,
|
|
78
|
-
// }
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## OpenAI compatibility
|
|
82
|
-
|
|
83
|
-
Because OpenRouter speaks the OpenAI Chat Completions dialect, this provider can also target any OpenAI-compatible endpoint (vLLM, LM Studio, Groq, local OpenAI-compat gateways) by passing `baseUrl` pointing at the alternate endpoint. For a zero-config generic OpenAI-compatible client, use the forthcoming `@namzu/http` package instead.
|
|
65
|
+
`chatStream` is the only model entry point; a non-streaming call is that
|
|
66
|
+
stream collected. In practice the kernel's run loop calls it and hands you
|
|
67
|
+
events.
|
|
84
68
|
|
|
85
|
-
##
|
|
69
|
+
## Documentation
|
|
86
70
|
|
|
87
|
-
|
|
71
|
+
- [The OpenRouter driver — models, the window, credentials and attribution](https://github.com/cogitave/namzu/blob/main/docs/providers/openrouter.md)
|
|
72
|
+
- [Namzu docs](https://github.com/cogitave/namzu/tree/main/docs)
|
|
88
73
|
|
|
89
74
|
## License
|
|
90
75
|
|
|
91
|
-
FSL-1.1-MIT
|
|
76
|
+
FSL-1.1-MIT, converting to MIT two years after each release.
|
package/dist/client.d.ts
CHANGED
|
@@ -33,6 +33,30 @@ export declare class OpenRouterProvider implements LLMProvider {
|
|
|
33
33
|
* key is genuinely refused.
|
|
34
34
|
*/
|
|
35
35
|
probeCredential(): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* The vendor's own `context_length` for this model.
|
|
38
|
+
*
|
|
39
|
+
* This driver already parsed the number and threw it away: `listModels`
|
|
40
|
+
* maps it into `contextWindow` and nothing downstream ever asked. The
|
|
41
|
+
* kernel meanwhile fell back to a hand-maintained prefix table whose own
|
|
42
|
+
* header records what that costs — every Claude entry carried 200k
|
|
43
|
+
* including the 1M-window models, so those runs compacted at roughly 14%
|
|
44
|
+
* full. OpenRouter fronts hundreds of models from a dozen vendors, so it
|
|
45
|
+
* is the driver where a static table drifts fastest.
|
|
46
|
+
*
|
|
47
|
+
* `undefined` for a model the listing does not contain, rather than a
|
|
48
|
+
* guess: "I asked and it is not there" leaves the table exactly as
|
|
49
|
+
* authoritative as it was, while a substituted number would present a
|
|
50
|
+
* guess as a vendor answer.
|
|
51
|
+
*
|
|
52
|
+
* Cached for the process, because a listing of several hundred models is
|
|
53
|
+
* a real payload and a model's window does not change under a running
|
|
54
|
+
* run. A failure is NOT cached — the next run asks again rather than
|
|
55
|
+
* inheriting one bad minute forever.
|
|
56
|
+
*/
|
|
57
|
+
resolveContextWindow(model: string, signal?: AbortSignal): Promise<number | undefined>;
|
|
58
|
+
/** Resolved once per process; see the note on `resolveContextWindow`. */
|
|
59
|
+
private contextWindows?;
|
|
36
60
|
listModels(): Promise<ModelInfo[]>;
|
|
37
61
|
healthCheck(): Promise<boolean>;
|
|
38
62
|
}
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,oBAAoB,EACpB,WAAW,EACX,SAAS,EACT,oBAAoB,EACpB,WAAW,EAGX,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,oBAAoB,EACpB,WAAW,EACX,SAAS,EACT,oBAAoB,EACpB,WAAW,EAGX,MAAM,YAAY,CAAA;AAUnB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAwClD;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,EAAE,oBAOrC,CAAA;AAED,qBAAa,kBAAmB,YAAW,WAAW;IACrD,QAAQ,CAAC,EAAE,gBAAe;IAC1B,QAAQ,CAAC,IAAI,gBAAe;IAC5B,QAAQ,CAAC,YAAY,uBAA0B;IAE/C,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,OAAO,CAAQ;gBAEX,MAAM,EAAE,gBAAgB;IAQpC,OAAO,CAAC,UAAU;IAkBlB,OAAO,CAAC,cAAc;IAwBtB,OAAO,CAAC,gBAAgB;IAqCjB,UAAU,CAAC,MAAM,EAAE,oBAAoB,GAAG,aAAa,CAAC,WAAW,CAAC;IAmI3E;;;;;;;;;;;;;OAaG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAWtC;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IA0B5F,yEAAyE;IACzE,OAAO,CAAC,cAAc,CAAC,CAA8B;IAE/C,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IA+BlC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;CAWrC"}
|
package/dist/client.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ProviderRequestError, assertThinkingUnsupported, isCallerAbortError, isProviderRequestError, providerHttpError, providerVendorError, } from '@namzu/sdk';
|
|
2
|
+
import { attributionHeaders } from '@namzu/sdk';
|
|
2
3
|
const OPENROUTER_BASE_URL = process.env.OPENROUTER_BASE_URL ?? 'https://openrouter.ai/api/v1';
|
|
3
4
|
function parseUsage(raw) {
|
|
4
5
|
if (!raw) {
|
|
@@ -52,6 +53,10 @@ export class OpenRouterProvider {
|
|
|
52
53
|
}
|
|
53
54
|
getHeaders() {
|
|
54
55
|
const headers = {
|
|
56
|
+
// First, so anything a host sets below still wins. Attribution is
|
|
57
|
+
// what this kernel says about itself; a host overriding it has a
|
|
58
|
+
// reason and is not to be argued with.
|
|
59
|
+
...attributionHeaders(),
|
|
55
60
|
Authorization: `Bearer ${this.config.apiKey}`,
|
|
56
61
|
'Content-Type': 'application/json',
|
|
57
62
|
};
|
|
@@ -261,6 +266,49 @@ export class OpenRouterProvider {
|
|
|
261
266
|
throw err;
|
|
262
267
|
}
|
|
263
268
|
}
|
|
269
|
+
/**
|
|
270
|
+
* The vendor's own `context_length` for this model.
|
|
271
|
+
*
|
|
272
|
+
* This driver already parsed the number and threw it away: `listModels`
|
|
273
|
+
* maps it into `contextWindow` and nothing downstream ever asked. The
|
|
274
|
+
* kernel meanwhile fell back to a hand-maintained prefix table whose own
|
|
275
|
+
* header records what that costs — every Claude entry carried 200k
|
|
276
|
+
* including the 1M-window models, so those runs compacted at roughly 14%
|
|
277
|
+
* full. OpenRouter fronts hundreds of models from a dozen vendors, so it
|
|
278
|
+
* is the driver where a static table drifts fastest.
|
|
279
|
+
*
|
|
280
|
+
* `undefined` for a model the listing does not contain, rather than a
|
|
281
|
+
* guess: "I asked and it is not there" leaves the table exactly as
|
|
282
|
+
* authoritative as it was, while a substituted number would present a
|
|
283
|
+
* guess as a vendor answer.
|
|
284
|
+
*
|
|
285
|
+
* Cached for the process, because a listing of several hundred models is
|
|
286
|
+
* a real payload and a model's window does not change under a running
|
|
287
|
+
* run. A failure is NOT cached — the next run asks again rather than
|
|
288
|
+
* inheriting one bad minute forever.
|
|
289
|
+
*/
|
|
290
|
+
async resolveContextWindow(model, signal) {
|
|
291
|
+
const pending = this.contextWindows ??
|
|
292
|
+
(async () => {
|
|
293
|
+
const models = await this.listModels();
|
|
294
|
+
return new Map(models
|
|
295
|
+
.filter((m) => typeof m.contextWindow === 'number')
|
|
296
|
+
.map((m) => [m.id, m.contextWindow]));
|
|
297
|
+
})().catch((err) => {
|
|
298
|
+
// Not cached. A listing endpoint that was down for a minute must
|
|
299
|
+
// not leave every later run answering from that minute.
|
|
300
|
+
this.contextWindows = undefined;
|
|
301
|
+
throw err;
|
|
302
|
+
});
|
|
303
|
+
this.contextWindows = pending;
|
|
304
|
+
const windows = await pending;
|
|
305
|
+
if (signal?.aborted)
|
|
306
|
+
return undefined;
|
|
307
|
+
const reported = windows.get(model);
|
|
308
|
+
return typeof reported === 'number' && reported > 0 ? reported : undefined;
|
|
309
|
+
}
|
|
310
|
+
/** Resolved once per process; see the note on `resolveContextWindow`. */
|
|
311
|
+
contextWindows;
|
|
264
312
|
async listModels() {
|
|
265
313
|
const response = await fetch(`${this.baseUrl}/models`, {
|
|
266
314
|
headers: this.getHeaders(),
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AASA,OAAO,EACN,oBAAoB,EACpB,yBAAyB,EACzB,kBAAkB,EAClB,sBAAsB,EACtB,iBAAiB,EACjB,mBAAmB,GACnB,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@namzu/openrouter",
|
|
3
|
-
"version": "2.1
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "OpenRouter LLM provider for @namzu/sdk. Access to 200+ models (Claude, GPT-4, Llama, Mixtral) via OpenRouter's unified API.",
|
|
5
5
|
"license": "FSL-1.1-MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@types/node": "^22.19.17",
|
|
53
53
|
"typescript": "^5.5.0",
|
|
54
54
|
"vitest": "^3.2.6",
|
|
55
|
-
"@namzu/sdk": "^
|
|
55
|
+
"@namzu/sdk": "^30.0.1"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"build": "tsc --build",
|
package/src/client.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
providerHttpError,
|
|
16
16
|
providerVendorError,
|
|
17
17
|
} from '@namzu/sdk'
|
|
18
|
+
import { attributionHeaders } from '@namzu/sdk'
|
|
18
19
|
import type { OpenRouterConfig } from './types.js'
|
|
19
20
|
|
|
20
21
|
const OPENROUTER_BASE_URL = process.env.OPENROUTER_BASE_URL ?? 'https://openrouter.ai/api/v1'
|
|
@@ -88,6 +89,10 @@ export class OpenRouterProvider implements LLMProvider {
|
|
|
88
89
|
|
|
89
90
|
private getHeaders(): Record<string, string> {
|
|
90
91
|
const headers: Record<string, string> = {
|
|
92
|
+
// First, so anything a host sets below still wins. Attribution is
|
|
93
|
+
// what this kernel says about itself; a host overriding it has a
|
|
94
|
+
// reason and is not to be argued with.
|
|
95
|
+
...attributionHeaders(),
|
|
91
96
|
Authorization: `Bearer ${this.config.apiKey}`,
|
|
92
97
|
'Content-Type': 'application/json',
|
|
93
98
|
}
|
|
@@ -317,6 +322,56 @@ export class OpenRouterProvider implements LLMProvider {
|
|
|
317
322
|
}
|
|
318
323
|
}
|
|
319
324
|
|
|
325
|
+
/**
|
|
326
|
+
* The vendor's own `context_length` for this model.
|
|
327
|
+
*
|
|
328
|
+
* This driver already parsed the number and threw it away: `listModels`
|
|
329
|
+
* maps it into `contextWindow` and nothing downstream ever asked. The
|
|
330
|
+
* kernel meanwhile fell back to a hand-maintained prefix table whose own
|
|
331
|
+
* header records what that costs — every Claude entry carried 200k
|
|
332
|
+
* including the 1M-window models, so those runs compacted at roughly 14%
|
|
333
|
+
* full. OpenRouter fronts hundreds of models from a dozen vendors, so it
|
|
334
|
+
* is the driver where a static table drifts fastest.
|
|
335
|
+
*
|
|
336
|
+
* `undefined` for a model the listing does not contain, rather than a
|
|
337
|
+
* guess: "I asked and it is not there" leaves the table exactly as
|
|
338
|
+
* authoritative as it was, while a substituted number would present a
|
|
339
|
+
* guess as a vendor answer.
|
|
340
|
+
*
|
|
341
|
+
* Cached for the process, because a listing of several hundred models is
|
|
342
|
+
* a real payload and a model's window does not change under a running
|
|
343
|
+
* run. A failure is NOT cached — the next run asks again rather than
|
|
344
|
+
* inheriting one bad minute forever.
|
|
345
|
+
*/
|
|
346
|
+
async resolveContextWindow(model: string, signal?: AbortSignal): Promise<number | undefined> {
|
|
347
|
+
const pending =
|
|
348
|
+
this.contextWindows ??
|
|
349
|
+
(async () => {
|
|
350
|
+
const models = await this.listModels()
|
|
351
|
+
return new Map<string, number>(
|
|
352
|
+
models
|
|
353
|
+
.filter(
|
|
354
|
+
(m): m is typeof m & { contextWindow: number } => typeof m.contextWindow === 'number',
|
|
355
|
+
)
|
|
356
|
+
.map((m) => [m.id, m.contextWindow]),
|
|
357
|
+
)
|
|
358
|
+
})().catch((err: unknown) => {
|
|
359
|
+
// Not cached. A listing endpoint that was down for a minute must
|
|
360
|
+
// not leave every later run answering from that minute.
|
|
361
|
+
this.contextWindows = undefined
|
|
362
|
+
throw err
|
|
363
|
+
})
|
|
364
|
+
this.contextWindows = pending
|
|
365
|
+
|
|
366
|
+
const windows = await pending
|
|
367
|
+
if (signal?.aborted) return undefined
|
|
368
|
+
const reported = windows.get(model)
|
|
369
|
+
return typeof reported === 'number' && reported > 0 ? reported : undefined
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** Resolved once per process; see the note on `resolveContextWindow`. */
|
|
373
|
+
private contextWindows?: Promise<Map<string, number>>
|
|
374
|
+
|
|
320
375
|
async listModels(): Promise<ModelInfo[]> {
|
|
321
376
|
const response = await fetch(`${this.baseUrl}/models`, {
|
|
322
377
|
headers: this.getHeaders(),
|