@pkent/aigateway 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  A provider-neutral LLM client library. One class routes chat / vision /
4
4
  streaming requests to OpenAI, Anthropic, Qwen (Alibaba DashScope), GLM (Zhipu
5
- AI), or OpenRouter based on the model name, and normalizes every response into a
6
- single shape.
5
+ AI), OpenRouter, or an OpenAI-compatible gateway (`aibroker`) based on the model
6
+ name, and normalizes every response into a single shape.
7
7
 
8
8
  No server, no `.env` — all configuration is passed into the constructor.
9
9
 
@@ -49,7 +49,7 @@ new AIGateway(model, key, options?)
49
49
 
50
50
  | Option | Type | Applies to | Default | Description |
51
51
  |-------------|--------|-----------------|------------------|-------------|
52
- | `baseURL` | string | all | provider default | Override the upstream endpoint (regional endpoints, proxies, self-hosted). |
52
+ | `baseURL` | string | all | provider default | Override the upstream endpoint (regional endpoints, proxies, self-hosted). **Required** for `aibroker` (no default). |
53
53
  | `maxTokens` | number | all | unset (see below)| Default max output tokens; a per-call `maxTokens` overrides it. |
54
54
  | `timeout` | number | all | unset (SDK default) | Default per-call request timeout in ms; a per-call `timeout` overrides it. |
55
55
  | `referer` | string | OpenRouter only | omitted | Sent as the `HTTP-Referer` attribution header. |
@@ -71,7 +71,8 @@ AIGateway.providers()
71
71
  // { id: 'anthropic', prefix: 'anthropic/' },
72
72
  // { id: 'qwen', prefix: 'qwen/' },
73
73
  // { id: 'glm', prefix: 'glm/' },
74
- // { id: 'openai', prefix: 'openai/' }
74
+ // { id: 'openai', prefix: 'openai/' },
75
+ // { id: 'aibroker', prefix: 'aibroker/' }
75
76
  // ]
76
77
  ```
77
78
 
@@ -137,10 +138,25 @@ catch-all — an unknown or missing segment throws `AIGatewayError`
137
138
  | `qwen/<model>` | `qwen` | `<model>` | OpenAI-compatible. Default base URL `https://dashscope-intl.aliyuncs.com/compatible-mode/v1`. |
138
139
  | `glm/<model>` | `glm` | `<model>` | OpenAI-compatible. Default base URL `https://open.bigmodel.cn/api/paas/v4`. |
139
140
  | `openrouter/<vendor>/<model>` | `openrouter` | `<vendor>/<model>` | Only the `openrouter/` segment is stripped, leaving OpenRouter's native id. Default base URL `https://openrouter.ai/api/v1`. |
141
+ | `aibroker/<remainder>` | `aibroker` | `<remainder>` | OpenAI-compatible gateway meta-provider. Only the `aibroker/` segment is stripped; the remainder is forwarded verbatim and the gateway does its own routing. **Requires** `baseURL` (no default) — the constructor throws `AIGatewayError` (`code: 'missing_base_url'`) without it. |
140
142
 
141
143
  OpenRouter is opt-in: send `openrouter/anthropic/claude-opus-4.8` to route
142
144
  through OpenRouter, or `anthropic/claude-opus-4.8` to hit Anthropic directly.
143
145
 
146
+ `aibroker` is a gateway meta-provider: it forwards to *any* OpenAI-compatible
147
+ gateway you point it at, so it embeds no host and **requires** a `baseURL`. Only
148
+ the leading `aibroker/` segment is stripped — everything after it is sent
149
+ upstream as the model id, letting the gateway do its own routing
150
+ (`aibroker/openai/chatgpt-5.5` → `openai/chatgpt-5.5`,
151
+ `aibroker/openrouter/openai/chatgpt-5.5` → `openrouter/openai/chatgpt-5.5`). The
152
+ key is passed straight through as the Bearer for the gateway.
153
+
154
+ ```js
155
+ const g = new AIGateway('aibroker/openai/chatgpt-5.5', GATEWAY_TOKEN, {
156
+ baseURL: 'https://your-gateway/v1',
157
+ });
158
+ ```
159
+
144
160
  **Adding a provider:** drop a module into [src/providers/](src/providers/)
145
161
  exporting `{ id, prefix, matches, create }` (where `matches` tests the
146
162
  `<id>/` segment) and register it in
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pkent/aigateway",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "A provider-neutral LLM client library for OpenAI, Anthropic, Qwen, GLM, and OpenRouter",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "scripts": {
11
11
  "test": "node --test",
12
- "prepublishOnly": "node --test test/aigateway.test.js test/cache-hints.test.js test/usage-normalization.test.js test/cancellation.test.js"
12
+ "prepublishOnly": "node --test test/aigateway.test.js test/cache-hints.test.js test/usage-normalization.test.js test/cancellation.test.js test/aibroker.test.js"
13
13
  },
14
14
  "files": [
15
15
  "src",
@@ -0,0 +1,22 @@
1
+ import { createOpenAICompatibleProvider } from './openaiCompatible.js';
2
+ import { AIGatewayError } from '../errors.js';
3
+
4
+ // "aibroker/<provider>/<model>" routes to an OpenAI-compatible gateway. The
5
+ // "aibroker/" segment is stripped (existing stripProviderPrefix) and the rest is
6
+ // forwarded verbatim as the model — the gateway does its own routing. The
7
+ // caller MUST supply the gateway URL via options.baseURL; there is no default.
8
+ export default {
9
+ id: 'aibroker',
10
+ prefix: 'aibroker/',
11
+ matches: model => typeof model === 'string' && model.startsWith('aibroker/'),
12
+ create({ apiKey, baseURL, client }) {
13
+ if (!client && !baseURL) {
14
+ throw new AIGatewayError(
15
+ 'The "aibroker" provider requires a baseURL (the gateway URL), e.g. ' +
16
+ 'new AIGateway(model, key, { baseURL: "https://your-gateway/v1" })',
17
+ { code: 'missing_base_url' },
18
+ );
19
+ }
20
+ return createOpenAICompatibleProvider({ id: 'aibroker', apiKey, baseURL, client });
21
+ },
22
+ };
@@ -3,10 +3,11 @@ import anthropic from './anthropic.js';
3
3
  import qwen from './qwen.js';
4
4
  import glm from './glm.js';
5
5
  import openai from './openai.js';
6
+ import aibroker from './aibroker.js';
6
7
 
7
8
  // Every model is addressed as "<provider>/<model>". The provider segments are
8
9
  // disjoint, so resolution order does not matter; there is no catch-all.
9
- const ENTRIES = [openrouter, anthropic, qwen, glm, openai];
10
+ const ENTRIES = [openrouter, anthropic, qwen, glm, openai, aibroker];
10
11
 
11
12
  export function resolveProviderEntry(model) {
12
13
  for (const entry of ENTRIES) {