From dd95c9cf328cb0e2658b2b57e9e95790902a5183 Mon Sep 17 00:00:00 2001 From: bu6n Date: Tue, 4 Aug 2026 06:46:42 +0200 Subject: [PATCH 01/14] feat(tensorx): add sync module for automated catalog updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sync provider models from TensorX's own /v1/model/info endpoint. Capability flags are three-valued in that catalog: true, false, and null for "not published". Only real booleans are authored so a null leaves the field inherited from the lab entry rather than overriding it with false. supported_openai_params is deliberately not read. It is a static LiteLLM-style list — all 32 catalog entries advertise the same params, including temperature and response_format on the Whisper and embedding models — so it carries no per-model signal. temperature and structured_output stay lab metadata. The endpoint publishes no name, description, or release date, so an unknown model is reported through skippedNotice for hand-authoring instead of being created from invented metadata. Base models resolve through the shared resolveCanonicalBaseModel, which matches metadata filenames case-insensitively. --- .github/workflows/sync-models.yml | 1 + packages/core/src/sync/index.ts | 5 +- packages/core/src/sync/providers/tensorx.ts | 162 ++++++++++++++++++++ 3 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 packages/core/src/sync/providers/tensorx.ts diff --git a/.github/workflows/sync-models.yml b/.github/workflows/sync-models.yml index 7edd032424..ebb4f04304 100644 --- a/.github/workflows/sync-models.yml +++ b/.github/workflows/sync-models.yml @@ -90,6 +90,7 @@ jobs: XAI_API_KEY: ${{ secrets.XAI_API_KEY }} CLOUDFLARE_WORKERS_AI_SYNC_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_WORKERS_AI_SYNC_ACCOUNT_ID }} CLOUDFLARE_WORKERS_AI_SYNC_API_TOKEN: ${{ secrets.CLOUDFLARE_WORKERS_AI_SYNC_API_TOKEN }} + TENSORX_API_KEY: ${{ secrets.TENSORX_API_KEY }} - name: Validate models run: bun validate diff --git a/packages/core/src/sync/index.ts b/packages/core/src/sync/index.ts index a3fa90270f..69069ae457 100644 --- a/packages/core/src/sync/index.ts +++ b/packages/core/src/sync/index.ts @@ -27,6 +27,7 @@ import { openrouter } from "./providers/openrouter.js"; import { ovhcloud } from "./providers/ovhcloud.js"; import { pioneer } from "./providers/pioneer.js"; import { requesty } from "./providers/requesty.js"; +import { tensorx } from "./providers/tensorx.js"; import { tinfoil } from "./providers/tinfoil.js"; import { vercel } from "./providers/vercel.js"; import { venice } from "./providers/venice.js"; @@ -133,6 +134,7 @@ export const providers: { ovhcloud: SyncProvider; pioneer: SyncProvider; requesty: SyncProvider; + tensorx: SyncProvider; tinfoil: SyncProvider; vercel: SyncProvider; venice: SyncProvider; @@ -161,6 +163,7 @@ export const providers: { ovhcloud, pioneer, requesty, + tensorx, tinfoil, vercel, venice, @@ -183,7 +186,7 @@ export const groups = { "vercel", ], cloudflare: ["cloudflare-workers-ai"], - direct: ["ambient", "anthropic", "baseten", "chutes", "deepinfra", "digitalocean", "google", "hyper", "openai", "ovhcloud", "pioneer", "tinfoil", "venice", "wandb", "xai"], + direct: ["ambient", "anthropic", "baseten", "chutes", "deepinfra", "digitalocean", "google", "hyper", "openai", "ovhcloud", "pioneer", "tensorx", "tinfoil", "venice", "wandb", "xai"], } as const; type ProviderID = keyof typeof providers; diff --git a/packages/core/src/sync/providers/tensorx.ts b/packages/core/src/sync/providers/tensorx.ts new file mode 100644 index 0000000000..ab0e02f61c --- /dev/null +++ b/packages/core/src/sync/providers/tensorx.ts @@ -0,0 +1,162 @@ +import { z } from "zod"; + +import type { ExistingModel, SyncProvider, SyncedFullModel, SyncedModel } from "../index.js"; +import { factorBaseModel, resolveCanonicalBaseModel } from "./openrouter.js"; + +const API_ENDPOINT = "https://api.tensorx.ai/v1/model/info"; + +// `supported_openai_params` is a static LiteLLM-style list: every catalog entry +// advertises the same params, including `temperature` and `response_format` on +// the Whisper and embedding models. It carries no per-model signal, so nothing +// is derived from it — `temperature` and `structured_output` stay lab metadata. +// +// `supports_*` uses three values: true, false, and null for "not published". +// Only real booleans are authored; null leaves the field to the base model. +const TensorXModelInfo = z.object({ + mode: z.string().nullish(), + max_input_tokens: z.number().int().nonnegative().nullish(), + max_output_tokens: z.number().int().nonnegative().nullish(), + max_tokens: z.number().int().nonnegative().nullish(), + supports_reasoning: z.boolean().nullish(), + supports_tool_choice: z.boolean().nullish(), + supports_function_calling: z.boolean().nullish(), + supports_vision: z.boolean().nullish(), + input_cost_per_token: z.number().nonnegative().nullish(), + output_cost_per_token: z.number().nonnegative().nullish(), + cache_read_input_token_cost: z.number().nonnegative().nullish(), + cache_creation_input_token_cost: z.number().nonnegative().nullish(), +}).passthrough(); + +export const TensorXModel = z.object({ + model_name: z.string().min(1), + model_info: TensorXModelInfo, +}); + +export const TensorXResponse = z.object({ + data: z.array(TensorXModel), +}); + +export type TensorXModel = z.infer; + +export const tensorx = { + id: "tensorx", + name: "TensorX", + modelsDir: "providers/tensorx/models", + preserveBaseModels: false, + // /v1/model/info returns a per-key view: a key scoped to a model group sees + // only that group, and chat requests for the rest fail with 403 rather than + // 404. Absence from the response is therefore not evidence that a model was + // retired, so local entries are never deleted on the strength of it. + deleteMissing: false, + sourceID(model) { + // Non-chat entries (embeddings, transcription, speech) are out of scope and + // are dropped silently; only unauthorable chat models get reported. + return model.model_info.mode === "chat" ? model.model_name : undefined; + }, + skippedNotice(ids) { + if (ids.length === 0) return []; + return [ + `${ids.length} TensorX chat models were not created because /v1/model/info publishes no name, description, or release date to author a model from.`, + `Add the lab entry under \`models/\` (or hand-author the provider file) first. Skipped remote IDs: ${ids.map((id) => `\`${id}\``).join(", ")}`, + ]; + }, + async fetchModels() { + const apiKey = process.env.TENSORX_API_KEY; + if (!apiKey) { + throw new Error("TensorX sync requires TENSORX_API_KEY environment variable"); + } + const response = await fetch(API_ENDPOINT, { + headers: { Authorization: `Bearer ${apiKey}` }, + }); + if (!response.ok) { + throw new Error(`TensorX model info request failed: ${response.status} ${response.statusText}`); + } + return response.json(); + }, + parseModels(raw) { + const models = TensorXResponse.parse(raw).data; + const seen = new Set(); + return models.filter((model) => { + if (seen.has(model.model_name)) return false; + seen.add(model.model_name); + return true; + }); + }, + translateModel(model, context) { + if (model.model_info.mode !== "chat") return undefined; + + const existing = context.existing(model.model_name); + const baseModel = resolveBaseModel(model.model_name); + // Nothing in this catalog can stand in for lab metadata — no display name, + // no description, no release date — so an unknown model is reported for + // hand-authoring instead of being invented. + if (baseModel === undefined && existing === undefined) return undefined; + + return { + id: model.model_name, + model: buildTensorXModel(model, baseModel, existing), + }; + }, +} satisfies SyncProvider; + +function buildTensorXModel( + model: TensorXModel, + baseModel: string | undefined, + existing: ExistingModel | undefined, +): SyncedModel { + const info = model.model_info; + + const limit = { + context: info.max_input_tokens ?? info.max_tokens ?? existing?.limit?.context, + output: info.max_output_tokens ?? existing?.limit?.output, + }; + + const cost = { + ...existing?.cost, + input: perMillion(info.input_cost_per_token) ?? existing?.cost?.input, + output: perMillion(info.output_cost_per_token) ?? existing?.cost?.output, + cache_read: perMillion(info.cache_read_input_token_cost) ?? existing?.cost?.cache_read, + // cache_creation_input_token_cost is null for every model in the catalog, so + // a null is "not published" rather than "not charged". Keep the authored + // price; it publishes real values as soon as TensorX fills the field in. + cache_write: perMillion(info.cache_creation_input_token_cost) ?? existing?.cost?.cache_write, + }; + + const toolFlags = [info.supports_tool_choice, info.supports_function_calling] + .filter((flag) => flag !== null && flag !== undefined); + + // `existing` is the base-model-resolved view, so factorBaseModel drops every + // field that still matches the lab entry and keeps only the real deltas. + const values: Record = { + ...existing, + attachment: info.supports_vision ?? existing?.attachment, + reasoning: info.supports_reasoning ?? existing?.reasoning, + tool_call: toolFlags.length > 0 ? toolFlags.some(Boolean) : existing?.tool_call, + cost, + limit, + }; + delete values.base_model; + delete values.base_model_omit; + + return baseModel === undefined + ? values as SyncedFullModel + : factorBaseModel(baseModel, values, limit, existing?.base_model_omit); +} + +// Dated snapshots TensorX serves that have no lab entry of their own. +const BASE_MODEL_ALIASES: Record = { + "deepseek/deepseek-r1-0528": "deepseek/deepseek-r1", + "deepseek/deepseek-r1-0625": "deepseek/deepseek-r1", +}; + +function resolveBaseModel(modelID: string): string | undefined { + // resolveCanonicalBaseModel owns the org-prefix map and matches metadata + // filenames case-insensitively, so `minimax/minimax-m3` still resolves to + // `models/minimax/MiniMax-M3.toml`. + return resolveCanonicalBaseModel(BASE_MODEL_ALIASES[modelID] ?? modelID); +} + +function perMillion(costPerToken: number | null | undefined): number | undefined { + if (costPerToken === null || costPerToken === undefined) return undefined; + return Math.round(costPerToken * 1_000_000 * 1e10) / 1e10; +} From 22c26d26491ce9a8c65031028ecabf521886acff Mon Sep 17 00:00:00 2001 From: bu6n Date: Tue, 4 Aug 2026 06:47:05 +0200 Subject: [PATCH 02/14] chore(tensorx): move reasoning wire paths into leading TOML headers The sync re-serializes provider files through Bun.TOML.parse, which discards comments; only the leading block is re-attached. Trailing comments on `type = "toggle"` / `type = "effort"` lines were therefore lost on the first sync run. AGENTS.md requires a leading top-of-file comment carrying the exact wire path for every toggle, so the request syntax moves there and survives future runs. No data changes. --- providers/tensorx/models/deepseek/deepseek-chat-v3.1.toml | 4 ++-- providers/tensorx/models/deepseek/deepseek-r1-0528.toml | 3 ++- providers/tensorx/models/deepseek/deepseek-v3.2.toml | 4 ++-- .../tensorx/models/deepseek/deepseek-v4-flash-0731.toml | 5 +++-- providers/tensorx/models/deepseek/deepseek-v4-flash.toml | 3 ++- providers/tensorx/models/deepseek/deepseek-v4-pro.toml | 3 ++- providers/tensorx/models/minimax/minimax-m2.5.toml | 3 ++- providers/tensorx/models/minimax/minimax-m3.toml | 3 ++- providers/tensorx/models/moonshotai/kimi-k2.6.toml | 3 ++- providers/tensorx/models/moonshotai/kimi-k2.7-code.toml | 3 ++- providers/tensorx/models/moonshotai/kimi-k3.toml | 5 +++-- .../tensorx/models/nvidia/nemotron-3-super-120b-a12b.toml | 3 ++- providers/tensorx/models/openai/gpt-oss-120b.toml | 3 ++- providers/tensorx/models/qwen/qwen3.5-122b-a10b.toml | 3 ++- providers/tensorx/models/qwen/qwen3.5-9b.toml | 4 ++-- providers/tensorx/models/z-ai/glm-4.7.toml | 3 ++- providers/tensorx/models/z-ai/glm-5-turbo.toml | 6 ++++-- providers/tensorx/models/z-ai/glm-5.1.toml | 6 ++++-- providers/tensorx/models/z-ai/glm-5.2.toml | 6 ++++-- providers/tensorx/models/z-ai/glm-5.toml | 3 ++- providers/tensorx/models/z-ai/glm-5v-turbo.toml | 6 ++++-- 21 files changed, 52 insertions(+), 30 deletions(-) diff --git a/providers/tensorx/models/deepseek/deepseek-chat-v3.1.toml b/providers/tensorx/models/deepseek/deepseek-chat-v3.1.toml index 93143b88c6..34f6124bc1 100644 --- a/providers/tensorx/models/deepseek/deepseek-chat-v3.1.toml +++ b/providers/tensorx/models/deepseek/deepseek-chat-v3.1.toml @@ -1,3 +1,4 @@ +# Effort: reasoning_effort = ; "none" disables reasoning name = "DeepSeek Chat V3.1" description = "DeepSeek chat model for instruction following, coding, and analysis" family = "deepseek" @@ -10,9 +11,8 @@ tool_call = true knowledge = "2024-11" open_weights = true - [[reasoning_options]] -type = "effort" # API: {"reasoning_effort": }; "none" disables reasoning +type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] [cost] diff --git a/providers/tensorx/models/deepseek/deepseek-r1-0528.toml b/providers/tensorx/models/deepseek/deepseek-r1-0528.toml index 5584722dd5..9a30b0a01f 100644 --- a/providers/tensorx/models/deepseek/deepseek-r1-0528.toml +++ b/providers/tensorx/models/deepseek/deepseek-r1-0528.toml @@ -1,10 +1,11 @@ +# Effort: reasoning_effort = ; reasoning is mandatory, "none" is rejected base_model = "deepseek/deepseek-r1" name = "DeepSeek R1-0528" release_date = "2025-05-28" last_updated = "2025-05-28" [[reasoning_options]] -type = "effort" # API: {"reasoning_effort": }; reasoning is mandatory, "none" is rejected +type = "effort" values = ["minimal", "low", "medium", "high", "xhigh", "max"] [cost] diff --git a/providers/tensorx/models/deepseek/deepseek-v3.2.toml b/providers/tensorx/models/deepseek/deepseek-v3.2.toml index dc3a096e9e..348e51b711 100644 --- a/providers/tensorx/models/deepseek/deepseek-v3.2.toml +++ b/providers/tensorx/models/deepseek/deepseek-v3.2.toml @@ -1,3 +1,4 @@ +# Effort: reasoning_effort = ; "none" disables reasoning name = "DeepSeek V3.2" description = "DeepSeek chat model for instruction following, coding, and analysis" family = "deepseek" @@ -10,9 +11,8 @@ tool_call = true knowledge = "2025-05" open_weights = true - [[reasoning_options]] -type = "effort" # API: {"reasoning_effort": }; "none" disables reasoning +type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] [cost] diff --git a/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml b/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml index 5c7bc69ad3..e775f90948 100644 --- a/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml +++ b/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml @@ -1,7 +1,8 @@ +# Toggle: chat_template_kwargs.thinking = true|false (default off) base_model = "deepseek/deepseek-v4-flash-0731" [[reasoning_options]] -type = "toggle" # API: {"chat_template_kwargs": {"thinking": true}} (default off) +type = "toggle" [cost] input = 0.25 @@ -9,4 +10,4 @@ output = 0.30 cache_read = 0.06 [limit] -context = 1048576 \ No newline at end of file +context = 1048576 diff --git a/providers/tensorx/models/deepseek/deepseek-v4-flash.toml b/providers/tensorx/models/deepseek/deepseek-v4-flash.toml index fdea8b9a03..aa2068bd2b 100644 --- a/providers/tensorx/models/deepseek/deepseek-v4-flash.toml +++ b/providers/tensorx/models/deepseek/deepseek-v4-flash.toml @@ -1,7 +1,8 @@ +# Toggle: chat_template_kwargs.thinking = true|false (default off) base_model = "deepseek/deepseek-v4-flash" [[reasoning_options]] -type = "toggle" # API: {"chat_template_kwargs": {"thinking": true}} (default off) +type = "toggle" [cost] input = 0.15 diff --git a/providers/tensorx/models/deepseek/deepseek-v4-pro.toml b/providers/tensorx/models/deepseek/deepseek-v4-pro.toml index ebe06937ea..71d6f837ba 100644 --- a/providers/tensorx/models/deepseek/deepseek-v4-pro.toml +++ b/providers/tensorx/models/deepseek/deepseek-v4-pro.toml @@ -1,7 +1,8 @@ +# Toggle: chat_template_kwargs.thinking = true|false (default off) base_model = "deepseek/deepseek-v4-pro" [[reasoning_options]] -type = "toggle" # API: {"chat_template_kwargs": {"thinking": true}} (default off) +type = "toggle" [cost] input = 1.75 diff --git a/providers/tensorx/models/minimax/minimax-m2.5.toml b/providers/tensorx/models/minimax/minimax-m2.5.toml index b9c42b9646..af9e83dc13 100644 --- a/providers/tensorx/models/minimax/minimax-m2.5.toml +++ b/providers/tensorx/models/minimax/minimax-m2.5.toml @@ -1,7 +1,8 @@ +# Effort: reasoning_effort = ; reasoning is mandatory, "none" is rejected base_model = "minimax/MiniMax-M2.5" [[reasoning_options]] -type = "effort" # API: {"reasoning_effort": }; reasoning is mandatory, "none" is rejected +type = "effort" values = ["minimal", "low", "medium", "high", "xhigh", "max"] [cost] diff --git a/providers/tensorx/models/minimax/minimax-m3.toml b/providers/tensorx/models/minimax/minimax-m3.toml index d9b2cb7dcb..fd320e2283 100644 --- a/providers/tensorx/models/minimax/minimax-m3.toml +++ b/providers/tensorx/models/minimax/minimax-m3.toml @@ -1,7 +1,8 @@ +# Toggle: chat_template_kwargs.thinking_mode = enabled|disabled (default "adaptive") base_model = "minimax/MiniMax-M3" [[reasoning_options]] -type = "toggle" # API: {"chat_template_kwargs": {"thinking_mode": "enabled" | "disabled"}} (default "adaptive") +type = "toggle" [cost] input = 0.4 diff --git a/providers/tensorx/models/moonshotai/kimi-k2.6.toml b/providers/tensorx/models/moonshotai/kimi-k2.6.toml index 4490b5bfe1..128f94094d 100644 --- a/providers/tensorx/models/moonshotai/kimi-k2.6.toml +++ b/providers/tensorx/models/moonshotai/kimi-k2.6.toml @@ -1,7 +1,8 @@ +# Toggle: chat_template_kwargs.thinking = true|false (default on) base_model = "moonshotai/kimi-k2.6" [[reasoning_options]] -type = "toggle" # API: {"chat_template_kwargs": {"thinking": false}} (default on) +type = "toggle" [cost] input = 1 diff --git a/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml b/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml index 77034868c0..1a404e46d6 100644 --- a/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml +++ b/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml @@ -1,7 +1,8 @@ +# Toggle: chat_template_kwargs.thinking = true|false (default on) base_model = "moonshotai/kimi-k2.7-code" [[reasoning_options]] -type = "toggle" # API: {"chat_template_kwargs": {"thinking": false}} (default on) +type = "toggle" [cost] input = 1.25 diff --git a/providers/tensorx/models/moonshotai/kimi-k3.toml b/providers/tensorx/models/moonshotai/kimi-k3.toml index c5f9a35187..403c0b14a0 100644 --- a/providers/tensorx/models/moonshotai/kimi-k3.toml +++ b/providers/tensorx/models/moonshotai/kimi-k3.toml @@ -1,10 +1,11 @@ # AI SDK auto-discovers native IDs via /v1/models — field values map those IDs +# Toggle: chat_template_kwargs.thinking = true|false (default on) base_model = "moonshotai/kimi-k3" [[reasoning_options]] -type = "toggle" # API: {"chat_template_kwargs": {"thinking": false}} (default on) +type = "toggle" [cost] input = 3.00 output = 15.00 -cache_read = 0.75 \ No newline at end of file +cache_read = 0.75 diff --git a/providers/tensorx/models/nvidia/nemotron-3-super-120b-a12b.toml b/providers/tensorx/models/nvidia/nemotron-3-super-120b-a12b.toml index 279eb86ea6..8423a4f38a 100644 --- a/providers/tensorx/models/nvidia/nemotron-3-super-120b-a12b.toml +++ b/providers/tensorx/models/nvidia/nemotron-3-super-120b-a12b.toml @@ -1,7 +1,8 @@ +# Effort: reasoning_effort = ; "none" disables reasoning base_model = "nvidia/nemotron-3-super-120b-a12b" [[reasoning_options]] -type = "effort" # API: {"reasoning_effort": }; "none" disables reasoning +type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] [cost] diff --git a/providers/tensorx/models/openai/gpt-oss-120b.toml b/providers/tensorx/models/openai/gpt-oss-120b.toml index b34a24534e..b6a30e839c 100644 --- a/providers/tensorx/models/openai/gpt-oss-120b.toml +++ b/providers/tensorx/models/openai/gpt-oss-120b.toml @@ -1,8 +1,9 @@ +# Effort: reasoning_effort = ; reasoning is mandatory, "none" is rejected base_model = "openai/gpt-oss-120b" knowledge = "2024-10" [[reasoning_options]] -type = "effort" # API: {"reasoning_effort": }; reasoning is mandatory, "none" is rejected +type = "effort" values = ["minimal", "low", "medium", "high", "xhigh", "max"] [cost] diff --git a/providers/tensorx/models/qwen/qwen3.5-122b-a10b.toml b/providers/tensorx/models/qwen/qwen3.5-122b-a10b.toml index 063495e1fb..fadb6545fa 100644 --- a/providers/tensorx/models/qwen/qwen3.5-122b-a10b.toml +++ b/providers/tensorx/models/qwen/qwen3.5-122b-a10b.toml @@ -1,7 +1,8 @@ +# Effort: reasoning_effort = ; "none" disables reasoning base_model = "alibaba/qwen3.5-122b-a10b" [[reasoning_options]] -type = "effort" # API: {"reasoning_effort": }; "none" disables reasoning +type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] [cost] diff --git a/providers/tensorx/models/qwen/qwen3.5-9b.toml b/providers/tensorx/models/qwen/qwen3.5-9b.toml index 93d4f8b02f..6419ca38b1 100644 --- a/providers/tensorx/models/qwen/qwen3.5-9b.toml +++ b/providers/tensorx/models/qwen/qwen3.5-9b.toml @@ -1,8 +1,8 @@ +# Effort: reasoning_effort = ; "none" disables reasoning base_model = "alibaba/qwen3.5-9b" - [[reasoning_options]] -type = "effort" # API: {"reasoning_effort": }; "none" disables reasoning +type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] [cost] diff --git a/providers/tensorx/models/z-ai/glm-4.7.toml b/providers/tensorx/models/z-ai/glm-4.7.toml index 931c963e6a..c33966c544 100644 --- a/providers/tensorx/models/z-ai/glm-4.7.toml +++ b/providers/tensorx/models/z-ai/glm-4.7.toml @@ -1,7 +1,8 @@ +# Effort: reasoning_effort = ; "none" disables reasoning base_model = "zhipuai/glm-4.7" [[reasoning_options]] -type = "effort" # API: {"reasoning_effort": }; "none" disables reasoning +type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] [cost] diff --git a/providers/tensorx/models/z-ai/glm-5-turbo.toml b/providers/tensorx/models/z-ai/glm-5-turbo.toml index 4e557e1c0c..9cde43e494 100644 --- a/providers/tensorx/models/z-ai/glm-5-turbo.toml +++ b/providers/tensorx/models/z-ai/glm-5-turbo.toml @@ -1,10 +1,12 @@ +# Toggle: chat_template_kwargs.enable_thinking = true|false (default on) +# Effort: reasoning_effort = ; "none" disables reasoning base_model = "zhipuai/glm-5-turbo" [[reasoning_options]] -type = "toggle" # API: {"chat_template_kwargs": {"enable_thinking": false}} (default on) +type = "toggle" [[reasoning_options]] -type = "effort" # API: {"reasoning_effort": }; "none" disables reasoning +type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] [cost] diff --git a/providers/tensorx/models/z-ai/glm-5.1.toml b/providers/tensorx/models/z-ai/glm-5.1.toml index 869157ad21..1ff0297c3a 100644 --- a/providers/tensorx/models/z-ai/glm-5.1.toml +++ b/providers/tensorx/models/z-ai/glm-5.1.toml @@ -1,10 +1,12 @@ +# Toggle: chat_template_kwargs.enable_thinking = true|false (default on) +# Effort: reasoning_effort = ; "none" disables reasoning base_model = "zhipuai/glm-5.1" [[reasoning_options]] -type = "toggle" # API: {"chat_template_kwargs": {"enable_thinking": false}} (default on) +type = "toggle" [[reasoning_options]] -type = "effort" # API: {"reasoning_effort": }; "none" disables reasoning +type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] [cost] diff --git a/providers/tensorx/models/z-ai/glm-5.2.toml b/providers/tensorx/models/z-ai/glm-5.2.toml index 04350a241e..2aef9e70ff 100644 --- a/providers/tensorx/models/z-ai/glm-5.2.toml +++ b/providers/tensorx/models/z-ai/glm-5.2.toml @@ -1,10 +1,12 @@ +# Toggle: chat_template_kwargs.enable_thinking = true|false (default on) +# Effort: reasoning_effort = ; "none" disables reasoning base_model = "zhipuai/glm-5.2" [[reasoning_options]] -type = "toggle" # API: {"chat_template_kwargs": {"enable_thinking": false}} (default on) +type = "toggle" [[reasoning_options]] -type = "effort" # API: {"reasoning_effort": }; "none" disables reasoning +type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] [cost] diff --git a/providers/tensorx/models/z-ai/glm-5.toml b/providers/tensorx/models/z-ai/glm-5.toml index 6d547a7361..5feee3affa 100644 --- a/providers/tensorx/models/z-ai/glm-5.toml +++ b/providers/tensorx/models/z-ai/glm-5.toml @@ -1,7 +1,8 @@ +# Effort: reasoning_effort = ; "none" disables reasoning base_model = "zhipuai/glm-5" [[reasoning_options]] -type = "effort" # API: {"reasoning_effort": }; "none" disables reasoning +type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] [cost] diff --git a/providers/tensorx/models/z-ai/glm-5v-turbo.toml b/providers/tensorx/models/z-ai/glm-5v-turbo.toml index c16e5d0679..ff12f7d1a7 100644 --- a/providers/tensorx/models/z-ai/glm-5v-turbo.toml +++ b/providers/tensorx/models/z-ai/glm-5v-turbo.toml @@ -1,10 +1,12 @@ +# Toggle: chat_template_kwargs.enable_thinking = true|false (default on) +# Effort: reasoning_effort = ; "none" disables reasoning base_model = "zhipuai/glm-5v-turbo" [[reasoning_options]] -type = "toggle" # API: {"chat_template_kwargs": {"enable_thinking": false}} (default on) +type = "toggle" [[reasoning_options]] -type = "effort" # API: {"reasoning_effort": }; "none" disables reasoning +type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] [cost] From 7f2df40304d3a704060d32f5354b144d82610da2 Mon Sep 17 00:00:00 2001 From: bu6n Date: Tue, 4 Aug 2026 06:47:26 +0200 Subject: [PATCH 03/14] chore(tensorx): sync output limits and cache pricing from own API Source: https://api.tensorx.ai/v1/model/info - max_output_tokens is published per model and was previously missing or stale on ten entries (deepseek-v4-*, kimi-k2.6/k2.7-code/k3, glm-5.1, glm-5.2, minimax-m3, qwen3.5-9b) - deepseek-v4-flash-0731 cache_read corrected 0.06 -> 0.0625 cache_creation_input_token_cost is null for every model in the catalog, so cache_write is left at its authored value rather than being dropped: a null there means "not published", not "not charged". --- .../tensorx/models/deepseek/deepseek-v4-flash-0731.toml | 7 ++++--- providers/tensorx/models/deepseek/deepseek-v4-flash.toml | 3 ++- providers/tensorx/models/deepseek/deepseek-v4-pro.toml | 3 ++- providers/tensorx/models/minimax/minimax-m3.toml | 4 ++-- providers/tensorx/models/moonshotai/kimi-k2.6.toml | 3 +++ providers/tensorx/models/moonshotai/kimi-k2.7-code.toml | 3 +++ providers/tensorx/models/moonshotai/kimi-k3.toml | 7 +++++-- providers/tensorx/models/qwen/qwen3.5-9b.toml | 3 +++ providers/tensorx/models/z-ai/glm-5.1.toml | 4 ++-- providers/tensorx/models/z-ai/glm-5.2.toml | 3 ++- 10 files changed, 28 insertions(+), 12 deletions(-) diff --git a/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml b/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml index e775f90948..8c7ae2bdb7 100644 --- a/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml +++ b/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml @@ -6,8 +6,9 @@ type = "toggle" [cost] input = 0.25 -output = 0.30 -cache_read = 0.06 +output = 0.3 +cache_read = 0.0625 [limit] -context = 1048576 +context = 1_048_576 +output = 64_000 diff --git a/providers/tensorx/models/deepseek/deepseek-v4-flash.toml b/providers/tensorx/models/deepseek/deepseek-v4-flash.toml index aa2068bd2b..934e1d58fe 100644 --- a/providers/tensorx/models/deepseek/deepseek-v4-flash.toml +++ b/providers/tensorx/models/deepseek/deepseek-v4-flash.toml @@ -11,4 +11,5 @@ cache_read = 0.0375 cache_write = 0.1875 [limit] -context = 1048576 +context = 1_048_576 +output = 64_000 diff --git a/providers/tensorx/models/deepseek/deepseek-v4-pro.toml b/providers/tensorx/models/deepseek/deepseek-v4-pro.toml index 71d6f837ba..48919a414a 100644 --- a/providers/tensorx/models/deepseek/deepseek-v4-pro.toml +++ b/providers/tensorx/models/deepseek/deepseek-v4-pro.toml @@ -11,4 +11,5 @@ cache_read = 0.4375 cache_write = 2.185 [limit] -context = 1048576 +context = 1_048_576 +output = 64_000 diff --git a/providers/tensorx/models/minimax/minimax-m3.toml b/providers/tensorx/models/minimax/minimax-m3.toml index fd320e2283..1bb0971570 100644 --- a/providers/tensorx/models/minimax/minimax-m3.toml +++ b/providers/tensorx/models/minimax/minimax-m3.toml @@ -10,5 +10,5 @@ output = 2 cache_read = 0.1 [limit] -context = 1048576 -output = 131072 +context = 1_048_576 +output = 64_000 diff --git a/providers/tensorx/models/moonshotai/kimi-k2.6.toml b/providers/tensorx/models/moonshotai/kimi-k2.6.toml index 128f94094d..b27b2030b1 100644 --- a/providers/tensorx/models/moonshotai/kimi-k2.6.toml +++ b/providers/tensorx/models/moonshotai/kimi-k2.6.toml @@ -9,3 +9,6 @@ input = 1 output = 4 cache_read = 0.25 cache_write = 1.25 + +[limit] +output = 64_000 diff --git a/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml b/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml index 1a404e46d6..a19e4ac666 100644 --- a/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml +++ b/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml @@ -8,3 +8,6 @@ type = "toggle" input = 1.25 output = 4.5 cache_read = 0.3125 + +[limit] +output = 64_000 diff --git a/providers/tensorx/models/moonshotai/kimi-k3.toml b/providers/tensorx/models/moonshotai/kimi-k3.toml index 403c0b14a0..0ed892c0fe 100644 --- a/providers/tensorx/models/moonshotai/kimi-k3.toml +++ b/providers/tensorx/models/moonshotai/kimi-k3.toml @@ -6,6 +6,9 @@ base_model = "moonshotai/kimi-k3" type = "toggle" [cost] -input = 3.00 -output = 15.00 +input = 3 +output = 15 cache_read = 0.75 + +[limit] +output = 64_000 diff --git a/providers/tensorx/models/qwen/qwen3.5-9b.toml b/providers/tensorx/models/qwen/qwen3.5-9b.toml index 6419ca38b1..c3d0bd7e62 100644 --- a/providers/tensorx/models/qwen/qwen3.5-9b.toml +++ b/providers/tensorx/models/qwen/qwen3.5-9b.toml @@ -10,3 +10,6 @@ input = 0.15 output = 0.2 cache_read = 0.0375 cache_write = 0.1875 + +[limit] +output = 262_144 diff --git a/providers/tensorx/models/z-ai/glm-5.1.toml b/providers/tensorx/models/z-ai/glm-5.1.toml index 1ff0297c3a..02c82a4bbf 100644 --- a/providers/tensorx/models/z-ai/glm-5.1.toml +++ b/providers/tensorx/models/z-ai/glm-5.1.toml @@ -16,5 +16,5 @@ cache_read = 0.35 cache_write = 1.75 [limit] -context = 202752 -output = 202752 +context = 202_752 +output = 64_000 diff --git a/providers/tensorx/models/z-ai/glm-5.2.toml b/providers/tensorx/models/z-ai/glm-5.2.toml index 2aef9e70ff..a74689fe5b 100644 --- a/providers/tensorx/models/z-ai/glm-5.2.toml +++ b/providers/tensorx/models/z-ai/glm-5.2.toml @@ -15,4 +15,5 @@ output = 4.5 cache_read = 0.375 [limit] -context = 1048576 +context = 1_048_576 +output = 64_000 From a732e279f8072d43f4f0eeef0a909064b8e5edb6 Mon Sep 17 00:00:00 2001 From: bu6n Date: Tue, 4 Aug 2026 07:00:17 +0200 Subject: [PATCH 04/14] fix(tensorx): declare reasoning side channel and kimi-k2.5 thinking toggle --- providers/tensorx/models/deepseek/deepseek-r1-0528.toml | 3 +++ providers/tensorx/models/deepseek/deepseek-v3.2.toml | 3 +++ .../tensorx/models/deepseek/deepseek-v4-flash-0731.toml | 3 +++ providers/tensorx/models/deepseek/deepseek-v4-flash.toml | 3 +++ providers/tensorx/models/deepseek/deepseek-v4-pro.toml | 3 +++ providers/tensorx/models/minimax/minimax-m2.5.toml | 3 +++ providers/tensorx/models/minimax/minimax-m3.toml | 3 +++ providers/tensorx/models/moonshotai/kimi-k2.5.toml | 8 +++++++- providers/tensorx/models/moonshotai/kimi-k2.6.toml | 3 +++ providers/tensorx/models/moonshotai/kimi-k2.7-code.toml | 3 +++ providers/tensorx/models/moonshotai/kimi-k3.toml | 3 +++ providers/tensorx/models/qwen/qwen3.5-122b-a10b.toml | 3 +++ providers/tensorx/models/qwen/qwen3.5-9b.toml | 3 +++ providers/tensorx/models/z-ai/glm-5-turbo.toml | 3 +++ providers/tensorx/models/z-ai/glm-5.1.toml | 3 +++ providers/tensorx/models/z-ai/glm-5.2.toml | 3 +++ providers/tensorx/models/z-ai/glm-5.toml | 3 +++ providers/tensorx/models/z-ai/glm-5v-turbo.toml | 3 +++ 18 files changed, 58 insertions(+), 1 deletion(-) diff --git a/providers/tensorx/models/deepseek/deepseek-r1-0528.toml b/providers/tensorx/models/deepseek/deepseek-r1-0528.toml index 9a30b0a01f..9d2e14ef42 100644 --- a/providers/tensorx/models/deepseek/deepseek-r1-0528.toml +++ b/providers/tensorx/models/deepseek/deepseek-r1-0528.toml @@ -8,6 +8,9 @@ last_updated = "2025-05-28" type = "effort" values = ["minimal", "low", "medium", "high", "xhigh", "max"] +[interleaved] +field = "reasoning_content" + [cost] input = 0.66 output = 2.6 diff --git a/providers/tensorx/models/deepseek/deepseek-v3.2.toml b/providers/tensorx/models/deepseek/deepseek-v3.2.toml index 348e51b711..491bf277d9 100644 --- a/providers/tensorx/models/deepseek/deepseek-v3.2.toml +++ b/providers/tensorx/models/deepseek/deepseek-v3.2.toml @@ -15,6 +15,9 @@ open_weights = true type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +[interleaved] +field = "reasoning_content" + [cost] input = 0.3 output = 0.5 diff --git a/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml b/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml index 8c7ae2bdb7..cea139857e 100644 --- a/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml +++ b/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml @@ -4,6 +4,9 @@ base_model = "deepseek/deepseek-v4-flash-0731" [[reasoning_options]] type = "toggle" +[interleaved] +field = "reasoning_content" + [cost] input = 0.25 output = 0.3 diff --git a/providers/tensorx/models/deepseek/deepseek-v4-flash.toml b/providers/tensorx/models/deepseek/deepseek-v4-flash.toml index 934e1d58fe..e0e19b5041 100644 --- a/providers/tensorx/models/deepseek/deepseek-v4-flash.toml +++ b/providers/tensorx/models/deepseek/deepseek-v4-flash.toml @@ -4,6 +4,9 @@ base_model = "deepseek/deepseek-v4-flash" [[reasoning_options]] type = "toggle" +[interleaved] +field = "reasoning_content" + [cost] input = 0.15 output = 0.3 diff --git a/providers/tensorx/models/deepseek/deepseek-v4-pro.toml b/providers/tensorx/models/deepseek/deepseek-v4-pro.toml index 48919a414a..ae9d34f09a 100644 --- a/providers/tensorx/models/deepseek/deepseek-v4-pro.toml +++ b/providers/tensorx/models/deepseek/deepseek-v4-pro.toml @@ -4,6 +4,9 @@ base_model = "deepseek/deepseek-v4-pro" [[reasoning_options]] type = "toggle" +[interleaved] +field = "reasoning_content" + [cost] input = 1.75 output = 3.5 diff --git a/providers/tensorx/models/minimax/minimax-m2.5.toml b/providers/tensorx/models/minimax/minimax-m2.5.toml index af9e83dc13..ff39dd12db 100644 --- a/providers/tensorx/models/minimax/minimax-m2.5.toml +++ b/providers/tensorx/models/minimax/minimax-m2.5.toml @@ -5,6 +5,9 @@ base_model = "minimax/MiniMax-M2.5" type = "effort" values = ["minimal", "low", "medium", "high", "xhigh", "max"] +[interleaved] +field = "reasoning_content" + [cost] input = 0.3 output = 1.2 diff --git a/providers/tensorx/models/minimax/minimax-m3.toml b/providers/tensorx/models/minimax/minimax-m3.toml index 1bb0971570..48eff16652 100644 --- a/providers/tensorx/models/minimax/minimax-m3.toml +++ b/providers/tensorx/models/minimax/minimax-m3.toml @@ -4,6 +4,9 @@ base_model = "minimax/MiniMax-M3" [[reasoning_options]] type = "toggle" +[interleaved] +field = "reasoning_content" + [cost] input = 0.4 output = 2 diff --git a/providers/tensorx/models/moonshotai/kimi-k2.5.toml b/providers/tensorx/models/moonshotai/kimi-k2.5.toml index 83821146bc..e14ff53bbe 100644 --- a/providers/tensorx/models/moonshotai/kimi-k2.5.toml +++ b/providers/tensorx/models/moonshotai/kimi-k2.5.toml @@ -1,5 +1,11 @@ +# Toggle: chat_template_kwargs.thinking = true|false (default on) base_model = "moonshotai/kimi-k2.5" -reasoning_options = [] + +[[reasoning_options]] +type = "toggle" + +[interleaved] +field = "reasoning_content" [cost] input = 0.5 diff --git a/providers/tensorx/models/moonshotai/kimi-k2.6.toml b/providers/tensorx/models/moonshotai/kimi-k2.6.toml index b27b2030b1..4eb9dbd777 100644 --- a/providers/tensorx/models/moonshotai/kimi-k2.6.toml +++ b/providers/tensorx/models/moonshotai/kimi-k2.6.toml @@ -4,6 +4,9 @@ base_model = "moonshotai/kimi-k2.6" [[reasoning_options]] type = "toggle" +[interleaved] +field = "reasoning_content" + [cost] input = 1 output = 4 diff --git a/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml b/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml index a19e4ac666..cb2a21846c 100644 --- a/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml +++ b/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml @@ -4,6 +4,9 @@ base_model = "moonshotai/kimi-k2.7-code" [[reasoning_options]] type = "toggle" +[interleaved] +field = "reasoning_content" + [cost] input = 1.25 output = 4.5 diff --git a/providers/tensorx/models/moonshotai/kimi-k3.toml b/providers/tensorx/models/moonshotai/kimi-k3.toml index 0ed892c0fe..43cee375f6 100644 --- a/providers/tensorx/models/moonshotai/kimi-k3.toml +++ b/providers/tensorx/models/moonshotai/kimi-k3.toml @@ -5,6 +5,9 @@ base_model = "moonshotai/kimi-k3" [[reasoning_options]] type = "toggle" +[interleaved] +field = "reasoning_content" + [cost] input = 3 output = 15 diff --git a/providers/tensorx/models/qwen/qwen3.5-122b-a10b.toml b/providers/tensorx/models/qwen/qwen3.5-122b-a10b.toml index fadb6545fa..f773843a0e 100644 --- a/providers/tensorx/models/qwen/qwen3.5-122b-a10b.toml +++ b/providers/tensorx/models/qwen/qwen3.5-122b-a10b.toml @@ -5,6 +5,9 @@ base_model = "alibaba/qwen3.5-122b-a10b" type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +[interleaved] +field = "reasoning_content" + [cost] input = 0.5 output = 3.5 diff --git a/providers/tensorx/models/qwen/qwen3.5-9b.toml b/providers/tensorx/models/qwen/qwen3.5-9b.toml index c3d0bd7e62..79ef102b6f 100644 --- a/providers/tensorx/models/qwen/qwen3.5-9b.toml +++ b/providers/tensorx/models/qwen/qwen3.5-9b.toml @@ -5,6 +5,9 @@ base_model = "alibaba/qwen3.5-9b" type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +[interleaved] +field = "reasoning_content" + [cost] input = 0.15 output = 0.2 diff --git a/providers/tensorx/models/z-ai/glm-5-turbo.toml b/providers/tensorx/models/z-ai/glm-5-turbo.toml index 9cde43e494..b549cb0c58 100644 --- a/providers/tensorx/models/z-ai/glm-5-turbo.toml +++ b/providers/tensorx/models/z-ai/glm-5-turbo.toml @@ -9,6 +9,9 @@ type = "toggle" type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +[interleaved] +field = "reasoning_content" + [cost] input = 1.2 output = 4 diff --git a/providers/tensorx/models/z-ai/glm-5.1.toml b/providers/tensorx/models/z-ai/glm-5.1.toml index 02c82a4bbf..ec2324116f 100644 --- a/providers/tensorx/models/z-ai/glm-5.1.toml +++ b/providers/tensorx/models/z-ai/glm-5.1.toml @@ -9,6 +9,9 @@ type = "toggle" type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +[interleaved] +field = "reasoning_content" + [cost] input = 1.4 output = 4.4 diff --git a/providers/tensorx/models/z-ai/glm-5.2.toml b/providers/tensorx/models/z-ai/glm-5.2.toml index a74689fe5b..dae334ea32 100644 --- a/providers/tensorx/models/z-ai/glm-5.2.toml +++ b/providers/tensorx/models/z-ai/glm-5.2.toml @@ -9,6 +9,9 @@ type = "toggle" type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +[interleaved] +field = "reasoning_content" + [cost] input = 1.5 output = 4.5 diff --git a/providers/tensorx/models/z-ai/glm-5.toml b/providers/tensorx/models/z-ai/glm-5.toml index 5feee3affa..550415c357 100644 --- a/providers/tensorx/models/z-ai/glm-5.toml +++ b/providers/tensorx/models/z-ai/glm-5.toml @@ -5,6 +5,9 @@ base_model = "zhipuai/glm-5" type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +[interleaved] +field = "reasoning_content" + [cost] input = 1 output = 3.2 diff --git a/providers/tensorx/models/z-ai/glm-5v-turbo.toml b/providers/tensorx/models/z-ai/glm-5v-turbo.toml index ff12f7d1a7..e945cb3d2e 100644 --- a/providers/tensorx/models/z-ai/glm-5v-turbo.toml +++ b/providers/tensorx/models/z-ai/glm-5v-turbo.toml @@ -9,6 +9,9 @@ type = "toggle" type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +[interleaved] +field = "reasoning_content" + [cost] input = 1.2 output = 4 From a81d094e138b7653be013ef408c2378308040e49 Mon Sep 17 00:00:00 2001 From: bu6n Date: Tue, 4 Aug 2026 07:42:55 +0200 Subject: [PATCH 05/14] fix(tensorx): honor local base_model, correct GLM effort controls --- packages/core/src/sync/providers/tensorx.ts | 13 ++++++++++++- .../models/deepseek/deepseek-v4-flash-0731.toml | 3 +++ .../tensorx/models/deepseek/deepseek-v4-flash.toml | 3 +++ .../tensorx/models/deepseek/deepseek-v4-pro.toml | 3 +++ providers/tensorx/models/z-ai/glm-5-turbo.toml | 10 ++++------ providers/tensorx/models/z-ai/glm-5.1.toml | 10 ++++------ providers/tensorx/models/z-ai/glm-5.2.toml | 8 +++----- providers/tensorx/models/z-ai/glm-5v-turbo.toml | 10 ++++------ 8 files changed, 36 insertions(+), 24 deletions(-) diff --git a/packages/core/src/sync/providers/tensorx.ts b/packages/core/src/sync/providers/tensorx.ts index ab0e02f61c..86f5c26d39 100644 --- a/packages/core/src/sync/providers/tensorx.ts +++ b/packages/core/src/sync/providers/tensorx.ts @@ -60,6 +60,13 @@ export const tensorx = { `Add the lab entry under \`models/\` (or hand-author the provider file) first. Skipped remote IDs: ${ids.map((id) => `\`${id}\``).join(", ")}`, ]; }, + missingNotice(paths) { + if (paths.length === 0) return []; + return [ + `${paths.length} local TensorX models were absent from /v1/model/info and were retained for manual lifecycle review.`, + `That endpoint is a per-key view, so absence can mean the sync key lacks access rather than the model being retired: ${paths.map((path) => `\`${path}\``).join(", ")}`, + ]; + }, async fetchModels() { const apiKey = process.env.TENSORX_API_KEY; if (!apiKey) { @@ -86,7 +93,11 @@ export const tensorx = { if (model.model_info.mode !== "chat") return undefined; const existing = context.existing(model.model_name); - const baseModel = resolveBaseModel(model.model_name); + // A base_model already authored locally wins over re-derivation. With + // preserveBaseModels false the runner will not put it back, so a resolution + // miss here (dropped alias, renamed lab entry, ID drift) would otherwise + // flatten the inherited lab fields into the provider TOML. + const baseModel = existing?.base_model ?? resolveBaseModel(model.model_name); // Nothing in this catalog can stand in for lab metadata — no display name, // no description, no release date — so an unknown model is reported for // hand-authoring instead of being invented. diff --git a/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml b/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml index cea139857e..043fc04bf4 100644 --- a/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml +++ b/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml @@ -1,4 +1,7 @@ # Toggle: chat_template_kwargs.thinking = true|false (default off) +# reasoning_effort is accepted here but not honored: low/high/max and an +# invalid value all produce the same reasoning-token distribution, so this +# host is toggle-only despite the lab exposing effort high|max. base_model = "deepseek/deepseek-v4-flash-0731" [[reasoning_options]] diff --git a/providers/tensorx/models/deepseek/deepseek-v4-flash.toml b/providers/tensorx/models/deepseek/deepseek-v4-flash.toml index e0e19b5041..71a4d392c8 100644 --- a/providers/tensorx/models/deepseek/deepseek-v4-flash.toml +++ b/providers/tensorx/models/deepseek/deepseek-v4-flash.toml @@ -1,4 +1,7 @@ # Toggle: chat_template_kwargs.thinking = true|false (default off) +# reasoning_effort is accepted here but not honored: low/high/max and an +# invalid value all produce the same reasoning-token distribution, so this +# host is toggle-only despite the lab exposing effort high|max. base_model = "deepseek/deepseek-v4-flash" [[reasoning_options]] diff --git a/providers/tensorx/models/deepseek/deepseek-v4-pro.toml b/providers/tensorx/models/deepseek/deepseek-v4-pro.toml index ae9d34f09a..b3bff278c6 100644 --- a/providers/tensorx/models/deepseek/deepseek-v4-pro.toml +++ b/providers/tensorx/models/deepseek/deepseek-v4-pro.toml @@ -1,4 +1,7 @@ # Toggle: chat_template_kwargs.thinking = true|false (default off) +# reasoning_effort is accepted here but not honored: low/high/max and an +# invalid value all produce the same reasoning-token distribution, so this +# host is toggle-only despite the lab exposing effort high|max. base_model = "deepseek/deepseek-v4-pro" [[reasoning_options]] diff --git a/providers/tensorx/models/z-ai/glm-5-turbo.toml b/providers/tensorx/models/z-ai/glm-5-turbo.toml index b549cb0c58..686e8f6b20 100644 --- a/providers/tensorx/models/z-ai/glm-5-turbo.toml +++ b/providers/tensorx/models/z-ai/glm-5-turbo.toml @@ -1,13 +1,11 @@ -# Toggle: chat_template_kwargs.enable_thinking = true|false (default on) -# Effort: reasoning_effort = ; "none" disables reasoning +# Off is effort=none; chat_template_kwargs.enable_thinking also toggles, but +# `none` already expresses it, so effort is the single declared control. +# Effort: reasoning_effort = none|low|medium|high (verified; others rejected 400) base_model = "zhipuai/glm-5-turbo" -[[reasoning_options]] -type = "toggle" - [[reasoning_options]] type = "effort" -values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +values = ["none", "low", "medium", "high"] [interleaved] field = "reasoning_content" diff --git a/providers/tensorx/models/z-ai/glm-5.1.toml b/providers/tensorx/models/z-ai/glm-5.1.toml index ec2324116f..281a6b268d 100644 --- a/providers/tensorx/models/z-ai/glm-5.1.toml +++ b/providers/tensorx/models/z-ai/glm-5.1.toml @@ -1,13 +1,11 @@ -# Toggle: chat_template_kwargs.enable_thinking = true|false (default on) -# Effort: reasoning_effort = ; "none" disables reasoning +# Off is effort=none; chat_template_kwargs.enable_thinking also toggles, but +# `none` already expresses it, so effort is the single declared control. +# Effort: reasoning_effort = none|low|medium|high|max (verified; others rejected 400) base_model = "zhipuai/glm-5.1" -[[reasoning_options]] -type = "toggle" - [[reasoning_options]] type = "effort" -values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +values = ["none", "low", "medium", "high", "max"] [interleaved] field = "reasoning_content" diff --git a/providers/tensorx/models/z-ai/glm-5.2.toml b/providers/tensorx/models/z-ai/glm-5.2.toml index dae334ea32..8601224b0b 100644 --- a/providers/tensorx/models/z-ai/glm-5.2.toml +++ b/providers/tensorx/models/z-ai/glm-5.2.toml @@ -1,10 +1,8 @@ -# Toggle: chat_template_kwargs.enable_thinking = true|false (default on) -# Effort: reasoning_effort = ; "none" disables reasoning +# Off is effort=none; chat_template_kwargs.enable_thinking also toggles, but +# `none` already expresses it, so effort is the single declared control. +# Effort: reasoning_effort = none|minimal|low|medium|high|xhigh|max (verified; others rejected 400) base_model = "zhipuai/glm-5.2" -[[reasoning_options]] -type = "toggle" - [[reasoning_options]] type = "effort" values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] diff --git a/providers/tensorx/models/z-ai/glm-5v-turbo.toml b/providers/tensorx/models/z-ai/glm-5v-turbo.toml index e945cb3d2e..ac2ba3cd3e 100644 --- a/providers/tensorx/models/z-ai/glm-5v-turbo.toml +++ b/providers/tensorx/models/z-ai/glm-5v-turbo.toml @@ -1,13 +1,11 @@ -# Toggle: chat_template_kwargs.enable_thinking = true|false (default on) -# Effort: reasoning_effort = ; "none" disables reasoning +# Off is effort=none; chat_template_kwargs.enable_thinking also toggles, but +# `none` already expresses it, so effort is the single declared control. +# Effort: reasoning_effort = none|low|medium|high (verified; others rejected 400) base_model = "zhipuai/glm-5v-turbo" -[[reasoning_options]] -type = "toggle" - [[reasoning_options]] type = "effort" -values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +values = ["none", "low", "medium", "high"] [interleaved] field = "reasoning_content" From 56807afd6b4342b7355c76bbdbf3ec2627c45a39 Mon Sep 17 00:00:00 2001 From: bu6n Date: Tue, 4 Aug 2026 08:37:51 +0200 Subject: [PATCH 06/14] fix(tensorx): guard partial pricing and author measured reasoning controls --- packages/core/src/sync/providers/tensorx.ts | 38 +++++++++++-------- .../tensorx/models/moonshotai/kimi-k2.5.toml | 8 ++-- .../tensorx/models/moonshotai/kimi-k2.6.toml | 2 + .../models/moonshotai/kimi-k2.7-code.toml | 2 + .../tensorx/models/moonshotai/kimi-k3.toml | 6 +++ .../tensorx/models/z-ai/glm-5-turbo.toml | 9 ++--- providers/tensorx/models/z-ai/glm-5.1.toml | 9 ++--- providers/tensorx/models/z-ai/glm-5.2.toml | 11 ++++-- providers/tensorx/models/z-ai/glm-5.toml | 6 ++- .../tensorx/models/z-ai/glm-5v-turbo.toml | 9 ++--- 10 files changed, 60 insertions(+), 40 deletions(-) diff --git a/packages/core/src/sync/providers/tensorx.ts b/packages/core/src/sync/providers/tensorx.ts index 86f5c26d39..c7fa301aa7 100644 --- a/packages/core/src/sync/providers/tensorx.ts +++ b/packages/core/src/sync/providers/tensorx.ts @@ -103,10 +103,8 @@ export const tensorx = { // hand-authoring instead of being invented. if (baseModel === undefined && existing === undefined) return undefined; - return { - id: model.model_name, - model: buildTensorXModel(model, baseModel, existing), - }; + const built = buildTensorXModel(model, baseModel, existing); + return built === undefined ? undefined : { id: model.model_name, model: built }; }, } satisfies SyncProvider; @@ -114,7 +112,7 @@ function buildTensorXModel( model: TensorXModel, baseModel: string | undefined, existing: ExistingModel | undefined, -): SyncedModel { +): SyncedModel | undefined { const info = model.model_info; const limit = { @@ -122,16 +120,26 @@ function buildTensorXModel( output: info.max_output_tokens ?? existing?.limit?.output, }; - const cost = { - ...existing?.cost, - input: perMillion(info.input_cost_per_token) ?? existing?.cost?.input, - output: perMillion(info.output_cost_per_token) ?? existing?.cost?.output, - cache_read: perMillion(info.cache_read_input_token_cost) ?? existing?.cost?.cache_read, - // cache_creation_input_token_cost is null for every model in the catalog, so - // a null is "not published" rather than "not charged". Keep the authored - // price; it publishes real values as soon as TensorX fills the field in. - cache_write: perMillion(info.cache_creation_input_token_cost) ?? existing?.cost?.cache_write, - }; + const input = perMillion(info.input_cost_per_token) ?? existing?.cost?.input; + const output = perMillion(info.output_cost_per_token) ?? existing?.cost?.output; + // Pricing is published only as a complete pair. A base_model file validates + // against a deepPartial schema, so a half-resolved cost would be written out + // as real pricing rather than rejected; a full model would abort the sync. + const cost = input === undefined || output === undefined + ? existing?.cost + : { + ...existing?.cost, + input, + output, + cache_read: perMillion(info.cache_read_input_token_cost) ?? existing?.cost?.cache_read, + // cache_creation_input_token_cost is null for every model in the catalog, + // so a null is "not published" rather than "not charged". Keep the + // authored price; real values publish as soon as TensorX fills it in. + cache_write: perMillion(info.cache_creation_input_token_cost) ?? existing?.cost?.cache_write, + }; + + // Never bring a brand-new model into the catalog without real pricing. + if (existing === undefined && cost === undefined) return undefined; const toolFlags = [info.supports_tool_choice, info.supports_function_calling] .filter((flag) => flag !== null && flag !== undefined); diff --git a/providers/tensorx/models/moonshotai/kimi-k2.5.toml b/providers/tensorx/models/moonshotai/kimi-k2.5.toml index e14ff53bbe..871007b6f9 100644 --- a/providers/tensorx/models/moonshotai/kimi-k2.5.toml +++ b/providers/tensorx/models/moonshotai/kimi-k2.5.toml @@ -1,8 +1,8 @@ -# Toggle: chat_template_kwargs.thinking = true|false (default on) +# Neither control is honored here: chat_template_kwargs.thinking and +# reasoning_effort (including none, and an invalid value) all leave the +# reasoning-token count unchanged over 8 runs. Reasoning is always on. base_model = "moonshotai/kimi-k2.5" - -[[reasoning_options]] -type = "toggle" +reasoning_options = [] [interleaved] field = "reasoning_content" diff --git a/providers/tensorx/models/moonshotai/kimi-k2.6.toml b/providers/tensorx/models/moonshotai/kimi-k2.6.toml index 4eb9dbd777..1457ff3269 100644 --- a/providers/tensorx/models/moonshotai/kimi-k2.6.toml +++ b/providers/tensorx/models/moonshotai/kimi-k2.6.toml @@ -1,4 +1,6 @@ # Toggle: chat_template_kwargs.thinking = true|false (default on) +# reasoning_effort is accepted but not honored here — an invalid value and +# none both leave the reasoning-token count unchanged — so this is toggle-only. base_model = "moonshotai/kimi-k2.6" [[reasoning_options]] diff --git a/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml b/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml index cb2a21846c..2456682013 100644 --- a/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml +++ b/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml @@ -1,4 +1,6 @@ # Toggle: chat_template_kwargs.thinking = true|false (default on) +# reasoning_effort is accepted but not honored here — an invalid value and +# none both leave the reasoning-token count unchanged — so this is toggle-only. base_model = "moonshotai/kimi-k2.7-code" [[reasoning_options]] diff --git a/providers/tensorx/models/moonshotai/kimi-k3.toml b/providers/tensorx/models/moonshotai/kimi-k3.toml index 43cee375f6..8b903afe89 100644 --- a/providers/tensorx/models/moonshotai/kimi-k3.toml +++ b/providers/tensorx/models/moonshotai/kimi-k3.toml @@ -1,10 +1,16 @@ # AI SDK auto-discovers native IDs via /v1/models — field values map those IDs # Toggle: chat_template_kwargs.thinking = true|false (default on) +# Effort: reasoning_effort = low|high|max; invalid values return 400 and low +# measurably lowers the reasoning-token count. Matches first-party Moonshot. base_model = "moonshotai/kimi-k3" [[reasoning_options]] type = "toggle" +[[reasoning_options]] +type = "effort" +values = ["low", "high", "max"] + [interleaved] field = "reasoning_content" diff --git a/providers/tensorx/models/z-ai/glm-5-turbo.toml b/providers/tensorx/models/z-ai/glm-5-turbo.toml index 686e8f6b20..7237603bb0 100644 --- a/providers/tensorx/models/z-ai/glm-5-turbo.toml +++ b/providers/tensorx/models/z-ai/glm-5-turbo.toml @@ -1,11 +1,10 @@ -# Off is effort=none; chat_template_kwargs.enable_thinking also toggles, but -# `none` already expresses it, so effort is the single declared control. -# Effort: reasoning_effort = none|low|medium|high (verified; others rejected 400) +# Toggle: chat_template_kwargs.enable_thinking = true|false (default on) +# No reasoning tokens were observed on this host under any setting, so the +# toggle is carried from first-party z.ai rather than verified here. base_model = "zhipuai/glm-5-turbo" [[reasoning_options]] -type = "effort" -values = ["none", "low", "medium", "high"] +type = "toggle" [interleaved] field = "reasoning_content" diff --git a/providers/tensorx/models/z-ai/glm-5.1.toml b/providers/tensorx/models/z-ai/glm-5.1.toml index 281a6b268d..5378fc7c25 100644 --- a/providers/tensorx/models/z-ai/glm-5.1.toml +++ b/providers/tensorx/models/z-ai/glm-5.1.toml @@ -1,11 +1,10 @@ -# Off is effort=none; chat_template_kwargs.enable_thinking also toggles, but -# `none` already expresses it, so effort is the single declared control. -# Effort: reasoning_effort = none|low|medium|high|max (verified; others rejected 400) +# Toggle: chat_template_kwargs.enable_thinking = true|false (default on) +# reasoning_effort is accepted but its graded levels were not separable here; +# first-party z.ai exposes only the toggle, so that is the declared control. base_model = "zhipuai/glm-5.1" [[reasoning_options]] -type = "effort" -values = ["none", "low", "medium", "high", "max"] +type = "toggle" [interleaved] field = "reasoning_content" diff --git a/providers/tensorx/models/z-ai/glm-5.2.toml b/providers/tensorx/models/z-ai/glm-5.2.toml index 8601224b0b..5bc8c2f958 100644 --- a/providers/tensorx/models/z-ai/glm-5.2.toml +++ b/providers/tensorx/models/z-ai/glm-5.2.toml @@ -1,11 +1,14 @@ -# Off is effort=none; chat_template_kwargs.enable_thinking also toggles, but -# `none` already expresses it, so effort is the single declared control. -# Effort: reasoning_effort = none|minimal|low|medium|high|xhigh|max (verified; others rejected 400) +# Toggle: chat_template_kwargs.enable_thinking = true|false (default on) +# Effort: reasoning_effort = high|max — z.ai maps none|minimal to off, +# low|medium to high and xhigh to max, so high|max are the effective levels. base_model = "zhipuai/glm-5.2" +[[reasoning_options]] +type = "toggle" + [[reasoning_options]] type = "effort" -values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +values = ["high", "max"] [interleaved] field = "reasoning_content" diff --git a/providers/tensorx/models/z-ai/glm-5.toml b/providers/tensorx/models/z-ai/glm-5.toml index 550415c357..fc34500580 100644 --- a/providers/tensorx/models/z-ai/glm-5.toml +++ b/providers/tensorx/models/z-ai/glm-5.toml @@ -1,9 +1,11 @@ -# Effort: reasoning_effort = ; "none" disables reasoning +# Effort: reasoning_effort = none|high|max; none verified to disable reasoning. +# chat_template_kwargs.enable_thinking is accepted but not honored here, and +# the graded levels were not separable, so only z.ai's effective levels list. base_model = "zhipuai/glm-5" [[reasoning_options]] type = "effort" -values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +values = ["none", "high", "max"] [interleaved] field = "reasoning_content" diff --git a/providers/tensorx/models/z-ai/glm-5v-turbo.toml b/providers/tensorx/models/z-ai/glm-5v-turbo.toml index ac2ba3cd3e..cc93bd2dda 100644 --- a/providers/tensorx/models/z-ai/glm-5v-turbo.toml +++ b/providers/tensorx/models/z-ai/glm-5v-turbo.toml @@ -1,11 +1,10 @@ -# Off is effort=none; chat_template_kwargs.enable_thinking also toggles, but -# `none` already expresses it, so effort is the single declared control. -# Effort: reasoning_effort = none|low|medium|high (verified; others rejected 400) +# Toggle: chat_template_kwargs.enable_thinking = true|false (default on) +# No reasoning tokens were observed on this host under any setting, so the +# toggle is carried from first-party z.ai rather than verified here. base_model = "zhipuai/glm-5v-turbo" [[reasoning_options]] -type = "effort" -values = ["none", "low", "medium", "high"] +type = "toggle" [interleaved] field = "reasoning_content" From d49ed5c86d71ffb6b5956fd3db79da89f017197f Mon Sep 17 00:00:00 2001 From: bu6n Date: Tue, 4 Aug 2026 09:52:24 +0200 Subject: [PATCH 07/14] fix(tensorx): publish only measured GLM-5 on/off, stop auto-creating reasoners --- packages/core/src/sync/providers/tensorx.ts | 10 ++++++++-- providers/tensorx/models/z-ai/glm-5.toml | 11 ++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/core/src/sync/providers/tensorx.ts b/packages/core/src/sync/providers/tensorx.ts index c7fa301aa7..ce7d827e8d 100644 --- a/packages/core/src/sync/providers/tensorx.ts +++ b/packages/core/src/sync/providers/tensorx.ts @@ -42,6 +42,12 @@ export const tensorx = { id: "tensorx", name: "TensorX", modelsDir: "providers/tensorx/models", + // /v1/model/info carries no reasoning controls and no side-channel field, so + // a created reasoner would be published with the runner's fallback + // `reasoning_options = []` — an assertion of "no caller control" that nothing + // here backs — and no `interleaved`. New IDs are reported for hand-authoring + // instead; updates to existing TOMLs are unaffected. + skipCreates: true, preserveBaseModels: false, // /v1/model/info returns a per-key view: a key scoped to a model group sees // only that group, and chat requests for the rest fail with 403 rather than @@ -56,8 +62,8 @@ export const tensorx = { skippedNotice(ids) { if (ids.length === 0) return []; return [ - `${ids.length} TensorX chat models were not created because /v1/model/info publishes no name, description, or release date to author a model from.`, - `Add the lab entry under \`models/\` (or hand-author the provider file) first. Skipped remote IDs: ${ids.map((id) => `\`${id}\``).join(", ")}`, + `${ids.length} TensorX chat models were not created: /v1/model/info publishes no name, description, or release date, and no reasoning controls or side-channel field, so a complete model cannot be authored safely.`, + `Add the lab entry under \`models/\` and hand-author \`reasoning_options\` / \`interleaved\` against the live API. Skipped remote IDs: ${ids.map((id) => `\`${id}\``).join(", ")}`, ]; }, missingNotice(paths) { diff --git a/providers/tensorx/models/z-ai/glm-5.toml b/providers/tensorx/models/z-ai/glm-5.toml index fc34500580..dea547aa61 100644 --- a/providers/tensorx/models/z-ai/glm-5.toml +++ b/providers/tensorx/models/z-ai/glm-5.toml @@ -1,11 +1,12 @@ -# Effort: reasoning_effort = none|high|max; none verified to disable reasoning. -# chat_template_kwargs.enable_thinking is accepted but not honored here, and -# the graded levels were not separable, so only z.ai's effective levels list. +# Toggle: reasoning_effort = none turns reasoning off (verified: 0 reasoning +# tokens); any other accepted value leaves it on. chat_template_kwargs. +# enable_thinking is accepted but is a no-op here, and no graded level was +# separable from another, so only on/off is published. First-party z.ai is +# likewise toggle-only for GLM-5. base_model = "zhipuai/glm-5" [[reasoning_options]] -type = "effort" -values = ["none", "high", "max"] +type = "toggle" [interleaved] field = "reasoning_content" From b318da2cc3409cef7a47cb9754fafe85aa0486ef Mon Sep 17 00:00:00 2001 From: bu6n Date: Tue, 4 Aug 2026 10:14:02 +0200 Subject: [PATCH 08/14] fix(tensorx): verify GLM turbo reasoning controls via reasoning_content --- providers/tensorx/models/z-ai/glm-5-turbo.toml | 9 ++++++--- providers/tensorx/models/z-ai/glm-5v-turbo.toml | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/providers/tensorx/models/z-ai/glm-5-turbo.toml b/providers/tensorx/models/z-ai/glm-5-turbo.toml index 7237603bb0..9f444b466d 100644 --- a/providers/tensorx/models/z-ai/glm-5-turbo.toml +++ b/providers/tensorx/models/z-ai/glm-5-turbo.toml @@ -1,6 +1,9 @@ -# Toggle: chat_template_kwargs.enable_thinking = true|false (default on) -# No reasoning tokens were observed on this host under any setting, so the -# toggle is carried from first-party z.ai rather than verified here. +# Toggle: chat_template_kwargs.enable_thinking = true|false (default on). +# Verified: false empties reasoning_content, true and the default fill it. +# This host streams reasoning into reasoning_content but does not count it in +# usage.reasoning_tokens, which reads 0 even while reasoning runs — measure +# the field, not the token count. reasoning_effort = none also suppresses it, +# but no graded level was separable, so only on/off is published. base_model = "zhipuai/glm-5-turbo" [[reasoning_options]] diff --git a/providers/tensorx/models/z-ai/glm-5v-turbo.toml b/providers/tensorx/models/z-ai/glm-5v-turbo.toml index cc93bd2dda..b884c3f19d 100644 --- a/providers/tensorx/models/z-ai/glm-5v-turbo.toml +++ b/providers/tensorx/models/z-ai/glm-5v-turbo.toml @@ -1,6 +1,9 @@ -# Toggle: chat_template_kwargs.enable_thinking = true|false (default on) -# No reasoning tokens were observed on this host under any setting, so the -# toggle is carried from first-party z.ai rather than verified here. +# Toggle: chat_template_kwargs.enable_thinking = true|false (default on). +# Verified: false empties reasoning_content, true and the default fill it. +# This host streams reasoning into reasoning_content but does not count it in +# usage.reasoning_tokens, which reads 0 even while reasoning runs — measure +# the field, not the token count. reasoning_effort = none also suppresses it, +# but no graded level was separable, so only on/off is published. base_model = "zhipuai/glm-5v-turbo" [[reasoning_options]] From ae50adabc169972b62a09fed74397908c3169bc0 Mon Sep 17 00:00:00 2001 From: bu6n Date: Tue, 4 Aug 2026 10:49:55 +0200 Subject: [PATCH 09/14] fix(tensorx): re-verify reasoning controls against reasoning_content --- .../models/deepseek/deepseek-v4-flash-0731.toml | 7 ++++--- .../tensorx/models/deepseek/deepseek-v4-flash.toml | 7 ++++--- .../tensorx/models/deepseek/deepseek-v4-pro.toml | 7 ++++--- providers/tensorx/models/moonshotai/kimi-k2.5.toml | 7 ++++--- providers/tensorx/models/moonshotai/kimi-k2.6.toml | 7 ++++--- .../tensorx/models/moonshotai/kimi-k2.7-code.toml | 7 ++++--- providers/tensorx/models/moonshotai/kimi-k3.toml | 13 ++++++------- providers/tensorx/models/z-ai/glm-5.toml | 9 +++++---- 8 files changed, 35 insertions(+), 29 deletions(-) diff --git a/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml b/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml index 043fc04bf4..c109b56717 100644 --- a/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml +++ b/providers/tensorx/models/deepseek/deepseek-v4-flash-0731.toml @@ -1,7 +1,8 @@ # Toggle: chat_template_kwargs.thinking = true|false (default off) -# reasoning_effort is accepted here but not honored: low/high/max and an -# invalid value all produce the same reasoning-token distribution, so this -# host is toggle-only despite the lab exposing effort high|max. +# reasoning_effort is accepted but not honored. Measured by reasoning_content +# length — not usage.reasoning_tokens, which this host under-reports — low, +# high, max and an invalid value all fall in the same range, so this host is +# toggle-only despite the lab exposing effort high|max. base_model = "deepseek/deepseek-v4-flash-0731" [[reasoning_options]] diff --git a/providers/tensorx/models/deepseek/deepseek-v4-flash.toml b/providers/tensorx/models/deepseek/deepseek-v4-flash.toml index 71a4d392c8..08fa020600 100644 --- a/providers/tensorx/models/deepseek/deepseek-v4-flash.toml +++ b/providers/tensorx/models/deepseek/deepseek-v4-flash.toml @@ -1,7 +1,8 @@ # Toggle: chat_template_kwargs.thinking = true|false (default off) -# reasoning_effort is accepted here but not honored: low/high/max and an -# invalid value all produce the same reasoning-token distribution, so this -# host is toggle-only despite the lab exposing effort high|max. +# reasoning_effort is accepted but not honored. Measured by reasoning_content +# length — not usage.reasoning_tokens, which this host under-reports — low, +# high, max and an invalid value all fall in the same range, so this host is +# toggle-only despite the lab exposing effort high|max. base_model = "deepseek/deepseek-v4-flash" [[reasoning_options]] diff --git a/providers/tensorx/models/deepseek/deepseek-v4-pro.toml b/providers/tensorx/models/deepseek/deepseek-v4-pro.toml index b3bff278c6..fec75b2d13 100644 --- a/providers/tensorx/models/deepseek/deepseek-v4-pro.toml +++ b/providers/tensorx/models/deepseek/deepseek-v4-pro.toml @@ -1,7 +1,8 @@ # Toggle: chat_template_kwargs.thinking = true|false (default off) -# reasoning_effort is accepted here but not honored: low/high/max and an -# invalid value all produce the same reasoning-token distribution, so this -# host is toggle-only despite the lab exposing effort high|max. +# reasoning_effort is accepted but not honored. Measured by reasoning_content +# length — not usage.reasoning_tokens, which this host under-reports — low, +# high, max and an invalid value all fall in the same range, so this host is +# toggle-only despite the lab exposing effort high|max. base_model = "deepseek/deepseek-v4-pro" [[reasoning_options]] diff --git a/providers/tensorx/models/moonshotai/kimi-k2.5.toml b/providers/tensorx/models/moonshotai/kimi-k2.5.toml index 871007b6f9..db3656d067 100644 --- a/providers/tensorx/models/moonshotai/kimi-k2.5.toml +++ b/providers/tensorx/models/moonshotai/kimi-k2.5.toml @@ -1,6 +1,7 @@ -# Neither control is honored here: chat_template_kwargs.thinking and -# reasoning_effort (including none, and an invalid value) all leave the -# reasoning-token count unchanged over 8 runs. Reasoning is always on. +# No caller control. Measured by reasoning_content length over 6 runs each, +# chat_template_kwargs.thinking = false and reasoning_effort = none both leave +# reasoning_content filled (0/6 empty). usage.reasoning_tokens is not the +# signal here because this host under-reports it. Reasoning is always on. base_model = "moonshotai/kimi-k2.5" reasoning_options = [] diff --git a/providers/tensorx/models/moonshotai/kimi-k2.6.toml b/providers/tensorx/models/moonshotai/kimi-k2.6.toml index 1457ff3269..3d926729dc 100644 --- a/providers/tensorx/models/moonshotai/kimi-k2.6.toml +++ b/providers/tensorx/models/moonshotai/kimi-k2.6.toml @@ -1,6 +1,7 @@ -# Toggle: chat_template_kwargs.thinking = true|false (default on) -# reasoning_effort is accepted but not honored here — an invalid value and -# none both leave the reasoning-token count unchanged — so this is toggle-only. +# Toggle: chat_template_kwargs.thinking = true|false (default on); verified by +# reasoning_content going empty when false. +# reasoning_effort is accepted but not honored: none, low, high, max and an +# invalid value all leave reasoning_content in the same range. base_model = "moonshotai/kimi-k2.6" [[reasoning_options]] diff --git a/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml b/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml index 2456682013..e9088bbfec 100644 --- a/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml +++ b/providers/tensorx/models/moonshotai/kimi-k2.7-code.toml @@ -1,6 +1,7 @@ -# Toggle: chat_template_kwargs.thinking = true|false (default on) -# reasoning_effort is accepted but not honored here — an invalid value and -# none both leave the reasoning-token count unchanged — so this is toggle-only. +# Toggle: chat_template_kwargs.thinking = true|false (default on); verified by +# reasoning_content going empty when false. +# reasoning_effort is accepted but not honored: none, low, high, max and an +# invalid value all leave reasoning_content in the same range. base_model = "moonshotai/kimi-k2.7-code" [[reasoning_options]] diff --git a/providers/tensorx/models/moonshotai/kimi-k3.toml b/providers/tensorx/models/moonshotai/kimi-k3.toml index 8b903afe89..4985c54953 100644 --- a/providers/tensorx/models/moonshotai/kimi-k3.toml +++ b/providers/tensorx/models/moonshotai/kimi-k3.toml @@ -1,15 +1,14 @@ # AI SDK auto-discovers native IDs via /v1/models — field values map those IDs -# Toggle: chat_template_kwargs.thinking = true|false (default on) -# Effort: reasoning_effort = low|high|max; invalid values return 400 and low -# measurably lowers the reasoning-token count. Matches first-party Moonshot. +# Effort: reasoning_effort = none|low|high|max, measured by reasoning_content +# length. none empties it in 9/9 runs and depth grows low < high < max; +# invalid values return 400. chat_template_kwargs.thinking = false is +# unreliable here (reasoning still streamed in 3/9 runs), so none is the +# published off switch and no toggle is declared. base_model = "moonshotai/kimi-k3" -[[reasoning_options]] -type = "toggle" - [[reasoning_options]] type = "effort" -values = ["low", "high", "max"] +values = ["none", "low", "high", "max"] [interleaved] field = "reasoning_content" diff --git a/providers/tensorx/models/z-ai/glm-5.toml b/providers/tensorx/models/z-ai/glm-5.toml index dea547aa61..03db1e3f3b 100644 --- a/providers/tensorx/models/z-ai/glm-5.toml +++ b/providers/tensorx/models/z-ai/glm-5.toml @@ -1,7 +1,8 @@ -# Toggle: reasoning_effort = none turns reasoning off (verified: 0 reasoning -# tokens); any other accepted value leaves it on. chat_template_kwargs. -# enable_thinking is accepted but is a no-op here, and no graded level was -# separable from another, so only on/off is published. First-party z.ai is +# Toggle: reasoning_effort = none turns reasoning off — verified by +# reasoning_content going empty, not by usage.reasoning_tokens, which this +# host under-reports. Any other accepted value leaves it on. +# chat_template_kwargs.enable_thinking is accepted but is a no-op here, and no +# graded level was separable, so only on/off is published. First-party z.ai is # likewise toggle-only for GLM-5. base_model = "zhipuai/glm-5" From aefa5824e20f91b213da53159ff9cf60731b69ae Mon Sep 17 00:00:00 2001 From: bu6n Date: Tue, 4 Aug 2026 11:24:46 +0200 Subject: [PATCH 10/14] fix(tensorx): model effort-as-off as effort, keep attachment and modalities coherent --- packages/core/src/sync/providers/tensorx.ts | 19 ++++++++++++++++++- .../models/deepseek/deepseek-v3.2.toml | 8 ++++++-- .../models/qwen/qwen3.5-122b-a10b.toml | 8 ++++++-- providers/tensorx/models/z-ai/glm-5.toml | 14 +++++++------- 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/packages/core/src/sync/providers/tensorx.ts b/packages/core/src/sync/providers/tensorx.ts index ce7d827e8d..bff889152f 100644 --- a/packages/core/src/sync/providers/tensorx.ts +++ b/packages/core/src/sync/providers/tensorx.ts @@ -150,15 +150,32 @@ function buildTensorXModel( const toolFlags = [info.supports_tool_choice, info.supports_function_calling] .filter((flag) => flag !== null && flag !== undefined); + // supports_vision is the only modality signal the catalog carries, so + // `attachment` and `modalities.input` move together. Authoring one without the + // other would publish `attachment = true` beside a text-only modality list, or + // `attachment = false` while image input stays inherited. Only `image` is + // touched — the flag says nothing about video or pdf. + const vision = info.supports_vision; + const inheritedInput = existing?.modalities?.input; + const modalities = vision === null || vision === undefined || inheritedInput === undefined + ? existing?.modalities + : { + ...existing?.modalities, + input: vision + ? (inheritedInput.includes("image") ? inheritedInput : [...inheritedInput, "image"]) + : inheritedInput.filter((modality) => modality !== "image"), + }; + // `existing` is the base-model-resolved view, so factorBaseModel drops every // field that still matches the lab entry and keeps only the real deltas. const values: Record = { ...existing, - attachment: info.supports_vision ?? existing?.attachment, + attachment: vision ?? existing?.attachment, reasoning: info.supports_reasoning ?? existing?.reasoning, tool_call: toolFlags.length > 0 ? toolFlags.some(Boolean) : existing?.tool_call, cost, limit, + modalities, }; delete values.base_model; delete values.base_model_omit; diff --git a/providers/tensorx/models/deepseek/deepseek-v3.2.toml b/providers/tensorx/models/deepseek/deepseek-v3.2.toml index 491bf277d9..874da8eb6c 100644 --- a/providers/tensorx/models/deepseek/deepseek-v3.2.toml +++ b/providers/tensorx/models/deepseek/deepseek-v3.2.toml @@ -1,4 +1,8 @@ -# Effort: reasoning_effort = ; "none" disables reasoning +# Effort: reasoning_effort = none|high. This host does not reason by default — +# reasoning_content is empty unless an effort value is sent — and none keeps it +# off. chat_template_kwargs.enable_thinking and thinking are no-ops. Measured +# by reasoning_content length; invalid values return 400 and no graded level +# was separable, so one on level is published. name = "DeepSeek V3.2" description = "DeepSeek chat model for instruction following, coding, and analysis" family = "deepseek" @@ -13,7 +17,7 @@ open_weights = true [[reasoning_options]] type = "effort" -values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +values = ["none", "high"] [interleaved] field = "reasoning_content" diff --git a/providers/tensorx/models/qwen/qwen3.5-122b-a10b.toml b/providers/tensorx/models/qwen/qwen3.5-122b-a10b.toml index f773843a0e..60fb5c6822 100644 --- a/providers/tensorx/models/qwen/qwen3.5-122b-a10b.toml +++ b/providers/tensorx/models/qwen/qwen3.5-122b-a10b.toml @@ -1,9 +1,13 @@ -# Effort: reasoning_effort = ; "none" disables reasoning +# Effort: reasoning_effort = none|high. Off is the effort value none, not a +# boolean field: chat_template_kwargs.enable_thinking and thinking are both +# accepted but are no-ops here. Measured by reasoning_content length (this +# host under-reports usage.reasoning_tokens); none empties it, invalid values +# return 400, and no graded level was separable, so one on level is published. base_model = "alibaba/qwen3.5-122b-a10b" [[reasoning_options]] type = "effort" -values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +values = ["none", "high"] [interleaved] field = "reasoning_content" diff --git a/providers/tensorx/models/z-ai/glm-5.toml b/providers/tensorx/models/z-ai/glm-5.toml index 03db1e3f3b..0696922a62 100644 --- a/providers/tensorx/models/z-ai/glm-5.toml +++ b/providers/tensorx/models/z-ai/glm-5.toml @@ -1,13 +1,13 @@ -# Toggle: reasoning_effort = none turns reasoning off — verified by -# reasoning_content going empty, not by usage.reasoning_tokens, which this -# host under-reports. Any other accepted value leaves it on. -# chat_template_kwargs.enable_thinking is accepted but is a no-op here, and no -# graded level was separable, so only on/off is published. First-party z.ai is -# likewise toggle-only for GLM-5. +# Effort: reasoning_effort = none|high. Off is the effort value none, not a +# boolean field: chat_template_kwargs.enable_thinking is accepted but is a no-op +# on this host, so no toggle is declared. Verified by reasoning_content going +# empty for none, not by usage.reasoning_tokens, which this host under-reports. +# No graded level was separable from another, so one on level is published. base_model = "zhipuai/glm-5" [[reasoning_options]] -type = "toggle" +type = "effort" +values = ["none", "high"] [interleaved] field = "reasoning_content" From 417aaf528f4ae3322fc2e7e99e5a62e02aaaac8e Mon Sep 17 00:00:00 2001 From: bu6n Date: Tue, 4 Aug 2026 11:32:44 +0200 Subject: [PATCH 11/14] fix(tensorx): narrow remaining effort enums to measured or lab-baseline controls --- .../tensorx/models/deepseek/deepseek-chat-v3.1.toml | 6 +++++- providers/tensorx/models/minimax/minimax-m2.5.toml | 10 +++++----- .../models/nvidia/nemotron-3-super-120b-a12b.toml | 6 +++++- providers/tensorx/models/openai/gpt-oss-120b.toml | 8 ++++++-- providers/tensorx/models/qwen/qwen3.5-9b.toml | 8 ++++++-- providers/tensorx/models/z-ai/glm-4.7.toml | 10 +++++++--- 6 files changed, 34 insertions(+), 14 deletions(-) diff --git a/providers/tensorx/models/deepseek/deepseek-chat-v3.1.toml b/providers/tensorx/models/deepseek/deepseek-chat-v3.1.toml index 34f6124bc1..1270bd036e 100644 --- a/providers/tensorx/models/deepseek/deepseek-chat-v3.1.toml +++ b/providers/tensorx/models/deepseek/deepseek-chat-v3.1.toml @@ -1,4 +1,8 @@ -# Effort: reasoning_effort = ; "none" disables reasoning +# Not reachable with the sync key (403, models=['public']), so nothing below +# could be measured against this host. Controls are carried from the lab/peer +# baseline; [interleaved] is deliberately omitted rather than assumed, even +# though all 18 reachable models here stream reasoning_content. +# No lab or peer entry authors reasoning options, so the list is left as-is. name = "DeepSeek Chat V3.1" description = "DeepSeek chat model for instruction following, coding, and analysis" family = "deepseek" diff --git a/providers/tensorx/models/minimax/minimax-m2.5.toml b/providers/tensorx/models/minimax/minimax-m2.5.toml index ff39dd12db..3fa9dbfe7f 100644 --- a/providers/tensorx/models/minimax/minimax-m2.5.toml +++ b/providers/tensorx/models/minimax/minimax-m2.5.toml @@ -1,9 +1,9 @@ -# Effort: reasoning_effort = ; reasoning is mandatory, "none" is rejected +# No caller control. reasoning_effort = none is rejected (400), low/medium/ +# high/max overlap entirely over 4 runs each, and chat_template_kwargs +# enable_thinking and thinking are both no-ops. Measured by reasoning_content +# length. Reasoning is always on, matching the lab and OpenRouter entries. base_model = "minimax/MiniMax-M2.5" - -[[reasoning_options]] -type = "effort" -values = ["minimal", "low", "medium", "high", "xhigh", "max"] +reasoning_options = [] [interleaved] field = "reasoning_content" diff --git a/providers/tensorx/models/nvidia/nemotron-3-super-120b-a12b.toml b/providers/tensorx/models/nvidia/nemotron-3-super-120b-a12b.toml index 8423a4f38a..c248acbc3a 100644 --- a/providers/tensorx/models/nvidia/nemotron-3-super-120b-a12b.toml +++ b/providers/tensorx/models/nvidia/nemotron-3-super-120b-a12b.toml @@ -1,4 +1,8 @@ -# Effort: reasoning_effort = ; "none" disables reasoning +# Not reachable with the sync key (403, models=['public']), so nothing below +# could be measured against this host. Controls are carried from the lab/peer +# baseline; [interleaved] is deliberately omitted rather than assumed, even +# though all 18 reachable models here stream reasoning_content. +# No lab or peer entry authors reasoning options, so the list is left as-is. base_model = "nvidia/nemotron-3-super-120b-a12b" [[reasoning_options]] diff --git a/providers/tensorx/models/openai/gpt-oss-120b.toml b/providers/tensorx/models/openai/gpt-oss-120b.toml index b6a30e839c..dfcf2045ea 100644 --- a/providers/tensorx/models/openai/gpt-oss-120b.toml +++ b/providers/tensorx/models/openai/gpt-oss-120b.toml @@ -1,10 +1,14 @@ -# Effort: reasoning_effort = ; reasoning is mandatory, "none" is rejected +# Not reachable with the sync key (403, models=['public']), so nothing below +# could be measured against this host. Controls are carried from the lab/peer +# baseline; [interleaved] is deliberately omitted rather than assumed, even +# though all 18 reachable models here stream reasoning_content. +# OpenRouter, the closest same-surface peer, exposes low|medium|high. base_model = "openai/gpt-oss-120b" knowledge = "2024-10" [[reasoning_options]] type = "effort" -values = ["minimal", "low", "medium", "high", "xhigh", "max"] +values = ["low", "medium", "high"] [cost] input = 0.04 diff --git a/providers/tensorx/models/qwen/qwen3.5-9b.toml b/providers/tensorx/models/qwen/qwen3.5-9b.toml index 79ef102b6f..0f6d4f879f 100644 --- a/providers/tensorx/models/qwen/qwen3.5-9b.toml +++ b/providers/tensorx/models/qwen/qwen3.5-9b.toml @@ -1,9 +1,13 @@ -# Effort: reasoning_effort = ; "none" disables reasoning +# Effort: reasoning_effort = none|high. Off is the effort value none, not a +# boolean field: chat_template_kwargs.enable_thinking and thinking are no-ops +# here. Measured by reasoning_content length; none empties it, invalid values +# return 400, and over 4 runs each low/medium/high/max overlap entirely +# (means within 60 chars), so one on level is published. base_model = "alibaba/qwen3.5-9b" [[reasoning_options]] type = "effort" -values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +values = ["none", "high"] [interleaved] field = "reasoning_content" diff --git a/providers/tensorx/models/z-ai/glm-4.7.toml b/providers/tensorx/models/z-ai/glm-4.7.toml index c33966c544..e0fcce5b2a 100644 --- a/providers/tensorx/models/z-ai/glm-4.7.toml +++ b/providers/tensorx/models/z-ai/glm-4.7.toml @@ -1,9 +1,13 @@ -# Effort: reasoning_effort = ; "none" disables reasoning +# Not reachable with the sync key (403, models=['public']), so nothing below +# could be measured against this host. Controls are carried from the lab/peer +# baseline; [interleaved] is deliberately omitted rather than assumed, even +# though all 18 reachable models here stream reasoning_content. +# First-party z.ai GLM-4.7 is toggle-only. +# Toggle: chat_template_kwargs.enable_thinking = true|false base_model = "zhipuai/glm-4.7" [[reasoning_options]] -type = "effort" -values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +type = "toggle" [cost] input = 0.6 From eca4d608c29053f386f3f434ecf3858141b8cd4d Mon Sep 17 00:00:00 2001 From: bu6n Date: Tue, 4 Aug 2026 11:39:37 +0200 Subject: [PATCH 12/14] fix(tensorx): copy peer toggle for unreachable DeepSeek V3.1 and Nemotron --- .../models/deepseek/deepseek-chat-v3.1.toml | 15 ++++++++------- .../models/nvidia/nemotron-3-super-120b-a12b.toml | 15 ++++++++------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/providers/tensorx/models/deepseek/deepseek-chat-v3.1.toml b/providers/tensorx/models/deepseek/deepseek-chat-v3.1.toml index 1270bd036e..f75eace0bf 100644 --- a/providers/tensorx/models/deepseek/deepseek-chat-v3.1.toml +++ b/providers/tensorx/models/deepseek/deepseek-chat-v3.1.toml @@ -1,8 +1,10 @@ -# Not reachable with the sync key (403, models=['public']), so nothing below -# could be measured against this host. Controls are carried from the lab/peer -# baseline; [interleaved] is deliberately omitted rather than assumed, even -# though all 18 reachable models here stream reasoning_content. -# No lab or peer entry authors reasoning options, so the list is left as-is. +# Not reachable with the sync key (403, models=['public']), so nothing here +# could be measured against this host. providers/openrouter/models/deepseek/ +# deepseek-chat-v3.1.toml authors a toggle, so that control shape is copied +# rather than keeping a full effort enum. +# Toggle: chat_template_kwargs.thinking = true|false — the path every reachable +# DeepSeek model on this host uses, but unverified for this ID. +# [interleaved] is omitted rather than assumed, for the same reason. name = "DeepSeek Chat V3.1" description = "DeepSeek chat model for instruction following, coding, and analysis" family = "deepseek" @@ -16,8 +18,7 @@ knowledge = "2024-11" open_weights = true [[reasoning_options]] -type = "effort" -values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +type = "toggle" [cost] input = 0.2 diff --git a/providers/tensorx/models/nvidia/nemotron-3-super-120b-a12b.toml b/providers/tensorx/models/nvidia/nemotron-3-super-120b-a12b.toml index c248acbc3a..b310722164 100644 --- a/providers/tensorx/models/nvidia/nemotron-3-super-120b-a12b.toml +++ b/providers/tensorx/models/nvidia/nemotron-3-super-120b-a12b.toml @@ -1,13 +1,14 @@ -# Not reachable with the sync key (403, models=['public']), so nothing below -# could be measured against this host. Controls are carried from the lab/peer -# baseline; [interleaved] is deliberately omitted rather than assumed, even -# though all 18 reachable models here stream reasoning_content. -# No lab or peer entry authors reasoning options, so the list is left as-is. +# Not reachable with the sync key (403, models=['public']), so nothing here +# could be measured against this host. First-party providers/nvidia/models/ +# nvidia/nemotron-3-super-120b-a12b.toml authors a toggle, so that control +# shape is copied rather than keeping a full effort enum. +# Toggle: wire path is neither documented by the lab entry nor verifiable with +# this key — confirm it before relying on it. +# [interleaved] is omitted rather than assumed, for the same reason. base_model = "nvidia/nemotron-3-super-120b-a12b" [[reasoning_options]] -type = "effort" -values = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] +type = "toggle" [cost] input = 0.3 From a960ce2db464c27c96f5aea35feb97c2a20c031a Mon Sep 17 00:00:00 2001 From: bu6n Date: Tue, 4 Aug 2026 13:58:17 +0200 Subject: [PATCH 13/14] fix(tensorx): match peer baseline for DeepSeek R1-0528 reasoning options --- providers/tensorx/models/deepseek/deepseek-r1-0528.toml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/providers/tensorx/models/deepseek/deepseek-r1-0528.toml b/providers/tensorx/models/deepseek/deepseek-r1-0528.toml index 9d2e14ef42..2d2925531f 100644 --- a/providers/tensorx/models/deepseek/deepseek-r1-0528.toml +++ b/providers/tensorx/models/deepseek/deepseek-r1-0528.toml @@ -1,12 +1,11 @@ -# Effort: reasoning_effort = ; reasoning is mandatory, "none" is rejected +# reasoning_effort is accepted but does not grade depth on this host, and none +# is rejected (400), so reasoning is always on. Matches the OpenRouter entry for +# this model. base_model = "deepseek/deepseek-r1" name = "DeepSeek R1-0528" release_date = "2025-05-28" last_updated = "2025-05-28" - -[[reasoning_options]] -type = "effort" -values = ["minimal", "low", "medium", "high", "xhigh", "max"] +reasoning_options = [] [interleaved] field = "reasoning_content" From e2e920f8f99fb2a9850d9340301d07135ffc879b Mon Sep 17 00:00:00 2001 From: bu6n Date: Tue, 4 Aug 2026 14:57:50 +0200 Subject: [PATCH 14/14] fix(tensorx): document Nemotron toggle wire path, derive attachment from modalities --- packages/core/src/sync/providers/tensorx.ts | 14 +++++++++----- .../models/nvidia/nemotron-3-super-120b-a12b.toml | 14 +++++++------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/packages/core/src/sync/providers/tensorx.ts b/packages/core/src/sync/providers/tensorx.ts index bff889152f..a8b71dcd0e 100644 --- a/packages/core/src/sync/providers/tensorx.ts +++ b/packages/core/src/sync/providers/tensorx.ts @@ -151,10 +151,10 @@ function buildTensorXModel( .filter((flag) => flag !== null && flag !== undefined); // supports_vision is the only modality signal the catalog carries, so - // `attachment` and `modalities.input` move together. Authoring one without the - // other would publish `attachment = true` beside a text-only modality list, or - // `attachment = false` while image input stays inherited. Only `image` is - // touched — the flag says nothing about video or pdf. + // `attachment` and `modalities.input` move together. Only `image` is edited — + // the flag says nothing about video or pdf — and `attachment` is then read + // back off the resulting list rather than off the flag, so a model that keeps + // video after losing image stays `attachment = true`. const vision = info.supports_vision; const inheritedInput = existing?.modalities?.input; const modalities = vision === null || vision === undefined || inheritedInput === undefined @@ -165,12 +165,16 @@ function buildTensorXModel( ? (inheritedInput.includes("image") ? inheritedInput : [...inheritedInput, "image"]) : inheritedInput.filter((modality) => modality !== "image"), }; + const resolvedInput = modalities?.input; + const attachment = vision === null || vision === undefined || resolvedInput === undefined + ? existing?.attachment + : resolvedInput.some((modality) => modality !== "text"); // `existing` is the base-model-resolved view, so factorBaseModel drops every // field that still matches the lab entry and keeps only the real deltas. const values: Record = { ...existing, - attachment: vision ?? existing?.attachment, + attachment, reasoning: info.supports_reasoning ?? existing?.reasoning, tool_call: toolFlags.length > 0 ? toolFlags.some(Boolean) : existing?.tool_call, cost, diff --git a/providers/tensorx/models/nvidia/nemotron-3-super-120b-a12b.toml b/providers/tensorx/models/nvidia/nemotron-3-super-120b-a12b.toml index b310722164..770b6699ed 100644 --- a/providers/tensorx/models/nvidia/nemotron-3-super-120b-a12b.toml +++ b/providers/tensorx/models/nvidia/nemotron-3-super-120b-a12b.toml @@ -1,10 +1,10 @@ -# Not reachable with the sync key (403, models=['public']), so nothing here -# could be measured against this host. First-party providers/nvidia/models/ -# nvidia/nemotron-3-super-120b-a12b.toml authors a toggle, so that control -# shape is copied rather than keeping a full effort enum. -# Toggle: wire path is neither documented by the lab entry nor verifiable with -# this key — confirm it before relying on it. -# [interleaved] is omitted rather than assumed, for the same reason. +# Toggle: chat_template_kwargs.enable_thinking = true|false +# Documented for this model by Workers AI, another OpenAI-compatible host: +# https://developers.cloudflare.com/workers-ai/models/nemotron-3-120b-a12b/sync-input.json +# It is also the field every GLM model on this host uses. Not reachable with the +# sync key (403, models=['public']), so it could not be confirmed here; the +# control shape follows first-party providers/nvidia/models/nvidia/ +# nemotron-3-super-120b-a12b.toml. [interleaved] is omitted rather than assumed. base_model = "nvidia/nemotron-3-super-120b-a12b" [[reasoning_options]]