@oh-my-pi/pi-catalog 16.1.15 → 16.1.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [16.1.17] - 2026-06-24
6
+
7
+ ### Fixed
8
+
9
+ - Fixed the Umans GLM-5.2 thinking-level picker collapsing to a single `high` tier after dynamic discovery: the `max` upstream level now resolves to the internal `xhigh` effort, the picker shows both `high` and `xhigh`, and the metadata maps `xhigh` back to Umans's native `max` wire tier. ([#3192](https://github.com/can1357/oh-my-pi/issues/3192))
10
+ - Fixed GitHub Copilot business and enterprise endpoints accepting image inputs that they reject with `400 vision is not supported`. The Copilot `/models` response advertises `capabilities.supports.vision = true` for Claude/GPT chat models on every host, but only the canonical personal endpoint (`https://api.githubcopilot.com`) actually serves them; `githubCopilotModelManagerOptions` now forces `input: ["text"]` whenever discovery resolves to a non-personal base URL, and `mergeDynamicModel` honours the dynamic value (instead of OR-upgrading) when the merged endpoint differs from the bundled reference. ([#3387](https://github.com/can1357/oh-my-pi/issues/3387))
11
+ - Fixed OpenRouter Anthropic compat to strip Responses reasoning history during replay so signed thinking blocks are not sent back to routed Anthropic providers. ([#3399](https://github.com/can1357/oh-my-pi/issues/3399))
12
+
5
13
  ## [16.1.14] - 2026-06-22
6
14
 
7
15
  ### Added
@@ -28,6 +28,16 @@ export type ParsedGitHubCopilotApiKey = {
28
28
  apiEndpoint?: string;
29
29
  };
30
30
  export declare function isPublicGitHubHost(host: string): boolean;
31
+ /**
32
+ * Canonical personal-Copilot API host. The business
33
+ * (`api.business.githubcopilot.com`) and enterprise (`copilot-api.{domain}`)
34
+ * endpoints respond with HTTP 400 "vision is not supported" on image inputs,
35
+ * so catalog discovery and capability gates MUST honour the upstream's
36
+ * `supports.vision` flag only for this exact base URL.
37
+ */
38
+ export declare const PERSONAL_GITHUB_COPILOT_BASE_URL: "https://api.githubcopilot.com";
39
+ /** `true` when the resolved base URL is the canonical personal-Copilot host. */
40
+ export declare function isPersonalGitHubCopilotBaseUrl(baseUrl: string | undefined): boolean;
31
41
  export declare function normalizeGitHubCopilotEnterpriseDomain(input: string | undefined): string | undefined;
32
42
  export declare function normalizeGitHubCopilotApiEndpoint(input: string | undefined): string | undefined;
33
43
  export declare function parseGitHubCopilotApiKey(apiKeyRaw: string): ParsedGitHubCopilotApiKey;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-catalog",
4
- "version": "16.1.15",
4
+ "version": "16.1.17",
5
5
  "description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -34,12 +34,12 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@bufbuild/protobuf": "^2.12.0",
37
- "@oh-my-pi/pi-utils": "16.1.15",
37
+ "@oh-my-pi/pi-utils": "16.1.17",
38
38
  "arktype": "^2.2.0",
39
39
  "zod": "^4"
40
40
  },
41
41
  "devDependencies": {
42
- "@oh-my-pi/pi-ai": "16.1.15",
42
+ "@oh-my-pi/pi-ai": "16.1.17",
43
43
  "@types/bun": "^1.3.14"
44
44
  },
45
45
  "engines": {
@@ -374,7 +374,7 @@ export function buildOpenAICompat(spec: ModelSpec<"openai-completions">): Resolv
374
374
  reasoningDisableMode: resolveReasoningDisableMode(thinkingFormat),
375
375
  omitReasoningEffort: false,
376
376
  includeEncryptedReasoning: true,
377
- filterReasoningHistory: false,
377
+ filterReasoningHistory: isOpenRouter && isAnthropicModel,
378
378
  thinkingKeep: usesMoonshotKimiPreservedThinking ? "all" : undefined,
379
379
  reasoningContentField: "reasoning_content",
380
380
  // Backends that 400 follow-up requests when prior assistant tool-call turns lack `reasoning_content`:
@@ -480,6 +480,7 @@ export function buildOpenAIResponsesCompat(spec: OpenAIResponsesSpecLike): Resol
480
480
  const id = spec.id ?? "";
481
481
  const thinkingFormat: ResolvedOpenAISharedCompat["thinkingFormat"] = isOpenRouter ? "openrouter" : "openai";
482
482
  const isKimiModel = id ? isKimiModelId(id) : false;
483
+ const isAnthropicModel = id ? isClaudeModelId(id) || isAnthropicNamespacedModelId(id) : false;
483
484
  const isDeepseekFamily = id ? isDeepseekModelIdOrName(id) || isDeepseekModelIdOrName(spec.name) : false;
484
485
  const reasoningCapable = Boolean(spec.reasoning);
485
486
 
@@ -505,7 +506,7 @@ export function buildOpenAIResponsesCompat(spec: OpenAIResponsesSpecLike): Resol
505
506
  reasoningDisableMode: resolveReasoningDisableMode(thinkingFormat),
506
507
  omitReasoningEffort: false,
507
508
  includeEncryptedReasoning: spec.provider !== "xai-oauth",
508
- filterReasoningHistory: spec.provider === "xai-oauth",
509
+ filterReasoningHistory: spec.provider === "xai-oauth" || (isOpenRouter && isAnthropicModel),
509
510
  disableReasoningOnForcedToolChoice: isKimiModel,
510
511
  disableReasoningOnToolChoice: isDeepseekFamily && reasoningCapable && !isOpenRouter,
511
512
  supportsToolChoice: true,
@@ -349,7 +349,15 @@ function fingerprintStatic<TApi extends Api>(
349
349
  }
350
350
 
351
351
  function mergeDynamicModel<TApi extends Api>(existingModel: Model<TApi>, dynamicModel: Model<TApi>): Model<TApi> {
352
- const supportsImage = existingModel.input.includes("image") || dynamicModel.input.includes("image");
352
+ // When discovery resolves the same model id to a different endpoint (e.g.
353
+ // a GitHub Copilot business/enterprise host), the bundled reference's
354
+ // capabilities are pinned to the canonical host and no longer apply —
355
+ // honour the dynamic value alone. Same-endpoint merges still OR-upgrade so
356
+ // a discovery that omits the capability flag doesn't drop bundled vision.
357
+ const endpointChanged = existingModel.baseUrl !== dynamicModel.baseUrl;
358
+ const supportsImage = endpointChanged
359
+ ? dynamicModel.input.includes("image")
360
+ : existingModel.input.includes("image") || dynamicModel.input.includes("image");
353
361
  // Re-build from spec stage: sparse compat comes from `compatConfig` (the
354
362
  // verbatim override vocabulary), never the resolved `compat` record.
355
363
  return buildModel({
@@ -301,12 +301,12 @@ function getModelDefinedEfforts<TApi extends Api>(
301
301
  ): readonly Effort[] | undefined {
302
302
  if (isGlm52ReasoningEffortModelId(spec.id)) {
303
303
  // Z.ai/Zhipu and OpenRouter both surface GLM-5.2's full effort ladder,
304
- // including the top `xhigh` (= "max") tier; Ollama Cloud exposes only
305
- // high/xhigh.
304
+ // including the top `xhigh` (= "max") tier; Umans and Ollama Cloud
305
+ // expose only high/max.
306
306
  if (isZaiThinkingFormat(compat) || isOpenRouterThinkingFormat(compat)) {
307
307
  return DEFAULT_REASONING_EFFORTS_WITH_XHIGH;
308
308
  }
309
- if (isOllamaCloudGlm52ReasoningEffortModel(spec)) {
309
+ if (isUmansGlm52ReasoningEffortModel(spec) || isOllamaCloudGlm52ReasoningEffortModel(spec)) {
310
310
  return GLM_52_HIGH_MAX_REASONING_EFFORTS;
311
311
  }
312
312
  }
@@ -325,6 +325,10 @@ function isOllamaCloudGlm52ReasoningEffortModel<TApi extends Api>(spec: ModelSpe
325
325
  return spec.api === "ollama-chat" && spec.provider === "ollama-cloud" && isGlm52ReasoningEffortModelId(spec.id);
326
326
  }
327
327
 
328
+ function isUmansGlm52ReasoningEffortModel<TApi extends Api>(spec: ModelSpec<TApi>): boolean {
329
+ return spec.api === "anthropic-messages" && spec.provider === "umans" && isGlm52ReasoningEffortModelId(spec.id);
330
+ }
331
+
328
332
  function isMinimaxReasoningModelOnAnthropicEndpoint<TApi extends Api>(spec: ModelSpec<TApi>): boolean {
329
333
  return spec.api === "anthropic-messages" && (isMinimaxM2FamilyModelId(spec.id) || isMinimaxM3FamilyModelId(spec.id));
330
334
  }
@@ -378,15 +382,16 @@ function inferDetectedEffortMap<TApi extends Api>(
378
382
  // `xhigh` 400s — collapse minimal->none, low/medium/high->high, xhigh->max.
379
383
  // - OpenRouter: `max` 400s and `xhigh` IS its max tier, so it passes `xhigh`
380
384
  // through literally (no map; the tier is exposed via getModelDefinedEfforts).
381
- // - Other openai-compat hosts (Fireworks, resellers) and Ollama Cloud keep
382
- // their distinct lower tiers and host quirks (e.g. Fireworks rejects
383
- // `minimal`, so `minimal->none` stays) and only remap the top `xhigh` UI
384
- // tier onto the genuine `max` budget. Filtered to supported efforts later.
385
+ // - Umans and Ollama Cloud expose only high/max on their GLM-5.2 routes.
386
+ // - Other openai-compat hosts (Fireworks, resellers) keep their distinct
387
+ // lower tiers and host quirks (e.g. Fireworks rejects `minimal`, so
388
+ // `minimal->none` stays) and only remap the top `xhigh` UI tier onto the
389
+ // genuine `max` budget. Filtered to supported efforts later.
385
390
  const isGlm52 = isGlm52ReasoningEffortModelId(spec.id);
386
391
  if (isGlm52 && isZaiThinkingFormat(compat)) {
387
392
  return ZAI_GLM_52_REASONING_EFFORT_MAP;
388
393
  }
389
- if (isOllamaCloudGlm52ReasoningEffortModel(spec)) {
394
+ if (isUmansGlm52ReasoningEffortModel(spec) || isOllamaCloudGlm52ReasoningEffortModel(spec)) {
390
395
  return GLM_52_XHIGH_MAX_EFFORT_MAP;
391
396
  }
392
397
  if (isSakanaFuguReasoningModel(spec)) {
@@ -577,6 +582,9 @@ function inferThinkingControlMode<TApi extends Api>(
577
582
  if (isMinimaxReasoningModelOnAnthropicEndpoint(spec)) {
578
583
  return "anthropic-adaptive";
579
584
  }
585
+ if (isUmansGlm52ReasoningEffortModel(spec)) {
586
+ return "anthropic-budget-effort";
587
+ }
580
588
  if (parsedModel.family === "anthropic") {
581
589
  if (semverGte(parsedModel.version, "4.6")) {
582
590
  return "anthropic-adaptive";
package/src/models.json CHANGED
@@ -20926,7 +20926,7 @@
20926
20926
  "huggingface": {
20927
20927
  "deepseek-ai/DeepSeek-R1": {
20928
20928
  "id": "deepseek-ai/DeepSeek-R1",
20929
- "name": "DeepSeek R1",
20929
+ "name": "DeepSeek-R1",
20930
20930
  "api": "openai-completions",
20931
20931
  "provider": "huggingface",
20932
20932
  "baseUrl": "https://router.huggingface.co/v1",
@@ -20935,13 +20935,13 @@
20935
20935
  "text"
20936
20936
  ],
20937
20937
  "cost": {
20938
- "input": 3,
20939
- "output": 7,
20940
- "cacheRead": 3,
20941
- "cacheWrite": 3
20938
+ "input": 0.7,
20939
+ "output": 2.5,
20940
+ "cacheRead": 0,
20941
+ "cacheWrite": 0
20942
20942
  },
20943
- "contextWindow": 131072,
20944
- "maxTokens": 8192,
20943
+ "contextWindow": 64000,
20944
+ "maxTokens": 32768,
20945
20945
  "thinking": {
20946
20946
  "mode": "effort",
20947
20947
  "efforts": [
@@ -21051,6 +21051,42 @@
21051
21051
  }
21052
21052
  }
21053
21053
  },
21054
+ "deepseek-ai/DeepSeek-V4-Flash": {
21055
+ "id": "deepseek-ai/DeepSeek-V4-Flash",
21056
+ "name": "DeepSeek V4 Flash",
21057
+ "api": "openai-completions",
21058
+ "provider": "huggingface",
21059
+ "baseUrl": "https://router.huggingface.co/v1",
21060
+ "reasoning": true,
21061
+ "input": [
21062
+ "text"
21063
+ ],
21064
+ "cost": {
21065
+ "input": 0.14,
21066
+ "output": 0.28,
21067
+ "cacheRead": 0,
21068
+ "cacheWrite": 0
21069
+ },
21070
+ "contextWindow": 1048576,
21071
+ "maxTokens": 384000,
21072
+ "thinking": {
21073
+ "mode": "effort",
21074
+ "efforts": [
21075
+ "minimal",
21076
+ "low",
21077
+ "medium",
21078
+ "high",
21079
+ "xhigh"
21080
+ ],
21081
+ "effortMap": {
21082
+ "minimal": "high",
21083
+ "low": "high",
21084
+ "medium": "high",
21085
+ "high": "high",
21086
+ "xhigh": "max"
21087
+ }
21088
+ }
21089
+ },
21054
21090
  "deepseek-ai/DeepSeek-V4-Pro": {
21055
21091
  "id": "deepseek-ai/DeepSeek-V4-Pro",
21056
21092
  "name": "DeepSeek V4 Pro",
@@ -21087,6 +21123,85 @@
21087
21123
  }
21088
21124
  }
21089
21125
  },
21126
+ "google/gemma-4-26B-A4B-it": {
21127
+ "id": "google/gemma-4-26B-A4B-it",
21128
+ "name": "Gemma 4 26B A4B IT",
21129
+ "api": "openai-completions",
21130
+ "provider": "huggingface",
21131
+ "baseUrl": "https://router.huggingface.co/v1",
21132
+ "reasoning": true,
21133
+ "input": [
21134
+ "text",
21135
+ "image"
21136
+ ],
21137
+ "cost": {
21138
+ "input": 0.13,
21139
+ "output": 0.4,
21140
+ "cacheRead": 0,
21141
+ "cacheWrite": 0
21142
+ },
21143
+ "contextWindow": 262144,
21144
+ "maxTokens": 32768,
21145
+ "thinking": {
21146
+ "mode": "effort",
21147
+ "efforts": [
21148
+ "minimal",
21149
+ "low",
21150
+ "medium",
21151
+ "high",
21152
+ "xhigh"
21153
+ ]
21154
+ }
21155
+ },
21156
+ "google/gemma-4-31B-it": {
21157
+ "id": "google/gemma-4-31B-it",
21158
+ "name": "Gemma 4 31B IT",
21159
+ "api": "openai-completions",
21160
+ "provider": "huggingface",
21161
+ "baseUrl": "https://router.huggingface.co/v1",
21162
+ "reasoning": true,
21163
+ "input": [
21164
+ "text",
21165
+ "image"
21166
+ ],
21167
+ "cost": {
21168
+ "input": 0.14,
21169
+ "output": 0.4,
21170
+ "cacheRead": 0,
21171
+ "cacheWrite": 0
21172
+ },
21173
+ "contextWindow": 262144,
21174
+ "maxTokens": 32768,
21175
+ "thinking": {
21176
+ "mode": "effort",
21177
+ "efforts": [
21178
+ "minimal",
21179
+ "low",
21180
+ "medium",
21181
+ "high",
21182
+ "xhigh"
21183
+ ]
21184
+ }
21185
+ },
21186
+ "meta-llama/Llama-3.3-70B-Instruct": {
21187
+ "id": "meta-llama/Llama-3.3-70B-Instruct",
21188
+ "name": "Llama-3.3-70B-Instruct",
21189
+ "api": "openai-completions",
21190
+ "provider": "huggingface",
21191
+ "baseUrl": "https://router.huggingface.co/v1",
21192
+ "reasoning": false,
21193
+ "input": [
21194
+ "text"
21195
+ ],
21196
+ "cost": {
21197
+ "input": 0.59,
21198
+ "output": 0.79,
21199
+ "cacheRead": 0,
21200
+ "cacheWrite": 0
21201
+ },
21202
+ "contextWindow": 131072,
21203
+ "maxTokens": 4096
21204
+ },
21090
21205
  "meta-llama/Llama-3.3-70B-Instruct-Turbo": {
21091
21206
  "id": "meta-llama/Llama-3.3-70B-Instruct-Turbo",
21092
21207
  "name": "Llama 3.3 70B",
@@ -21106,6 +21221,34 @@
21106
21221
  "contextWindow": 131072,
21107
21222
  "maxTokens": 8192
21108
21223
  },
21224
+ "MiniMaxAI/MiniMax-M2": {
21225
+ "id": "MiniMaxAI/MiniMax-M2",
21226
+ "name": "MiniMax-M2",
21227
+ "api": "openai-completions",
21228
+ "provider": "huggingface",
21229
+ "baseUrl": "https://router.huggingface.co/v1",
21230
+ "reasoning": true,
21231
+ "input": [
21232
+ "text"
21233
+ ],
21234
+ "cost": {
21235
+ "input": 0.3,
21236
+ "output": 1.2,
21237
+ "cacheRead": 0,
21238
+ "cacheWrite": 0
21239
+ },
21240
+ "contextWindow": 204800,
21241
+ "maxTokens": 128000,
21242
+ "thinking": {
21243
+ "mode": "effort",
21244
+ "efforts": [
21245
+ "low",
21246
+ "medium",
21247
+ "high"
21248
+ ],
21249
+ "requiresEffort": true
21250
+ }
21251
+ },
21109
21252
  "MiniMaxAI/MiniMax-M2.1": {
21110
21253
  "id": "MiniMaxAI/MiniMax-M2.1",
21111
21254
  "name": "MiniMax-M2.1",
@@ -21190,6 +21333,36 @@
21190
21333
  "requiresEffort": true
21191
21334
  }
21192
21335
  },
21336
+ "MiniMaxAI/MiniMax-M3": {
21337
+ "id": "MiniMaxAI/MiniMax-M3",
21338
+ "name": "MiniMax-M3",
21339
+ "api": "openai-completions",
21340
+ "provider": "huggingface",
21341
+ "baseUrl": "https://router.huggingface.co/v1",
21342
+ "reasoning": true,
21343
+ "input": [
21344
+ "text",
21345
+ "image"
21346
+ ],
21347
+ "cost": {
21348
+ "input": 0.3,
21349
+ "output": 1.2,
21350
+ "cacheRead": 0,
21351
+ "cacheWrite": 0
21352
+ },
21353
+ "contextWindow": 524288,
21354
+ "maxTokens": 128000,
21355
+ "thinking": {
21356
+ "mode": "effort",
21357
+ "efforts": [
21358
+ "minimal",
21359
+ "low",
21360
+ "medium",
21361
+ "high",
21362
+ "xhigh"
21363
+ ]
21364
+ }
21365
+ },
21193
21366
  "moonshotai/Kimi-K2-Instruct": {
21194
21367
  "id": "moonshotai/Kimi-K2-Instruct",
21195
21368
  "name": "Kimi-K2-Instruct",
@@ -21318,6 +21491,36 @@
21318
21491
  ]
21319
21492
  }
21320
21493
  },
21494
+ "moonshotai/Kimi-K2.7-Code": {
21495
+ "id": "moonshotai/Kimi-K2.7-Code",
21496
+ "name": "Kimi K2.7 Code",
21497
+ "api": "openai-completions",
21498
+ "provider": "huggingface",
21499
+ "baseUrl": "https://router.huggingface.co/v1",
21500
+ "reasoning": true,
21501
+ "input": [
21502
+ "text",
21503
+ "image"
21504
+ ],
21505
+ "cost": {
21506
+ "input": 0.95,
21507
+ "output": 4,
21508
+ "cacheRead": 0,
21509
+ "cacheWrite": 0
21510
+ },
21511
+ "contextWindow": 262144,
21512
+ "maxTokens": 262144,
21513
+ "thinking": {
21514
+ "mode": "effort",
21515
+ "efforts": [
21516
+ "minimal",
21517
+ "low",
21518
+ "medium",
21519
+ "high",
21520
+ "xhigh"
21521
+ ]
21522
+ }
21523
+ },
21321
21524
  "openai/gpt-oss-120b": {
21322
21525
  "id": "openai/gpt-oss-120b",
21323
21526
  "name": "GPT OSS 120B",
@@ -21345,6 +21548,34 @@
21345
21548
  ]
21346
21549
  }
21347
21550
  },
21551
+ "Qwen/Qwen3-235B-A22B": {
21552
+ "id": "Qwen/Qwen3-235B-A22B",
21553
+ "name": "Qwen3 235B-A22B",
21554
+ "api": "openai-completions",
21555
+ "provider": "huggingface",
21556
+ "baseUrl": "https://router.huggingface.co/v1",
21557
+ "reasoning": true,
21558
+ "input": [
21559
+ "text"
21560
+ ],
21561
+ "cost": {
21562
+ "input": 0.2,
21563
+ "output": 0.8,
21564
+ "cacheRead": 0,
21565
+ "cacheWrite": 0
21566
+ },
21567
+ "contextWindow": 40960,
21568
+ "maxTokens": 16384,
21569
+ "thinking": {
21570
+ "mode": "effort",
21571
+ "efforts": [
21572
+ "minimal",
21573
+ "low",
21574
+ "medium",
21575
+ "high"
21576
+ ]
21577
+ }
21578
+ },
21348
21579
  "Qwen/Qwen3-235B-A22B-Thinking-2507": {
21349
21580
  "id": "Qwen/Qwen3-235B-A22B-Thinking-2507",
21350
21581
  "name": "Qwen3-235B-A22B-Thinking-2507",
@@ -21374,6 +21605,53 @@
21374
21605
  "requiresEffort": true
21375
21606
  }
21376
21607
  },
21608
+ "Qwen/Qwen3-32B": {
21609
+ "id": "Qwen/Qwen3-32B",
21610
+ "name": "Qwen3 32B",
21611
+ "api": "openai-completions",
21612
+ "provider": "huggingface",
21613
+ "baseUrl": "https://router.huggingface.co/v1",
21614
+ "reasoning": true,
21615
+ "input": [
21616
+ "text"
21617
+ ],
21618
+ "cost": {
21619
+ "input": 0.29,
21620
+ "output": 0.59,
21621
+ "cacheRead": 0,
21622
+ "cacheWrite": 0
21623
+ },
21624
+ "contextWindow": 131072,
21625
+ "maxTokens": 16384,
21626
+ "thinking": {
21627
+ "mode": "effort",
21628
+ "efforts": [
21629
+ "minimal",
21630
+ "low",
21631
+ "medium",
21632
+ "high"
21633
+ ]
21634
+ }
21635
+ },
21636
+ "Qwen/Qwen3-Coder-30B-A3B-Instruct": {
21637
+ "id": "Qwen/Qwen3-Coder-30B-A3B-Instruct",
21638
+ "name": "Qwen3-Coder 30B-A3B Instruct",
21639
+ "api": "openai-completions",
21640
+ "provider": "huggingface",
21641
+ "baseUrl": "https://router.huggingface.co/v1",
21642
+ "reasoning": false,
21643
+ "input": [
21644
+ "text"
21645
+ ],
21646
+ "cost": {
21647
+ "input": 0.07,
21648
+ "output": 0.26,
21649
+ "cacheRead": 0,
21650
+ "cacheWrite": 0
21651
+ },
21652
+ "contextWindow": 262144,
21653
+ "maxTokens": 65536
21654
+ },
21377
21655
  "Qwen/Qwen3-Coder-480B-A35B-Instruct": {
21378
21656
  "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct",
21379
21657
  "name": "Qwen3-Coder-480B-A35B-Instruct",
@@ -21450,6 +21728,93 @@
21450
21728
  "contextWindow": 262144,
21451
21729
  "maxTokens": 131072
21452
21730
  },
21731
+ "Qwen/Qwen3.5-122B-A10B": {
21732
+ "id": "Qwen/Qwen3.5-122B-A10B",
21733
+ "name": "Qwen3.5 122B-A10B",
21734
+ "api": "openai-completions",
21735
+ "provider": "huggingface",
21736
+ "baseUrl": "https://router.huggingface.co/v1",
21737
+ "reasoning": true,
21738
+ "input": [
21739
+ "text",
21740
+ "image"
21741
+ ],
21742
+ "cost": {
21743
+ "input": 0.4,
21744
+ "output": 3.2,
21745
+ "cacheRead": 0,
21746
+ "cacheWrite": 0
21747
+ },
21748
+ "contextWindow": 262144,
21749
+ "maxTokens": 65536,
21750
+ "thinking": {
21751
+ "mode": "effort",
21752
+ "efforts": [
21753
+ "minimal",
21754
+ "low",
21755
+ "medium",
21756
+ "high"
21757
+ ]
21758
+ }
21759
+ },
21760
+ "Qwen/Qwen3.5-27B": {
21761
+ "id": "Qwen/Qwen3.5-27B",
21762
+ "name": "Qwen3.5 27B",
21763
+ "api": "openai-completions",
21764
+ "provider": "huggingface",
21765
+ "baseUrl": "https://router.huggingface.co/v1",
21766
+ "reasoning": true,
21767
+ "input": [
21768
+ "text",
21769
+ "image"
21770
+ ],
21771
+ "cost": {
21772
+ "input": 0.3,
21773
+ "output": 2.4,
21774
+ "cacheRead": 0,
21775
+ "cacheWrite": 0
21776
+ },
21777
+ "contextWindow": 262144,
21778
+ "maxTokens": 65536,
21779
+ "thinking": {
21780
+ "mode": "effort",
21781
+ "efforts": [
21782
+ "minimal",
21783
+ "low",
21784
+ "medium",
21785
+ "high"
21786
+ ]
21787
+ }
21788
+ },
21789
+ "Qwen/Qwen3.5-35B-A3B": {
21790
+ "id": "Qwen/Qwen3.5-35B-A3B",
21791
+ "name": "Qwen3.5 35B-A3B",
21792
+ "api": "openai-completions",
21793
+ "provider": "huggingface",
21794
+ "baseUrl": "https://router.huggingface.co/v1",
21795
+ "reasoning": true,
21796
+ "input": [
21797
+ "text",
21798
+ "image"
21799
+ ],
21800
+ "cost": {
21801
+ "input": 0.25,
21802
+ "output": 2,
21803
+ "cacheRead": 0,
21804
+ "cacheWrite": 0
21805
+ },
21806
+ "contextWindow": 262144,
21807
+ "maxTokens": 65536,
21808
+ "thinking": {
21809
+ "mode": "effort",
21810
+ "efforts": [
21811
+ "minimal",
21812
+ "low",
21813
+ "medium",
21814
+ "high"
21815
+ ]
21816
+ }
21817
+ },
21453
21818
  "Qwen/Qwen3.5-397B-A17B": {
21454
21819
  "id": "Qwen/Qwen3.5-397B-A17B",
21455
21820
  "name": "Qwen3.5-397B-A17B",
@@ -21479,6 +21844,93 @@
21479
21844
  ]
21480
21845
  }
21481
21846
  },
21847
+ "Qwen/Qwen3.5-9B": {
21848
+ "id": "Qwen/Qwen3.5-9B",
21849
+ "name": "Qwen3.5 9B",
21850
+ "api": "openai-completions",
21851
+ "provider": "huggingface",
21852
+ "baseUrl": "https://router.huggingface.co/v1",
21853
+ "reasoning": true,
21854
+ "input": [
21855
+ "text",
21856
+ "image"
21857
+ ],
21858
+ "cost": {
21859
+ "input": 0.17,
21860
+ "output": 0.25,
21861
+ "cacheRead": 0,
21862
+ "cacheWrite": 0
21863
+ },
21864
+ "contextWindow": 262144,
21865
+ "maxTokens": 65536,
21866
+ "thinking": {
21867
+ "mode": "effort",
21868
+ "efforts": [
21869
+ "minimal",
21870
+ "low",
21871
+ "medium",
21872
+ "high"
21873
+ ]
21874
+ }
21875
+ },
21876
+ "Qwen/Qwen3.6-35B-A3B": {
21877
+ "id": "Qwen/Qwen3.6-35B-A3B",
21878
+ "name": "Qwen3.6 35B-A3B",
21879
+ "api": "openai-completions",
21880
+ "provider": "huggingface",
21881
+ "baseUrl": "https://router.huggingface.co/v1",
21882
+ "reasoning": true,
21883
+ "input": [
21884
+ "text",
21885
+ "image"
21886
+ ],
21887
+ "cost": {
21888
+ "input": 0.15,
21889
+ "output": 0.95,
21890
+ "cacheRead": 0,
21891
+ "cacheWrite": 0
21892
+ },
21893
+ "contextWindow": 262144,
21894
+ "maxTokens": 65536,
21895
+ "thinking": {
21896
+ "mode": "effort",
21897
+ "efforts": [
21898
+ "minimal",
21899
+ "low",
21900
+ "medium",
21901
+ "high"
21902
+ ]
21903
+ }
21904
+ },
21905
+ "stepfun-ai/Step-3.5-Flash": {
21906
+ "id": "stepfun-ai/Step-3.5-Flash",
21907
+ "name": "Step 3.5 Flash",
21908
+ "api": "openai-completions",
21909
+ "provider": "huggingface",
21910
+ "baseUrl": "https://router.huggingface.co/v1",
21911
+ "reasoning": true,
21912
+ "input": [
21913
+ "text"
21914
+ ],
21915
+ "cost": {
21916
+ "input": 0.1,
21917
+ "output": 0.3,
21918
+ "cacheRead": 0,
21919
+ "cacheWrite": 0
21920
+ },
21921
+ "contextWindow": 262144,
21922
+ "maxTokens": 256000,
21923
+ "thinking": {
21924
+ "mode": "effort",
21925
+ "efforts": [
21926
+ "minimal",
21927
+ "low",
21928
+ "medium",
21929
+ "high",
21930
+ "xhigh"
21931
+ ]
21932
+ }
21933
+ },
21482
21934
  "XiaomiMiMo/MiMo-V2-Flash": {
21483
21935
  "id": "XiaomiMiMo/MiMo-V2-Flash",
21484
21936
  "name": "MiMo-V2-Flash",
@@ -21506,6 +21958,123 @@
21506
21958
  ]
21507
21959
  }
21508
21960
  },
21961
+ "zai-org/GLM-4.5": {
21962
+ "id": "zai-org/GLM-4.5",
21963
+ "name": "GLM-4.5",
21964
+ "api": "openai-completions",
21965
+ "provider": "huggingface",
21966
+ "baseUrl": "https://router.huggingface.co/v1",
21967
+ "reasoning": true,
21968
+ "input": [
21969
+ "text"
21970
+ ],
21971
+ "cost": {
21972
+ "input": 0.6,
21973
+ "output": 2.2,
21974
+ "cacheRead": 0,
21975
+ "cacheWrite": 0
21976
+ },
21977
+ "contextWindow": 131072,
21978
+ "maxTokens": 98304,
21979
+ "thinking": {
21980
+ "mode": "effort",
21981
+ "efforts": [
21982
+ "minimal",
21983
+ "low",
21984
+ "medium",
21985
+ "high",
21986
+ "xhigh"
21987
+ ]
21988
+ }
21989
+ },
21990
+ "zai-org/GLM-4.5-Air": {
21991
+ "id": "zai-org/GLM-4.5-Air",
21992
+ "name": "GLM-4.5-Air",
21993
+ "api": "openai-completions",
21994
+ "provider": "huggingface",
21995
+ "baseUrl": "https://router.huggingface.co/v1",
21996
+ "reasoning": true,
21997
+ "input": [
21998
+ "text"
21999
+ ],
22000
+ "cost": {
22001
+ "input": 0.13,
22002
+ "output": 0.85,
22003
+ "cacheRead": 0,
22004
+ "cacheWrite": 0
22005
+ },
22006
+ "contextWindow": 131072,
22007
+ "maxTokens": 98304,
22008
+ "thinking": {
22009
+ "mode": "effort",
22010
+ "efforts": [
22011
+ "minimal",
22012
+ "low",
22013
+ "medium",
22014
+ "high",
22015
+ "xhigh"
22016
+ ]
22017
+ }
22018
+ },
22019
+ "zai-org/GLM-4.5V": {
22020
+ "id": "zai-org/GLM-4.5V",
22021
+ "name": "GLM-4.5V",
22022
+ "api": "openai-completions",
22023
+ "provider": "huggingface",
22024
+ "baseUrl": "https://router.huggingface.co/v1",
22025
+ "reasoning": true,
22026
+ "input": [
22027
+ "text",
22028
+ "image"
22029
+ ],
22030
+ "cost": {
22031
+ "input": 0.6,
22032
+ "output": 1.8,
22033
+ "cacheRead": 0,
22034
+ "cacheWrite": 0
22035
+ },
22036
+ "contextWindow": 65536,
22037
+ "maxTokens": 16384,
22038
+ "thinking": {
22039
+ "mode": "effort",
22040
+ "efforts": [
22041
+ "minimal",
22042
+ "low",
22043
+ "medium",
22044
+ "high",
22045
+ "xhigh"
22046
+ ]
22047
+ }
22048
+ },
22049
+ "zai-org/GLM-4.6": {
22050
+ "id": "zai-org/GLM-4.6",
22051
+ "name": "GLM-4.6",
22052
+ "api": "openai-completions",
22053
+ "provider": "huggingface",
22054
+ "baseUrl": "https://router.huggingface.co/v1",
22055
+ "reasoning": true,
22056
+ "input": [
22057
+ "text"
22058
+ ],
22059
+ "cost": {
22060
+ "input": 0.55,
22061
+ "output": 2.2,
22062
+ "cacheRead": 0,
22063
+ "cacheWrite": 0
22064
+ },
22065
+ "contextWindow": 204800,
22066
+ "maxTokens": 131072,
22067
+ "thinking": {
22068
+ "mode": "effort",
22069
+ "efforts": [
22070
+ "minimal",
22071
+ "low",
22072
+ "medium",
22073
+ "high",
22074
+ "xhigh"
22075
+ ]
22076
+ }
22077
+ },
21509
22078
  "zai-org/GLM-4.7": {
21510
22079
  "id": "zai-org/GLM-4.7",
21511
22080
  "name": "GLM-4.7",
@@ -21621,6 +22190,35 @@
21621
22190
  "xhigh"
21622
22191
  ]
21623
22192
  }
22193
+ },
22194
+ "zai-org/GLM-5.2": {
22195
+ "id": "zai-org/GLM-5.2",
22196
+ "name": "GLM-5.2",
22197
+ "api": "openai-completions",
22198
+ "provider": "huggingface",
22199
+ "baseUrl": "https://router.huggingface.co/v1",
22200
+ "reasoning": true,
22201
+ "input": [
22202
+ "text"
22203
+ ],
22204
+ "cost": {
22205
+ "input": 1.4,
22206
+ "output": 4.4,
22207
+ "cacheRead": 0,
22208
+ "cacheWrite": 0
22209
+ },
22210
+ "contextWindow": 262144,
22211
+ "maxTokens": 131072,
22212
+ "thinking": {
22213
+ "mode": "effort",
22214
+ "efforts": [
22215
+ "minimal",
22216
+ "low",
22217
+ "medium",
22218
+ "high",
22219
+ "xhigh"
22220
+ ]
22221
+ }
21624
22222
  }
21625
22223
  },
21626
22224
  "kilo": {
@@ -46112,11 +46710,11 @@
46112
46710
  },
46113
46711
  "Qwen/Qwen3-235B-A22B": {
46114
46712
  "id": "Qwen/Qwen3-235B-A22B",
46115
- "name": "Qwen/Qwen3-235B-A22B",
46713
+ "name": "Qwen3 235B-A22B",
46116
46714
  "api": "openai-completions",
46117
46715
  "provider": "nanogpt",
46118
46716
  "baseUrl": "https://nano-gpt.com/api/v1",
46119
- "reasoning": false,
46717
+ "reasoning": true,
46120
46718
  "input": [
46121
46719
  "text"
46122
46720
  ],
@@ -46127,7 +46725,16 @@
46127
46725
  "cacheWrite": 0
46128
46726
  },
46129
46727
  "contextWindow": 131072,
46130
- "maxTokens": 8192
46728
+ "maxTokens": 8192,
46729
+ "thinking": {
46730
+ "mode": "effort",
46731
+ "efforts": [
46732
+ "minimal",
46733
+ "low",
46734
+ "medium",
46735
+ "high"
46736
+ ]
46737
+ }
46131
46738
  },
46132
46739
  "qwen/Qwen3-235B-A22B-Instruct-2507": {
46133
46740
  "id": "qwen/Qwen3-235B-A22B-Instruct-2507",
@@ -46647,13 +47254,14 @@
46647
47254
  },
46648
47255
  "Qwen/Qwen3.6-35B-A3B": {
46649
47256
  "id": "Qwen/Qwen3.6-35B-A3B",
46650
- "name": "Qwen/Qwen3.6-35B-A3B",
47257
+ "name": "Qwen3.6 35B-A3B",
46651
47258
  "api": "openai-completions",
46652
47259
  "provider": "nanogpt",
46653
47260
  "baseUrl": "https://nano-gpt.com/api/v1",
46654
47261
  "reasoning": true,
46655
47262
  "input": [
46656
- "text"
47263
+ "text",
47264
+ "image"
46657
47265
  ],
46658
47266
  "cost": {
46659
47267
  "input": 0,
@@ -47716,6 +48324,25 @@
47716
48324
  "contextWindow": null,
47717
48325
  "maxTokens": null
47718
48326
  },
48327
+ "sakana/fugu-ultra": {
48328
+ "id": "sakana/fugu-ultra",
48329
+ "name": "sakana/fugu-ultra",
48330
+ "api": "openai-completions",
48331
+ "provider": "nanogpt",
48332
+ "baseUrl": "https://nano-gpt.com/api/v1",
48333
+ "reasoning": false,
48334
+ "input": [
48335
+ "text"
48336
+ ],
48337
+ "cost": {
48338
+ "input": 0,
48339
+ "output": 0,
48340
+ "cacheRead": 0,
48341
+ "cacheWrite": 0
48342
+ },
48343
+ "contextWindow": 1000000,
48344
+ "maxTokens": null
48345
+ },
47719
48346
  "Salesforce/Llama-xLAM-2-70b-fc-r": {
47720
48347
  "id": "Salesforce/Llama-xLAM-2-70b-fc-r",
47721
48348
  "name": "Salesforce/Llama-xLAM-2-70b-fc-r",
@@ -69124,9 +69751,9 @@
69124
69751
  "text"
69125
69752
  ],
69126
69753
  "cost": {
69127
- "input": 1,
69128
- "output": 4,
69129
- "cacheRead": 0.18,
69754
+ "input": 0.98,
69755
+ "output": 3.08,
69756
+ "cacheRead": 0.182,
69130
69757
  "cacheWrite": 0
69131
69758
  },
69132
69759
  "contextWindow": 1048576,
@@ -69694,7 +70321,7 @@
69694
70321
  "together": {
69695
70322
  "deepseek-ai/DeepSeek-R1": {
69696
70323
  "id": "deepseek-ai/DeepSeek-R1",
69697
- "name": "DeepSeek R1",
70324
+ "name": "DeepSeek-R1",
69698
70325
  "api": "openai-completions",
69699
70326
  "provider": "together",
69700
70327
  "baseUrl": "https://api.together.xyz/v1",
@@ -70600,14 +71227,14 @@
70600
71227
  "baseUrl": "https://api.code.umans.ai",
70601
71228
  "reasoning": true,
70602
71229
  "thinking": {
70603
- "mode": "budget",
71230
+ "mode": "anthropic-budget-effort",
70604
71231
  "efforts": [
70605
- "minimal",
70606
- "low",
70607
- "medium",
70608
71232
  "high",
70609
71233
  "xhigh"
70610
- ]
71234
+ ],
71235
+ "effortMap": {
71236
+ "xhigh": "max"
71237
+ }
70611
71238
  },
70612
71239
  "input": [
70613
71240
  "text"
@@ -77765,6 +78392,36 @@
77765
78392
  ]
77766
78393
  }
77767
78394
  },
78395
+ "sakana/fugu-ultra": {
78396
+ "id": "sakana/fugu-ultra",
78397
+ "name": "Fugu Ultra",
78398
+ "api": "anthropic-messages",
78399
+ "provider": "vercel-ai-gateway",
78400
+ "baseUrl": "https://ai-gateway.vercel.sh",
78401
+ "reasoning": true,
78402
+ "input": [
78403
+ "text",
78404
+ "image"
78405
+ ],
78406
+ "cost": {
78407
+ "input": 5,
78408
+ "output": 30,
78409
+ "cacheRead": 0.5,
78410
+ "cacheWrite": 0
78411
+ },
78412
+ "contextWindow": 1000000,
78413
+ "maxTokens": 1000000,
78414
+ "thinking": {
78415
+ "mode": "budget",
78416
+ "efforts": [
78417
+ "minimal",
78418
+ "low",
78419
+ "medium",
78420
+ "high",
78421
+ "xhigh"
78422
+ ]
78423
+ }
78424
+ },
77768
78425
  "stepfun/step-3.5-flash": {
77769
78426
  "id": "stepfun/step-3.5-flash",
77770
78427
  "name": "Step 3.5 Flash",
@@ -10,7 +10,12 @@ import type { ModelManagerOptions } from "../model-manager";
10
10
  import { getBundledModels } from "../models";
11
11
  import type { Api, FetchImpl, Model, ModelSpec, Provider, ThinkingConfig } from "../types";
12
12
  import { isAnthropicOAuthToken, isRecord, toBoolean, toNumber, toPositiveNumber } from "../utils";
13
- import { COPILOT_API_HEADERS, getGitHubCopilotBaseUrl, parseGitHubCopilotApiKey } from "../wire/github-copilot";
13
+ import {
14
+ COPILOT_API_HEADERS,
15
+ getGitHubCopilotBaseUrl,
16
+ isPersonalGitHubCopilotBaseUrl,
17
+ parseGitHubCopilotApiKey,
18
+ } from "../wire/github-copilot";
14
19
  import { createBundledReferenceMap, createReferenceResolver, toModelSpec } from "./bundled-references";
15
20
 
16
21
  const MODELS_DEV_URL = "https://models.dev/api.json";
@@ -566,7 +571,9 @@ const UMANS_REASONING_EFFORT_BY_LEVEL: Record<string, Effort> = {
566
571
  medium: Effort.Medium,
567
572
  high: Effort.High,
568
573
  xhigh: Effort.XHigh,
574
+ max: Effort.XHigh,
569
575
  };
576
+ const UMANS_MAX_REASONING_EFFORT_MAP = { [Effort.XHigh]: "max" } as const;
570
577
  const UMANS_DEFAULT_REASONING_EFFORTS = [Effort.Minimal, Effort.Low, Effort.Medium, Effort.High, Effort.XHigh] as const;
571
578
  const UMANS_VIA_HANDOFF_MODEL_IDS = ["umans-glm-5.1", "umans-glm-5.2"] as const;
572
579
 
@@ -620,10 +627,20 @@ function mapUmansReasoningEfforts(value: unknown): readonly Effort[] {
620
627
  return efforts.length > 0 ? efforts : UMANS_DEFAULT_REASONING_EFFORTS;
621
628
  }
622
629
 
630
+ function umansHasMaxReasoningLevel(value: unknown): boolean {
631
+ return isRecord(value) && Array.isArray(value.levels) && value.levels.includes("max");
632
+ }
633
+
623
634
  function mapUmansThinkingConfig(value: unknown): ThinkingConfig | undefined {
624
635
  if (!umansReasoningSupported(value)) return undefined;
625
636
  const efforts = mapUmansReasoningEfforts(value);
626
- const thinking: ThinkingConfig = { mode: "budget", efforts };
637
+ const thinking: ThinkingConfig = {
638
+ mode: umansHasMaxReasoningLevel(value) ? "anthropic-budget-effort" : "budget",
639
+ efforts,
640
+ };
641
+ if (thinking.mode === "anthropic-budget-effort") {
642
+ thinking.effortMap = UMANS_MAX_REASONING_EFFORT_MAP;
643
+ }
627
644
  if (isRecord(value)) {
628
645
  if (value.can_disable === false) {
629
646
  thinking.requiresEffort = true;
@@ -3113,10 +3130,16 @@ export function githubCopilotModelManagerOptions(config?: GithubCopilotModelMana
3113
3130
  ? entry.name
3114
3131
  : (reference?.name ?? defaults.name);
3115
3132
  const api = inferCopilotApi(defaults.id);
3133
+ // `supports.vision` reports the model's intrinsic capability, but
3134
+ // the business/enterprise endpoints respond `400 vision is not
3135
+ // supported` on image inputs. Only honour the flag for the
3136
+ // canonical personal-Copilot host.
3116
3137
  const supportsVision = extractCopilotSupportsVision(entry);
3117
- const input: ModelSpec<Api>["input"] = supportsVision
3118
- ? ["text", "image"]
3119
- : (reference?.input ?? defaults.input);
3138
+ const input: ModelSpec<Api>["input"] = isPersonalGitHubCopilotBaseUrl(baseUrl)
3139
+ ? supportsVision
3140
+ ? ["text", "image"]
3141
+ : (reference?.input ?? defaults.input)
3142
+ : ["text"];
3120
3143
  // With COPILOT_API_HEADERS the served window is the long-context
3121
3144
  // ceiling; the default tier ends at token_prices.default.context_max
3122
3145
  // prompt tokens. Cap the base entry to the default tier — the long
@@ -45,6 +45,20 @@ export function isPublicGitHubHost(host: string): boolean {
45
45
  return PUBLIC_GITHUB_HOSTS.has(host.trim().toLowerCase());
46
46
  }
47
47
 
48
+ /**
49
+ * Canonical personal-Copilot API host. The business
50
+ * (`api.business.githubcopilot.com`) and enterprise (`copilot-api.{domain}`)
51
+ * endpoints respond with HTTP 400 "vision is not supported" on image inputs,
52
+ * so catalog discovery and capability gates MUST honour the upstream's
53
+ * `supports.vision` flag only for this exact base URL.
54
+ */
55
+ export const PERSONAL_GITHUB_COPILOT_BASE_URL = "https://api.githubcopilot.com" as const;
56
+
57
+ /** `true` when the resolved base URL is the canonical personal-Copilot host. */
58
+ export function isPersonalGitHubCopilotBaseUrl(baseUrl: string | undefined): boolean {
59
+ return baseUrl === PERSONAL_GITHUB_COPILOT_BASE_URL;
60
+ }
61
+
48
62
  export function normalizeGitHubCopilotEnterpriseDomain(input: string | undefined): string | undefined {
49
63
  const trimmed = input?.trim();
50
64
  if (!trimmed) return undefined;