@namzu/openrouter 1.1.0 → 2.0.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 CHANGED
@@ -1,5 +1,76 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 48d9d67: Published tarballs no longer contain test files.
8
+
9
+ `files: ["dist", "src", ...]` reads as "the build output and the sources" and
10
+ means "everything the compiler emitted and everything in the tree", so every
11
+ compiled test, its declaration, and both source maps shipped to the registry —
12
+ and for the twelve packages that also ship `src`, the raw test sources went with
13
+ them.
14
+
15
+ Measured on the versions currently published:
16
+
17
+ | package | files | of which tests | unpacked |
18
+ | ------------ | ----------- | -------------- | ------------------ |
19
+ | `@namzu/sdk` | 3879 → 2239 | 1640 (42%) | 12.73 MB → 6.81 MB |
20
+ | `@namzu/cli` | 462 → 282 | 180 (39%) | 1.21 MB → 0.73 MB |
21
+
22
+ Nothing you can import changes. Every package restricts `exports` to `"."`, so
23
+ Node refused a deep subpath into those files already — they were weight in the
24
+ tarball and nothing else. Hence `patch`: there is no consumer-visible surface
25
+ here, only less to download.
26
+
27
+ The exclusions are at the packaging layer, not the compiler. Adding `exclude`
28
+ to `tsconfig.json` would have kept tests out of `dist` and also dropped them
29
+ from `tsc --noEmit`, silently ending type-checking of the entire test suite —
30
+ trading a packaging defect for a much worse one.
31
+
32
+ ## 2.0.0
33
+
34
+ ### Major Changes
35
+
36
+ - 1500973: Every driver that cannot think now says so instead of dropping the request.
37
+
38
+ `thinking` sits on `ChatCompletionParams`, so every driver accepts it. Five of
39
+ them — Bedrock, OpenRouter, HTTP, Ollama, LM Studio — implemented none of it
40
+ and dropped the field: the caller got an ordinary completion with an empty
41
+ `reasoning` array, which is indistinguishable from a model that simply chose
42
+ not to reason. The request looked honoured and the answer looked like an
43
+ answer.
44
+
45
+ The OpenAI driver already refused instead, with the reasoning written out
46
+ beside it. So the rule had been decided once and applied once, while five
47
+ siblings went on being silent. It moves to `@namzu/sdk` as
48
+ `assertThinkingUnsupported(driverName, params)`, and a new driver now inherits
49
+ it rather than re-deciding it.
50
+
51
+ The error names the driver, which in a multi-provider setup is the difference
52
+ between a bug report about the model and a one-line configuration fix.
53
+
54
+ **Turning thinking off stays a no-op** on all of them, because that is the
55
+ state a driver without thinking is already in — a config shared across
56
+ providers saying `{ type: 'disabled' }` should not fail on the ones that were
57
+ never going to think.
58
+
59
+ `assertThinkingSupported` in `@namzu/openai` is unchanged as an export and now
60
+ delegates to the shared helper. Its message changed: it no longer says
61
+ "extended thinking", because `adaptive` is refused too and calling that
62
+ extended would be wrong.
63
+
64
+ **Migration.** If you passed `thinking` to any of the five and relied on it
65
+ being ignored, remove it — you were receiving a non-thinking answer either way,
66
+ and now you find out at the call instead of by inspecting an empty array.
67
+
68
+ Not in this change: implementing thinking natively on Bedrock, which serves the
69
+ same Claude models through a different wire and deserves the per-model
70
+ resolution the Anthropic driver just gained. That needs the Converse request
71
+ and response shapes verified against the reference first, and is not something
72
+ to guess at.
73
+
3
74
  ## 1.1.0
4
75
 
5
76
  ### Minor Changes
@@ -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;AAQnB,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;IAclB,OAAO,CAAC,cAAc;IAwBtB,OAAO,CAAC,gBAAgB;IAqCjB,UAAU,CAAC,MAAM,EAAE,oBAAoB,GAAG,aAAa,CAAC,WAAW,CAAC;IAkIrE,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IA+BlC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;CAWrC"}
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;AASnB,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;IAclB,OAAO,CAAC,cAAc;IAwBtB,OAAO,CAAC,gBAAgB;IAqCjB,UAAU,CAAC,MAAM,EAAE,oBAAoB,GAAG,aAAa,CAAC,WAAW,CAAC;IAmIrE,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IA+BlC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;CAWrC"}
package/dist/client.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ProviderRequestError, isCallerAbortError, isProviderRequestError, providerHttpError, providerVendorError, } from '@namzu/sdk';
1
+ import { ProviderRequestError, assertThinkingUnsupported, isCallerAbortError, isProviderRequestError, providerHttpError, providerVendorError, } from '@namzu/sdk';
2
2
  const OPENROUTER_BASE_URL = process.env.OPENROUTER_BASE_URL ?? 'https://openrouter.ai/api/v1';
3
3
  function parseUsage(raw) {
4
4
  if (!raw) {
@@ -126,6 +126,7 @@ export class OpenRouterProvider {
126
126
  return body;
127
127
  }
128
128
  async *chatStream(params) {
129
+ assertThinkingUnsupported('OpenRouterProvider', params);
129
130
  const body = this.buildRequestBody(params, true);
130
131
  const timeout = AbortSignal.timeout(this.config.timeout ?? 120_000);
131
132
  // Compose the caller abort with the request timeout so a Stop cancels the
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
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": "1.1.0",
3
+ "version": "2.0.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",
@@ -23,7 +23,17 @@
23
23
  },
24
24
  "files": [
25
25
  "dist",
26
+ "!dist/**/*.test.*",
27
+ "!dist/**/*.proc-test.*",
28
+ "!dist/**/__tests__",
29
+ "!dist/**/__fixtures__",
30
+ "!dist/**/test-setup.*",
26
31
  "src",
32
+ "!src/**/*.test.*",
33
+ "!src/**/*.proc-test.*",
34
+ "!src/**/__tests__",
35
+ "!src/**/__fixtures__",
36
+ "!src/**/test-setup.*",
27
37
  "LICENSE.md",
28
38
  "README.md",
29
39
  "CHANGELOG.md"
@@ -42,7 +52,7 @@
42
52
  "@types/node": "^22.19.17",
43
53
  "typescript": "^5.5.0",
44
54
  "vitest": "^3.2.6",
45
- "@namzu/sdk": "^3.0.0"
55
+ "@namzu/sdk": "^15.0.0"
46
56
  },
47
57
  "scripts": {
48
58
  "build": "tsc --build",
package/src/client.ts CHANGED
@@ -9,6 +9,7 @@ import type {
9
9
  } from '@namzu/sdk'
10
10
  import {
11
11
  ProviderRequestError,
12
+ assertThinkingUnsupported,
12
13
  isCallerAbortError,
13
14
  isProviderRequestError,
14
15
  providerHttpError,
@@ -161,6 +162,7 @@ export class OpenRouterProvider implements LLMProvider {
161
162
  }
162
163
 
163
164
  async *chatStream(params: ChatCompletionParams): AsyncIterable<StreamChunk> {
165
+ assertThinkingUnsupported('OpenRouterProvider', params)
164
166
  const body = this.buildRequestBody(params, true)
165
167
 
166
168
  const timeout = AbortSignal.timeout(this.config.timeout ?? 120_000)
@@ -1,15 +0,0 @@
1
- /**
2
- * Provider error taxonomy — OpenRouter driver.
3
- *
4
- * Every provider failure must reach the caller as a classified
5
- * `ProviderRequestError` (kind + status + retryAfterMs + providerId), not
6
- * as an opaque vendor string. The message must be built from the status
7
- * line and the classified kind ONLY — never from the response body, which
8
- * is where a credential echoed back by the upstream would leak into a log.
9
- *
10
- * Transport seam: the driver calls the global `fetch` directly, so the
11
- * existing `vi.stubGlobal('fetch', …)` harness from `http.test.ts` applies
12
- * verbatim.
13
- */
14
- export {};
15
- //# sourceMappingURL=error-taxonomy.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"error-taxonomy.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/error-taxonomy.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
@@ -1,187 +0,0 @@
1
- /**
2
- * Provider error taxonomy — OpenRouter driver.
3
- *
4
- * Every provider failure must reach the caller as a classified
5
- * `ProviderRequestError` (kind + status + retryAfterMs + providerId), not
6
- * as an opaque vendor string. The message must be built from the status
7
- * line and the classified kind ONLY — never from the response body, which
8
- * is where a credential echoed back by the upstream would leak into a log.
9
- *
10
- * Transport seam: the driver calls the global `fetch` directly, so the
11
- * existing `vi.stubGlobal('fetch', …)` harness from `http.test.ts` applies
12
- * verbatim.
13
- */
14
- import { afterEach, describe, expect, it, vi } from 'vitest';
15
- import { OpenRouterProvider } from '../client.js';
16
- /**
17
- * An obviously fake, non-functional token. Present ONLY to prove the
18
- * driver does not interpolate a response body into a thrown message.
19
- */
20
- const FAKE_CREDENTIAL = 'sk-ant-FAKE-DO-NOT-USE-0000';
21
- afterEach(() => {
22
- vi.unstubAllGlobals();
23
- });
24
- function respond(status, body, headers = {}) {
25
- return new Response(body, {
26
- status,
27
- headers: { 'Content-Type': 'application/json', ...headers },
28
- });
29
- }
30
- function sseResponse(frames) {
31
- return new Response(`${frames.join('\n\n')}\n\n`, {
32
- status: 200,
33
- headers: { 'Content-Type': 'text/event-stream' },
34
- });
35
- }
36
- async function captureChatStreamError(provider, signal) {
37
- try {
38
- for await (const _chunk of provider.chatStream({
39
- model: 'anthropic/claude-sonnet-4-5',
40
- messages: [{ role: 'user', content: 'hi' }],
41
- signal,
42
- })) {
43
- // drain
44
- }
45
- }
46
- catch (err) {
47
- return err;
48
- }
49
- throw new Error('expected chatStream to throw');
50
- }
51
- function makeProvider() {
52
- return new OpenRouterProvider({
53
- apiKey: 'test-key',
54
- baseUrl: 'https://example.test/api/v1',
55
- });
56
- }
57
- describe('@namzu/openrouter — provider error taxonomy', () => {
58
- it('(a) 429 with `retry-after: 2` throws a throttle-classified error carrying retryAfterMs', async () => {
59
- vi.stubGlobal('fetch', vi.fn().mockResolvedValue(respond(429, JSON.stringify({ error: { message: 'rate limit exceeded' } }), {
60
- 'retry-after': '2',
61
- })));
62
- const err = await captureChatStreamError(makeProvider());
63
- expect(err).toMatchObject({
64
- name: 'ProviderRequestError',
65
- kind: 'throttle',
66
- status: 429,
67
- retryAfterMs: 2000,
68
- providerId: 'openrouter',
69
- });
70
- });
71
- it("(c) 400 whose body says the prompt is too long classifies as 'context_overflow'", async () => {
72
- vi.stubGlobal('fetch', vi.fn().mockResolvedValue(respond(400, JSON.stringify({
73
- error: {
74
- type: 'invalid_request_error',
75
- message: 'prompt is too long: 305231 tokens > 200000 maximum',
76
- },
77
- }))));
78
- const err = await captureChatStreamError(makeProvider());
79
- expect(err).toMatchObject({
80
- name: 'ProviderRequestError',
81
- kind: 'context_overflow',
82
- status: 400,
83
- providerId: 'openrouter',
84
- });
85
- });
86
- it("(c) 400 that is not an overflow classifies as 'bad_request'", async () => {
87
- vi.stubGlobal('fetch', vi.fn().mockResolvedValue(respond(400, JSON.stringify({
88
- error: {
89
- type: 'invalid_request_error',
90
- message: "unknown field 'temperture'",
91
- },
92
- }))));
93
- const err = await captureChatStreamError(makeProvider());
94
- expect(err).toMatchObject({
95
- name: 'ProviderRequestError',
96
- kind: 'bad_request',
97
- status: 400,
98
- providerId: 'openrouter',
99
- });
100
- });
101
- it("(a/auth) 401 classifies as 'auth'", async () => {
102
- vi.stubGlobal('fetch', vi
103
- .fn()
104
- .mockResolvedValue(respond(401, JSON.stringify({ error: { message: 'No auth credentials found' } }))));
105
- const err = await captureChatStreamError(makeProvider());
106
- expect(err).toMatchObject({
107
- name: 'ProviderRequestError',
108
- kind: 'auth',
109
- status: 401,
110
- providerId: 'openrouter',
111
- });
112
- });
113
- it('(d) SECURITY: a credential echoed back in a 401 body never reaches the thrown message', async () => {
114
- vi.stubGlobal('fetch', vi.fn().mockResolvedValue(respond(401, JSON.stringify({
115
- error: { message: `invalid api key: ${FAKE_CREDENTIAL}` },
116
- }))));
117
- const err = await captureChatStreamError(makeProvider());
118
- expect(err).toBeInstanceOf(Error);
119
- const message = err.message;
120
- expect(message).not.toContain(FAKE_CREDENTIAL);
121
- expect(JSON.stringify(err)).not.toContain(FAKE_CREDENTIAL);
122
- expect('cause' in err).toBe(false);
123
- });
124
- it('(d) SECURITY: a credential echoed back in a 400 body never reaches the thrown message', async () => {
125
- vi.stubGlobal('fetch', vi
126
- .fn()
127
- .mockResolvedValue(respond(400, `bad request for key ${FAKE_CREDENTIAL}: model not permitted`)));
128
- const err = await captureChatStreamError(makeProvider());
129
- expect(err.message).not.toContain(FAKE_CREDENTIAL);
130
- });
131
- it("classifies a fetch rejection as 'network' without retaining its cause", async () => {
132
- const vendor = new Error(`socket failed for ${FAKE_CREDENTIAL}`);
133
- vi.stubGlobal('fetch', vi.fn().mockRejectedValue(vendor));
134
- const err = await captureChatStreamError(makeProvider());
135
- expect(err).toMatchObject({
136
- name: 'ProviderRequestError',
137
- kind: 'network',
138
- providerId: 'openrouter',
139
- });
140
- expect(err.message).not.toContain(FAKE_CREDENTIAL);
141
- expect('cause' in err).toBe(false);
142
- });
143
- it('preserves the caller abort reason when fetch replaces the error object', async () => {
144
- const controller = new AbortController();
145
- const reason = new Error('user stopped');
146
- const fetchAbort = Object.assign(new Error('request aborted'), {
147
- name: 'AbortError',
148
- });
149
- controller.abort(reason);
150
- vi.stubGlobal('fetch', vi.fn().mockRejectedValue(fetchAbort));
151
- const err = await captureChatStreamError(makeProvider(), controller.signal);
152
- expect(fetchAbort).not.toBe(reason);
153
- expect(err).toBe(reason);
154
- });
155
- it('classifies and sanitizes an SSE error after the 200 response', async () => {
156
- vi.stubGlobal('fetch', vi.fn().mockResolvedValue(sseResponse([
157
- `data: ${JSON.stringify({
158
- error: {
159
- type: 'overloaded_error',
160
- message: `echoed ${FAKE_CREDENTIAL}`,
161
- },
162
- })}`,
163
- ])));
164
- const err = await captureChatStreamError(makeProvider());
165
- expect(err).toMatchObject({
166
- name: 'ProviderRequestError',
167
- kind: 'server',
168
- providerId: 'openrouter',
169
- });
170
- expect(err.message).not.toContain(FAKE_CREDENTIAL);
171
- expect(JSON.stringify(err)).not.toContain(FAKE_CREDENTIAL);
172
- expect('cause' in err).toBe(false);
173
- });
174
- it('classifies malformed SSE without retaining the credential-bearing frame', async () => {
175
- vi.stubGlobal('fetch', vi.fn().mockResolvedValue(sseResponse([`data: ${FAKE_CREDENTIAL} not-json`])));
176
- const err = await captureChatStreamError(makeProvider());
177
- expect(err).toMatchObject({
178
- name: 'ProviderRequestError',
179
- kind: 'server',
180
- providerId: 'openrouter',
181
- });
182
- expect(err.message).not.toContain(FAKE_CREDENTIAL);
183
- expect(JSON.stringify(err)).not.toContain(FAKE_CREDENTIAL);
184
- expect('cause' in err).toBe(false);
185
- });
186
- });
187
- //# sourceMappingURL=error-taxonomy.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"error-taxonomy.test.js","sourceRoot":"","sources":["../../src/__tests__/error-taxonomy.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=openrouter.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"openrouter.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/openrouter.test.ts"],"names":[],"mappings":""}
@@ -1,85 +0,0 @@
1
- import { DuplicateProviderError, ProviderRegistry } from '@namzu/sdk';
2
- import { beforeEach, describe, expect, it } from 'vitest';
3
- import { OPENROUTER_CAPABILITIES, OpenRouterProvider, registerOpenRouter } from '../index.js';
4
- // Ensure a clean slate between tests. The sdk pre-registers 'mock' on import
5
- // via its sideEffects whitelist; we only need to clear 'openrouter' to make
6
- // re-registration deterministic across tests.
7
- beforeEach(() => {
8
- if (ProviderRegistry.isSupported('openrouter')) {
9
- ProviderRegistry.unregister('openrouter');
10
- }
11
- });
12
- describe('@namzu/openrouter', () => {
13
- describe('registerOpenRouter()', () => {
14
- it("adds 'openrouter' to the ProviderRegistry", () => {
15
- expect(ProviderRegistry.isSupported('openrouter')).toBe(false);
16
- registerOpenRouter();
17
- expect(ProviderRegistry.isSupported('openrouter')).toBe(true);
18
- expect(ProviderRegistry.listTypes()).toContain('openrouter');
19
- });
20
- it('throws DuplicateProviderError when called twice without options', () => {
21
- registerOpenRouter();
22
- expect(() => registerOpenRouter()).toThrowError(DuplicateProviderError);
23
- });
24
- it('allows re-registration when { replace: true } is passed', () => {
25
- registerOpenRouter();
26
- expect(() => registerOpenRouter({ replace: true })).not.toThrow();
27
- expect(ProviderRegistry.isSupported('openrouter')).toBe(true);
28
- });
29
- it('exposes capabilities through the registry after registration', () => {
30
- registerOpenRouter();
31
- const caps = ProviderRegistry.getCapabilities('openrouter');
32
- expect(caps).toEqual(OPENROUTER_CAPABILITIES);
33
- });
34
- });
35
- describe('OPENROUTER_CAPABILITIES', () => {
36
- it('declares the expected capability flags', () => {
37
- expect(OPENROUTER_CAPABILITIES).toEqual({
38
- supportsTools: true,
39
- supportsStreaming: true,
40
- supportsFunctionCalling: true,
41
- supportsVision: false,
42
- supportsDocuments: false,
43
- });
44
- });
45
- it('is exposed on the provider instance for runtime negotiation', () => {
46
- const provider = new OpenRouterProvider({ apiKey: 'test-key' });
47
- expect(provider.capabilities).toEqual(OPENROUTER_CAPABILITIES);
48
- });
49
- });
50
- describe('ProviderRegistry.create({ type: "openrouter", ... })', () => {
51
- it('narrows the config type via module augmentation and instantiates OpenRouterProvider', () => {
52
- registerOpenRouter();
53
- const { provider, capabilities } = ProviderRegistry.create({
54
- type: 'openrouter',
55
- apiKey: 'test-key',
56
- siteUrl: 'https://example.com',
57
- siteName: 'Test',
58
- });
59
- expect(provider).toBeInstanceOf(OpenRouterProvider);
60
- expect(capabilities).toEqual(OPENROUTER_CAPABILITIES);
61
- });
62
- });
63
- it('keeps the Namzu enforcement hint out of the OpenRouter request body', () => {
64
- const provider = new OpenRouterProvider({ apiKey: 'test-key' });
65
- const tools = [
66
- {
67
- type: 'function',
68
- function: {
69
- name: 'edit',
70
- description: 'Edit',
71
- parameters: { type: 'object' },
72
- },
73
- },
74
- ];
75
- const body = provider.buildRequestBody({
76
- model: 'anthropic/claude-sonnet-5',
77
- messages: [{ role: 'user', content: 'edit' }],
78
- tools,
79
- enforceToolInputSchema: ['edit'],
80
- }, true);
81
- expect(body).not.toHaveProperty('enforceToolInputSchema');
82
- expect(body.tools).toEqual(tools);
83
- });
84
- });
85
- //# sourceMappingURL=openrouter.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"openrouter.test.js","sourceRoot":"","sources":["../../src/__tests__/openrouter.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=vision.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vision.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/vision.test.ts"],"names":[],"mappings":""}
@@ -1,42 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { OPENROUTER_CAPABILITIES } from '../client.js';
3
- /**
4
- * This driver does not map attachments, and says so.
5
- *
6
- * Shipping without a wire shape is legitimate; claiming one you do not have
7
- * is not. The runtime reads these flags and warns — or fails under
8
- * `strictCapabilities` — before the request is built, so the flags are the
9
- * contract, and what this pins is drift in either direction: flipping a
10
- * flag without writing the mapping makes the runtime stop warning about
11
- * images that still vanish, and writing the mapping without flipping the
12
- * flag makes it keep warning about images that now arrive.
13
- */
14
- describe('the declared capabilities are the honest ones', () => {
15
- it('does not claim vision', () => {
16
- expect(OPENROUTER_CAPABILITIES.supportsVision).toBe(false);
17
- });
18
- it('does not claim documents', () => {
19
- expect(OPENROUTER_CAPABILITIES.supportsDocuments).toBe(false);
20
- });
21
- it('claims the tool support it does have', () => {
22
- expect(OPENROUTER_CAPABILITIES.supportsTools).toBe(true);
23
- expect(OPENROUTER_CAPABILITIES.supportsFunctionCalling).toBe(true);
24
- });
25
- it('claims streaming', () => {
26
- expect(OPENROUTER_CAPABILITIES.supportsStreaming).toBe(true);
27
- });
28
- it('answers every flag the negotiation reads', () => {
29
- // An absent flag defaults to permissive, so a missing one is not a
30
- // neutral omission — it is a claim.
31
- for (const flag of [
32
- 'supportsTools',
33
- 'supportsStreaming',
34
- 'supportsFunctionCalling',
35
- 'supportsVision',
36
- 'supportsDocuments',
37
- ]) {
38
- expect(typeof OPENROUTER_CAPABILITIES[flag]).toBe('boolean');
39
- }
40
- });
41
- });
42
- //# sourceMappingURL=vision.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vision.test.js","sourceRoot":"","sources":["../../src/__tests__/vision.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAEtD;;;;;;;;;;GAUG;AAEH,QAAQ,CAAC,+CAA+C,EAAE,GAAG,EAAE;IAC9D,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,uBAAuB,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC3D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,uBAAuB,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC9D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,uBAAuB,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACxD,MAAM,CAAC,uBAAuB,CAAC,uBAAuB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACnE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC3B,MAAM,CAAC,uBAAuB,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC7D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QACnD,mEAAmE;QACnE,oCAAoC;QACpC,KAAK,MAAM,IAAI,IAAI;YAClB,eAAe;YACf,mBAAmB;YACnB,yBAAyB;YACzB,gBAAgB;YAChB,mBAAmB;SACV,EAAE,CAAC;YACZ,MAAM,CAAC,OAAO,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC7D,CAAC;IACF,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -1,272 +0,0 @@
1
- /**
2
- * Provider error taxonomy — OpenRouter driver.
3
- *
4
- * Every provider failure must reach the caller as a classified
5
- * `ProviderRequestError` (kind + status + retryAfterMs + providerId), not
6
- * as an opaque vendor string. The message must be built from the status
7
- * line and the classified kind ONLY — never from the response body, which
8
- * is where a credential echoed back by the upstream would leak into a log.
9
- *
10
- * Transport seam: the driver calls the global `fetch` directly, so the
11
- * existing `vi.stubGlobal('fetch', …)` harness from `http.test.ts` applies
12
- * verbatim.
13
- */
14
-
15
- import { afterEach, describe, expect, it, vi } from 'vitest'
16
- import { OpenRouterProvider } from '../client.js'
17
-
18
- /**
19
- * An obviously fake, non-functional token. Present ONLY to prove the
20
- * driver does not interpolate a response body into a thrown message.
21
- */
22
- const FAKE_CREDENTIAL = 'sk-ant-FAKE-DO-NOT-USE-0000'
23
-
24
- afterEach(() => {
25
- vi.unstubAllGlobals()
26
- })
27
-
28
- function respond(status: number, body: string, headers: Record<string, string> = {}): Response {
29
- return new Response(body, {
30
- status,
31
- headers: { 'Content-Type': 'application/json', ...headers },
32
- })
33
- }
34
-
35
- function sseResponse(frames: string[]): Response {
36
- return new Response(`${frames.join('\n\n')}\n\n`, {
37
- status: 200,
38
- headers: { 'Content-Type': 'text/event-stream' },
39
- })
40
- }
41
-
42
- async function captureChatStreamError(
43
- provider: OpenRouterProvider,
44
- signal?: AbortSignal,
45
- ): Promise<unknown> {
46
- try {
47
- for await (const _chunk of provider.chatStream({
48
- model: 'anthropic/claude-sonnet-4-5',
49
- messages: [{ role: 'user', content: 'hi' }],
50
- signal,
51
- })) {
52
- // drain
53
- }
54
- } catch (err) {
55
- return err
56
- }
57
- throw new Error('expected chatStream to throw')
58
- }
59
-
60
- function makeProvider(): OpenRouterProvider {
61
- return new OpenRouterProvider({
62
- apiKey: 'test-key',
63
- baseUrl: 'https://example.test/api/v1',
64
- })
65
- }
66
-
67
- describe('@namzu/openrouter — provider error taxonomy', () => {
68
- it('(a) 429 with `retry-after: 2` throws a throttle-classified error carrying retryAfterMs', async () => {
69
- vi.stubGlobal(
70
- 'fetch',
71
- vi.fn().mockResolvedValue(
72
- respond(429, JSON.stringify({ error: { message: 'rate limit exceeded' } }), {
73
- 'retry-after': '2',
74
- }),
75
- ),
76
- )
77
-
78
- const err = await captureChatStreamError(makeProvider())
79
-
80
- expect(err).toMatchObject({
81
- name: 'ProviderRequestError',
82
- kind: 'throttle',
83
- status: 429,
84
- retryAfterMs: 2000,
85
- providerId: 'openrouter',
86
- })
87
- })
88
-
89
- it("(c) 400 whose body says the prompt is too long classifies as 'context_overflow'", async () => {
90
- vi.stubGlobal(
91
- 'fetch',
92
- vi.fn().mockResolvedValue(
93
- respond(
94
- 400,
95
- JSON.stringify({
96
- error: {
97
- type: 'invalid_request_error',
98
- message: 'prompt is too long: 305231 tokens > 200000 maximum',
99
- },
100
- }),
101
- ),
102
- ),
103
- )
104
-
105
- const err = await captureChatStreamError(makeProvider())
106
-
107
- expect(err).toMatchObject({
108
- name: 'ProviderRequestError',
109
- kind: 'context_overflow',
110
- status: 400,
111
- providerId: 'openrouter',
112
- })
113
- })
114
-
115
- it("(c) 400 that is not an overflow classifies as 'bad_request'", async () => {
116
- vi.stubGlobal(
117
- 'fetch',
118
- vi.fn().mockResolvedValue(
119
- respond(
120
- 400,
121
- JSON.stringify({
122
- error: {
123
- type: 'invalid_request_error',
124
- message: "unknown field 'temperture'",
125
- },
126
- }),
127
- ),
128
- ),
129
- )
130
-
131
- const err = await captureChatStreamError(makeProvider())
132
-
133
- expect(err).toMatchObject({
134
- name: 'ProviderRequestError',
135
- kind: 'bad_request',
136
- status: 400,
137
- providerId: 'openrouter',
138
- })
139
- })
140
-
141
- it("(a/auth) 401 classifies as 'auth'", async () => {
142
- vi.stubGlobal(
143
- 'fetch',
144
- vi
145
- .fn()
146
- .mockResolvedValue(
147
- respond(401, JSON.stringify({ error: { message: 'No auth credentials found' } })),
148
- ),
149
- )
150
-
151
- const err = await captureChatStreamError(makeProvider())
152
-
153
- expect(err).toMatchObject({
154
- name: 'ProviderRequestError',
155
- kind: 'auth',
156
- status: 401,
157
- providerId: 'openrouter',
158
- })
159
- })
160
-
161
- it('(d) SECURITY: a credential echoed back in a 401 body never reaches the thrown message', async () => {
162
- vi.stubGlobal(
163
- 'fetch',
164
- vi.fn().mockResolvedValue(
165
- respond(
166
- 401,
167
- JSON.stringify({
168
- error: { message: `invalid api key: ${FAKE_CREDENTIAL}` },
169
- }),
170
- ),
171
- ),
172
- )
173
-
174
- const err = await captureChatStreamError(makeProvider())
175
-
176
- expect(err).toBeInstanceOf(Error)
177
- const message = (err as Error).message
178
- expect(message).not.toContain(FAKE_CREDENTIAL)
179
- expect(JSON.stringify(err)).not.toContain(FAKE_CREDENTIAL)
180
- expect('cause' in (err as object)).toBe(false)
181
- })
182
-
183
- it('(d) SECURITY: a credential echoed back in a 400 body never reaches the thrown message', async () => {
184
- vi.stubGlobal(
185
- 'fetch',
186
- vi
187
- .fn()
188
- .mockResolvedValue(
189
- respond(400, `bad request for key ${FAKE_CREDENTIAL}: model not permitted`),
190
- ),
191
- )
192
-
193
- const err = await captureChatStreamError(makeProvider())
194
-
195
- expect((err as Error).message).not.toContain(FAKE_CREDENTIAL)
196
- })
197
-
198
- it("classifies a fetch rejection as 'network' without retaining its cause", async () => {
199
- const vendor = new Error(`socket failed for ${FAKE_CREDENTIAL}`)
200
- vi.stubGlobal('fetch', vi.fn().mockRejectedValue(vendor))
201
-
202
- const err = await captureChatStreamError(makeProvider())
203
-
204
- expect(err).toMatchObject({
205
- name: 'ProviderRequestError',
206
- kind: 'network',
207
- providerId: 'openrouter',
208
- })
209
- expect((err as Error).message).not.toContain(FAKE_CREDENTIAL)
210
- expect('cause' in (err as object)).toBe(false)
211
- })
212
-
213
- it('preserves the caller abort reason when fetch replaces the error object', async () => {
214
- const controller = new AbortController()
215
- const reason = new Error('user stopped')
216
- const fetchAbort = Object.assign(new Error('request aborted'), {
217
- name: 'AbortError',
218
- })
219
- controller.abort(reason)
220
- vi.stubGlobal('fetch', vi.fn().mockRejectedValue(fetchAbort))
221
-
222
- const err = await captureChatStreamError(makeProvider(), controller.signal)
223
-
224
- expect(fetchAbort).not.toBe(reason)
225
- expect(err).toBe(reason)
226
- })
227
-
228
- it('classifies and sanitizes an SSE error after the 200 response', async () => {
229
- vi.stubGlobal(
230
- 'fetch',
231
- vi.fn().mockResolvedValue(
232
- sseResponse([
233
- `data: ${JSON.stringify({
234
- error: {
235
- type: 'overloaded_error',
236
- message: `echoed ${FAKE_CREDENTIAL}`,
237
- },
238
- })}`,
239
- ]),
240
- ),
241
- )
242
-
243
- const err = await captureChatStreamError(makeProvider())
244
-
245
- expect(err).toMatchObject({
246
- name: 'ProviderRequestError',
247
- kind: 'server',
248
- providerId: 'openrouter',
249
- })
250
- expect((err as Error).message).not.toContain(FAKE_CREDENTIAL)
251
- expect(JSON.stringify(err)).not.toContain(FAKE_CREDENTIAL)
252
- expect('cause' in (err as object)).toBe(false)
253
- })
254
-
255
- it('classifies malformed SSE without retaining the credential-bearing frame', async () => {
256
- vi.stubGlobal(
257
- 'fetch',
258
- vi.fn().mockResolvedValue(sseResponse([`data: ${FAKE_CREDENTIAL} not-json`])),
259
- )
260
-
261
- const err = await captureChatStreamError(makeProvider())
262
-
263
- expect(err).toMatchObject({
264
- name: 'ProviderRequestError',
265
- kind: 'server',
266
- providerId: 'openrouter',
267
- })
268
- expect((err as Error).message).not.toContain(FAKE_CREDENTIAL)
269
- expect(JSON.stringify(err)).not.toContain(FAKE_CREDENTIAL)
270
- expect('cause' in (err as object)).toBe(false)
271
- })
272
- })
@@ -1,104 +0,0 @@
1
- import { DuplicateProviderError, ProviderRegistry } from '@namzu/sdk'
2
- import { beforeEach, describe, expect, it } from 'vitest'
3
- import { OPENROUTER_CAPABILITIES, OpenRouterProvider, registerOpenRouter } from '../index.js'
4
-
5
- // Ensure a clean slate between tests. The sdk pre-registers 'mock' on import
6
- // via its sideEffects whitelist; we only need to clear 'openrouter' to make
7
- // re-registration deterministic across tests.
8
- beforeEach(() => {
9
- if (ProviderRegistry.isSupported('openrouter')) {
10
- ProviderRegistry.unregister('openrouter')
11
- }
12
- })
13
-
14
- describe('@namzu/openrouter', () => {
15
- describe('registerOpenRouter()', () => {
16
- it("adds 'openrouter' to the ProviderRegistry", () => {
17
- expect(ProviderRegistry.isSupported('openrouter')).toBe(false)
18
- registerOpenRouter()
19
- expect(ProviderRegistry.isSupported('openrouter')).toBe(true)
20
- expect(ProviderRegistry.listTypes()).toContain('openrouter')
21
- })
22
-
23
- it('throws DuplicateProviderError when called twice without options', () => {
24
- registerOpenRouter()
25
- expect(() => registerOpenRouter()).toThrowError(DuplicateProviderError)
26
- })
27
-
28
- it('allows re-registration when { replace: true } is passed', () => {
29
- registerOpenRouter()
30
- expect(() => registerOpenRouter({ replace: true })).not.toThrow()
31
- expect(ProviderRegistry.isSupported('openrouter')).toBe(true)
32
- })
33
-
34
- it('exposes capabilities through the registry after registration', () => {
35
- registerOpenRouter()
36
- const caps = ProviderRegistry.getCapabilities('openrouter')
37
- expect(caps).toEqual(OPENROUTER_CAPABILITIES)
38
- })
39
- })
40
-
41
- describe('OPENROUTER_CAPABILITIES', () => {
42
- it('declares the expected capability flags', () => {
43
- expect(OPENROUTER_CAPABILITIES).toEqual({
44
- supportsTools: true,
45
- supportsStreaming: true,
46
- supportsFunctionCalling: true,
47
- supportsVision: false,
48
- supportsDocuments: false,
49
- })
50
- })
51
-
52
- it('is exposed on the provider instance for runtime negotiation', () => {
53
- const provider = new OpenRouterProvider({ apiKey: 'test-key' })
54
- expect(provider.capabilities).toEqual(OPENROUTER_CAPABILITIES)
55
- })
56
- })
57
-
58
- describe('ProviderRegistry.create({ type: "openrouter", ... })', () => {
59
- it('narrows the config type via module augmentation and instantiates OpenRouterProvider', () => {
60
- registerOpenRouter()
61
- const { provider, capabilities } = ProviderRegistry.create({
62
- type: 'openrouter',
63
- apiKey: 'test-key',
64
- siteUrl: 'https://example.com',
65
- siteName: 'Test',
66
- })
67
- expect(provider).toBeInstanceOf(OpenRouterProvider)
68
- expect(capabilities).toEqual(OPENROUTER_CAPABILITIES)
69
- })
70
- })
71
-
72
- it('keeps the Namzu enforcement hint out of the OpenRouter request body', () => {
73
- const provider = new OpenRouterProvider({ apiKey: 'test-key' })
74
- const tools = [
75
- {
76
- type: 'function' as const,
77
- function: {
78
- name: 'edit',
79
- description: 'Edit',
80
- parameters: { type: 'object' },
81
- },
82
- },
83
- ]
84
- const body = (
85
- provider as unknown as {
86
- buildRequestBody(
87
- params: import('@namzu/sdk').ChatCompletionParams,
88
- stream: boolean,
89
- ): Record<string, unknown>
90
- }
91
- ).buildRequestBody(
92
- {
93
- model: 'anthropic/claude-sonnet-5',
94
- messages: [{ role: 'user', content: 'edit' }],
95
- tools,
96
- enforceToolInputSchema: ['edit'],
97
- },
98
- true,
99
- )
100
-
101
- expect(body).not.toHaveProperty('enforceToolInputSchema')
102
- expect(body.tools).toEqual(tools)
103
- })
104
- })
@@ -1,48 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
-
3
- import { OPENROUTER_CAPABILITIES } from '../client.js'
4
-
5
- /**
6
- * This driver does not map attachments, and says so.
7
- *
8
- * Shipping without a wire shape is legitimate; claiming one you do not have
9
- * is not. The runtime reads these flags and warns — or fails under
10
- * `strictCapabilities` — before the request is built, so the flags are the
11
- * contract, and what this pins is drift in either direction: flipping a
12
- * flag without writing the mapping makes the runtime stop warning about
13
- * images that still vanish, and writing the mapping without flipping the
14
- * flag makes it keep warning about images that now arrive.
15
- */
16
-
17
- describe('the declared capabilities are the honest ones', () => {
18
- it('does not claim vision', () => {
19
- expect(OPENROUTER_CAPABILITIES.supportsVision).toBe(false)
20
- })
21
-
22
- it('does not claim documents', () => {
23
- expect(OPENROUTER_CAPABILITIES.supportsDocuments).toBe(false)
24
- })
25
-
26
- it('claims the tool support it does have', () => {
27
- expect(OPENROUTER_CAPABILITIES.supportsTools).toBe(true)
28
- expect(OPENROUTER_CAPABILITIES.supportsFunctionCalling).toBe(true)
29
- })
30
-
31
- it('claims streaming', () => {
32
- expect(OPENROUTER_CAPABILITIES.supportsStreaming).toBe(true)
33
- })
34
-
35
- it('answers every flag the negotiation reads', () => {
36
- // An absent flag defaults to permissive, so a missing one is not a
37
- // neutral omission — it is a claim.
38
- for (const flag of [
39
- 'supportsTools',
40
- 'supportsStreaming',
41
- 'supportsFunctionCalling',
42
- 'supportsVision',
43
- 'supportsDocuments',
44
- ] as const) {
45
- expect(typeof OPENROUTER_CAPABILITIES[flag]).toBe('boolean')
46
- }
47
- })
48
- })