@oh-my-pi/pi-catalog 17.3.7 → 17.4.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/CHANGELOG.md +36 -0
- package/dist/types/build.d.ts +5 -0
- package/dist/types/discovery/cursor-proto.d.ts +5362 -0
- package/dist/types/discovery/devin-proto.d.ts +1549 -0
- package/dist/types/discovery/index.d.ts +1 -0
- package/dist/types/discovery/protobuf.d.ts +102 -0
- package/dist/types/identity/family.d.ts +23 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/model-thinking.d.ts +6 -2
- package/dist/types/model-tokenizer.d.ts +8 -0
- package/dist/types/provider-models/descriptors.d.ts +1 -0
- package/dist/types/types.d.ts +27 -1
- package/dist/types/variant-collapse.d.ts +2 -0
- package/package.json +5 -6
- package/src/build.ts +7 -0
- package/src/compat/openai.ts +27 -1
- package/src/discovery/codex.ts +118 -24
- package/src/discovery/cursor-proto.ts +8322 -0
- package/src/discovery/cursor.ts +16 -3
- package/src/discovery/devin-proto.ts +2037 -0
- package/src/discovery/devin.ts +4 -3
- package/src/discovery/index.ts +1 -0
- package/src/discovery/protobuf.ts +1073 -0
- package/src/hosts.ts +22 -1
- package/src/identity/family.ts +42 -1
- package/src/index.ts +1 -0
- package/src/model-cache.ts +67 -6
- package/src/model-thinking.ts +38 -6
- package/src/model-tokenizer.ts +75 -0
- package/src/models.json +185055 -2118
- package/src/models.ts +6 -5
- package/src/provider-models/bundled-references.ts +12 -2
- package/src/provider-models/cache-provider-id.ts +3 -1
- package/src/provider-models/descriptors.ts +1 -0
- package/src/provider-models/openai-compat.ts +194 -44
- package/src/types.ts +36 -0
- package/src/variant-collapse.ts +67 -34
- package/dist/types/discovery/cursor-gen/agent_pb.d.ts +0 -16769
- package/dist/types/discovery/devin-gen/buf/validate/validate_pb.d.ts +0 -1715
- package/dist/types/discovery/devin-gen/exa/analytics_pb/analytics_pb.d.ts +0 -693
- package/dist/types/discovery/devin-gen/exa/api_server_pb/api_server_pb.d.ts +0 -9158
- package/dist/types/discovery/devin-gen/exa/auth_pb/auth_pb.d.ts +0 -52
- package/dist/types/discovery/devin-gen/exa/auto_cascade_common_pb/auto_cascade_common_pb.d.ts +0 -276
- package/dist/types/discovery/devin-gen/exa/bug_checker_pb/bug_checker_pb.d.ts +0 -78
- package/dist/types/discovery/devin-gen/exa/cascade_plugins_pb/cascade_plugins_pb.d.ts +0 -999
- package/dist/types/discovery/devin-gen/exa/chat_pb/chat_pb.d.ts +0 -1704
- package/dist/types/discovery/devin-gen/exa/code_edit/code_edit_pb/code_edit_pb.d.ts +0 -656
- package/dist/types/discovery/devin-gen/exa/codeium_common_pb/codeium_common_pb.d.ts +0 -15014
- package/dist/types/discovery/devin-gen/exa/context_module_pb/context_module_pb.d.ts +0 -607
- package/dist/types/discovery/devin-gen/exa/cortex_pb/cortex_pb.d.ts +0 -11830
- package/dist/types/discovery/devin-gen/exa/diff_action_pb/diff_action_pb.d.ts +0 -248
- package/dist/types/discovery/devin-gen/exa/index_pb/index_pb.d.ts +0 -1747
- package/dist/types/discovery/devin-gen/exa/knowledge_base_pb/knowledge_base_pb.d.ts +0 -509
- package/dist/types/discovery/devin-gen/exa/language_server_pb/language_server_pb.d.ts +0 -9048
- package/dist/types/discovery/devin-gen/exa/opensearch_clients_pb/opensearch_clients_pb.d.ts +0 -1760
- package/dist/types/discovery/devin-gen/exa/prompt_pb/prompt_pb.d.ts +0 -286
- package/dist/types/discovery/devin-gen/exa/reactive_component_pb/reactive_component_pb.d.ts +0 -405
- package/dist/types/discovery/devin-gen/exa/trust_pb/trust_pb.d.ts +0 -582
- package/src/discovery/cursor-gen/agent_pb.ts +0 -19513
- package/src/discovery/devin-gen/buf/validate/validate_pb.ts +0 -1862
- package/src/discovery/devin-gen/exa/analytics_pb/analytics_pb.ts +0 -871
- package/src/discovery/devin-gen/exa/api_server_pb/api_server_pb.ts +0 -11083
- package/src/discovery/devin-gen/exa/auth_pb/auth_pb.ts +0 -71
- package/src/discovery/devin-gen/exa/auto_cascade_common_pb/auto_cascade_common_pb.ts +0 -348
- package/src/discovery/devin-gen/exa/bug_checker_pb/bug_checker_pb.ts +0 -103
- package/src/discovery/devin-gen/exa/cascade_plugins_pb/cascade_plugins_pb.ts +0 -1198
- package/src/discovery/devin-gen/exa/chat_pb/chat_pb.ts +0 -2063
- package/src/discovery/devin-gen/exa/code_edit/code_edit_pb/code_edit_pb.ts +0 -810
- package/src/discovery/devin-gen/exa/codeium_common_pb/codeium_common_pb.ts +0 -18354
- package/src/discovery/devin-gen/exa/context_module_pb/context_module_pb.ts +0 -732
- package/src/discovery/devin-gen/exa/cortex_pb/cortex_pb.ts +0 -14277
- package/src/discovery/devin-gen/exa/diff_action_pb/diff_action_pb.ts +0 -312
- package/src/discovery/devin-gen/exa/index_pb/index_pb.ts +0 -2106
- package/src/discovery/devin-gen/exa/knowledge_base_pb/knowledge_base_pb.ts +0 -623
- package/src/discovery/devin-gen/exa/language_server_pb/language_server_pb.ts +0 -10918
- package/src/discovery/devin-gen/exa/opensearch_clients_pb/opensearch_clients_pb.ts +0 -2125
- package/src/discovery/devin-gen/exa/prompt_pb/prompt_pb.ts +0 -361
- package/src/discovery/devin-gen/exa/reactive_component_pb/reactive_component_pb.ts +0 -450
- package/src/discovery/devin-gen/exa/trust_pb/trust_pb.ts +0 -712
package/src/models.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { buildModel } from "./build";
|
|
2
1
|
import MODELS from "./models.json" with { type: "json" };
|
|
3
|
-
import type { Api, KnownProvider, Model,
|
|
2
|
+
import type { Api, KnownProvider, Model, TokenCost, Usage } from "./types";
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Static bundled model registry loaded from `models.json`.
|
|
@@ -12,7 +11,7 @@ import type { Api, KnownProvider, Model, ModelSpec, TokenCost, Usage } from "./t
|
|
|
12
11
|
*/
|
|
13
12
|
const modelRegistry = new Map<string, Map<string, Model<Api>>>();
|
|
14
13
|
|
|
15
|
-
/**
|
|
14
|
+
/** Return one provider's bundled models, materialized by the generator. */
|
|
16
15
|
function getProviderModels(provider: string): Map<string, Model<Api>> | undefined {
|
|
17
16
|
const cachedModels = modelRegistry.get(provider);
|
|
18
17
|
if (cachedModels !== undefined) return cachedModels;
|
|
@@ -20,8 +19,10 @@ function getProviderModels(provider: string): Map<string, Model<Api>> | undefine
|
|
|
20
19
|
|
|
21
20
|
const providerModels = new Map<string, Model<Api>>();
|
|
22
21
|
const rawModels = MODELS[provider as keyof typeof MODELS];
|
|
23
|
-
for (const
|
|
24
|
-
|
|
22
|
+
for (const id in rawModels) {
|
|
23
|
+
// models.json rows are complete Models emitted by generate-models.ts;
|
|
24
|
+
// consuming them verbatim keeps startup allocation-free.
|
|
25
|
+
providerModels.set(id, rawModels[id as keyof typeof rawModels] as unknown as Model<Api>);
|
|
25
26
|
}
|
|
26
27
|
modelRegistry.set(provider, providerModels);
|
|
27
28
|
return providerModels;
|
|
@@ -9,8 +9,18 @@ import type { Api, Model, ModelSpec } from "../types";
|
|
|
9
9
|
* manager, which rebuilds via `buildModel`.
|
|
10
10
|
*/
|
|
11
11
|
export function toModelSpec<TApi extends Api>(model: Model<TApi>): ModelSpec<TApi> {
|
|
12
|
-
const {
|
|
13
|
-
|
|
12
|
+
const {
|
|
13
|
+
compat: _compat,
|
|
14
|
+
compatConfig,
|
|
15
|
+
supportsComputerUse: _derivedComputerUse,
|
|
16
|
+
supportsComputerUseConfig,
|
|
17
|
+
...rest
|
|
18
|
+
} = model;
|
|
19
|
+
return {
|
|
20
|
+
...rest,
|
|
21
|
+
...(supportsComputerUseConfig !== undefined ? { supportsComputerUse: supportsComputerUseConfig } : {}),
|
|
22
|
+
compat: compatConfig,
|
|
23
|
+
} as ModelSpec<TApi>;
|
|
14
24
|
}
|
|
15
25
|
|
|
16
26
|
export function createBundledReferenceMap<TApi extends Api>(
|
|
@@ -73,8 +73,10 @@ export function resolveModelCacheProviderId(providerId: string, options: ModelCa
|
|
|
73
73
|
case "openrouter":
|
|
74
74
|
return "openrouter:pseudo-api";
|
|
75
75
|
case "vllm": {
|
|
76
|
+
// v2: qwen3.8 rows cached before the reasoning/template-effort upgrade
|
|
77
|
+
// carry `reasoning: false` and must be refetched.
|
|
76
78
|
const baseUrl = options.baseUrl ?? getDefaultModelDiscoveryBaseUrl(providerId)!;
|
|
77
|
-
return `vllm:${Bun.hash(baseUrl).toString(36)}`;
|
|
79
|
+
return `vllm:models-v2:${Bun.hash(baseUrl).toString(36)}`;
|
|
78
80
|
}
|
|
79
81
|
default:
|
|
80
82
|
return providerId;
|
|
@@ -474,6 +474,7 @@ export const CATALOG_PROVIDERS = [
|
|
|
474
474
|
defaultModel: "openai/gpt-oss-120b",
|
|
475
475
|
envVars: ["COREWEAVE_API_KEY", "WANDB_API_KEY"],
|
|
476
476
|
createModelManagerOptions: (config: ModelManagerConfig) => coreWeaveModelManagerOptions(config),
|
|
477
|
+
dynamicModelsAuthoritative: true,
|
|
477
478
|
catalogDiscovery: { label: "CoreWeave Serverless Inference" },
|
|
478
479
|
},
|
|
479
480
|
{
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
isGrokReasoningEffortCapable,
|
|
17
17
|
isKimiK3ModelId,
|
|
18
18
|
isKimiModelId,
|
|
19
|
+
isQwen38PlusTemplateEffortModelId,
|
|
19
20
|
isReasoningGlmModelId,
|
|
20
21
|
} from "../identity/family";
|
|
21
22
|
import { resolveModelReference } from "../identity/reference";
|
|
@@ -1073,10 +1074,61 @@ export interface GmiCloudModelManagerConfig {
|
|
|
1073
1074
|
fetch?: FetchImpl;
|
|
1074
1075
|
}
|
|
1075
1076
|
|
|
1077
|
+
/**
|
|
1078
|
+
* Map a discovered GMI Cloud model to a full spec.
|
|
1079
|
+
*
|
|
1080
|
+
* GMI's `/v1/models` returns only bare `{id}` rows, so discovery defaults carry
|
|
1081
|
+
* no limits, reasoning, or thinking metadata. When a gmi-cloud bundled
|
|
1082
|
+
* reference exists (the seeded default) it supplies GMI's published tariff and
|
|
1083
|
+
* limits directly. Every other id is an open-weight model GMI resells under its
|
|
1084
|
+
* canonical id (`deepseek-ai/…`, `moonshotai/…`, `zai-org/…`, `Qwen/…`), so its
|
|
1085
|
+
* intrinsic capabilities — context window, output limit, reasoning, thinking
|
|
1086
|
+
* ladder — are recovered from any bundled upstream entry via the canonical
|
|
1087
|
+
* reference index. Pricing is deliberately never borrowed across providers:
|
|
1088
|
+
* GMI's per-model tariff is unknown for these ids, so cost stays zeroed rather
|
|
1089
|
+
* than inheriting another provider's rate.
|
|
1090
|
+
*/
|
|
1091
|
+
function mapGmiCloudModel(
|
|
1092
|
+
entry: OpenAICompatibleModelRecord,
|
|
1093
|
+
defaults: ModelSpec<"openai-completions">,
|
|
1094
|
+
reference: ModelSpec<"openai-completions"> | undefined,
|
|
1095
|
+
): ModelSpec<"openai-completions"> {
|
|
1096
|
+
if (reference) {
|
|
1097
|
+
return mapWithBundledReference(entry, defaults, reference);
|
|
1098
|
+
}
|
|
1099
|
+
const canonical = resolveModelReference(defaults.id, getBundledModelReferenceIndex()) as
|
|
1100
|
+
| ModelSpec<"openai-completions">
|
|
1101
|
+
| undefined;
|
|
1102
|
+
if (!canonical) {
|
|
1103
|
+
return { ...defaults, name: toModelName(entry.name, defaults.name) };
|
|
1104
|
+
}
|
|
1105
|
+
const contextWindow = canonical.contextWindow ?? defaults.contextWindow;
|
|
1106
|
+
const maxTokens =
|
|
1107
|
+
canonical.maxTokens != null && contextWindow != null
|
|
1108
|
+
? Math.min(canonical.maxTokens, contextWindow)
|
|
1109
|
+
: (canonical.maxTokens ?? defaults.maxTokens);
|
|
1110
|
+
return {
|
|
1111
|
+
...defaults,
|
|
1112
|
+
name: toModelName(entry.name, canonical.name ?? defaults.name),
|
|
1113
|
+
reasoning: canonical.reasoning,
|
|
1114
|
+
input: canonical.input,
|
|
1115
|
+
...(canonical.thinking && { thinking: canonical.thinking }),
|
|
1116
|
+
contextWindow,
|
|
1117
|
+
maxTokens,
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1076
1121
|
export function gmiCloudModelManagerOptions(
|
|
1077
1122
|
config?: GmiCloudModelManagerConfig,
|
|
1078
1123
|
): ModelManagerOptions<"openai-completions"> {
|
|
1079
|
-
return
|
|
1124
|
+
return createOpenAICompatibleModelManagerOptions({
|
|
1125
|
+
api: "openai-completions",
|
|
1126
|
+
providerId: "gmi-cloud",
|
|
1127
|
+
defaultBaseUrl: GMI_CLOUD_BASE_URL,
|
|
1128
|
+
config,
|
|
1129
|
+
requireApiKey: true,
|
|
1130
|
+
mapModel: mapGmiCloudModel,
|
|
1131
|
+
});
|
|
1080
1132
|
}
|
|
1081
1133
|
|
|
1082
1134
|
// ---------------------------------------------------------------------------
|
|
@@ -2439,6 +2491,73 @@ function openCodeBaseUrlForApi(api: Api, basePath: string): string {
|
|
|
2439
2491
|
return api === "anthropic-messages" ? basePath : `${basePath}/v1`;
|
|
2440
2492
|
}
|
|
2441
2493
|
|
|
2494
|
+
// Per-id API pins correcting upstream metadata mismatches on the OpenCode
|
|
2495
|
+
// gateways. Applied in two places: the models.dev resolver rules
|
|
2496
|
+
// (OPENCODE_ZEN_API_RESOLUTION / OPENCODE_GO_API_RESOLUTION) and the live
|
|
2497
|
+
// /v1/models discovery mapper in openCodeModelManagerOptions — the gateways
|
|
2498
|
+
// list ids that models.dev omits entirely (muse-spark-1.2[-contributor] on
|
|
2499
|
+
// opencode-go, #8957), so discovery cannot rely on bundled references alone.
|
|
2500
|
+
//
|
|
2501
|
+
// OpenCode Zen: models.dev declares minimax-m3-free (and forward-compat
|
|
2502
|
+
// minimax-m3) with `provider.npm = "@ai-sdk/anthropic"`, but the Zen gateway
|
|
2503
|
+
// only serves them at https://opencode.ai/zen/v1/chat/completions (verified
|
|
2504
|
+
// against the live /v1/models response — minimax-m3-free is listed there, and
|
|
2505
|
+
// the gateway has no /v1/messages route for it). Without this override the
|
|
2506
|
+
// resolver POSTs anthropic-shaped requests to /v1/messages and the UI surfaces
|
|
2507
|
+
// raw <invoke>/<|minimax|>/<tool_call> markup (#1617).
|
|
2508
|
+
const OPENCODE_ZEN_API_ID_OVERRIDES: Readonly<Record<string, Api>> = {
|
|
2509
|
+
"minimax-m3": "openai-completions",
|
|
2510
|
+
"minimax-m3-free": "openai-completions",
|
|
2511
|
+
};
|
|
2512
|
+
// OpenCode Go: models.dev declares minimax-m2.7 / qwen3.5-plus / qwen3.6-plus
|
|
2513
|
+
// (and now also minimax-m3) with `provider.npm = "@ai-sdk/anthropic"`, but
|
|
2514
|
+
// the OpenCode Go gateway only serves them at
|
|
2515
|
+
// `https://opencode.ai/zen/go/v1/chat/completions` (verified against
|
|
2516
|
+
// https://opencode.ai/zen/go/v1/models and the upstream endpoint table at
|
|
2517
|
+
// https://opencode.ai/docs/go/#endpoints — minimax-m2.5 works the same way
|
|
2518
|
+
// and lacks an `npm` field on models.dev so it already falls through to the
|
|
2519
|
+
// openai-completions default). Without this override the resolver would POST
|
|
2520
|
+
// anthropic-style requests to /v1/messages and the gateway would return its
|
|
2521
|
+
// `Page Not Found` HTML (issue #887 for the qwen/m2.7 entries; minimax-m3
|
|
2522
|
+
// and minimax-m3-free added under #1617 for the same root cause).
|
|
2523
|
+
//
|
|
2524
|
+
// deepseek-v4-flash is the inverse case: it falls through to
|
|
2525
|
+
// openai-completions by default, but the Go gateway's
|
|
2526
|
+
// /zen/go/v1/chat/completions route does not work for this model while
|
|
2527
|
+
// /zen/go/v1/responses does (user-verified against the live gateway,
|
|
2528
|
+
// 2026-08-08; Flash only — deepseek-v4-pro serves fine on chat completions).
|
|
2529
|
+
//
|
|
2530
|
+
// muse-spark-1.2 / muse-spark-1.2-contributor are the same inverse case, but
|
|
2531
|
+
// worse: models.dev does not list them under opencode-go at all, so they have
|
|
2532
|
+
// no bundled reference and only exist via live gateway discovery. Without the
|
|
2533
|
+
// discovery-side pin they default to openai-completions even though the
|
|
2534
|
+
// gateway only serves them at /zen/go/v1/responses (@ai-sdk/openai per
|
|
2535
|
+
// https://opencode.ai/docs/go/#endpoints). The completions parser then closes
|
|
2536
|
+
// the stream with no finish_reason on every tool-call turn (#8957).
|
|
2537
|
+
const OPENCODE_GO_API_ID_OVERRIDES: Readonly<Record<string, Api>> = {
|
|
2538
|
+
"deepseek-v4-flash": "openai-responses",
|
|
2539
|
+
"muse-spark-1.2": "openai-responses",
|
|
2540
|
+
"muse-spark-1.2-contributor": "openai-responses",
|
|
2541
|
+
"minimax-m2.7": "openai-completions",
|
|
2542
|
+
"minimax-m3": "openai-completions",
|
|
2543
|
+
"minimax-m3-free": "openai-completions",
|
|
2544
|
+
"qwen3.5-plus": "openai-completions",
|
|
2545
|
+
"qwen3.6-plus": "openai-completions",
|
|
2546
|
+
};
|
|
2547
|
+
|
|
2548
|
+
// Billing-variant suffixes the OpenCode gateways append to a base model id
|
|
2549
|
+
// without changing its transport (`deepseek-v4-flash-free`,
|
|
2550
|
+
// `muse-spark-1.2-contributor`).
|
|
2551
|
+
const OPENCODE_VARIANT_SUFFIXES = ["-contributor", "-free"] as const;
|
|
2552
|
+
|
|
2553
|
+
/** Strips a billing-variant suffix; null when `id` is not a variant. */
|
|
2554
|
+
function openCodeBaseModelId(id: string): string | null {
|
|
2555
|
+
for (const suffix of OPENCODE_VARIANT_SUFFIXES) {
|
|
2556
|
+
if (id.endsWith(suffix) && id.length > suffix.length) return id.slice(0, -suffix.length);
|
|
2557
|
+
}
|
|
2558
|
+
return null;
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2442
2561
|
function openCodeModelManagerOptions(
|
|
2443
2562
|
providerId: "opencode-go" | "opencode-zen",
|
|
2444
2563
|
config?: OpenCodeModelManagerConfig,
|
|
@@ -2449,10 +2568,38 @@ function openCodeModelManagerOptions(
|
|
|
2449
2568
|
const basePath = normalizeOpenCodeBasePath(config?.baseUrl, defaultBasePath);
|
|
2450
2569
|
const discoveryBaseUrl = openCodeBaseUrlForApi("openai-completions", basePath);
|
|
2451
2570
|
const references = createBundledReferenceMap<Api>(providerId);
|
|
2571
|
+
// Both gateways share one operator with identical endpoint semantics, so
|
|
2572
|
+
// the sibling's bundled catalog is a routing hint for ids models.dev has
|
|
2573
|
+
// not picked up under this gateway yet.
|
|
2574
|
+
const siblingReferences = createBundledReferenceMap<Api>(
|
|
2575
|
+
providerId === "opencode-go" ? "opencode-zen" : "opencode-go",
|
|
2576
|
+
);
|
|
2577
|
+
const apiOverrides = providerId === "opencode-go" ? OPENCODE_GO_API_ID_OVERRIDES : OPENCODE_ZEN_API_ID_OVERRIDES;
|
|
2578
|
+
// Routes a discovered id with no same-provider metadata. models.dev lags
|
|
2579
|
+
// the gateway (muse-spark-1.2[-contributor] shipped gateway-first, #8957),
|
|
2580
|
+
// so borrow the openai-responses route from the sibling gateway or the
|
|
2581
|
+
// billing-variant base id. Responses ONLY: openai-completions is already
|
|
2582
|
+
// the default, and anthropic-messages transports genuinely diverge across
|
|
2583
|
+
// gateways (e.g. minimax-m2.5), so borrowing them would import upstream
|
|
2584
|
+
// metadata noise as hard routing errors.
|
|
2585
|
+
const fallbackApi = (id: string, base: string | null): Api | undefined => {
|
|
2586
|
+
const hints = [
|
|
2587
|
+
siblingReferences.get(id)?.api,
|
|
2588
|
+
base ? references.get(base)?.api : undefined,
|
|
2589
|
+
base ? siblingReferences.get(base)?.api : undefined,
|
|
2590
|
+
];
|
|
2591
|
+
return hints.includes("openai-responses") ? "openai-responses" : undefined;
|
|
2592
|
+
};
|
|
2452
2593
|
return {
|
|
2453
2594
|
providerId,
|
|
2454
2595
|
cacheProviderId: resolveModelCacheProviderId(providerId, { apiKey, baseUrl: discoveryBaseUrl }),
|
|
2455
2596
|
dynamicModelsAuthoritative: true,
|
|
2597
|
+
// The per-id API pins are cache identity: without this, rows cached
|
|
2598
|
+
// before a pin was added keep the wrong endpoint until TTL expiry
|
|
2599
|
+
// (#8957 — 17.3.7 caches held muse-spark-1.2[-contributor] on chat
|
|
2600
|
+
// completions after the pin shipped). Sibling-catalog drift is bounded
|
|
2601
|
+
// by the 2h cache TTL instead.
|
|
2602
|
+
dropCachedModelIdsOnStaticMismatch: Object.keys(apiOverrides),
|
|
2456
2603
|
...(apiKey && {
|
|
2457
2604
|
fetchDynamicModels: () =>
|
|
2458
2605
|
fetchOpenAICompatibleModels<Api>({
|
|
@@ -2463,17 +2610,26 @@ function openCodeModelManagerOptions(
|
|
|
2463
2610
|
mapModel: (entry, defaults) => {
|
|
2464
2611
|
const reference = references.get(defaults.id);
|
|
2465
2612
|
const name = toModelName(entry.name, reference?.name ?? defaults.name);
|
|
2613
|
+
const base = openCodeBaseModelId(defaults.id);
|
|
2614
|
+
// Pins win over bundled references (stale bundled routes
|
|
2615
|
+
// must not stick), and a base-id pin covers its billing
|
|
2616
|
+
// variants; the responses fallback covers gateway-first ids.
|
|
2617
|
+
const api =
|
|
2618
|
+
apiOverrides[defaults.id] ??
|
|
2619
|
+
(base ? apiOverrides[base] : undefined) ??
|
|
2620
|
+
reference?.api ??
|
|
2621
|
+
fallbackApi(defaults.id, base) ??
|
|
2622
|
+
defaults.api;
|
|
2623
|
+
const baseUrl = openCodeBaseUrlForApi(api, basePath);
|
|
2466
2624
|
if (!reference) {
|
|
2467
|
-
return {
|
|
2468
|
-
...defaults,
|
|
2469
|
-
name,
|
|
2470
|
-
};
|
|
2625
|
+
return { ...defaults, name, api, baseUrl };
|
|
2471
2626
|
}
|
|
2472
2627
|
return {
|
|
2473
2628
|
...reference,
|
|
2474
2629
|
id: defaults.id,
|
|
2475
2630
|
name,
|
|
2476
|
-
|
|
2631
|
+
api,
|
|
2632
|
+
baseUrl,
|
|
2477
2633
|
contextWindow: toPositiveNumber(entry.context_length, reference.contextWindow),
|
|
2478
2634
|
maxTokens: toPositiveNumber(entry.max_completion_tokens, reference.maxTokens),
|
|
2479
2635
|
};
|
|
@@ -2980,6 +3136,10 @@ export const ALIBABA_TOKEN_PLAN_DISCOVERED_MODEL_LIMITS: Readonly<Record<string,
|
|
|
2980
3136
|
contextWindow: 1_000_000,
|
|
2981
3137
|
maxTokens: 384_000,
|
|
2982
3138
|
},
|
|
3139
|
+
"deepseek-v4-pro-0813": {
|
|
3140
|
+
contextWindow: 1_000_000,
|
|
3141
|
+
maxTokens: 384_000,
|
|
3142
|
+
},
|
|
2983
3143
|
"deepseek-v3.2": {
|
|
2984
3144
|
contextWindow: 131_072,
|
|
2985
3145
|
maxTokens: 65_536,
|
|
@@ -4994,6 +5154,11 @@ export function vllmModelManagerOptions(config?: VllmModelManagerConfig): ModelM
|
|
|
4994
5154
|
return {
|
|
4995
5155
|
...model,
|
|
4996
5156
|
contextWindow: toPositiveNumber(entry.max_model_len, model.contextWindow),
|
|
5157
|
+
// vLLM's /v1/models reports no reasoning capability. Qwen 3.8+
|
|
5158
|
+
// open weights always think (the template cannot disable it), so
|
|
5159
|
+
// light up the effort dial; buildModel derives the template
|
|
5160
|
+
// ladder from the id + local-backend compat.
|
|
5161
|
+
reasoning: model.reasoning || isQwen38PlusTemplateEffortModelId(model.id),
|
|
4997
5162
|
};
|
|
4998
5163
|
},
|
|
4999
5164
|
fetch: config?.fetch,
|
|
@@ -5071,8 +5236,18 @@ export interface GithubCopilotModelManagerConfig {
|
|
|
5071
5236
|
|
|
5072
5237
|
const COPILOT_ANTHROPIC_MODEL_PATTERN = /^claude-(haiku|sonnet|opus|fable|mythos)-\d/;
|
|
5073
5238
|
const isCopilotResponsesModelId = (modelId: string): boolean =>
|
|
5074
|
-
modelId === "grok-4.5" ||
|
|
5075
|
-
|
|
5239
|
+
modelId === "grok-4.5" ||
|
|
5240
|
+
modelId === "grok-4.6" ||
|
|
5241
|
+
modelId.startsWith("gpt-5") ||
|
|
5242
|
+
modelId.startsWith("oswe") ||
|
|
5243
|
+
modelId.startsWith("mai-");
|
|
5244
|
+
const COPILOT_CACHE_INVALIDATED_MODEL_IDS = [
|
|
5245
|
+
"grok-4.5",
|
|
5246
|
+
"grok-4.5-1m",
|
|
5247
|
+
"grok-4.6",
|
|
5248
|
+
"grok-4.6-1m",
|
|
5249
|
+
"mai-code-1-flash-picker",
|
|
5250
|
+
];
|
|
5076
5251
|
|
|
5077
5252
|
function inferCopilotApi(modelId: string): Api {
|
|
5078
5253
|
if (COPILOT_ANTHROPIC_MODEL_PATTERN.test(modelId)) {
|
|
@@ -5677,42 +5852,17 @@ function createOpenCodeApiResolution(
|
|
|
5677
5852
|
};
|
|
5678
5853
|
}
|
|
5679
5854
|
|
|
5680
|
-
//
|
|
5681
|
-
//
|
|
5682
|
-
//
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
const
|
|
5688
|
-
"
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
// OpenCode Go: models.dev declares minimax-m2.7 / qwen3.5-plus / qwen3.6-plus
|
|
5692
|
-
// (and now also minimax-m3) with `provider.npm = "@ai-sdk/anthropic"`, but
|
|
5693
|
-
// the OpenCode Go gateway only serves them at
|
|
5694
|
-
// `https://opencode.ai/zen/go/v1/chat/completions` (verified against
|
|
5695
|
-
// https://opencode.ai/zen/go/v1/models and the upstream endpoint table at
|
|
5696
|
-
// https://opencode.ai/docs/go/#endpoints — minimax-m2.5 works the same way
|
|
5697
|
-
// and lacks an `npm` field on models.dev so it already falls through to the
|
|
5698
|
-
// openai-completions default). Without this override the resolver would POST
|
|
5699
|
-
// anthropic-style requests to /v1/messages and the gateway would return its
|
|
5700
|
-
// `Page Not Found` HTML (issue #887 for the qwen/m2.7 entries; minimax-m3
|
|
5701
|
-
// and minimax-m3-free added under #1617 for the same root cause).
|
|
5702
|
-
//
|
|
5703
|
-
// deepseek-v4-flash is the inverse case: it falls through to
|
|
5704
|
-
// openai-completions by default, but the Go gateway's
|
|
5705
|
-
// /zen/go/v1/chat/completions route does not work for this model while
|
|
5706
|
-
// /zen/go/v1/responses does (user-verified against the live gateway,
|
|
5707
|
-
// 2026-08-08; Flash only — deepseek-v4-pro serves fine on chat completions).
|
|
5708
|
-
const OPENCODE_GO_API_RESOLUTION = createOpenCodeApiResolution("https://opencode.ai/zen/go", {
|
|
5709
|
-
"deepseek-v4-flash": "openai-responses",
|
|
5710
|
-
"minimax-m2.7": "openai-completions",
|
|
5711
|
-
"minimax-m3": "openai-completions",
|
|
5712
|
-
"minimax-m3-free": "openai-completions",
|
|
5713
|
-
"qwen3.5-plus": "openai-completions",
|
|
5714
|
-
"qwen3.6-plus": "openai-completions",
|
|
5715
|
-
});
|
|
5855
|
+
// Resolver rules for the models.dev descriptor path; the per-id pins live in
|
|
5856
|
+
// OPENCODE_ZEN_API_ID_OVERRIDES / OPENCODE_GO_API_ID_OVERRIDES (section 8),
|
|
5857
|
+
// which also drive the live-discovery mapper.
|
|
5858
|
+
const OPENCODE_ZEN_API_RESOLUTION = createOpenCodeApiResolution(
|
|
5859
|
+
"https://opencode.ai/zen",
|
|
5860
|
+
OPENCODE_ZEN_API_ID_OVERRIDES,
|
|
5861
|
+
);
|
|
5862
|
+
const OPENCODE_GO_API_RESOLUTION = createOpenCodeApiResolution(
|
|
5863
|
+
"https://opencode.ai/zen/go",
|
|
5864
|
+
OPENCODE_GO_API_ID_OVERRIDES,
|
|
5865
|
+
);
|
|
5716
5866
|
|
|
5717
5867
|
const COPILOT_BASE_URL = "https://api.githubcopilot.com";
|
|
5718
5868
|
|
package/src/types.ts
CHANGED
|
@@ -259,6 +259,16 @@ export interface OpenAICompat {
|
|
|
259
259
|
* Non-Qwen templates ignore the flag, so the auto-detection is safe.
|
|
260
260
|
*/
|
|
261
261
|
qwenPreserveThinking?: boolean;
|
|
262
|
+
/**
|
|
263
|
+
* Route the requested thinking effort onto the Qwen 3.8+ chat template's
|
|
264
|
+
* `reasoning_effort` kwarg (`low`/`medium`/`xhigh`; template default
|
|
265
|
+
* `xhigh`). Emitted inside `chat_template_kwargs` for both Qwen dialects
|
|
266
|
+
* (plus the top-level field on the `qwen` dialect, which newer llama.cpp
|
|
267
|
+
* builds map natively). Without it the qwen dialects only toggle
|
|
268
|
+
* `enable_thinking` and the template always thinks at its `xhigh` default.
|
|
269
|
+
* Default: auto-detected (Qwen 3.8+ id on a local llama.cpp-style backend).
|
|
270
|
+
*/
|
|
271
|
+
qwenTemplateReasoningEffort?: boolean;
|
|
262
272
|
/** Whether assistant tool-call messages must include non-empty content. Default: false. */
|
|
263
273
|
requiresAssistantContentForToolCalls?: boolean;
|
|
264
274
|
/** Whether the provider supports the `tool_choice` parameter. Default: true. */
|
|
@@ -604,6 +614,7 @@ export interface ResolvedOpenAISharedCompat {
|
|
|
604
614
|
allowsSyntheticReasoningContentForToolCalls: boolean;
|
|
605
615
|
replayReasoningContent: boolean;
|
|
606
616
|
qwenPreserveThinking: boolean;
|
|
617
|
+
qwenTemplateReasoningEffort: boolean;
|
|
607
618
|
requiresThinkingAsText: boolean;
|
|
608
619
|
requiresMistralToolIds: boolean;
|
|
609
620
|
requiresToolResultName: boolean;
|
|
@@ -669,6 +680,7 @@ export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat &
|
|
|
669
680
|
| "allowsSyntheticReasoningContentForToolCalls"
|
|
670
681
|
| "replayReasoningContent"
|
|
671
682
|
| "qwenPreserveThinking"
|
|
683
|
+
| "qwenTemplateReasoningEffort"
|
|
672
684
|
| "requiresThinkingAsText"
|
|
673
685
|
| "requiresMistralToolIds"
|
|
674
686
|
| "requiresToolResultName"
|
|
@@ -847,6 +859,24 @@ export interface ModelCost extends TokenCost {
|
|
|
847
859
|
longContext?: LongContextTokenCost;
|
|
848
860
|
}
|
|
849
861
|
|
|
862
|
+
/**
|
|
863
|
+
* Exact local content tokenizer family for a model.
|
|
864
|
+
*
|
|
865
|
+
* Absent means no first-party local tokenizer is known and consumers retain
|
|
866
|
+
* their estimate/default-tokenizer policy. The values name tokenizer
|
|
867
|
+
* generations rather than providers: DeepSeek V3 through V4 share
|
|
868
|
+
* `"deepseek-v3"`; Kimi K2 through K3 share `"kimi-k2"`.
|
|
869
|
+
*/
|
|
870
|
+
export type ModelTokenizer =
|
|
871
|
+
| "claude-v3"
|
|
872
|
+
| "claude-v47"
|
|
873
|
+
| "claude-v5"
|
|
874
|
+
| "claude-v5-sonnet"
|
|
875
|
+
| "qwen3"
|
|
876
|
+
| "deepseek-v3"
|
|
877
|
+
| "kimi-k2"
|
|
878
|
+
| "glm5";
|
|
879
|
+
|
|
850
880
|
// Model interface for the unified model system
|
|
851
881
|
export interface Model<TApi extends Api = Api> {
|
|
852
882
|
id: string;
|
|
@@ -871,6 +901,12 @@ export interface Model<TApi extends Api = Api> {
|
|
|
871
901
|
provider: Provider;
|
|
872
902
|
baseUrl: string;
|
|
873
903
|
reasoning: boolean;
|
|
904
|
+
/**
|
|
905
|
+
* Exact local tokenizer family resolved from the model identity or supplied
|
|
906
|
+
* explicitly by a catalog/discovery source. Absent leaves local counting to
|
|
907
|
+
* the consumer's fallback policy.
|
|
908
|
+
*/
|
|
909
|
+
tokenizer?: ModelTokenizer;
|
|
874
910
|
input: ("text" | "image")[];
|
|
875
911
|
/**
|
|
876
912
|
* Decoder family used for image inputs when it has narrower format support
|