codeep 2.16.0 → 2.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- <img src="Codeep.gif" alt="Codeep demo" width="700">
12
+ <img src="promo/sources/tui-current.png" alt="Codeep terminal UI with agent timeline, changed files, checks, and resource estimates" width="1000">
13
13
  </p>
14
14
 
15
15
  <p align="center">
@@ -23,6 +23,16 @@
23
23
  <a href="https://github.com/VladoIvankovic/Codeep"><img src="https://img.shields.io/github/stars/VladoIvankovic/Codeep?style=social" alt="GitHub stars"></a>
24
24
  </p>
25
25
 
26
+ ## One agent, every surface
27
+
28
+ Codeep keeps the same project context, provider configuration, sessions, and
29
+ agent workflow wherever you work:
30
+
31
+ - **[Terminal / TUI](https://codeep.dev/docs/installation)** — the primary CLI experience, with Plan → Read → Edit → Verify → Summary, live file changes, checks, token cost, and estimated energy and cooling-water impact.
32
+ - **[macOS app](https://codeep.dev/docs/mac)** — a native SwiftUI workbench with project conversations and Run Inspector.
33
+ - **[VS Code extension](https://github.com/VladoIvankovic/Codeep-vscode)** — the same agent over ACP, directly inside the editor. Also available on the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=VladoIvankovic.codeep).
34
+ - **[Web dashboard](https://codeep.dev/dashboard)** — synced sessions, usage, costs, tasks, and project activity.
35
+
26
36
  ## Upgrading
27
37
 
28
38
  Running `npm install -g codeep@latest` picks up the new version — config,
@@ -1029,11 +1039,11 @@ After installation, `codeep` is available globally in your terminal. Simply run
1029
1039
  > /profile save fast
1030
1040
 
1031
1041
  > /provider # switch to openai
1032
- > /model gpt-4.1
1042
+ > /model gpt-5.6-sol
1033
1043
  > /profile save work
1034
1044
 
1035
1045
  > /model fast # instantly switch to z.ai / glm-5.2
1036
- > /model work # instantly switch to openai / gpt-4.1
1046
+ > /model work # instantly switch to openai / gpt-5.6-sol
1037
1047
  ```
1038
1048
 
1039
1049
  ### Session Management
@@ -1265,6 +1275,17 @@ With write access enabled:
1265
1275
  | `GOOGLE_API_KEY` | Google AI (Gemini) API key |
1266
1276
  | `MINIMAX_API_KEY` | MiniMax (international) API key |
1267
1277
  | `MINIMAX_CN_API_KEY` | MiniMax China API key |
1278
+ | `KIMI_CODE_API_KEY` | Kimi Code subscription key |
1279
+ | `MOONSHOT_API_KEY` | Kimi international pay-per-use key |
1280
+ | `MOONSHOT_CN_API_KEY` | Kimi China pay-per-use key |
1281
+ | `XAI_API_KEY` | Grok (xAI) API key |
1282
+ | `BAILIAN_CODING_PLAN_API_KEY` | Qwen international Coding Plan key |
1283
+ | `BAILIAN_TOKEN_PLAN_API_KEY` | Qwen international Token Plan key |
1284
+ | `DASHSCOPE_API_KEY` | Qwen international pay-per-use key |
1285
+ | `BAILIAN_CODING_PLAN_CN_API_KEY` | Qwen China Coding Plan key |
1286
+ | `DASHSCOPE_CN_API_KEY` | Qwen China pay-per-use key |
1287
+ | `MODELSCOPE_API_KEY` | ModelScope token for its live model catalog |
1288
+ | `OPENROUTER_API_KEY` | OpenRouter API key |
1268
1289
 
1269
1290
  ### Settings (`/settings`)
1270
1291
 
@@ -1366,6 +1387,10 @@ Contributions are welcome! Before opening a PR, please read the
1366
1387
  how to propose a change. For provider integrations specifically, the guide
1367
1388
  walks through the files you need to touch.
1368
1389
 
1390
+ The active-product scope, model source index, replacement rules, telemetry
1391
+ contract, and recurring review checklist live in the
1392
+ [**model maintenance policy**](./docs/MODEL_MAINTENANCE.md).
1393
+
1369
1394
  Quick version: `npm install` → `npm test` → `npx tsc --noEmit` clean → open a
1370
1395
  PR against `main`. To report a security issue, see
1371
1396
  [**Security policy**](./SECURITY.md).
@@ -1473,7 +1498,7 @@ The chat sidebar now surfaces two extra ACP signals that previously only the TUI
1473
1498
  ### Editor-native actions (new in 2.2)
1474
1499
 
1475
1500
  - **Code Actions (lightbulb)** — select code and press `Ctrl+.` for **Explain**, **Improve / refactor**, **Add tests**, and **Add doc comment**. On a line with an error/warning, a **Fix this problem** quick-fix sends the diagnostic plus the code to Codeep. Everything routes through the chat, so the full agent (file edits via the diff preview, MCP tools) is available.
1476
- - **Model picker in the status bar** — click `Codeep · <model>` (or run **Codeep: Select Provider & Model**) to switch provider + model from a quick-pick. Providers with open-ended catalogs (OpenRouter, Ollama, custom endpoints) let you type a model id.
1501
+ - **Model picker in the status bar** — click `Codeep · <model>` (or run **Codeep: Select Provider & Model**) to switch provider + model from a quick-pick. Providers with open-ended catalogs (OpenRouter, ModelScope, Ollama, custom endpoints) let you type a model id.
1477
1502
  - **Self-hosted endpoints from settings** — point the extension at vLLM / LiteLLM / LM Studio / text-generation-webui with `codeep.baseUrl` (e.g. `http://localhost:8000/v1`), plus `codeep.provider` (`custom` or `openai`) and `codeep.model`. The `codeep.provider` / `codeep.model` settings are applied on every connect, so they stay authoritative.
1478
1503
  - **Get Started walkthrough** — a native VS Code walkthrough (Help → Get Started) covering CLI install, opening the chat, editor actions, and choosing a model.
1479
1504
 
@@ -224,7 +224,7 @@ export function buildProviderList() {
224
224
  // Model metadata so ACP clients (e.g. the VS Code model picker) can
225
225
  // offer a provider → model selector without hardcoding a catalog.
226
226
  // `dynamicModels` flags providers whose model list is open-ended
227
- // (OpenRouter, Ollama, custom endpoints) — clients should let the
227
+ // (OpenRouter, ModelScope, Ollama, custom endpoints) — clients should let the
228
228
  // user type a model id rather than only pick from `models`.
229
229
  models: p.models.map((m) => ({ id: m.id, name: m.name })),
230
230
  defaultModel: p.defaultModel,
@@ -2,7 +2,7 @@ import Conf from 'conf';
2
2
  import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, unlinkSync, statSync } from 'fs';
3
3
  import { join, dirname } from 'path';
4
4
  import { randomUUID } from 'crypto';
5
- import { PROVIDERS, getProvider, getProviderBaseUrl } from './providers.js';
5
+ import { PROVIDERS, getProvider, getProviderBaseUrl, replacementModelFor } from './providers.js';
6
6
  import { logSession } from '../utils/logger.js';
7
7
  import { createSecureStorage } from '../utils/keychain.js';
8
8
  // We'll initialize GLOBAL_SESSIONS_DIR after config is created (to use config.path)
@@ -255,8 +255,9 @@ if (config.get('agentMode') === 'auto') {
255
255
  // affected sliders were effectively lies). Each migration now runs exactly
256
256
  // once per config, recorded via `migrationVersion`; after that, whatever the
257
257
  // user sets sticks. Bump MIGRATION_VERSION when adding a new one.
258
- const MIGRATION_VERSION = 1;
259
- if ((config.get('migrationVersion') ?? 0) < 1) {
258
+ const MIGRATION_VERSION = 4;
259
+ const currentMigrationVersion = config.get('migrationVersion') ?? 0;
260
+ if (currentMigrationVersion < 1) {
260
261
  // Migrate the old runaway default (10000 iterations) down to a sane
261
262
  // ceiling, and old conservative defaults up to the current ones.
262
263
  if (config.get('agentMaxIterations') >= 10000) {
@@ -277,6 +278,18 @@ if ((config.get('migrationVersion') ?? 0) < 1) {
277
278
  if (config.get('rateLimitCommands') <= 100) {
278
279
  config.set('rateLimitCommands', 10000);
279
280
  }
281
+ }
282
+ if (currentMigrationVersion < 4) {
283
+ // Vendor aliases below were removed from Codeep's curated catalogue after
284
+ // their replacements became available. Migrate only exact known aliases:
285
+ // OpenRouter/Ollama/custom model ids remain user-controlled.
286
+ const provider = config.get('provider');
287
+ const model = config.get('model');
288
+ const replacement = replacementModelFor(provider, model);
289
+ if (replacement)
290
+ config.set('model', replacement);
291
+ }
292
+ if (currentMigrationVersion < MIGRATION_VERSION) {
280
293
  config.set('migrationVersion', MIGRATION_VERSION);
281
294
  }
282
295
  // Global sessions directory - use same directory as conf package for cross-platform consistency
@@ -1216,7 +1229,10 @@ export function loadProfile(name) {
1216
1229
  }
1217
1230
  export function applyProfile(profile) {
1218
1231
  config.set('provider', profile.provider);
1219
- config.set('model', profile.model);
1232
+ // A profile saved before a vendor retired a model would otherwise restore an
1233
+ // id the picker no longer offers. Normalize it exactly like the startup
1234
+ // migration does — dynamic OpenRouter/Ollama/custom ids are never rewritten.
1235
+ config.set('model', replacementModelFor(profile.provider, profile.model) ?? profile.model);
1220
1236
  config.set('protocol', profile.protocol);
1221
1237
  config.set('temperature', profile.temperature);
1222
1238
  config.set('maxTokens', profile.maxTokens);
@@ -45,6 +45,7 @@ export interface ProviderConfig {
45
45
  export declare const PROVIDERS: Record<string, ProviderConfig>;
46
46
  export type ProviderId = keyof typeof PROVIDERS;
47
47
  export declare function getProvider(id: string): ProviderConfig | null;
48
+ export declare function replacementModelFor(providerId: string, modelId: string): string | undefined;
48
49
  export declare function getProviderList(): {
49
50
  id: string;
50
51
  name: string;
@@ -133,8 +134,8 @@ export declare function availableReasoningTiers(providerId: string, model: strin
133
134
  /**
134
135
  * Map a (possibly out-of-range) tier to the tier this model actually distinguishes,
135
136
  * for display — the chip + the checked menu row. The effort setting is global, so
136
- * a tier picked on Opus ('low') may not exist on GLM-5.2; we show the level GLM
137
- * will really run (its 'low' clamps to 'high'). Picks the available tier whose
137
+ * a tier picked on Opus ('medium') may not exist on Kimi K3; we show the level
138
+ * Kimi will really run (its 'medium' clamps to 'high'). Picks the tier whose
138
139
  * effective param equals the requested one. 'auto' (or unsupported) → 'auto'.
139
140
  */
140
141
  export declare function resolveReasoningTier(providerId: string, model: string, tier: ReasoningTier): ReasoningTier;
@@ -18,11 +18,12 @@ export const PROVIDERS = {
18
18
  },
19
19
  },
20
20
  models: [
21
- { id: 'glm-5.2', name: 'GLM-5.2', description: 'Latest GLM model, available to all users' },
21
+ { id: 'glm-5.2', name: 'GLM-5.2', description: 'Latest flagship for project-scale engineering (1M context)' },
22
22
  { id: 'glm-5-turbo', name: 'GLM-5 Turbo', description: 'Fast GLM-5 variant, available to all users' },
23
23
  ],
24
24
  defaultModel: 'glm-5.2',
25
25
  defaultProtocol: 'openai',
26
+ maxOutputTokens: 131_072,
26
27
  envKey: 'ZAI_API_KEY',
27
28
  subscribeUrl: 'https://z.ai/subscribe?ic=NXYNXZOV14',
28
29
  groupLabel: 'Z.AI — Subscription (GLM Coding Plan)',
@@ -44,11 +45,12 @@ export const PROVIDERS = {
44
45
  },
45
46
  },
46
47
  models: [
47
- { id: 'glm-5.2', name: 'GLM-5.2', description: 'Latest GLM model' },
48
+ { id: 'glm-5.2', name: 'GLM-5.2', description: 'Latest flagship for project-scale engineering (1M context)' },
48
49
  { id: 'glm-5-turbo', name: 'GLM-5 Turbo', description: 'Fast GLM-5 variant' },
49
50
  ],
50
51
  defaultModel: 'glm-5.2',
51
52
  defaultProtocol: 'openai',
53
+ maxOutputTokens: 131_072,
52
54
  envKey: 'ZAI_API_KEY',
53
55
  subscribeUrl: 'https://api.z.ai',
54
56
  groupLabel: 'Z.AI — API (pay-per-use)',
@@ -70,11 +72,12 @@ export const PROVIDERS = {
70
72
  },
71
73
  },
72
74
  models: [
73
- { id: 'glm-5.2', name: 'GLM-5.2', description: 'Latest GLM model, available to all users' },
75
+ { id: 'glm-5.2', name: 'GLM-5.2', description: 'Latest flagship for project-scale engineering (1M context)' },
74
76
  { id: 'glm-5-turbo', name: 'GLM-5 Turbo', description: 'Fast GLM-5 variant, available to all users' },
75
77
  ],
76
78
  defaultModel: 'glm-5.2',
77
79
  defaultProtocol: 'openai',
80
+ maxOutputTokens: 131_072,
78
81
  envKey: 'ZAI_CN_API_KEY',
79
82
  subscribeUrl: 'https://open.bigmodel.cn/glm-coding',
80
83
  groupLabel: 'Z.AI China — Subscription (GLM Coding Plan)',
@@ -96,11 +99,12 @@ export const PROVIDERS = {
96
99
  },
97
100
  },
98
101
  models: [
99
- { id: 'glm-5.2', name: 'GLM-5.2', description: 'Latest GLM model' },
102
+ { id: 'glm-5.2', name: 'GLM-5.2', description: 'Latest flagship for project-scale engineering (1M context)' },
100
103
  { id: 'glm-5-turbo', name: 'GLM-5 Turbo', description: 'Fast GLM-5 variant' },
101
104
  ],
102
105
  defaultModel: 'glm-5.2',
103
106
  defaultProtocol: 'openai',
107
+ maxOutputTokens: 131_072,
104
108
  envKey: 'ZAI_CN_API_KEY',
105
109
  subscribeUrl: 'https://open.bigmodel.cn',
106
110
  groupLabel: 'Z.AI China — API (pay-per-use)',
@@ -205,9 +209,9 @@ export const PROVIDERS = {
205
209
  },
206
210
  // ── Kimi (Moonshot AI) ────────────────────────────────────────────
207
211
  // Subscription (Kimi Code) mirrors the Z.AI GLM-Coding-Plan shape: a
208
- // dedicated coding base URL + a separate key, model id ALWAYS
209
- // `kimi-for-coding` (a backend alias). OpenAI-compatible is the
210
- // battle-tested path so we don't expose the Anthropic surface here.
212
+ // dedicated coding base URL + a separate key. Model availability depends
213
+ // on the user's plan, so the picker labels the restricted K3/high-speed ids
214
+ // instead of pretending every subscription includes them.
211
215
  'kimi': {
212
216
  name: 'Kimi (Moonshot) — Coding Plan',
213
217
  description: 'Kimi Code subscription',
@@ -215,7 +219,10 @@ export const PROVIDERS = {
215
219
  openai: { baseUrl: 'https://api.kimi.com/coding/v1', authHeader: 'Bearer', supportsNativeTools: true },
216
220
  },
217
221
  models: [
218
- { id: 'kimi-for-coding', name: 'Kimi Code', description: 'Subscription alias — auto-maps to the latest Kimi coding model (K2.7 Code)' },
222
+ { id: 'kimi-for-coding', name: 'Kimi Code', description: 'Available on every Kimi Code plan — maps to K2.7 Code' },
223
+ { id: 'k3', name: 'Kimi K3', description: '1M-context flagship — Moderato plan or higher' },
224
+ { id: 'k3-256k', name: 'Kimi K3 (256K)', description: 'K3 with a smaller context window — Moderato plan or higher' },
225
+ { id: 'kimi-for-coding-highspeed', name: 'Kimi Code (High-Speed)', description: 'Low-latency K2.7 Code — Allegretto plan or higher' },
219
226
  ],
220
227
  defaultModel: 'kimi-for-coding',
221
228
  defaultProtocol: 'openai',
@@ -232,21 +239,18 @@ export const PROVIDERS = {
232
239
  openai: { baseUrl: 'https://api.moonshot.ai/v1', authHeader: 'Bearer', supportsNativeTools: true },
233
240
  },
234
241
  models: [
235
- { id: 'kimi-k3-code', name: 'Kimi K3 Code', description: 'Newest flagship agentic coding model (1M context, deep reasoning)' },
236
- { id: 'kimi-k3-code-highspeed', name: 'Kimi K3 Code (High-Speed)', description: 'Throughput-tuned K3 Code for latency-sensitive loops' },
237
- { id: 'kimi-k3-thinking', name: 'Kimi K3 Thinking', description: 'K3 with explicit reasoning traces (highest quality, slower)' },
238
- { id: 'kimi-k2.7-code', name: 'Kimi K2.7 Code', description: 'Previous-gen flagship agentic coding model (256K context)' },
242
+ { id: 'kimi-k3', name: 'Kimi K3', description: 'Latest flagship for software engineering and deep reasoning (1M context)' },
243
+ { id: 'kimi-k2.7-code', name: 'Kimi K2.7 Code', description: 'Coding-specialized model (256K context)' },
239
244
  { id: 'kimi-k2.7-code-highspeed', name: 'Kimi K2.7 Code (High-Speed)', description: 'Throughput-tuned K2.7 Code for latency-sensitive loops' },
240
- { id: 'kimi-k2.6', name: 'Kimi K2.6', description: 'Previous-gen multimodal reasoning model' },
241
- { id: 'kimi-k2.5', name: 'Kimi K2.5', description: 'Older general-purpose model (cheaper)' },
245
+ { id: 'kimi-k2.6', name: 'Kimi K2.6', description: 'General-purpose multimodal reasoning model' },
242
246
  ],
243
- defaultModel: 'kimi-k3-code',
247
+ defaultModel: 'kimi-k3',
244
248
  defaultProtocol: 'openai',
245
- maxOutputTokens: 65_536,
249
+ maxOutputTokens: 131_072,
246
250
  envKey: 'MOONSHOT_API_KEY',
247
251
  subscribeUrl: 'https://platform.kimi.ai/console/api-keys',
248
252
  groupLabel: 'Kimi — API (pay-per-use)',
249
- hint: 'Pay-per-use via Moonshot API key (platform.kimi.ai). K3 models support 1M context and explicit reasoning.',
253
+ hint: 'Pay-per-use via Moonshot API key (platform.kimi.ai). Kimi K3 supports 1M context and graded reasoning.',
250
254
  },
251
255
  'kimi-cn': {
252
256
  name: 'Kimi China (Moonshot)',
@@ -255,21 +259,18 @@ export const PROVIDERS = {
255
259
  openai: { baseUrl: 'https://api.moonshot.cn/v1', authHeader: 'Bearer', supportsNativeTools: true },
256
260
  },
257
261
  models: [
258
- { id: 'kimi-k3-code', name: 'Kimi K3 Code', description: 'Newest flagship agentic coding model (1M context, deep reasoning)' },
259
- { id: 'kimi-k3-code-highspeed', name: 'Kimi K3 Code (High-Speed)', description: 'Throughput-tuned K3 Code' },
260
- { id: 'kimi-k3-thinking', name: 'Kimi K3 Thinking', description: 'K3 with explicit reasoning traces' },
261
- { id: 'kimi-k2.7-code', name: 'Kimi K2.7 Code', description: 'Previous-gen flagship agentic coding model (256K context)' },
262
+ { id: 'kimi-k3', name: 'Kimi K3', description: 'Latest flagship for software engineering and deep reasoning (1M context)' },
263
+ { id: 'kimi-k2.7-code', name: 'Kimi K2.7 Code', description: 'Coding-specialized model (256K context)' },
262
264
  { id: 'kimi-k2.7-code-highspeed', name: 'Kimi K2.7 Code (High-Speed)', description: 'Throughput-tuned K2.7 Code' },
263
- { id: 'kimi-k2.6', name: 'Kimi K2.6', description: 'Previous-gen multimodal reasoning model' },
264
- { id: 'kimi-k2.5', name: 'Kimi K2.5', description: 'Older general-purpose model' },
265
+ { id: 'kimi-k2.6', name: 'Kimi K2.6', description: 'General-purpose multimodal reasoning model' },
265
266
  ],
266
- defaultModel: 'kimi-k3-code',
267
+ defaultModel: 'kimi-k3',
267
268
  defaultProtocol: 'openai',
268
- maxOutputTokens: 65_536,
269
+ maxOutputTokens: 131_072,
269
270
  envKey: 'MOONSHOT_CN_API_KEY',
270
271
  subscribeUrl: 'https://platform.moonshot.cn/console/api-keys',
271
272
  groupLabel: 'Kimi China — API (pay-per-use)',
272
- hint: 'Pay-per-use via Moonshot China API key (platform.moonshot.cn). K3 models support 1M context.',
273
+ hint: 'Pay-per-use via Moonshot China API key (platform.moonshot.cn). Kimi K3 supports 1M context.',
273
274
  },
274
275
  // ── Grok (xAI) ────────────────────────────────────────────────────
275
276
  // Pay-per-use today (console.x.ai key). The SuperGrok / X Premium+
@@ -285,8 +286,6 @@ export const PROVIDERS = {
285
286
  { id: 'grok-4.5', name: 'Grok 4.5', description: 'Flagship reasoning model — highest quality, 500K context' },
286
287
  { id: 'grok-build-0.1', name: 'Grok Build 0.1', description: 'Agentic coding model — fast, 256K context' },
287
288
  { id: 'grok-4.3', name: 'Grok 4.3', description: 'Previous flagship, 1M context' },
288
- { id: 'grok-code-fast-1', name: 'Grok Code Fast 1', description: 'Low-cost speed-first coder (alias of Build 0.1)' },
289
- { id: 'grok-4-fast-reasoning', name: 'Grok 4 Fast (reasoning)', description: 'Cheap reasoning model, very large context' },
290
289
  ],
291
290
  defaultModel: 'grok-build-0.1',
292
291
  defaultProtocol: 'openai',
@@ -307,11 +306,11 @@ export const PROVIDERS = {
307
306
  openai: { baseUrl: 'https://coding-intl.dashscope.aliyuncs.com/v1', authHeader: 'Bearer', supportsNativeTools: true },
308
307
  },
309
308
  models: [
310
- { id: 'qwen3-coder-plus', name: 'Qwen3-Coder Plus', description: 'Flagship coding model — best quality' },
311
- { id: 'qwen3-coder-next', name: 'Qwen3-Coder Next', description: 'Balanced quality/speed/cost' },
312
- { id: 'qwen3.7-max', name: 'Qwen3.7-Max', description: 'Flagship general model (code + reasoning)' },
309
+ { id: 'qwen3.7-plus', name: 'Qwen3.7-Plus', description: 'Recommended current model for coding, reasoning, and vision' },
310
+ { id: 'qwen3.6-plus', name: 'Qwen3.6-Plus', description: 'Fast multimodal model with a 1M context window' },
311
+ { id: 'qwen3.5-plus', name: 'Qwen3.5-Plus', description: 'Efficient general-purpose Coding Plan model' },
313
312
  ],
314
- defaultModel: 'qwen3-coder-plus',
313
+ defaultModel: 'qwen3.7-plus',
315
314
  defaultProtocol: 'openai',
316
315
  maxOutputTokens: 65_536,
317
316
  noStreamWithTools: true,
@@ -327,12 +326,11 @@ export const PROVIDERS = {
327
326
  openai: { baseUrl: 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1', authHeader: 'Bearer', supportsNativeTools: true },
328
327
  },
329
328
  models: [
330
- { id: 'qwen3-coder-plus', name: 'Qwen3-Coder Plus', description: 'Flagship coding model (256K, up to 1M)' },
331
- { id: 'qwen3-coder-next', name: 'Qwen3-Coder Next', description: 'Balanced quality/speed/cost' },
332
- { id: 'qwen3-coder-flash', name: 'Qwen3-Coder Flash', description: 'Fast/cheap coder' },
333
- { id: 'qwen3.7-max', name: 'Qwen3.7-Max', description: 'Flagship general model' },
329
+ { id: 'qwen3.7-max', name: 'Qwen3.7-Max', description: 'Latest flagship for complex coding and reasoning' },
330
+ { id: 'qwen3.7-plus', name: 'Qwen3.7-Plus', description: 'Balanced quality, speed, and price (1M context)' },
331
+ { id: 'qwen3.6-flash', name: 'Qwen3.6-Flash', description: 'Low-latency, low-cost multimodal model' },
334
332
  ],
335
- defaultModel: 'qwen3-coder-plus',
333
+ defaultModel: 'qwen3.7-max',
336
334
  defaultProtocol: 'openai',
337
335
  maxOutputTokens: 65_536,
338
336
  noStreamWithTools: true,
@@ -341,6 +339,28 @@ export const PROVIDERS = {
341
339
  groupLabel: 'Qwen — API (pay-per-use)',
342
340
  hint: 'Pay-per-use via Alibaba Model Studio key (DASHSCOPE_API_KEY).',
343
341
  },
342
+ 'qwen-token-plan': {
343
+ name: 'Qwen (Alibaba) — Token Plan',
344
+ description: 'Qwen Token Plan subscription (international)',
345
+ protocols: {
346
+ openai: { baseUrl: 'https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1', authHeader: 'Bearer', supportsNativeTools: true },
347
+ },
348
+ models: [
349
+ { id: 'qwen3.8-max-preview', name: 'Qwen3.8-Max Preview', description: 'Newest Token Plan flagship for complex agentic work' },
350
+ { id: 'qwen3.7-max', name: 'Qwen3.7-Max', description: 'Production flagship for complex coding and reasoning' },
351
+ { id: 'qwen3.7-plus', name: 'Qwen3.7-Plus', description: 'Balanced quality and throughput' },
352
+ { id: 'qwen3.6-plus', name: 'Qwen3.6-Plus', description: 'Fast multimodal model with a 1M context window' },
353
+ { id: 'qwen3.6-flash', name: 'Qwen3.6-Flash', description: 'Low-latency, credit-efficient model' },
354
+ ],
355
+ defaultModel: 'qwen3.8-max-preview',
356
+ defaultProtocol: 'openai',
357
+ maxOutputTokens: 131_072,
358
+ noStreamWithTools: true,
359
+ envKey: 'BAILIAN_TOKEN_PLAN_API_KEY',
360
+ subscribeUrl: 'https://modelstudio.console.alibabacloud.com/',
361
+ groupLabel: 'Qwen — Subscription (Token Plan)',
362
+ hint: 'Uses monthly Token Plan credits. Requires a separate sk-sp-… Token Plan key.',
363
+ },
344
364
  'qwen-cn': {
345
365
  name: 'Qwen China — Coding Plan',
346
366
  description: 'Qwen Coding Plan subscription (China)',
@@ -348,11 +368,11 @@ export const PROVIDERS = {
348
368
  openai: { baseUrl: 'https://coding.dashscope.aliyuncs.com/v1', authHeader: 'Bearer', supportsNativeTools: true },
349
369
  },
350
370
  models: [
351
- { id: 'qwen3-coder-plus', name: 'Qwen3-Coder Plus', description: 'Flagship coding model — best quality' },
352
- { id: 'qwen3-coder-next', name: 'Qwen3-Coder Next', description: 'Balanced quality/speed/cost' },
353
- { id: 'qwen3.7-max', name: 'Qwen3.7-Max', description: 'Flagship general model' },
371
+ { id: 'qwen3.7-plus', name: 'Qwen3.7-Plus', description: 'Recommended current model for coding, reasoning, and vision' },
372
+ { id: 'qwen3.6-plus', name: 'Qwen3.6-Plus', description: 'Fast multimodal model with a 1M context window' },
373
+ { id: 'qwen3.5-plus', name: 'Qwen3.5-Plus', description: 'Efficient general-purpose Coding Plan model' },
354
374
  ],
355
- defaultModel: 'qwen3-coder-plus',
375
+ defaultModel: 'qwen3.7-plus',
356
376
  defaultProtocol: 'openai',
357
377
  maxOutputTokens: 65_536,
358
378
  noStreamWithTools: true,
@@ -368,12 +388,11 @@ export const PROVIDERS = {
368
388
  openai: { baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1', authHeader: 'Bearer', supportsNativeTools: true },
369
389
  },
370
390
  models: [
371
- { id: 'qwen3-coder-plus', name: 'Qwen3-Coder Plus', description: 'Flagship coding model' },
372
- { id: 'qwen3-coder-next', name: 'Qwen3-Coder Next', description: 'Balanced quality/speed/cost' },
373
- { id: 'qwen3-coder-flash', name: 'Qwen3-Coder Flash', description: 'Fast/cheap coder' },
374
- { id: 'qwen3.7-max', name: 'Qwen3.7-Max', description: 'Flagship general model' },
391
+ { id: 'qwen3.7-max', name: 'Qwen3.7-Max', description: 'Latest flagship for complex coding and reasoning' },
392
+ { id: 'qwen3.7-plus', name: 'Qwen3.7-Plus', description: 'Balanced quality, speed, and price (1M context)' },
393
+ { id: 'qwen3.6-flash', name: 'Qwen3.6-Flash', description: 'Low-latency, low-cost multimodal model' },
375
394
  ],
376
- defaultModel: 'qwen3-coder-plus',
395
+ defaultModel: 'qwen3.7-max',
377
396
  defaultProtocol: 'openai',
378
397
  maxOutputTokens: 65_536,
379
398
  noStreamWithTools: true,
@@ -384,21 +403,22 @@ export const PROVIDERS = {
384
403
  },
385
404
  'modelscope': {
386
405
  name: 'ModelScope (free Qwen)',
387
- description: 'Free Qwen3-Coder inference via ModelScope',
406
+ description: 'Live free-model catalog via ModelScope',
388
407
  protocols: {
389
408
  openai: { baseUrl: 'https://api-inference.modelscope.cn/v1', authHeader: 'Bearer', supportsNativeTools: true },
390
409
  },
391
410
  models: [
392
- { id: 'Qwen/Qwen3-Coder-480B-A35B-Instruct', name: 'Qwen3-Coder 480B', description: 'Open MoE coder — free tier (~2000 req/day)' },
411
+ { id: 'Qwen/Qwen3-Coder-480B-A35B-Instruct', name: 'Qwen3-Coder 480B', description: 'Fallback model shown until the live catalog loads' },
393
412
  ],
394
413
  defaultModel: 'Qwen/Qwen3-Coder-480B-A35B-Instruct',
395
414
  defaultProtocol: 'openai',
396
415
  maxOutputTokens: 65_536,
397
416
  noStreamWithTools: true,
417
+ dynamicModels: true,
398
418
  envKey: 'MODELSCOPE_API_KEY',
399
419
  subscribeUrl: 'https://modelscope.cn/my/myaccesstoken',
400
420
  groupLabel: 'ModelScope — Free (Qwen)',
401
- hint: 'Free tier (~2000 req/day) via ModelScope token (modelscope.cn). Needs a bound Aliyun account.',
421
+ hint: 'Fetches the live free catalog for your ModelScope token; availability and limits vary by account.',
402
422
  },
403
423
  'openai': {
404
424
  name: 'OpenAI',
@@ -414,9 +434,6 @@ export const PROVIDERS = {
414
434
  { id: 'gpt-5.6-sol', name: 'GPT-5.6 Sol', description: 'Most capable GPT — best for coding & agentic work' },
415
435
  { id: 'gpt-5.6-terra', name: 'GPT-5.6 Terra', description: 'Balanced — GPT-5.5 quality at about half the price' },
416
436
  { id: 'gpt-5.6-luna', name: 'GPT-5.6 Luna', description: 'Fast and cheap — high-volume workloads' },
417
- { id: 'gpt-5.5', name: 'GPT-5.5', description: 'Previous flagship GPT' },
418
- { id: 'gpt-5.4', name: 'GPT-5.4', description: 'Older generation GPT' },
419
- { id: 'gpt-5.4-mini', name: 'GPT-5.4 Mini', description: 'Faster and cheaper GPT-5.4' },
420
437
  ],
421
438
  defaultModel: 'gpt-5.6-sol',
422
439
  defaultProtocol: 'openai',
@@ -461,8 +478,9 @@ export const PROVIDERS = {
461
478
  },
462
479
  models: [
463
480
  { id: 'gemini-3.1-pro-preview', name: 'Gemini 3.1 Pro', description: 'Most capable Gemini model' },
464
- { id: 'gemini-3.5-flash', name: 'Gemini 3.5 Flash', description: 'Pro-level intelligence at Flash speed' },
465
- { id: 'gemini-3.1-flash-lite', name: 'Gemini 3.1 Flash-Lite', description: 'Low-latency, low-cost workhorse (1M context)' },
481
+ { id: 'gemini-3.6-flash', name: 'Gemini 3.6 Flash', description: 'Latest production Flash model' },
482
+ { id: 'gemini-3.5-flash', name: 'Gemini 3.5 Flash', description: 'Stable frontier Flash model for coding and long agentic tasks' },
483
+ { id: 'gemini-3.5-flash-lite', name: 'Gemini 3.5 Flash-Lite', description: 'Latest low-latency, low-cost workhorse' },
466
484
  ],
467
485
  defaultModel: 'gemini-3.1-pro-preview',
468
486
  defaultProtocol: 'openai',
@@ -488,19 +506,17 @@ export const PROVIDERS = {
488
506
  models: [
489
507
  { id: 'openrouter/auto', name: 'Auto-route', description: 'OpenRouter picks the best model for the task' },
490
508
  { id: 'anthropic/claude-fable-5', name: 'Claude Fable 5', description: 'Anthropic — most capable' },
491
- { id: 'anthropic/claude-opus-4', name: 'Claude Opus 4', description: 'Anthropic — Opus tier' },
509
+ { id: 'anthropic/claude-opus-5', name: 'Claude Opus 5', description: 'Anthropic — flagship Opus tier' },
492
510
  { id: 'anthropic/claude-sonnet-5', name: 'Claude Sonnet 5', description: 'Anthropic — balanced' },
493
511
  { id: 'openai/gpt-5.6-sol', name: 'GPT-5.6 Sol', description: 'OpenAI — flagship' },
494
- { id: 'openai/gpt-5.4-mini', name: 'GPT-5.4 Mini', description: 'OpenAI — fast/cheap' },
495
- { id: 'google/gemini-3.1-pro', name: 'Gemini 3.1 Pro', description: 'Google — multimodal' },
496
- { id: 'meta-llama/llama-3.1-405b-instruct', name: 'Llama 3.1 405B', description: 'Meta — open weights, largest' },
497
- { id: 'meta-llama/llama-3.1-70b-instruct', name: 'Llama 3.1 70B', description: 'Meta — open weights, fast' },
498
- { id: 'deepseek/deepseek-v4', name: 'DeepSeek V4', description: 'DeepSeek via OpenRouter' },
499
- { id: 'mistralai/mistral-large', name: 'Mistral Large', description: 'Mistral — flagship' },
500
- { id: 'qwen/qwen-2.5-coder-32b-instruct', name: 'Qwen 2.5 Coder 32B', description: 'Alibaba — coding-tuned' },
512
+ { id: 'openai/gpt-5.6-luna', name: 'GPT-5.6 Luna', description: 'OpenAI — fast/efficient' },
513
+ { id: 'google/gemini-3.6-flash', name: 'Gemini 3.6 Flash', description: 'Google — latest production Flash' },
514
+ { id: 'deepseek/deepseek-v4-pro', name: 'DeepSeek V4 Pro', description: 'DeepSeek — flagship agentic model' },
515
+ { id: 'moonshotai/kimi-k3', name: 'Kimi K3', description: 'Moonshot — long-horizon coding' },
516
+ { id: 'qwen/qwen3.8-max', name: 'Qwen 3.8 Max', description: 'Alibaba — latest flagship' },
501
517
  { id: 'x-ai/grok-4.5', name: 'Grok 4.5', description: 'xAI — flagship reasoning' },
502
518
  ],
503
- defaultModel: 'anthropic/claude-opus-4',
519
+ defaultModel: 'openrouter/auto',
504
520
  defaultProtocol: 'openai',
505
521
  envKey: 'OPENROUTER_API_KEY',
506
522
  subscribeUrl: 'https://openrouter.ai/keys',
@@ -550,6 +566,65 @@ export const PROVIDERS = {
550
566
  export function getProvider(id) {
551
567
  return PROVIDERS[id] || null;
552
568
  }
569
+ /**
570
+ * Exact migrations for curated model ids that vendors replaced.
571
+ *
572
+ * Keep this deliberately narrower than the provider catalogue. Dynamic
573
+ * OpenRouter/Ollama/custom ids are user-controlled and must never be rewritten.
574
+ */
575
+ const RETIRED_MODEL_REPLACEMENTS = {
576
+ 'z.ai': { 'glm-5.1': 'glm-5.2', 'glm-5': 'glm-5.2' },
577
+ 'z.ai-api': { 'glm-5.1': 'glm-5.2', 'glm-5': 'glm-5.2' },
578
+ 'z.ai-cn': { 'glm-5.1': 'glm-5.2', 'glm-5': 'glm-5.2' },
579
+ 'z.ai-cn-api': { 'glm-5.1': 'glm-5.2', 'glm-5': 'glm-5.2' },
580
+ google: {
581
+ 'gemini-3.1-flash-lite': 'gemini-3.5-flash-lite',
582
+ },
583
+ grok: {
584
+ 'grok-code-fast-1': 'grok-build-0.1',
585
+ 'grok-4-fast-reasoning': 'grok-4.3',
586
+ },
587
+ openai: {
588
+ 'gpt-5.5': 'gpt-5.6-sol',
589
+ 'gpt-5.4': 'gpt-5.6-terra',
590
+ 'gpt-5.4-mini': 'gpt-5.6-luna',
591
+ },
592
+ 'kimi-api': {
593
+ 'kimi-k3-code': 'kimi-k3',
594
+ 'kimi-k3-code-highspeed': 'kimi-k3',
595
+ 'kimi-k3-thinking': 'kimi-k3',
596
+ 'kimi-k2.5': 'kimi-k2.6',
597
+ },
598
+ 'kimi-cn': {
599
+ 'kimi-k3-code': 'kimi-k3',
600
+ 'kimi-k3-code-highspeed': 'kimi-k3',
601
+ 'kimi-k3-thinking': 'kimi-k3',
602
+ 'kimi-k2.5': 'kimi-k2.6',
603
+ },
604
+ qwen: {
605
+ 'qwen3-coder-plus': 'qwen3.7-plus',
606
+ 'qwen3-coder-next': 'qwen3.7-plus',
607
+ 'qwen3.7-max': 'qwen3.7-plus',
608
+ },
609
+ 'qwen-api': {
610
+ 'qwen3-coder-plus': 'qwen3.7-max',
611
+ 'qwen3-coder-next': 'qwen3.7-max',
612
+ 'qwen3-coder-flash': 'qwen3.6-flash',
613
+ },
614
+ 'qwen-cn': {
615
+ 'qwen3-coder-plus': 'qwen3.7-plus',
616
+ 'qwen3-coder-next': 'qwen3.7-plus',
617
+ 'qwen3.7-max': 'qwen3.7-plus',
618
+ },
619
+ 'qwen-cn-api': {
620
+ 'qwen3-coder-plus': 'qwen3.7-max',
621
+ 'qwen3-coder-next': 'qwen3.7-max',
622
+ 'qwen3-coder-flash': 'qwen3.6-flash',
623
+ },
624
+ };
625
+ export function replacementModelFor(providerId, modelId) {
626
+ return RETIRED_MODEL_REPLACEMENTS[providerId]?.[modelId];
627
+ }
553
628
  /**
554
629
  * Curated display order for the first-run login flow + `/provider` /
555
630
  * `/login` pickers. Headline / popular providers float to the top so
@@ -567,6 +642,7 @@ const DISPLAY_ORDER = [
567
642
  'kimi',
568
643
  'kimi-api',
569
644
  'qwen',
645
+ 'qwen-token-plan',
570
646
  'qwen-api',
571
647
  'grok',
572
648
  'deepseek',
@@ -673,7 +749,7 @@ export function providerNoStreamWithTools(providerId) {
673
749
  */
674
750
  const SAMPLING_PARAMS_REJECTED = [
675
751
  'claude-fable-5', 'claude-opus-5', 'claude-opus-4-8', 'claude-opus-4-7', 'claude-sonnet-5',
676
- 'kimi-k3-code', 'kimi-k3-thinking', 'kimi-k2.7-code', 'kimi-for-coding',
752
+ 'kimi-k3', 'kimi-k2.7-code', 'kimi-for-coding', 'k3',
677
753
  ];
678
754
  export function modelRejectsSamplingParams(model) {
679
755
  return SAMPLING_PARAMS_REJECTED.some(id => model === id || model.startsWith(`${id}-`));
@@ -731,9 +807,13 @@ export function modelSupportsReasoningEffort(providerId, model) {
731
807
  case 'z.ai-api':
732
808
  case 'z.ai-cn':
733
809
  case 'z.ai-cn-api':
734
- // GLM-5.2 added graded High/Max effort. glm-5-turbo is a plain thinking
735
- // toggle (no graded levels) so it stays out.
810
+ // GLM-5.2 exposes graded High/Max effort; Turbo is a plain toggle.
736
811
  return idMatches(id, 'glm-5-2');
812
+ case 'kimi':
813
+ return idMatches(id, 'k3');
814
+ case 'kimi-api':
815
+ case 'kimi-cn':
816
+ return idMatches(id, 'kimi-k3');
737
817
  case 'grok':
738
818
  // Grok reasoning models accept reasoning_effort (none/low/medium/high).
739
819
  // The coders (grok-code-fast, grok-build — the default) are NON-reasoning
@@ -743,8 +823,7 @@ export function modelSupportsReasoningEffort(providerId, model) {
743
823
  if (id.startsWith('grok-build') || id.startsWith('grok-code'))
744
824
  return false;
745
825
  return id.startsWith('grok') && !id.includes('non-reasoning');
746
- // Kimi (thinking on/off, not graded) and Qwen coders (non-thinking) have
747
- // no graded knob → fall through to default false.
826
+ // GLM Turbo and Qwen coders expose thinking on/off, not a graded knob.
748
827
  case 'openrouter':
749
828
  // OpenRouter normalizes a unified `reasoning` field and silently ignores
750
829
  // it for non-reasoning models, so the control is always safe to expose.
@@ -784,6 +863,11 @@ export function reasoningParamsFor(providerId, model, tier) {
784
863
  case 'z.ai-cn-api':
785
864
  // Graded thinking depth: high (default) or max. Lower tiers collapse to high.
786
865
  return { reasoning_effort: tier === 'max' ? 'max' : 'high' };
866
+ case 'kimi':
867
+ case 'kimi-api':
868
+ case 'kimi-cn':
869
+ // Kimi K3 accepts low/high/max; collapse our medium tier to high.
870
+ return { reasoning_effort: tier === 'low' ? 'low' : tier === 'max' ? 'max' : 'high' };
787
871
  case 'grok':
788
872
  // none/low/medium/high — no "max"; map our Max → high (the ceiling).
789
873
  return { reasoning_effort: tier === 'max' ? 'high' : tier };
@@ -820,6 +904,10 @@ export function availableReasoningTiers(providerId, model) {
820
904
  case 'z.ai-cn':
821
905
  case 'z.ai-cn-api':
822
906
  return ['auto', 'high', 'max'];
907
+ case 'kimi':
908
+ case 'kimi-api':
909
+ case 'kimi-cn':
910
+ return ['auto', 'low', 'high', 'max'];
823
911
  case 'grok':
824
912
  return ['auto', 'low', 'medium', 'high'];
825
913
  case 'openrouter':
@@ -831,8 +919,8 @@ export function availableReasoningTiers(providerId, model) {
831
919
  /**
832
920
  * Map a (possibly out-of-range) tier to the tier this model actually distinguishes,
833
921
  * for display — the chip + the checked menu row. The effort setting is global, so
834
- * a tier picked on Opus ('low') may not exist on GLM-5.2; we show the level GLM
835
- * will really run (its 'low' clamps to 'high'). Picks the available tier whose
922
+ * a tier picked on Opus ('medium') may not exist on Kimi K3; we show the level
923
+ * Kimi will really run (its 'medium' clamps to 'high'). Picks the tier whose
836
924
  * effective param equals the requested one. 'auto' (or unsupported) → 'auto'.
837
925
  */
838
926
  export function resolveReasoningTier(providerId, model, tier) {