@providerkit/core 0.6.0 → 0.7.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/dist/index.d.ts CHANGED
@@ -11,9 +11,11 @@ export * from "./tools.ts";
11
11
  export * from "./schema.ts";
12
12
  export * from "./context.ts";
13
13
  export * from "./capability.ts";
14
+ export * from "./presets.ts";
14
15
  export * from "./providers/anthropic.ts";
15
16
  export * from "./providers/openai.ts";
16
17
  export * from "./providers/responses.ts";
17
18
  export * from "./providers/gemini.ts";
18
19
  export * from "./providers/zai.ts";
20
+ export * from "./providers/factory.ts";
19
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC"}
package/dist/index.js CHANGED
@@ -11,9 +11,11 @@ export * from "./tools.js";
11
11
  export * from "./schema.js";
12
12
  export * from "./context.js";
13
13
  export * from "./capability.js";
14
+ export * from "./presets.js";
14
15
  export * from "./providers/anthropic.js";
15
16
  export * from "./providers/openai.js";
16
17
  export * from "./providers/responses.js";
17
18
  export * from "./providers/gemini.js";
18
19
  export * from "./providers/zai.js";
20
+ export * from "./providers/factory.js";
19
21
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC"}
@@ -0,0 +1,249 @@
1
+ /**
2
+ * Provider presets — hand-curated, wire-level facts only.
3
+ *
4
+ * A preset is everything `createPresetProvider` needs to speak to one
5
+ * endpoint: which adapter shape it speaks, its API root, how the credential
6
+ * rides, and what it is called. Deliberately absent: prices (invariant 9 —
7
+ * they drift on a vendor's schedule and a wrong number in a library is a
8
+ * wrong number in everyone's ledger), icons, colors, marketing names, and
9
+ * sign-in flows (an `oauth` preset expects the CALLER to hand over an access
10
+ * token; acquiring one stays app-side).
11
+ *
12
+ * Sources: the coding-plan endpoints and auth quirks are measured
13
+ * (tabrunner's extension + this repo's adopters, 2026-09); the model lists
14
+ * are representative, not exhaustive — every adapter takes a per-call model,
15
+ * so a missing id costs nothing.
16
+ *
17
+ * Azure is deliberately ABSENT: its base URL is per-deployment
18
+ * (`https://<resource>.openai.azure.com`), so no static preset can carry it —
19
+ * point createOpenAIProvider's baseUrl at your resource instead.
20
+ */
21
+ export type PresetShape = "anthropic" | "openai" | "responses" | "gemini";
22
+ /**
23
+ * How the credential reaches the endpoint.
24
+ * - `key`: the vendor's native key header (Anthropic reads `x-api-key`,
25
+ * Gemini `x-goog-api-key`); the OpenAI shapes have only Bearer, so they
26
+ * never use this.
27
+ * - `bearer`: `Authorization: Bearer` — the OpenAI shapes' only mode, and the
28
+ * coding-plan gateways' mode on the Anthropic wire (measured: Z.ai's coding
29
+ * endpoint ignores `x-api-key` and reads Bearer).
30
+ * - `oauth`: same wire as `bearer`, but the token is a short-lived access
31
+ * token from a sign-in flow the caller owns. The preset may carry the beta
32
+ * headers that switch the endpoint into OAuth mode.
33
+ */
34
+ export type PresetAuth = "key" | "bearer" | "oauth";
35
+ export interface ProviderPreset {
36
+ /** Adapter wire format. */
37
+ shape: PresetShape;
38
+ /** API root — the adapter appends its own path (/v1/chat/completions,
39
+ * /v1/messages, …), so this must NOT carry the version. */
40
+ baseUrl: string;
41
+ auth: PresetAuth;
42
+ /** Fallback when the caller passes no model. */
43
+ defaultModel?: string;
44
+ /** Representative model ids. */
45
+ models?: string[];
46
+ /** Static protocol headers the endpoint requires (e.g. OAuth beta flags).
47
+ * Per-request headers (request ids, account ids) are the caller's. */
48
+ headers?: Record<string, string>;
49
+ /** True when the endpoint hard-400s image parts (measured on DeepSeek). */
50
+ textOnly?: boolean;
51
+ /** Anthropic-shape dialect: say "no thinking" with an explicit
52
+ * `thinking: { type: "disabled" }` marker when effort is none. For
53
+ * endpoints where an ABSENT field means the model's default — thinking ON
54
+ * for reasoning-mandatory models (measured on Z.ai's coding endpoint:
55
+ * omit → thinking block; disabled → none). Native Anthropic defaults to
56
+ * off when the field is absent and must stay unset. */
57
+ explicitNone?: boolean;
58
+ }
59
+ export declare const PROVIDER_PRESETS: {
60
+ readonly anthropic: {
61
+ readonly shape: "anthropic";
62
+ readonly baseUrl: "https://api.anthropic.com";
63
+ readonly auth: "key";
64
+ readonly defaultModel: "claude-sonnet-4-6";
65
+ readonly models: ["claude-sonnet-4-6", "claude-opus-5", "claude-fable-5-1"];
66
+ };
67
+ readonly openai: {
68
+ readonly shape: "openai";
69
+ readonly baseUrl: "https://api.openai.com";
70
+ readonly auth: "key";
71
+ readonly defaultModel: "gpt-5.6-sol";
72
+ readonly models: ["gpt-5.6-sol", "gpt-5-pro", "gpt-5-nano"];
73
+ };
74
+ readonly google: {
75
+ readonly shape: "gemini";
76
+ readonly baseUrl: "https://generativelanguage.googleapis.com";
77
+ readonly auth: "key";
78
+ readonly defaultModel: "gemini-3.1-pro";
79
+ readonly models: ["gemini-3.1-pro", "gemini-2.5-flash"];
80
+ };
81
+ /** Gemini behind its OpenAI-compatible route — the drop-in for codebases
82
+ * that only speak the openai shape. */
83
+ readonly "google-openai": {
84
+ readonly shape: "openai";
85
+ readonly baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai";
86
+ readonly auth: "key";
87
+ readonly defaultModel: "gemini-3.1-pro";
88
+ readonly models: ["gemini-3.1-pro", "gemini-2.5-flash"];
89
+ };
90
+ readonly deepseek: {
91
+ readonly shape: "openai";
92
+ readonly baseUrl: "https://api.deepseek.com";
93
+ readonly auth: "key";
94
+ readonly defaultModel: "deepseek-v4-flash";
95
+ readonly models: ["deepseek-v4-flash", "deepseek-v4-pro", "deepseek-flash"];
96
+ readonly textOnly: true;
97
+ };
98
+ readonly openrouter: {
99
+ readonly shape: "openai";
100
+ readonly baseUrl: "https://openrouter.ai/api";
101
+ readonly auth: "key";
102
+ readonly defaultModel: "deepseek/deepseek-v4.1-flash";
103
+ readonly models: ["deepseek/deepseek-v4.1-flash", "z-ai/glm-5.3-flash", "qwen/qwen3.7-max"];
104
+ };
105
+ readonly groq: {
106
+ readonly shape: "openai";
107
+ readonly baseUrl: "https://api.groq.com/openai/v1";
108
+ readonly auth: "key";
109
+ readonly defaultModel: "llama-3.3-70b-versatile";
110
+ readonly models: ["llama-3.3-70b-versatile", "qwen/qwen3.8-27b"];
111
+ };
112
+ readonly mistral: {
113
+ readonly shape: "openai";
114
+ readonly baseUrl: "https://api.mistral.ai/v1";
115
+ readonly auth: "key";
116
+ readonly defaultModel: "devstral-2512";
117
+ readonly models: ["devstral-2512", "magistral-small", "mistral-small-2506"];
118
+ };
119
+ readonly xai: {
120
+ readonly shape: "openai";
121
+ readonly baseUrl: "https://api.x.ai/v1";
122
+ readonly auth: "key";
123
+ readonly defaultModel: "grok-4.5";
124
+ readonly models: ["grok-4.5", "grok-4.3", "grok-4.20-0309-reasoning"];
125
+ };
126
+ readonly together: {
127
+ readonly shape: "openai";
128
+ readonly baseUrl: "https://api.together.xyz/v1";
129
+ readonly auth: "key";
130
+ readonly defaultModel: "deepseek-ai/DeepSeek-V3";
131
+ };
132
+ readonly fireworks: {
133
+ readonly shape: "openai";
134
+ readonly baseUrl: "https://api.fireworks.ai/inference/v1";
135
+ readonly auth: "key";
136
+ };
137
+ readonly cerebras: {
138
+ readonly shape: "openai";
139
+ readonly baseUrl: "https://api.cerebras.ai/v1";
140
+ readonly auth: "key";
141
+ readonly defaultModel: "gpt-oss-120b";
142
+ readonly models: ["gpt-oss-120b", "qwen-3.8-27b"];
143
+ };
144
+ readonly moonshot: {
145
+ readonly shape: "openai";
146
+ readonly baseUrl: "https://api.moonshot.ai/v1";
147
+ readonly auth: "key";
148
+ readonly defaultModel: "kimi-k2.7-code";
149
+ readonly models: ["kimi-k2.7-code", "kimi-k2.7-code-highspeed", "kimi-k3"];
150
+ };
151
+ readonly zhipu: {
152
+ readonly shape: "openai";
153
+ readonly baseUrl: "https://api.z.ai/api/paas/v4";
154
+ readonly auth: "key";
155
+ readonly defaultModel: "glm-5.3-flash";
156
+ readonly models: ["glm-5.3-flash", "glm-5.2", "glm-4.7"];
157
+ };
158
+ readonly minimax: {
159
+ readonly shape: "anthropic";
160
+ readonly baseUrl: "https://api.minimax.io/anthropic";
161
+ readonly auth: "key";
162
+ readonly defaultModel: "MiniMax-M2.5";
163
+ readonly models: ["MiniMax-M3", "MiniMax-M2.5", "MiniMax-M2.1"];
164
+ };
165
+ readonly zai: {
166
+ readonly shape: "anthropic";
167
+ readonly baseUrl: "https://api.z.ai/api/anthropic";
168
+ readonly auth: "bearer";
169
+ readonly defaultModel: "glm-5.3-flash";
170
+ readonly models: ["glm-5.3-flash", "glm-5.3-highspeed", "glm-5.2", "glm-5-turbo"];
171
+ readonly explicitNone: true;
172
+ };
173
+ readonly kimi: {
174
+ readonly shape: "anthropic";
175
+ readonly baseUrl: "https://api.kimi.ai/coding";
176
+ readonly auth: "bearer";
177
+ readonly defaultModel: "kimi-for-coding";
178
+ readonly models: ["kimi-for-coding", "kimi-for-coding-highspeed", "k3"];
179
+ };
180
+ /** Alibaba's dashscope coding plan — OpenAI-compatible per its registry. */
181
+ readonly "alibaba-coding-plan": {
182
+ readonly shape: "openai";
183
+ readonly baseUrl: "https://coding-intl.dashscope.aliyuncs.com/v1";
184
+ readonly auth: "bearer";
185
+ readonly defaultModel: "qwen3.7-max";
186
+ readonly models: ["qwen3.7-max", "qwen3-coder-next", "glm-4.7"];
187
+ };
188
+ /** QwenCloud's token plan — Anthropic wire (measured by tabrunner). */
189
+ readonly qwen: {
190
+ readonly shape: "anthropic";
191
+ readonly baseUrl: "https://token-plan.ap-southeast-1.maas.aliyuncs.com/apps/anthropic";
192
+ readonly auth: "bearer";
193
+ readonly defaultModel: "qwen3.8-max";
194
+ readonly models: ["qwen3.8-max", "qwen3.6-flash"];
195
+ };
196
+ readonly ollama: {
197
+ readonly shape: "openai";
198
+ readonly baseUrl: "http://localhost:11434/v1";
199
+ readonly auth: "bearer";
200
+ };
201
+ readonly lmstudio: {
202
+ readonly shape: "openai";
203
+ readonly baseUrl: "http://127.0.0.1:1234/v1";
204
+ readonly auth: "bearer";
205
+ };
206
+ readonly vllm: {
207
+ readonly shape: "openai";
208
+ readonly baseUrl: "http://localhost:8000/v1";
209
+ readonly auth: "bearer";
210
+ };
211
+ readonly claude: {
212
+ readonly shape: "anthropic";
213
+ readonly baseUrl: "https://api.anthropic.com";
214
+ readonly auth: "oauth";
215
+ readonly defaultModel: "claude-sonnet-4-6";
216
+ readonly models: ["claude-sonnet-4-6", "claude-opus-5"];
217
+ readonly headers: {
218
+ readonly "anthropic-beta": "claude-code-20250219,oauth-2025-04-20";
219
+ };
220
+ };
221
+ /** The Codex backend behind a ChatGPT sign-in — Responses wire, no public
222
+ * model list, so these ids are the list. */
223
+ readonly chatgpt: {
224
+ readonly shape: "responses";
225
+ readonly baseUrl: "https://chatgpt.com/backend-api/codex";
226
+ readonly auth: "oauth";
227
+ readonly defaultModel: "gpt-5.3-codex";
228
+ readonly models: ["gpt-5.3-codex", "gpt-5.5", "gpt-5.4-mini"];
229
+ };
230
+ /** Kimi's coding endpoint reached with a subscription token instead of a
231
+ * key — Kimi bills the two separately. */
232
+ readonly "kimi-plan": {
233
+ readonly shape: "anthropic";
234
+ readonly baseUrl: "https://api.kimi.ai/coding";
235
+ readonly auth: "oauth";
236
+ readonly defaultModel: "kimi-for-coding";
237
+ };
238
+ readonly "github-copilot": {
239
+ readonly shape: "openai";
240
+ readonly baseUrl: "https://api.githubcopilot.com";
241
+ readonly auth: "oauth";
242
+ readonly defaultModel: "gpt-5.6-sol";
243
+ readonly models: ["gpt-5.6-sol", "claude-opus-5", "claude-opus-4.8", "kimi-k2.7-code"];
244
+ };
245
+ };
246
+ export type ProviderPresetId = keyof typeof PROVIDER_PRESETS;
247
+ /** Every valid preset id — the factory's unknown-id error lists these. */
248
+ export declare const PRESET_IDS: ProviderPresetId[];
249
+ //# sourceMappingURL=presets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../src/presets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE1E;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEpD,MAAM,WAAW,cAAc;IAC7B,2BAA2B;IAC3B,KAAK,EAAE,WAAW,CAAC;IACnB;gEAC4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,UAAU,CAAC;IACjB,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;2EACuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;4DAKwD;IACxD,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;IAyB3B;4CACwC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAuGxC,4EAA4E;;;;;;;;IAQ5E,uEAAuE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAqCvE;iDAC6C;;;;;;;;IAQ7C;+CAC2C;;;;;;;;;;;;;;CAcM,CAAC;AAEpD,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,gBAAgB,CAAC;AAE7D,0EAA0E;AAC1E,eAAO,MAAM,UAAU,EAAoC,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,199 @@
1
+ export const PROVIDER_PRESETS = {
2
+ // ── Keyed, native shapes ────────────────────────────────────────────────
3
+ anthropic: {
4
+ shape: "anthropic",
5
+ baseUrl: "https://api.anthropic.com",
6
+ auth: "key",
7
+ defaultModel: "claude-sonnet-4-6",
8
+ models: ["claude-sonnet-4-6", "claude-opus-5", "claude-fable-5-1"],
9
+ },
10
+ openai: {
11
+ shape: "openai",
12
+ baseUrl: "https://api.openai.com",
13
+ auth: "key",
14
+ defaultModel: "gpt-5.6-sol",
15
+ models: ["gpt-5.6-sol", "gpt-5-pro", "gpt-5-nano"],
16
+ },
17
+ google: {
18
+ // Native Generative Language REST — the adapter authenticates with
19
+ // `x-goog-api-key` (NOT Bearer) and fixes its own /v1… paths.
20
+ shape: "gemini",
21
+ baseUrl: "https://generativelanguage.googleapis.com",
22
+ auth: "key",
23
+ defaultModel: "gemini-3.1-pro",
24
+ models: ["gemini-3.1-pro", "gemini-2.5-flash"],
25
+ },
26
+ /** Gemini behind its OpenAI-compatible route — the drop-in for codebases
27
+ * that only speak the openai shape. */
28
+ "google-openai": {
29
+ shape: "openai",
30
+ baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai",
31
+ auth: "key",
32
+ defaultModel: "gemini-3.1-pro",
33
+ models: ["gemini-3.1-pro", "gemini-2.5-flash"],
34
+ },
35
+ deepseek: {
36
+ shape: "openai",
37
+ baseUrl: "https://api.deepseek.com",
38
+ auth: "key",
39
+ defaultModel: "deepseek-v4-flash",
40
+ models: ["deepseek-v4-flash", "deepseek-v4-pro", "deepseek-flash"],
41
+ // Text-only API — an image part in the body is a hard 400 (measured).
42
+ textOnly: true,
43
+ },
44
+ openrouter: {
45
+ shape: "openai",
46
+ baseUrl: "https://openrouter.ai/api",
47
+ auth: "key",
48
+ defaultModel: "deepseek/deepseek-v4.1-flash",
49
+ models: ["deepseek/deepseek-v4.1-flash", "z-ai/glm-5.3-flash", "qwen/qwen3.7-max"],
50
+ },
51
+ groq: {
52
+ shape: "openai",
53
+ baseUrl: "https://api.groq.com/openai/v1",
54
+ auth: "key",
55
+ defaultModel: "llama-3.3-70b-versatile",
56
+ models: ["llama-3.3-70b-versatile", "qwen/qwen3.8-27b"],
57
+ },
58
+ mistral: {
59
+ shape: "openai",
60
+ baseUrl: "https://api.mistral.ai/v1",
61
+ auth: "key",
62
+ defaultModel: "devstral-2512",
63
+ models: ["devstral-2512", "magistral-small", "mistral-small-2506"],
64
+ },
65
+ xai: {
66
+ shape: "openai",
67
+ baseUrl: "https://api.x.ai/v1",
68
+ auth: "key",
69
+ defaultModel: "grok-4.5",
70
+ models: ["grok-4.5", "grok-4.3", "grok-4.20-0309-reasoning"],
71
+ },
72
+ together: {
73
+ shape: "openai",
74
+ baseUrl: "https://api.together.xyz/v1",
75
+ auth: "key",
76
+ defaultModel: "deepseek-ai/DeepSeek-V3",
77
+ },
78
+ fireworks: {
79
+ shape: "openai",
80
+ baseUrl: "https://api.fireworks.ai/inference/v1",
81
+ auth: "key",
82
+ },
83
+ cerebras: {
84
+ shape: "openai",
85
+ baseUrl: "https://api.cerebras.ai/v1",
86
+ auth: "key",
87
+ defaultModel: "gpt-oss-120b",
88
+ models: ["gpt-oss-120b", "qwen-3.8-27b"],
89
+ },
90
+ moonshot: {
91
+ shape: "openai",
92
+ baseUrl: "https://api.moonshot.ai/v1",
93
+ auth: "key",
94
+ defaultModel: "kimi-k2.7-code",
95
+ models: ["kimi-k2.7-code", "kimi-k2.7-code-highspeed", "kimi-k3"],
96
+ },
97
+ zhipu: {
98
+ shape: "openai",
99
+ baseUrl: "https://api.z.ai/api/paas/v4",
100
+ auth: "key",
101
+ defaultModel: "glm-5.3-flash",
102
+ models: ["glm-5.3-flash", "glm-5.2", "glm-4.7"],
103
+ },
104
+ minimax: {
105
+ shape: "anthropic",
106
+ baseUrl: "https://api.minimax.io/anthropic",
107
+ auth: "key",
108
+ defaultModel: "MiniMax-M2.5",
109
+ models: ["MiniMax-M3", "MiniMax-M2.5", "MiniMax-M2.1"],
110
+ },
111
+ // ── Coding plans — Anthropic wire + Bearer (measured family trait) ─────
112
+ zai: {
113
+ shape: "anthropic",
114
+ baseUrl: "https://api.z.ai/api/anthropic",
115
+ auth: "bearer",
116
+ defaultModel: "glm-5.3-flash",
117
+ models: ["glm-5.3-flash", "glm-5.3-highspeed", "glm-5.2", "glm-5-turbo"],
118
+ // Model ids are BARE here — the gateway-prefixed spelling
119
+ // (`z-ai/glm-5.3-flash`) answers 400 [1211] Unknown Model.
120
+ explicitNone: true,
121
+ },
122
+ kimi: {
123
+ shape: "anthropic",
124
+ baseUrl: "https://api.kimi.ai/coding",
125
+ auth: "bearer",
126
+ defaultModel: "kimi-for-coding",
127
+ models: ["kimi-for-coding", "kimi-for-coding-highspeed", "k3"],
128
+ },
129
+ /** Alibaba's dashscope coding plan — OpenAI-compatible per its registry. */
130
+ "alibaba-coding-plan": {
131
+ shape: "openai",
132
+ baseUrl: "https://coding-intl.dashscope.aliyuncs.com/v1",
133
+ auth: "bearer",
134
+ defaultModel: "qwen3.7-max",
135
+ models: ["qwen3.7-max", "qwen3-coder-next", "glm-4.7"],
136
+ },
137
+ /** QwenCloud's token plan — Anthropic wire (measured by tabrunner). */
138
+ qwen: {
139
+ shape: "anthropic",
140
+ baseUrl: "https://token-plan.ap-southeast-1.maas.aliyuncs.com/apps/anthropic",
141
+ auth: "bearer",
142
+ defaultModel: "qwen3.8-max",
143
+ models: ["qwen3.8-max", "qwen3.6-flash"],
144
+ },
145
+ // ── Local runtimes ──────────────────────────────────────────────────────
146
+ ollama: {
147
+ shape: "openai",
148
+ baseUrl: "http://localhost:11434/v1",
149
+ auth: "bearer",
150
+ },
151
+ lmstudio: {
152
+ shape: "openai",
153
+ baseUrl: "http://127.0.0.1:1234/v1",
154
+ auth: "bearer",
155
+ },
156
+ vllm: {
157
+ shape: "openai",
158
+ baseUrl: "http://localhost:8000/v1",
159
+ auth: "bearer",
160
+ },
161
+ // ── OAuth — the caller owns the sign-in flow and hands over the token ───
162
+ claude: {
163
+ shape: "anthropic",
164
+ baseUrl: "https://api.anthropic.com",
165
+ auth: "oauth",
166
+ defaultModel: "claude-sonnet-4-6",
167
+ models: ["claude-sonnet-4-6", "claude-opus-5"],
168
+ // The beta flag is what switches the API into OAuth-token mode (measured
169
+ // by tabrunner's Claude plan sign-in).
170
+ headers: { "anthropic-beta": "claude-code-20250219,oauth-2025-04-20" },
171
+ },
172
+ /** The Codex backend behind a ChatGPT sign-in — Responses wire, no public
173
+ * model list, so these ids are the list. */
174
+ chatgpt: {
175
+ shape: "responses",
176
+ baseUrl: "https://chatgpt.com/backend-api/codex",
177
+ auth: "oauth",
178
+ defaultModel: "gpt-5.3-codex",
179
+ models: ["gpt-5.3-codex", "gpt-5.5", "gpt-5.4-mini"],
180
+ },
181
+ /** Kimi's coding endpoint reached with a subscription token instead of a
182
+ * key — Kimi bills the two separately. */
183
+ "kimi-plan": {
184
+ shape: "anthropic",
185
+ baseUrl: "https://api.kimi.ai/coding",
186
+ auth: "oauth",
187
+ defaultModel: "kimi-for-coding",
188
+ },
189
+ "github-copilot": {
190
+ shape: "openai",
191
+ baseUrl: "https://api.githubcopilot.com",
192
+ auth: "oauth",
193
+ defaultModel: "gpt-5.6-sol",
194
+ models: ["gpt-5.6-sol", "claude-opus-5", "claude-opus-4.8", "kimi-k2.7-code"],
195
+ },
196
+ };
197
+ /** Every valid preset id — the factory's unknown-id error lists these. */
198
+ export const PRESET_IDS = Object.keys(PROVIDER_PRESETS);
199
+ //# sourceMappingURL=presets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.js","sourceRoot":"","sources":["../src/presets.ts"],"names":[],"mappings":"AA6DA,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,2EAA2E;IAC3E,SAAS,EAAE;QACT,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,2BAA2B;QACpC,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,mBAAmB;QACjC,MAAM,EAAE,CAAC,mBAAmB,EAAE,eAAe,EAAE,kBAAkB,CAAC;KACnE;IACD,MAAM,EAAE;QACN,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,wBAAwB;QACjC,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,aAAa;QAC3B,MAAM,EAAE,CAAC,aAAa,EAAE,WAAW,EAAE,YAAY,CAAC;KACnD;IACD,MAAM,EAAE;QACN,mEAAmE;QACnE,8DAA8D;QAC9D,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,2CAA2C;QACpD,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,gBAAgB;QAC9B,MAAM,EAAE,CAAC,gBAAgB,EAAE,kBAAkB,CAAC;KAC/C;IACD;4CACwC;IACxC,eAAe,EAAE;QACf,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,yDAAyD;QAClE,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,gBAAgB;QAC9B,MAAM,EAAE,CAAC,gBAAgB,EAAE,kBAAkB,CAAC;KAC/C;IACD,QAAQ,EAAE;QACR,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,0BAA0B;QACnC,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,mBAAmB;QACjC,MAAM,EAAE,CAAC,mBAAmB,EAAE,iBAAiB,EAAE,gBAAgB,CAAC;QAClE,sEAAsE;QACtE,QAAQ,EAAE,IAAI;KACf;IACD,UAAU,EAAE;QACV,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,2BAA2B;QACpC,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,8BAA8B;QAC5C,MAAM,EAAE,CAAC,8BAA8B,EAAE,oBAAoB,EAAE,kBAAkB,CAAC;KACnF;IACD,IAAI,EAAE;QACJ,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,gCAAgC;QACzC,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,yBAAyB;QACvC,MAAM,EAAE,CAAC,yBAAyB,EAAE,kBAAkB,CAAC;KACxD;IACD,OAAO,EAAE;QACP,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,2BAA2B;QACpC,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,eAAe;QAC7B,MAAM,EAAE,CAAC,eAAe,EAAE,iBAAiB,EAAE,oBAAoB,CAAC;KACnE;IACD,GAAG,EAAE;QACH,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,qBAAqB;QAC9B,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,UAAU;QACxB,MAAM,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,0BAA0B,CAAC;KAC7D;IACD,QAAQ,EAAE;QACR,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,6BAA6B;QACtC,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,yBAAyB;KACxC;IACD,SAAS,EAAE;QACT,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,uCAAuC;QAChD,IAAI,EAAE,KAAK;KACZ;IACD,QAAQ,EAAE;QACR,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,4BAA4B;QACrC,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,cAAc;QAC5B,MAAM,EAAE,CAAC,cAAc,EAAE,cAAc,CAAC;KACzC;IACD,QAAQ,EAAE;QACR,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,4BAA4B;QACrC,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,gBAAgB;QAC9B,MAAM,EAAE,CAAC,gBAAgB,EAAE,0BAA0B,EAAE,SAAS,CAAC;KAClE;IACD,KAAK,EAAE;QACL,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,8BAA8B;QACvC,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,eAAe;QAC7B,MAAM,EAAE,CAAC,eAAe,EAAE,SAAS,EAAE,SAAS,CAAC;KAChD;IACD,OAAO,EAAE;QACP,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,kCAAkC;QAC3C,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,cAAc;QAC5B,MAAM,EAAE,CAAC,YAAY,EAAE,cAAc,EAAE,cAAc,CAAC;KACvD;IAED,0EAA0E;IAC1E,GAAG,EAAE;QACH,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,gCAAgC;QACzC,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,eAAe;QAC7B,MAAM,EAAE,CAAC,eAAe,EAAE,mBAAmB,EAAE,SAAS,EAAE,aAAa,CAAC;QACxE,0DAA0D;QAC1D,2DAA2D;QAC3D,YAAY,EAAE,IAAI;KACnB;IACD,IAAI,EAAE;QACJ,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,4BAA4B;QACrC,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,iBAAiB;QAC/B,MAAM,EAAE,CAAC,iBAAiB,EAAE,2BAA2B,EAAE,IAAI,CAAC;KAC/D;IACD,4EAA4E;IAC5E,qBAAqB,EAAE;QACrB,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,+CAA+C;QACxD,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,aAAa;QAC3B,MAAM,EAAE,CAAC,aAAa,EAAE,kBAAkB,EAAE,SAAS,CAAC;KACvD;IACD,uEAAuE;IACvE,IAAI,EAAE;QACJ,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,oEAAoE;QAC7E,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,aAAa;QAC3B,MAAM,EAAE,CAAC,aAAa,EAAE,eAAe,CAAC;KACzC;IAED,2EAA2E;IAC3E,MAAM,EAAE;QACN,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,2BAA2B;QACpC,IAAI,EAAE,QAAQ;KACf;IACD,QAAQ,EAAE;QACR,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,0BAA0B;QACnC,IAAI,EAAE,QAAQ;KACf;IACD,IAAI,EAAE;QACJ,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,0BAA0B;QACnC,IAAI,EAAE,QAAQ;KACf;IAED,2EAA2E;IAC3E,MAAM,EAAE;QACN,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,2BAA2B;QACpC,IAAI,EAAE,OAAO;QACb,YAAY,EAAE,mBAAmB;QACjC,MAAM,EAAE,CAAC,mBAAmB,EAAE,eAAe,CAAC;QAC9C,yEAAyE;QACzE,uCAAuC;QACvC,OAAO,EAAE,EAAE,gBAAgB,EAAE,uCAAuC,EAAE;KACvE;IACD;iDAC6C;IAC7C,OAAO,EAAE;QACP,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,uCAAuC;QAChD,IAAI,EAAE,OAAO;QACb,YAAY,EAAE,eAAe;QAC7B,MAAM,EAAE,CAAC,eAAe,EAAE,SAAS,EAAE,cAAc,CAAC;KACrD;IACD;+CAC2C;IAC3C,WAAW,EAAE;QACX,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,4BAA4B;QACrC,IAAI,EAAE,OAAO;QACb,YAAY,EAAE,iBAAiB;KAChC;IACD,gBAAgB,EAAE;QAChB,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,+BAA+B;QACxC,IAAI,EAAE,OAAO;QACb,YAAY,EAAE,aAAa;QAC3B,MAAM,EAAE,CAAC,aAAa,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,CAAC;KAC9E;CACgD,CAAC;AAIpD,0EAA0E;AAC1E,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAuB,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { type ProviderPresetId } from "../presets.ts";
2
+ import type { Effort, Provider } from "../types.ts";
3
+ export interface PresetProviderConfig {
4
+ /** The credential: an API key for `key`/`bearer` presets, an ACCESS TOKEN
5
+ * for `oauth` ones. Acquiring the token is the caller's job. */
6
+ apiKey: string;
7
+ /** Which model to run. Absent = the preset's `defaultModel`; a preset
8
+ * without either throws rather than sending a request nobody chose. */
9
+ model?: string;
10
+ effort?: Effort;
11
+ /** Output ceiling. The Anthropic shape requires one; adapters default it. */
12
+ maxTokens?: number;
13
+ /** Per-request headers (request ids, `ChatGPT-Account-Id`) on top of the
14
+ * preset's static protocol headers. */
15
+ headers?: Record<string, string>;
16
+ fetchImpl?: typeof fetch;
17
+ }
18
+ export declare function createPresetProvider(id: ProviderPresetId, config: PresetProviderConfig): Provider;
19
+ //# sourceMappingURL=factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/providers/factory.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAqD,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACzG,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEpD,MAAM,WAAW,oBAAoB;IACnC;qEACiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf;4EACwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;4CACwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,gBAAgB,EAAE,MAAM,EAAE,oBAAoB,GAAG,QAAQ,CAkEjG"}
@@ -0,0 +1,82 @@
1
+ // The one-line switch: resolve a preset id into a wired provider.
2
+ //
3
+ // Consumers used to write their own switch over providers — the same
4
+ // dispatch, re-derived per codebase, each quietly accumulating dialect
5
+ // knowledge (which gateway takes Bearer, which needs the thinking marker).
6
+ // The presets table + this factory is that dispatch, said once: a caller
7
+ // names an id and hands over a credential, and the header style, endpoint
8
+ // and adapter come from the table.
9
+ //
10
+ // `effort` passes through to the adapter unchanged — the per-endpoint
11
+ // thinking dialects (Z.ai's explicit disabled marker, OpenRouter's floors)
12
+ // are the adapters' knowledge, and this factory must not re-derive them.
13
+ import { createAnthropicProvider } from "./anthropic.js";
14
+ import { createGeminiProvider } from "./gemini.js";
15
+ import { createOpenAIProvider } from "./openai.js";
16
+ import { createResponsesProvider } from "./responses.js";
17
+ import { PRESET_IDS, PROVIDER_PRESETS } from "../presets.js";
18
+ export function createPresetProvider(id, config) {
19
+ // The table is closed (`satisfies`), but a caller may hold an id as a plain
20
+ // string — validate rather than index into undefined.
21
+ if (!(id in PROVIDER_PRESETS)) {
22
+ throw new Error(`[providerkit] Unknown provider preset "${id}". Valid ids: ${PRESET_IDS.join(", ")}`);
23
+ }
24
+ const preset = PROVIDER_PRESETS[id];
25
+ const model = config.model ?? preset.defaultModel;
26
+ if (!model) {
27
+ throw new Error(`[providerkit] Preset "${id}" has no defaultModel — pass a model.`);
28
+ }
29
+ const headers = { ...preset.headers, ...config.headers };
30
+ switch (preset.shape) {
31
+ case "anthropic":
32
+ // `key` rides Anthropic's native x-api-key; coding plans and OAuth
33
+ // tokens read Bearer (measured across the family's coding endpoints).
34
+ return createAnthropicProvider({
35
+ apiKey: config.apiKey,
36
+ model,
37
+ effort: config.effort,
38
+ maxTokens: config.maxTokens,
39
+ baseUrl: preset.baseUrl,
40
+ id,
41
+ headers,
42
+ bearer: preset.auth !== "key",
43
+ // The endpoint's thinking dialect rides the table (zai: silence means
44
+ // the model default, which is ON — "none" must be said out loud).
45
+ ...(preset.explicitNone ? { explicitNone: true } : {}),
46
+ fetchImpl: config.fetchImpl,
47
+ });
48
+ case "openai":
49
+ return createOpenAIProvider({
50
+ id,
51
+ apiKey: config.apiKey,
52
+ model,
53
+ effort: config.effort,
54
+ maxTokens: config.maxTokens,
55
+ baseUrl: preset.baseUrl,
56
+ headers,
57
+ fetchImpl: config.fetchImpl,
58
+ });
59
+ case "responses":
60
+ return createResponsesProvider({
61
+ apiKey: config.apiKey,
62
+ model,
63
+ effort: config.effort,
64
+ maxTokens: config.maxTokens,
65
+ baseUrl: preset.baseUrl,
66
+ id,
67
+ headers,
68
+ fetchImpl: config.fetchImpl,
69
+ });
70
+ case "gemini":
71
+ return createGeminiProvider({
72
+ apiKey: config.apiKey,
73
+ model,
74
+ effort: config.effort,
75
+ baseUrl: preset.baseUrl,
76
+ id,
77
+ headers,
78
+ fetchImpl: config.fetchImpl,
79
+ });
80
+ }
81
+ }
82
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/providers/factory.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@providerkit/core",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "The layer under your agent loop: one seam for every LLM provider, plus the failure handling you only learn in production.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -11,8 +11,10 @@ export * from "./tools.ts";
11
11
  export * from "./schema.ts";
12
12
  export * from "./context.ts";
13
13
  export * from "./capability.ts";
14
+ export * from "./presets.ts";
14
15
  export * from "./providers/anthropic.ts";
15
16
  export * from "./providers/openai.ts";
16
17
  export * from "./providers/responses.ts";
17
18
  export * from "./providers/gemini.ts";
18
19
  export * from "./providers/zai.ts";
20
+ export * from "./providers/factory.ts";
package/src/presets.ts ADDED
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Provider presets — hand-curated, wire-level facts only.
3
+ *
4
+ * A preset is everything `createPresetProvider` needs to speak to one
5
+ * endpoint: which adapter shape it speaks, its API root, how the credential
6
+ * rides, and what it is called. Deliberately absent: prices (invariant 9 —
7
+ * they drift on a vendor's schedule and a wrong number in a library is a
8
+ * wrong number in everyone's ledger), icons, colors, marketing names, and
9
+ * sign-in flows (an `oauth` preset expects the CALLER to hand over an access
10
+ * token; acquiring one stays app-side).
11
+ *
12
+ * Sources: the coding-plan endpoints and auth quirks are measured
13
+ * (tabrunner's extension + this repo's adopters, 2026-09); the model lists
14
+ * are representative, not exhaustive — every adapter takes a per-call model,
15
+ * so a missing id costs nothing.
16
+ *
17
+ * Azure is deliberately ABSENT: its base URL is per-deployment
18
+ * (`https://<resource>.openai.azure.com`), so no static preset can carry it —
19
+ * point createOpenAIProvider's baseUrl at your resource instead.
20
+ */
21
+ export type PresetShape = "anthropic" | "openai" | "responses" | "gemini";
22
+
23
+ /**
24
+ * How the credential reaches the endpoint.
25
+ * - `key`: the vendor's native key header (Anthropic reads `x-api-key`,
26
+ * Gemini `x-goog-api-key`); the OpenAI shapes have only Bearer, so they
27
+ * never use this.
28
+ * - `bearer`: `Authorization: Bearer` — the OpenAI shapes' only mode, and the
29
+ * coding-plan gateways' mode on the Anthropic wire (measured: Z.ai's coding
30
+ * endpoint ignores `x-api-key` and reads Bearer).
31
+ * - `oauth`: same wire as `bearer`, but the token is a short-lived access
32
+ * token from a sign-in flow the caller owns. The preset may carry the beta
33
+ * headers that switch the endpoint into OAuth mode.
34
+ */
35
+ export type PresetAuth = "key" | "bearer" | "oauth";
36
+
37
+ export interface ProviderPreset {
38
+ /** Adapter wire format. */
39
+ shape: PresetShape;
40
+ /** API root — the adapter appends its own path (/v1/chat/completions,
41
+ * /v1/messages, …), so this must NOT carry the version. */
42
+ baseUrl: string;
43
+ auth: PresetAuth;
44
+ /** Fallback when the caller passes no model. */
45
+ defaultModel?: string;
46
+ /** Representative model ids. */
47
+ models?: string[];
48
+ /** Static protocol headers the endpoint requires (e.g. OAuth beta flags).
49
+ * Per-request headers (request ids, account ids) are the caller's. */
50
+ headers?: Record<string, string>;
51
+ /** True when the endpoint hard-400s image parts (measured on DeepSeek). */
52
+ textOnly?: boolean;
53
+ /** Anthropic-shape dialect: say "no thinking" with an explicit
54
+ * `thinking: { type: "disabled" }` marker when effort is none. For
55
+ * endpoints where an ABSENT field means the model's default — thinking ON
56
+ * for reasoning-mandatory models (measured on Z.ai's coding endpoint:
57
+ * omit → thinking block; disabled → none). Native Anthropic defaults to
58
+ * off when the field is absent and must stay unset. */
59
+ explicitNone?: boolean;
60
+ }
61
+
62
+ export const PROVIDER_PRESETS = {
63
+ // ── Keyed, native shapes ────────────────────────────────────────────────
64
+ anthropic: {
65
+ shape: "anthropic",
66
+ baseUrl: "https://api.anthropic.com",
67
+ auth: "key",
68
+ defaultModel: "claude-sonnet-4-6",
69
+ models: ["claude-sonnet-4-6", "claude-opus-5", "claude-fable-5-1"],
70
+ },
71
+ openai: {
72
+ shape: "openai",
73
+ baseUrl: "https://api.openai.com",
74
+ auth: "key",
75
+ defaultModel: "gpt-5.6-sol",
76
+ models: ["gpt-5.6-sol", "gpt-5-pro", "gpt-5-nano"],
77
+ },
78
+ google: {
79
+ // Native Generative Language REST — the adapter authenticates with
80
+ // `x-goog-api-key` (NOT Bearer) and fixes its own /v1… paths.
81
+ shape: "gemini",
82
+ baseUrl: "https://generativelanguage.googleapis.com",
83
+ auth: "key",
84
+ defaultModel: "gemini-3.1-pro",
85
+ models: ["gemini-3.1-pro", "gemini-2.5-flash"],
86
+ },
87
+ /** Gemini behind its OpenAI-compatible route — the drop-in for codebases
88
+ * that only speak the openai shape. */
89
+ "google-openai": {
90
+ shape: "openai",
91
+ baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai",
92
+ auth: "key",
93
+ defaultModel: "gemini-3.1-pro",
94
+ models: ["gemini-3.1-pro", "gemini-2.5-flash"],
95
+ },
96
+ deepseek: {
97
+ shape: "openai",
98
+ baseUrl: "https://api.deepseek.com",
99
+ auth: "key",
100
+ defaultModel: "deepseek-v4-flash",
101
+ models: ["deepseek-v4-flash", "deepseek-v4-pro", "deepseek-flash"],
102
+ // Text-only API — an image part in the body is a hard 400 (measured).
103
+ textOnly: true,
104
+ },
105
+ openrouter: {
106
+ shape: "openai",
107
+ baseUrl: "https://openrouter.ai/api",
108
+ auth: "key",
109
+ defaultModel: "deepseek/deepseek-v4.1-flash",
110
+ models: ["deepseek/deepseek-v4.1-flash", "z-ai/glm-5.3-flash", "qwen/qwen3.7-max"],
111
+ },
112
+ groq: {
113
+ shape: "openai",
114
+ baseUrl: "https://api.groq.com/openai/v1",
115
+ auth: "key",
116
+ defaultModel: "llama-3.3-70b-versatile",
117
+ models: ["llama-3.3-70b-versatile", "qwen/qwen3.8-27b"],
118
+ },
119
+ mistral: {
120
+ shape: "openai",
121
+ baseUrl: "https://api.mistral.ai/v1",
122
+ auth: "key",
123
+ defaultModel: "devstral-2512",
124
+ models: ["devstral-2512", "magistral-small", "mistral-small-2506"],
125
+ },
126
+ xai: {
127
+ shape: "openai",
128
+ baseUrl: "https://api.x.ai/v1",
129
+ auth: "key",
130
+ defaultModel: "grok-4.5",
131
+ models: ["grok-4.5", "grok-4.3", "grok-4.20-0309-reasoning"],
132
+ },
133
+ together: {
134
+ shape: "openai",
135
+ baseUrl: "https://api.together.xyz/v1",
136
+ auth: "key",
137
+ defaultModel: "deepseek-ai/DeepSeek-V3",
138
+ },
139
+ fireworks: {
140
+ shape: "openai",
141
+ baseUrl: "https://api.fireworks.ai/inference/v1",
142
+ auth: "key",
143
+ },
144
+ cerebras: {
145
+ shape: "openai",
146
+ baseUrl: "https://api.cerebras.ai/v1",
147
+ auth: "key",
148
+ defaultModel: "gpt-oss-120b",
149
+ models: ["gpt-oss-120b", "qwen-3.8-27b"],
150
+ },
151
+ moonshot: {
152
+ shape: "openai",
153
+ baseUrl: "https://api.moonshot.ai/v1",
154
+ auth: "key",
155
+ defaultModel: "kimi-k2.7-code",
156
+ models: ["kimi-k2.7-code", "kimi-k2.7-code-highspeed", "kimi-k3"],
157
+ },
158
+ zhipu: {
159
+ shape: "openai",
160
+ baseUrl: "https://api.z.ai/api/paas/v4",
161
+ auth: "key",
162
+ defaultModel: "glm-5.3-flash",
163
+ models: ["glm-5.3-flash", "glm-5.2", "glm-4.7"],
164
+ },
165
+ minimax: {
166
+ shape: "anthropic",
167
+ baseUrl: "https://api.minimax.io/anthropic",
168
+ auth: "key",
169
+ defaultModel: "MiniMax-M2.5",
170
+ models: ["MiniMax-M3", "MiniMax-M2.5", "MiniMax-M2.1"],
171
+ },
172
+
173
+ // ── Coding plans — Anthropic wire + Bearer (measured family trait) ─────
174
+ zai: {
175
+ shape: "anthropic",
176
+ baseUrl: "https://api.z.ai/api/anthropic",
177
+ auth: "bearer",
178
+ defaultModel: "glm-5.3-flash",
179
+ models: ["glm-5.3-flash", "glm-5.3-highspeed", "glm-5.2", "glm-5-turbo"],
180
+ // Model ids are BARE here — the gateway-prefixed spelling
181
+ // (`z-ai/glm-5.3-flash`) answers 400 [1211] Unknown Model.
182
+ explicitNone: true,
183
+ },
184
+ kimi: {
185
+ shape: "anthropic",
186
+ baseUrl: "https://api.kimi.ai/coding",
187
+ auth: "bearer",
188
+ defaultModel: "kimi-for-coding",
189
+ models: ["kimi-for-coding", "kimi-for-coding-highspeed", "k3"],
190
+ },
191
+ /** Alibaba's dashscope coding plan — OpenAI-compatible per its registry. */
192
+ "alibaba-coding-plan": {
193
+ shape: "openai",
194
+ baseUrl: "https://coding-intl.dashscope.aliyuncs.com/v1",
195
+ auth: "bearer",
196
+ defaultModel: "qwen3.7-max",
197
+ models: ["qwen3.7-max", "qwen3-coder-next", "glm-4.7"],
198
+ },
199
+ /** QwenCloud's token plan — Anthropic wire (measured by tabrunner). */
200
+ qwen: {
201
+ shape: "anthropic",
202
+ baseUrl: "https://token-plan.ap-southeast-1.maas.aliyuncs.com/apps/anthropic",
203
+ auth: "bearer",
204
+ defaultModel: "qwen3.8-max",
205
+ models: ["qwen3.8-max", "qwen3.6-flash"],
206
+ },
207
+
208
+ // ── Local runtimes ──────────────────────────────────────────────────────
209
+ ollama: {
210
+ shape: "openai",
211
+ baseUrl: "http://localhost:11434/v1",
212
+ auth: "bearer",
213
+ },
214
+ lmstudio: {
215
+ shape: "openai",
216
+ baseUrl: "http://127.0.0.1:1234/v1",
217
+ auth: "bearer",
218
+ },
219
+ vllm: {
220
+ shape: "openai",
221
+ baseUrl: "http://localhost:8000/v1",
222
+ auth: "bearer",
223
+ },
224
+
225
+ // ── OAuth — the caller owns the sign-in flow and hands over the token ───
226
+ claude: {
227
+ shape: "anthropic",
228
+ baseUrl: "https://api.anthropic.com",
229
+ auth: "oauth",
230
+ defaultModel: "claude-sonnet-4-6",
231
+ models: ["claude-sonnet-4-6", "claude-opus-5"],
232
+ // The beta flag is what switches the API into OAuth-token mode (measured
233
+ // by tabrunner's Claude plan sign-in).
234
+ headers: { "anthropic-beta": "claude-code-20250219,oauth-2025-04-20" },
235
+ },
236
+ /** The Codex backend behind a ChatGPT sign-in — Responses wire, no public
237
+ * model list, so these ids are the list. */
238
+ chatgpt: {
239
+ shape: "responses",
240
+ baseUrl: "https://chatgpt.com/backend-api/codex",
241
+ auth: "oauth",
242
+ defaultModel: "gpt-5.3-codex",
243
+ models: ["gpt-5.3-codex", "gpt-5.5", "gpt-5.4-mini"],
244
+ },
245
+ /** Kimi's coding endpoint reached with a subscription token instead of a
246
+ * key — Kimi bills the two separately. */
247
+ "kimi-plan": {
248
+ shape: "anthropic",
249
+ baseUrl: "https://api.kimi.ai/coding",
250
+ auth: "oauth",
251
+ defaultModel: "kimi-for-coding",
252
+ },
253
+ "github-copilot": {
254
+ shape: "openai",
255
+ baseUrl: "https://api.githubcopilot.com",
256
+ auth: "oauth",
257
+ defaultModel: "gpt-5.6-sol",
258
+ models: ["gpt-5.6-sol", "claude-opus-5", "claude-opus-4.8", "kimi-k2.7-code"],
259
+ },
260
+ } as const satisfies Record<string, ProviderPreset>;
261
+
262
+ export type ProviderPresetId = keyof typeof PROVIDER_PRESETS;
263
+
264
+ /** Every valid preset id — the factory's unknown-id error lists these. */
265
+ export const PRESET_IDS = Object.keys(PROVIDER_PRESETS) as ProviderPresetId[];
@@ -0,0 +1,102 @@
1
+ // The one-line switch: resolve a preset id into a wired provider.
2
+ //
3
+ // Consumers used to write their own switch over providers — the same
4
+ // dispatch, re-derived per codebase, each quietly accumulating dialect
5
+ // knowledge (which gateway takes Bearer, which needs the thinking marker).
6
+ // The presets table + this factory is that dispatch, said once: a caller
7
+ // names an id and hands over a credential, and the header style, endpoint
8
+ // and adapter come from the table.
9
+ //
10
+ // `effort` passes through to the adapter unchanged — the per-endpoint
11
+ // thinking dialects (Z.ai's explicit disabled marker, OpenRouter's floors)
12
+ // are the adapters' knowledge, and this factory must not re-derive them.
13
+ import { createAnthropicProvider } from "./anthropic.ts";
14
+ import { createGeminiProvider } from "./gemini.ts";
15
+ import { createOpenAIProvider } from "./openai.ts";
16
+ import { createResponsesProvider } from "./responses.ts";
17
+ import { PRESET_IDS, PROVIDER_PRESETS, type ProviderPreset, type ProviderPresetId } from "../presets.ts";
18
+ import type { Effort, Provider } from "../types.ts";
19
+
20
+ export interface PresetProviderConfig {
21
+ /** The credential: an API key for `key`/`bearer` presets, an ACCESS TOKEN
22
+ * for `oauth` ones. Acquiring the token is the caller's job. */
23
+ apiKey: string;
24
+ /** Which model to run. Absent = the preset's `defaultModel`; a preset
25
+ * without either throws rather than sending a request nobody chose. */
26
+ model?: string;
27
+ effort?: Effort;
28
+ /** Output ceiling. The Anthropic shape requires one; adapters default it. */
29
+ maxTokens?: number;
30
+ /** Per-request headers (request ids, `ChatGPT-Account-Id`) on top of the
31
+ * preset's static protocol headers. */
32
+ headers?: Record<string, string>;
33
+ fetchImpl?: typeof fetch;
34
+ }
35
+
36
+ export function createPresetProvider(id: ProviderPresetId, config: PresetProviderConfig): Provider {
37
+ // The table is closed (`satisfies`), but a caller may hold an id as a plain
38
+ // string — validate rather than index into undefined.
39
+ if (!(id in PROVIDER_PRESETS)) {
40
+ throw new Error(
41
+ `[providerkit] Unknown provider preset "${id}". Valid ids: ${PRESET_IDS.join(", ")}`,
42
+ );
43
+ }
44
+ const preset: ProviderPreset = PROVIDER_PRESETS[id];
45
+ const model = config.model ?? preset.defaultModel;
46
+ if (!model) {
47
+ throw new Error(`[providerkit] Preset "${id}" has no defaultModel — pass a model.`);
48
+ }
49
+ const headers = { ...preset.headers, ...config.headers };
50
+
51
+ switch (preset.shape) {
52
+ case "anthropic":
53
+ // `key` rides Anthropic's native x-api-key; coding plans and OAuth
54
+ // tokens read Bearer (measured across the family's coding endpoints).
55
+ return createAnthropicProvider({
56
+ apiKey: config.apiKey,
57
+ model,
58
+ effort: config.effort,
59
+ maxTokens: config.maxTokens,
60
+ baseUrl: preset.baseUrl,
61
+ id,
62
+ headers,
63
+ bearer: preset.auth !== "key",
64
+ // The endpoint's thinking dialect rides the table (zai: silence means
65
+ // the model default, which is ON — "none" must be said out loud).
66
+ ...(preset.explicitNone ? { explicitNone: true } : {}),
67
+ fetchImpl: config.fetchImpl,
68
+ });
69
+ case "openai":
70
+ return createOpenAIProvider({
71
+ id,
72
+ apiKey: config.apiKey,
73
+ model,
74
+ effort: config.effort,
75
+ maxTokens: config.maxTokens,
76
+ baseUrl: preset.baseUrl,
77
+ headers,
78
+ fetchImpl: config.fetchImpl,
79
+ });
80
+ case "responses":
81
+ return createResponsesProvider({
82
+ apiKey: config.apiKey,
83
+ model,
84
+ effort: config.effort,
85
+ maxTokens: config.maxTokens,
86
+ baseUrl: preset.baseUrl,
87
+ id,
88
+ headers,
89
+ fetchImpl: config.fetchImpl,
90
+ });
91
+ case "gemini":
92
+ return createGeminiProvider({
93
+ apiKey: config.apiKey,
94
+ model,
95
+ effort: config.effort,
96
+ baseUrl: preset.baseUrl,
97
+ id,
98
+ headers,
99
+ fetchImpl: config.fetchImpl,
100
+ });
101
+ }
102
+ }