@oh-my-pi/pi-catalog 17.2.11 → 17.2.12

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.
@@ -18,7 +18,7 @@ import {
18
18
  } from "../identity/family";
19
19
  import { resolveModelReference } from "../identity/reference";
20
20
  import type { ModelManagerOptions } from "../model-manager";
21
- import { getBundledModels } from "../models";
21
+ import { type GeneratedProvider, getBundledModels } from "../models";
22
22
  import type { Api, FetchImpl, Model, ModelSpec, OpenAICompat, Provider, ThinkingConfig } from "../types";
23
23
  import { discoveryFetch, isAnthropicOAuthToken, isRecord, toBoolean, toNumber, toPositiveNumber } from "../utils";
24
24
  import { ALIBABA_TOKEN_PLAN_BASE_URL, parseAlibabaTokenPlanCredential } from "../wire/alibaba-token-plan";
@@ -592,60 +592,68 @@ function resolveSimpleProviderHeaders(
592
592
  return typeof headers === "function" ? headers() : headers;
593
593
  }
594
594
 
595
- export function createSimpleOpenAICompletionsOptions(
596
- providerId: Parameters<typeof getBundledModels>[0],
597
- defaultBaseUrl: string,
598
- config?: SimpleProviderConfig,
599
- ): ModelManagerOptions<"openai-completions"> {
600
- const apiKey = config?.apiKey;
601
- const baseUrl = config?.baseUrl ?? defaultBaseUrl;
602
- const references = createBundledReferenceMap<"openai-completions">(providerId);
595
+ type OpenAICompatibleModelManagerBuilderOptions<TApi extends Api> = {
596
+ api: TApi;
597
+ providerId: GeneratedProvider;
598
+ defaultBaseUrl: string;
599
+ config?: SimpleProviderConfig;
600
+ headers?: SimpleProviderDiscoveryHeaders;
601
+ dynamicModelsAuthoritative?: true;
602
+ requireApiKey?: true;
603
+ filterModel?: (
604
+ entry: OpenAICompatibleModelRecord,
605
+ model: ModelSpec<TApi>,
606
+ references: Map<string, ModelSpec<TApi>>,
607
+ ) => boolean;
608
+ mapModel: (
609
+ entry: OpenAICompatibleModelRecord,
610
+ defaults: ModelSpec<TApi>,
611
+ reference: ModelSpec<TApi> | undefined,
612
+ ) => ModelSpec<TApi> | null;
613
+ };
614
+
615
+ function createOpenAICompatibleModelManagerOptions<TApi extends Api>(
616
+ options: OpenAICompatibleModelManagerBuilderOptions<TApi>,
617
+ ): ModelManagerOptions<TApi> {
618
+ const apiKey = options.config?.apiKey;
619
+ const baseUrl = options.config?.baseUrl ?? options.defaultBaseUrl;
620
+ const references = createBundledReferenceMap<TApi>(options.providerId);
621
+ const filterModel = options.filterModel;
603
622
  return {
604
- providerId,
605
- ...(apiKey && {
623
+ providerId: options.providerId,
624
+ ...(options.dynamicModelsAuthoritative && { dynamicModelsAuthoritative: true }),
625
+ ...((!options.requireApiKey || apiKey) && {
606
626
  fetchDynamicModels: () =>
607
627
  fetchOpenAICompatibleModels({
608
- api: "openai-completions",
609
- provider: providerId,
628
+ api: options.api,
629
+ provider: options.providerId,
610
630
  baseUrl,
611
631
  apiKey,
612
- headers: resolveSimpleProviderHeaders(config?.headers),
613
- mapModel: (entry, defaults) => {
614
- const reference = references.get(defaults.id);
615
- return mapWithBundledReference(entry, defaults, reference);
616
- },
617
- fetch: config?.fetch,
632
+ ...(options.headers && { headers: resolveSimpleProviderHeaders(options.headers) }),
633
+ ...(filterModel && {
634
+ filterModel: (entry, model) => filterModel(entry, model, references),
635
+ }),
636
+ mapModel: (entry, defaults) => options.mapModel(entry, defaults, references.get(defaults.id)),
637
+ fetch: options.config?.fetch,
618
638
  }),
619
639
  }),
620
640
  };
621
641
  }
622
642
 
623
- function createSimpleOpenAIResponsesOptions(
643
+ export function createSimpleOpenAICompletionsOptions(
624
644
  providerId: Parameters<typeof getBundledModels>[0],
625
645
  defaultBaseUrl: string,
626
646
  config?: SimpleProviderConfig,
627
- ): ModelManagerOptions<"openai-responses"> {
628
- const apiKey = config?.apiKey;
629
- const baseUrl = config?.baseUrl ?? defaultBaseUrl;
630
- const references = createBundledReferenceMap<"openai-responses">(providerId);
631
- return {
647
+ ): ModelManagerOptions<"openai-completions"> {
648
+ return createOpenAICompatibleModelManagerOptions({
649
+ api: "openai-completions",
632
650
  providerId,
633
- ...(apiKey && {
634
- fetchDynamicModels: () =>
635
- fetchOpenAICompatibleModels({
636
- api: "openai-responses",
637
- provider: providerId,
638
- baseUrl,
639
- apiKey,
640
- headers: resolveSimpleProviderHeaders(config?.headers),
641
- mapModel: (entry, defaults) => {
642
- const reference = references.get(defaults.id);
643
- return mapWithBundledReference(entry, defaults, reference);
644
- },
645
- fetch: config?.fetch,
646
- }),
647
- }),
648
- };
651
+ defaultBaseUrl,
652
+ config,
653
+ headers: config?.headers,
654
+ requireApiKey: true,
655
+ mapModel: mapWithBundledReference,
656
+ });
649
657
  }
650
658
 
651
659
  function createSimpleAnthropicProviderOptions(
@@ -865,27 +873,15 @@ export interface OpenAIModelManagerConfig {
865
873
  }
866
874
 
867
875
  export function openaiModelManagerOptions(config?: OpenAIModelManagerConfig): ModelManagerOptions<"openai-responses"> {
868
- const apiKey = config?.apiKey;
869
- const baseUrl = config?.baseUrl ?? "https://api.openai.com/v1";
870
- const references = createBundledReferenceMap<"openai-responses">("openai");
871
- return {
876
+ return createOpenAICompatibleModelManagerOptions({
877
+ api: "openai-responses",
872
878
  providerId: "openai",
873
- ...(apiKey && {
874
- fetchDynamicModels: () =>
875
- fetchOpenAICompatibleModels({
876
- api: "openai-responses",
877
- provider: "openai",
878
- baseUrl,
879
- apiKey,
880
- filterModel: (_entry, model) => isLikelyOpenAIResponsesModelId(model.id, references),
881
- mapModel: (entry, defaults) => {
882
- const reference = references.get(defaults.id);
883
- return mapWithBundledReference(entry, defaults, reference);
884
- },
885
- fetch: config?.fetch,
886
- }),
887
- }),
888
- };
879
+ defaultBaseUrl: "https://api.openai.com/v1",
880
+ config,
881
+ requireApiKey: true,
882
+ filterModel: (_entry, model, references) => isLikelyOpenAIResponsesModelId(model.id, references),
883
+ mapModel: mapWithBundledReference,
884
+ });
889
885
  }
890
886
 
891
887
  /** First-party gpt-5.6 SKUs that accept `reasoning: { mode: "pro" }` on the Responses APIs. */
@@ -1036,27 +1032,15 @@ export interface CerebrasModelManagerConfig {
1036
1032
  export function cerebrasModelManagerOptions(
1037
1033
  config?: CerebrasModelManagerConfig,
1038
1034
  ): ModelManagerOptions<"openai-completions"> {
1039
- const apiKey = config?.apiKey;
1040
- const baseUrl = config?.baseUrl ?? "https://api.cerebras.ai/v1";
1041
- const references = createBundledReferenceMap<"openai-completions">("cerebras");
1042
- return {
1035
+ return createOpenAICompatibleModelManagerOptions({
1036
+ api: "openai-completions",
1043
1037
  providerId: "cerebras",
1044
- ...(apiKey && {
1045
- fetchDynamicModels: () =>
1046
- fetchOpenAICompatibleModels({
1047
- api: "openai-completions",
1048
- provider: "cerebras",
1049
- baseUrl,
1050
- apiKey,
1051
- mapModel: (entry, defaults) => {
1052
- const reference = references.get(defaults.id);
1053
- const model = mapWithBundledReference(entry, defaults, reference);
1054
- return applyCerebrasDiscoveryOverrides(model);
1055
- },
1056
- fetch: config?.fetch,
1057
- }),
1058
- }),
1059
- };
1038
+ defaultBaseUrl: "https://api.cerebras.ai/v1",
1039
+ config,
1040
+ requireApiKey: true,
1041
+ mapModel: (entry, defaults, reference) =>
1042
+ applyCerebrasDiscoveryOverrides(mapWithBundledReference(entry, defaults, reference)),
1043
+ });
1060
1044
  }
1061
1045
 
1062
1046
  // ---------------------------------------------------------------------------
@@ -1160,31 +1144,23 @@ function mapNovitaModel(
1160
1144
  export function novitaModelManagerOptions(
1161
1145
  config?: NovitaModelManagerConfig,
1162
1146
  ): ModelManagerOptions<"openai-completions"> {
1163
- const apiKey = config?.apiKey;
1164
- const baseUrl = config?.baseUrl ?? "https://api.novita.ai/openai/v1";
1165
- const references = createBundledReferenceMap<"openai-completions">("novita");
1166
- return {
1147
+ return createOpenAICompatibleModelManagerOptions({
1148
+ api: "openai-completions",
1167
1149
  providerId: "novita",
1150
+ defaultBaseUrl: "https://api.novita.ai/openai/v1",
1151
+ config,
1168
1152
  dynamicModelsAuthoritative: true,
1169
- fetchDynamicModels: async () =>
1170
- fetchOpenAICompatibleModels({
1171
- api: "openai-completions",
1172
- provider: "novita",
1173
- baseUrl,
1174
- apiKey,
1175
- mapModel: (entry, defaults) => mapNovitaModel(entry, defaults, references.get(defaults.id)),
1176
- filterModel: (entry, model) => {
1177
- const active = typeof entry.status !== "number" || entry.status === 1;
1178
- return (
1179
- active &&
1180
- isPublicNovitaModelId(model.id) &&
1181
- novitaArrayIncludes(entry.endpoints, "chat/completions") &&
1182
- toPositiveNumber(entry.max_output_tokens, 0) > 0
1183
- );
1184
- },
1185
- fetch: config?.fetch,
1186
- }),
1187
- };
1153
+ filterModel: (entry, model) => {
1154
+ const active = typeof entry.status !== "number" || entry.status === 1;
1155
+ return (
1156
+ active &&
1157
+ isPublicNovitaModelId(model.id) &&
1158
+ novitaArrayIncludes(entry.endpoints, "chat/completions") &&
1159
+ toPositiveNumber(entry.max_output_tokens, 0) > 0
1160
+ );
1161
+ },
1162
+ mapModel: mapNovitaModel,
1163
+ });
1188
1164
  }
1189
1165
 
1190
1166
  // ---------------------------------------------------------------------------
@@ -1453,11 +1429,14 @@ export function xaiOAuthModelManagerOptions(
1453
1429
  ): ModelManagerOptions<"openai-responses"> {
1454
1430
  const defaultBaseUrl = "https://api.x.ai/v1";
1455
1431
  const resolvedBaseUrl = config?.baseUrl ?? defaultBaseUrl;
1456
- const base = createSimpleOpenAIResponsesOptions(
1457
- "xai-oauth" as Parameters<typeof getBundledModels>[0],
1432
+ const base = createOpenAICompatibleModelManagerOptions({
1433
+ api: "openai-responses",
1434
+ providerId: "xai-oauth",
1458
1435
  defaultBaseUrl,
1459
1436
  config,
1460
- );
1437
+ requireApiKey: true,
1438
+ mapModel: mapWithBundledReference,
1439
+ });
1461
1440
  // Static seed handed to the runtime model manager so the picker populates on
1462
1441
  // a fresh login even before `fetchDynamicModels` fires (it is gated on
1463
1442
  // `config.apiKey` at construction time, and OAuth tokens resolve later via
@@ -1510,28 +1489,16 @@ export interface AimlApiModelManagerConfig {
1510
1489
  export function aimlApiModelManagerOptions(
1511
1490
  config?: AimlApiModelManagerConfig,
1512
1491
  ): ModelManagerOptions<"openai-completions"> {
1513
- const apiKey = config?.apiKey;
1514
- const baseUrl = config?.baseUrl ?? "https://api.aimlapi.com/v1";
1515
- const references = createBundledReferenceMap<"openai-completions">("aimlapi");
1516
- return {
1492
+ return createOpenAICompatibleModelManagerOptions({
1493
+ api: "openai-completions",
1517
1494
  providerId: "aimlapi",
1495
+ defaultBaseUrl: "https://api.aimlapi.com/v1",
1496
+ config,
1518
1497
  dynamicModelsAuthoritative: true,
1519
- ...(apiKey && {
1520
- fetchDynamicModels: () =>
1521
- fetchOpenAICompatibleModels({
1522
- api: "openai-completions",
1523
- provider: "aimlapi",
1524
- baseUrl,
1525
- apiKey,
1526
- filterModel: (_entry, model) => isLikelyAimlApiChatModelId(model.id),
1527
- mapModel: (entry, defaults) => {
1528
- const reference = references.get(defaults.id);
1529
- return mapWithBundledReference(entry, defaults, reference);
1530
- },
1531
- fetch: config?.fetch,
1532
- }),
1533
- }),
1534
- };
1498
+ requireApiKey: true,
1499
+ filterModel: (_entry, model) => isLikelyAimlApiChatModelId(model.id),
1500
+ mapModel: mapWithBundledReference,
1501
+ });
1535
1502
  }
1536
1503
 
1537
1504
  // ---------------------------------------------------------------------------
@@ -2699,24 +2666,13 @@ export interface AlibabaCodingPlanModelManagerConfig {
2699
2666
  export function alibabaCodingPlanModelManagerOptions(
2700
2667
  config?: AlibabaCodingPlanModelManagerConfig,
2701
2668
  ): ModelManagerOptions<"openai-completions"> {
2702
- const apiKey = config?.apiKey;
2703
- const baseUrl = config?.baseUrl ?? "https://coding-intl.dashscope.aliyuncs.com/v1";
2704
- const references = createBundledReferenceMap<"openai-completions">("alibaba-coding-plan");
2705
- return {
2669
+ return createOpenAICompatibleModelManagerOptions({
2670
+ api: "openai-completions",
2706
2671
  providerId: "alibaba-coding-plan",
2707
- fetchDynamicModels: () =>
2708
- fetchOpenAICompatibleModels({
2709
- api: "openai-completions",
2710
- provider: "alibaba-coding-plan",
2711
- baseUrl,
2712
- apiKey,
2713
- mapModel: (entry, defaults) => {
2714
- const reference = references.get(defaults.id);
2715
- return mapWithBundledReference(entry, defaults, reference);
2716
- },
2717
- fetch: config?.fetch,
2718
- }),
2719
- };
2672
+ defaultBaseUrl: "https://coding-intl.dashscope.aliyuncs.com/v1",
2673
+ config,
2674
+ mapModel: mapWithBundledReference,
2675
+ });
2720
2676
  }
2721
2677
 
2722
2678
  // ---------------------------------------------------------------------------
@@ -2733,6 +2689,17 @@ const ALIBABA_TOKEN_PLAN_REASONING: ThinkingConfig = {
2733
2689
  mode: "effort",
2734
2690
  efforts: [Effort.Minimal, Effort.Low, Effort.Medium, Effort.High],
2735
2691
  };
2692
+ // Qwen3.8-Max combines Qwen's binary thinking toggle with OpenAI-style
2693
+ // `reasoning_effort`. The base Qwen view encodes disabled turns; reasoning
2694
+ // requests swap to the OpenAI effort dialect and explicitly enable thinking.
2695
+ const ALIBABA_TOKEN_PLAN_QWEN_EFFORT_COMPAT: OpenAICompat = {
2696
+ ...ALIBABA_TOKEN_PLAN_COMPAT,
2697
+ supportsReasoningEffort: true,
2698
+ whenThinking: {
2699
+ thinkingFormat: "openai",
2700
+ extraBody: { enable_thinking: true },
2701
+ },
2702
+ };
2736
2703
 
2737
2704
  export const ALIBABA_TOKEN_PLAN_STATIC_MODELS: readonly ModelSpec<"openai-completions">[] = [
2738
2705
  {
@@ -2756,6 +2723,24 @@ export const ALIBABA_TOKEN_PLAN_STATIC_MODELS: readonly ModelSpec<"openai-comple
2756
2723
  supportsReasoningEffort: true,
2757
2724
  },
2758
2725
  },
2726
+ {
2727
+ id: "qwen3.8-max",
2728
+ name: "Qwen3.8 Max",
2729
+ api: "openai-completions",
2730
+ provider: "alibaba-token-plan",
2731
+ baseUrl: ALIBABA_TOKEN_PLAN_BASE_URL,
2732
+ reasoning: true,
2733
+ input: ["text", "image"],
2734
+ cost: ALIBABA_TOKEN_PLAN_COST,
2735
+ contextWindow: 1_000_000,
2736
+ maxTokens: 131_072,
2737
+ thinking: {
2738
+ mode: "effort",
2739
+ efforts: [Effort.Low, Effort.Medium, Effort.XHigh],
2740
+ defaultLevel: Effort.XHigh,
2741
+ },
2742
+ compat: ALIBABA_TOKEN_PLAN_QWEN_EFFORT_COMPAT,
2743
+ },
2759
2744
  {
2760
2745
  id: "qwen3.7-max",
2761
2746
  name: "Qwen3.7 Max",
@@ -3519,29 +3504,20 @@ export interface VeniceModelManagerConfig {
3519
3504
  export function veniceModelManagerOptions(
3520
3505
  config?: VeniceModelManagerConfig,
3521
3506
  ): ModelManagerOptions<"openai-completions"> {
3522
- const apiKey = config?.apiKey;
3523
- const baseUrl = config?.baseUrl ?? "https://api.venice.ai/api/v1";
3524
- const references = createBundledReferenceMap<"openai-completions">("venice");
3525
- return {
3507
+ return createOpenAICompatibleModelManagerOptions({
3508
+ api: "openai-completions",
3526
3509
  providerId: "venice",
3527
- fetchDynamicModels: () =>
3528
- fetchOpenAICompatibleModels({
3529
- api: "openai-completions",
3530
- provider: "venice",
3531
- baseUrl,
3532
- apiKey,
3533
- mapModel: (entry, defaults) => {
3534
- const reference = references.get(defaults.id);
3535
- const model = mapWithBundledReference(entry, defaults, reference);
3536
- return {
3537
- ...model,
3538
- maxTokens: clampKimiK27CodeMaxTokens(defaults.id, model.maxTokens),
3539
- compat: { ...model.compat, supportsUsageInStreaming: false },
3540
- };
3541
- },
3542
- fetch: config?.fetch,
3543
- }),
3544
- };
3510
+ defaultBaseUrl: "https://api.venice.ai/api/v1",
3511
+ config,
3512
+ mapModel: (entry, defaults, reference) => {
3513
+ const model = mapWithBundledReference(entry, defaults, reference);
3514
+ return {
3515
+ ...model,
3516
+ maxTokens: clampKimiK27CodeMaxTokens(defaults.id, model.maxTokens),
3517
+ compat: { ...model.compat, supportsUsageInStreaming: false },
3518
+ };
3519
+ },
3520
+ });
3545
3521
  }
3546
3522
 
3547
3523
  // ---------------------------------------------------------------------------
@@ -3557,83 +3533,66 @@ export interface BasetenModelManagerConfig {
3557
3533
  export function basetenModelManagerOptions(
3558
3534
  config?: BasetenModelManagerConfig,
3559
3535
  ): ModelManagerOptions<"openai-completions"> {
3560
- const apiKey = config?.apiKey;
3561
- const baseUrl = config?.baseUrl ?? "https://inference.baseten.co/v1";
3562
- const references = createBundledReferenceMap<"openai-completions">("baseten");
3563
- return {
3536
+ return createOpenAICompatibleModelManagerOptions({
3537
+ api: "openai-completions",
3564
3538
  providerId: "baseten",
3539
+ defaultBaseUrl: "https://inference.baseten.co/v1",
3540
+ config,
3565
3541
  dynamicModelsAuthoritative: true,
3566
- ...(apiKey && {
3567
- fetchDynamicModels: () =>
3568
- fetchOpenAICompatibleModels({
3569
- api: "openai-completions",
3570
- provider: "baseten",
3571
- baseUrl,
3572
- apiKey,
3573
- mapModel: (entry, defaults) => {
3574
- const reference = references.get(defaults.id);
3575
- const raw = entry as Record<string, unknown> & {
3576
- supported_features?: unknown;
3577
- input_modalities?: unknown;
3578
- pricing?: Record<string, unknown>;
3579
- };
3580
- const features = Array.isArray(raw.supported_features) ? raw.supported_features : [];
3581
- const modalities = Array.isArray(raw.input_modalities) ? raw.input_modalities : [];
3582
-
3583
- const isBasetenNativeReasoning =
3584
- defaults.id === "openai/gpt-oss-120b" ||
3585
- defaults.id === "deepseek-ai/DeepSeek-V4-Pro" ||
3586
- defaults.id === "zai-org/GLM-5.2";
3587
- const reasoning =
3588
- isBasetenNativeReasoning &&
3589
- (features.includes("reasoning") || features.includes("reasoning_effort"));
3590
- const supportsTools = features.includes("tools") ? undefined : false;
3591
- const vision = modalities.includes("image") || (reference?.input.includes("image") ?? false);
3592
-
3593
- const pricing = raw.pricing ?? {};
3594
- const cost = {
3595
- input: toPositiveNumber(pricing.prompt, 0) * 1_000_000,
3596
- output: toPositiveNumber(pricing.completion, 0) * 1_000_000,
3597
- cacheRead: toPositiveNumber(pricing.input_cache_read, 0) * 1_000_000,
3598
- cacheWrite: 0,
3599
- };
3542
+ requireApiKey: true,
3543
+ mapModel: (entry, defaults, reference) => {
3544
+ const raw = entry as Record<string, unknown> & {
3545
+ supported_features?: unknown;
3546
+ input_modalities?: unknown;
3547
+ pricing?: Record<string, unknown>;
3548
+ };
3549
+ const features = Array.isArray(raw.supported_features) ? raw.supported_features : [];
3550
+ const modalities = Array.isArray(raw.input_modalities) ? raw.input_modalities : [];
3551
+
3552
+ const isBasetenNativeReasoning =
3553
+ defaults.id === "openai/gpt-oss-120b" ||
3554
+ defaults.id === "deepseek-ai/DeepSeek-V4-Pro" ||
3555
+ defaults.id === "zai-org/GLM-5.2";
3556
+ const reasoning =
3557
+ isBasetenNativeReasoning && (features.includes("reasoning") || features.includes("reasoning_effort"));
3558
+ const supportsTools = features.includes("tools") ? undefined : false;
3559
+ const vision = modalities.includes("image") || (reference?.input.includes("image") ?? false);
3560
+
3561
+ const pricing = raw.pricing ?? {};
3562
+ const cost = {
3563
+ input: toPositiveNumber(pricing.prompt, 0) * 1_000_000,
3564
+ output: toPositiveNumber(pricing.completion, 0) * 1_000_000,
3565
+ cacheRead: toPositiveNumber(pricing.input_cache_read, 0) * 1_000_000,
3566
+ cacheWrite: 0,
3567
+ };
3600
3568
 
3601
- const contextWindow = toPositiveNumber(
3602
- raw.context_length,
3603
- reference?.contextWindow ?? defaults.contextWindow,
3604
- );
3605
- const maxTokens = toPositiveNumber(
3606
- raw.max_completion_tokens,
3607
- reference?.maxTokens ?? defaults.maxTokens,
3608
- );
3569
+ const contextWindow = toPositiveNumber(raw.context_length, reference?.contextWindow ?? defaults.contextWindow);
3570
+ const maxTokens = toPositiveNumber(raw.max_completion_tokens, reference?.maxTokens ?? defaults.maxTokens);
3609
3571
 
3610
- const baseModel = mapWithBundledReference(entry, defaults, reference);
3572
+ const baseModel = mapWithBundledReference(entry, defaults, reference);
3611
3573
 
3612
- // Baseten's reasoning router accepts only the high/max
3613
- // effort tiers for its GLM-5.2 and gpt-oss routes.
3614
- const isEffortReasoning = defaults.id === "openai/gpt-oss-120b" || defaults.id === "zai-org/GLM-5.2";
3615
- const thinking = isEffortReasoning
3616
- ? {
3617
- mode: "effort" as const,
3618
- efforts: [Effort.High, Effort.Max],
3619
- }
3620
- : undefined;
3574
+ // Baseten's reasoning router accepts only the high/max
3575
+ // effort tiers for its GLM-5.2 and gpt-oss routes.
3576
+ const isEffortReasoning = defaults.id === "openai/gpt-oss-120b" || defaults.id === "zai-org/GLM-5.2";
3577
+ const thinking = isEffortReasoning
3578
+ ? {
3579
+ mode: "effort" as const,
3580
+ efforts: [Effort.High, Effort.Max],
3581
+ }
3582
+ : undefined;
3621
3583
 
3622
- return {
3623
- ...baseModel,
3624
- reasoning,
3625
- input: vision ? ["text", "image"] : ["text"],
3626
- cost,
3627
- contextWindow,
3628
- maxTokens,
3629
- ...(thinking ? { thinking } : {}),
3630
- ...(supportsTools === false ? { supportsTools } : {}),
3631
- };
3632
- },
3633
- fetch: config?.fetch,
3634
- }),
3635
- }),
3636
- };
3584
+ return {
3585
+ ...baseModel,
3586
+ reasoning,
3587
+ input: vision ? ["text", "image"] : ["text"],
3588
+ cost,
3589
+ contextWindow,
3590
+ maxTokens,
3591
+ ...(thinking ? { thinking } : {}),
3592
+ ...(supportsTools === false ? { supportsTools } : {}),
3593
+ };
3594
+ },
3595
+ });
3637
3596
  }
3638
3597
 
3639
3598
  // ---------------------------------------------------------------------------
@@ -3830,7 +3789,14 @@ export interface MetaModelManagerConfig {
3830
3789
 
3831
3790
  export function metaModelManagerOptions(config?: MetaModelManagerConfig): ModelManagerOptions<"openai-responses"> {
3832
3791
  return {
3833
- ...createSimpleOpenAIResponsesOptions("meta", META_MODEL_API_BASE_URL, config),
3792
+ ...createOpenAICompatibleModelManagerOptions({
3793
+ api: "openai-responses",
3794
+ providerId: "meta",
3795
+ defaultBaseUrl: META_MODEL_API_BASE_URL,
3796
+ config,
3797
+ requireApiKey: true,
3798
+ mapModel: mapWithBundledReference,
3799
+ }),
3834
3800
  staticModels: META_MUSE_STATIC_MODELS,
3835
3801
  };
3836
3802
  }
@@ -3865,67 +3831,56 @@ const MOONSHOT_KIMI_K3_THINKING: ThinkingConfig = { mode: "effort", efforts: [Ef
3865
3831
  export function moonshotModelManagerOptions(
3866
3832
  config?: MoonshotModelManagerConfig,
3867
3833
  ): ModelManagerOptions<"openai-completions"> {
3868
- const apiKey = config?.apiKey;
3869
- // `MOONSHOT_BASE_URL` redirects discovery (and the streaming request that
3870
- // inherits this baseUrl) at the Kimi China platform `api.moonshot.cn`; an
3871
- // explicit `config.baseUrl` still wins. Mirrors LITELLM_BASE_URL/LM_STUDIO_BASE_URL. (#2883)
3872
- const baseUrl = config?.baseUrl ?? Bun.env.MOONSHOT_BASE_URL ?? "https://api.moonshot.ai/v1";
3873
- const references = createBundledReferenceMap<"openai-completions">("moonshot");
3874
- return {
3834
+ return createOpenAICompatibleModelManagerOptions({
3835
+ api: "openai-completions",
3875
3836
  providerId: "moonshot",
3876
- ...(apiKey && {
3877
- fetchDynamicModels: () =>
3878
- fetchOpenAICompatibleModels({
3879
- api: "openai-completions",
3880
- provider: "moonshot",
3881
- baseUrl,
3882
- apiKey,
3883
- mapModel: (entry, defaults) => {
3884
- const reference = references.get(defaults.id);
3885
- const model = mapWithBundledReference(entry, defaults, reference);
3886
- const id = model.id.toLowerCase();
3887
- // Kimi K3 is discovered but has no bundled/models.dev reference, so the
3888
- // generic dynamic defaults would report it "Free" with no capabilities
3889
- // (#5756). Stamp the official pricing/limits when the endpoint doesn't
3890
- // carry them, and mark it reasoning + vision. K3 always reasons via
3891
- // `reasoning_effort: "max"` and does NOT use the K2.x `thinking` block,
3892
- // so its thinking config is the single-tier `max` scale — the wire path
3893
- // routes it through `reasoning_effort` (see `buildOpenAICompat`).
3894
- if (!reference && isKimiK3ModelId(id)) {
3895
- const isZeroCost = model.cost.input === 0 && model.cost.output === 0 && model.cost.cacheRead === 0;
3896
- return {
3897
- ...model,
3898
- reasoning: true,
3899
- input: ["text", "image"],
3900
- cost: isZeroCost ? { ...MOONSHOT_KIMI_K3_COST } : model.cost,
3901
- contextWindow: model.contextWindow ?? MOONSHOT_KIMI_K3_CONTEXT_WINDOW,
3902
- maxTokens: model.maxTokens ?? MOONSHOT_KIMI_K3_MAX_TOKENS,
3903
- thinking: model.thinking ?? { ...MOONSHOT_KIMI_K3_THINKING },
3904
- };
3905
- }
3906
- // Moonshot's K2.x family (K2.5, K2.6, kimi-k2-thinking, …) is reasoning-capable
3907
- // and vision-capable on the native API. Without these flags the openai-completions
3908
- // path skips the z.ai-format `thinking` block, and Moonshot K2.6 stalls on first
3909
- // turn because its endpoint expects an explicit `thinking: {type}` (#2113). Match
3910
- // the bundled K2.5 metadata for every K2.x id we discover.
3911
- const isKimiK2Reasoning = id.includes("thinking") || /(^|\/)kimi-k2(?:\.\d+)?(?:[-:]|$)/.test(id);
3912
- const isVision =
3913
- id.includes("vision") || id.includes("vl") || /(^|\/)kimi-k2(?:\.\d+)?(?:[-:]|$)/.test(id);
3914
- return {
3915
- ...model,
3916
- reasoning: isKimiK2Reasoning || model.reasoning,
3917
- input: isVision ? ["text", "image"] : model.input,
3918
- thinking:
3919
- model.thinking ??
3920
- (isKimiK2Reasoning
3921
- ? { mode: "effort", efforts: [Effort.Minimal, Effort.Low, Effort.Medium, Effort.High] }
3922
- : undefined),
3923
- };
3924
- },
3925
- fetch: config?.fetch,
3926
- }),
3927
- }),
3928
- };
3837
+ // `MOONSHOT_BASE_URL` redirects discovery (and the streaming request that
3838
+ // inherits this baseUrl) at the Kimi China platform `api.moonshot.cn`; an
3839
+ // explicit `config.baseUrl` still wins. Mirrors LITELLM_BASE_URL/LM_STUDIO_BASE_URL. (#2883)
3840
+ defaultBaseUrl: Bun.env.MOONSHOT_BASE_URL ?? "https://api.moonshot.ai/v1",
3841
+ config,
3842
+ requireApiKey: true,
3843
+ mapModel: (entry, defaults, reference) => {
3844
+ const model = mapWithBundledReference(entry, defaults, reference);
3845
+ const id = model.id.toLowerCase();
3846
+ // Kimi K3 is discovered but has no bundled/models.dev reference, so the
3847
+ // generic dynamic defaults would report it "Free" with no capabilities
3848
+ // (#5756). Stamp the official pricing/limits when the endpoint doesn't
3849
+ // carry them, and mark it reasoning + vision. K3 always reasons via
3850
+ // `reasoning_effort: "max"` and does NOT use the K2.x `thinking` block,
3851
+ // so its thinking config is the single-tier `max` scale — the wire path
3852
+ // routes it through `reasoning_effort` (see `buildOpenAICompat`).
3853
+ if (!reference && isKimiK3ModelId(id)) {
3854
+ const isZeroCost = model.cost.input === 0 && model.cost.output === 0 && model.cost.cacheRead === 0;
3855
+ return {
3856
+ ...model,
3857
+ reasoning: true,
3858
+ input: ["text", "image"],
3859
+ cost: isZeroCost ? { ...MOONSHOT_KIMI_K3_COST } : model.cost,
3860
+ contextWindow: model.contextWindow ?? MOONSHOT_KIMI_K3_CONTEXT_WINDOW,
3861
+ maxTokens: model.maxTokens ?? MOONSHOT_KIMI_K3_MAX_TOKENS,
3862
+ thinking: model.thinking ?? { ...MOONSHOT_KIMI_K3_THINKING },
3863
+ };
3864
+ }
3865
+ // Moonshot's K2.x family (K2.5, K2.6, kimi-k2-thinking, …) is reasoning-capable
3866
+ // and vision-capable on the native API. Without these flags the openai-completions
3867
+ // path skips the z.ai-format `thinking` block, and Moonshot K2.6 stalls on first
3868
+ // turn because its endpoint expects an explicit `thinking: {type}` (#2113). Match
3869
+ // the bundled K2.5 metadata for every K2.x id we discover.
3870
+ const isKimiK2Reasoning = id.includes("thinking") || /(^|\/)kimi-k2(?:\.\d+)?(?:[-:]|$)/.test(id);
3871
+ const isVision = id.includes("vision") || id.includes("vl") || /(^|\/)kimi-k2(?:\.\d+)?(?:[-:]|$)/.test(id);
3872
+ return {
3873
+ ...model,
3874
+ reasoning: isKimiK2Reasoning || model.reasoning,
3875
+ input: isVision ? ["text", "image"] : model.input,
3876
+ thinking:
3877
+ model.thinking ??
3878
+ (isKimiK2Reasoning
3879
+ ? { mode: "effort", efforts: [Effort.Minimal, Effort.Low, Effort.Medium, Effort.High] }
3880
+ : undefined),
3881
+ };
3882
+ },
3883
+ });
3929
3884
  }
3930
3885
 
3931
3886
  // ---------------------------------------------------------------------------
@@ -5575,7 +5530,14 @@ const OPENCODE_ZEN_API_RESOLUTION = createOpenCodeApiResolution("https://opencod
5575
5530
  // anthropic-style requests to /v1/messages and the gateway would return its
5576
5531
  // `Page Not Found` HTML (issue #887 for the qwen/m2.7 entries; minimax-m3
5577
5532
  // and minimax-m3-free added under #1617 for the same root cause).
5533
+ //
5534
+ // deepseek-v4-flash is the inverse case: it falls through to
5535
+ // openai-completions by default, but the Go gateway's
5536
+ // /zen/go/v1/chat/completions route does not work for this model while
5537
+ // /zen/go/v1/responses does (user-verified against the live gateway,
5538
+ // 2026-08-08; Flash only — deepseek-v4-pro serves fine on chat completions).
5578
5539
  const OPENCODE_GO_API_RESOLUTION = createOpenCodeApiResolution("https://opencode.ai/zen/go", {
5540
+ "deepseek-v4-flash": "openai-responses",
5579
5541
  "minimax-m2.7": "openai-completions",
5580
5542
  "minimax-m3": "openai-completions",
5581
5543
  "minimax-m3-free": "openai-completions",