@sayknow-cli/ai 0.5.2 → 0.5.8
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 +23 -0
- package/dist/types/model-thinking.d.ts +7 -0
- package/dist/types/provider-models/openai-compat.d.ts +10 -0
- package/dist/types/providers/anthropic.d.ts +1 -1
- package/dist/types/types.d.ts +7 -1
- package/dist/types/utils/discovery/openai-compatible.d.ts +10 -0
- package/dist/types/utils/oauth/sglang.d.ts +12 -0
- package/dist/types/utils/oauth/types.d.ts +1 -1
- package/package.json +2 -2
- package/src/auth-storage.ts +32 -6
- package/src/model-thinking.ts +68 -8
- package/src/models.json +12150 -1310
- package/src/provider-models/descriptors.ts +13 -1
- package/src/provider-models/openai-compat.ts +152 -0
- package/src/providers/anthropic.ts +12 -1
- package/src/providers/openai-completions.ts +56 -14
- package/src/stream.ts +15 -21
- package/src/types.ts +9 -1
- package/src/utils/discovery/openai-compatible.ts +106 -2
- package/src/utils/oauth/index.ts +6 -0
- package/src/utils/oauth/sglang.ts +39 -0
- package/src/utils/oauth/types.ts +1 -0
- package/src/utils/overflow.ts +64 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.5.8] - 2026-09-10
|
|
6
|
+
|
|
7
|
+
## [0.5.7] - 2026-09-10
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Bundled `openai-codex/gpt-6-astra` (ported from upstream #5294) so eligible ChatGPT accounts can select GPT-6 Astra without waiting for authenticated Codex discovery. The reviewed snapshot records the 272K prompt budget, 128K output cap, text-and-image input, websocket preference, low-through-max reasoning efforts, freeform `apply_patch`, and standard published pricing ($10/$50, cache read $1, cache write $12.50). Upstream's above-272K pricing tier is intentionally omitted: this fork's cost engine has no long-context tier support, so the field would be dead data. The GPT model-id parser and the generated `apply_patch` policy now recognize the `astra` variant (GPT-6), and the catalog was regenerated, which also picks up the current models.dev snapshot across gateway providers.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Bumped the advertised Claude Code client version from 2.1.219 to 2.1.267. Anthropic gates newer models (e.g. the 5.1 line) on the advertised client version and rejected requests with HTTP 400 `claude_code_version_too_old` ("version 2.1.251 or newer is required"), so those models were unusable through the Claude Code OAuth path.
|
|
16
|
+
|
|
17
|
+
## [0.5.3] - 2026-08-28
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Added first-class oMLX and SGLang OpenAI-compatible local providers. oMLX includes model capability enrichment and macOS profiles; SGLang discovery is credentialless only on normalized loopback origins and supports trusted `SGLANG_BASE_URL`/`SGLANG_API_KEY` configuration.
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Hardened local OpenAI-compatible discovery with bounded catalogs, redirect refusal, canonical loopback URLs, safe oMLX limits, and explicit-only SGLang login; deprecated `sglang-local` credentials no longer shadow real keys.
|
|
25
|
+
|
|
26
|
+
- Anthropic's measured `invalid_request_error` prompt-overflow envelope now triggers context compaction only when its reported token usage actually exceeds the reported maximum, while auth, quota, rate-limit, and unverified prose remain authoritative non-overflow failures.
|
|
27
|
+
|
|
5
28
|
## [0.7.5] - 2026-06-27
|
|
6
29
|
|
|
7
30
|
### Fixed
|
|
@@ -27,6 +27,13 @@ export declare function enrichModelThinking<TApi extends Api>(model: ApiModel<TA
|
|
|
27
27
|
* canonical rules, replacing any existing `thinking`.
|
|
28
28
|
*/
|
|
29
29
|
export declare function refreshModelThinking<TApi extends Api>(model: ApiModel<TApi>): ApiModel<TApi>;
|
|
30
|
+
/**
|
|
31
|
+
* Extract the GLM generation from a Zhipu/ZAI model id: `glm-5.3` and
|
|
32
|
+
* `glm-5.3-flash` -> 5.3, `glm-5` and `glm-5-turbo` -> 5, `glm-4.7` -> 4.7.
|
|
33
|
+
* Returns undefined for ids that are not a plain GLM generation, including the
|
|
34
|
+
* vision line (`glm-5v-turbo`), so those never inherit text-model corrections.
|
|
35
|
+
*/
|
|
36
|
+
export declare function glmGeneration(modelId: string): number | undefined;
|
|
30
37
|
/**
|
|
31
38
|
* Apply upstream metadata corrections to a mutable array of models.
|
|
32
39
|
*
|
|
@@ -153,6 +153,11 @@ export interface LmStudioModelManagerConfig {
|
|
|
153
153
|
baseUrl?: string;
|
|
154
154
|
}
|
|
155
155
|
export declare function lmStudioModelManagerOptions(config?: LmStudioModelManagerConfig): ModelManagerOptions<"openai-completions">;
|
|
156
|
+
export interface OmlxModelManagerConfig {
|
|
157
|
+
apiKey?: string;
|
|
158
|
+
baseUrl?: string;
|
|
159
|
+
}
|
|
160
|
+
export declare function omlxModelManagerOptions(config?: OmlxModelManagerConfig): ModelManagerOptions<"openai-completions">;
|
|
156
161
|
export interface SyntheticModelManagerConfig {
|
|
157
162
|
apiKey?: string;
|
|
158
163
|
baseUrl?: string;
|
|
@@ -210,6 +215,11 @@ export interface VllmModelManagerConfig {
|
|
|
210
215
|
baseUrl?: string;
|
|
211
216
|
}
|
|
212
217
|
export declare function vllmModelManagerOptions(config?: VllmModelManagerConfig): ModelManagerOptions<"openai-completions">;
|
|
218
|
+
export interface SglangModelManagerConfig {
|
|
219
|
+
apiKey?: string;
|
|
220
|
+
baseUrl?: string;
|
|
221
|
+
}
|
|
222
|
+
export declare function sglangModelManagerOptions(config?: SglangModelManagerConfig): ModelManagerOptions<"openai-completions">;
|
|
213
223
|
export interface NanoGptModelManagerConfig {
|
|
214
224
|
apiKey?: string;
|
|
215
225
|
baseUrl?: string;
|
|
@@ -50,7 +50,7 @@ export declare function isAnthropicThinkingBlockMutationError(error: unknown): b
|
|
|
50
50
|
* than only the latest one.
|
|
51
51
|
*/
|
|
52
52
|
export declare function isAnthropicThinkingSignatureInvalidError(error: unknown): boolean;
|
|
53
|
-
export declare const claudeCodeVersion = "2.1.
|
|
53
|
+
export declare const claudeCodeVersion = "2.1.267";
|
|
54
54
|
export declare const claudeCodeEntrypoint = "sdk-cli";
|
|
55
55
|
export declare const claudeToolPrefix: string;
|
|
56
56
|
export declare const claudeCodeSystemInstruction = "You are a Claude agent, built on Anthropic's Claude Agent SDK.";
|
package/dist/types/types.d.ts
CHANGED
|
@@ -51,7 +51,7 @@ export interface ThinkingConfig {
|
|
|
51
51
|
/** Provider-specific transport used to encode the selected effort. */
|
|
52
52
|
mode: ThinkingControlMode;
|
|
53
53
|
}
|
|
54
|
-
export type KnownProvider = "alibaba-token-plan" | "amazon-bedrock" | "azure-openai" | "anthropic" | "google" | "google-gemini-cli" | "google-antigravity" | "google-vertex" | "openai" | "openai-codex" | "kimi-code" | "minimax-code" | "minimax-code-cn" | "github-copilot" | "fireworks" | "firepass" | "fugu" | "gitlab-duo" | "cursor" | "deepseek" | "deepinfra" | "xai" | "groq" | "cerebras" | "openrouter" | "kilo" | "vercel-ai-gateway" | "zai" | "glm-zcode" | "mistral" | "minimax" | "opencode-go" | "opencode-zen" | "opengateway" | "bizrouter" | "synthetic" | "cloudflare-ai-gateway" | "huggingface" | "litellm" | "moonshot" | "nvidia" | "nanogpt" | "ollama" | "ollama-cloud" | "qianfan" | "qwen-portal" | "together" | "venice" | "vllm" | "xiaomi" | "xiaomi-token-plan-sgp" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "zenmux" | "lm-studio";
|
|
54
|
+
export type KnownProvider = "alibaba-token-plan" | "amazon-bedrock" | "azure-openai" | "anthropic" | "google" | "google-gemini-cli" | "google-antigravity" | "google-vertex" | "openai" | "openai-codex" | "kimi-code" | "minimax-code" | "minimax-code-cn" | "github-copilot" | "fireworks" | "firepass" | "fugu" | "gitlab-duo" | "cursor" | "deepseek" | "deepinfra" | "xai" | "groq" | "cerebras" | "openrouter" | "kilo" | "vercel-ai-gateway" | "zai" | "glm-zcode" | "mistral" | "minimax" | "opencode-go" | "opencode-zen" | "opengateway" | "bizrouter" | "synthetic" | "cloudflare-ai-gateway" | "huggingface" | "litellm" | "moonshot" | "nvidia" | "nanogpt" | "ollama" | "ollama-cloud" | "qianfan" | "qwen-portal" | "together" | "venice" | "vllm" | "xiaomi" | "xiaomi-token-plan-sgp" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "zenmux" | "lm-studio" | "omlx" | "sglang";
|
|
55
55
|
export type Provider = KnownProvider | string;
|
|
56
56
|
import type { Effort } from "./model-thinking";
|
|
57
57
|
/** Token budgets for each thinking level (token-based providers only) */
|
|
@@ -355,6 +355,12 @@ export interface ToolCall {
|
|
|
355
355
|
* rejects the call with a retryable error instead.
|
|
356
356
|
*/
|
|
357
357
|
incompleteArguments?: boolean;
|
|
358
|
+
/**
|
|
359
|
+
* Transient raw JSON for a provider-detected `\uXXXX`-escaped non-ASCII
|
|
360
|
+
* tool payload. The agent loop validates and removes it before persistence.
|
|
361
|
+
*/
|
|
362
|
+
escapedNonAsciiArguments?: boolean;
|
|
363
|
+
escapedNonAsciiArgumentsRaw?: string;
|
|
358
364
|
}
|
|
359
365
|
export interface Usage {
|
|
360
366
|
/** Non-cached input tokens (matches the bucket the provider bills as new input). */
|
|
@@ -72,3 +72,13 @@ export interface FetchOpenAICompatibleModelsOptions<TApi extends Api> {
|
|
|
72
72
|
* Returns `[]` only when the endpoint responds successfully with no usable models.
|
|
73
73
|
*/
|
|
74
74
|
export declare function fetchOpenAICompatibleModels<TApi extends Api>(options: FetchOpenAICompatibleModelsOptions<TApi>): Promise<Model<TApi>[] | null>;
|
|
75
|
+
/**
|
|
76
|
+
* Returns a canonical HTTP(S) OpenAI-compatible base URL without embedded URL
|
|
77
|
+
* credentials, query parameters, or fragments.
|
|
78
|
+
*/
|
|
79
|
+
export declare function resolveCanonicalOpenAIBaseUrl(value: string | undefined): string | undefined;
|
|
80
|
+
/**
|
|
81
|
+
* Returns a local OpenAI-compatible base URL only when it is an HTTP(S)
|
|
82
|
+
* loopback endpoint; otherwise returns the trusted fallback.
|
|
83
|
+
*/
|
|
84
|
+
export declare function resolveLoopbackOpenAIBaseUrl(value: string | undefined, fallback: string): string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SGLang login flow.
|
|
3
|
+
*
|
|
4
|
+
* SGLang commonly exposes an OpenAI-compatible API on a local server. It may
|
|
5
|
+
* require a bearer token, but local servers commonly allow unauthenticated
|
|
6
|
+
* access. This flow stores an API-key-style credential for auth storage.
|
|
7
|
+
*/
|
|
8
|
+
import type { OAuthController } from "./types";
|
|
9
|
+
/**
|
|
10
|
+
* Login to SGLang with an explicit bearer token.
|
|
11
|
+
*/
|
|
12
|
+
export declare function loginSglang(options: OAuthController): Promise<string>;
|
|
@@ -7,7 +7,7 @@ export type OAuthCredentials = {
|
|
|
7
7
|
email?: string;
|
|
8
8
|
accountId?: string;
|
|
9
9
|
};
|
|
10
|
-
export type OAuthProvider = "alibaba-token-plan" | "anthropic" | "bizrouter" | "cerebras" | "cloudflare-ai-gateway" | "cursor" | "deepseek" | "deepinfra" | "fireworks" | "firepass" | "fugu" | "github-copilot" | "google-gemini-cli" | "google-antigravity" | "gitlab-duo" | "huggingface" | "kimi-code" | "kilo" | "kagi" | "litellm" | "lm-studio" | "minimax-code" | "minimax-code-cn" | "moonshot" | "nvidia" | "nanogpt" | "ollama" | "ollama-cloud" | "openai-codex" | "openai-codex-device" | "opencode-go" | "opencode-zen" | "opengateway" | "parallel" | "perplexity" | "qianfan" | "qwen-portal" | "synthetic" | "tavily" | "together" | "venice" | "vercel-ai-gateway" | "vllm" | "xai" | "glm-zcode" | "xiaomi" | "xiaomi-token-plan-sgp" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "zenmux" | "zai";
|
|
10
|
+
export type OAuthProvider = "alibaba-token-plan" | "anthropic" | "bizrouter" | "cerebras" | "cloudflare-ai-gateway" | "cursor" | "deepseek" | "deepinfra" | "fireworks" | "firepass" | "fugu" | "github-copilot" | "google-gemini-cli" | "google-antigravity" | "gitlab-duo" | "huggingface" | "kimi-code" | "kilo" | "kagi" | "litellm" | "lm-studio" | "minimax-code" | "minimax-code-cn" | "moonshot" | "nvidia" | "nanogpt" | "ollama" | "ollama-cloud" | "openai-codex" | "openai-codex-device" | "opencode-go" | "opencode-zen" | "opengateway" | "parallel" | "perplexity" | "qianfan" | "qwen-portal" | "synthetic" | "tavily" | "together" | "venice" | "vercel-ai-gateway" | "vllm" | "sglang" | "xai" | "glm-zcode" | "xiaomi" | "xiaomi-token-plan-sgp" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "zenmux" | "zai";
|
|
11
11
|
export type OAuthProviderId = OAuthProvider | (string & {});
|
|
12
12
|
export type OAuthPrompt = {
|
|
13
13
|
message: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@sayknow-cli/ai",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.8",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
6
|
"homepage": "https://sayknow-cli.com",
|
|
7
7
|
"author": "jaybeyond",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@anthropic-ai/sdk": "^0.94.0",
|
|
45
45
|
"@bufbuild/protobuf": "^2.12.0",
|
|
46
|
-
"@sayknow-cli/utils": "0.5.
|
|
46
|
+
"@sayknow-cli/utils": "0.5.8",
|
|
47
47
|
"openai": "^6.36.0",
|
|
48
48
|
"partial-json": "^0.1.7",
|
|
49
49
|
"zod": "4.4.3"
|
package/src/auth-storage.ts
CHANGED
|
@@ -37,6 +37,12 @@ import { loginDeepSeek } from "./utils/oauth/deepseek";
|
|
|
37
37
|
import { loginOpenAICodexDevice } from "./utils/oauth/openai-codex";
|
|
38
38
|
import type { OAuthController, OAuthCredentials, OAuthProvider, OAuthProviderId } from "./utils/oauth/types";
|
|
39
39
|
|
|
40
|
+
const DEPRECATED_SGLANG_NO_AUTH_TOKEN = "sglang-local";
|
|
41
|
+
|
|
42
|
+
function isDeprecatedSglangNoAuthToken(provider: string, apiKey: string | undefined): boolean {
|
|
43
|
+
return provider === "sglang" && apiKey === DEPRECATED_SGLANG_NO_AUTH_TOKEN;
|
|
44
|
+
}
|
|
45
|
+
|
|
40
46
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
41
47
|
// Credential Types
|
|
42
48
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -1351,6 +1357,11 @@ export class AuthStorage {
|
|
|
1351
1357
|
.filter(
|
|
1352
1358
|
(entry): entry is { credential: Extract<AuthCredential, { type: T }>; index: number } =>
|
|
1353
1359
|
entry.credential.type === type,
|
|
1360
|
+
)
|
|
1361
|
+
.filter(
|
|
1362
|
+
entry =>
|
|
1363
|
+
type !== "api_key" ||
|
|
1364
|
+
!isDeprecatedSglangNoAuthToken(provider, (entry.credential as ApiKeyCredential).key),
|
|
1354
1365
|
);
|
|
1355
1366
|
|
|
1356
1367
|
if (credentials.length === 0) return undefined;
|
|
@@ -1950,6 +1961,12 @@ export class AuthStorage {
|
|
|
1950
1961
|
await saveApiKeyCredential(apiKey);
|
|
1951
1962
|
return;
|
|
1952
1963
|
}
|
|
1964
|
+
case "sglang": {
|
|
1965
|
+
const { loginSglang } = await import("./utils/oauth/sglang");
|
|
1966
|
+
const apiKey = await loginSglang(ctrl);
|
|
1967
|
+
await saveApiKeyCredential(apiKey);
|
|
1968
|
+
return;
|
|
1969
|
+
}
|
|
1953
1970
|
case "parallel": {
|
|
1954
1971
|
const { loginParallel } = await import("./utils/oauth/parallel");
|
|
1955
1972
|
const apiKey = await loginParallel(ctrl);
|
|
@@ -3434,7 +3451,8 @@ export class AuthStorage {
|
|
|
3434
3451
|
|
|
3435
3452
|
const apiKeySelection = this.#selectCredentialByType(provider, "api_key");
|
|
3436
3453
|
if (apiKeySelection) {
|
|
3437
|
-
|
|
3454
|
+
const apiKey = await this.#configValueResolver(apiKeySelection.credential.key);
|
|
3455
|
+
if (!isDeprecatedSglangNoAuthToken(provider, apiKey)) return apiKey;
|
|
3438
3456
|
}
|
|
3439
3457
|
|
|
3440
3458
|
// Return current OAuth access token only if it is not already expired.
|
|
@@ -3487,16 +3505,24 @@ export class AuthStorage {
|
|
|
3487
3505
|
return configKey;
|
|
3488
3506
|
}
|
|
3489
3507
|
|
|
3508
|
+
let skippedDeprecatedNoAuthToken = false;
|
|
3490
3509
|
if (selectedCredential?.credential.type === "api_key") {
|
|
3491
|
-
this.#
|
|
3492
|
-
|
|
3510
|
+
const apiKey = await this.#configValueResolver(selectedCredential.credential.key);
|
|
3511
|
+
if (!isDeprecatedSglangNoAuthToken(provider, apiKey)) {
|
|
3512
|
+
this.#recordSessionCredential(provider, sessionId, "api_key", selectedCredential.index);
|
|
3513
|
+
return apiKey;
|
|
3514
|
+
}
|
|
3515
|
+
skippedDeprecatedNoAuthToken = true;
|
|
3493
3516
|
}
|
|
3494
3517
|
|
|
3495
|
-
if (!selectedCredential) {
|
|
3518
|
+
if (!selectedCredential || skippedDeprecatedNoAuthToken) {
|
|
3496
3519
|
const apiKeySelection = this.#selectCredentialByType(provider, "api_key", sessionId);
|
|
3497
3520
|
if (apiKeySelection) {
|
|
3498
|
-
this.#
|
|
3499
|
-
|
|
3521
|
+
const apiKey = await this.#configValueResolver(apiKeySelection.credential.key);
|
|
3522
|
+
if (!isDeprecatedSglangNoAuthToken(provider, apiKey)) {
|
|
3523
|
+
this.#recordSessionCredential(provider, sessionId, "api_key", apiKeySelection.index);
|
|
3524
|
+
return apiKey;
|
|
3525
|
+
}
|
|
3500
3526
|
}
|
|
3501
3527
|
}
|
|
3502
3528
|
|
package/src/model-thinking.ts
CHANGED
|
@@ -64,6 +64,7 @@ type SemVer = {
|
|
|
64
64
|
type GeminiKind = "pro" | "flash";
|
|
65
65
|
type AnthropicKind = "opus" | "sonnet" | "fable";
|
|
66
66
|
type OpenAIVariant =
|
|
67
|
+
| "astra"
|
|
67
68
|
| "base"
|
|
68
69
|
| "codex"
|
|
69
70
|
| "codex-max"
|
|
@@ -190,6 +191,24 @@ export function refreshModelThinking<TApi extends Api>(model: ApiModel<TApi>): A
|
|
|
190
191
|
return { ...model, thinking: inferModelThinking(model) };
|
|
191
192
|
}
|
|
192
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Extract the GLM generation from a Zhipu/ZAI model id: `glm-5.3` and
|
|
196
|
+
* `glm-5.3-flash` -> 5.3, `glm-5` and `glm-5-turbo` -> 5, `glm-4.7` -> 4.7.
|
|
197
|
+
* Returns undefined for ids that are not a plain GLM generation, including the
|
|
198
|
+
* vision line (`glm-5v-turbo`), so those never inherit text-model corrections.
|
|
199
|
+
*/
|
|
200
|
+
export function glmGeneration(modelId: string): number | undefined {
|
|
201
|
+
const match = modelId.toLowerCase().match(/^glm-(\d+)(?:\.(\d+))?(?![\d.v])/);
|
|
202
|
+
if (!match) return undefined;
|
|
203
|
+
const [, major, minor] = match;
|
|
204
|
+
return minor === undefined ? Number(major) : Number(`${major}.${minor}`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function glmGenerationAtLeast(modelId: string, minimum: number): boolean {
|
|
208
|
+
const generation = glmGeneration(modelId);
|
|
209
|
+
return generation !== undefined && generation >= minimum;
|
|
210
|
+
}
|
|
211
|
+
|
|
193
212
|
/**
|
|
194
213
|
* Apply upstream metadata corrections to a mutable array of models.
|
|
195
214
|
*
|
|
@@ -198,7 +217,11 @@ export function refreshModelThinking<TApi extends Api>(model: ApiModel<TApi>): A
|
|
|
198
217
|
*/
|
|
199
218
|
export function applyGeneratedModelPolicies(models: ApiModel<Api>[]): void {
|
|
200
219
|
for (let index = 0; index < models.length; index++) {
|
|
201
|
-
const
|
|
220
|
+
const source = models[index]!;
|
|
221
|
+
if (source.provider === "omlx") {
|
|
222
|
+
source.reasoning = true;
|
|
223
|
+
}
|
|
224
|
+
const model = refreshModelThinking(source);
|
|
202
225
|
applyGeneratedModelPolicy(model);
|
|
203
226
|
models[index] = model;
|
|
204
227
|
}
|
|
@@ -377,6 +400,16 @@ function applyGeneratedModelPolicy(model: ApiModel<Api>): void {
|
|
|
377
400
|
};
|
|
378
401
|
delete model.compat.thinkingFormat;
|
|
379
402
|
}
|
|
403
|
+
if (model.provider === "omlx" && model.api === "openai-completions") {
|
|
404
|
+
model.compat = {
|
|
405
|
+
...(model.compat ?? {}),
|
|
406
|
+
supportsStore: false,
|
|
407
|
+
supportsDeveloperRole: false,
|
|
408
|
+
supportsReasoningEffort: true,
|
|
409
|
+
thinkingFormat: "qwen-chat-template",
|
|
410
|
+
reasoningContentField: "reasoning_content",
|
|
411
|
+
};
|
|
412
|
+
}
|
|
380
413
|
model.name = scrubGeneratedModelName(model.name);
|
|
381
414
|
if (
|
|
382
415
|
model.api === "openai-completions" &&
|
|
@@ -411,13 +444,31 @@ function applyGeneratedModelPolicy(model: ApiModel<Api>): void {
|
|
|
411
444
|
if (parsedModel.family === "openai") {
|
|
412
445
|
applyOpenAICatalogPolicy(model, parsedModel);
|
|
413
446
|
}
|
|
414
|
-
// GLM-5.2 (Zhipu/ZAI):
|
|
415
|
-
// catalog copied GLM-5.1's 200K and that stale value survives
|
|
416
|
-
// (provider-scoped models bypass the models.dev refresh in
|
|
417
|
-
// Pin
|
|
418
|
-
|
|
447
|
+
// GLM-5.2 and newer (Zhipu/ZAI): ship a 1M lossless context window, but the
|
|
448
|
+
// bundled catalog copied GLM-5.1's 200K and that stale value survives
|
|
449
|
+
// generate-models (provider-scoped models bypass the models.dev refresh in
|
|
450
|
+
// applyGlobalModelsDevFallback). Pin the true 1M so context-cap /
|
|
451
|
+
// auto-compaction thresholds aren't tripped ~5x early.
|
|
452
|
+
//
|
|
453
|
+
// Matched by generation rather than by exact id so the next GLM point
|
|
454
|
+
// release inherits the correct window instead of silently regressing to
|
|
455
|
+
// whatever the catalog happens to carry. The correction only raises a
|
|
456
|
+
// stale-low window: a future generation that genuinely ships more than 1M
|
|
457
|
+
// keeps its larger catalog value instead of being clamped down to 1M.
|
|
458
|
+
if (model.provider === "zai" && glmGenerationAtLeast(model.id, 5.2) && model.contextWindow < 1_000_000) {
|
|
419
459
|
model.contextWindow = 1_000_000;
|
|
420
460
|
}
|
|
461
|
+
// Alibaba Token Plan's qwen3.8-max-preview is routed through the OpenAI
|
|
462
|
+
// Responses API. models.dev recently started publishing the whole
|
|
463
|
+
// alibaba-token-plan provider, and its blanket chat-completions mapping wins
|
|
464
|
+
// the generate-models merge, so a regeneration silently reroutes this one
|
|
465
|
+
// paid model. Pin the routing that ships today and is covered by
|
|
466
|
+
// register-builtins' Responses lazy-path watchdog until the endpoint is
|
|
467
|
+
// re-verified; the catalog's other metadata (vision input, 131K output cap)
|
|
468
|
+
// is still inherited.
|
|
469
|
+
if (model.provider === "alibaba-token-plan" && model.id === "qwen3.8-max-preview") {
|
|
470
|
+
model.api = "openai-responses" as typeof model.api;
|
|
471
|
+
}
|
|
421
472
|
// MiniMax-M3: MiniMax exposes a 1M context tier, but usage beyond 512K is
|
|
422
473
|
// billed separately. Keep bundled/default metadata at the billing-safe 512K
|
|
423
474
|
// unless an explicit paid-tier contract is added.
|
|
@@ -454,7 +505,10 @@ function inferGeneratedApplyPatchToolType(
|
|
|
454
505
|
model: ApiModel<Api>,
|
|
455
506
|
parsedModel: ParsedModel,
|
|
456
507
|
): ApiModel<Api>["applyPatchToolType"] {
|
|
457
|
-
if (
|
|
508
|
+
if (
|
|
509
|
+
parsedModel.family !== "openai" ||
|
|
510
|
+
(parsedModel.version.major !== 5 && !(parsedModel.version.major === 6 && parsedModel.variant === "astra"))
|
|
511
|
+
) {
|
|
458
512
|
return undefined;
|
|
459
513
|
}
|
|
460
514
|
if (model.provider === "openai" && model.api === "openai-responses") {
|
|
@@ -527,6 +581,9 @@ function inferDefaultEffort<TApi extends Api>(model: ApiModel<TApi>, parsedModel
|
|
|
527
581
|
) {
|
|
528
582
|
return GPT_5_5_DEFAULT_EFFORT;
|
|
529
583
|
}
|
|
584
|
+
if (model.provider === "omlx") {
|
|
585
|
+
return Effort.Medium;
|
|
586
|
+
}
|
|
530
587
|
return undefined;
|
|
531
588
|
}
|
|
532
589
|
|
|
@@ -662,6 +719,9 @@ function inferFallbackEfforts<TApi extends Api>(model: ApiModel<TApi>): readonly
|
|
|
662
719
|
return DEFAULT_REASONING_EFFORTS;
|
|
663
720
|
}
|
|
664
721
|
if (model.api === "openai-completions") {
|
|
722
|
+
if (model.provider === "omlx") {
|
|
723
|
+
return [Effort.Low, Effort.Medium, Effort.High];
|
|
724
|
+
}
|
|
665
725
|
const compat = resolveOpenAICompat(model as ApiModel<"openai-completions">);
|
|
666
726
|
if (compat.thinkingFormat === "openai" && compat.supportsReasoningEffort) {
|
|
667
727
|
return DEFAULT_REASONING_EFFORTS_WITH_XHIGH;
|
|
@@ -758,7 +818,7 @@ function parseAnthropicModel(modelId: string): AnthropicModel | null {
|
|
|
758
818
|
|
|
759
819
|
function parseOpenAIModel(modelId: string): OpenAIModel | null {
|
|
760
820
|
const match =
|
|
761
|
-
/gpt-(\d+(?:\.\d+){0,2})(?:-(codex-spark|codex-mini|codex-max|codex|luna|mini|max|nano|sol|terra))?$/.exec(
|
|
821
|
+
/gpt-(\d+(?:\.\d+){0,2})(?:-(astra|codex-spark|codex-mini|codex-max|codex|luna|mini|max|nano|sol|terra))?$/.exec(
|
|
762
822
|
modelId,
|
|
763
823
|
);
|
|
764
824
|
if (!match) {
|