codeep 3.4.0 → 3.5.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/acp/commands.d.ts +15 -0
- package/dist/acp/commands.js +39 -5
- package/dist/acp/server.d.ts +13 -0
- package/dist/acp/server.js +283 -27
- package/dist/acp/serverHandlers.js +10 -10
- package/dist/acp/session.d.ts +13 -2
- package/dist/acp/transport.d.ts +6 -0
- package/dist/acp/transport.js +98 -3
- package/dist/api/index.js +6 -3
- package/dist/config/index.js +12 -4
- package/dist/config/providers.d.ts +48 -4
- package/dist/config/providers.js +325 -88
- package/dist/renderer/agentExecution.js +116 -69
- package/dist/renderer/commands.js +36 -11
- package/dist/renderer/main.d.ts +24 -0
- package/dist/renderer/main.js +57 -2
- package/dist/utils/agent.d.ts +33 -2
- package/dist/utils/agent.js +86 -8
- package/dist/utils/agentChat.js +22 -10
- package/dist/utils/checkpoints.js +3 -0
- package/dist/utils/codeReview.js +28 -23
- package/dist/utils/git.d.ts +262 -4
- package/dist/utils/git.js +1928 -61
- package/dist/utils/gitHookInstaller.d.ts +32 -1
- package/dist/utils/gitHookInstaller.js +76 -8
- package/dist/utils/headlessReview.js +26 -5
- package/dist/utils/personalities.js +8 -2
- package/dist/utils/shell.d.ts +108 -0
- package/dist/utils/shell.js +364 -5
- package/dist/utils/taskPlanner.js +12 -4
- package/dist/utils/telegramApproval.d.ts +10 -2
- package/dist/utils/telegramApproval.js +22 -4
- package/dist/utils/tokenTracker.d.ts +13 -5
- package/dist/utils/tokenTracker.js +163 -34
- package/dist/utils/toolExecution.d.ts +41 -0
- package/dist/utils/toolExecution.js +357 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/config/providers.js
CHANGED
|
@@ -17,11 +17,15 @@ export const PROVIDERS = {
|
|
|
17
17
|
supportsNativeTools: true,
|
|
18
18
|
},
|
|
19
19
|
},
|
|
20
|
+
// The plan accepts exactly these two ("Only the following two models can be
|
|
21
|
+
// called: GLM-5.3, GLM-5.3-Flash" — docs.z.ai/devpack/faq, 2026-09-23). It
|
|
22
|
+
// routes GLM-5.2/5.1 to 5.3, so a 5.2 entry labelled 5.3 as an older model,
|
|
23
|
+
// and Turbo is not on the plan at all: Z.AI warns other models risk
|
|
24
|
+
// "unexpected charges", which a flat-fee surface would never show in /cost.
|
|
25
|
+
// Stored ids migrate via RETIRED_MODEL_REPLACEMENTS.
|
|
20
26
|
models: [
|
|
21
27
|
{ id: 'glm-5.3', name: 'GLM-5.3', description: 'Latest flagship for project-scale engineering (1M context)' },
|
|
22
28
|
{ id: 'glm-5.3-flash', name: 'GLM-5.3 Flash', description: 'Same 1M context at roughly a ninth of the price' },
|
|
23
|
-
{ id: 'glm-5.2', name: 'GLM-5.2', description: 'Previous flagship for project-scale engineering (1M context)' },
|
|
24
|
-
{ id: 'glm-5-turbo', name: 'GLM-5 Turbo', description: 'Fast GLM-5 variant, available to all users' },
|
|
25
29
|
],
|
|
26
30
|
defaultModel: 'glm-5.3',
|
|
27
31
|
defaultProtocol: 'openai',
|
|
@@ -48,14 +52,16 @@ export const PROVIDERS = {
|
|
|
48
52
|
},
|
|
49
53
|
},
|
|
50
54
|
models: [
|
|
51
|
-
// GLM-5.3 reached the standalone pay-per-use API on 2026-08-
|
|
52
|
-
// priced on docs.z.ai/guides/overview/pricing
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
+
// GLM-5.3 reached the standalone pay-per-use API on 2026-08-18 and is
|
|
56
|
+
// priced on docs.z.ai/guides/overview/pricing, as is FlashX (not on
|
|
57
|
+
// either Coding Plan). GLM-5-Turbo is no longer on that price list, the
|
|
58
|
+
// models overview or the OpenAPI model enum — it was last listed on
|
|
59
|
+
// 2026-07-31, with no deprecation notice — so it is not offered here;
|
|
60
|
+
// stored configs move to Flash. China (`z.ai-cn-api`) still sells it.
|
|
55
61
|
{ id: 'glm-5.3', name: 'GLM-5.3', description: 'Latest flagship for project-scale engineering (1M context)' },
|
|
56
62
|
{ id: 'glm-5.3-flash', name: 'GLM-5.3 Flash', description: 'Same 1M context at roughly a ninth of the price' },
|
|
63
|
+
{ id: 'glm-5.3-flashx', name: 'GLM-5.3 FlashX', description: 'Faster GLM-5.3 Flash (about 200 tokens/s), 1M context' },
|
|
57
64
|
{ id: 'glm-5.2', name: 'GLM-5.2', description: 'Previous flagship for project-scale engineering (1M context)' },
|
|
58
|
-
{ id: 'glm-5-turbo', name: 'GLM-5 Turbo', description: 'Fast GLM-5 variant' },
|
|
59
65
|
],
|
|
60
66
|
defaultModel: 'glm-5.3',
|
|
61
67
|
defaultProtocol: 'openai',
|
|
@@ -80,12 +86,13 @@ export const PROVIDERS = {
|
|
|
80
86
|
supportsNativeTools: true,
|
|
81
87
|
},
|
|
82
88
|
},
|
|
83
|
-
//
|
|
84
|
-
//
|
|
89
|
+
// The China plan now carries the same two models on every tier ("所有套餐均
|
|
90
|
+
// 支持 GLM-5.3、GLM-5.3-Flash" — docs.bigmodel.cn/cn/coding-plan/overview) and
|
|
91
|
+
// switches GLM-5.2/5.1 to 5.3 and GLM-5-Turbo to 5.3-Flash. FlashX is not on
|
|
92
|
+
// the plan. Stored ids migrate via RETIRED_MODEL_REPLACEMENTS.
|
|
85
93
|
models: [
|
|
86
94
|
{ id: 'glm-5.3', name: 'GLM-5.3', description: 'Latest flagship for project-scale engineering (1M context)' },
|
|
87
|
-
{ id: 'glm-5.
|
|
88
|
-
{ id: 'glm-5-turbo', name: 'GLM-5 Turbo', description: 'Fast GLM-5 variant, available to all users' },
|
|
95
|
+
{ id: 'glm-5.3-flash', name: 'GLM-5.3 Flash', description: 'Same 1M context, much lighter on plan quota' },
|
|
89
96
|
],
|
|
90
97
|
defaultModel: 'glm-5.3',
|
|
91
98
|
defaultProtocol: 'openai',
|
|
@@ -114,7 +121,10 @@ export const PROVIDERS = {
|
|
|
114
121
|
models: [
|
|
115
122
|
{ id: 'glm-5.3', name: 'GLM-5.3', description: 'Latest flagship for project-scale engineering (1M context)' },
|
|
116
123
|
{ id: 'glm-5.3-flash', name: 'GLM-5.3 Flash', description: 'Same 1M context at a tenth of the price' },
|
|
124
|
+
{ id: 'glm-5.3-flashx', name: 'GLM-5.3 FlashX', description: 'Faster GLM-5.3 Flash (about 200 tokens/s), 1M context' },
|
|
117
125
|
{ id: 'glm-5.2', name: 'GLM-5.2', description: 'Previous flagship for project-scale engineering (1M context)' },
|
|
126
|
+
// Still listed and priced on BigModel pay-per-use (CNY 5/22 below 32K
|
|
127
|
+
// input); only the China Coding Plan reroutes it.
|
|
118
128
|
{ id: 'glm-5-turbo', name: 'GLM-5 Turbo', description: 'Fast GLM-5 variant' },
|
|
119
129
|
],
|
|
120
130
|
defaultModel: 'glm-5.3',
|
|
@@ -212,17 +222,23 @@ export const PROVIDERS = {
|
|
|
212
222
|
supportsNativeTools: true,
|
|
213
223
|
},
|
|
214
224
|
},
|
|
215
|
-
//
|
|
216
|
-
//
|
|
217
|
-
//
|
|
218
|
-
//
|
|
219
|
-
//
|
|
220
|
-
//
|
|
225
|
+
// DeepSeek's pricing page names `deepseek-flash` (V4.1 Flash) as the model
|
|
226
|
+
// to use, so it stays the default; the retired `deepseek-v4-flash` ids are
|
|
227
|
+
// served by it and migrate via RETIRED_MODEL_REPLACEMENTS.
|
|
228
|
+
//
|
|
229
|
+
// V4 Pro was announced to route to Flash from 2026-09-14, and Codeep 3.3.0
|
|
230
|
+
// migrated it away. DeepSeek reversed that on 2026-09-11, before the
|
|
231
|
+
// cutover: the changelog's 09-10 entry now says V4 Pro service continues
|
|
232
|
+
// "with the billing method remaining unchanged", and the pricing page and
|
|
233
|
+
// API reference list `deepseek-v4-pro` (DeepSeek-V4-Pro-0813) beside Flash.
|
|
234
|
+
// The 09-10 news post still carries the old routing text; the changelog is
|
|
235
|
+
// the newer source. So Pro is a separate, separately billed model again.
|
|
221
236
|
//
|
|
222
|
-
//
|
|
223
|
-
// `deepseek/deepseek-v4.
|
|
237
|
+
// The ids differ on OpenRouter: `deepseek/deepseek-v4.1-flash`, and
|
|
238
|
+
// `deepseek/deepseek-v4-pro-0813` for this Pro (see the fallback list).
|
|
224
239
|
models: [
|
|
225
240
|
{ id: 'deepseek-flash', name: 'DeepSeek V4.1 Flash', description: 'Current DeepSeek model — thinking on by default, vision, 1M context, 384K output' },
|
|
241
|
+
{ id: 'deepseek-v4-pro', name: 'DeepSeek V4 Pro', description: 'Larger V4 model (V4-Pro-0813) — thinking on, 1M context, no vision, about 4x Flash\'s price' },
|
|
226
242
|
],
|
|
227
243
|
defaultModel: 'deepseek-flash',
|
|
228
244
|
defaultProtocol: 'openai',
|
|
@@ -243,11 +259,18 @@ export const PROVIDERS = {
|
|
|
243
259
|
protocols: {
|
|
244
260
|
openai: { baseUrl: 'https://api.kimi.com/coding/v1', authHeader: 'Bearer', supportsNativeTools: true },
|
|
245
261
|
},
|
|
262
|
+
// Kimi Code upgraded `kimi-for-coding` in place to K2.8 Preview on
|
|
263
|
+
// 2026-09-11 (1,048,576 context on every tier, effort low/high/max). The
|
|
264
|
+
// plans were then renamed: Plus ≈ Moderato, Pro ≈ Allegretto, and the new Go
|
|
265
|
+
// tier has no coding quota. K3 reaches 1M context only on Pro/Allegretto; on
|
|
266
|
+
// Plus/Moderato it is capped at 256K, and going past that returns HTTP 401
|
|
267
|
+
// "Your current plan supports only kimi-k3 up to 256K context"
|
|
268
|
+
// (kimi.com/code/docs/en/kimi-code/models.html, error-reference.html).
|
|
246
269
|
models: [
|
|
247
|
-
{ id: 'kimi-for-coding', name: 'Kimi Code', description: '
|
|
248
|
-
{ id: 'k3', name: 'Kimi K3', description: '1M
|
|
249
|
-
{ id: 'k3-256k', name: 'Kimi K3 (256K)', description: 'K3 with a
|
|
250
|
-
{ id: 'kimi-for-coding-highspeed', name: 'Kimi Code (High-Speed)', description: '
|
|
270
|
+
{ id: 'kimi-for-coding', name: 'Kimi Code', description: 'K2.8 Preview, 1M context — every Kimi Code plan (Plus/Andante and above)' },
|
|
271
|
+
{ id: 'k3', name: 'Kimi K3', description: 'Flagship — 1M context on Pro/Allegretto and above; Plus/Moderato is capped at 256K (use K3 256K there)' },
|
|
272
|
+
{ id: 'k3-256k', name: 'Kimi K3 (256K)', description: 'K3 with a 256K context window — Plus/Moderato plan or higher' },
|
|
273
|
+
{ id: 'kimi-for-coding-highspeed', name: 'Kimi Code (High-Speed)', description: 'K2.7 Code HighSpeed, 256K context — Pro/Allegretto plan or higher' },
|
|
251
274
|
],
|
|
252
275
|
defaultModel: 'kimi-for-coding',
|
|
253
276
|
defaultProtocol: 'openai',
|
|
@@ -309,15 +332,17 @@ export const PROVIDERS = {
|
|
|
309
332
|
openai: { baseUrl: 'https://api.x.ai/v1', authHeader: 'Bearer', supportsNativeTools: true },
|
|
310
333
|
},
|
|
311
334
|
models: [
|
|
312
|
-
{ id: 'grok-4.
|
|
313
|
-
{ id: 'grok-4.
|
|
335
|
+
{ id: 'grok-4.7', name: 'Grok 4.7', description: 'Flagship reasoning model — xAI recommends it for code, 500K context' },
|
|
336
|
+
{ id: 'grok-4.6', name: 'Grok 4.6', description: 'Previous flagship reasoning model, 500K context' },
|
|
337
|
+
{ id: 'grok-4.5', name: 'Grok 4.5', description: 'Older flagship reasoning model, 500K context' },
|
|
314
338
|
{ id: 'grok-build-0.1', name: 'Grok Build 0.1', description: 'Agentic coding model — fast, 256K context' },
|
|
315
339
|
{ id: 'grok-4.3', name: 'Grok 4.3', description: 'Older flagship, 1M context' },
|
|
316
340
|
],
|
|
317
|
-
// Stays on the agentic coder, not the new flagship. grok-4.
|
|
318
|
-
// model
|
|
319
|
-
//
|
|
320
|
-
//
|
|
341
|
+
// Stays on the agentic coder, not the new flagship. grok-4.7 is the better
|
|
342
|
+
// model — xAI's models page recommends only it, "including code", and it is
|
|
343
|
+
// the default of xAI's own Grok Build agent — but it bills 2x input and 3x
|
|
344
|
+
// output against grok-build-0.1, so moving every unpinned user onto it
|
|
345
|
+
// silently is not ours to decide. It is one `/model` away.
|
|
321
346
|
defaultModel: 'grok-build-0.1',
|
|
322
347
|
defaultProtocol: 'openai',
|
|
323
348
|
useMaxCompletionTokens: true, // reasoning models reject max_tokens
|
|
@@ -358,8 +383,7 @@ export const PROVIDERS = {
|
|
|
358
383
|
openai: { baseUrl: 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1', authHeader: 'Bearer', supportsNativeTools: true },
|
|
359
384
|
},
|
|
360
385
|
// 3.8 Max and Flash are GA on Model Studio international and cost less
|
|
361
|
-
// than the 3.7 Max / 3.6 Flash they sit above.
|
|
362
|
-
// separate listing and is not changed on this evidence.
|
|
386
|
+
// than the 3.7 Max / 3.6 Flash they sit above.
|
|
363
387
|
models: [
|
|
364
388
|
{ id: 'qwen3.8-max', name: 'Qwen3.8-Max', description: 'Latest flagship for complex coding and reasoning (1M context)' },
|
|
365
389
|
{ id: 'qwen3.8-flash', name: 'Qwen3.8-Flash', description: 'Low-latency, low-cost multimodal model (1M context)' },
|
|
@@ -382,14 +406,22 @@ export const PROVIDERS = {
|
|
|
382
406
|
protocols: {
|
|
383
407
|
openai: { baseUrl: 'https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1', authHeader: 'Bearer', supportsNativeTools: true },
|
|
384
408
|
},
|
|
409
|
+
// qwen3.8-max-preview is retired here: Alibaba routes it to qwen3.8-max,
|
|
410
|
+
// bills it at that rate and says to update the id (token-plan-personal-
|
|
411
|
+
// overview, 2026-09-23); stored configs migrate. The plan now has Personal
|
|
412
|
+
// and Team editions on this same URL and key format, with different
|
|
413
|
+
// allowlists — qwen3.6-plus is Team-only, and a Personal key gets
|
|
414
|
+
// "403 AccessDenied.Unpurchased" for it. Nothing here can tell the two
|
|
415
|
+
// editions apart, so the entry says so rather than disappearing on Team.
|
|
385
416
|
models: [
|
|
386
|
-
{ id: 'qwen3.8-max
|
|
387
|
-
{ id: 'qwen3.
|
|
417
|
+
{ id: 'qwen3.8-max', name: 'Qwen3.8-Max', description: 'Token Plan flagship for complex agentic work (1M context)' },
|
|
418
|
+
{ id: 'qwen3.8-flash', name: 'Qwen3.8-Flash', description: 'Low-latency, credit-efficient model (1M context)' },
|
|
419
|
+
{ id: 'qwen3.7-max', name: 'Qwen3.7-Max', description: 'Previous flagship for complex coding and reasoning' },
|
|
388
420
|
{ id: 'qwen3.7-plus', name: 'Qwen3.7-Plus', description: 'Balanced quality and throughput' },
|
|
389
|
-
{ id: 'qwen3.6-plus', name: 'Qwen3.6-Plus', description: '
|
|
390
|
-
{ id: 'qwen3.6-flash', name: 'Qwen3.6-Flash', description: '
|
|
421
|
+
{ id: 'qwen3.6-plus', name: 'Qwen3.6-Plus', description: 'Team edition only — a Personal plan returns 403 for it' },
|
|
422
|
+
{ id: 'qwen3.6-flash', name: 'Qwen3.6-Flash', description: 'Previous low-latency, credit-efficient model' },
|
|
391
423
|
],
|
|
392
|
-
defaultModel: 'qwen3.8-max
|
|
424
|
+
defaultModel: 'qwen3.8-max',
|
|
393
425
|
defaultProtocol: 'openai',
|
|
394
426
|
maxOutputTokens: 131_072,
|
|
395
427
|
noStreamWithTools: true,
|
|
@@ -426,10 +458,18 @@ export const PROVIDERS = {
|
|
|
426
458
|
protocols: {
|
|
427
459
|
openai: { baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1', authHeader: 'Bearer', supportsNativeTools: true },
|
|
428
460
|
},
|
|
461
|
+
// 3.8 Max and Flash have been GA in China (Beijing) since 2026-08-02 and
|
|
462
|
+
// 2026-08-26, at CNY 12/36 and 0.8/2.7 (help.aliyun.com/zh/model-studio/
|
|
463
|
+
// qwen3-8-max, qwen3-8-flash). Pricing is keyed by id, so they reuse the
|
|
464
|
+
// international USD rows — an over-estimate, the same policy as z.ai-cn.
|
|
465
|
+
// The default is unchanged: 3.8 Max costs the same as 3.7 Max in Beijing,
|
|
466
|
+
// and moving unpinned users was not part of adding it.
|
|
429
467
|
models: [
|
|
430
|
-
{ id: 'qwen3.
|
|
468
|
+
{ id: 'qwen3.8-max', name: 'Qwen3.8-Max', description: 'Latest flagship for complex coding and reasoning (1M context)' },
|
|
469
|
+
{ id: 'qwen3.8-flash', name: 'Qwen3.8-Flash', description: 'Low-latency, low-cost multimodal model (1M context)' },
|
|
470
|
+
{ id: 'qwen3.7-max', name: 'Qwen3.7-Max', description: 'Previous flagship for complex coding and reasoning' },
|
|
431
471
|
{ id: 'qwen3.7-plus', name: 'Qwen3.7-Plus', description: 'Balanced quality, speed, and price (1M context)' },
|
|
432
|
-
{ id: 'qwen3.6-flash', name: 'Qwen3.6-Flash', description: '
|
|
472
|
+
{ id: 'qwen3.6-flash', name: 'Qwen3.6-Flash', description: 'Previous low-latency, low-cost multimodal model' },
|
|
433
473
|
],
|
|
434
474
|
defaultModel: 'qwen3.7-max',
|
|
435
475
|
defaultProtocol: 'openai',
|
|
@@ -446,10 +486,16 @@ export const PROVIDERS = {
|
|
|
446
486
|
protocols: {
|
|
447
487
|
openai: { baseUrl: 'https://api-inference.modelscope.cn/v1', authHeader: 'Bearer', supportsNativeTools: true },
|
|
448
488
|
},
|
|
489
|
+
// Shown only until the live catalogue loads. The previous fallback,
|
|
490
|
+
// Qwen/Qwen3-Coder-480B-A35B-Instruct, is no longer served: it is absent from
|
|
491
|
+
// api-inference.modelscope.cn/v1/models (2026-09-23) and its hub entry has
|
|
492
|
+
// SupportApiInference false. ModelScope names no successor, so this pick is
|
|
493
|
+
// Codeep's: the largest Qwen in the live list, whose model card documents
|
|
494
|
+
// tool calling ("Qwen3.5 excels in tool calling capabilities").
|
|
449
495
|
models: [
|
|
450
|
-
{ id: 'Qwen/Qwen3-
|
|
496
|
+
{ id: 'Qwen/Qwen3.5-397B-A17B', name: 'Qwen3.5 397B', description: 'Fallback model shown until the live catalog loads' },
|
|
451
497
|
],
|
|
452
|
-
defaultModel: 'Qwen/Qwen3-
|
|
498
|
+
defaultModel: 'Qwen/Qwen3.5-397B-A17B',
|
|
453
499
|
defaultProtocol: 'openai',
|
|
454
500
|
maxOutputTokens: 65_536,
|
|
455
501
|
noStreamWithTools: true,
|
|
@@ -462,7 +508,7 @@ export const PROVIDERS = {
|
|
|
462
508
|
},
|
|
463
509
|
'openai': {
|
|
464
510
|
name: 'OpenAI',
|
|
465
|
-
description: 'GPT
|
|
511
|
+
description: 'GPT models',
|
|
466
512
|
protocols: {
|
|
467
513
|
openai: {
|
|
468
514
|
baseUrl: 'https://api.openai.com/v1',
|
|
@@ -470,9 +516,21 @@ export const PROVIDERS = {
|
|
|
470
516
|
supportsNativeTools: true,
|
|
471
517
|
},
|
|
472
518
|
},
|
|
519
|
+
// Chat Completions is the only OpenAI endpoint Codeep calls, and GPT-6 has a
|
|
520
|
+
// documented tool restriction there (developers.openai.com guides/
|
|
521
|
+
// latest-model and reasoning): Sol and Luna call tools only with
|
|
522
|
+
// reasoning_effort "none", and "Chat Completions does not support function
|
|
523
|
+
// calling with GPT-6 Astra" at all. So Astra is not offered until a
|
|
524
|
+
// Responses API transport exists — stored configs move to Sol — and Sol and
|
|
525
|
+
// Luna run agent turns with reasoning off (see reasoningParamsFor).
|
|
526
|
+
//
|
|
527
|
+
// The default stays 5.6 Sol: it is the newest model OpenAI documents with
|
|
528
|
+
// reasoning AND tool calls on Chat Completions ("The Chat Completions
|
|
529
|
+
// examples use GPT-5.6 for compatibility" — function-calling guide).
|
|
473
530
|
models: [
|
|
474
|
-
{ id: 'gpt-6-
|
|
475
|
-
{ id: 'gpt-
|
|
531
|
+
{ id: 'gpt-5.6-sol', name: 'GPT-5.6 Sol', description: 'Most capable GPT for coding & agentic work on Codeep\'s transport' },
|
|
532
|
+
{ id: 'gpt-6-sol', name: 'GPT-6 Sol', description: 'GPT-6 at $2/$10, 1M context — agent turns run with reasoning off (tools need effort "none" here); /thinking applies to plain chat' },
|
|
533
|
+
{ id: 'gpt-6-luna', name: 'GPT-6 Luna', description: 'Cheapest GPT-6 ($0.10/$0.50), 1M context — agent turns run with reasoning off, as for Sol' },
|
|
476
534
|
{ id: 'gpt-5.6-terra', name: 'GPT-5.6 Terra', description: 'Balanced — GPT-5.5 quality at about half the price' },
|
|
477
535
|
{ id: 'gpt-5.6-luna', name: 'GPT-5.6 Luna', description: 'Fast and cheap — high-volume workloads' },
|
|
478
536
|
],
|
|
@@ -497,12 +555,20 @@ export const PROVIDERS = {
|
|
|
497
555
|
},
|
|
498
556
|
models: [
|
|
499
557
|
{ id: 'claude-fable-5-1', name: 'Claude Fable 5.1', description: 'Most capable — hardest reasoning & long-horizon agentic work' },
|
|
558
|
+
{ id: 'claude-opus-5-5', name: 'Claude Opus 5.5', description: 'Complex agentic coding & deep reasoning — $4/$20, 1M context' },
|
|
500
559
|
{ id: 'claude-fable-5', name: 'Claude Fable 5', description: 'Superseded by 5.1 — same price, kept for pinned configs' },
|
|
501
|
-
{ id: 'claude-opus-5', name: 'Claude Opus 5', description: '
|
|
560
|
+
{ id: 'claude-opus-5', name: 'Claude Opus 5', description: 'Legacy since Opus 5.5 — kept for pinned configs' },
|
|
502
561
|
{ id: 'claude-sonnet-5', name: 'Claude Sonnet 5', description: 'Best balance of speed and intelligence' },
|
|
503
562
|
{ id: 'claude-haiku-4-5-20251001', name: 'Claude Haiku', description: 'Fastest and most affordable' },
|
|
504
563
|
],
|
|
505
|
-
|
|
564
|
+
// Anthropic's models overview now says to "start with Claude Opus 5.5 for
|
|
565
|
+
// most workloads", and it is 20% cheaper than Opus 5 (now "Active
|
|
566
|
+
// (legacy)", retiring no sooner than 2027-07-24 — so no migration). One
|
|
567
|
+
// behaviour change comes with it: Opus 5.5 defaults to MEDIUM effort where
|
|
568
|
+
// Opus 5 defaulted to high, and /thinking auto sends no effort, so an
|
|
569
|
+
// unpinned user runs one level lower than before. It also thinks more per
|
|
570
|
+
// turn at a given effort — see minResponseTokensFor.
|
|
571
|
+
defaultModel: 'claude-opus-5-5',
|
|
506
572
|
defaultProtocol: 'anthropic',
|
|
507
573
|
envKey: 'ANTHROPIC_API_KEY',
|
|
508
574
|
groupLabel: 'Anthropic',
|
|
@@ -543,28 +609,38 @@ export const PROVIDERS = {
|
|
|
543
609
|
supportsNativeTools: true,
|
|
544
610
|
},
|
|
545
611
|
},
|
|
546
|
-
//
|
|
612
|
+
// A short fallback — the full catalog (100+) is fetched lazily via
|
|
547
613
|
// fetchOpenRouterModels() because dynamicModels is true.
|
|
548
614
|
// We keep these hardcoded so first-time users without network
|
|
549
615
|
// get a working dropdown.
|
|
550
616
|
models: [
|
|
551
617
|
{ id: 'openrouter/auto', name: 'Auto-route', description: 'OpenRouter picks the best model for the task' },
|
|
552
|
-
|
|
618
|
+
// Dotted, as OpenRouter's /api/v1/models lists them. The hyphenated
|
|
619
|
+
// `anthropic/claude-fable-5-1` this used to carry resolves on OpenRouter's
|
|
620
|
+
// metadata lookup but is absent from the models list, so a pick made
|
|
621
|
+
// before the live catalogue loaded matched nothing in it.
|
|
622
|
+
{ id: 'anthropic/claude-fable-5.1', name: 'Claude Fable 5.1', description: 'Anthropic — most capable' },
|
|
623
|
+
{ id: 'anthropic/claude-opus-5.5', name: 'Claude Opus 5.5', description: 'Anthropic — current Opus' },
|
|
553
624
|
{ id: 'anthropic/claude-fable-5', name: 'Claude Fable 5', description: 'Anthropic — superseded by 5.1' },
|
|
554
|
-
{ id: 'anthropic/claude-opus-5', name: 'Claude Opus 5', description: 'Anthropic —
|
|
625
|
+
{ id: 'anthropic/claude-opus-5', name: 'Claude Opus 5', description: 'Anthropic — legacy Opus' },
|
|
555
626
|
{ id: 'anthropic/claude-sonnet-5', name: 'Claude Sonnet 5', description: 'Anthropic — balanced' },
|
|
556
627
|
{ id: 'openai/gpt-6-astra', name: 'GPT-6 Astra', description: 'OpenAI — frontier' },
|
|
628
|
+
{ id: 'openai/gpt-6-sol', name: 'GPT-6 Sol', description: 'OpenAI — GPT-6, balanced' },
|
|
629
|
+
{ id: 'openai/gpt-6-luna', name: 'GPT-6 Luna', description: 'OpenAI — GPT-6, fast/cheap' },
|
|
557
630
|
{ id: 'openai/gpt-5.6-sol', name: 'GPT-5.6 Sol', description: 'OpenAI — flagship' },
|
|
558
631
|
{ id: 'openai/gpt-5.6-luna', name: 'GPT-5.6 Luna', description: 'OpenAI — fast/efficient' },
|
|
559
632
|
{ id: 'google/gemini-3.8-flash', name: 'Gemini 3.8 Flash', description: 'Google — latest production Flash' },
|
|
560
633
|
{ id: 'google/gemini-3.7-flash', name: 'Gemini 3.7 Flash', description: 'Google — previous production Flash' },
|
|
561
634
|
{ id: 'deepseek/deepseek-v4.1-flash', name: 'DeepSeek V4.1 Flash', description: 'DeepSeek — current model' },
|
|
635
|
+
// The GA Pro, with a DeepSeek-hosted endpoint. `deepseek/deepseek-v4-pro`
|
|
636
|
+
// is the April 0423 preview, served only by third parties.
|
|
637
|
+
{ id: 'deepseek/deepseek-v4-pro-0813', name: 'DeepSeek V4 Pro', description: 'DeepSeek — larger V4 model' },
|
|
562
638
|
{ id: 'moonshotai/kimi-k3', name: 'Kimi K3', description: 'Moonshot — long-horizon coding' },
|
|
563
639
|
// Dated on purpose: OpenRouter lists only the snapshot. The undated
|
|
564
640
|
// `qwen/qwen3.8-max` this used to carry does not exist there, so picking
|
|
565
641
|
// it before the live catalogue loaded was an error.
|
|
566
642
|
{ id: 'qwen/qwen3.8-max-0902', name: 'Qwen 3.8 Max', description: 'Alibaba — latest flagship' },
|
|
567
|
-
{ id: 'x-ai/grok-4.
|
|
643
|
+
{ id: 'x-ai/grok-4.7', name: 'Grok 4.7', description: 'xAI — flagship reasoning' },
|
|
568
644
|
],
|
|
569
645
|
defaultModel: 'openrouter/auto',
|
|
570
646
|
defaultProtocol: 'openai',
|
|
@@ -620,22 +696,36 @@ export function getProvider(id) {
|
|
|
620
696
|
* Exact migrations for curated model ids that vendors replaced.
|
|
621
697
|
*
|
|
622
698
|
* Keep this deliberately narrower than the provider catalogue. Dynamic
|
|
623
|
-
* OpenRouter/Ollama/custom ids are user-controlled and must never be rewritten
|
|
699
|
+
* OpenRouter/Ollama/custom ids are user-controlled and must never be rewritten;
|
|
700
|
+
* ModelScope's one entry is the exception, explained where it sits.
|
|
624
701
|
*/
|
|
625
702
|
const RETIRED_MODEL_REPLACEMENTS = {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
703
|
+
// Both GLM Coding Plans accept exactly GLM-5.3 and GLM-5.3-Flash. Z.AI routes
|
|
704
|
+
// 5.2 and 5.1 to 5.3 on both, and the China plan routes Turbo to 5.3-Flash.
|
|
705
|
+
// Plain glm-5, and Turbo on the international plan, are Codeep's extension of
|
|
706
|
+
// the same routing: neither plan's text names them.
|
|
707
|
+
'z.ai': { 'glm-5.2': 'glm-5.3', 'glm-5.1': 'glm-5.3', 'glm-5': 'glm-5.3', 'glm-5-turbo': 'glm-5.3-flash' },
|
|
708
|
+
// Pay-per-use still sells 5.2 as its own id. Turbo left the international
|
|
709
|
+
// price list and model enum with no notice and no named successor, so it
|
|
710
|
+
// follows the China plan's routing to Flash.
|
|
711
|
+
'z.ai-api': { 'glm-5.1': 'glm-5.2', 'glm-5': 'glm-5.2', 'glm-5-turbo': 'glm-5.3-flash' },
|
|
712
|
+
'z.ai-cn': { 'glm-5.2': 'glm-5.3', 'glm-5.1': 'glm-5.3', 'glm-5': 'glm-5.3', 'glm-5-turbo': 'glm-5.3-flash' },
|
|
629
713
|
'z.ai-cn-api': { 'glm-5.1': 'glm-5.2', 'glm-5': 'glm-5.2' },
|
|
630
714
|
google: {
|
|
631
715
|
'gemini-3.1-flash-lite': 'gemini-3.5-flash-lite',
|
|
716
|
+
// Google's deprecations table names 3.6 Flash (no shutdown date yet). Its
|
|
717
|
+
// /whats-new-gemini-3.5 guide suggests 3.5 Flash instead; the lifecycle
|
|
718
|
+
// table is the dedicated source, and 3.5 Flash would cost twice as much.
|
|
719
|
+
'gemini-3-flash-preview': 'gemini-3.6-flash',
|
|
720
|
+
// Shut down 2026-03-09; the server already aliases the id to 3.1 Pro.
|
|
721
|
+
'gemini-3-pro-preview': 'gemini-3.1-pro-preview',
|
|
632
722
|
},
|
|
633
|
-
//
|
|
634
|
-
//
|
|
723
|
+
// The V4 Flash ids are retired and served by V4.1 Flash. There is no V4 Pro
|
|
724
|
+
// entry: DeepSeek cancelled its routing to Flash (see the catalogue above),
|
|
725
|
+
// and rewriting it moved users off a live, separately billed model.
|
|
635
726
|
deepseek: {
|
|
636
727
|
'deepseek-v4-flash': 'deepseek-flash',
|
|
637
728
|
'deepseek-v4-flash-vision-exp': 'deepseek-flash',
|
|
638
|
-
'deepseek-v4-pro': 'deepseek-flash',
|
|
639
729
|
},
|
|
640
730
|
grok: {
|
|
641
731
|
'grok-code-fast-1': 'grok-build-0.1',
|
|
@@ -645,6 +735,13 @@ const RETIRED_MODEL_REPLACEMENTS = {
|
|
|
645
735
|
'gpt-5.5': 'gpt-5.6-sol',
|
|
646
736
|
'gpt-5.4': 'gpt-5.6-terra',
|
|
647
737
|
'gpt-5.4-mini': 'gpt-5.6-luna',
|
|
738
|
+
// Not retired by OpenAI. Astra cannot call tools on Chat Completions at all
|
|
739
|
+
// ("Chat Completions does not support function calling with GPT-6 Astra"),
|
|
740
|
+
// and agentChat turns a 400 on a tools request into the text-tool fallback,
|
|
741
|
+
// so every agent turn on it silently ran without native tools. Sol is the
|
|
742
|
+
// GPT-6 that can call tools here. Drop this entry once a Responses API
|
|
743
|
+
// transport exists and Astra is offered again.
|
|
744
|
+
'gpt-6-astra': 'gpt-6-sol',
|
|
648
745
|
},
|
|
649
746
|
'kimi-api': {
|
|
650
747
|
'kimi-k3-code': 'kimi-k3',
|
|
@@ -658,30 +755,66 @@ const RETIRED_MODEL_REPLACEMENTS = {
|
|
|
658
755
|
'kimi-k3-thinking': 'kimi-k3',
|
|
659
756
|
'kimi-k2.5': 'kimi-k2.6',
|
|
660
757
|
},
|
|
758
|
+
// Alibaba retires qwen3-coder-plus, qwen3-coder-next and bare qwen3-max on
|
|
759
|
+
// 2026-10-10, on the plans as well (notices 1949 and 1950). It names
|
|
760
|
+
// qwen3.7-plus for both coders and qwen3.7-max for qwen3-max — but 3.7 Max is
|
|
761
|
+
// not on the Coding Plan allowlist, so the two Coding Plan surfaces land
|
|
762
|
+
// qwen3-max on 3.7 Plus, exactly as their own qwen3.7-max entry does.
|
|
661
763
|
qwen: {
|
|
662
764
|
'qwen3-coder-plus': 'qwen3.7-plus',
|
|
663
765
|
'qwen3-coder-next': 'qwen3.7-plus',
|
|
664
766
|
'qwen3.7-max': 'qwen3.7-plus',
|
|
767
|
+
'qwen3-max': 'qwen3.7-plus',
|
|
665
768
|
},
|
|
769
|
+
// The coders used to go to qwen3.7-max here, which bills 6.25x the input rate
|
|
770
|
+
// of the qwen3.7-plus Alibaba names. Configs already moved stay where they
|
|
771
|
+
// are: 3.7 Max is a valid model.
|
|
666
772
|
'qwen-api': {
|
|
667
|
-
'qwen3-coder-plus': 'qwen3.7-
|
|
668
|
-
'qwen3-coder-next': 'qwen3.7-
|
|
773
|
+
'qwen3-coder-plus': 'qwen3.7-plus',
|
|
774
|
+
'qwen3-coder-next': 'qwen3.7-plus',
|
|
669
775
|
'qwen3-coder-flash': 'qwen3.6-flash',
|
|
776
|
+
'qwen3-max': 'qwen3.7-max',
|
|
777
|
+
},
|
|
778
|
+
// The preview is retired and routed to qwen3.8-max, which Alibaba says to use.
|
|
779
|
+
'qwen-token-plan': {
|
|
780
|
+
'qwen3.8-max-preview': 'qwen3.8-max',
|
|
781
|
+
'qwen3-coder-plus': 'qwen3.7-plus',
|
|
782
|
+
'qwen3-coder-next': 'qwen3.7-plus',
|
|
783
|
+
'qwen3-max': 'qwen3.7-max',
|
|
670
784
|
},
|
|
671
785
|
'qwen-cn': {
|
|
672
786
|
'qwen3-coder-plus': 'qwen3.7-plus',
|
|
673
787
|
'qwen3-coder-next': 'qwen3.7-plus',
|
|
674
788
|
'qwen3.7-max': 'qwen3.7-plus',
|
|
789
|
+
'qwen3-max': 'qwen3.7-plus',
|
|
675
790
|
},
|
|
676
791
|
'qwen-cn-api': {
|
|
677
|
-
'qwen3-coder-plus': 'qwen3.7-
|
|
678
|
-
'qwen3-coder-next': 'qwen3.7-
|
|
792
|
+
'qwen3-coder-plus': 'qwen3.7-plus',
|
|
793
|
+
'qwen3-coder-next': 'qwen3.7-plus',
|
|
679
794
|
'qwen3-coder-flash': 'qwen3.6-flash',
|
|
795
|
+
'qwen3-max': 'qwen3.7-max',
|
|
796
|
+
},
|
|
797
|
+
// The one entry on a dynamic catalogue, and the exception to the rule above:
|
|
798
|
+
// the 480B coder was Codeep's own fallback default, so most configs holding
|
|
799
|
+
// it never chose it, and ModelScope stopped serving it (see the catalogue
|
|
800
|
+
// entry). Exact id only; every other ModelScope id stays the user's. Drop
|
|
801
|
+
// this if ModelScope serves the 480B again.
|
|
802
|
+
modelscope: {
|
|
803
|
+
'Qwen/Qwen3-Coder-480B-A35B-Instruct': 'Qwen/Qwen3.5-397B-A17B',
|
|
680
804
|
},
|
|
681
805
|
};
|
|
806
|
+
/**
|
|
807
|
+
* One exact lookup, never followed further: every target must already be a
|
|
808
|
+
* model its own provider offers (providers.test.ts holds the map to that), so a
|
|
809
|
+
* chain can never be needed and the macOS mirror stays a flat table too.
|
|
810
|
+
*/
|
|
682
811
|
export function replacementModelFor(providerId, modelId) {
|
|
683
812
|
return RETIRED_MODEL_REPLACEMENTS[providerId]?.[modelId];
|
|
684
813
|
}
|
|
814
|
+
/** The whole map, read-only — for the invariant test and nothing else. */
|
|
815
|
+
export function retiredModelReplacements() {
|
|
816
|
+
return RETIRED_MODEL_REPLACEMENTS;
|
|
817
|
+
}
|
|
685
818
|
/**
|
|
686
819
|
* Curated display order for the first-run login flow + `/provider` /
|
|
687
820
|
* `/login` pickers. Headline / popular providers float to the top so
|
|
@@ -811,11 +944,16 @@ export function providerNoStreamWithTools(providerId) {
|
|
|
811
944
|
* omission as default. Kimi K2.x code/thinking models fix temperature
|
|
812
945
|
* internally and 400 on any custom value, so they're here too. Google removed
|
|
813
946
|
* the deprecated sampling parameters outright in the Gemini 3.7 generation.
|
|
947
|
+
* GPT-6 takes temperature/top_p only at reasoning_effort "none" (Astra never):
|
|
948
|
+
* the direct `openai` provider already omits them for every model through
|
|
949
|
+
* requiresDefaultTemperature, so this entry is for `openai/gpt-6-*` on
|
|
950
|
+
* OpenRouter, the one path where a GPT-6 id could still be sent one.
|
|
814
951
|
*/
|
|
815
952
|
const SAMPLING_PARAMS_REJECTED = [
|
|
816
953
|
'claude-fable-5', 'claude-opus-5', 'claude-opus-4-8', 'claude-opus-4-7', 'claude-sonnet-5',
|
|
817
954
|
'kimi-k3', 'kimi-k2.7-code', 'kimi-for-coding', 'k3',
|
|
818
955
|
'gemini-3.7-flash', 'gemini-3.8-flash',
|
|
956
|
+
'gpt-6',
|
|
819
957
|
];
|
|
820
958
|
export function modelRejectsSamplingParams(model) {
|
|
821
959
|
// Canonicalize both sides. OpenRouter routes these as `google/gemini-3.7-flash`
|
|
@@ -837,6 +975,25 @@ export function getEffectiveMaxTokens(providerId, requested) {
|
|
|
837
975
|
return requested;
|
|
838
976
|
return Math.min(requested, provider.maxOutputTokens);
|
|
839
977
|
}
|
|
978
|
+
/**
|
|
979
|
+
* The smallest response budget (`max_tokens`) worth sending this model, or 0
|
|
980
|
+
* for no floor. Callers take the larger of this and whatever they would have
|
|
981
|
+
* sent, then apply getEffectiveMaxTokens as usual.
|
|
982
|
+
*
|
|
983
|
+
* Claude Opus 5.5 thinks on every request — adaptive thinking cannot be turned
|
|
984
|
+
* off — and "tends to think more per turn than Claude Opus 5" at the same
|
|
985
|
+
* effort; Anthropic's notes say to "leave room in max_tokens for the thinking",
|
|
986
|
+
* which spends the same limit as the answer. The task planner's 2048, or a
|
|
987
|
+
* maxTokens lowered in /settings, could go on thinking alone and cut the reply
|
|
988
|
+
* off. 32K is Codeep's own default; the Max tier gets 64K, where Anthropic's
|
|
989
|
+
* advice for max effort on Opus 5 is "starting at 64k tokens". Matched on the
|
|
990
|
+
* canonical id, so `anthropic/claude-opus-5.5` on OpenRouter is covered too.
|
|
991
|
+
*/
|
|
992
|
+
export function minResponseTokensFor(model, tier) {
|
|
993
|
+
if (!idMatches(canonicalModelId(model), 'claude-opus-5-5'))
|
|
994
|
+
return 0;
|
|
995
|
+
return tier === 'max' ? 65_536 : 32_768;
|
|
996
|
+
}
|
|
840
997
|
export const REASONING_TIERS = ['auto', 'low', 'medium', 'high', 'max'];
|
|
841
998
|
/**
|
|
842
999
|
* Canonicalize a model id for capability matching: lowercase, drop any
|
|
@@ -855,6 +1012,64 @@ export function canonicalModelId(model) {
|
|
|
855
1012
|
function idMatches(id, prefix) {
|
|
856
1013
|
return id === prefix || id.startsWith(`${prefix}-`);
|
|
857
1014
|
}
|
|
1015
|
+
/**
|
|
1016
|
+
* GPT-6 Sol and Luna on Chat Completions support function calling "only with
|
|
1017
|
+
* `reasoning_effort` set to `none`" (developers.openai.com models/gpt-6-sol,
|
|
1018
|
+
* guides/latest-model). So a request that carries tools to them must send
|
|
1019
|
+
* "none", whatever /thinking says. Direct `openai` only: OpenRouter may reach
|
|
1020
|
+
* OpenAI through the Responses API, where the rule does not apply, and Astra
|
|
1021
|
+
* rejects "none" with a 400 (it is not offered on `openai` at all).
|
|
1022
|
+
*/
|
|
1023
|
+
export function toolsForceReasoningOff(providerId, model) {
|
|
1024
|
+
if (providerId !== 'openai')
|
|
1025
|
+
return false;
|
|
1026
|
+
const id = canonicalModelId(model);
|
|
1027
|
+
return idMatches(id, 'gpt-6-sol') || idMatches(id, 'gpt-6-luna');
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* What /thinking must tell the user when the tier does not reach every request
|
|
1031
|
+
* for this model, or null. Without it the setting would look applied while
|
|
1032
|
+
* agent turns quietly ran at "none".
|
|
1033
|
+
*/
|
|
1034
|
+
export function agentTurnReasoningNote(providerId, model) {
|
|
1035
|
+
if (!toolsForceReasoningOff(providerId, model))
|
|
1036
|
+
return null;
|
|
1037
|
+
return `Agent turns on ${model} send reasoning_effort "none" whatever the tier — OpenAI's Chat Completions API lets GPT-6 Sol and Luna call tools only with reasoning off. The tier applies to plain chat.`;
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
1040
|
+
* What our Max tier sends as OpenRouter's unified `reasoning.effort`.
|
|
1041
|
+
*
|
|
1042
|
+
* OpenRouter accepts "xhigh" and "max", but only where the model does. Its
|
|
1043
|
+
* /api/v1/models `reasoning.supported_efforts` (read 2026-09-23) lists "max"
|
|
1044
|
+
* for GPT-5.6 and GPT-6, the Claude 5 family and Opus 4.7/4.8, DeepSeek V4.1
|
|
1045
|
+
* Flash and V4 Pro 0813, and Kimi K3; "xhigh" is the ceiling for GPT-5.4/5.5,
|
|
1046
|
+
* Grok 4.6/4.7 and Qwen 3.8 Max. Everything else keeps the old "high" cap —
|
|
1047
|
+
* including the 0423 `deepseek/deepseek-v4-pro` preview (xhigh|high only) and
|
|
1048
|
+
* Grok 4.5/4.3, which list no xhigh — because OpenRouter does not document what
|
|
1049
|
+
* happens to a level a model does not list.
|
|
1050
|
+
*/
|
|
1051
|
+
function openRouterMaxEffort(model) {
|
|
1052
|
+
const id = canonicalModelId(model);
|
|
1053
|
+
const max = ['gpt-5-6', 'gpt-6', 'claude-opus-5', 'claude-fable-5', 'claude-sonnet-5',
|
|
1054
|
+
'claude-opus-4-7', 'claude-opus-4-8', 'deepseek-v4-1-flash', 'deepseek-v4-pro-0813', 'kimi-k3'];
|
|
1055
|
+
if (max.some(prefix => idMatches(id, prefix)))
|
|
1056
|
+
return 'max';
|
|
1057
|
+
const xhigh = ['gpt-5-5', 'gpt-5-4', 'grok-4-6', 'grok-4-7', 'qwen3-8-max'];
|
|
1058
|
+
if (xhigh.some(prefix => idMatches(id, prefix)))
|
|
1059
|
+
return 'xhigh';
|
|
1060
|
+
return 'high';
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* Grok models whose ceiling is "xhigh". xAI's reasoning guide: "`xhigh` is
|
|
1064
|
+
* available on `grok-4.6` and later", and grok-4.7 lists it. grok-4.5 and
|
|
1065
|
+
* grok-4.3 are disputed — their model pages list xhigh, while the guide says 4.5
|
|
1066
|
+
* treats it as "high" and the May-15 page gives 4.3 four levels ending at high —
|
|
1067
|
+
* so they keep the high ceiling until a live request settles it.
|
|
1068
|
+
*/
|
|
1069
|
+
function grokHasXhigh(model) {
|
|
1070
|
+
const id = canonicalModelId(model);
|
|
1071
|
+
return idMatches(id, 'grok-4-6') || idMatches(id, 'grok-4-7');
|
|
1072
|
+
}
|
|
858
1073
|
/**
|
|
859
1074
|
* Does this provider+model expose a GRADED thinking-effort control we can drive?
|
|
860
1075
|
* Used to gate the `/thinking` UI — hidden entirely for models without one.
|
|
@@ -890,16 +1105,21 @@ export function modelSupportsReasoningEffort(providerId, model) {
|
|
|
890
1105
|
// Turbo is a plain toggle.
|
|
891
1106
|
return idMatches(id, 'glm-5-2') || idMatches(id, 'glm-5-3');
|
|
892
1107
|
case 'kimi':
|
|
893
|
-
|
|
1108
|
+
// `kimi-for-coding` is K2.8 Preview since 2026-09-11 and takes low/high/max
|
|
1109
|
+
// (default max). Matched EXACTLY: idMatches would also take in
|
|
1110
|
+
// `kimi-for-coding-highspeed`, which is K2.7 Code HighSpeed — thinking
|
|
1111
|
+
// always on, no effort ladder.
|
|
1112
|
+
return idMatches(id, 'k3') || id === 'kimi-for-coding';
|
|
894
1113
|
case 'kimi-api':
|
|
895
1114
|
case 'kimi-cn':
|
|
896
1115
|
return idMatches(id, 'kimi-k3');
|
|
897
1116
|
case 'grok':
|
|
898
|
-
// Grok reasoning models accept reasoning_effort (
|
|
899
|
-
//
|
|
900
|
-
//
|
|
901
|
-
//
|
|
902
|
-
//
|
|
1117
|
+
// Grok reasoning models accept reasoning_effort (low/medium/high, plus
|
|
1118
|
+
// xhigh from grok-4.6; 4.3 also takes none, which no tier sends). The
|
|
1119
|
+
// coders (grok-code-fast, grok-build — the default) reason internally but
|
|
1120
|
+
// have no effort control and 400 on the parameter; a 400 here silently
|
|
1121
|
+
// drops the whole turn into the weaker text-tool fallback (agentChat.ts),
|
|
1122
|
+
// so exclude them alongside the explicit *-non-reasoning variants.
|
|
903
1123
|
if (id.startsWith('grok-build') || id.startsWith('grok-code'))
|
|
904
1124
|
return false;
|
|
905
1125
|
return id.startsWith('grok') && !id.includes('non-reasoning');
|
|
@@ -919,7 +1139,14 @@ export function modelSupportsReasoningEffort(providerId, model) {
|
|
|
919
1139
|
* models, or providers without a graded knob — so callers can spread it
|
|
920
1140
|
* unconditionally. Keep in lockstep with macOS `ModelTuning.reasoningParams`.
|
|
921
1141
|
*/
|
|
922
|
-
export function reasoningParamsFor(providerId, model, tier
|
|
1142
|
+
export function reasoningParamsFor(providerId, model, tier,
|
|
1143
|
+
/** The request carries a non-empty `tools` array (native tool calling). */
|
|
1144
|
+
opts = {}) {
|
|
1145
|
+
// Before the 'auto' return on purpose: auto sends nothing, GPT-6 Sol/Luna then
|
|
1146
|
+
// run at their default "medium", and that is exactly the combination OpenAI
|
|
1147
|
+
// documents as unable to call tools on Chat Completions.
|
|
1148
|
+
if (opts.tools && toolsForceReasoningOff(providerId, model))
|
|
1149
|
+
return { reasoning_effort: 'none' };
|
|
923
1150
|
// 'auto', or any unexpected value from an older/garbled config, → no param.
|
|
924
1151
|
// (Guards against ever emitting e.g. `effort: undefined`, which could 400.)
|
|
925
1152
|
if (tier === 'auto' || !REASONING_TIERS.includes(tier))
|
|
@@ -930,9 +1157,14 @@ export function reasoningParamsFor(providerId, model, tier) {
|
|
|
930
1157
|
case 'anthropic':
|
|
931
1158
|
// low / medium / high / max — all valid on the capable Claude models.
|
|
932
1159
|
return { output_config: { effort: tier } };
|
|
933
|
-
case 'openai':
|
|
934
|
-
// none/low/medium/high/xhigh
|
|
935
|
-
|
|
1160
|
+
case 'openai': {
|
|
1161
|
+
// Chat Completions takes none/minimal/low/medium/high/xhigh/max, but "max"
|
|
1162
|
+
// is per model: it arrived with GPT-5.6 (changelog 2026-07-09) and every
|
|
1163
|
+
// GPT-6 page lists it. GPT-5.5 and earlier top out at xhigh.
|
|
1164
|
+
const id = canonicalModelId(model);
|
|
1165
|
+
const hasMax = idMatches(id, 'gpt-5-6') || idMatches(id, 'gpt-6');
|
|
1166
|
+
return { reasoning_effort: tier === 'max' ? (hasMax ? 'max' : 'xhigh') : tier };
|
|
1167
|
+
}
|
|
936
1168
|
case 'google':
|
|
937
1169
|
// Gemini's OpenAI-compat layer maps reasoning_effort onto thinking_level
|
|
938
1170
|
// and documents low | medium | high. (Medium 400'd on Gemini 3 Preview,
|
|
@@ -941,13 +1173,12 @@ export function reasoningParamsFor(providerId, model, tier) {
|
|
|
941
1173
|
// 'minimal' is deliberately not emitted: 3.7 Flash rejects it outright.
|
|
942
1174
|
return { reasoning_effort: tier === 'max' ? 'high' : tier };
|
|
943
1175
|
case 'deepseek':
|
|
944
|
-
// V4.1 Flash
|
|
945
|
-
//
|
|
946
|
-
//
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
}
|
|
950
|
-
return { reasoning_effort: tier === 'max' ? 'max' : 'high' };
|
|
1176
|
+
// V4.1 Flash and V4 Pro both distinguish low / high / max — "The thinking
|
|
1177
|
+
// modes of V4-Pro and V4-Flash now support three thinking effort levels"
|
|
1178
|
+
// (changelog 2026-08-13; mapping table: minimal+low→low,
|
|
1179
|
+
// medium+high+xhigh→high, max+ultra→max). Always an effort, never a
|
|
1180
|
+
// disabled block.
|
|
1181
|
+
return { reasoning_effort: tier === 'low' ? 'low' : tier === 'max' ? 'max' : 'high' };
|
|
951
1182
|
case 'z.ai':
|
|
952
1183
|
case 'z.ai-api':
|
|
953
1184
|
case 'z.ai-cn':
|
|
@@ -965,11 +1196,12 @@ export function reasoningParamsFor(providerId, model, tier) {
|
|
|
965
1196
|
// Kimi K3 accepts low/high/max; collapse our medium tier to high.
|
|
966
1197
|
return { reasoning_effort: tier === 'low' ? 'low' : tier === 'max' ? 'max' : 'high' };
|
|
967
1198
|
case 'grok':
|
|
968
|
-
//
|
|
969
|
-
|
|
1199
|
+
// No "max" on xAI; our Max maps to the model's own ceiling — xhigh from
|
|
1200
|
+
// grok-4.6, high below it (see grokHasXhigh).
|
|
1201
|
+
return { reasoning_effort: tier === 'max' ? (grokHasXhigh(model) ? 'xhigh' : 'high') : tier };
|
|
970
1202
|
case 'openrouter':
|
|
971
|
-
// Unified reasoning object;
|
|
972
|
-
return { reasoning: { effort: tier === 'max' ?
|
|
1203
|
+
// Unified reasoning object; Max goes as high as the model lists.
|
|
1204
|
+
return { reasoning: { effort: tier === 'max' ? openRouterMaxEffort(model) : tier } };
|
|
973
1205
|
default:
|
|
974
1206
|
return {};
|
|
975
1207
|
}
|
|
@@ -977,8 +1209,11 @@ export function reasoningParamsFor(providerId, model, tier) {
|
|
|
977
1209
|
/**
|
|
978
1210
|
* The DISTINCT tiers a given provider+model actually exposes — used to build a
|
|
979
1211
|
* per-model picker that only offers levels the model can tell apart (e.g.
|
|
980
|
-
* GLM-5.2
|
|
981
|
-
*
|
|
1212
|
+
* GLM-5.2 grades only high|max; Gemini via the OpenAI-compat layer has no max).
|
|
1213
|
+
* Always leads with 'auto'. `[]` for models with no graded knob.
|
|
1214
|
+
*
|
|
1215
|
+
* GPT-6 Sol/Luna list their full set: it is what they run on plain chat. Agent
|
|
1216
|
+
* turns send "none" regardless (toolsForceReasoningOff), and /thinking says so.
|
|
982
1217
|
*
|
|
983
1218
|
* Kept in lockstep with `reasoningParamsFor` (the providers-test asserts every
|
|
984
1219
|
* listed tier yields a DISTINCT param, so this can't silently drift). Mirrors
|
|
@@ -997,9 +1232,7 @@ export function availableReasoningTiers(providerId, model) {
|
|
|
997
1232
|
// coding, so collapsing it hid the setting most users want.
|
|
998
1233
|
return ['auto', 'low', 'medium', 'high'];
|
|
999
1234
|
case 'deepseek':
|
|
1000
|
-
return
|
|
1001
|
-
? ['auto', 'low', 'high', 'max']
|
|
1002
|
-
: ['auto', 'high', 'max'];
|
|
1235
|
+
return ['auto', 'low', 'high', 'max'];
|
|
1003
1236
|
case 'z.ai':
|
|
1004
1237
|
case 'z.ai-api':
|
|
1005
1238
|
case 'z.ai-cn':
|
|
@@ -1013,9 +1246,13 @@ export function availableReasoningTiers(providerId, model) {
|
|
|
1013
1246
|
case 'kimi-cn':
|
|
1014
1247
|
return ['auto', 'low', 'high', 'max'];
|
|
1015
1248
|
case 'grok':
|
|
1016
|
-
return
|
|
1249
|
+
return grokHasXhigh(model)
|
|
1250
|
+
? ['auto', 'low', 'medium', 'high', 'max']
|
|
1251
|
+
: ['auto', 'low', 'medium', 'high'];
|
|
1017
1252
|
case 'openrouter':
|
|
1018
|
-
return
|
|
1253
|
+
return openRouterMaxEffort(model) === 'high'
|
|
1254
|
+
? ['auto', 'low', 'medium', 'high']
|
|
1255
|
+
: ['auto', 'low', 'medium', 'high', 'max'];
|
|
1019
1256
|
default:
|
|
1020
1257
|
return [];
|
|
1021
1258
|
}
|