From bf5973a6fe767815a667f0473f6bf6c336cfe603 Mon Sep 17 00:00:00 2001 From: effortprogrammer Date: Sun, 6 Sep 2026 22:47:20 +0900 Subject: [PATCH 1/8] fix(coding-agent): preserve hooks on cancellable trigger turns Fixes #1329. Run and apply before_agent_start for idle custom-trigger turns, retain final admission, and prevent provider calls after cancellation during an awaited hook. --- .../scripts/scenarios/issue-1329-qa.mjs | 278 ++++++++++++++++++ .../coding-agent/src/core/agent-session.ts | 95 ++++-- packages/coding-agent/src/core/changes.md | 18 ++ .../agent-session-model-extension.test.ts | 2 +- ...29-trigger-turn-before-agent-start.test.ts | 153 ++++++++++ 5 files changed, 514 insertions(+), 32 deletions(-) create mode 100644 .agents/skills/senpi-qa/scripts/scenarios/issue-1329-qa.mjs create mode 100644 packages/coding-agent/test/suite/regressions/issue-1329-trigger-turn-before-agent-start.test.ts diff --git a/.agents/skills/senpi-qa/scripts/scenarios/issue-1329-qa.mjs b/.agents/skills/senpi-qa/scripts/scenarios/issue-1329-qa.mjs new file mode 100644 index 0000000000..13f09ad6a7 --- /dev/null +++ b/.agents/skills/senpi-qa/scripts/scenarios/issue-1329-qa.mjs @@ -0,0 +1,278 @@ +#!/usr/bin/env node +/** + * Real RPC/CLI regression QA for #1329. + * + * Drives an idle `send_custom_message` triggerTurn through the source CLI and + * asserts the local fake provider's direct-RPC and extension-produced wake + * requests each contain both the extension hook marker and original trigger exactly once. + */ + +import { existsSync, readFileSync, writeFileSync } from "node:fs"; +import { createServer } from "node:net"; +import { join } from "node:path"; +import { + createChecks, + evidenceDir, + guardRealAuth, + installCleanupHooks, + makeSandbox, + repoRoot, +} from "../lib/common.mjs"; +import { startFakeModelServer } from "../lib/fake-model-server.mjs"; +import { hermeticEnv, writeMockModelsJson } from "../lib/mock-loop-support.mjs"; +import { TargetRpcClient } from "../lib/target-rpc-client.mjs"; + +const NORMAL_PROMPT = "issue-1329 normal"; +const WAKE_PROMPT = "issue-1329 wake"; +const EXTENSION_WAKE_PROMPT = "issue-1329 extension wake"; +const HOOK_PREFIX = "issue-1329-hook:"; +const SYSTEM_PREFIX = "issue-1329-system:"; +const NORMAL_REPLY = "ISSUE_1329_NORMAL_REPLY"; +const WAKE_REPLY = "ISSUE_1329_WAKE_REPLY"; +const EXTENSION_WAKE_REPLY = "ISSUE_1329_EXTENSION_WAKE_REPLY"; + +function argument(name) { + const index = process.argv.indexOf(name); + return index >= 0 ? process.argv[index + 1] : undefined; +} + +function requestMessageText(message) { + const content = message?.content; + if (typeof content === "string") return content; + if (!Array.isArray(content)) return ""; + return content + .map((part) => (typeof part?.text === "string" ? part.text : typeof part?.content === "string" ? part.content : "")) + .join("\n"); +} + +function countExactRequestMessage(messages, text) { + return messages.filter((message) => requestMessageText(message) === text).length; +} + +async function portIsReleased(port) { + const probe = createServer(); + try { + await new Promise((resolve, reject) => { + probe.once("error", reject); + probe.listen(port, "127.0.0.1", resolve); + }); + return true; + } catch { + return false; + } finally { + await new Promise((resolve) => probe.close(() => resolve())); + } +} + +function writeProbeExtension(path, recordsPath) { + writeFileSync( + path, + `import { appendFileSync } from "node:fs"; + +export default function issue1329Probe(pi) { + pi.on("before_agent_start", (event) => { + appendFileSync(${JSON.stringify(recordsPath)}, JSON.stringify({ event: "before_agent_start", prompt: event.prompt }) + "\\n"); + return { + message: { customType: "issue-1329-hook", content: ${JSON.stringify(HOOK_PREFIX)} + event.prompt, display: false }, + systemPrompt: event.systemPrompt + "\\n" + ${JSON.stringify(SYSTEM_PREFIX)} + event.prompt, + }; + }); + pi.registerCommand("issue-1329-extension-wake", { + description: "Send the #1329 wake from the extension API.", + handler: async () => { + await pi.sendMessage( + { customType: "issue-1329-extension-trigger", content: ${JSON.stringify(EXTENSION_WAKE_PROMPT)}, display: false }, + { triggerTurn: true, deliverAs: "followUp" }, + ); + }, + }); +} +`, + ); +} + +function readProbeRecords(path) { + if (!existsSync(path)) return []; + return readFileSync(path, "utf8") + .split("\n") + .filter(Boolean) + .map((line) => JSON.parse(line)); +} + +function sanitizedRequests(requests) { + return requests.map((request) => ({ + method: request.method, + url: request.url, + model: request.model, + stream: request.stream, + body: { + model: request.body?.model, + messages: Array.isArray(request.body?.messages) + ? request.body.messages.map((message) => + message?.role === "system" + ? { + role: "system", + containsIssue1329SystemMarker: requestMessageText(message).includes(SYSTEM_PREFIX), + } + : { role: message?.role, content: message?.content }, + ) + : [], + }, + authorization: request.authorization ? "" : null, + apiKeyHeader: request.apiKeyHeader ? "" : null, + })); +} + +async function main() { + const selfTest = process.argv.includes("--self-test"); + const evidenceName = argument("--evidence") ?? (selfTest ? "issue-1329-self-test" : undefined); + if (!evidenceName) throw new Error("--evidence is required unless --self-test is used"); + + installCleanupHooks(); + const checks = createChecks("issue-1329-qa.mjs"); + const authGuard = guardRealAuth(); + const evidence = evidenceDir(evidenceName); + const box = makeSandbox("issue-1329-qa"); + const extensionPath = join(box.dir, "issue-1329-probe.mjs"); + const recordsPath = join(box.dir, "issue-1329-probe.jsonl"); + let client; + let server; + let report = { scenario: "issue-1329-qa", selfTest, error: undefined }; + let serverPortReleased = false; + + try { + writeProbeExtension(extensionPath, recordsPath); + server = await startFakeModelServer({ + turns: [{ text: NORMAL_REPLY }, { text: WAKE_REPLY }, { text: EXTENSION_WAKE_REPLY }], + }); + writeMockModelsJson(box.agentDir, server, "openai-completions"); + client = new TargetRpcClient({ + env: hermeticEnv(box.env), + cwd: box.cwd, + targetRoot: repoRoot(), + extraArgs: ["--extension", extensionPath], + }); + + const selected = await client.send({ type: "set_model", provider: "mock", modelId: "mock-model" }); + checks.ok("source CLI selected the sandbox fake model", selected.success === true, JSON.stringify(selected)); + + // Subscribe before each action so this scenario never depends on elapsed time. + const firstSettled = client.waitFor((event) => event.message.type === "agent_settled"); + const firstIdle = client.waitFor((event) => event.message.type === "agent_idle"); + const prompted = await client.send({ type: "prompt", message: NORMAL_PROMPT }); + await firstSettled; + await firstIdle; + checks.ok("normal turn completed before the idle trigger", prompted.success === true, JSON.stringify(prompted)); + + const wakeStarted = client.waitFor((event) => event.message.type === "agent_start"); + const wakeSettled = client.waitFor((event) => event.message.type === "agent_settled"); + const wakeIdle = client.waitFor((event) => event.message.type === "agent_idle"); + const woke = await client.send({ + type: "send_custom_message", + customType: "issue-1329-trigger", + content: WAKE_PROMPT, + display: false, + triggerTurn: true, + deliverAs: "followUp", + }); + await wakeStarted; + await wakeSettled; + await wakeIdle; + checks.ok("direct RPC idle triggerTurn custom message completed", woke.success === true, JSON.stringify(woke)); + + const extensionWakeStarted = client.waitFor((event) => event.message.type === "agent_start"); + const extensionWakeSettled = client.waitFor((event) => event.message.type === "agent_settled"); + const extensionWakeIdle = client.waitFor((event) => event.message.type === "agent_idle"); + const extensionCommand = await client.send({ type: "prompt", message: "/issue-1329-extension-wake" }); + await extensionWakeStarted; + await extensionWakeSettled; + await extensionWakeIdle; + checks.ok("extension-produced idle triggerTurn completed", extensionCommand.success === true, JSON.stringify(extensionCommand)); + + const records = readProbeRecords(recordsPath); + const directWakeRequest = server.requests[1]; + const extensionWakeRequest = server.requests[2]; + const directWakeMessages = Array.isArray(directWakeRequest?.body?.messages) ? directWakeRequest.body.messages : []; + const extensionWakeMessages = Array.isArray(extensionWakeRequest?.body?.messages) + ? extensionWakeRequest.body.messages + : []; + const directWakeWire = JSON.stringify(directWakeRequest?.body ?? {}); + const extensionWakeWire = JSON.stringify(extensionWakeRequest?.body ?? {}); + checks.ok("exactly three provider requests reached the local fake server", server.requests.length === 3, `count=${server.requests.length}`); + checks.ok( + "before_agent_start ran once for normal, direct RPC, and extension wake turns", + JSON.stringify(records.map((record) => record.prompt)) === + JSON.stringify([NORMAL_PROMPT, WAKE_PROMPT, EXTENSION_WAKE_PROMPT]), + JSON.stringify(records), + ); + for (const [label, prompt, messages, wire] of [ + ["direct RPC", WAKE_PROMPT, directWakeMessages, directWakeWire], + ["extension-produced", EXTENSION_WAKE_PROMPT, extensionWakeMessages, extensionWakeWire], + ]) { + checks.ok( + `actual ${label} wake request contains the original trigger exactly once`, + countExactRequestMessage(messages, prompt) === 1, + `count=${countExactRequestMessage(messages, prompt)}`, + ); + checks.ok( + `actual ${label} wake request contains the hook marker exactly once`, + countExactRequestMessage(messages, `${HOOK_PREFIX}${prompt}`) === 1, + `count=${countExactRequestMessage(messages, `${HOOK_PREFIX}${prompt}`)}`, + ); + checks.ok( + `actual ${label} wake request contains the hook system-prompt override`, + wire.includes(`${SYSTEM_PREFIX}${prompt}`), + "wire marker present", + ); + } + + report = { + scenario: "issue-1329-qa", + selfTest, + requestCount: server.requests.length, + directRpcWakeRequestIndex: 1, + extensionWakeRequestIndex: 2, + requests: sanitizedRequests(server.requests), + probeRecords: records, + rpcEvents: client.events.map((event) => event.message.type), + error: undefined, + }; + } catch (error) { + report = { + ...report, + error: error instanceof Error ? error.message : String(error), + }; + checks.ok("scenario completed", false, report.error); + } finally { + await client?.close(); + if (server) { + await server.stop(); + serverPortReleased = await portIsReleased(server.port); + } + box.cleanup(); + const authUnchanged = authGuard.assertUnchanged(); + checks.ok("real auth unchanged", authUnchanged, authGuard.path); + const cleanup = { + clientClosed: client === undefined || client.child.exitCode !== null, + serverPortReleased, + sandboxRemoved: !existsSync(box.dir), + realAuthUnchanged: authUnchanged, + }; + writeFileSync(join(evidence, "issue-1329-qa.json"), JSON.stringify({ ...report, cleanup }, null, 2)); + writeFileSync( + join(evidence, "README.md"), + [ + "# Issue #1329 QA", + "", + "- Real source CLI in RPC mode against a local fake OpenAI server.", + "- Direct-RPC and extension-produced wakes each have one original trigger, one hook marker, and the hook system override in their captured request.", + "- `issue-1329-qa.json` contains sanitized request bodies, hook records, RPC events, and cleanup receipt.", + "", + ].join("\n"), + ); + } + + process.exitCode = checks.finish() ? 0 : 1; +} + +await main(); diff --git a/packages/coding-agent/src/core/agent-session.ts b/packages/coding-agent/src/core/agent-session.ts index 7d74c06ad6..c42a5216c2 100644 --- a/packages/coding-agent/src/core/agent-session.ts +++ b/packages/coding-agent/src/core/agent-session.ts @@ -1027,6 +1027,8 @@ export class AgentSession { private _isAgentRunActive = false; private _toolExecutionDepth = 0; private _promptStartPending = false; + /** User-abort generation at the start of an idle trigger turn's awaited admission hooks. */ + private _triggerTurnAdmissionAbortGeneration: number | undefined; private _nextInputId = 0; private _idleWaitPromise: Promise | undefined; private _resolveIdleWait: (() => void) | undefined; @@ -3852,29 +3854,7 @@ export class AgentSession { this._baseSystemPrompt, this._baseSystemPromptOptions, ); - // Add all custom messages from extensions - if (result?.messages) { - for (const msg of result.messages) { - messages.push({ - role: "custom", - customType: msg.customType, - // Untyped extensions can pass null/missing content; normalize at ingestion. - content: msg.content ?? [], - display: msg.display, - details: msg.details, - timestamp: Date.now(), - }); - } - } - // Apply extension-modified system prompt, or reset to base - if (result?.systemPrompt !== undefined) { - this._systemPromptOverride = result.systemPrompt; - this.agent.state.systemPrompt = result.systemPrompt; - } else { - // Ensure we're using the base prompt (in case previous turn had modifications) - this._systemPromptOverride = undefined; - this.agent.state.systemPrompt = this._baseSystemPrompt; - } + this._applyBeforeAgentStartResult(messages, result); // The preflight above only sees persisted session context. These prompt, // next-turn, and before_agent_start additions are also provider-visible, @@ -3922,6 +3902,34 @@ export class AgentSession { } } + /** Apply before_agent_start additions and reset any prior turn's system-prompt override. */ + private _applyBeforeAgentStartResult( + messages: AgentMessage[], + result: Awaited>, + ): void { + if (result?.messages) { + for (const msg of result.messages) { + messages.push({ + role: "custom", + customType: msg.customType, + // Untyped extensions can pass null/missing content; normalize at ingestion. + content: msg.content ?? [], + display: msg.display, + details: msg.details, + timestamp: Date.now(), + }); + } + } + if (result?.systemPrompt !== undefined) { + this._systemPromptOverride = result.systemPrompt; + this.agent.state.systemPrompt = result.systemPrompt; + } else { + // Ensure we're using the base prompt (in case a previous turn had modifications). + this._systemPromptOverride = undefined; + this.agent.state.systemPrompt = this._baseSystemPrompt; + } + } + /** * Try to execute an extension command. Returns true if command was found and executed. */ @@ -4329,22 +4337,44 @@ export class AgentSession { this.agent.steer(appMessage); } } else if (options?.triggerTurn) { + const messages: AgentMessage[] = [appMessage]; + const queueTriggerForLater = (): void => { + if (options.deliverAs === "followUp") { + this.agent.followUp(appMessage); + } else { + this.agent.steer(appMessage); + } + }; + this._triggerTurnAdmissionAbortGeneration = userAbortGeneration; try { await this._enforceCompactionBeforeProvider(this._findLastAssistantMessage(), false, "pre_prompt"); - await this._enforceFinalProviderAdmission([appMessage]); + const result = await this._extensionRunner.emitBeforeAgentStart( + contentText(appMessage.content, ""), + undefined, + this._baseSystemPrompt, + this._baseSystemPromptOptions, + ); + if (userAbortGeneration !== this._userAbortGeneration) { + queueTriggerForLater(); + return; + } + this._applyBeforeAgentStartResult(messages, result); + await this._enforceFinalProviderAdmission(messages); + if (userAbortGeneration !== this._userAbortGeneration) { + queueTriggerForLater(); + return; + } } catch (error) { // Mirror sendUserMessage's retention contract: an admission // rejection must retain the message for later delivery instead // of silently dropping it (the fire-and-forget extension action // swallows this rejection). - if (options.deliverAs === "followUp") { - this.agent.followUp(appMessage); - } else { - this.agent.steer(appMessage); - } + queueTriggerForLater(); throw error; + } finally { + this._triggerTurnAdmissionAbortGeneration = undefined; } - await this._promptAgent(appMessage, deferredTurnClaim); + await this._promptAgent(messages, deferredTurnClaim); } else if (this.isStreaming) { this._pendingCustomMessages.push(appMessage); } else { @@ -4550,13 +4580,16 @@ export class AgentSession { // Streaming aborts are carried by agent_end provenance; only gaps need session_abort. const wasMidRun = this.isStreaming && this._retryAbortController === undefined; const hadRetryBackoff = this._retryAbortController !== undefined; - const hadCompactionOrPending = !this.isStreaming && (this.isCompacting || this.pendingMessageCount > 0); + const hasPendingTriggerTurnAdmission = this._triggerTurnAdmissionAbortGeneration === this._userAbortGeneration; + const hadCompactionOrPending = + !this.isStreaming && (this.isCompacting || this.pendingMessageCount > 0 || hasPendingTriggerTurnAdmission); const hadClearedQueues = this._hadClearedQueuedMessages; const joinedAgentEndBoundary = this._abortProvenance.hasOpenAgentEndBoundary; this._hadClearedQueuedMessages = false; const shouldEmitAbort = !joinedAgentEndBoundary && !wasMidRun && (hadRetryBackoff || hadCompactionOrPending || hadClearedQueues); this.abortCompaction(); + if (hasPendingTriggerTurnAdmission) this._recordUserAbort(); await this._abortActiveAgentAndRetry("user"); if (!shouldEmitAbort) return; try { diff --git a/packages/coding-agent/src/core/changes.md b/packages/coding-agent/src/core/changes.md index ef881bdf12..68b30150d2 100644 --- a/packages/coding-agent/src/core/changes.md +++ b/packages/coding-agent/src/core/changes.md @@ -41,6 +41,24 @@ # changes +## 2026-09-06 - Run before_agent_start for idle custom trigger turns (#1329) + +### What changed + +- `packages/coding-agent/src/core/agent-session.ts` routes an idle `sendCustomMessage(..., { triggerTurn: true })` through `before_agent_start` after core pre-provider compaction and before final provider admission. Hook custom messages and system-prompt overrides use the same application path as ordinary prompts. A user abort while an awaited hook is held prevents a ghost provider turn and retains the trigger in its selected queue. + +### Why + +- Extension-triggered turns bypassed `before_agent_start`, so hook-provided context and system-prompt changes were absent from their actual provider request. Awaiting the newly-added hook also created an abort window where a released hook could start a turn after the user cancelled it. + +### Why an extension could not handle it + +- The idle trigger-turn branch chooses provider admission, cancellation ownership, and invokes the agent loop inside `AgentSession`; extensions only receive the lifecycle hook after the host emits it. + +### Expected merge conflict zones + +- MEDIUM: `sendCustomMessage` trigger-turn admission, cancellation generation, and the shared `before_agent_start` result application in `packages/coding-agent/src/core/agent-session.ts`. + ## 2026-09-06 - Preserve inline skill anchors in composed prompts ### What changed diff --git a/packages/coding-agent/test/suite/agent-session-model-extension.test.ts b/packages/coding-agent/test/suite/agent-session-model-extension.test.ts index 44d2ba7afa..1f26a5c772 100644 --- a/packages/coding-agent/test/suite/agent-session-model-extension.test.ts +++ b/packages/coding-agent/test/suite/agent-session-model-extension.test.ts @@ -580,7 +580,7 @@ describe("AgentSession model and extension characterization", () => { }, { label: "trigger-turn custom state", - beforeAgentStartCalls: 0, + beforeAgentStartCalls: 1, admit: async (harness: Harness, oversized: string) => await harness.session.sendCustomMessage( { customType: "oversized-trigger-turn", content: oversized, display: false }, diff --git a/packages/coding-agent/test/suite/regressions/issue-1329-trigger-turn-before-agent-start.test.ts b/packages/coding-agent/test/suite/regressions/issue-1329-trigger-turn-before-agent-start.test.ts new file mode 100644 index 0000000000..39c592aeba --- /dev/null +++ b/packages/coding-agent/test/suite/regressions/issue-1329-trigger-turn-before-agent-start.test.ts @@ -0,0 +1,153 @@ +import type { AgentMessage } from "@earendil-works/pi-agent-core"; +import { fauxAssistantMessage } from "@earendil-works/pi-ai"; +import { afterEach, describe, expect, it } from "vitest"; +import { createHarness, getMessageText, type Harness } from "../harness.ts"; + +function countMessageText(messages: readonly AgentMessage[], text: string): number { + return messages.filter((message) => getMessageText(message) === text).length; +} + +function createDeferred(): { promise: Promise; resolve: () => void } { + let resolve: (() => void) | undefined; + const promise = new Promise((next) => { + resolve = next; + }); + if (!resolve) throw new Error("Deferred resolver was not initialized"); + return { promise, resolve }; +} + +describe("issue #1329: trigger-turn custom messages enter before_agent_start", () => { + const harnesses: Harness[] = []; + + afterEach(() => { + while (harnesses.length > 0) harnesses.pop()?.cleanup(); + }); + + it("injects the hook result into the actual wake request exactly once", async () => { + const hookPrompts: string[] = []; + const providerRequests: Array<{ messages: AgentMessage[]; systemPrompt: string | undefined }> = []; + const harness = await createHarness({ + extensionFactories: [ + (pi) => { + pi.on("before_agent_start", (event) => { + hookPrompts.push(event.prompt); + return { + message: { + customType: "issue-1329-hook", + content: `hook-marker:${event.prompt}`, + display: false, + }, + systemPrompt: `${event.systemPrompt}\nissue-1329-system:${event.prompt}`, + }; + }); + }, + ], + }); + harnesses.push(harness); + harness.setResponses([ + (context) => { + providerRequests.push({ messages: context.messages, systemPrompt: context.systemPrompt }); + return fauxAssistantMessage("normal complete"); + }, + (context) => { + providerRequests.push({ messages: context.messages, systemPrompt: context.systemPrompt }); + return fauxAssistantMessage("wake complete"); + }, + ]); + + await harness.session.prompt("normal"); + await harness.session.sendCustomMessage( + { customType: "issue-1329-trigger", content: "wake", display: false }, + { triggerTurn: true, deliverAs: "followUp" }, + ); + + expect(harness.faux.state.callCount).toBe(2); + expect(hookPrompts).toEqual(["normal", "wake"]); + const wakeRequest = providerRequests[1]; + expect(wakeRequest).toBeDefined(); + expect(countMessageText(wakeRequest?.messages ?? [], "wake")).toBe(1); + expect(countMessageText(wakeRequest?.messages ?? [], "hook-marker:wake")).toBe(1); + expect(wakeRequest?.systemPrompt).toContain("issue-1329-system:wake"); + }); + + it("does not start a ghost turn when the user aborts a held trigger hook", async () => { + const hookEntered = createDeferred(); + const releaseHook = createDeferred(); + const harness = await createHarness({ + extensionFactories: [ + (pi) => { + pi.on("before_agent_start", async (event) => { + if (event.prompt !== "wake") return undefined; + hookEntered.resolve(); + await releaseHook.promise; + return { + message: { customType: "issue-1329-hook", content: "hook-marker:wake", display: false }, + }; + }); + }, + ], + }); + harnesses.push(harness); + harness.setResponses([fauxAssistantMessage("must not reach provider")]); + + const trigger = harness.session.sendCustomMessage( + { customType: "issue-1329-trigger", content: "wake", display: false }, + { triggerTurn: true, deliverAs: "followUp" }, + ); + await hookEntered.promise; + await harness.session.abort(); + releaseHook.resolve(); + await trigger; + await harness.session.waitForSettledSessionWork(); + + expect(harness.faux.state.callCount).toBe(0); + expect(harness.session.agent.hasQueuedMessages()).toBe(true); + expect( + harness.session.messages.some((message) => message.role === "custom" && getMessageText(message) === "wake"), + ).toBe(false); + }); + + it("queues the trigger message when its hook addition fails final admission", async () => { + const hookPrompts: string[] = []; + const oversizedHookMessage = "hook-added context ".repeat(2_000); + const harness = await createHarness({ + models: [{ id: "issue-1329-final-admission", contextWindow: 5_000, maxTokens: 1_000 }], + settings: { compaction: { enabled: true, keepRecentTokens: 1, reserveTokens: 1_000 } }, + extensionFactories: [ + (pi) => { + pi.on("before_agent_start", (event) => { + hookPrompts.push(event.prompt); + return event.prompt === "wake" + ? { + message: { + customType: "issue-1329-oversized-hook", + content: oversizedHookMessage, + display: false, + }, + } + : undefined; + }); + pi.on("session_before_compact", () => ({ + cancel: true, + rejectionCause: "cancelled-by-extension", + reason: "issue-1329 final-admission retention", + })); + }, + ], + }); + harnesses.push(harness); + harness.setResponses([fauxAssistantMessage("normal complete"), fauxAssistantMessage("must not reach provider")]); + + await harness.session.prompt("normal"); + await expect( + harness.session.sendCustomMessage( + { customType: "issue-1329-trigger", content: "wake", display: false }, + { triggerTurn: true, deliverAs: "followUp" }, + ), + ).rejects.toThrow("Context remains above the compaction threshold because compaction did not complete"); + + expect(hookPrompts).toEqual(["normal", "wake"]); + expect(harness.faux.state.callCount).toBe(1); + expect(harness.session.agent.hasQueuedMessages()).toBe(true); + }); +}); From 04b72381cba7638b6b585ebdd96ddc0250749cdb Mon Sep 17 00:00:00 2001 From: effortprogrammer Date: Sun, 6 Sep 2026 23:25:17 +0900 Subject: [PATCH 2/8] fix(ttsr): recover numeric loops without truncating code Fixes #1330. Detect bounded numeric prose drift, retain tool-progress and code-fence guards, and wait for hooked recovery turns before printing their final result (#1329). --- .../scripts/scenarios/issue-1330-qa.mjs | 232 ++++++++++++++++++ packages/coding-agent/src/changes.md | 18 ++ .../coding-agent/src/core/agent-session.ts | 1 + packages/coding-agent/src/core/changes.md | 18 ++ .../core/extensions/builtin/ttsr/changes.md | 62 +++++ .../ttsr/detectors/collapse-paragraphs.ts | 230 +++++++++++++++-- .../builtin/ttsr/detectors/collapse.ts | 2 +- .../src/core/extensions/builtin/ttsr/index.ts | 4 + .../src/core/extensions/builtin/ttsr/types.ts | 1 + .../src/core/extensions/builtin/ttsr/watch.ts | 13 +- packages/coding-agent/src/modes/print-mode.ts | 3 +- .../issue-1329-print-settled-trigger.test.ts | 85 +++++++ .../issue-1330-nested-fence-control.test.ts | 81 ++++++ .../test/suite/ttsr-extension.test.ts | 98 +++++++- .../test/ttsr/control-leak-helpers.ts | 7 +- .../ttsr/detector-collapse-paragraphs.test.ts | 91 ++++++- .../test/ttsr/detector-collapse.test.ts | 9 +- 17 files changed, 920 insertions(+), 35 deletions(-) create mode 100644 .agents/skills/senpi-qa/scripts/scenarios/issue-1330-qa.mjs create mode 100644 packages/coding-agent/test/suite/regressions/issue-1329-print-settled-trigger.test.ts create mode 100644 packages/coding-agent/test/suite/regressions/issue-1330-nested-fence-control.test.ts diff --git a/.agents/skills/senpi-qa/scripts/scenarios/issue-1330-qa.mjs b/.agents/skills/senpi-qa/scripts/scenarios/issue-1330-qa.mjs new file mode 100644 index 0000000000..0b083eab25 --- /dev/null +++ b/.agents/skills/senpi-qa/scripts/scenarios/issue-1330-qa.mjs @@ -0,0 +1,232 @@ +#!/usr/bin/env node +/** Real CLI QA for #1330's conservative numeric paragraph-loop detector. */ + +import { existsSync, readFileSync, readdirSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; + +import { createChecks, evidenceDir, guardRealAuth, installCleanupHooks, makeSandbox, runCli } from "../lib/common.mjs"; +import { startFakeModelServer } from "../lib/fake-model-server.mjs"; +import { API_PRESETS, hermeticEnv, writeMockModelsJson } from "../lib/mock-loop-support.mjs"; + +const API_NAME = "openai-completions"; +const FINAL_MARKER = "SENPI-QA-1330-NUMERIC-RECOVERY"; +const TOOL_MARKER = "SENPI-QA-1330-TOOL-PROGRESS-FINAL"; +const NORMAL_MARKER = "SENPI-QA-1330-NORMAL-FINAL"; +const CODE_MARKER = "SENPI-QA-1330-CODE-FINAL"; + +function singleDigitParagraph(step) { + return `I am carefully describing the exact same implementation plan for this task, but now writing step ${step} with no substantive progress at all.`; +} + +function codeParagraph(value) { + return `const retryLimit = ${value}; const detail = "This code paragraph stays long enough to be eligible while its literal is meaningful program data.";`; +} + +function readFirstPersistedAssistant(box) { + const files = readdirSync(box.sessionDir, { recursive: true, encoding: "utf8" }) + .filter((name) => name.endsWith(".jsonl")) + .map((name) => join(box.sessionDir, name)); + for (const file of files) { + for (const line of readFileSync(file, "utf8").split(/\r?\n/)) { + if (!line.trim()) continue; + const entry = JSON.parse(line); + if (entry.type === "message" && entry.message?.role === "assistant") return entry.message; + } + } + return undefined; +} + +function assistantText(message) { + return Array.isArray(message?.content) + ? message.content + .filter((block) => block?.type === "text" && typeof block.text === "string") + .map((block) => block.text) + .join("") + : ""; +} + +function writeEventExtension(box) { + const eventPath = join(box.dir, "agent-events.jsonl"); + const extensionPath = join(box.dir, "issue-1330-events.mjs"); + writeFileSync( + extensionPath, + `import { appendFileSync } from "node:fs";\nconst path = ${JSON.stringify(eventPath)};\nconst record = (event) => appendFileSync(path, JSON.stringify(event) + "\\n");\nexport default function(pi) { pi.on("agent_end", (event) => record({ type: "agent_end", aborted: event.aborted, abortSource: event.abortSource })); pi.on("message_update", (event) => record({ type: event.assistantMessageEvent.type })); }\n`, + ); + return { eventPath, extensionPath }; +} + +function readEvents(path) { + return existsSync(path) + ? readFileSync(path, "utf8") + .split(/\r?\n/) + .filter(Boolean) + .map((line) => JSON.parse(line)) + : []; +} + +function requestText(message) { + if (typeof message?.content === "string") return message.content; + if (!Array.isArray(message?.content)) return ""; + return message.content + .map((part) => (typeof part?.text === "string" ? part.text : typeof part?.content === "string" ? part.content : "")) + .join("\n"); +} + +function sanitizeRequests(requests) { + return requests.map((request) => ({ + method: request.method, + url: request.url, + model: request.model, + stream: request.stream, + authorization: request.authorization ? "" : null, + apiKeyHeader: request.apiKeyHeader ? "" : null, + messages: (request.body?.messages ?? []).map((message) => { + const text = requestText(message); + return { + role: message?.role, + chars: text.length, + content: message?.role === "system" ? "" : text.slice(0, 2000), + }; + }), + toolNames: (request.tools ?? []) + .map((tool) => tool?.function?.name ?? tool?.name) + .filter((name) => typeof name === "string"), + })); +} + +async function runCase(name, turns, extraArgs = []) { + const box = makeSandbox(`issue-1330-${name}`); + const server = await startFakeModelServer({ turns }); + const prepared = writeEventExtension(box); + const preset = API_PRESETS[API_NAME]; + writeMockModelsJson(box.agentDir, server, API_NAME); + try { + const result = await runCli( + [ + "--provider", + preset.provider, + "--model", + preset.modelId, + "--no-context-files", + "--no-extensions", + "--extension", + prepared.extensionPath, + "--approve", + ...extraArgs, + "--print", + `Run the deterministic ${name} QA case.`, + ], + { env: hermeticEnv(box.env), cwd: box.cwd, timeoutMs: 120000 }, + ); + return { + name, + result, + requests: sanitizeRequests(server.requests), + events: readEvents(prepared.eventPath), + persisted: readFirstPersistedAssistant(box), + cleanup: async () => { + await server.stop(); + box.cleanup(); + return { serverStopped: true, sandboxRemoved: !existsSync(box.dir) }; + }, + }; + } catch (error) { + await server.stop(); + box.cleanup(); + throw error; + } +} + +function parseArgs(argv) { + let evidenceSlug; + let selfTest = false; + for (let index = 0; index < argv.length; index++) { + if (argv[index] === "--self-test") selfTest = true; + else if (argv[index] === "--evidence") evidenceSlug = argv[++index]; + else throw new Error(`unknown argument: ${argv[index]}`); + } + if (evidenceSlug !== undefined && !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(evidenceSlug)) { + throw new Error("--evidence requires a safe single path segment"); + } + return { evidenceSlug, selfTest }; +} + +async function main() { + const { evidenceSlug, selfTest } = parseArgs(process.argv.slice(2)); + installCleanupHooks(); + const guard = guardRealAuth(); + const checks = createChecks("issue-1330-qa"); + const reports = []; + const paragraphs = [singleDigitParagraph(3), singleDigitParagraph(4), singleDigitParagraph(5)]; + + const numeric = await runCase("original-single-digit-loop", [{ text: `${paragraphs.join("\n\n")}\n\n`, chunks: 30 }, { text: FINAL_MARKER }]); + try { + const persistedText = assistantText(numeric.persisted); + const recoveryRequest = JSON.stringify(numeric.requests[1] ?? {}); + checks.ok("numeric loop: real CLI exits after exactly one recovery", numeric.result.code === 0 && !numeric.result.timedOut && numeric.requests.length === 2, `code=${numeric.result.code} requests=${numeric.requests.length}`); + checks.ok("numeric loop: system abort is observable before recovery", numeric.events.filter((event) => event.type === "agent_end").map((event) => event.abortSource).join(",") === "system,", `events=${JSON.stringify(numeric.events)}`); + checks.ok("numeric loop: persisted replay is truncated at the first repeat", persistedText.includes(paragraphs[0]) && !persistedText.includes(paragraphs[1]) && persistedText.includes("[output interrupted by stream rule]"), `chars=${persistedText.length}`); + checks.ok("numeric loop: recovery request carries one collapse nudge", recoveryRequest.includes("collapse-repetition"), `nudge=${recoveryRequest.includes("collapse-repetition")}`); + checks.ok("numeric loop: final recovery marker reaches the actual CLI output", `${numeric.result.stdout}\n${numeric.result.stderr}`.includes(FINAL_MARKER), `marker=${FINAL_MARKER}`); + reports.push({ name: numeric.name, result: numeric.result, requests: numeric.requests, events: numeric.events }); + } finally { + const cleanup = await numeric.cleanup(); + reports.push({ name: `${numeric.name}-cleanup`, cleanup }); + } + + const tool = await runCase( + "tool-progress-collapse-isolation", + [ + { text: `${paragraphs[0]}\n\n`, toolCalls: [{ name: "bash", args: { command: "printf first-progress" } }] }, + { text: `${paragraphs[1]}\n\n`, toolCalls: [{ name: "bash", args: { command: "printf second-progress" } }] }, + { text: `${paragraphs[2]}\n\n${TOOL_MARKER}` }, + ], + ["--ttsr-rules-disabled", "repetitive-turns"], + ); + try { + checks.ok("tool progress (collapse isolation): three same-track occurrences complete without a collapse remediation", tool.result.code === 0 && !tool.result.timedOut && tool.requests.length === 3 && tool.events.filter((event) => event.type === "agent_end").every((event) => event.abortSource !== "system"), `scope=collapse-only; repetitive-turns disabled; code=${tool.result.code} requests=${tool.requests.length} events=${JSON.stringify(tool.events)}`); + checks.ok("tool progress (collapse isolation): two tool lifecycles precede the third occurrence", tool.events.filter((event) => event.type === "toolcall_end").length === 2 && `${tool.result.stdout}\n${tool.result.stderr}`.includes(paragraphs[2]), `toolEnds=${tool.events.filter((event) => event.type === "toolcall_end").length}`); + checks.ok("tool progress (collapse isolation): final marker reaches the actual CLI output", `${tool.result.stdout}\n${tool.result.stderr}`.includes(TOOL_MARKER), `marker=${TOOL_MARKER}`); + reports.push({ name: tool.name, result: tool.result, requests: tool.requests, events: tool.events }); + } finally { + reports.push({ name: `${tool.name}-cleanup`, cleanup: await tool.cleanup() }); + } + + const normal = await runCase("normal-progress-full-guard", [ + { text: "I inspected the implementation and found the first distinct source location.", toolCalls: [{ name: "bash", args: { command: "printf normal-first" } }] }, + { text: "I changed the isolated detector condition and documented a separate safety rationale.", toolCalls: [{ name: "bash", args: { command: "printf normal-second" } }] }, + { text: `I verified the regression suite against a distinct final assertion: ${NORMAL_MARKER}.` }, + ]); + const code = await runCase("code-control", [{ text: `${[3, 4, 5].map(codeParagraph).join("\n\n")}\n\n\`\`\`ts\n${[3, 4, 5].map(codeParagraph).join("\n\n")}\n\`\`\`\n\n\`\`\`\`markdown\n\`\`\`text\n\n${paragraphs.join("\n\n")}\n\n\`\`\`\n\`\`\`\`\n\n${CODE_MARKER}` }]); + try { + checks.ok("normal progress (full guard): three distinct tool-backed updates avoid every remediation", normal.result.code === 0 && !normal.result.timedOut && normal.requests.length === 3 && normal.events.filter((event) => event.type === "agent_end").every((event) => event.abortSource !== "system"), `scope=all protections; code=${normal.result.code} requests=${normal.requests.length} events=${JSON.stringify(normal.events)}`); + checks.ok("code control: unfenced, fenced, and nested-fence examples avoid a remediation", code.result.code === 0 && !code.result.timedOut && code.requests.length === 1 && code.events.filter((event) => event.type === "agent_end").every((event) => event.abortSource !== "system"), `code=${code.result.code} requests=${code.requests.length} events=${JSON.stringify(code.events)}`); + checks.ok("normal prose: marker reaches actual CLI output", `${normal.result.stdout}\n${normal.result.stderr}`.includes(NORMAL_MARKER), `marker=${NORMAL_MARKER}`); + checks.ok("code control: marker reaches actual CLI output", `${code.result.stdout}\n${code.result.stderr}`.includes(CODE_MARKER), `marker=${CODE_MARKER}`); + reports.push( + { name: normal.name, result: normal.result, requests: normal.requests, events: normal.events }, + { name: code.name, result: code.result, requests: code.requests, events: code.events }, + ); + } finally { + reports.push( + { name: `${normal.name}-cleanup`, cleanup: await normal.cleanup() }, + { name: `${code.name}-cleanup`, cleanup: await code.cleanup() }, + ); + } + + guard.assertUnchanged(); + checks.ok("credential guard: real auth is unchanged", true, "guardRealAuth passed"); + if (evidenceSlug !== undefined) { + const dir = evidenceDir(evidenceSlug); + writeFileSync(join(dir, "issue-1330-qa.json"), `${JSON.stringify({ command: process.argv.slice(0, 2).join(" "), selfTest, reports }, null, 2)}\n`); + const rawOutput = reports + .filter((report) => report.result !== undefined) + .map((report) => `--- ${report.name} stdout ---\n${report.result.stdout}\n--- ${report.name} stderr ---\n${report.result.stderr}`) + .join("\n"); + writeFileSync(join(dir, "issue-1330-qa.raw.log"), `${rawOutput}\n`); + process.stderr.write(`evidence: ${dir}\n`); + } + process.exit(checks.finish() ? 0 : 1); +} + +await main(); diff --git a/packages/coding-agent/src/changes.md b/packages/coding-agent/src/changes.md index d568158826..6010863460 100644 --- a/packages/coding-agent/src/changes.md +++ b/packages/coding-agent/src/changes.md @@ -1,5 +1,23 @@ # changes +## 2026-09-06 - Print the settled recovery result + +### What changed + +- `packages/coding-agent/src/modes/print-mode.ts` waits for settled session work before selecting the final assistant result and exit status. + +### Why + +- Awaited hooks in a recovery turn could leave the preceding aborted response visible while the next turn was still starting. Reading it early printed a stale error or response. + +### Why an extension could not handle it + +- Result selection, process exit status, and runtime disposal belong to the print-mode host. + +### Expected merge conflict zones + +- `packages/coding-agent/src/modes/print-mode.ts` final output selection and settlement ordering. + ## 2026-09-06 - Preserve inline skill anchors in composed prompts ### What changed diff --git a/packages/coding-agent/src/core/agent-session.ts b/packages/coding-agent/src/core/agent-session.ts index c42a5216c2..b1be469a2d 100644 --- a/packages/coding-agent/src/core/agent-session.ts +++ b/packages/coding-agent/src/core/agent-session.ts @@ -4337,6 +4337,7 @@ export class AgentSession { this.agent.steer(appMessage); } } else if (options?.triggerTurn) { + finishSessionWork ??= this._sessionWorkBarrier.begin(); const messages: AgentMessage[] = [appMessage]; const queueTriggerForLater = (): void => { if (options.deliverAs === "followUp") { diff --git a/packages/coding-agent/src/core/changes.md b/packages/coding-agent/src/core/changes.md index 68b30150d2..0933843275 100644 --- a/packages/coding-agent/src/core/changes.md +++ b/packages/coding-agent/src/core/changes.md @@ -1,4 +1,22 @@ +## 2026-09-06 - Track awaited custom-trigger admission through settlement + +### What changed + +- `packages/coding-agent/src/core/agent-session.ts` registers idle custom-trigger admission and execution with the session work barrier, including awaited `before_agent_start` handlers. + +### Why + +- A recovery turn scheduled from `agent_settled` can still be in its hook when the preceding prompt returns. Hosts must not treat that pending turn as completed work. + +### Why an extension could not handle it + +- The host owns the session work barrier and the lifetime of custom-trigger admission. + +### Expected merge conflict zones + +- `packages/coding-agent/src/core/agent-session.ts` idle `sendCustomMessage` admission and its existing finally cleanup. + ## 2026-09-05 - Persist Astra reasoning configuration updates ### What changed diff --git a/packages/coding-agent/src/core/extensions/builtin/ttsr/changes.md b/packages/coding-agent/src/core/extensions/builtin/ttsr/changes.md index 1c30a68695..667942271e 100644 --- a/packages/coding-agent/src/core/extensions/builtin/ttsr/changes.md +++ b/packages/coding-agent/src/core/extensions/builtin/ttsr/changes.md @@ -1,5 +1,67 @@ # TTSR Fork Tracker +## 2026-09-06 - Preserve nested fenced examples during numeric detection + +### What changed + +- `detectors/collapse-paragraphs.ts` retains the opening fence marker and length. Shorter nested fences and fence lines with trailing non-whitespace do not end the protected code region. + +### Why + +- Three numeric prose examples inside a four-backtick Markdown example were incorrectly treated as a model loop after an inner triple-backtick line. + +### Why an extension could not handle it + +- This remains within the existing TTSR extension's streaming scanner and remediation boundary. + +### Expected merge conflict zones + +- `detectors/collapse-paragraphs.ts` code-fence state and line safety checks. +- Regression: nested shorter fences, invalid closing lines, and numeric repetition after the actual closing fence. + +## 2026-09-06 - Single-digit numeric paragraph repetition safety + +### What changed + +- Normalized paragraph evidence now includes standalone single-digit counters, covering the original no-progress `step 3`/`step 4`/`step 5` loop. +- Numbered `1.`/`1)` lists, identifier digits, structured `step N of ...` plans, code punctuation, and fenced code remain ineligible. Fence state persists across blank paragraph boundaries until its matching closing fence. + +### Why + +The multi-digit floor missed the original reported loop. A lexical safety boundary is more precise than a digit-width boundary: it catches an isolated prose counter while retaining meaningful numbered plans and code/math data. + +### Why an extension could not handle it + +Not applicable: stream evidence and its code-fence context belong to the extension-local paragraph scanner; no provider or `AgentSession` change is required. + +### Expected merge conflict zones + +- LOW: `detectors/collapse-paragraphs.ts` digit-run eligibility and fence state. +- Coverage: direct original-loop RED/GREEN plus nonvacuous tool-progress, code, fenced-code, exact-repeat, and user-cancellation regressions; real CLI evidence saves raw output and cleanup receipts. + +## 2026-09-06 - Conservative numeric paragraph repetition + +### What changed + +- `detectors/collapse-paragraphs.ts` retains its byte-exact hashes and adds a second hash only for conservative prose numeric drift: one sentinel replaces a bounded multi-digit ASCII run only when it is whitespace-bounded. +- Normalized candidates are rejected for code/math syntax, numbered-list lines, identifiers, more than two numeric runs per paragraph, and any paragraph whose text spans a tool-progress epoch. Exact candidates retain the existing behavior across tool progress. +- `watch.ts`, `types.ts`, and `index.ts` track a per-generation tool-progress epoch. Tool call start, delta, and end events advance it before text detector dispatch. + +### Why + +A model can loop through long, otherwise identical prose while changing only multi-digit status values. That loop can consume an unbounded stream, but truncating code, dates, lists, identifiers, or tool-backed progress would discard meaningful output. The deliberately narrow grammar favors false negatives over destructive false positives. + +### Why an extension could not handle it + +Not applicable: the TTSR extension already owns streamed paragraph evidence, system-abort remediation, truncation, recovery nudges, and the public `message_update` lifecycle. No provider or `AgentSession` changes are required. + +### Expected merge conflict zones + +- LOW: `detectors/collapse-paragraphs.ts` hash state and candidate selection; preserve the exact hash path and existing remediation offsets. +- LOW: `watch.ts`, `types.ts`, and `index.ts` stream event wiring; advance progress before dispatching text and keep paragraph collapse disabled for tool streams. +- Coverage: detector tests pin exact repeats, per-character/random chunking, numeric drift, tool progress, code/math/identifier and punctuation negatives; faux-provider tests pin exactly one system abort/recovery and tool-progress preservation. + + ## 2026-09-03 - Within-message paragraph repetition ### What changed and why diff --git a/packages/coding-agent/src/core/extensions/builtin/ttsr/detectors/collapse-paragraphs.ts b/packages/coding-agent/src/core/extensions/builtin/ttsr/detectors/collapse-paragraphs.ts index d2691ffb68..f9cdda6ec9 100644 --- a/packages/coding-agent/src/core/extensions/builtin/ttsr/detectors/collapse-paragraphs.ts +++ b/packages/coding-agent/src/core/extensions/builtin/ttsr/detectors/collapse-paragraphs.ts @@ -13,11 +13,19 @@ const HASH_A_OFFSET = 0x811c9dc5; const HASH_A_PRIME = 0x01000193; const HASH_B_OFFSET = 5381; const HASH_B_MULTIPLIER = 31; +const NUMBER_SENTINEL = 0x110000; +const MAX_NORMALIZED_DIGIT_RUN = 32; +const MAX_NORMALIZED_NUMERIC_RUNS_PER_PARAGRAPH = 2; interface ParagraphEntry { readonly hashA: number; readonly hashB: number; readonly utf16Length: number; + readonly normalizedHashA: number; + readonly normalizedHashB: number; + readonly normalizedLength: number; + readonly normalizationSafe: boolean; + readonly progressEpoch: number | undefined; readonly startOffset: number; readonly text: string | undefined; } @@ -31,12 +39,27 @@ export interface ParagraphRepeatState { lineHasContent: boolean; lineStartOffset: number; lineText: string; + lineNormalizedHashA: number; + lineNormalizedHashB: number; + lineNormalizedLength: number; + lineNormalizationSafe: boolean; + linePreviousWasWhitespace: boolean; + numberRun: string; + numberRunStartsAfterWhitespace: boolean; + numberRunAtLineStart: boolean; + codeFence: { readonly marker: "`" | "~"; readonly length: number } | undefined; hashA: number; hashB: number; length: number; wordChars: number; startOffset: number; retained: string; + normalizedHashA: number; + normalizedHashB: number; + normalizedLength: number; + normalizationSafe: boolean; + progressEpoch: number | undefined; + numericRunCount: number; } export function createParagraphRepeatState(): ParagraphRepeatState { @@ -49,12 +72,27 @@ export function createParagraphRepeatState(): ParagraphRepeatState { lineHasContent: false, lineStartOffset: 0, lineText: "", + lineNormalizedHashA: HASH_A_OFFSET, + lineNormalizedHashB: HASH_B_OFFSET, + lineNormalizedLength: 0, + lineNormalizationSafe: true, + linePreviousWasWhitespace: true, + numberRun: "", + numberRunStartsAfterWhitespace: false, + numberRunAtLineStart: false, + codeFence: undefined, hashA: HASH_A_OFFSET, hashB: HASH_B_OFFSET, length: 0, wordChars: 0, startOffset: 0, retained: "", + normalizedHashA: HASH_A_OFFSET, + normalizedHashB: HASH_B_OFFSET, + normalizedLength: 0, + normalizationSafe: true, + progressEpoch: undefined, + numericRunCount: 0, }; } @@ -62,35 +100,105 @@ function isSameParagraph(a: ParagraphEntry, b: ParagraphEntry): boolean { return a.hashA === b.hashA && a.hashB === b.hashB && a.utf16Length === b.utf16Length; } +function isSameNormalizedParagraph(a: ParagraphEntry, b: ParagraphEntry): boolean { + return ( + a.normalizationSafe && + b.normalizationSafe && + a.progressEpoch === b.progressEpoch && + a.normalizedHashA === b.normalizedHashA && + a.normalizedHashB === b.normalizedHashB && + a.normalizedLength === b.normalizedLength + ); +} + +function appendNormalizedCode(state: ParagraphRepeatState, code: number): void { + state.lineNormalizedHashA = Math.imul(state.lineNormalizedHashA ^ code, HASH_A_PRIME); + state.lineNormalizedHashB = (Math.imul(state.lineNormalizedHashB, HASH_B_MULTIPLIER) + code) | 0; + state.lineNormalizedLength += 1; +} + +function appendNormalizedText(state: ParagraphRepeatState, value: string): void { + for (let index = 0; index < value.length; index++) appendNormalizedCode(state, value.charCodeAt(index)); +} + +function flushNumberRun(state: ParagraphRepeatState, nextIsWhitespace: boolean): void { + if (state.numberRun.length === 0) return; + const normalize = state.lineNormalizationSafe && state.numberRunStartsAfterWhitespace && nextIsWhitespace; + if (normalize) { + appendNormalizedCode(state, NUMBER_SENTINEL); + } else { + appendNormalizedText(state, state.numberRun); + } + state.numberRun = ""; + state.numberRunStartsAfterWhitespace = false; + state.numberRunAtLineStart = false; +} + +function resetLine(state: ParagraphRepeatState, startOffset: number): void { + state.lineHashA = HASH_A_OFFSET; + state.lineHashB = HASH_B_OFFSET; + state.lineLength = 0; + state.lineWordChars = 0; + state.lineHasContent = false; + state.lineStartOffset = startOffset; + state.lineText = ""; + state.lineNormalizedHashA = HASH_A_OFFSET; + state.lineNormalizedHashB = HASH_B_OFFSET; + state.lineNormalizedLength = 0; + state.lineNormalizationSafe = true; + state.linePreviousWasWhitespace = true; + state.numberRun = ""; + state.numberRunStartsAfterWhitespace = false; + state.numberRunAtLineStart = false; +} + +function resetParagraph(state: ParagraphRepeatState): void { + state.hashA = HASH_A_OFFSET; + state.hashB = HASH_B_OFFSET; + state.length = 0; + state.wordChars = 0; + state.startOffset = 0; + state.retained = ""; + state.normalizedHashA = HASH_A_OFFSET; + state.normalizedHashB = HASH_B_OFFSET; + state.normalizedLength = 0; + state.normalizationSafe = true; + state.progressEpoch = undefined; + state.numericRunCount = 0; +} + function completeParagraph(state: ParagraphRepeatState): DetectorMatch | null { const paragraph: ParagraphEntry = { hashA: state.hashA, hashB: state.hashB, utf16Length: state.length, + normalizedHashA: state.normalizedHashA, + normalizedHashB: state.normalizedHashB, + normalizedLength: state.normalizedLength, + normalizationSafe: state.normalizationSafe, + progressEpoch: state.progressEpoch, startOffset: state.startOffset, text: state.retained.length > 0 ? state.retained : undefined, }; const eligible = state.length >= PARAGRAPH_MIN_CHARS && state.wordChars >= PARAGRAPH_MIN_WORD_CHARS; - state.hashA = HASH_A_OFFSET; - state.hashB = HASH_B_OFFSET; - state.length = 0; - state.wordChars = 0; - state.startOffset = 0; - state.retained = ""; + resetParagraph(state); if (!eligible) return null; - // Oldest -> newest, so `first` is the earliest occurrence and `second` the first repeat. - let occurrences = 1; - let first: ParagraphEntry | undefined; - let second: ParagraphEntry | undefined; + + const exactMatches: ParagraphEntry[] = []; + const normalizedMatches: ParagraphEntry[] = []; for (let back = state.ring.size - 1; back >= 0; back--) { const previous = state.ring.getBack(back); - if (previous === undefined || !isSameParagraph(previous, paragraph)) continue; - occurrences += 1; - if (first === undefined) first = previous; - else if (second === undefined) second = previous; + if (previous === undefined) continue; + if (isSameParagraph(previous, paragraph)) exactMatches.push(previous); + if (isSameNormalizedParagraph(previous, paragraph)) normalizedMatches.push(previous); } + const normalized = exactMatches.length < PARAGRAPH_REPEAT_THRESHOLD - 1; + const matches = normalized ? normalizedMatches : exactMatches; state.ring.push(paragraph); - if (occurrences < PARAGRAPH_REPEAT_THRESHOLD || first === undefined || second === undefined) return null; + if (matches.length < PARAGRAPH_REPEAT_THRESHOLD - 1) return null; + const [first, second] = matches; + if (first === undefined || second === undefined) return null; + const occurrences = matches.length + 1; return { rule: "collapse-repetition", reason: `paragraph repeated ${occurrences} times within one message (${paragraph.utf16Length} chars)`, @@ -100,42 +208,112 @@ function completeParagraph(state: ParagraphRepeatState): DetectorMatch | null { mechanism: "paragraph-repeat", occurrences, paragraphChars: paragraph.utf16Length, + ...(normalized ? { normalized: true } : {}), sample: (first.text ?? "").slice(0, SAMPLE_LENGTH), }, }; } -export function updateParagraphRepeats(state: ParagraphRepeatState, entry: ScalarEntry): DetectorMatch | null { +function noteProgressEpoch(state: ParagraphRepeatState, progressEpoch: number): void { + if (state.progressEpoch === undefined) { + state.progressEpoch = progressEpoch; + } else if (state.progressEpoch !== progressEpoch) { + state.normalizationSafe = false; + } +} + +function updateLineSafety(state: ParagraphRepeatState): void { + const fenceMatch = /^[\t ]*(`{3,}|~{3,})/.exec(state.lineText); + const fence = fenceMatch?.[1]; + const marker = fence?.[0]; + if (state.codeFence !== undefined) { + state.lineNormalizationSafe = false; + if ( + fenceMatch !== null && + fence !== undefined && + marker === state.codeFence.marker && + fence.length >= state.codeFence.length && + state.lineLength === state.lineText.length && + state.lineText.slice(fenceMatch[0].length).trim().length === 0 + ) { + state.codeFence = undefined; + } + } else if (fence !== undefined && (marker === "`" || marker === "~")) { + state.lineNormalizationSafe = false; + state.codeFence = { marker, length: fence.length }; + } + if (/\b(?:step|phase|item)\s+\d+\s+of\b/i.test(state.lineText)) state.lineNormalizationSafe = false; +} + +function updateNormalizedLine(state: ParagraphRepeatState, entry: ScalarEntry, lineWasEmpty: boolean): void { + const codePoint = entry.value.codePointAt(0) ?? 0; + const isDigit = codePoint >= 48 && codePoint <= 57; + if (isDigit) { + if (state.numberRun.length === 0) { + state.numberRunStartsAfterWhitespace = state.linePreviousWasWhitespace; + state.numberRunAtLineStart = lineWasEmpty; + state.numericRunCount += 1; + if (state.numericRunCount > MAX_NORMALIZED_NUMERIC_RUNS_PER_PARAGRAPH) { + state.normalizationSafe = false; + } + } + if (state.numberRun.length < MAX_NORMALIZED_DIGIT_RUN) { + state.numberRun += entry.value; + } else { + state.lineNormalizationSafe = false; + } + state.linePreviousWasWhitespace = false; + return; + } + + if (state.numberRunAtLineStart && (entry.value === "." || entry.value === ")")) state.lineNormalizationSafe = false; + flushNumberRun(state, isAsciiWhitespace(codePoint)); + if (entry.value === "`" || ";={}[]*/^".includes(entry.value)) state.lineNormalizationSafe = false; + appendNormalizedText(state, entry.value); + state.linePreviousWasWhitespace = isAsciiWhitespace(codePoint); +} + +export function updateParagraphRepeats( + state: ParagraphRepeatState, + entry: ScalarEntry, + progressEpoch = 0, +): DetectorMatch | null { if (entry.value.charCodeAt(0) === CharCode.LineFeed) { let result: DetectorMatch | null = null; if (state.lineHasContent) { + updateLineSafety(state); + flushNumberRun(state, true); if (state.length === 0) state.startOffset = state.lineStartOffset; state.hashA = Math.imul(state.hashA ^ state.lineHashA, HASH_A_PRIME); state.hashB = (Math.imul(state.hashB, HASH_B_MULTIPLIER) + state.lineHashB) | 0; state.length += state.lineLength + 1; state.wordChars += state.lineWordChars; if (state.retained.length < PARAGRAPH_TEXT_RETENTION_MAX) state.retained += `${state.lineText}\n`; + state.normalizedHashA = Math.imul(state.normalizedHashA ^ state.lineNormalizedHashA, HASH_A_PRIME); + state.normalizedHashB = (Math.imul(state.normalizedHashB, HASH_B_MULTIPLIER) + state.lineNormalizedHashB) | 0; + state.normalizedLength += state.lineNormalizedLength + 1; + state.normalizationSafe &&= state.lineNormalizationSafe; } else if (state.length > 0) { result = completeParagraph(state); } - state.lineHashA = HASH_A_OFFSET; - state.lineHashB = HASH_B_OFFSET; - state.lineLength = 0; - state.lineWordChars = 0; - state.lineHasContent = false; - state.lineStartOffset = entry.startOffset + 1; - state.lineText = ""; + resetLine(state, entry.startOffset + 1); return result; } - for (let i = 0; i < entry.value.length; i++) { - const code = entry.value.charCodeAt(i); + + for (let index = 0; index < entry.value.length; index++) { + const code = entry.value.charCodeAt(index); state.lineHashA = Math.imul(state.lineHashA ^ code, HASH_A_PRIME); state.lineHashB = (Math.imul(state.lineHashB, HASH_B_MULTIPLIER) + code) | 0; } const codePoint = entry.value.codePointAt(0) ?? 0; - if (!isAsciiWhitespace(codePoint)) state.lineHasContent = true; + const lineWasEmpty = !state.lineHasContent; + if (!isAsciiWhitespace(codePoint)) { + state.lineHasContent = true; + noteProgressEpoch(state, progressEpoch); + } if (isAsciiAlphanumeric(codePoint) || (codePoint > 0x7f && !isBoxDrawing(codePoint))) state.lineWordChars += 1; state.lineLength += entry.width; if (state.lineText.length < PARAGRAPH_TEXT_RETENTION_MAX) state.lineText += entry.value; + updateNormalizedLine(state, entry, lineWasEmpty); return null; } diff --git a/packages/coding-agent/src/core/extensions/builtin/ttsr/detectors/collapse.ts b/packages/coding-agent/src/core/extensions/builtin/ttsr/detectors/collapse.ts index 266df25fb8..ad95d91b73 100644 --- a/packages/coding-agent/src/core/extensions/builtin/ttsr/detectors/collapse.ts +++ b/packages/coding-agent/src/core/extensions/builtin/ttsr/detectors/collapse.ts @@ -52,7 +52,7 @@ function checkDelta(state: CollapseState, delta: string, context: DetectorContex updateWhitespaceFlood(state.whitespace, entry) ?? updateShortPeriods(state.periods, entry, state.tailRing) ?? updateLineCycles(state.lines, entry) ?? - (watchParagraphs ? updateParagraphRepeats(state.paragraphs, entry) : null); + (watchParagraphs ? updateParagraphRepeats(state.paragraphs, entry, context.toolProgressEpoch) : null); if (match !== null) { state.latched = match; return match; diff --git a/packages/coding-agent/src/core/extensions/builtin/ttsr/index.ts b/packages/coding-agent/src/core/extensions/builtin/ttsr/index.ts index c25217fa9c..ffdabc1f58 100644 --- a/packages/coding-agent/src/core/extensions/builtin/ttsr/index.ts +++ b/packages/coding-agent/src/core/extensions/builtin/ttsr/index.ts @@ -187,6 +187,10 @@ export default function ttsrExtension(pi: ExtensionAPI): void { pi.on("message_update", (event: MessageUpdateEvent, ctx) => { ensureInitialized(ctx); if (disabled || manager === null || watcher === null) return; + const eventType = event.assistantMessageEvent.type; + if (eventType === "toolcall_start" || eventType === "toolcall_delta" || eventType === "toolcall_end") { + watcher.observeToolProgress(); + } const streamDelta = getTtsrStreamDelta(event); if (streamDelta === null) return; const { source, streamKey, delta, toolName } = streamDelta; diff --git a/packages/coding-agent/src/core/extensions/builtin/ttsr/types.ts b/packages/coding-agent/src/core/extensions/builtin/ttsr/types.ts index 357e47b8ff..9c8a3e66d1 100644 --- a/packages/coding-agent/src/core/extensions/builtin/ttsr/types.ts +++ b/packages/coding-agent/src/core/extensions/builtin/ttsr/types.ts @@ -43,6 +43,7 @@ export interface DetectorContext { readonly source: TtsrStreamSource; readonly streamKey: string; readonly generation: number; + readonly toolProgressEpoch: number; } export interface DetectorMatch { diff --git a/packages/coding-agent/src/core/extensions/builtin/ttsr/watch.ts b/packages/coding-agent/src/core/extensions/builtin/ttsr/watch.ts index ee351c57aa..33a91e1f4a 100644 --- a/packages/coding-agent/src/core/extensions/builtin/ttsr/watch.ts +++ b/packages/coding-agent/src/core/extensions/builtin/ttsr/watch.ts @@ -20,6 +20,7 @@ export class StreamWatcher { readonly #leakDetector = createControlLeakDetector(); readonly #disabledBuiltin: ReadonlySet; readonly #tracks = new Map(); + #toolProgressEpoch = 0; constructor(manager: TtsrManager, disabledBuiltinRules: readonly string[]) { this.#manager = manager; @@ -28,9 +29,14 @@ export class StreamWatcher { reset(): void { this.#tracks.clear(); + this.#toolProgressEpoch = 0; this.#manager.resetBuffers(); } + observeToolProgress(): void { + this.#toolProgressEpoch += 1; + } + handleDelta( source: "text" | "thinking" | "tool", streamKey: string, @@ -39,7 +45,12 @@ export class StreamWatcher { toolName?: string, ): WatchOutcome { const track = this.#trackFor(source, streamKey); - const detectorCtx: DetectorContext = { source, streamKey, generation }; + const detectorCtx: DetectorContext = { + source, + streamKey, + generation, + toolProgressEpoch: this.#toolProgressEpoch, + }; const leakMatch = this.#disabledBuiltin.has(CONTROL_LEAK_RULE_NAME) ? null : this.#leakDetector.checkDelta(track.leak, delta, detectorCtx); diff --git a/packages/coding-agent/src/modes/print-mode.ts b/packages/coding-agent/src/modes/print-mode.ts index fe58008ad6..59287e05b2 100644 --- a/packages/coding-agent/src/modes/print-mode.ts +++ b/packages/coding-agent/src/modes/print-mode.ts @@ -144,6 +144,8 @@ export async function runPrintMode(runtimeHost: AgentSessionRuntime, options: Pr await session.prompt(message, { sessionTitlePrompt: false }); } + await session.waitForSettledSessionWork(); + if (mode === "text") { const state = session.state; const lastMessage = state.messages.findLast((message) => message.role === "assistant"); @@ -166,7 +168,6 @@ export async function runPrintMode(runtimeHost: AgentSessionRuntime, options: Pr } } - await session.waitForSettledSessionWork(); return exitCode; } catch (error: unknown) { console.error(error instanceof Error ? error.message : String(error)); diff --git a/packages/coding-agent/test/suite/regressions/issue-1329-print-settled-trigger.test.ts b/packages/coding-agent/test/suite/regressions/issue-1329-print-settled-trigger.test.ts new file mode 100644 index 0000000000..554d980a4a --- /dev/null +++ b/packages/coding-agent/test/suite/regressions/issue-1329-print-settled-trigger.test.ts @@ -0,0 +1,85 @@ +import { join } from "node:path"; +import { fauxAssistantMessage } from "@earendil-works/pi-ai"; +import { describe, expect, it, vi } from "vitest"; +import { AgentSessionRuntime } from "../../../src/core/agent-session-runtime.ts"; +import { runPrintMode } from "../../../src/modes/print-mode.ts"; +import { getModelRuntime } from "../../model-runtime-test-utils.ts"; +import { createTestResourceLoader } from "../../utilities.ts"; +import { createHarness } from "../harness.ts"; + +const output = vi.hoisted((): { lines: string[] } => ({ lines: [] })); + +vi.mock("../../../src/core/output-guard.ts", () => ({ + flushRawStdout: async () => {}, + waitForRawStdoutBackpressure: async () => {}, + writeRawStdout: (text: string) => output.lines.push(text), +})); + +describe("issue #1329: print waits for a settled-event trigger", () => { + it("prints the final continuation instead of the preceding response", async () => { + output.lines = []; + const hookEntered = Promise.withResolvers(); + const releaseHook = Promise.withResolvers(); + const providerEntered = Promise.withResolvers(); + const releaseProvider = Promise.withResolvers(); + let sent = false; + const harness = await createHarness({ + extensionFactories: [ + (pi) => { + pi.on("before_agent_start", async (event) => { + if (event.prompt !== "issue-1329-continuation") return; + hookEntered.resolve(); + await releaseHook.promise; + }); + pi.on("agent_settled", () => { + if (sent) return; + sent = true; + pi.sendMessage( + { customType: "issue-1329-recovery", content: "issue-1329-continuation", display: false }, + { triggerTurn: true }, + ); + }); + }, + ], + }); + harness.setResponses([ + fauxAssistantMessage("ISSUE_1329_PRECEDING"), + async () => { + providerEntered.resolve(); + await releaseProvider.promise; + return fauxAssistantMessage("ISSUE_1329_FINAL"); + }, + ]); + const runtime = new AgentSessionRuntime( + harness.session, + { + cwd: harness.tempDir, + agentDir: join(harness.tempDir, "agent"), + authStorage: harness.authStorage, + modelRegistry: harness.modelRegistry, + modelRuntime: getModelRuntime(harness.modelRegistry), + settingsManager: harness.settingsManager, + resourceLoader: createTestResourceLoader(), + diagnostics: [], + }, + async () => { + throw new Error("This scenario does not replace the runtime"); + }, + ); + const printed = runPrintMode(runtime, { mode: "text", initialMessage: "normal" }); + try { + await hookEntered.promise; + releaseHook.resolve(); + await providerEntered.promise; + releaseProvider.resolve(); + + expect(await printed).toBe(0); + expect(output.lines.join("")).toBe("ISSUE_1329_FINAL\n"); + } finally { + releaseHook.resolve(); + releaseProvider.resolve(); + await printed; + harness.cleanup(); + } + }); +}); diff --git a/packages/coding-agent/test/suite/regressions/issue-1330-nested-fence-control.test.ts b/packages/coding-agent/test/suite/regressions/issue-1330-nested-fence-control.test.ts new file mode 100644 index 0000000000..2f00184e5f --- /dev/null +++ b/packages/coding-agent/test/suite/regressions/issue-1330-nested-fence-control.test.ts @@ -0,0 +1,81 @@ +import { describe, expect, it } from "vitest"; +import { + createParagraphRepeatState, + updateParagraphRepeats, +} from "../../../src/core/extensions/builtin/ttsr/detectors/collapse-paragraphs.ts"; +import type { DetectorMatch } from "../../../src/core/extensions/builtin/ttsr/types.ts"; + +function paragraph(step: number): string { + return `I am carefully describing the exact same implementation plan for this task, but now writing step ${step} with no substantive progress at all.`; +} + +function detect(text: string): DetectorMatch[] { + const state = createParagraphRepeatState(); + const matches: DetectorMatch[] = []; + let offset = 0; + for (const value of text) { + const match = updateParagraphRepeats(state, { value, width: value.length, startOffset: offset }); + offset += value.length; + if (match !== null) matches.push(match); + } + return matches; +} + +describe("issue #1330: numeric prose inside code fences", () => { + it("does not close a four-backtick fence with a shorter nested fence", () => { + const text = [ + "````markdown", + "```text", + "", + paragraph(3), + "", + paragraph(4), + "", + paragraph(5), + "", + "```", + "````", + "", + ].join("\n"); + + expect(detect(text)).toEqual([]); + }); + + it("does not treat a fence with trailing text as a closing fence", () => { + const text = [ + "```text", + "```not-a-closing-fence", + "", + paragraph(3), + "", + paragraph(4), + "", + paragraph(5), + "", + "```", + "", + ].join("\n"); + + expect(detect(text)).toEqual([]); + }); + + it("detects a numeric loop after the actual closing fence", () => { + const text = [ + "````markdown", + "```text", + "sample", + "```", + "````", + "", + paragraph(3), + "", + paragraph(4), + "", + paragraph(5), + "", + "", + ].join("\n"); + + expect(detect(text)).toHaveLength(1); + }); +}); diff --git a/packages/coding-agent/test/suite/ttsr-extension.test.ts b/packages/coding-agent/test/suite/ttsr-extension.test.ts index 14a4b90970..d01242ddb3 100644 --- a/packages/coding-agent/test/suite/ttsr-extension.test.ts +++ b/packages/coding-agent/test/suite/ttsr-extension.test.ts @@ -1,5 +1,5 @@ import { readFileSync } from "node:fs"; -import { fauxAssistantMessage, fauxText, fauxThinking } from "@earendil-works/pi-ai"; +import { fauxAssistantMessage, fauxText, fauxThinking, fauxToolCall } from "@earendil-works/pi-ai"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import ttsrExtension from "../../src/core/extensions/builtin/ttsr/index.ts"; @@ -26,6 +26,10 @@ function ctrlToken(name: string): string { return ["<", "|", name, "|", ">"].join(""); } +function numericParagraph(first: number, second: number): string { + return `This status report records ${first} completed checks and ${second} pending checks while the implementation team preserves every scoped result, documents each concrete action, and keeps the recovery path precise for the next review.`; +} + function readSessionLines(harness: Harness): string[] { const file = harness.sessionManager.getSessionFile(); if (file === undefined) { @@ -129,9 +133,26 @@ describe("fabricated unavailable-tool call remediation", () => { describe("collapse remediation persistence", () => { let harness: Harness; + let abortSources: Array; + let streamEventTypes: string[]; beforeEach(async () => { - harness = await createHarness({ extensionFactories: [ttsrExtension], persistSession: true }); + abortSources = []; + streamEventTypes = []; + harness = await createHarness({ + extensionFactories: [ + ttsrExtension, + (pi) => { + pi.on("agent_end", (event) => { + abortSources.push(event.abortSource); + }); + pi.on("message_update", (event) => { + streamEventTypes.push(event.assistantMessageEvent.type); + }); + }, + ], + persistSession: true, + }); }); afterEach(() => { @@ -173,6 +194,79 @@ describe("collapse remediation persistence", () => { expect(getMessageText(assistantEntries[1]?.message)).toContain("recovered answer"); }); + + it("interrupts a numeric-only paragraph loop, truncates it, and completes one recovery turn", async () => { + const paragraphs = [numericParagraph(101, 201), numericParagraph(102, 202), numericParagraph(103, 203)]; + const loopText = `${paragraphs.join("\n\n")}\n\n`; + harness.setResponses([ + fauxAssistantMessage([fauxText(loopText)]), + fauxAssistantMessage([fauxText("recovered after numeric paragraph loop")]), + ]); + + await harness.session.prompt("do work"); + + const entries = readSessionEntries(harness); + const assistants = entries.filter((entry) => entry.type === "message" && entry.message?.role === "assistant"); + const aborted = assistants[0]?.message; + expect(abortSources).toEqual(["system", undefined]); + expect(harness.faux.getCallLog()).toHaveLength(2); + expect(aborted?.stopReason).toBe("aborted"); + expect(streamText(aborted, "text")).toContain(paragraphs[0]); + expect(streamText(aborted, "text")).not.toContain(paragraphs[1]); + expect(ttsrNudges(harness)).toHaveLength(1); + expect(streamText(assistants[1]?.message, "text")).toContain("recovered after numeric paragraph loop"); + }); + + it("keeps numeric paragraphs when tool progress separates them", async () => { + const paragraphs = [numericParagraph(101, 201), numericParagraph(102, 202), numericParagraph(103, 203)]; + harness.setResponses([ + fauxAssistantMessage( + [ + fauxText(`${paragraphs[0]}\n\n`), + fauxToolCall("bash", { command: "printf first-progress" }, { id: "first-progress" }), + fauxText(`${paragraphs[1]}\n\n`), + fauxToolCall("bash", { command: "printf second-progress" }, { id: "second-progress" }), + fauxText(`${paragraphs[2]}\n\n`), + ], + { stopReason: "toolUse" }, + ), + fauxAssistantMessage([fauxText("final after tool progress")]), + ]); + + await harness.session.prompt("do work"); + + const entries = readSessionEntries(harness); + const assistants = entries.filter((entry) => entry.type === "message" && entry.message?.role === "assistant"); + expect(abortSources).toEqual([undefined]); + expect(harness.faux.getCallLog()).toHaveLength(2); + expect(ttsrNudges(harness)).toEqual([]); + expect(streamText(assistants[0]?.message, "text")).toContain(paragraphs[2]); + expect(streamText(assistants[1]?.message, "text")).toContain("final after tool progress"); + const firstToolEnd = streamEventTypes.indexOf("toolcall_end"); + const secondTextStart = streamEventTypes.indexOf("text_start", firstToolEnd + 1); + const secondToolEnd = streamEventTypes.indexOf("toolcall_end", secondTextStart + 1); + const thirdTextStart = streamEventTypes.indexOf("text_start", secondToolEnd + 1); + expect(firstToolEnd).toBeGreaterThan(streamEventTypes.indexOf("text_end")); + expect(secondTextStart).toBeGreaterThan(firstToolEnd); + expect(secondToolEnd).toBeGreaterThan(secondTextStart); + expect(thirdTextStart).toBeGreaterThan(secondToolEnd); + }); + + it("keeps three single-digit code and fenced-code paragraphs without a remediation", async () => { + const codeParagraph = (value: number) => + `const retryLimit = ${value}; const detail = "This code paragraph stays long enough to be eligible while its literal is meaningful program data.";`; + const unfenced = [3, 4, 5].map(codeParagraph).join("\n\n"); + const fenced = `\`\`\`ts\n${[3, 4, 5].map(codeParagraph).join("\n\n")}\n\`\`\``; + harness.setResponses([fauxAssistantMessage([fauxText(`${unfenced}\n\n${fenced}\n\n`)])]); + + await harness.session.prompt("do work"); + + expect(abortSources).toEqual([undefined]); + expect(harness.faux.getCallLog()).toHaveLength(1); + expect(ttsrNudges(harness)).toEqual([]); + expect(getMessageText(harness.session.messages.at(-1))).toContain(codeParagraph(5)); + expect(streamEventTypes.filter((type) => type === "text_delta")).not.toHaveLength(0); + }); }); describe("leakage remediation retry", () => { diff --git a/packages/coding-agent/test/ttsr/control-leak-helpers.ts b/packages/coding-agent/test/ttsr/control-leak-helpers.ts index 07665a12de..bdb3265020 100644 --- a/packages/coding-agent/test/ttsr/control-leak-helpers.ts +++ b/packages/coding-agent/test/ttsr/control-leak-helpers.ts @@ -25,7 +25,12 @@ export function bracket(name: string): string { return [LEFT_BRACKET, name, RIGHT_BRACKET].join(""); } -export const CONTROL_LEAK_CTX: DetectorContext = { source: "thinking", streamKey: "fixture", generation: 1 }; +export const CONTROL_LEAK_CTX: DetectorContext = { + source: "thinking", + streamKey: "fixture", + generation: 1, + toolProgressEpoch: 0, +}; export const PLAIN_PROSE_PREFIX = "We reviewed the failing render together and compared both panels side by side. " + diff --git a/packages/coding-agent/test/ttsr/detector-collapse-paragraphs.test.ts b/packages/coding-agent/test/ttsr/detector-collapse-paragraphs.test.ts index 96b1d1b721..042ef2a99c 100644 --- a/packages/coding-agent/test/ttsr/detector-collapse-paragraphs.test.ts +++ b/packages/coding-agent/test/ttsr/detector-collapse-paragraphs.test.ts @@ -11,12 +11,20 @@ import { lcg } from "./collapse-test-inputs.ts"; type Source = DetectorContext["source"]; -const context: DetectorContext = { source: "text", streamKey: "text:0", generation: 1 }; +const context: DetectorContext = { source: "text", streamKey: "text:0", generation: 1, toolProgressEpoch: 0 }; function narration(i: number): string { return `Now I'm writing step ${i} of the plan: defining the shared context block with rules and tool guidance, then each research lane with its own scoped prompt and report path. The implementation keeps every result precise and useful.`; } +function numericNarration(first: number, second: number): string { + return `This status report records ${first} completed checks and ${second} pending checks while the implementation team preserves every scoped result, documents each concrete action, and keeps the recovery path precise for the next review.`; +} + +function originalSingleDigitNarration(step: number): string { + return `I am carefully describing the exact same implementation plan for this task, but now writing step ${step} with no substantive progress at all.`; +} + function loop(cycle: number, cycles: number, separator = "\n\n"): string { const block = Array.from({ length: cycle }, (_, i) => narration(i)).join(separator); return `${Array.from({ length: cycles }, () => block).join(separator)}${separator}`; @@ -52,6 +60,21 @@ function direct(input: string): DetectorMatch | null { return match; } +function numericLoop(values: readonly [number, number][]): string { + return `${values.map(([first, second]) => numericNarration(first, second)).join("\n\n")}\n\n`; +} + +function feedAtEpochs(segments: readonly { readonly text: string; readonly epoch: number }[]): DetectorMatch | null { + const state = createCollapseState(); + let match: DetectorMatch | null = null; + for (const segment of segments) { + for (const char of segment.text) { + match ??= collapseDetector.checkDelta(state, char, { ...context, toolProgressEpoch: segment.epoch }); + } + } + return match; +} + describe("paragraph repetition detector", () => { it("fires when the same 7-paragraph cycle streams three times", () => { const input = loop(7, 3); @@ -66,6 +89,72 @@ describe("paragraph repetition detector", () => { it("stays silent after only two occurrences", () => expect(perChar(loop(7, 2))).toBeNull()); + it("detects the original single-digit no-progress loop", () => { + const input = `${[3, 4, 5].map(originalSingleDigitNarration).join("\n\n")}\n\n`; + const match = perChar(input); + expect(match?.rule).toBe("collapse-repetition"); + expect(match?.detail).toMatchObject({ mechanism: "paragraph-repeat", normalized: true, occurrences: 3 }); + expect(match?.anomalyStartOffset).toBe(0); + expect(match?.garbageStartOffset).toBe(`${originalSingleDigitNarration(3)}\n\n`.length); + }); + + it("keeps exact matching byte-exact while detecting three prose paragraphs with numeric drift", () => { + const exact = `${numericNarration(101, 201)}\n\n`.repeat(3); + const input = numericLoop([ + [101, 201], + [102, 202], + [103, 203], + ]); + const expectedGarbageStart = `${numericNarration(101, 201)}\n\n`.length; + const match = perChar(input); + + expect(direct(exact)?.detail).toMatchObject({ mechanism: "paragraph-repeat", occurrences: 3 }); + expect(direct(input)?.detail).toMatchObject({ normalized: true, occurrences: 3 }); + expect(match?.rule).toBe("collapse-repetition"); + expect(match?.anomalyStartOffset).toBe(0); + expect(match?.garbageStartOffset).toBe(expectedGarbageStart); + expect(random(input, 901)).toEqual(match); + }); + + it("does not normalize numeric drift across tool progress", () => { + const paragraphs = [numericNarration(101, 201), numericNarration(102, 202), numericNarration(103, 203)]; + expect(feedAtEpochs(paragraphs.map((text, epoch) => ({ text: `${text}\n\n`, epoch })))).toBeNull(); + }); + + it("keeps byte-exact repeats active across tool progress", () => { + const paragraph = numericNarration(101, 201); + const match = feedAtEpochs([0, 1, 2].map((epoch) => ({ text: `${paragraph}\n\n`, epoch }))); + expect(match?.detail).toMatchObject({ mechanism: "paragraph-repeat", occurrences: 3 }); + expect(match?.detail.normalized).toBeUndefined(); + }); + + it("does not normalize changed prose, identifiers, code, math lists, punctuation, or whitespace", () => { + const prose = numericNarration(101, 201); + const changedProse = prose.replace("pending checks", "blocked checks"); + const identifiers = (id: number) => + `The worker${id} summary gives a detailed narrative with enough ordinary words to qualify as a paragraph while preserving the exact identifier for the next implementation review.`; + const code = (value: number) => + `const retryLimit = ${value}; const summary = "The implementation keeps this code sample long enough to qualify as an eligible paragraph without treating its values as prose progress.";`; + const structuredStep = (step: number) => + `I am recording step ${step} of the seven-step implementation plan with enough detailed prose to remain an eligible paragraph while preserving the meaningful planned sequence.`; + const mathList = (value: number) => + `${value}. Preserve the first mathematical checkpoint with enough explanatory prose for eligibility.\n${value + 1}. Preserve the second mathematical checkpoint with enough explanatory prose for eligibility.`; + const numericList = (value: number) => + `The mathematical checkpoint list contains ${value}, ${value + 100}, and ${value + 200} as meaningful values while the detailed explanation remains long enough to qualify as a paragraph.`; + + expect(perChar(`${prose}\n\n${prose}\n\n${changedProse}\n\n`)).toBeNull(); + expect(perChar(`${identifiers(3)}\n\n${identifiers(4)}\n\n${identifiers(5)}\n\n`)).toBeNull(); + expect(perChar(`${code(3)}\n\n${code(4)}\n\n${code(5)}\n\n`)).toBeNull(); + expect(perChar(`\`\`\`ts\n${code(3)}\n\n${code(4)}\n\n${code(5)}\n\`\`\`\n\n`)).toBeNull(); + expect(perChar(`${structuredStep(3)}\n\n${structuredStep(4)}\n\n${structuredStep(5)}\n\n`)).toBeNull(); + expect(perChar(`${mathList(3)}\n\n${mathList(4)}\n\n${mathList(5)}\n\n`)).toBeNull(); + expect(perChar(`${numericList(101)}\n\n${numericList(102)}\n\n${numericList(103)}\n\n`)).toBeNull(); + expect(perChar(`${prose}\n\n${prose.replace("checks and", "checks, and")}\n\n${prose}\n\n`)).toBeNull(); + expect( + perChar(`${prose}\n\n${prose.replace("completed checks", "completed checks")}\n\n${prose}\n\n`), + ).toBeNull(); + }); + it("ignores short paragraphs and punctuation-only paragraphs", () => { expect(direct("Done.\n\n".repeat(5))).toBeNull(); expect(direct(`${"-".repeat(80)}\n\n`.repeat(4))).toBeNull(); diff --git a/packages/coding-agent/test/ttsr/detector-collapse.test.ts b/packages/coding-agent/test/ttsr/detector-collapse.test.ts index 98ba322768..a90f4fe4ee 100644 --- a/packages/coding-agent/test/ttsr/detector-collapse.test.ts +++ b/packages/coding-agent/test/ttsr/detector-collapse.test.ts @@ -41,8 +41,13 @@ interface FeedOutcome { readonly latchedStable: boolean; } -const FEED_CONTEXT: DetectorContext = { source: "thinking", streamKey: "collapse-test", generation: 1 }; -const TOOL_FEED_CONTEXT: DetectorContext = { source: "tool", streamKey: "tool:0", generation: 1 }; +const FEED_CONTEXT: DetectorContext = { + source: "thinking", + streamKey: "collapse-test", + generation: 1, + toolProgressEpoch: 0, +}; +const TOOL_FEED_CONTEXT: DetectorContext = { source: "tool", streamKey: "tool:0", generation: 1, toolProgressEpoch: 0 }; function feedChunks(chunks: readonly string[]): FeedOutcome { const state = createCollapseState(); From e1e610e9cb148002b40f54507364b745442f8881 Mon Sep 17 00:00:00 2001 From: effortprogrammer Date: Sun, 6 Sep 2026 23:35:42 +0900 Subject: [PATCH 3/8] fix(coding-agent): publish hydrated transcript history atomically Fixes #1076. Keep incomplete renders on the initial visible boundary while warming caches, preserve live appends and resize, and publish full history once ready. --- .../scripts/scenarios/issue-1076-qa.mjs | 407 ++++++++++++++++++ .../src/modes/interactive/changes.md | 18 + .../progressive-transcript-container.ts | 51 ++- .../progressive-transcript-container.test.ts | 44 ++ 4 files changed, 500 insertions(+), 20 deletions(-) create mode 100755 .agents/skills/senpi-qa/scripts/scenarios/issue-1076-qa.mjs diff --git a/.agents/skills/senpi-qa/scripts/scenarios/issue-1076-qa.mjs b/.agents/skills/senpi-qa/scripts/scenarios/issue-1076-qa.mjs new file mode 100755 index 0000000000..e4f075b01e --- /dev/null +++ b/.agents/skills/senpi-qa/scripts/scenarios/issue-1076-qa.mjs @@ -0,0 +1,407 @@ +#!/usr/bin/env node +/** + * Real native-PTY regression proof for #1076. + * + * Resumes a 5,000-message sandbox session at both 80 and 120 columns. The + * resize, scroll-to-top, and live prompt are triggered by the actual tail-frame + * PTY output, not a delay, while the container still has deferred history. + */ +import { createWriteStream, existsSync, readFileSync, realpathSync, writeFileSync } from "node:fs"; +import { once } from "node:events"; +import { finished } from "node:stream/promises"; +import { createRequire } from "node:module"; +import { dirname, join } from "node:path"; +import { pathToFileURL } from "node:url"; +import { spawnSync } from "node:child_process"; +import { + cliEntry, + evidenceDir, + guardRealAuth, + makeSandbox, + repoRoot, + stripAnsi, + tsxEntry, +} from "../lib/common.mjs"; +import { startFakeModelServer } from "../lib/fake-model-server.mjs"; +import { hermeticEnv, writeMockModelsJson } from "../lib/mock-loop-support.mjs"; +import { teardownPty } from "../lib/tui-resume-teardown.mjs"; + +const require = createRequire(import.meta.url); +const ROWS = 34; +const MESSAGE_COUNT = 5000; +const SESSION_ID = "issue-1076-resume"; +const HEAD_MARKER = "Issue1076FullHistoryHeadA1B2"; +const TAIL_MARKER = "Issue1076InitialTailE5F6"; +const SESSION_LAST_MARKER = "Issue1076SessionLastG7H8"; +const LIVE_MARKER = "Issue1076LiveAppendI9J0"; +const BOOT_TIMEOUT_MS = 60_000; +const RESUME_TIMEOUT_MS = 60_000; +const COMPLETE_TIMEOUT_MS = 180_000; +const COMMAND = "node .agents/skills/senpi-qa/scripts/scenarios/issue-1076-qa.mjs --evidence issue-1076 --self-test"; + +function parseArgs(argv) { + let evidence; + let targetRoot; + let selfTest = false; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === "--self-test") { + selfTest = true; + continue; + } + if (arg === "--evidence" || arg === "--target-root") { + const value = argv[++index]; + if (!value) throw new Error(`${arg} requires a value`); + if (arg === "--evidence") evidence = value; + else targetRoot = value; + continue; + } + throw new Error(`Unknown option: ${arg}`); + } + if (!evidence) throw new Error("--evidence is required"); + return { evidence, selfTest, targetRoot }; +} + +function ensureNodePtySpawnHelperExecutable() { + if (process.platform === "win32") return; + const { chmodSync, statSync } = require("node:fs"); + const packagePath = require.resolve("node-pty/package.json"); + const helper = join(dirname(packagePath), "prebuilds", `${process.platform}-${process.arch}`, "spawn-helper"); + if (!existsSync(helper)) return; + const mode = statSync(helper).mode & 0o777; + if ((mode & 0o111) === 0) chmodSync(helper, mode | 0o755); +} + +async function loadNodePty() { + ensureNodePtySpawnHelperExecutable(); + const mod = await import("node-pty"); + return mod.default ?? mod; +} + +function attachStream(term, events) { + let exit; + let resolveExit; + const exitPromise = new Promise((resolve) => { + resolveExit = resolve; + }); + const stream = { raw: "", exit: undefined, exitPromise }; + term.onData((data) => { + stream.raw += data; + events.push({ type: "write", data }); + for (const listener of [...listeners]) listener(); + }); + term.onExit((event) => { + exit = event; + stream.exit = event; + resolveExit(event); + for (const listener of [...listeners]) listener(); + }); + const listeners = new Set(); + return { + stream, + waitFor(predicate, timeoutMs, label) { + return new Promise((resolve, reject) => { + let settled = false; + const finish = (error) => { + if (settled) return; + settled = true; + clearTimeout(timer); + listeners.delete(inspect); + if (error) reject(error); + else resolve(stream.raw); + }; + const inspect = () => { + if (predicate(stream.raw)) finish(); + else if (exit) finish(new Error(`${label}: PTY exited before the expected output`)); + }; + const timer = setTimeout(() => finish(new Error(`${label} timed out after ${timeoutMs}ms`)), timeoutMs); + listeners.add(inspect); + inspect(); + }); + }, + }; +} + +async function writeSession(path, cwd) { + const stream = createWriteStream(path); + const write = async (record) => { + if (!stream.write(`${JSON.stringify(record)}\n`)) await once(stream, "drain"); + }; + const timestamp = 1_800_000_000_000; + await write({ type: "session", version: 3, id: SESSION_ID, timestamp: new Date(timestamp).toISOString(), cwd }); + let parentId = null; + for (let index = 1; index <= MESSAGE_COUNT; index += 1) { + const historyMarker = `Issue1076History-${String(index).padStart(4, "0")}`; + const text = + index === 1 + ? `${HEAD_MARKER} ${historyMarker}` + : index === 4996 + ? `${TAIL_MARKER} ${historyMarker}` + : index === MESSAGE_COUNT + ? `${SESSION_LAST_MARKER} ${historyMarker}` + : historyMarker; + const messageTimestamp = timestamp + index; + const id = `message-${index}`; + await write({ + type: "message", + id, + parentId, + timestamp: new Date(messageTimestamp).toISOString(), + message: { role: "user", content: [{ type: "text", text }], timestamp: messageTimestamp }, + }); + parentId = id; + } + stream.end(); + await finished(stream); +} + +function check(rows, name, pass, detail = "") { + rows.push({ name, pass: Boolean(pass), detail }); + process.stdout.write(`[${pass ? "PASS" : "FAIL"}] ${name}${detail ? ` - ${detail}` : ""}\n`); +} + +function sanitizedRequests(requests) { + return requests.map((request) => ({ method: request.method, url: request.url, model: request.model, stream: request.stream })); +} + +function writeRenderObserver(box, root, logPath) { + const componentUrl = pathToFileURL( + join(root, "packages", "coding-agent", "src", "modes", "interactive", "components", "progressive-transcript-container.ts"), + ).href; + const source = ` +import { appendFileSync } from "node:fs"; +import { ProgressiveTranscriptContainer } from ${JSON.stringify(componentUrl)}; + +const logPath = ${JSON.stringify(logPath)}; +const originalRender = ProgressiveTranscriptContainer.prototype.render; +ProgressiveTranscriptContainer.prototype.render = function(width) { + const beforeFullyHydrated = this.isFullyHydrated; + const lines = originalRender.call(this, width); + const marker = lines.join("\\n").match(/Issue1076History-(\\d+)/u); + appendFileSync(logPath, JSON.stringify({ + width, + beforeFullyHydrated, + afterFullyHydrated: this.isFullyHydrated, + firstPersistedIndex: marker === null ? null : Number(marker[1]), + }) + "\\n"); + return lines; +}; + +export default function issue1076RenderObserver() {} +`; + const path = join(box.dir, "issue-1076-render-observer.mjs"); + writeFileSync(path, source); + return path; +} + +function readRenderObservations(path) { + if (!existsSync(path)) return []; + return readFileSync(path, "utf8") + .split("\n") + .filter(Boolean) + .map((line) => JSON.parse(line)); +} + +async function runWidth({ root, evidence, initialCols, resizeCols, server }) { + const box = makeSandbox(`issue-1076-${initialCols}`); + const guard = guardRealAuth(); + const events = []; + const actions = []; + const initialRequestCount = server.requests.length; + let sequence = 0; + let term; + let driver; + let runError; + let receipt; + const event = (type, detail) => actions.push({ sequence: ++sequence, type, ...detail }); + try { + const cwd = realpathSync(box.cwd); + await writeSession(join(box.sessionDir, `2027-01-15T00-00-01-000Z_${SESSION_ID}.jsonl`), cwd); + writeMockModelsJson(box.agentDir, server, "openai-completions"); + const observationPath = join(box.dir, "render-observations.jsonl"); + const observerExtension = writeRenderObserver(box, root, observationPath); + const pty = await loadNodePty(); + term = pty.spawn( + process.execPath, + [ + tsxEntry(root), + "--tsconfig", + join(root, "tsconfig.json"), + cliEntry(root), + "--no-context-files", + "--no-skills", + "--no-extensions", + "--extension", + observerExtension, + "--approve", + "--tui-mode", + "fullscreen", + "--provider", + "mock", + "--model", + "mock-model", + ], + { name: "xterm-256color", cols: initialCols, rows: ROWS, cwd, env: hermeticEnv({ ...box.env, TERM: "xterm-256color", COLORTERM: "truecolor" }) }, + ); + driver = attachStream(term, events); + const { stream } = driver; + await driver.waitFor((raw) => stripAnsi(raw).includes("senpi v"), BOOT_TIMEOUT_MS, `boot at ${initialCols} columns`); + event("boot", { cols: initialCols, rows: ROWS, sentinel: "senpi v" }); + + const selector = driver.waitFor( + (raw) => stripAnsi(raw).includes("Resume Session") && stripAnsi(raw).includes(HEAD_MARKER), + RESUME_TIMEOUT_MS, + `resume selector at ${initialCols} columns`, + ); + term.write("/resume\r"); + event("input", { data: "/resume\\r" }); + await selector; + + const resumeOffset = stream.raw.length; + const tailFrame = driver.waitFor( + (raw) => stripAnsi(raw.slice(resumeOffset)).includes(TAIL_MARKER), + RESUME_TIMEOUT_MS, + `initial tail frame at ${initialCols} columns`, + ); + term.write("\r"); + event("input", { data: "\\r", select: "latest" }); + await tailFrame; + event("tail-frame", { marker: TAIL_MARKER, rawOffset: stream.raw.length, cols: initialCols, rows: ROWS }); + + const triggerOffset = stream.raw.length; + const fullHistory = driver.waitFor( + (raw) => stripAnsi(raw.slice(triggerOffset)).includes(HEAD_MARKER), + COMPLETE_TIMEOUT_MS, + `full history reveal at ${initialCols} columns`, + ); + const liveAppend = driver.waitFor( + (raw) => stripAnsi(raw.slice(triggerOffset)).includes(LIVE_MARKER), + COMPLETE_TIMEOUT_MS, + `live append at ${initialCols} columns`, + ); + term.resize(resizeCols, ROWS); + events.push({ type: "resize", cols: resizeCols, rows: ROWS, snapshot: "resize-trigger" }); + event("resize", { cols: resizeCols, rows: ROWS, after: "tail-frame" }); + term.write("\x1b[H"); + event("input", { data: "\\u001b[H", key: "home" }); + term.write("append the issue-1076 live marker\r"); + event("input", { data: "append the issue-1076 live marker\\r", after: "resize" }); + await fullHistory; + term.write("\x1b[F"); + event("input", { data: "\\u001b[F", key: "end", after: "full-history" }); + await liveAppend; + event("complete", { headMarker: HEAD_MARKER, liveMarker: LIVE_MARKER, cols: resizeCols, rows: ROWS }); + + const headOffset = stream.raw.indexOf(HEAD_MARKER, triggerOffset); + const liveOffset = stream.raw.indexOf(LIVE_MARKER, triggerOffset); + const observations = readRenderObservations(observationPath); + const initialTailRender = observations.find( + (observation) => observation.width === initialCols && !observation.beforeFullyHydrated && observation.firstPersistedIndex !== null, + ); + const incompleteResizeRender = observations.find( + (observation) => observation.width === resizeCols && !observation.beforeFullyHydrated && observation.firstPersistedIndex !== null, + ); + const checks = []; + check(checks, `initial ${initialCols}-column tail rendered before trigger`, stream.raw.slice(resumeOffset, triggerOffset).includes(TAIL_MARKER)); + check(checks, `resize caused an actual incomplete TUI render at ${resizeCols} columns`, incompleteResizeRender !== undefined, JSON.stringify(incompleteResizeRender)); + check( + checks, + `incomplete ${resizeCols}-column resize did not publish any partial prefix`, + initialTailRender !== undefined && incompleteResizeRender?.firstPersistedIndex === initialTailRender.firstPersistedIndex, + `initial=${JSON.stringify(initialTailRender)} resize=${JSON.stringify(incompleteResizeRender)}`, + ); + check(checks, `full history reached the top at ${resizeCols} columns`, headOffset >= 0, `headOffset=${headOffset}`); + check(checks, `live append survived hydration at ${resizeCols} columns`, liveOffset >= 0, `liveOffset=${liveOffset}`); + const requestCount = server.requests.length - initialRequestCount; + check(checks, `one local fake-model request completed at ${initialCols} columns`, requestCount === 1, `requests=${requestCount}`); + + const prefix = join(evidence, `resume-${initialCols}-to-${resizeCols}`); + writeFileSync(`${prefix}.ans`, stream.raw); + events.at(-1).snapshot = "complete"; + writeFileSync(`${prefix}.events.json`, `${JSON.stringify({ cols: initialCols, rows: ROWS, scrollback: 20_000, events }, null, 2)}\n`); + writeFileSync(`${prefix}.actions.json`, `${JSON.stringify(actions, null, 2)}\n`); + writeFileSync(`${prefix}.render-observations.json`, `${JSON.stringify(observations, null, 2)}\n`); + const replay = spawnSync(process.execPath, [join(root, "scripts", "qa", "xterm-render.mjs"), "replay", `${prefix}.events.json`, "--out-json", `${prefix}.grid.json`], { + cwd: root, + encoding: "utf8", + }); + check(checks, `ordered ${initialCols}/${resizeCols} replay produced grids`, replay.status === 0, replay.stderr || replay.stdout); + writeFileSync(`${prefix}.replay.log`, `${replay.stdout}${replay.stderr}`); + const rendered = spawnSync( + process.execPath, + [ + join(root, "scripts", "qa", "xterm-render.mjs"), + "render", + `${prefix}.ans`, + "--cols", + String(resizeCols), + "--rows", + String(ROWS), + "--out-json", + `${prefix}.final.grid.json`, + "--out-html", + `${prefix}.html`, + "--title", + `Issue #1076 resume ${initialCols} to ${resizeCols}`, + ], + { cwd: root, encoding: "utf8" }, + ); + check(checks, `xterm HTML capture produced at ${resizeCols} columns`, rendered.status === 0, rendered.stderr || rendered.stdout); + writeFileSync(`${prefix}.render.log`, `${rendered.stdout}${rendered.stderr}`); + writeFileSync(`${prefix}.checks.json`, `${JSON.stringify(checks, null, 2)}\n`); + return { checks, prefix }; + } catch (error) { + runError = error; + return { checks: [{ name: `runtime at ${initialCols} columns`, pass: false, detail: error instanceof Error ? error.stack : String(error) }], prefix: join(evidence, `resume-${initialCols}-to-${resizeCols}`) }; + } finally { + if (term && driver) { + try { + receipt = await teardownPty(term, driver.stream); + } catch (error) { + receipt = error.receipt ?? { ptyExited: false, error: error instanceof Error ? error.message : String(error) }; + } + } + box.cleanup(); + const cleanup = { + ptyExited: receipt?.ptyExited ?? !term, + sandboxRemoved: !existsSync(box.dir), + authUnchanged: guard.assertUnchanged(), + runError: runError instanceof Error ? runError.message : undefined, + }; + writeFileSync(join(evidence, `resume-${initialCols}-to-${resizeCols}.cleanup.json`), `${JSON.stringify(cleanup, null, 2)}\n`); + if (runError && driver) { + writeFileSync(join(evidence, `resume-${initialCols}-to-${resizeCols}.failure.ans`), driver.stream.raw); + } + } +} + +async function main() { + const options = parseArgs(process.argv.slice(2)); + const root = realpathSync(options.targetRoot ?? repoRoot()); + if (!existsSync(cliEntry(root)) || !existsSync(tsxEntry(root))) { + throw new Error(`--target-root must contain source CLI and tsx dependencies: ${root}`); + } + const evidence = evidenceDir(options.evidence); + const server = await startFakeModelServer({ turns: [{ text: LIVE_MARKER }] }); + let results; + try { + results = [ + await runWidth({ root, evidence, initialCols: 80, resizeCols: 120, server }), + await runWidth({ root, evidence, initialCols: 120, resizeCols: 80, server }), + ]; + } finally { + await server.stop(); + } + const checks = results.flatMap((result) => result.checks); + const passed = checks.every((item) => item.pass); + writeFileSync(join(evidence, "command.txt"), `${COMMAND}\n`); + writeFileSync(join(evidence, "requests.json"), `${JSON.stringify(sanitizedRequests(server.requests), null, 2)}\n`); + writeFileSync(join(evidence, "summary.json"), `${JSON.stringify({ selfTest: options.selfTest, passed, checks, widths: [80, 120], rows: ROWS }, null, 2)}\n`); + process.stderr.write(`evidence: ${evidence}\n`); + if (!passed) process.exitCode = 1; +} + +main().catch((error) => { + process.stderr.write(`${error instanceof Error ? error.stack : String(error)}\n`); + process.exitCode = 1; +}); diff --git a/packages/coding-agent/src/modes/interactive/changes.md b/packages/coding-agent/src/modes/interactive/changes.md index dbe78f6c4e..d00cf0e4dd 100644 --- a/packages/coding-agent/src/modes/interactive/changes.md +++ b/packages/coding-agent/src/modes/interactive/changes.md @@ -1,4 +1,22 @@ +## 2026-09-06 - Keep progressive transcript warming private until completion (#1076) + +### What changed + +- `packages/coding-agent/src/modes/interactive/components/progressive-transcript-container.ts` now keeps separate visible and warmed history boundaries. Background chunks populate deferred child caches without changing the incomplete frame; only the completed pass publishes the full transcript in its existing single repaint. + +### Why + +- The previous shared boundary moved after every warm chunk. Any unrelated TUI render, including a live append or resize, could expose a partial history prefix before hydration had completed, making a resumed transcript visibly jump. The fixed visible boundary preserves the original tail and live appends at every width until the atomic full-history reveal. + +### Why an extension could not handle it + +- The boundary controls the private render scheduling and child range passed to the interactive TUI container before extension UI can observe or alter the frame. + +### Expected merge conflict zones + +- LOW: `packages/coding-agent/src/modes/interactive/components/progressive-transcript-container.ts` around hydration boundary initialization, chunk completion, and reset handling. + ## 2026-09-05 - Restore Working text shimmer on turn start ### What changed diff --git a/packages/coding-agent/src/modes/interactive/components/progressive-transcript-container.ts b/packages/coding-agent/src/modes/interactive/components/progressive-transcript-container.ts index d1f4045256..615781de5e 100644 --- a/packages/coding-agent/src/modes/interactive/components/progressive-transcript-container.ts +++ b/packages/coding-agent/src/modes/interactive/components/progressive-transcript-container.ts @@ -42,12 +42,18 @@ export class ProgressiveTranscriptContainer extends Container { private readonly requestRender: () => void; /** - * Index of the first child proven renderable, or `PENDING_FIRST_PAINT` before - * any frame has been painted. Walks down to 0 as hydration warms the history. - * A distinct sentinel is required because 0 legitimately means "fully - * hydrated", which is also the state of a freshly cleared transcript. + * Index of the first child published to the TUI. It is fixed to the first + * frame's tail boundary until the entire deferred head has warmed, then drops + * to zero in one atomic completion repaint. */ - private hydratedFrom: number = PENDING_FIRST_PAINT; + private visibleFrom: number = PENDING_FIRST_PAINT; + + /** + * Index of the next deferred child to warm. Unlike `visibleFrom`, this moves + * toward zero in background chunks and is never exposed by an incomplete + * render. + */ + private warmedFrom: number = PENDING_FIRST_PAINT; private hydrationScheduled = false; private hydrationGeneration = 0; /** @@ -70,30 +76,32 @@ export class ProgressiveTranscriptContainer extends Container { /** True when every child has been rendered at least once and no work is pending. */ get isFullyHydrated(): boolean { - return this.hydratedFrom === 0 && !this.hydrationScheduled; + return this.visibleFrom === 0 && !this.hydrationScheduled; } override render(width: number): string[] { this.lastRenderWidth = width; const total = this.children.length; - if (this.hydratedFrom === 0 || total === 0) { - this.hydratedFrom = 0; + if (this.visibleFrom === 0 || total === 0) { + this.visibleFrom = 0; + this.warmedFrom = 0; return super.render(width); } const firstVisible = Math.max(0, total - this.tailBudget); if (firstVisible === 0) { // Whole transcript fits the visible budget: nothing is worth deferring. - this.hydratedFrom = 0; + this.visibleFrom = 0; + this.warmedFrom = 0; return super.render(width); } - // Never move the watermark forward: a child warmed by an earlier chunk must - // stay warm even when later frames only need the tail. - this.hydratedFrom = - this.hydratedFrom === PENDING_FIRST_PAINT ? firstVisible : Math.min(this.hydratedFrom, firstVisible); + if (this.visibleFrom === PENDING_FIRST_PAINT) { + this.visibleFrom = firstVisible; + this.warmedFrom = firstVisible; + } this.scheduleHydration(); - return this.renderRange(this.hydratedFrom, total, width); + return this.renderRange(this.visibleFrom, total, width); } // `addChild` is inherited: a live message appended before hydration finishes @@ -101,13 +109,15 @@ export class ProgressiveTranscriptContainer extends Container { override clear(): void { this.cancelHydration(); - this.hydratedFrom = PENDING_FIRST_PAINT; + this.visibleFrom = PENDING_FIRST_PAINT; + this.warmedFrom = PENDING_FIRST_PAINT; super.clear(); } override detachAll(): void { this.cancelHydration(); - this.hydratedFrom = PENDING_FIRST_PAINT; + this.visibleFrom = PENDING_FIRST_PAINT; + this.warmedFrom = PENDING_FIRST_PAINT; super.detachAll(); } @@ -157,19 +167,20 @@ export class ProgressiveTranscriptContainer extends Container { */ private warmNextChunk(generation: number): void { if (this.hydrationHalted || generation !== this.hydrationGeneration) return; - if (this.hydratedFrom === 0) return; + if (this.warmedFrom === 0) return; - const chunkEnd = this.hydratedFrom; + const chunkEnd = this.warmedFrom; const chunkStart = Math.max(0, chunkEnd - this.warmChunkSize); const width = this.lastRenderWidth; if (width !== undefined) { // Discard the lines: this pass exists only to fill each child's cache. this.renderRange(chunkStart, chunkEnd, width); } - this.hydratedFrom = chunkStart; + this.warmedFrom = chunkStart; if (chunkStart === 0) { - // The whole transcript is renderable now; ask the TUI to repaint it. + // The whole transcript is renderable now; publish it in one repaint. + this.visibleFrom = 0; this.requestRender(); return; } diff --git a/packages/coding-agent/test/suite/progressive-transcript-container.test.ts b/packages/coding-agent/test/suite/progressive-transcript-container.test.ts index b9034517b6..17ac193340 100644 --- a/packages/coding-agent/test/suite/progressive-transcript-container.test.ts +++ b/packages/coding-agent/test/suite/progressive-transcript-container.test.ts @@ -55,6 +55,11 @@ function countingLines(index: number): readonly [string, string] { return [`component-${index}-w${WIDTH}`, `component-${index}-body`]; } +function firstRenderedComponentIndex(lines: readonly string[]): number | undefined { + const first = lines.find((line) => /^component-\d+-w\d+$/u.test(line)); + return first === undefined ? undefined : Number(/^component-(\d+)-w\d+$/u.exec(first)?.[1]); +} + function createProgressive(rerender: () => void): ProgressiveTranscriptContainer { return new ProgressiveTranscriptContainer({ tailBudget: TAIL_BUDGET, @@ -102,6 +107,45 @@ describe("ProgressiveTranscriptContainer", () => { expect(lines).toStrictEqual(expectedTail.flatMap((component) => countingLines(component.index))); }); + // Issue #1076: warming cached head components must not publish a partial prefix. + it("keeps the initial tail boundary through unrelated renders and a resize while hydration is incomplete", async () => { + // Given: enough deferred history that one warm chunk cannot finish hydration + const container = createProgressive(() => {}); + populate(container, LARGE_TRANSCRIPT); + + // When: the first tail frame is followed by exactly one warming macrotask + const firstFrame = container.render(120); + const firstVisible = firstRenderedComponentIndex(firstFrame); + expect(firstVisible).toBe(LARGE_TRANSCRIPT - TAIL_BUDGET); + await new Promise((resolve) => setImmediate(resolve)); + expect(container.isFullyHydrated).toBe(false); + + // And: a live child arrives while an unrelated render and resize occur. + const live = new CountingComponent(LARGE_TRANSCRIPT); + container.addChild(live); + const resizedFrame = container.render(80); + + // Then: only the original tail and the live append are visible; warmed head + // rows do not leak into the incomplete frame. + expect(firstRenderedComponentIndex(resizedFrame)).toBe(firstVisible); + expect(resizedFrame).toContain(`component-${firstVisible}-w80`); + expect(resizedFrame.slice(-2)).toStrictEqual([ + `component-${LARGE_TRANSCRIPT}-w80`, + `component-${LARGE_TRANSCRIPT}-body`, + ]); + expect(live.renderCount).toBe(1); + + // And: the one atomic completion reveal still publishes the full history at + // the resized width, including the appended live tail. + await awaitHydration(container, LARGE_TRANSCRIPT / WARM_CHUNK + 8); + const complete = container.render(80); + expect(firstRenderedComponentIndex(complete)).toBe(0); + expect(complete.slice(-2)).toStrictEqual([ + `component-${LARGE_TRANSCRIPT}-w80`, + `component-${LARGE_TRANSCRIPT}-body`, + ]); + }); + it("eventually renders the full history exactly like an ordinary Container", async () => { // Given: identical transcripts in a plain Container and the progressive one const baseline = new Container(); From 944ccdcb69670dbf5fbc8b4a61e4dce9b74fb984 Mon Sep 17 00:00:00 2001 From: effortprogrammer Date: Mon, 7 Sep 2026 00:39:30 +0900 Subject: [PATCH 4/8] fix(ai): align generated reasoning controls with adapters Fixes #891. Constrain 58 built-in catalog entries to implemented controls, preserve graded models, remove the stale Xiaomi override, and regenerate only selected provider artifacts with validated selectors. --- .../scripts/scenarios/issue-891-qa.mjs | 178 +++++++++ .../scripts/scenarios/issue-891-tui-qa.mjs | 361 ++++++++++++++++++ packages/ai/changes.md | 21 + packages/ai/scripts/generate-models.ts | 122 +++++- packages/ai/src/changes.md | 18 + packages/ai/src/providers/all.ts | 1 - packages/ai/src/providers/data/.manifest.json | 2 +- .../providers/data/alibaba-token-plan.json | 2 +- .../ai/src/providers/data/moonshotai-cn.json | 2 +- .../ai/src/providers/data/moonshotai.json | 2 +- .../ai/src/providers/data/opencode-go.json | 2 +- packages/ai/src/providers/data/opencode.json | 2 +- .../providers/data/qwen-token-plan-cn.json | 2 +- .../data/qwen-token-plan-individual.json | 2 +- .../src/providers/data/qwen-token-plan.json | 2 +- .../providers/data/xiaomi-token-plan-ams.json | 2 +- .../providers/data/xiaomi-token-plan-cn.json | 2 +- .../providers/data/xiaomi-token-plan-sgp.json | 2 +- packages/ai/src/providers/data/xiaomi.json | 2 +- .../ai/src/providers/data/zai-coding-cn.json | 2 +- packages/ai/src/providers/data/zai.json | 2 +- .../ai/test/generate-models-strict.test.ts | 90 +++++ .../issue-891-thinking-capabilities.test.ts | 83 ++++ ...openai-completions-thinking-matrix.test.ts | 72 +++- .../openai-completions-tool-choice.test.ts | 4 +- 25 files changed, 941 insertions(+), 39 deletions(-) create mode 100644 .agents/skills/senpi-qa/scripts/scenarios/issue-891-qa.mjs create mode 100644 .agents/skills/senpi-qa/scripts/scenarios/issue-891-tui-qa.mjs create mode 100644 packages/ai/test/issue-891-thinking-capabilities.test.ts diff --git a/.agents/skills/senpi-qa/scripts/scenarios/issue-891-qa.mjs b/.agents/skills/senpi-qa/scripts/scenarios/issue-891-qa.mjs new file mode 100644 index 0000000000..aa93e93651 --- /dev/null +++ b/.agents/skills/senpi-qa/scripts/scenarios/issue-891-qa.mjs @@ -0,0 +1,178 @@ +#!/usr/bin/env node +/** + * Real source-CLI proof for #891 generated reasoning capabilities. + * + * Uses built-in metadata with sandbox provider baseUrl overrides, so the catalog + * remains the production generated catalog while every request goes to a local + * OpenAI-compatible server. The RPC CLI command surface dispatches the same + * /reasoning and /efforts commands as the interactive TUI. + */ +import { existsSync, readFileSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; +import { + createChecks, + evidenceDir, + guardRealAuth, + installCleanupHooks, + makeSandbox, + repoRoot, +} from "../lib/common.mjs"; +import { startFakeModelServer } from "../lib/fake-model-server.mjs"; +import { hermeticEnv } from "../lib/mock-loop-support.mjs"; +import { TargetRpcClient } from "../lib/target-rpc-client.mjs"; + +const XIAOMI_PROVIDER = "xiaomi"; +const XIAOMI_MODEL = "mimo-v2.5-pro"; +const QWEN_PROVIDER = "qwen-token-plan"; +const QWEN_MODEL = "qwen3.8-max"; +const ON_OFF_ERROR = `Reasoning effort is not configurable for ${XIAOMI_PROVIDER}/${XIAOMI_MODEL}; this model supports on/off only. Use /reasoning on or /reasoning off.`; + +function argument(name, fallback) { + const index = process.argv.indexOf(name); + return index >= 0 ? process.argv[index + 1] : fallback; +} + +function writeOverrides(agentDir, baseUrl) { + writeFileSync( + join(agentDir, "models.json"), + JSON.stringify( + { + providers: { + [XIAOMI_PROVIDER]: { baseUrl, apiKey: "xiaomi-local-qa", api: "openai-completions" }, + [QWEN_PROVIDER]: { baseUrl, apiKey: "qwen-local-qa", api: "openai-completions" }, + }, + }, + null, + 2, + ), + ); +} + +async function main() { + installCleanupHooks(); + const evidence = evidenceDir(argument("--evidence", "issue-891")); + const checks = createChecks("issue-891-qa"); + const guard = guardRealAuth(); + const box = makeSandbox("issue-891-qa"); + const env = hermeticEnv(box.env); + let server; + let client; + let serverStopped = false; + let sandboxRemoved = false; + + try { + server = await startFakeModelServer({ + turns: [{ text: "OFF-WIRE" }, { text: "ON-WIRE" }, { text: "GRADED-WIRE" }], + }); + writeOverrides(box.agentDir, server.url); + client = new TargetRpcClient({ env, cwd: box.cwd, targetRoot: repoRoot(), extraArgs: ["--multi-session"] }); + const openXiaomi = await client.send({ + type: "open_session", + cwd: box.cwd, + provider: XIAOMI_PROVIDER, + modelId: XIAOMI_MODEL, + }); + const xiaomiSession = openXiaomi.data?.sessionId; + checks.ok("opens the built-in Xiaomi model through the real source CLI", openXiaomi.success === true && !!xiaomiSession); + const sendXiaomi = (command) => client.send({ ...command, sessionId: xiaomiSession }); + + const offNotify = client.waitFor( + (event) => event.message.type === "extension_ui_request" && event.message.method === "notify" && event.message.sessionId === xiaomiSession, + ); + await sendXiaomi({ type: "prompt", message: "/reasoning off" }); + const offNotification = await offNotify; + checks.ok("/reasoning off is accepted", offNotification.message.message === "Reasoning: off."); + + const offEnd = client.waitFor((event) => event.message.type === "agent_end" && event.message.sessionId === xiaomiSession); + await sendXiaomi({ type: "prompt", message: "Return OFF-WIRE." }); + await offEnd; + checks.ok("off turn reaches the local fake server", server.requests.length === 1); + checks.ok( + "off turn serializes documented disabled thinking", + server.requests[0]?.body?.thinking?.type === "disabled" && server.requests[0]?.body?.reasoning_effort === undefined, + JSON.stringify(server.requests[0]?.body), + ); + + const onNotify = client.waitFor( + (event) => event.message.type === "extension_ui_request" && event.message.method === "notify" && event.message.sessionId === xiaomiSession, + ); + await sendXiaomi({ type: "prompt", message: "/reasoning on" }); + const onNotification = await onNotify; + checks.ok("/reasoning on is accepted", onNotification.message.message === "Reasoning: on (high)."); + + const onEnd = client.waitFor((event) => event.message.type === "agent_end" && event.message.sessionId === xiaomiSession); + await sendXiaomi({ type: "prompt", message: "Return ON-WIRE." }); + await onEnd; + checks.ok( + "on turn serializes enabled thinking without invented effort", + server.requests[1]?.body?.thinking?.type === "enabled" && server.requests[1]?.body?.reasoning_effort === undefined, + JSON.stringify(server.requests[1]?.body), + ); + + const refusedEffort = client.waitFor( + (event) => event.message.type === "extension_ui_request" && event.message.method === "notify" && event.message.sessionId === xiaomiSession, + ); + await sendXiaomi({ type: "prompt", message: "/efforts low" }); + const effortNotification = await refusedEffort; + checks.ok("/efforts is refused for an on/off model", effortNotification.message.message === ON_OFF_ERROR); + checks.ok("refused Xiaomi effort makes no provider request", server.requests.length === 2); + + const openQwen = await client.send({ + type: "open_session", + cwd: box.cwd, + provider: QWEN_PROVIDER, + modelId: QWEN_MODEL, + }); + const qwenSession = openQwen.data?.sessionId; + checks.ok("opens the built-in graded Qwen model", openQwen.success === true && !!qwenSession); + const sendQwen = (command) => client.send({ ...command, sessionId: qwenSession }); + + const gradedNotify = client.waitFor( + (event) => event.message.type === "extension_ui_request" && event.message.method === "notify" && event.message.sessionId === qwenSession, + ); + await sendQwen({ type: "prompt", message: "/efforts low" }); + const gradedNotification = await gradedNotify; + checks.ok("graded /efforts low is accepted", gradedNotification.message.message?.startsWith("Reasoning effort: low.")); + + const gradedEnd = client.waitFor((event) => event.message.type === "agent_end" && event.message.sessionId === qwenSession); + await sendQwen({ type: "prompt", message: "Return GRADED-WIRE." }); + await gradedEnd; + checks.ok( + "graded Qwen request preserves its documented low effort", + server.requests[2]?.body?.enable_thinking === true && server.requests[2]?.body?.reasoning_effort === "low", + JSON.stringify(server.requests[2]?.body), + ); + + const settings = JSON.parse(readFileSync(join(box.agentDir, "settings.json"), "utf8")); + checks.ok( + "valid graded effort persists in sandbox settings", + settings.modelThinkingLevels?.[`${QWEN_PROVIDER}/${QWEN_MODEL}`] === "low", + JSON.stringify(settings.modelThinkingLevels), + ); + writeFileSync( + join(evidence, "issue-891-requests.json"), + JSON.stringify(server.requests.map(({ authorization: _authorization, apiKeyHeader: _apiKeyHeader, ...request }) => request), null, 2), + ); + writeFileSync(join(evidence, "issue-891-events.json"), JSON.stringify(client.events, null, 2)); + } finally { + if (client) await client.close(); + if (server) { + await server.stop(); + serverStopped = true; + } + box.cleanup(); + sandboxRemoved = !existsSync(box.dir); + } + + checks.ok("local fake server stopped", serverStopped); + checks.ok("sandbox removed", sandboxRemoved, box.dir); + checks.ok("real auth unchanged", guard.assertUnchanged(), guard.path); + const passed = checks.finish(); + writeFileSync(join(evidence, "issue-891-summary.json"), JSON.stringify({ passed, serverStopped, sandboxRemoved }, null, 2)); + process.exit(passed ? 0 : 1); +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/.agents/skills/senpi-qa/scripts/scenarios/issue-891-tui-qa.mjs b/.agents/skills/senpi-qa/scripts/scenarios/issue-891-tui-qa.mjs new file mode 100644 index 0000000000..a69a777c6f --- /dev/null +++ b/.agents/skills/senpi-qa/scripts/scenarios/issue-891-tui-qa.mjs @@ -0,0 +1,361 @@ +#!/usr/bin/env node +/** + * Native-PTY TUI proof for #891 reasoning capabilities. + * + * Drives the source CLI under Bun inside a sandbox. The built-in Xiaomi and + * Qwen model records remain authoritative; only their sandbox provider URLs + * and keys point at the local fake server. + * + * Usage: + * node .agents/skills/senpi-qa/scripts/scenarios/issue-891-tui-qa.mjs --evidence issue-891-tui + */ +import { execFileSync } from "node:child_process"; +import { chmodSync, existsSync, readFileSync, statSync, writeFileSync } from "node:fs"; +import { createRequire } from "node:module"; +import { dirname, join } from "node:path"; +import { + createChecks, + evidenceDir, + guardRealAuth, + makeSandbox, + repoRoot, + stripAnsi, +} from "../lib/common.mjs"; +import { startFakeModelServer } from "../lib/fake-model-server.mjs"; +import { hermeticEnv } from "../lib/mock-loop-support.mjs"; +import { teardownPty } from "../lib/tui-resume-teardown.mjs"; + +const require = createRequire(import.meta.url); +const BUN = process.env.SENPI_QA_BUN || "bun"; +const XIAOMI = { provider: "xiaomi", model: "mimo-v2.5-pro" }; +const QWEN = { provider: "qwen-token-plan", model: "qwen3.8-max" }; +const ROWS = 32; +const BOOT_TIMEOUT_MS = 60_000; + +function argument(name, fallback) { + const index = process.argv.indexOf(name); + return index >= 0 ? process.argv[index + 1] : fallback; +} + +function sourceSha(root) { + return execFileSync("git", ["rev-parse", "HEAD"], { cwd: root, encoding: "utf8" }).trim(); +} + +function validateBun(command) { + let version; + try { + version = execFileSync(command, ["--version"], { encoding: "utf8" }).trim(); + } catch (error) { + throw new Error(`Bun executable is unavailable: ${command} (${error instanceof Error ? error.message : String(error)})`); + } + const match = /^(\d+)\.(\d+)(?:\.(\d+))?/.exec(version); + if (!match) throw new Error(`Bun returned an unrecognized version: ${version}`); + const major = Number(match[1]); + const minor = Number(match[2]); + if (major < 1 || (major === 1 && minor < 4)) { + throw new Error(`Bun >=1.4 is required, got ${version} from ${command}`); + } + return { command, version }; +} + +function writeOverrides(agentDir, baseUrl) { + writeFileSync( + join(agentDir, "models.json"), + JSON.stringify( + { + providers: { + [XIAOMI.provider]: { baseUrl, apiKey: "xiaomi-local-qa", api: "openai-completions" }, + [QWEN.provider]: { baseUrl, apiKey: "qwen-local-qa", api: "openai-completions" }, + }, + }, + null, + 2, + ), + ); +} + +function ensureNodePtySpawnHelperExecutable() { + if (process.platform === "win32") return; + const packagePath = require.resolve("node-pty/package.json"); + const helper = join(dirname(packagePath), "prebuilds", `${process.platform}-${process.arch}`, "spawn-helper"); + if (!existsSync(helper)) return; + const mode = statSync(helper).mode & 0o777; + if ((mode & 0o111) === 0) chmodSync(helper, mode | 0o755); +} + +async function loadNodePty() { + ensureNodePtySpawnHelperExecutable(); + const mod = await import("node-pty"); + return mod.default ?? mod; +} + +function normalized(raw) { + // The TUI emits OSC hyperlinks between wrapped rows; remove them before + // matching human-visible notification text across a resize boundary. + return stripAnsi(raw.replace(/\u001b\][^\u0007]*\u0007/g, "")).replace(/\s+/g, " "); +} + +function synchronizedFrameEnd(raw) { + const begin = raw.lastIndexOf("\x1b[?2026h"); + const end = raw.lastIndexOf("\x1b[?2026l"); + return begin >= 0 && end > begin ? end + "\x1b[?2026l".length : -1; +} + +function waitForText(stream, text, { after = 0, label, timeoutMs = BOOT_TIMEOUT_MS, exactBorder = false } = {}) { + return new Promise((resolve, reject) => { + let settled = false; + const inspect = () => { + const frameEnd = synchronizedFrameEnd(stream.raw); + const captured = stream.raw.slice(after); + const matches = exactBorder + ? stripAnsi(captured).match(/\u2500+/g)?.at(-1) === text + : normalized(captured).includes(text); + if (matches && frameEnd >= after) { + finish(resolve, { rawCutoff: stream.raw.length, eventCutoff: stream.events.length, frameEnd }); + } else if (stream.exit) { + finish(reject, new Error(`${label}: PTY exited before ${JSON.stringify(text)} in a complete synchronized frame`)); + } + }; + const timer = setTimeout(() => finish(reject, new Error(`${label} timed out waiting for ${JSON.stringify(text)} in a complete synchronized frame`)), timeoutMs); + const finish = (fn, value) => { + if (settled) return; + settled = true; + clearTimeout(timer); + stream.listeners.delete(inspect); + fn(value); + }; + stream.listeners.add(inspect); + inspect(); + }); +} + +function createStream(term, events) { + const stream = { raw: "", events, exit: null, listeners: new Set(), exitPromise: null, resolveExit: null }; + stream.exitPromise = new Promise((resolve) => { + stream.resolveExit = resolve; + }); + term.onData((data) => { + events.push({ type: "write", data }); + stream.raw += data; + for (const listener of [...stream.listeners]) listener(); + }); + term.onExit((event) => { + stream.exit = event; + stream.resolveExit(event); + for (const listener of [...stream.listeners]) listener(); + }); + return stream; +} + +function recordAction(actions, session, type, detail = {}) { + actions.push({ at: new Date().toISOString(), session, type, ...detail }); +} + +async function openTui({ root, box, bun, env, model, actions, name, runs }) { + const pty = await loadNodePty(); + const term = pty.spawn( + bun.command, + [ + join(root, "packages", "coding-agent", "src", "cli.ts"), + "--no-context-files", + "--no-skills", + "--approve", + "--provider", + model.provider, + "--model", + model.model, + "/reasoning", + ], + { name: "xterm-256color", cols: 80, rows: ROWS, cwd: box.cwd, env }, + ); + const events = [{ type: "resize", cols: 80, rows: ROWS }]; + const stream = createStream(term, events); + const run = { term, stream, events, name, closed: false }; + runs.push(run); + recordAction(actions, name, "spawn", { command: bun.command, bunVersion: bun.version, cols: 80, rows: ROWS, model: `${model.provider}/${model.model}` }); + // InteractiveMode awaits initial messages before it enters getUserInput(), so + // this initial CLI command is a deterministic ready signal for PTY writes. + const ready = await waitForText(stream, "Reasoning: ", { label: `${name} initial /reasoning` }); + recordAction(actions, name, "ready", { sentinel: "Reasoning: ", ...ready }); + return run; +} + +async function resize(run, cols, actions) { + const geometry = waitForText(run.stream, "\u2500".repeat(cols), { + after: run.stream.raw.length, + label: `${run.name} ${cols}-column redraw`, + exactBorder: true, + }); + run.term.resize(cols, ROWS); + run.events.push({ type: "resize", cols, rows: ROWS }); + recordAction(actions, run.name, "resize", { cols, rows: ROWS }); + const frame = await geometry; + recordAction(actions, run.name, "resize-rendered", { cols, rows: ROWS, ...frame }); +} + +async function command(run, text, expected, actions) { + const after = run.stream.raw.length; + const observed = waitForText(run.stream, expected, { after, label: `${run.name} ${text}` }); + const input = `${text}\r`; + run.inputs ??= []; + run.inputs.push(input); + run.term.write(input); + recordAction(actions, run.name, "write", { data: input, expects: expected }); + const observedFrame = await observed; + run.lastObserved = observedFrame; + recordAction(actions, run.name, "observed", { text: expected, ...observedFrame }); +} + +async function closeTui(run, actions) { + if (run.closed) return run.receipt; + run.receipt = await teardownPty(run.term, run.stream); + run.closed = true; + recordAction(actions, run.name, "pty-exit", run.receipt); + return run.receipt; +} + +function captureRun(run, actions) { + const rawCutoff = run.lastObserved?.rawCutoff; + const eventCutoff = run.lastObserved?.eventCutoff; + if (!Number.isInteger(rawCutoff) || !Number.isInteger(eventCutoff) || synchronizedFrameEnd(run.stream.raw.slice(0, rawCutoff)) < 0) { + throw new Error(`${run.name}: cannot capture before a complete synchronized frame`); + } + run.capture = { rawCutoff, eventCutoff }; + recordAction(actions, run.name, "capture", run.capture); +} + +function writeRunEvidence(evidence, run) { + const raw = run.stream.raw.slice(0, run.capture?.rawCutoff); + const events = run.events.slice(0, run.capture?.eventCutoff); + writeFileSync(join(evidence, `${run.name}.ans`), raw); + writeFileSync(join(evidence, `${run.name}.txt`), stripAnsi(raw)); + writeFileSync(join(evidence, `${run.name}-events.json`), `${JSON.stringify({ cols: 80, rows: ROWS, events }, null, 2)}\n`); + return { raw, events }; +} + +async function main() { + const root = repoRoot(); + const evidence = evidenceDir(argument("--evidence", "issue-891-tui")); + const checks = createChecks("issue-891-tui-qa"); + const guard = guardRealAuth(); + const box = makeSandbox("issue-891-tui-qa"); + const env = hermeticEnv({ ...box.env, TERM: "xterm-256color", COLORTERM: "truecolor", PI_SKIP_VERSION_CHECK: "1" }); + const actions = []; + const runs = []; + let server; + let failure; + let serverStopped = false; + let sandboxRemoved = false; + let authUnchanged = false; + + try { + const bun = validateBun(BUN); + server = await startFakeModelServer(); + writeOverrides(box.agentDir, server.url); + + const xiaomi = await openTui({ root, box, bun, env, model: XIAOMI, actions, name: "xiaomi", runs }); + await resize(xiaomi, 120, actions); + await command(xiaomi, "/reasoning off", "Reasoning: off.", actions); + await resize(xiaomi, 80, actions); + await command(xiaomi, "/reasoning on", "Reasoning: on (high).", actions); + await resize(xiaomi, 120, actions); + await command( + xiaomi, + "/efforts low", + "Reasoning effort is not configurable for xiaomi/mimo-v2.5-pro; this model supports on/off only. Use /reasoning on or /reasoning off.", + actions, + ); + captureRun(xiaomi, actions); + await closeTui(xiaomi, actions); + + const qwen = await openTui({ root, box, bun, env, model: QWEN, actions, name: "qwen", runs }); + await resize(qwen, 120, actions); + await command(qwen, "/efforts low", "Reasoning effort: low. Available: low, medium, xhigh.", actions); + await resize(qwen, 80, actions); + await command(qwen, "/reasoning off", "Reasoning: off.", actions); + await command(qwen, "/reasoning on", "Reasoning: on (low).", actions); + captureRun(qwen, actions); + await closeTui(qwen, actions); + + const settings = JSON.parse(readFileSync(join(box.agentDir, "settings.json"), "utf8")); + checks.ok( + "graded effort persists in sandbox settings", + settings.modelThinkingLevels?.[`${QWEN.provider}/${QWEN.model}`] === "low", + JSON.stringify(settings.modelThinkingLevels), + ); + + const qwenRestart = await openTui({ root, box, bun, env, model: QWEN, actions, name: "qwen-restart", runs }); + await resize(qwenRestart, 120, actions); + await command(qwenRestart, "/reasoning", "Reasoning: on (low).", actions); + captureRun(qwenRestart, actions); + await closeTui(qwenRestart, actions); + + const capturedRaw = (run) => run.stream.raw.slice(0, run.capture.rawCutoff); + const capturedEvents = (run) => run.events.slice(0, run.capture.eventCutoff); + const replay = (run) => capturedEvents(run).filter((event) => event.type === "write").map((event) => event.data).join(""); + checks.ok("native PTY ran with Bun >=1.4", true, `${bun.command} ${bun.version}`); + checks.ok("on/off model accepted /reasoning off and on", normalized(capturedRaw(xiaomi)).includes("Reasoning: off.") && normalized(capturedRaw(xiaomi)).includes("Reasoning: on (high).")); + checks.ok("on/off model refused /efforts low", normalized(capturedRaw(xiaomi)).includes("this model supports on/off only.")); + checks.ok("graded model accepted /efforts low", normalized(capturedRaw(qwen)).includes("Reasoning effort: low. Available: low, medium, xhigh.")); + checks.ok("restart observed the persisted graded level", normalized(capturedRaw(qwenRestart)).includes("Reasoning: on (low).")); + checks.ok( + "captured ANSI prefixes equal ordered PTY output writes", + runs.every((run) => capturedEvents(run).some((event) => event.type === "write") && replay(run) === capturedRaw(run)), + runs.map((run) => `${run.name}:${capturedEvents(run).filter((event) => event.type === "write").length}`).join(", "), + ); + checks.ok( + "PTY replay events exclude keyboard writes", + runs.every((run) => capturedEvents(run).every((event) => event.type !== "write" || !run.inputs?.includes(event.data))), + ); + checks.ok("commands made no external provider request", server.requests.length === 0, String(server.requests.length)); + } catch (error) { + failure = error; + } finally { + for (const run of [...runs].reverse()) { + try { + await closeTui(run, actions); + } catch (error) { + failure ??= error; + } + writeRunEvidence(evidence, run); + } + if (server) { + try { + await server.stop(); + serverStopped = true; + } catch (error) { + failure ??= error; + } + } + box.cleanup(); + sandboxRemoved = !existsSync(box.dir); + try { + authUnchanged = guard.assertUnchanged(); + } catch (error) { + failure ??= error; + } + writeFileSync(join(evidence, "action-log.json"), `${JSON.stringify(actions, null, 2)}\n`); + writeFileSync(join(evidence, "source-sha.txt"), `${sourceSha(root)}\n`); + writeFileSync( + join(evidence, "cleanup.json"), + `${JSON.stringify({ runs: runs.map(({ name, receipt }) => ({ name, receipt })), serverStopped, sandboxRemoved, authUnchanged }, null, 2)}\n`, + ); + writeFileSync(join(evidence, "auth-receipt.json"), `${JSON.stringify({ path: guard.path, unchanged: authUnchanged }, null, 2)}\n`); + } + + checks.ok("all PTYs exited before sandbox cleanup", runs.length === 3 && runs.every((run) => run.receipt?.ptyExited)); + checks.ok("local fake server stopped", serverStopped); + checks.ok("sandbox removed", sandboxRemoved, box.dir); + checks.ok("real auth unchanged", authUnchanged, guard.path); + const checksPassed = checks.finish(); + const passed = !failure && checksPassed; + writeFileSync(join(evidence, "summary.json"), `${JSON.stringify({ passed, sourceSHA: sourceSha(root), error: failure ? String(failure) : null }, null, 2)}\n`); + process.stderr.write(`evidence: ${evidence}\n`); + if (failure) throw failure; + process.exit(passed ? 0 : 1); +} + +main().catch((error) => { + process.stderr.write(`${error instanceof Error ? error.stack : String(error)}\n`); + process.exit(1); +}); diff --git a/packages/ai/changes.md b/packages/ai/changes.md index bb09cf6ef5..4f3a8aa1e2 100644 --- a/packages/ai/changes.md +++ b/packages/ai/changes.md @@ -20,6 +20,27 @@ # changes.md — ai +## 2026-09-06 - Scope generated model updates to selected providers + +### What changed + +- `packages/ai/scripts/generate-models.ts` accepts `--providers ` for strict, provider-scoped data regeneration. It preserves every unselected data file byte-for-byte, rebuilds the manifest over the mixed staged set, validates the complete catalog atomically, and leaves generated TypeScript shards untouched. `--generated-at` pins a reproducible manifest timestamp for scoped runs. +- `packages/ai/scripts/generate-models.ts` emits explicit reasoning maps for the affected built-in models instead of advertising effort levels their adapters do not distinguish. Documented graded controls remain graded, and custom-provider fallback behavior is unchanged. +- Provider selectors must be own catalog entries; inherited names such as `__proto__` are rejected before generated artifacts are replaced. + +### Why + +- A capability-only catalog correction must not pick up unrelated live-provider price, context, or inventory churn from full regeneration. +- Toggle-only controls must not appear as a configurable effort ladder. Where current upstream documentation is incomplete, the maps describe the control surface implemented by the existing Senpi adapter, not unverified upstream capabilities. + +### Why an extension could not handle it + +- Model-data generation and manifest integrity run at build time before extensions load. + +### Expected merge conflict zones + +- MEDIUM: `packages/ai/scripts/generate-models.ts` option parsing and staged data writer. + ## 2026-09-05 - Normalize GPT-6 Astra reasoning maps across OpenAI-family catalogs ### What changed diff --git a/packages/ai/scripts/generate-models.ts b/packages/ai/scripts/generate-models.ts index 41cc13ad9d..66070f733e 100644 --- a/packages/ai/scripts/generate-models.ts +++ b/packages/ai/scripts/generate-models.ts @@ -28,6 +28,7 @@ import { type ModelDataStructure, MODEL_DATA_MANIFEST_FILE, readModelDataProviderIds, + readModelDataStructure, validateGeneratedModelData, validateModelDataDirectory, } from "./model-data.ts"; @@ -42,12 +43,16 @@ function readGeneratorOptions(args: string[]): { jsonOnly: boolean; jsonOutputDir: string | undefined; pretty: boolean; + providerIds: string[] | undefined; + generatedAt: string | undefined; } { let strict = false; let dataOnly = false; let jsonOnly = false; let jsonOutputDir: string | undefined; let pretty = false; + let providerIds: string[] | undefined; + let generatedAt: string | undefined; for (let index = 0; index < args.length; index++) { const arg = args[index]; @@ -73,12 +78,32 @@ function readGeneratorOptions(args: string[]): { jsonOutputDir = resolve(value); continue; } + if (arg === "--providers") { + const value = args[++index]; + if (!value) throw new Error("--providers requires a comma-separated provider list"); + const values = value.split(",").map((providerId) => providerId.trim()); + if (values.some((providerId) => providerId.length === 0)) { + throw new Error("--providers cannot contain empty provider IDs"); + } + providerIds = Array.from(new Set(values)).sort(); + if (providerIds.length !== values.length) throw new Error("--providers cannot contain duplicate provider IDs"); + continue; + } + if (arg === "--generated-at") { + const value = args[++index]; + if (!value || Number.isNaN(Date.parse(value))) throw new Error("--generated-at requires an ISO timestamp"); + generatedAt = new Date(value).toISOString(); + continue; + } throw new Error(`Unknown argument: ${arg}`); } if (jsonOnly && !jsonOutputDir) throw new Error("--json-only requires --json-output"); if (dataOnly && (jsonOnly || jsonOutputDir)) throw new Error("--data-only cannot be combined with JSON catalog output"); - return { strict, dataOnly, jsonOnly, jsonOutputDir, pretty }; + if (providerIds && (dataOnly || jsonOnly || jsonOutputDir)) { + throw new Error("--providers cannot be combined with --data-only or JSON catalog output"); + } + return { strict, dataOnly, jsonOnly, jsonOutputDir, pretty, providerIds, generatedAt }; } const generatorOptions = readGeneratorOptions(process.argv.slice(2)); @@ -247,6 +272,39 @@ const ZAI_GLM52_THINKING_LEVEL_MAP = { xhigh: null, max: "max", } as const; + +// These OpenAI-compatible adapters only serialize a thinking enable/disable +// switch for these models; they have no distinct effort payload. +const ON_OFF_THINKING_LEVEL_MAP = { + minimal: null, + low: null, + medium: null, + xhigh: null, + max: null, +} as const; +const ALWAYS_ON_THINKING_LEVEL_MAP = { + off: null, + minimal: null, + low: null, + medium: null, + xhigh: null, + max: null, +} as const; +const ALIBABA_TOKEN_PLAN_ON_OFF_MODEL_IDS = new Set([ + "deepseek-v3.2", + "kimi-k2.5", + "kimi-k2.6", + "qwen3.6-flash", + "qwen3.6-plus", + "qwen3.7-max", + "qwen3.7-plus", + "qwen3.8-flash", + "qwen3.8-max", + "qwen3.8-max-preview", +]); +const MOONSHOT_ON_OFF_MODEL_IDS = new Set(["kimi-k2-thinking", "kimi-k2-thinking-turbo", "kimi-k2.5", "kimi-k2.6"]); +const XIAOMI_ON_OFF_MODEL_IDS = new Set(["mimo-v2.5", "mimo-v2.5-pro", "mimo-v2.5-pro-ultraspeed"]); +const ZAI_ON_OFF_MODEL_IDS = new Set(["glm-4.6v", "glm-5-turbo", "glm-5.1", "glm-5v-turbo"]); const OPENCODE_GO_GLM52_THINKING_LEVEL_MAP = { off: null, minimal: null, @@ -1968,6 +2026,16 @@ async function loadModelsDevData(): Promise[]> { const isGlm5x = isGlm52 || /^(?:glm-5\.3)(?:-(?:flash|highspeed))?$/.test(modelId); const referenceCost = modelId === "glm-5.2-highspeed" ? undefined : data.zai?.models[modelId]?.cost ?? m.cost; + const thinkingLevelMap = + modelId === "glm-4.7" + ? ALWAYS_ON_THINKING_LEVEL_MAP + : ZAI_ON_OFF_MODEL_IDS.has(modelId) + ? ON_OFF_THINKING_LEVEL_MAP + : isGlm52 + ? ZAI_GLM52_THINKING_LEVEL_MAP + : isGlm5x + ? getEffortThinkingLevelMap(m.reasoning_options ?? []) + : undefined; models.push({ id: modelId, name: m.name || modelId, @@ -1975,11 +2043,7 @@ async function loadModelsDevData(): Promise[]> { provider, baseUrl, reasoning: m.reasoning === true, - ...(isGlm52 - ? { thinkingLevelMap: ZAI_GLM52_THINKING_LEVEL_MAP } - : isGlm5x - ? { thinkingLevelMap: getEffortThinkingLevelMap(m.reasoning_options ?? []) } - : {}), + ...(thinkingLevelMap ? { thinkingLevelMap } : {}), input: supportsImage ? ["text", "image"] : ["text"], cost: { input: referenceCost?.input || 0, @@ -2215,6 +2279,12 @@ async function loadModelsDevData(): Promise[]> { } } + const thinkingLevelMap = + variant.provider === "opencode" && modelId === "kimi-k2.6" + ? ON_OFF_THINKING_LEVEL_MAP + : variant.provider === "opencode-go" && modelId === "qwen3.6-plus" + ? ON_OFF_THINKING_LEVEL_MAP + : undefined; models.push({ id: modelId, name: m.name || modelId, @@ -2222,6 +2292,7 @@ async function loadModelsDevData(): Promise[]> { provider: variant.provider, baseUrl, reasoning: m.reasoning === true, + ...(thinkingLevelMap ? { thinkingLevelMap } : {}), input: m.modalities?.input?.includes("image") ? ["text", "image"] : ["text"], cost: { input: m.cost?.input || 0, @@ -2423,6 +2494,7 @@ async function loadModelsDevData(): Promise[]> { provider, baseUrl, reasoning: isKimiK3 || m.reasoning === true, + ...(MOONSHOT_ON_OFF_MODEL_IDS.has(modelId) ? { thinkingLevelMap: ON_OFF_THINKING_LEVEL_MAP } : {}), input: m.modalities?.input?.includes("image") ? ["text", "image"] : ["text"], cost: { input: m.cost?.input || (isKimiK3 ? KIMI_K3_COST.input : 0), @@ -2445,7 +2517,7 @@ async function loadModelsDevData(): Promise[]> { const xiaomiCompat: OpenAICompletionsCompat = { requiresReasoningContentOnAssistantMessages: true, thinkingFormat: "deepseek", - supportsDisabledThinking: false, + supportsReasoningEffort: false, }; const xiaomiVariants = [ { source: "xiaomi", provider: "xiaomi", baseUrl: "https://api.xiaomimimo.com/v1" }, @@ -2483,6 +2555,7 @@ async function loadModelsDevData(): Promise[]> { baseUrl, compat: xiaomiCompat, reasoning: m.reasoning === true, + ...(XIAOMI_ON_OFF_MODEL_IDS.has(modelId) ? { thinkingLevelMap: ON_OFF_THINKING_LEVEL_MAP } : {}), input: m.modalities?.input?.includes("image") ? ["text", "image"] : ["text"], cost: { input: m.cost?.input || 0, @@ -2556,7 +2629,7 @@ async function loadModelsDevData(): Promise[]> { ? QWEN_TOKEN_PLAN_QWEN38_THINKING_LEVEL_MAP : QWEN_TOKEN_PLAN_HIGH_MAX_THINKING_LEVEL_MAP, } - : {}), + : { thinkingLevelMap: ON_OFF_THINKING_LEVEL_MAP }), reasoning: m.reasoning === true, input: m.modalities?.input?.includes("image") ? ["text", "image"] : ["text"], cost: { @@ -2599,11 +2672,18 @@ async function loadModelsDevData(): Promise[]> { } else if (family.startsWith("deepseek")) { compat.requiresReasoningContentOnAssistantMessages = true; compat.thinkingFormat = "deepseek"; + if (modelId === "deepseek-v3.2") compat.supportsReasoningEffort = false; } else if (family.startsWith("kimi")) { compat.thinkingFormat = "deepseek"; compat.supportsReasoningEffort = false; } + const thinkingLevelMap = + modelId === "kimi-k2.7-code" + ? ALWAYS_ON_THINKING_LEVEL_MAP + : ALIBABA_TOKEN_PLAN_ON_OFF_MODEL_IDS.has(modelId) + ? ON_OFF_THINKING_LEVEL_MAP + : undefined; models.push({ id: modelId, name: m.name || modelId, @@ -2612,6 +2692,7 @@ async function loadModelsDevData(): Promise[]> { baseUrl: alibabaTokenPlanBaseUrl, compat, reasoning: m.reasoning === true, + ...(thinkingLevelMap ? { thinkingLevelMap } : {}), input: m.modalities?.input?.includes("image") ? ["text", "image"] : ["text"], cost: { input: m.cost?.input || 0, @@ -3403,9 +3484,15 @@ async function generateModels() { const serializeJson = (value: unknown) => `${JSON.stringify(value, null, generatorOptions.pretty ? 2 : undefined)}\n`; const writeJson = (path: string, value: unknown) => writeFileSync(path, serializeJson(value)); - const generatedDataProviderIds = generatorOptions.dataOnly - ? readModelDataProviderIds(packageRoot) - : sortedProviderIds; + const existingModelDataStructure = generatorOptions.providerIds ? readModelDataStructure(packageRoot) : undefined; + const unknownProviderIds = + generatorOptions.providerIds?.filter( + (providerId) => existingModelDataStructure === undefined || !Object.hasOwn(existingModelDataStructure, providerId), + ) ?? []; + if (unknownProviderIds.length > 0) { + throw new Error(`Unknown provider selector: ${unknownProviderIds.join(", ")}`); + } + const generatedDataProviderIds = generatorOptions.providerIds ?? (generatorOptions.dataOnly ? readModelDataProviderIds(packageRoot) : sortedProviderIds); const missingProviderIds = generatedDataProviderIds.filter((providerId) => !jsonProviders[providerId]); if (missingProviderIds.length > 0) { throw new Error(`Cannot hydrate missing providers: ${missingProviderIds.join(", ")}`); @@ -3413,7 +3500,7 @@ async function generateModels() { // Only the ignored internal data is grouped by API for type derivation. Public JSON catalog output stays flat. const generatedDataProviders: Record>>> = {}; - const modelDataStructure: ModelDataStructure = {}; + const modelDataStructure: ModelDataStructure = { ...existingModelDataStructure }; for (const providerId of generatedDataProviderIds) { const models = jsonProviders[providerId]; generatedDataProviders[providerId] = {}; @@ -3429,7 +3516,7 @@ async function generateModels() { } } - const generatedAt = new Date().toISOString(); + const generatedAt = generatorOptions.generatedAt ?? new Date().toISOString(); if (!generatorOptions.jsonOnly) { // Stage and validate all provider values before replacing the current generated data. @@ -3442,9 +3529,12 @@ async function generateModels() { try { mkdirSync(stagedDataDir, { recursive: true }); const fileContents: Record = {}; - for (const providerId of generatedDataProviderIds) { + const stagedProviderIds = existingModelDataStructure ? Object.keys(existingModelDataStructure).sort() : generatedDataProviderIds; + for (const providerId of stagedProviderIds) { const filename = `${providerId}.json`; - const content = serializeJson(generatedDataProviders[providerId]); + const content = generatedDataProviders[providerId] + ? serializeJson(generatedDataProviders[providerId]) + : readFileSync(join(dataDir, filename), "utf8"); fileContents[filename] = content; writeFileSync(join(stagedDataDir, filename), content); } @@ -3454,7 +3544,7 @@ async function generateModels() { ); validateModelDataDirectory(modelDataStructure, stagedDataDir); - if (!generatorOptions.dataOnly) { + if (!generatorOptions.dataOnly && !generatorOptions.providerIds) { const previousShardContents = new Map( readdirSync(providersDir) .filter((entry) => entry.endsWith(".models.ts")) diff --git a/packages/ai/src/changes.md b/packages/ai/src/changes.md index 41d39a530c..24873a172e 100644 --- a/packages/ai/src/changes.md +++ b/packages/ai/src/changes.md @@ -1,4 +1,22 @@ +## 2026-09-06 - Preserve generated Xiaomi disabled-thinking capability + +### What changed + +- `packages/ai/src/providers/all.ts` no longer overwrites the generated Xiaomi MiMo `supportsDisabledThinking` compatibility value when normalizing `mimo-v2.5-pro`. + +### Why + +- Xiaomi's documented OpenAI-compatible API accepts `thinking.type: "disabled"`; the stale runtime override made `/reasoning off` omit the disable request after catalog generation had correctly enabled it. + +### Why an extension could not handle it + +- Builtin model normalization and outbound provider metadata resolve before extension command handling. + +### Expected merge conflict zones + +- LOW: the Xiaomi `normalizeBuiltinModel` compatibility merge in `packages/ai/src/providers/all.ts`. + ## 2026-09-05 - Project Astra configuration updates at the Responses wire ### What changed diff --git a/packages/ai/src/providers/all.ts b/packages/ai/src/providers/all.ts index 23350fd51f..e7b4fecbe1 100644 --- a/packages/ai/src/providers/all.ts +++ b/packages/ai/src/providers/all.ts @@ -79,7 +79,6 @@ function normalizeBuiltinModel(model: Model | undefined) ...model.compat, requiresReasoningContentOnAssistantMessages: true, thinkingFormat: "deepseek", - supportsDisabledThinking: false, }, } as Model; } diff --git a/packages/ai/src/providers/data/.manifest.json b/packages/ai/src/providers/data/.manifest.json index 1b1f98e9ca..2a4de4a8fe 100644 --- a/packages/ai/src/providers/data/.manifest.json +++ b/packages/ai/src/providers/data/.manifest.json @@ -1 +1 @@ -{"schemaVersion":3,"generatedAt":"2026-09-05T14:17:25.422Z","structureHash":"5cf00ed699dfcf1d110e8fe8c9f1147d3ac96aee7df0e3546ee3a1840dfedf5d","files":{"alibaba-token-plan.json":"9f9e8f88b1faa2e4134a0d8bcda600531d4d044d64b7ec3d2373f1db46dcf452","amazon-bedrock.json":"c86cdf3eb28122f8682415543012feee0a84dd4a30f03b784dfffde92b0d69f4","ant-ling.json":"4979fe79d99ed97382d7ce40170c6132e932e77906de1eb54464c042e7d63633","anthropic.json":"e9d883ee35d94dba963320b5496bd7dd368d226cbafcf134bfec66a0a24b3b7f","azure-openai-responses.json":"fda6124a327ac009e2bc990b5fdbb1cce38d25b3903a22db9fc0916a64265185","baseten.json":"8f7430af599249a01f446b5b717856dd58d484e76f5dbccf86c0ec7b6661468d","cerebras.json":"38272a7525d6680c71bb4bb3c4085e871768b400832e2013b0e7fd92f8fd4f05","cloudflare-ai-gateway.json":"f135f718d749355fe745823c3fc1315019ba37a6f20ae8523fafe9dd0c46d090","cloudflare-workers-ai.json":"07ef63208ff7517fd1a80962f18143e21de399640423329490b157f459ccf995","deepseek.json":"e3106724723fd82d48a3ff685da9908a3a7b7b4fd84cc3cfe97a6a23067b6029","fireworks.json":"0b480dcad5ff4072ef299d887f27ed3ed96e2246aa57ffa3bac02ecee9aee331","github-copilot.json":"54129bbff5764fed2c5da83adc00332eb95bd85377bb2442fd9f36b78a96df05","google-vertex.json":"e1631109172dc1f7d7977570420a5bb86258bdd1088427e244a2c51545c4f24d","google.json":"7619bf03edd2a7acb06a2274a14b13c3a61354288abe029a758401d4de36a8fd","groq.json":"e4728fd72e358cd8f25e9a518e9b49a521ef44523d3debe38a7db9e0663c4077","huggingface.json":"3a004b58d3f801077a81f5be5cdf40c59ce1070c9c68f279e8d6c8902d441b19","kimi-coding.json":"88150f8970f83e17968b02f3b33fac803b96ebf1474e76437689b7d0f1b69363","minimax-cn.json":"65d37e55a6d9585855f94b3fb7739308d107fe248ebd9e1001d1c5d4606ad2c4","minimax.json":"c7dc5765995ae77242916430929c7cc9a782589f7e483e13f7e01663190d028e","mistral.json":"e3a109306644bf2f2fa38fece50b2d3ce1dbe3b87b1f1b9e2d70cce7eb5c0ea1","moonshotai-cn.json":"dbf1b71ee36812fe64b014177ff455809a8dd852bbbd584422645beb85635127","moonshotai.json":"2d7518b4769e97ac900366175c8b60ff86a02675bb6f6cc2fffcc6761fda6faa","nvidia.json":"7e5d6e027f61e36f8d806d0af311cda93a40e75920b8a0645eddf0ab9f058033","openai-codex.json":"dfe2ffc02604acf026c8e94a3b45a8d73cef3f4d7b4783ef95316c44ce1bb46d","openai.json":"3852260e9ef6e73ae7c284a105919c0df4617128aef28d9f8cc8847e679f3b57","opencode-go.json":"e5191ca2337d31c5baa3d603284a981dfaefb67693ff227cc523a3937f02a2d8","opencode.json":"9c66625f296a141a47f3c94c3299cc9ccf8e8130ffa6092d72265a79d97b3fd7","opengateway.json":"ea7baf1096fe1488ee080ece109743fe69a8ccc111908a991ca09532efc60e15","openrouter.json":"472b33a7668461c200a2f5ac5a3c60398288a0209c1b269616bdfbeb6446fbc2","qwen-token-plan-cn.json":"e62dde34edb603376a1dc60b2a74a9c2605b9e81d81df55cc259796c45aa4793","qwen-token-plan-individual.json":"5649fd4075ada766ec65a7a162cd65f096a7ecc29960ace04b2e6a6a4a995a41","qwen-token-plan.json":"fe914313157ff41ab2f71977f0fdcfedb3a8a205d1092e3180f6799e5d7942fd","together.json":"6010980c9b0af72c60965ae325dbdb21e67c91844a7f7f6f7d71d363f1325f56","vercel-ai-gateway.json":"3a6ef6dfd89ab87eb305b4c2bb8f5bb890d2d017b79b76a9195411a53a1c360a","xai.json":"9973aae022723732b8a7ea12107e6fb8b3f1d0e087ec6bbc2ee18f0820595e19","xiaomi-token-plan-ams.json":"568b9992cf320536a65826e26a414afa5c0d17f083a01af4bd96658d9dd3e705","xiaomi-token-plan-cn.json":"c423857d0bbb0b126394eaf1ebb2a91bf2d1193cc5a4fe77843ff0f4536a0a80","xiaomi-token-plan-sgp.json":"008f1eb41037e93c5ae478f12815cd67bac1978f131ffefa602775bb60b63fea","xiaomi.json":"37acf451bb4364bdca2ecea6b7d962590d9974a87e80cfe34bb800be6a95c13b","zai-coding-cn.json":"d3c969020a7ab978497837a3301c7bca364d704082832221cfe61e6596333e56","zai.json":"f42790c77fb4681a656897a9d860b939916c0ddf979a5f16856bce9573cdf64e"}} +{"schemaVersion":3,"generatedAt":"2026-09-06T00:00:00.000Z","structureHash":"5cf00ed699dfcf1d110e8fe8c9f1147d3ac96aee7df0e3546ee3a1840dfedf5d","files":{"alibaba-token-plan.json":"59a7ab84ef3b0f241ea15bb091390652570b96a0ce2f6619724fbe5a629db969","amazon-bedrock.json":"c86cdf3eb28122f8682415543012feee0a84dd4a30f03b784dfffde92b0d69f4","ant-ling.json":"4979fe79d99ed97382d7ce40170c6132e932e77906de1eb54464c042e7d63633","anthropic.json":"e9d883ee35d94dba963320b5496bd7dd368d226cbafcf134bfec66a0a24b3b7f","azure-openai-responses.json":"fda6124a327ac009e2bc990b5fdbb1cce38d25b3903a22db9fc0916a64265185","baseten.json":"8f7430af599249a01f446b5b717856dd58d484e76f5dbccf86c0ec7b6661468d","cerebras.json":"38272a7525d6680c71bb4bb3c4085e871768b400832e2013b0e7fd92f8fd4f05","cloudflare-ai-gateway.json":"f135f718d749355fe745823c3fc1315019ba37a6f20ae8523fafe9dd0c46d090","cloudflare-workers-ai.json":"07ef63208ff7517fd1a80962f18143e21de399640423329490b157f459ccf995","deepseek.json":"e3106724723fd82d48a3ff685da9908a3a7b7b4fd84cc3cfe97a6a23067b6029","fireworks.json":"0b480dcad5ff4072ef299d887f27ed3ed96e2246aa57ffa3bac02ecee9aee331","github-copilot.json":"54129bbff5764fed2c5da83adc00332eb95bd85377bb2442fd9f36b78a96df05","google-vertex.json":"e1631109172dc1f7d7977570420a5bb86258bdd1088427e244a2c51545c4f24d","google.json":"7619bf03edd2a7acb06a2274a14b13c3a61354288abe029a758401d4de36a8fd","groq.json":"e4728fd72e358cd8f25e9a518e9b49a521ef44523d3debe38a7db9e0663c4077","huggingface.json":"3a004b58d3f801077a81f5be5cdf40c59ce1070c9c68f279e8d6c8902d441b19","kimi-coding.json":"88150f8970f83e17968b02f3b33fac803b96ebf1474e76437689b7d0f1b69363","minimax-cn.json":"65d37e55a6d9585855f94b3fb7739308d107fe248ebd9e1001d1c5d4606ad2c4","minimax.json":"c7dc5765995ae77242916430929c7cc9a782589f7e483e13f7e01663190d028e","mistral.json":"e3a109306644bf2f2fa38fece50b2d3ce1dbe3b87b1f1b9e2d70cce7eb5c0ea1","moonshotai-cn.json":"9a6f9f35fb74d32284fb263e13cbcd375ebe8c89140ad93f02b12478dfe97970","moonshotai.json":"a0bfc0ee12e782d1987acfa4cc465f10ac55d7b89071e2ec4d3a7380cf790831","nvidia.json":"7e5d6e027f61e36f8d806d0af311cda93a40e75920b8a0645eddf0ab9f058033","openai-codex.json":"dfe2ffc02604acf026c8e94a3b45a8d73cef3f4d7b4783ef95316c44ce1bb46d","openai.json":"3852260e9ef6e73ae7c284a105919c0df4617128aef28d9f8cc8847e679f3b57","opencode-go.json":"747ab9d44b2a48f6ca55894296cf9bcf8df5ca03c7ded74026eefa5e74e88250","opencode.json":"d5ef678f06b6113b2c24f3164be33e98ee07851344b9b323026a02aaa5f812ce","opengateway.json":"ea7baf1096fe1488ee080ece109743fe69a8ccc111908a991ca09532efc60e15","openrouter.json":"472b33a7668461c200a2f5ac5a3c60398288a0209c1b269616bdfbeb6446fbc2","qwen-token-plan-cn.json":"a3addc5bd8de66c5d676bd11a01442515ea8c786a952f43b885e653950bed3f2","qwen-token-plan-individual.json":"86d1dd467695c6df282c8e2b4384d23323d622a96f0358840eb09e141d0e9da4","qwen-token-plan.json":"37e321a2e0b912d8e9c5cd13dc10a5b3b0638d764f7bb20c3aaab262ee1078ea","together.json":"6010980c9b0af72c60965ae325dbdb21e67c91844a7f7f6f7d71d363f1325f56","vercel-ai-gateway.json":"3a6ef6dfd89ab87eb305b4c2bb8f5bb890d2d017b79b76a9195411a53a1c360a","xai.json":"9973aae022723732b8a7ea12107e6fb8b3f1d0e087ec6bbc2ee18f0820595e19","xiaomi-token-plan-ams.json":"66190c086ddc6d72afae5dc51027ac385ff7bffa3a565fa4c41ac254ca043b55","xiaomi-token-plan-cn.json":"a0e81b80e7bb582a779f9dcea04979eae80b2405bb9f7c0a432a774f908524f1","xiaomi-token-plan-sgp.json":"a70aeb60f510c9116ccec615314032b7a3a2265b1ff93a4fce48e2b4a92ec208","xiaomi.json":"957b4a5fb9d4e63b96f75f33167287c541332b79df2e3a3ff22c911463e12ee2","zai-coding-cn.json":"6b396a967808dd7f7e800990b3d69f04adfd2a1811b8328d1fe7275ae758153d","zai.json":"3a5dd70915c46c676a17362f9f0d018c239a1f2555ea675b682890e3417ebff3"}} diff --git a/packages/ai/src/providers/data/alibaba-token-plan.json b/packages/ai/src/providers/data/alibaba-token-plan.json index 4288becd5b..8c5785da82 100644 --- a/packages/ai/src/providers/data/alibaba-token-plan.json +++ b/packages/ai/src/providers/data/alibaba-token-plan.json @@ -1 +1 @@ -{"openai-completions":{"MiniMax-M2.5":{"id":"MiniMax-M2.5","name":"MiniMax-M2.5","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":196608,"maxTokens":32768},"deepseek-v3.2":{"id":"deepseek-v3.2","name":"DeepSeek V3.2","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":131072,"maxTokens":65536},"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4-flash-0731":{"id":"deepseek-v4-flash-0731","name":"DeepSeek V4 Flash 0731","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4-pro-0813":{"id":"deepseek-v4-pro-0813","name":"DeepSeek V4 Pro 0813","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"glm-5":{"id":"glm-5","name":"GLM-5","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":16384},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":128000},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":98304},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"qwen3.6-flash":{"id":"qwen3.6-flash","name":"Qwen3.6 Flash","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-max-preview":{"id":"qwen3.8-max-preview","name":"Qwen3.8 Max Preview","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072}}} +{"openai-completions":{"MiniMax-M2.5":{"id":"MiniMax-M2.5","name":"MiniMax-M2.5","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":196608,"maxTokens":32768},"deepseek-v3.2":{"id":"deepseek-v3.2","name":"DeepSeek V3.2","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":131072,"maxTokens":65536},"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4-flash-0731":{"id":"deepseek-v4-flash-0731","name":"DeepSeek V4 Flash 0731","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4-pro-0813":{"id":"deepseek-v4-pro-0813","name":"DeepSeek V4 Pro 0813","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"glm-5":{"id":"glm-5","name":"GLM-5","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":16384},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":128000},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":98304},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"qwen3.6-flash":{"id":"qwen3.6-flash","name":"Qwen3.6 Flash","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-max-preview":{"id":"qwen3.8-max-preview","name":"Qwen3.8 Max Preview","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072}}} diff --git a/packages/ai/src/providers/data/moonshotai-cn.json b/packages/ai/src/providers/data/moonshotai-cn.json index cb043d4e6d..90681ebd1d 100644 --- a/packages/ai/src/providers/data/moonshotai-cn.json +++ b/packages/ai/src/providers/data/moonshotai-cn.json @@ -1 +1 @@ -{"openai-completions":{"kimi-k2-0711-preview":{"id":"kimi-k2-0711-preview","name":"Kimi K2 0711","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":false,"input":["text"],"cost":{"input":0.6,"output":2.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":131072,"maxTokens":16384,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2-0905-preview":{"id":"kimi-k2-0905-preview","name":"Kimi K2 0905","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":false,"input":["text"],"cost":{"input":0.6,"output":2.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2-thinking":{"id":"kimi-k2-thinking","name":"Kimi K2 Thinking","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":true,"input":["text"],"cost":{"input":0.6,"output":2.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2-thinking-turbo":{"id":"kimi-k2-thinking-turbo","name":"Kimi K2 Thinking Turbo","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":true,"input":["text"],"cost":{"input":1.15,"output":8,"cacheRead":0.15,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2-turbo-preview":{"id":"kimi-k2-turbo-preview","name":"Kimi K2 Turbo","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":false,"input":["text"],"cost":{"input":2.4,"output":10,"cacheRead":0.6,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.6,"output":3,"cacheRead":0.1,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.16,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.19,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"},"thinkingLevelMap":{"off":null}},"kimi-k2.7-code-highspeed":{"id":"kimi-k2.7-code-highspeed","name":"Kimi K2.7 Code HighSpeed","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.9,"output":8,"cacheRead":0.38,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"},"thinkingLevelMap":{"off":null}},"kimi-k3":{"id":"kimi-k3","name":"Kimi K3","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"openai","requiresReasoningContentOnAssistantMessages":true,"deferredToolsMode":"kimi"},"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}}}} +{"openai-completions":{"kimi-k2-0711-preview":{"id":"kimi-k2-0711-preview","name":"Kimi K2 0711","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":false,"input":["text"],"cost":{"input":0.6,"output":2.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":131072,"maxTokens":16384,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2-0905-preview":{"id":"kimi-k2-0905-preview","name":"Kimi K2 0905","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":false,"input":["text"],"cost":{"input":0.6,"output":2.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2-thinking":{"id":"kimi-k2-thinking","name":"Kimi K2 Thinking","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":0.6,"output":2.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2-thinking-turbo":{"id":"kimi-k2-thinking-turbo","name":"Kimi K2 Thinking Turbo","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":1.15,"output":8,"cacheRead":0.15,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2-turbo-preview":{"id":"kimi-k2-turbo-preview","name":"Kimi K2 Turbo","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":false,"input":["text"],"cost":{"input":2.4,"output":10,"cacheRead":0.6,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0.6,"output":3,"cacheRead":0.1,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.16,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.19,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"},"thinkingLevelMap":{"off":null}},"kimi-k2.7-code-highspeed":{"id":"kimi-k2.7-code-highspeed","name":"Kimi K2.7 Code HighSpeed","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.9,"output":8,"cacheRead":0.38,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"},"thinkingLevelMap":{"off":null}},"kimi-k3":{"id":"kimi-k3","name":"Kimi K3","api":"openai-completions","provider":"moonshotai-cn","baseUrl":"https://api.moonshot.cn/v1","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"openai","requiresReasoningContentOnAssistantMessages":true,"deferredToolsMode":"kimi"},"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}}}} diff --git a/packages/ai/src/providers/data/moonshotai.json b/packages/ai/src/providers/data/moonshotai.json index 8557c2d4e7..98e7b2eac7 100644 --- a/packages/ai/src/providers/data/moonshotai.json +++ b/packages/ai/src/providers/data/moonshotai.json @@ -1 +1 @@ -{"openai-completions":{"kimi-k2-0711-preview":{"id":"kimi-k2-0711-preview","name":"Kimi K2 0711","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":false,"input":["text"],"cost":{"input":0.6,"output":2.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":131072,"maxTokens":16384,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2-0905-preview":{"id":"kimi-k2-0905-preview","name":"Kimi K2 0905","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":false,"input":["text"],"cost":{"input":0.6,"output":2.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2-thinking":{"id":"kimi-k2-thinking","name":"Kimi K2 Thinking","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":true,"input":["text"],"cost":{"input":0.6,"output":2.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2-thinking-turbo":{"id":"kimi-k2-thinking-turbo","name":"Kimi K2 Thinking Turbo","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":true,"input":["text"],"cost":{"input":1.15,"output":8,"cacheRead":0.15,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2-turbo-preview":{"id":"kimi-k2-turbo-preview","name":"Kimi K2 Turbo","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":false,"input":["text"],"cost":{"input":2.4,"output":10,"cacheRead":0.6,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.6,"output":3,"cacheRead":0.1,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.16,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.19,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"},"thinkingLevelMap":{"off":null}},"kimi-k2.7-code-highspeed":{"id":"kimi-k2.7-code-highspeed","name":"Kimi K2.7 Code HighSpeed","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.9,"output":8,"cacheRead":0.38,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"},"thinkingLevelMap":{"off":null}},"kimi-k3":{"id":"kimi-k3","name":"Kimi K3","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"openai","requiresReasoningContentOnAssistantMessages":true,"deferredToolsMode":"kimi"},"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}}}} +{"openai-completions":{"kimi-k2-0711-preview":{"id":"kimi-k2-0711-preview","name":"Kimi K2 0711","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":false,"input":["text"],"cost":{"input":0.6,"output":2.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":131072,"maxTokens":16384,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2-0905-preview":{"id":"kimi-k2-0905-preview","name":"Kimi K2 0905","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":false,"input":["text"],"cost":{"input":0.6,"output":2.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2-thinking":{"id":"kimi-k2-thinking","name":"Kimi K2 Thinking","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":0.6,"output":2.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2-thinking-turbo":{"id":"kimi-k2-thinking-turbo","name":"Kimi K2 Thinking Turbo","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":1.15,"output":8,"cacheRead":0.15,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2-turbo-preview":{"id":"kimi-k2-turbo-preview","name":"Kimi K2 Turbo","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":false,"input":["text"],"cost":{"input":2.4,"output":10,"cacheRead":0.6,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0.6,"output":3,"cacheRead":0.1,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.16,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"}},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.19,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"},"thinkingLevelMap":{"off":null}},"kimi-k2.7-code-highspeed":{"id":"kimi-k2.7-code-highspeed","name":"Kimi K2.7 Code HighSpeed","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.9,"output":8,"cacheRead":0.38,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"deepseek"},"thinkingLevelMap":{"off":null}},"kimi-k3":{"id":"kimi-k3","name":"Kimi K3","api":"openai-completions","provider":"moonshotai","baseUrl":"https://api.moonshot.ai/v1","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsPromptCacheKey":true,"thinkingFormat":"openai","requiresReasoningContentOnAssistantMessages":true,"deferredToolsMode":"kimi"},"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}}}} diff --git a/packages/ai/src/providers/data/opencode-go.json b/packages/ai/src/providers/data/opencode-go.json index cf9b48266c..bd9f0ce52e 100644 --- a/packages/ai/src/providers/data/opencode-go.json +++ b/packages/ai/src/providers/data/opencode-go.json @@ -1 +1 @@ -{"anthropic-messages":{"minimax-m3":{"id":"minimax-m3","name":"MiniMax-M3","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go","reasoning":true,"input":["text","image"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.06,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.47,"cacheRead":0.016,"cacheWrite":0.2},"contextWindow":1000000,"maxTokens":131072}},"openai-completions":{"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.22,"output":0.66,"cacheRead":0.007,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":"low","medium":null,"high":"high","max":"max"}},"deepseek-v4-flash-vision-exp":{"id":"deepseek-v4-flash-vision-exp","name":"DeepSeek V4 Flash Vision Exp","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.22,"output":0.66,"cacheRead":0.007,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":"low","medium":null,"high":"high","max":"max"}},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro (New)","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.66,"output":1.98,"cacheRead":0.022,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":202752,"maxTokens":32768},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"}},"glm-5.3":{"id":"glm-5.3","name":"GLM-5.3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"}},"glm-5.3-flash":{"id":"glm-5.3-flash","name":"GLM-5.3-Flash (2x usage)","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.075,"output":0.25,"cacheRead":0.015,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}},"hy3":{"id":"hy3","name":"Hy3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.14,"output":0.58,"cacheRead":0.035,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":256000,"maxTokens":128000,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":null}},"hy4-preview":{"id":"hy4-preview","name":"Hy4 preview","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.834,"output":2.501,"cacheRead":0.042,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1024000,"maxTokens":64000,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":null}},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.16,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"thinkingFormat":"deepseek","supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false},"contextWindow":262144,"maxTokens":65536,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null}},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.19,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":262144,"maxTokens":262144},"kimi-k3":{"id":"kimi-k3","name":"Kimi K3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}},"longcat-2.0":{"id":"longcat-2.0","name":"LongCat-2.0","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.006,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072},"mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo V2.5","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.14,"output":0.28,"cacheRead":0.0028,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":128000},"mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo V2.5 Pro","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.435,"output":0.87,"cacheRead":0.003625,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":128000},"minimax-m2.7":{"id":"minimax-m2.7","name":"MiniMax-M2.7","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.06,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":204800,"maxTokens":131072},"omen-alpha":{"id":"omen-alpha","name":"Omen Alpha","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.2,"output":0.66,"cacheRead":0.04,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":500000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":null}},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.5,"output":3,"cacheRead":0.05,"cacheWrite":0.625},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"thinkingFormat":"qwen","maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":2.5,"output":7.5,"cacheRead":0.5,"cacheWrite":3.125},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.4,"output":1.6,"cacheRead":0.04,"cacheWrite":0.5},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":6,"cacheRead":0.25,"cacheWrite":2.5},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null}}},"openai-responses":{"gpt-5.6-luna":{"id":"gpt-5.6-luna","name":"GPT-5.6 Luna","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.2,"output":1.2,"cacheRead":0.02,"cacheWrite":0.25},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}},"grok-4.6":{"id":"grok-4.6","name":"Grok 4.6","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":6,"cacheRead":0.5,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":500000,"maxTokens":500000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"muse-spark-1.2-contributor":{"id":"muse-spark-1.2-contributor","name":"Muse Spark 1.2 Contributor","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.1,"output":0.2,"cacheRead":0.002,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"muse-spark-1.3-contributor":{"id":"muse-spark-1.3-contributor","name":"Muse Spark 1.3 Contributor","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.1,"output":0.2,"cacheRead":0.002,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}}}} +{"anthropic-messages":{"minimax-m3":{"id":"minimax-m3","name":"MiniMax-M3","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go","reasoning":true,"input":["text","image"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.06,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.47,"cacheRead":0.016,"cacheWrite":0.2},"contextWindow":1000000,"maxTokens":131072}},"openai-completions":{"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.22,"output":0.66,"cacheRead":0.007,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":"low","medium":null,"high":"high","max":"max"}},"deepseek-v4-flash-vision-exp":{"id":"deepseek-v4-flash-vision-exp","name":"DeepSeek V4 Flash Vision Exp","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.22,"output":0.66,"cacheRead":0.007,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":"low","medium":null,"high":"high","max":"max"}},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro (New)","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.66,"output":1.98,"cacheRead":0.022,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":202752,"maxTokens":32768},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"}},"glm-5.3":{"id":"glm-5.3","name":"GLM-5.3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"}},"glm-5.3-flash":{"id":"glm-5.3-flash","name":"GLM-5.3-Flash (2x usage)","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.075,"output":0.25,"cacheRead":0.015,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}},"hy3":{"id":"hy3","name":"Hy3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.14,"output":0.58,"cacheRead":0.035,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":256000,"maxTokens":128000,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":null}},"hy4-preview":{"id":"hy4-preview","name":"Hy4 preview","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.834,"output":2.501,"cacheRead":0.042,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1024000,"maxTokens":64000,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":null}},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.16,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"thinkingFormat":"deepseek","supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false},"contextWindow":262144,"maxTokens":65536,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null}},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.19,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":262144,"maxTokens":262144},"kimi-k3":{"id":"kimi-k3","name":"Kimi K3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}},"longcat-2.0":{"id":"longcat-2.0","name":"LongCat-2.0","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.006,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072},"mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo V2.5","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.14,"output":0.28,"cacheRead":0.0028,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":128000},"mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo V2.5 Pro","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.435,"output":0.87,"cacheRead":0.003625,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":128000},"minimax-m2.7":{"id":"minimax-m2.7","name":"MiniMax-M2.7","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.06,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":204800,"maxTokens":131072},"omen-alpha":{"id":"omen-alpha","name":"Omen Alpha","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.2,"output":0.66,"cacheRead":0.04,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":500000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":null}},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0.5,"output":3,"cacheRead":0.05,"cacheWrite":0.625},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"thinkingFormat":"qwen","maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":2.5,"output":7.5,"cacheRead":0.5,"cacheWrite":3.125},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.4,"output":1.6,"cacheRead":0.04,"cacheWrite":0.5},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":6,"cacheRead":0.25,"cacheWrite":2.5},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null}}},"openai-responses":{"gpt-5.6-luna":{"id":"gpt-5.6-luna","name":"GPT-5.6 Luna","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.2,"output":1.2,"cacheRead":0.02,"cacheWrite":0.25},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}},"grok-4.6":{"id":"grok-4.6","name":"Grok 4.6","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":6,"cacheRead":0.5,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":500000,"maxTokens":500000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"muse-spark-1.2-contributor":{"id":"muse-spark-1.2-contributor","name":"Muse Spark 1.2 Contributor","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.1,"output":0.2,"cacheRead":0.002,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"muse-spark-1.3-contributor":{"id":"muse-spark-1.3-contributor","name":"Muse Spark 1.3 Contributor","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.1,"output":0.2,"cacheRead":0.002,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}}}} diff --git a/packages/ai/src/providers/data/opencode.json b/packages/ai/src/providers/data/opencode.json index ab5acecb18..c362678c90 100644 --- a/packages/ai/src/providers/data/opencode.json +++ b/packages/ai/src/providers/data/opencode.json @@ -1 +1 @@ -{"anthropic-messages":{"claude-fable-5":{"id":"claude-fable-5","name":"Claude Fable 5","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":10,"output":50,"cacheRead":1,"cacheWrite":12.5},"contextWindow":1000000,"maxTokens":128000,"thinkingLevelMap":{"xhigh":"xhigh","max":"max"},"compat":{"supportsDisabledThinking":false,"forceAdaptiveThinking":true}},"claude-fable-5-1":{"id":"claude-fable-5-1","name":"Claude Fable 5.1","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":10,"output":50,"cacheRead":0.25,"cacheWrite":12.5},"contextWindow":1000000,"maxTokens":128000,"thinkingLevelMap":{"xhigh":"xhigh","max":"max"},"compat":{"supportsDisabledThinking":false,"forceAdaptiveThinking":true}},"claude-haiku-4-5":{"id":"claude-haiku-4-5","name":"Claude Haiku 4.5","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":1,"output":5,"cacheRead":0.1,"cacheWrite":1.25},"contextWindow":200000,"maxTokens":64000},"claude-opus-4-5":{"id":"claude-opus-4-5","name":"Claude Opus 4.5","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":5,"output":25,"cacheRead":0.5,"cacheWrite":6.25},"contextWindow":200000,"maxTokens":64000},"claude-opus-4-6":{"id":"claude-opus-4-6","name":"Claude Opus 4.6","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":5,"output":25,"cacheRead":0.5,"cacheWrite":6.25},"contextWindow":1000000,"maxTokens":128000,"thinkingLevelMap":{"max":"max"},"compat":{"forceAdaptiveThinking":true}},"claude-opus-4-7":{"id":"claude-opus-4-7","name":"Claude Opus 4.7","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":5,"output":25,"cacheRead":0.5,"cacheWrite":6.25},"contextWindow":1000000,"maxTokens":128000,"thinkingLevelMap":{"xhigh":"xhigh","max":"max"},"compat":{"forceAdaptiveThinking":true,"supportsTemperature":false}},"claude-opus-4-8":{"id":"claude-opus-4-8","name":"Claude Opus 4.8","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":5,"output":25,"cacheRead":0.5,"cacheWrite":6.25},"contextWindow":1000000,"maxTokens":128000,"thinkingLevelMap":{"xhigh":"xhigh","max":"max"},"compat":{"forceAdaptiveThinking":true,"supportsTemperature":false}},"claude-opus-5":{"id":"claude-opus-5","name":"Claude Opus 5","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":5,"output":25,"cacheRead":0.5,"cacheWrite":6.25},"contextWindow":1000000,"maxTokens":128000,"thinkingLevelMap":{"xhigh":"xhigh","max":"max"},"compat":{"forceAdaptiveThinking":true,"supportsTemperature":false}},"claude-sonnet-4":{"id":"claude-sonnet-4","name":"Claude Sonnet 4","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":3.75},"contextWindow":200000,"maxTokens":64000},"claude-sonnet-4-5":{"id":"claude-sonnet-4-5","name":"Claude Sonnet 4.5","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":3.75},"contextWindow":200000,"maxTokens":64000},"claude-sonnet-4-6":{"id":"claude-sonnet-4-6","name":"Claude Sonnet 4.6","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":3.75},"contextWindow":1000000,"maxTokens":64000,"thinkingLevelMap":{"max":"max"},"compat":{"forceAdaptiveThinking":true}},"claude-sonnet-5":{"id":"claude-sonnet-5","name":"Claude Sonnet 5","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":10,"cacheRead":0.2,"cacheWrite":2.5},"contextWindow":1000000,"maxTokens":128000,"thinkingLevelMap":{"xhigh":"xhigh","max":"max"},"compat":{"forceAdaptiveThinking":true}},"qwen3.5-plus":{"id":"qwen3.5-plus","name":"Qwen3.5 Plus","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":0.2,"output":1.2,"cacheRead":0.02,"cacheWrite":0.25},"contextWindow":262144,"maxTokens":65536},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":0.5,"output":3,"cacheRead":0.05,"cacheWrite":0.625},"contextWindow":262144,"maxTokens":65536}},"google-generative-ai":{"gemini-3-flash":{"id":"gemini-3-flash","name":"Gemini 3 Flash","api":"google-generative-ai","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.5,"output":3,"cacheRead":0.05,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"thinkingLevelMap":{"off":null}},"gemini-3.1-pro":{"id":"gemini-3.1-pro","name":"Gemini 3.1 Pro Preview","api":"google-generative-ai","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":12,"cacheRead":0.2,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"thinkingLevelMap":{"off":null,"minimal":null,"low":"LOW","medium":null,"high":"HIGH"}},"gemini-3.5-flash":{"id":"gemini-3.5-flash","name":"Gemini 3.5 Flash","api":"google-generative-ai","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.5,"output":9,"cacheRead":0.15,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"thinkingLevelMap":{"off":null}},"gemini-3.5-flash-lite":{"id":"gemini-3.5-flash-lite","name":"Gemini 3.5 Flash Lite","api":"google-generative-ai","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.3,"output":2.5,"cacheRead":0.03,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"thinkingLevelMap":{"off":null}},"gemini-3.6-flash":{"id":"gemini-3.6-flash","name":"Gemini 3.6 Flash","api":"google-generative-ai","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.5,"output":7.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"thinkingLevelMap":{"off":null}},"gemini-3.7-flash":{"id":"gemini-3.7-flash","name":"Gemini 3.7 Flash","api":"google-generative-ai","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.5,"output":7.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"thinkingLevelMap":{"off":null}},"gemini-3.8-flash":{"id":"gemini-3.8-flash","name":"Gemini 3.8 Flash","api":"google-generative-ai","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.5,"output":7.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"thinkingLevelMap":{"off":null}}},"openai-completions":{"big-pickle":{"id":"big-pickle","name":"Big Pickle","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":200000,"maxTokens":32000},"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":0.14,"output":0.28,"cacheRead":0.028,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false,"requiresReasoningContentOnAssistantMessages":true},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}},"deepseek-v4-flash-vision-exp":{"id":"deepseek-v4-flash-vision-exp","name":"DeepSeek V4 Flash Vision Exp","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.14,"output":0.28,"cacheRead":0.028,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":1.74,"output":3.84,"cacheRead":0.145,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false,"requiresReasoningContentOnAssistantMessages":true},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"}},"glm-5":{"id":"glm-5","name":"GLM-5","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":1,"output":3.2,"cacheRead":0.2,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":204800,"maxTokens":131072},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":204800,"maxTokens":131072},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"}},"glm-5.3":{"id":"glm-5.3","name":"GLM-5.3","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}},"glm-5.3-flash":{"id":"glm-5.3-flash","name":"GLM-5.3-Flash","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.5,"cacheRead":0.03,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.6,"output":3,"cacheRead":0.08,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false},"contextWindow":262144,"maxTokens":65536},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.16,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"thinkingFormat":"deepseek","supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false},"contextWindow":262144,"maxTokens":65536},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.19,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false},"contextWindow":262144,"maxTokens":262144},"kimi-k3":{"id":"kimi-k3","name":"Kimi K3","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}},"ling-3.0-flash-fin-free":{"id":"ling-3.0-flash-fin-free","name":"Ling 3.0 Flash Fin Free","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":262144,"maxTokens":32768},"mimo-v2.5-free":{"id":"mimo-v2.5-free","name":"MiMo V2.5 Free","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":200000,"maxTokens":32000},"minimax-m2.5":{"id":"minimax-m2.5","name":"MiniMax-M2.5","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.06,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":204800,"maxTokens":131072},"minimax-m2.7":{"id":"minimax-m2.7","name":"MiniMax-M2.7","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.06,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false},"contextWindow":204800,"maxTokens":131072},"minimax-m3":{"id":"minimax-m3","name":"MiniMax-M3","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.06,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":512000,"maxTokens":128000},"nemotron-3-ultra-free":{"id":"nemotron-3-ultra-free","name":"Nemotron 3 Ultra Free","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":128000},"nemotron-3.5-lightning-free":{"id":"nemotron-3.5-lightning-free","name":"Nemotron 3.5 Lightning Free","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":262144,"maxTokens":262144}},"openai-responses":{"gpt-5":{"id":"gpt-5","name":"GPT-5","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.07,"output":8.5,"cacheRead":0.107,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":null,"max":null}},"gpt-5-codex":{"id":"gpt-5-codex","name":"GPT-5 Codex","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.07,"output":8.5,"cacheRead":0.107,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":null}},"gpt-5-nano":{"id":"gpt-5-nano","name":"GPT-5 Nano","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.05,"output":0.4,"cacheRead":0.005,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":null,"max":null}},"gpt-5.1":{"id":"gpt-5.1","name":"GPT-5.1","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.07,"output":8.5,"cacheRead":0.107,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":null}},"gpt-5.1-codex":{"id":"gpt-5.1-codex","name":"GPT-5.1 Codex","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.07,"output":8.5,"cacheRead":0.107,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":null}},"gpt-5.1-codex-max":{"id":"gpt-5.1-codex-max","name":"GPT-5.1 Codex Max","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.25,"output":10,"cacheRead":0.125,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.1-codex-mini":{"id":"gpt-5.1-codex-mini","name":"GPT-5.1 Codex Mini","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.25,"output":2,"cacheRead":0.025,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":null}},"gpt-5.2":{"id":"gpt-5.2","name":"GPT-5.2","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.75,"output":14,"cacheRead":0.175,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.2-codex":{"id":"gpt-5.2-codex","name":"GPT-5.2 Codex","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.75,"output":14,"cacheRead":0.175,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.3-codex":{"id":"gpt-5.3-codex","name":"GPT-5.3 Codex","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.75,"output":14,"cacheRead":0.175,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.4":{"id":"gpt-5.4","name":"GPT-5.4","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":2.5,"output":15,"cacheRead":0.25,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":272000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.4-mini":{"id":"gpt-5.4-mini","name":"GPT-5.4 Mini","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.75,"output":4.5,"cacheRead":0.075,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.4-nano":{"id":"gpt-5.4-nano","name":"GPT-5.4 Nano","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.2,"output":1.25,"cacheRead":0.02,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.4-pro":{"id":"gpt-5.4-pro","name":"GPT-5.4 Pro","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":30,"output":180,"cacheRead":30,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.5":{"id":"gpt-5.5","name":"GPT-5.5","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":5,"output":30,"cacheRead":0.5,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.5-pro":{"id":"gpt-5.5-pro","name":"GPT-5.5 Pro","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":30,"output":180,"cacheRead":30,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.6-luna":{"id":"gpt-5.6-luna","name":"GPT-5.6 Luna","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.2,"output":1.2,"cacheRead":0.02,"cacheWrite":0.25},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}},"gpt-5.6-sol":{"id":"gpt-5.6-sol","name":"GPT-5.6 Sol (50% Off)","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":10,"cacheRead":0.2,"cacheWrite":2.5},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}},"gpt-5.6-terra":{"id":"gpt-5.6-terra","name":"GPT-5.6 Terra","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":2.5,"output":15,"cacheRead":0.25,"cacheWrite":3.125},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}},"gpt-6-astra":{"id":"gpt-6-astra","name":"GPT-6 Astra","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":10,"output":50,"cacheRead":1,"cacheWrite":12.5},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}},"grok-4.5":{"id":"grok-4.5","name":"Grok 4.5","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":6,"cacheRead":0.3,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":500000,"maxTokens":500000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":null}},"grok-4.6":{"id":"grok-4.6","name":"Grok 4.6","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":6,"cacheRead":0.5,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":500000,"maxTokens":500000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"grok-build-0.1":{"id":"grok-build-0.1","name":"Grok Build 0.1","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1,"output":2,"cacheRead":0.2,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsReasoningEffort":false},"contextWindow":256000,"maxTokens":256000,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null}},"muse-spark-1.2":{"id":"muse-spark-1.2","name":"Muse Spark 1.2","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.25,"output":4.25,"cacheRead":0.15,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"muse-spark-1.2-contributor-free":{"id":"muse-spark-1.2-contributor-free","name":"Muse Spark 1.2 Free","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"muse-spark-1.3":{"id":"muse-spark-1.3","name":"Muse Spark 1.3","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.25,"output":4.25,"cacheRead":0.15,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}},"muse-spark-1.3-contributor-free":{"id":"muse-spark-1.3-contributor-free","name":"Muse Spark 1.3 Free","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}}}} +{"anthropic-messages":{"claude-fable-5":{"id":"claude-fable-5","name":"Claude Fable 5","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":10,"output":50,"cacheRead":1,"cacheWrite":12.5},"contextWindow":1000000,"maxTokens":128000,"thinkingLevelMap":{"xhigh":"xhigh","max":"max"},"compat":{"supportsDisabledThinking":false,"forceAdaptiveThinking":true}},"claude-fable-5-1":{"id":"claude-fable-5-1","name":"Claude Fable 5.1","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":10,"output":50,"cacheRead":0.25,"cacheWrite":12.5},"contextWindow":1000000,"maxTokens":128000,"thinkingLevelMap":{"xhigh":"xhigh","max":"max"},"compat":{"supportsDisabledThinking":false,"forceAdaptiveThinking":true}},"claude-haiku-4-5":{"id":"claude-haiku-4-5","name":"Claude Haiku 4.5","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":1,"output":5,"cacheRead":0.1,"cacheWrite":1.25},"contextWindow":200000,"maxTokens":64000},"claude-opus-4-5":{"id":"claude-opus-4-5","name":"Claude Opus 4.5","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":5,"output":25,"cacheRead":0.5,"cacheWrite":6.25},"contextWindow":200000,"maxTokens":64000},"claude-opus-4-6":{"id":"claude-opus-4-6","name":"Claude Opus 4.6","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":5,"output":25,"cacheRead":0.5,"cacheWrite":6.25},"contextWindow":1000000,"maxTokens":128000,"thinkingLevelMap":{"max":"max"},"compat":{"forceAdaptiveThinking":true}},"claude-opus-4-7":{"id":"claude-opus-4-7","name":"Claude Opus 4.7","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":5,"output":25,"cacheRead":0.5,"cacheWrite":6.25},"contextWindow":1000000,"maxTokens":128000,"thinkingLevelMap":{"xhigh":"xhigh","max":"max"},"compat":{"forceAdaptiveThinking":true,"supportsTemperature":false}},"claude-opus-4-8":{"id":"claude-opus-4-8","name":"Claude Opus 4.8","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":5,"output":25,"cacheRead":0.5,"cacheWrite":6.25},"contextWindow":1000000,"maxTokens":128000,"thinkingLevelMap":{"xhigh":"xhigh","max":"max"},"compat":{"forceAdaptiveThinking":true,"supportsTemperature":false}},"claude-opus-5":{"id":"claude-opus-5","name":"Claude Opus 5","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":5,"output":25,"cacheRead":0.5,"cacheWrite":6.25},"contextWindow":1000000,"maxTokens":128000,"thinkingLevelMap":{"xhigh":"xhigh","max":"max"},"compat":{"forceAdaptiveThinking":true,"supportsTemperature":false}},"claude-sonnet-4":{"id":"claude-sonnet-4","name":"Claude Sonnet 4","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":3.75},"contextWindow":200000,"maxTokens":64000},"claude-sonnet-4-5":{"id":"claude-sonnet-4-5","name":"Claude Sonnet 4.5","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":3.75},"contextWindow":200000,"maxTokens":64000},"claude-sonnet-4-6":{"id":"claude-sonnet-4-6","name":"Claude Sonnet 4.6","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":3.75},"contextWindow":1000000,"maxTokens":64000,"thinkingLevelMap":{"max":"max"},"compat":{"forceAdaptiveThinking":true}},"claude-sonnet-5":{"id":"claude-sonnet-5","name":"Claude Sonnet 5","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":10,"cacheRead":0.2,"cacheWrite":2.5},"contextWindow":1000000,"maxTokens":128000,"thinkingLevelMap":{"xhigh":"xhigh","max":"max"},"compat":{"forceAdaptiveThinking":true}},"qwen3.5-plus":{"id":"qwen3.5-plus","name":"Qwen3.5 Plus","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":0.2,"output":1.2,"cacheRead":0.02,"cacheWrite":0.25},"contextWindow":262144,"maxTokens":65536},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"anthropic-messages","provider":"opencode","baseUrl":"https://opencode.ai/zen","reasoning":true,"input":["text","image"],"cost":{"input":0.5,"output":3,"cacheRead":0.05,"cacheWrite":0.625},"contextWindow":262144,"maxTokens":65536}},"google-generative-ai":{"gemini-3-flash":{"id":"gemini-3-flash","name":"Gemini 3 Flash","api":"google-generative-ai","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.5,"output":3,"cacheRead":0.05,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"thinkingLevelMap":{"off":null}},"gemini-3.1-pro":{"id":"gemini-3.1-pro","name":"Gemini 3.1 Pro Preview","api":"google-generative-ai","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":12,"cacheRead":0.2,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"thinkingLevelMap":{"off":null,"minimal":null,"low":"LOW","medium":null,"high":"HIGH"}},"gemini-3.5-flash":{"id":"gemini-3.5-flash","name":"Gemini 3.5 Flash","api":"google-generative-ai","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.5,"output":9,"cacheRead":0.15,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"thinkingLevelMap":{"off":null}},"gemini-3.5-flash-lite":{"id":"gemini-3.5-flash-lite","name":"Gemini 3.5 Flash Lite","api":"google-generative-ai","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.3,"output":2.5,"cacheRead":0.03,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"thinkingLevelMap":{"off":null}},"gemini-3.6-flash":{"id":"gemini-3.6-flash","name":"Gemini 3.6 Flash","api":"google-generative-ai","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.5,"output":7.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"thinkingLevelMap":{"off":null}},"gemini-3.7-flash":{"id":"gemini-3.7-flash","name":"Gemini 3.7 Flash","api":"google-generative-ai","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.5,"output":7.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"thinkingLevelMap":{"off":null}},"gemini-3.8-flash":{"id":"gemini-3.8-flash","name":"Gemini 3.8 Flash","api":"google-generative-ai","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.5,"output":7.5,"cacheRead":0.15,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"thinkingLevelMap":{"off":null}}},"openai-completions":{"big-pickle":{"id":"big-pickle","name":"Big Pickle","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":200000,"maxTokens":32000},"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":0.14,"output":0.28,"cacheRead":0.028,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false,"requiresReasoningContentOnAssistantMessages":true},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}},"deepseek-v4-flash-vision-exp":{"id":"deepseek-v4-flash-vision-exp","name":"DeepSeek V4 Flash Vision Exp","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.14,"output":0.28,"cacheRead":0.028,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":1.74,"output":3.84,"cacheRead":0.145,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false,"requiresReasoningContentOnAssistantMessages":true},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"}},"glm-5":{"id":"glm-5","name":"GLM-5","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":1,"output":3.2,"cacheRead":0.2,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":204800,"maxTokens":131072},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":204800,"maxTokens":131072},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"}},"glm-5.3":{"id":"glm-5.3","name":"GLM-5.3","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}},"glm-5.3-flash":{"id":"glm-5.3-flash","name":"GLM-5.3-Flash","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.5,"cacheRead":0.03,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.6,"output":3,"cacheRead":0.08,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false},"contextWindow":262144,"maxTokens":65536},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.16,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"thinkingFormat":"deepseek","supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false},"contextWindow":262144,"maxTokens":65536},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.19,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false},"contextWindow":262144,"maxTokens":262144},"kimi-k3":{"id":"kimi-k3","name":"Kimi K3","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}},"ling-3.0-flash-fin-free":{"id":"ling-3.0-flash-fin-free","name":"Ling 3.0 Flash Fin Free","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":262144,"maxTokens":32768},"mimo-v2.5-free":{"id":"mimo-v2.5-free","name":"MiMo V2.5 Free","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":200000,"maxTokens":32000},"minimax-m2.5":{"id":"minimax-m2.5","name":"MiniMax-M2.5","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.06,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":204800,"maxTokens":131072},"minimax-m2.7":{"id":"minimax-m2.7","name":"MiniMax-M2.7","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.06,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false},"contextWindow":204800,"maxTokens":131072},"minimax-m3":{"id":"minimax-m3","name":"MiniMax-M3","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.06,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":512000,"maxTokens":128000},"nemotron-3-ultra-free":{"id":"nemotron-3-ultra-free","name":"Nemotron 3 Ultra Free","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":128000},"nemotron-3.5-lightning-free":{"id":"nemotron-3.5-lightning-free","name":"Nemotron 3.5 Lightning Free","api":"openai-completions","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":262144,"maxTokens":262144}},"openai-responses":{"gpt-5":{"id":"gpt-5","name":"GPT-5","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.07,"output":8.5,"cacheRead":0.107,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":null,"max":null}},"gpt-5-codex":{"id":"gpt-5-codex","name":"GPT-5 Codex","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.07,"output":8.5,"cacheRead":0.107,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":null}},"gpt-5-nano":{"id":"gpt-5-nano","name":"GPT-5 Nano","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.05,"output":0.4,"cacheRead":0.005,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":null,"max":null}},"gpt-5.1":{"id":"gpt-5.1","name":"GPT-5.1","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.07,"output":8.5,"cacheRead":0.107,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":null}},"gpt-5.1-codex":{"id":"gpt-5.1-codex","name":"GPT-5.1 Codex","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.07,"output":8.5,"cacheRead":0.107,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":null}},"gpt-5.1-codex-max":{"id":"gpt-5.1-codex-max","name":"GPT-5.1 Codex Max","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.25,"output":10,"cacheRead":0.125,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.1-codex-mini":{"id":"gpt-5.1-codex-mini","name":"GPT-5.1 Codex Mini","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.25,"output":2,"cacheRead":0.025,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":null}},"gpt-5.2":{"id":"gpt-5.2","name":"GPT-5.2","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.75,"output":14,"cacheRead":0.175,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.2-codex":{"id":"gpt-5.2-codex","name":"GPT-5.2 Codex","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.75,"output":14,"cacheRead":0.175,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.3-codex":{"id":"gpt-5.3-codex","name":"GPT-5.3 Codex","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.75,"output":14,"cacheRead":0.175,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.4":{"id":"gpt-5.4","name":"GPT-5.4","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":2.5,"output":15,"cacheRead":0.25,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":272000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.4-mini":{"id":"gpt-5.4-mini","name":"GPT-5.4 Mini","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.75,"output":4.5,"cacheRead":0.075,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.4-nano":{"id":"gpt-5.4-nano","name":"GPT-5.4 Nano","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.2,"output":1.25,"cacheRead":0.02,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":400000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.4-pro":{"id":"gpt-5.4-pro","name":"GPT-5.4 Pro","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":30,"output":180,"cacheRead":30,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.5":{"id":"gpt-5.5","name":"GPT-5.5","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":5,"output":30,"cacheRead":0.5,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.5-pro":{"id":"gpt-5.5-pro","name":"GPT-5.5 Pro","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":30,"output":180,"cacheRead":30,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":"medium","high":"high","xhigh":"xhigh","max":null}},"gpt-5.6-luna":{"id":"gpt-5.6-luna","name":"GPT-5.6 Luna","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.2,"output":1.2,"cacheRead":0.02,"cacheWrite":0.25},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}},"gpt-5.6-sol":{"id":"gpt-5.6-sol","name":"GPT-5.6 Sol (50% Off)","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":10,"cacheRead":0.2,"cacheWrite":2.5},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}},"gpt-5.6-terra":{"id":"gpt-5.6-terra","name":"GPT-5.6 Terra","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":2.5,"output":15,"cacheRead":0.25,"cacheWrite":3.125},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}},"gpt-6-astra":{"id":"gpt-6-astra","name":"GPT-6 Astra","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":10,"output":50,"cacheRead":1,"cacheWrite":12.5},"compat":{"sessionAffinityFormat":"openai-nosession","supportsOpenAIGrammarTools":true},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}},"grok-4.5":{"id":"grok-4.5","name":"Grok 4.5","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":6,"cacheRead":0.3,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":500000,"maxTokens":500000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":null}},"grok-4.6":{"id":"grok-4.6","name":"Grok 4.6","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":6,"cacheRead":0.5,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":500000,"maxTokens":500000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"grok-build-0.1":{"id":"grok-build-0.1","name":"Grok Build 0.1","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1,"output":2,"cacheRead":0.2,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession","supportsReasoningEffort":false},"contextWindow":256000,"maxTokens":256000,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null}},"muse-spark-1.2":{"id":"muse-spark-1.2","name":"Muse Spark 1.2","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.25,"output":4.25,"cacheRead":0.15,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"muse-spark-1.2-contributor-free":{"id":"muse-spark-1.2-contributor-free","name":"Muse Spark 1.2 Free","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"muse-spark-1.3":{"id":"muse-spark-1.3","name":"Muse Spark 1.3","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":1.25,"output":4.25,"cacheRead":0.15,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}},"muse-spark-1.3-contributor-free":{"id":"muse-spark-1.3-contributor-free","name":"Muse Spark 1.3 Free","api":"openai-responses","provider":"opencode","baseUrl":"https://opencode.ai/zen/v1","reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}}}} diff --git a/packages/ai/src/providers/data/qwen-token-plan-cn.json b/packages/ai/src/providers/data/qwen-token-plan-cn.json index e93d0d65ad..46c44d2fb4 100644 --- a/packages/ai/src/providers/data/qwen-token-plan-cn.json +++ b/packages/ai/src/providers/data/qwen-token-plan-cn.json @@ -1 +1 @@ -{"openai-completions":{"MiniMax-M2.5":{"id":"MiniMax-M2.5","name":"MiniMax-M2.5","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":196608,"maxTokens":32768},"deepseek-v3.2":{"id":"deepseek-v3.2","name":"DeepSeek V3.2","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":131072,"maxTokens":65536},"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-flash-0731":{"id":"deepseek-v4-flash-0731","name":"DeepSeek V4 Flash 0731","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro-0813":{"id":"deepseek-v4-pro-0813","name":"DeepSeek V4 Pro 0813","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"glm-5":{"id":"glm-5","name":"GLM-5","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":16384},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":128000},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":98304},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"qwen3.6-flash":{"id":"qwen3.6-flash","name":"Qwen3.6 Flash","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072}}} +{"openai-completions":{"MiniMax-M2.5":{"id":"MiniMax-M2.5","name":"MiniMax-M2.5","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":196608,"maxTokens":32768},"deepseek-v3.2":{"id":"deepseek-v3.2","name":"DeepSeek V3.2","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":131072,"maxTokens":65536},"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-flash-0731":{"id":"deepseek-v4-flash-0731","name":"DeepSeek V4 Flash 0731","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro-0813":{"id":"deepseek-v4-pro-0813","name":"DeepSeek V4 Pro 0813","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"glm-5":{"id":"glm-5","name":"GLM-5","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":16384},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":128000},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":98304},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"qwen3.6-flash":{"id":"qwen3.6-flash","name":"Qwen3.6 Flash","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072}}} diff --git a/packages/ai/src/providers/data/qwen-token-plan-individual.json b/packages/ai/src/providers/data/qwen-token-plan-individual.json index d26f20a587..8e30cacfc6 100644 --- a/packages/ai/src/providers/data/qwen-token-plan-individual.json +++ b/packages/ai/src/providers/data/qwen-token-plan-individual.json @@ -1 +1 @@ -{"openai-completions":{"deepseek-v4-flash-0731":{"id":"deepseek-v4-flash-0731","name":"DeepSeek V4 Flash 0731","api":"openai-completions","provider":"qwen-token-plan-individual","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro","api":"openai-completions","provider":"qwen-token-plan-individual","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro-0813":{"id":"deepseek-v4-pro-0813","name":"DeepSeek V4 Pro 0813","api":"openai-completions","provider":"qwen-token-plan-individual","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"qwen-token-plan-individual","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.6-flash":{"id":"qwen3.6-flash","name":"Qwen3.6 Flash","api":"openai-completions","provider":"qwen-token-plan-individual","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"qwen-token-plan-individual","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"qwen-token-plan-individual","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"qwen-token-plan-individual","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072}}} +{"openai-completions":{"deepseek-v4-flash-0731":{"id":"deepseek-v4-flash-0731","name":"DeepSeek V4 Flash 0731","api":"openai-completions","provider":"qwen-token-plan-individual","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro","api":"openai-completions","provider":"qwen-token-plan-individual","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro-0813":{"id":"deepseek-v4-pro-0813","name":"DeepSeek V4 Pro 0813","api":"openai-completions","provider":"qwen-token-plan-individual","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"qwen-token-plan-individual","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.6-flash":{"id":"qwen3.6-flash","name":"Qwen3.6 Flash","api":"openai-completions","provider":"qwen-token-plan-individual","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"qwen-token-plan-individual","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"qwen-token-plan-individual","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"qwen-token-plan-individual","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072}}} diff --git a/packages/ai/src/providers/data/qwen-token-plan.json b/packages/ai/src/providers/data/qwen-token-plan.json index 45bf79a4fb..09358d31f3 100644 --- a/packages/ai/src/providers/data/qwen-token-plan.json +++ b/packages/ai/src/providers/data/qwen-token-plan.json @@ -1 +1 @@ -{"openai-completions":{"MiniMax-M2.5":{"id":"MiniMax-M2.5","name":"MiniMax-M2.5","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":196608,"maxTokens":32768},"deepseek-v3.2":{"id":"deepseek-v3.2","name":"DeepSeek V3.2","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":131072,"maxTokens":65536},"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-flash-0731":{"id":"deepseek-v4-flash-0731","name":"DeepSeek V4 Flash 0731","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro-0813":{"id":"deepseek-v4-pro-0813","name":"DeepSeek V4 Pro 0813","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"glm-5":{"id":"glm-5","name":"GLM-5","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":16384},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":128000},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":98304},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"qwen3.6-flash":{"id":"qwen3.6-flash","name":"Qwen3.6 Flash","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072}}} +{"openai-completions":{"MiniMax-M2.5":{"id":"MiniMax-M2.5","name":"MiniMax-M2.5","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":196608,"maxTokens":32768},"deepseek-v3.2":{"id":"deepseek-v3.2","name":"DeepSeek V3.2","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":131072,"maxTokens":65536},"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-flash-0731":{"id":"deepseek-v4-flash-0731","name":"DeepSeek V4 Flash 0731","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro-0813":{"id":"deepseek-v4-pro-0813","name":"DeepSeek V4 Pro 0813","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"glm-5":{"id":"glm-5","name":"GLM-5","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":16384},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":128000},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":98304},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"qwen3.6-flash":{"id":"qwen3.6-flash","name":"Qwen3.6 Flash","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072}}} diff --git a/packages/ai/src/providers/data/xiaomi-token-plan-ams.json b/packages/ai/src/providers/data/xiaomi-token-plan-ams.json index c8293ce683..95aadf594a 100644 --- a/packages/ai/src/providers/data/xiaomi-token-plan-ams.json +++ b/packages/ai/src/providers/data/xiaomi-token-plan-ams.json @@ -1 +1 @@ -{"openai-completions":{"mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo-V2.5","api":"openai-completions","provider":"xiaomi-token-plan-ams","baseUrl":"https://token-plan-ams.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072},"mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo-V2.5-Pro","api":"openai-completions","provider":"xiaomi-token-plan-ams","baseUrl":"https://token-plan-ams.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072}}} +{"openai-completions":{"mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo-V2.5","api":"openai-completions","provider":"xiaomi-token-plan-ams","baseUrl":"https://token-plan-ams.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072},"mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo-V2.5-Pro","api":"openai-completions","provider":"xiaomi-token-plan-ams","baseUrl":"https://token-plan-ams.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072}}} diff --git a/packages/ai/src/providers/data/xiaomi-token-plan-cn.json b/packages/ai/src/providers/data/xiaomi-token-plan-cn.json index 715ba38bda..be43e1b821 100644 --- a/packages/ai/src/providers/data/xiaomi-token-plan-cn.json +++ b/packages/ai/src/providers/data/xiaomi-token-plan-cn.json @@ -1 +1 @@ -{"openai-completions":{"mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo-V2.5","api":"openai-completions","provider":"xiaomi-token-plan-cn","baseUrl":"https://token-plan-cn.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072},"mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo-V2.5-Pro","api":"openai-completions","provider":"xiaomi-token-plan-cn","baseUrl":"https://token-plan-cn.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072}}} +{"openai-completions":{"mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo-V2.5","api":"openai-completions","provider":"xiaomi-token-plan-cn","baseUrl":"https://token-plan-cn.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072},"mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo-V2.5-Pro","api":"openai-completions","provider":"xiaomi-token-plan-cn","baseUrl":"https://token-plan-cn.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072}}} diff --git a/packages/ai/src/providers/data/xiaomi-token-plan-sgp.json b/packages/ai/src/providers/data/xiaomi-token-plan-sgp.json index 8849d92dad..a911a7b159 100644 --- a/packages/ai/src/providers/data/xiaomi-token-plan-sgp.json +++ b/packages/ai/src/providers/data/xiaomi-token-plan-sgp.json @@ -1 +1 @@ -{"openai-completions":{"mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo-V2.5","api":"openai-completions","provider":"xiaomi-token-plan-sgp","baseUrl":"https://token-plan-sgp.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072},"mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo-V2.5-Pro","api":"openai-completions","provider":"xiaomi-token-plan-sgp","baseUrl":"https://token-plan-sgp.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072}}} +{"openai-completions":{"mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo-V2.5","api":"openai-completions","provider":"xiaomi-token-plan-sgp","baseUrl":"https://token-plan-sgp.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072},"mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo-V2.5-Pro","api":"openai-completions","provider":"xiaomi-token-plan-sgp","baseUrl":"https://token-plan-sgp.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072}}} diff --git a/packages/ai/src/providers/data/xiaomi.json b/packages/ai/src/providers/data/xiaomi.json index f137e8e263..aaeaba24b4 100644 --- a/packages/ai/src/providers/data/xiaomi.json +++ b/packages/ai/src/providers/data/xiaomi.json @@ -1 +1 @@ -{"openai-completions":{"mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo-V2.5","api":"openai-completions","provider":"xiaomi","baseUrl":"https://api.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0.14,"output":0.28,"cacheRead":0.0028,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072},"mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo-V2.5-Pro","api":"openai-completions","provider":"xiaomi","baseUrl":"https://api.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text"],"cost":{"input":0.435,"output":0.87,"cacheRead":0.0036,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072},"mimo-v2.5-pro-ultraspeed":{"id":"mimo-v2.5-pro-ultraspeed","name":"MiMo-V2.5-Pro-UltraSpeed","api":"openai-completions","provider":"xiaomi","baseUrl":"https://api.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text"],"cost":{"input":1.305,"output":2.61,"cacheRead":0.0108,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072}}} +{"openai-completions":{"mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo-V2.5","api":"openai-completions","provider":"xiaomi","baseUrl":"https://api.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0.14,"output":0.28,"cacheRead":0.0028,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072},"mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo-V2.5-Pro","api":"openai-completions","provider":"xiaomi","baseUrl":"https://api.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":0.435,"output":0.87,"cacheRead":0.0036,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072},"mimo-v2.5-pro-ultraspeed":{"id":"mimo-v2.5-pro-ultraspeed","name":"MiMo-V2.5-Pro-UltraSpeed","api":"openai-completions","provider":"xiaomi","baseUrl":"https://api.xiaomimimo.com/v1","compat":{"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":1.305,"output":2.61,"cacheRead":0.0108,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072}}} diff --git a/packages/ai/src/providers/data/zai-coding-cn.json b/packages/ai/src/providers/data/zai-coding-cn.json index 72efe358bd..767eeae51c 100644 --- a/packages/ai/src/providers/data/zai-coding-cn.json +++ b/packages/ai/src/providers/data/zai-coding-cn.json @@ -1 +1 @@ -{"openai-completions":{"glm-4.6v":{"id":"glm-4.6v","name":"GLM-4.6V","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"input":["text","image"],"cost":{"input":0.3,"output":0.9,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":128000,"maxTokens":32768},"glm-4.7":{"id":"glm-4.7","name":"GLM-4.7","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"input":["text"],"cost":{"input":0.6,"output":2.2,"cacheRead":0.11,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":204800,"maxTokens":131072},"glm-5-turbo":{"id":"glm-5-turbo","name":"GLM-5-Turbo","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"input":["text"],"cost":{"input":1.2,"output":4,"cacheRead":0.24,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":200000,"maxTokens":131072},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":200000,"maxTokens":131072},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5.2-highspeed":{"id":"glm-5.2-highspeed","name":"GLM-5.2 Highspeed","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5.3":{"id":"glm-5.3","name":"GLM-5.3","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5.3-flash":{"id":"glm-5.3-flash","name":"GLM-5.3-Flash","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":0.075,"output":0.25,"cacheRead":0.015,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5.3-highspeed":{"id":"glm-5.3-highspeed","name":"GLM-5.3 Highspeed","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5v-turbo":{"id":"glm-5v-turbo","name":"GLM-5V-Turbo","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"input":["text","image"],"cost":{"input":1.2,"output":4,"cacheRead":0.24,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":200000,"maxTokens":131072}}} +{"openai-completions":{"glm-4.6v":{"id":"glm-4.6v","name":"GLM-4.6V","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0.3,"output":0.9,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":128000,"maxTokens":32768},"glm-4.7":{"id":"glm-4.7","name":"GLM-4.7","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":0.6,"output":2.2,"cacheRead":0.11,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":204800,"maxTokens":131072},"glm-5-turbo":{"id":"glm-5-turbo","name":"GLM-5-Turbo","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":1.2,"output":4,"cacheRead":0.24,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":200000,"maxTokens":131072},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":200000,"maxTokens":131072},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5.2-highspeed":{"id":"glm-5.2-highspeed","name":"GLM-5.2 Highspeed","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5.3":{"id":"glm-5.3","name":"GLM-5.3","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5.3-flash":{"id":"glm-5.3-flash","name":"GLM-5.3-Flash","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":0.075,"output":0.25,"cacheRead":0.015,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5.3-highspeed":{"id":"glm-5.3-highspeed","name":"GLM-5.3 Highspeed","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5v-turbo":{"id":"glm-5v-turbo","name":"GLM-5V-Turbo","api":"openai-completions","provider":"zai-coding-cn","baseUrl":"https://open.bigmodel.cn/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":1.2,"output":4,"cacheRead":0.24,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":200000,"maxTokens":131072}}} diff --git a/packages/ai/src/providers/data/zai.json b/packages/ai/src/providers/data/zai.json index 95654f5313..a03ada8a37 100644 --- a/packages/ai/src/providers/data/zai.json +++ b/packages/ai/src/providers/data/zai.json @@ -1 +1 @@ -{"openai-completions":{"glm-4.7":{"id":"glm-4.7","name":"GLM-4.7","api":"openai-completions","provider":"zai","baseUrl":"https://api.z.ai/api/coding/paas/v4","reasoning":true,"input":["text"],"cost":{"input":0.6,"output":2.2,"cacheRead":0.11,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":204800,"maxTokens":131072},"glm-5-turbo":{"id":"glm-5-turbo","name":"GLM-5-Turbo","api":"openai-completions","provider":"zai","baseUrl":"https://api.z.ai/api/coding/paas/v4","reasoning":true,"input":["text"],"cost":{"input":1.2,"output":4,"cacheRead":0.24,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":200000,"maxTokens":131072},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"zai","baseUrl":"https://api.z.ai/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5.2-highspeed":{"id":"glm-5.2-highspeed","name":"GLM-5.2 Highspeed","api":"openai-completions","provider":"zai","baseUrl":"https://api.z.ai/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5.3":{"id":"glm-5.3","name":"GLM-5.3","api":"openai-completions","provider":"zai","baseUrl":"https://api.z.ai/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5.3-flash":{"id":"glm-5.3-flash","name":"GLM-5.3-Flash","api":"openai-completions","provider":"zai","baseUrl":"https://api.z.ai/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":0.075,"output":0.25,"cacheRead":0.015,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5.3-highspeed":{"id":"glm-5.3-highspeed","name":"GLM-5.3 Highspeed","api":"openai-completions","provider":"zai","baseUrl":"https://api.z.ai/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072}}} +{"openai-completions":{"glm-4.7":{"id":"glm-4.7","name":"GLM-4.7","api":"openai-completions","provider":"zai","baseUrl":"https://api.z.ai/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":0.6,"output":2.2,"cacheRead":0.11,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":204800,"maxTokens":131072},"glm-5-turbo":{"id":"glm-5-turbo","name":"GLM-5-Turbo","api":"openai-completions","provider":"zai","baseUrl":"https://api.z.ai/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":1.2,"output":4,"cacheRead":0.24,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":200000,"maxTokens":131072},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"zai","baseUrl":"https://api.z.ai/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5.2-highspeed":{"id":"glm-5.2-highspeed","name":"GLM-5.2 Highspeed","api":"openai-completions","provider":"zai","baseUrl":"https://api.z.ai/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5.3":{"id":"glm-5.3","name":"GLM-5.3","api":"openai-completions","provider":"zai","baseUrl":"https://api.z.ai/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5.3-flash":{"id":"glm-5.3-flash","name":"GLM-5.3-Flash","api":"openai-completions","provider":"zai","baseUrl":"https://api.z.ai/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":0.075,"output":0.25,"cacheRead":0.015,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072},"glm-5.3-highspeed":{"id":"glm-5.3-highspeed","name":"GLM-5.3 Highspeed","api":"openai-completions","provider":"zai","baseUrl":"https://api.z.ai/api/coding/paas/v4","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","thinkingFormat":"zai","zaiToolStream":true},"contextWindow":1000000,"maxTokens":131072}}} diff --git a/packages/ai/test/generate-models-strict.test.ts b/packages/ai/test/generate-models-strict.test.ts index eee4618db5..c7cf49896f 100644 --- a/packages/ai/test/generate-models-strict.test.ts +++ b/packages/ai/test/generate-models-strict.test.ts @@ -75,6 +75,96 @@ describe("strict model generation", () => { } }); + it("regenerates selected providers without changing unselected artifacts", () => { + const fixtureRoot = mkdtempSync(join(tmpdir(), "pi-generate-models-selected-")); + temporaryRoots.push(fixtureRoot); + const isolatedPackageRoot = join(fixtureRoot, "package"); + mkdirSync(isolatedPackageRoot); + for (const entry of ["package.json", "scripts", "src"]) { + cpSync(join(packageRoot, entry), join(isolatedPackageRoot, entry), { recursive: true }); + } + const preloadPath = join(fixtureRoot, "mock-models-dev.mjs"); + const catalog = { + "zai-coding-plan": { + models: { + "glm-4.7": { id: "glm-4.7", name: "GLM 4.7", tool_call: true, reasoning: true }, + }, + }, + "zhipuai-coding-plan": { + models: { + "glm-4.7": { id: "glm-4.7", name: "GLM 4.7 CN", tool_call: true, reasoning: true }, + }, + }, + }; + writeFileSync( + preloadPath, + `const catalog = ${JSON.stringify(catalog)};\n` + + `globalThis.fetch = async (input) => {\n` + + ` const url = String(input);\n` + + ` if (url === "https://models.dev/api.json") return new Response(JSON.stringify(catalog), { status: 200 });\n` + + ` if (url === "https://openrouter.ai/api/v1/models") return new Response(JSON.stringify({ data: [] }), { status: 200 });\n` + + ` if (url === "https://ai-gateway.vercel.sh/v1/models") return new Response(JSON.stringify({ data: [] }), { status: 200 });\n` + + ` if (url === "https://apis.opengateway.ai/v1/models") return new Response(JSON.stringify({ data: [] }), { status: 200 });\n` + + ` if (url.includes("api.nvidia.com")) return new Response(JSON.stringify({ data: [] }), { status: 200 });\n` + + ` throw new Error(\`Unexpected fetch: \${url}\`);\n` + + `};\n`, + ); + const selected = ["zai", "zai-coding-cn"]; + const unselectedPath = join(isolatedPackageRoot, "src/providers/data/openrouter.json"); + const unselectedBefore = readFileSync(unselectedPath, "utf8"); + const args = [ + "--import", + pathToFileURL(preloadPath).href, + "scripts/generate-models.ts", + "--providers", + selected.join(","), + "--generated-at", + "2026-09-06T00:00:00.000Z", + ]; + + const first = spawnSync(process.execPath, args, { cwd: isolatedPackageRoot, encoding: "utf8", timeout: 10_000 }); + expect(first.status, `${first.stdout}\n${first.stderr}`).toBe(0); + expect(readFileSync(unselectedPath, "utf8")).toBe(unselectedBefore); + const selectedFirst = selected.map((provider) => + readFileSync(join(isolatedPackageRoot, `src/providers/data/${provider}.json`), "utf8"), + ); + const manifestFirst = readFileSync(join(isolatedPackageRoot, "src/providers/data/.manifest.json"), "utf8"); + + const second = spawnSync(process.execPath, args, { cwd: isolatedPackageRoot, encoding: "utf8", timeout: 10_000 }); + expect(second.status, `${second.stdout}\n${second.stderr}`).toBe(0); + expect( + selected.map((provider) => + readFileSync(join(isolatedPackageRoot, `src/providers/data/${provider}.json`), "utf8"), + ), + ).toEqual(selectedFirst); + expect(readFileSync(join(isolatedPackageRoot, "src/providers/data/.manifest.json"), "utf8")).toBe(manifestFirst); + expect( + spawnSync(process.execPath, ["scripts/check-model-data.ts"], { cwd: isolatedPackageRoot, encoding: "utf8" }) + .status, + ).toBe(0); + + const invalid = spawnSync( + process.execPath, + ["--import", pathToFileURL(preloadPath).href, "scripts/generate-models.ts", "--providers", "zai,missing"], + { cwd: isolatedPackageRoot, encoding: "utf8", timeout: 10_000 }, + ); + expect(invalid.status).toBe(1); + expect(`${invalid.stdout}\n${invalid.stderr}`).toContain("Unknown provider selector: missing"); + expect(readFileSync(unselectedPath, "utf8")).toBe(unselectedBefore); + for (const providerId of ["__proto__", "constructor", "toString"]) { + const inherited = spawnSync( + process.execPath, + ["--import", pathToFileURL(preloadPath).href, "scripts/generate-models.ts", "--providers", providerId], + { cwd: isolatedPackageRoot, encoding: "utf8", timeout: 10_000 }, + ); + expect(inherited.status, `${providerId}: ${inherited.stdout}\n${inherited.stderr}`).toBe(1); + expect(readFileSync(join(isolatedPackageRoot, "src/providers/data/.manifest.json"), "utf8")).toBe( + manifestFirst, + ); + expect(readFileSync(unselectedPath, "utf8")).toBe(unselectedBefore); + } + }); + it("fails before mutating generated data when an Individual model loses tool support", () => { const fixtureRoot = mkdtempSync(join(tmpdir(), "pi-generate-models-")); temporaryRoots.push(fixtureRoot); diff --git a/packages/ai/test/issue-891-thinking-capabilities.test.ts b/packages/ai/test/issue-891-thinking-capabilities.test.ts new file mode 100644 index 0000000000..07de9a26c1 --- /dev/null +++ b/packages/ai/test/issue-891-thinking-capabilities.test.ts @@ -0,0 +1,83 @@ +import { describe, expect, it } from "vitest"; +import { getModel, getModels, getSupportedThinkingLevels } from "../src/compat.ts"; +import type { ModelThinkingLevel } from "../src/types.ts"; + +type CapabilityCase = { + provider: Parameters[0]; + id: string; + levels: ModelThinkingLevel[]; +}; + +const ON_OFF: ModelThinkingLevel[] = ["off", "high"]; +const ALWAYS_ON: ModelThinkingLevel[] = ["high"]; + +// #891: Every current map-less reasoning row must have an explicit catalog capability. +// This is intentionally a complete current-row table: a removed or renamed row fails instead +// of silently disappearing from the regression. +const CAPABILITY_CASES: CapabilityCase[] = [ + { provider: "alibaba-token-plan", id: "deepseek-v3.2", levels: ON_OFF }, + { provider: "alibaba-token-plan", id: "kimi-k2.5", levels: ON_OFF }, + { provider: "alibaba-token-plan", id: "kimi-k2.6", levels: ON_OFF }, + { provider: "alibaba-token-plan", id: "kimi-k2.7-code", levels: ALWAYS_ON }, + { provider: "alibaba-token-plan", id: "qwen3.6-flash", levels: ON_OFF }, + { provider: "alibaba-token-plan", id: "qwen3.6-plus", levels: ON_OFF }, + { provider: "alibaba-token-plan", id: "qwen3.7-max", levels: ON_OFF }, + { provider: "alibaba-token-plan", id: "qwen3.7-plus", levels: ON_OFF }, + { provider: "alibaba-token-plan", id: "qwen3.8-flash", levels: ON_OFF }, + { provider: "alibaba-token-plan", id: "qwen3.8-max", levels: ON_OFF }, + { provider: "alibaba-token-plan", id: "qwen3.8-max-preview", levels: ON_OFF }, + ...(["qwen-token-plan", "qwen-token-plan-cn"] as const).flatMap((provider) => [ + { provider, id: "MiniMax-M2.5", levels: ON_OFF }, + { provider, id: "deepseek-v3.2", levels: ON_OFF }, + { provider, id: "kimi-k2.5", levels: ON_OFF }, + { provider, id: "kimi-k2.6", levels: ON_OFF }, + { provider, id: "kimi-k2.7-code", levels: ON_OFF }, + { provider, id: "qwen3.6-flash", levels: ON_OFF }, + { provider, id: "qwen3.6-plus", levels: ON_OFF }, + { provider, id: "qwen3.7-max", levels: ON_OFF }, + { provider, id: "qwen3.7-plus", levels: ON_OFF }, + ]), + { provider: "qwen-token-plan-individual", id: "qwen3.6-flash", levels: ON_OFF }, + { provider: "qwen-token-plan-individual", id: "qwen3.7-max", levels: ON_OFF }, + { provider: "qwen-token-plan-individual", id: "qwen3.7-plus", levels: ON_OFF }, + ...(["moonshotai", "moonshotai-cn"] as const).flatMap((provider) => [ + { provider, id: "kimi-k2-thinking", levels: ON_OFF }, + { provider, id: "kimi-k2-thinking-turbo", levels: ON_OFF }, + { provider, id: "kimi-k2.5", levels: ON_OFF }, + { provider, id: "kimi-k2.6", levels: ON_OFF }, + ]), + { provider: "opencode", id: "kimi-k2.6", levels: ON_OFF }, + { provider: "opencode-go", id: "qwen3.6-plus", levels: ON_OFF }, + { provider: "xiaomi", id: "mimo-v2.5", levels: ON_OFF }, + { provider: "xiaomi", id: "mimo-v2.5-pro", levels: ON_OFF }, + { provider: "xiaomi", id: "mimo-v2.5-pro-ultraspeed", levels: ON_OFF }, + ...(["xiaomi-token-plan-ams", "xiaomi-token-plan-cn", "xiaomi-token-plan-sgp"] as const).flatMap((provider) => [ + { provider, id: "mimo-v2.5", levels: ON_OFF }, + { provider, id: "mimo-v2.5-pro", levels: ON_OFF }, + ]), + { provider: "zai", id: "glm-4.7", levels: ALWAYS_ON }, + { provider: "zai", id: "glm-5-turbo", levels: ON_OFF }, + { provider: "zai-coding-cn", id: "glm-4.6v", levels: ON_OFF }, + { provider: "zai-coding-cn", id: "glm-4.7", levels: ALWAYS_ON }, + { provider: "zai-coding-cn", id: "glm-5-turbo", levels: ON_OFF }, + { provider: "zai-coding-cn", id: "glm-5.1", levels: ON_OFF }, + { provider: "zai-coding-cn", id: "glm-5v-turbo", levels: ON_OFF }, +]; + +describe("issue #891 generated thinking capabilities", () => { + it.each(CAPABILITY_CASES)("limits $provider/$id to its serialized control surface", ({ provider, id, levels }) => { + const model = getModels(provider).find((candidate) => candidate.id === id); + + expect(model, `missing current catalog row ${provider}/${id}`).toBeDefined(); + if (!model) throw new Error(`missing current catalog row ${provider}/${id}`); + expect(getSupportedThinkingLevels(model)).toEqual(levels); + }); + + it("keeps documented Qwen reasoning effort controls graded", () => { + const model = getModel("qwen-token-plan", "qwen3.8-max"); + + expect(model).toBeDefined(); + if (!model) throw new Error("missing qwen-token-plan/qwen3.8-max"); + expect(getSupportedThinkingLevels(model)).toEqual(["off", "low", "medium", "xhigh"]); + }); +}); diff --git a/packages/ai/test/openai-completions-thinking-matrix.test.ts b/packages/ai/test/openai-completions-thinking-matrix.test.ts index 5188f3a219..a327e1e088 100644 --- a/packages/ai/test/openai-completions-thinking-matrix.test.ts +++ b/packages/ai/test/openai-completions-thinking-matrix.test.ts @@ -5,6 +5,7 @@ import type { BuiltinProvider } from "../src/providers/all.ts"; import type { Context, Model, ModelThinkingLevel, SimpleStreamOptions } from "../src/types.ts"; type CapturedPayload = { + enable_thinking?: boolean; reasoning?: { effort?: string }; reasoning_effort?: string; thinking?: { type?: string } | string; @@ -101,16 +102,16 @@ describe("OpenAI Completions thinking ladder fallbacks", () => { it.each([ { - name: "DeepSeek's two-tier ladder on Alibaba Token Plan", + name: "DeepSeek's enable switch on Alibaba Token Plan", model: getOpenAICompletionsModel("alibaba-token-plan", "deepseek-v3.2"), reasoning: "minimal" as const, - expected: { thinking: { type: "enabled" }, reasoning_effort: "high" }, + expected: { thinking: { type: "enabled" } }, }, { - name: "DeepSeek's max tier on Alibaba Token Plan", + name: "DeepSeek's enable switch on Alibaba Token Plan", model: getOpenAICompletionsModel("alibaba-token-plan", "deepseek-v3.2"), - reasoning: "xhigh" as const, - expected: { thinking: { type: "enabled" }, reasoning_effort: "max" }, + reasoning: "high" as const, + expected: { thinking: { type: "enabled" } }, }, { name: "OpenRouter DeepSeek's high-only ladder", @@ -196,6 +197,67 @@ describe("OpenAI Completions thinking ladder fallbacks", () => { } }); + it.each([ + { + name: "Alibaba DeepSeek", + model: getOpenAICompletionsModel("alibaba-token-plan", "deepseek-v3.2"), + on: { thinking: { type: "enabled" } }, + off: { thinking: { type: "disabled" } }, + }, + { + name: "Qwen Token Plan", + model: getOpenAICompletionsModel("qwen-token-plan", "qwen3.7-max"), + on: { enable_thinking: true }, + off: { enable_thinking: false }, + }, + { + name: "Moonshot Kimi", + model: getOpenAICompletionsModel("moonshotai", "kimi-k2.6"), + on: { thinking: { type: "enabled" } }, + off: { thinking: { type: "disabled" } }, + }, + { + name: "Xiaomi MiMo", + model: getOpenAICompletionsModel("xiaomi", "mimo-v2.5-pro"), + on: { thinking: { type: "enabled" } }, + off: { thinking: { type: "disabled" } }, + }, + { + name: "Z.AI GLM", + model: getOpenAICompletionsModel("zai", "glm-5-turbo"), + on: { thinking: { type: "enabled" } }, + off: { thinking: { type: "disabled" } }, + }, + ])("serializes every on/off effort request identically for $name", async ({ model, on, off }) => { + const enabledPayloads = await Promise.all( + (["minimal", "low", "medium", "high"] as const).map((level) => captureDirectPayload(model, level)), + ); + + for (const payload of enabledPayloads) { + expect(payload).toMatchObject(on); + expect(payload.reasoning_effort).toBeUndefined(); + } + expect(await capturePayload(model)).toMatchObject(off); + }); + + it("keeps Qwen's documented graded control distinct on the wire", async () => { + const model = getOpenAICompletionsModel("qwen-token-plan", "qwen3.8-max"); + + expect(await captureDirectPayload(model, "low")).toMatchObject({ + enable_thinking: true, + reasoning_effort: "low", + }); + expect(await captureDirectPayload(model, "medium")).toMatchObject({ + enable_thinking: true, + reasoning_effort: "medium", + }); + expect(await captureDirectPayload(model, "xhigh")).toMatchObject({ + enable_thinking: true, + reasoning_effort: "xhigh", + }); + expect(await capturePayload(model)).toMatchObject({ enable_thinking: false }); + }); + it("preserves map-less GPT-5.6 Sol's existing effort behavior", async () => { const model = { id: "gpt-5.6-sol", diff --git a/packages/ai/test/openai-completions-tool-choice.test.ts b/packages/ai/test/openai-completions-tool-choice.test.ts index c9c245f40b..004c9278a8 100644 --- a/packages/ai/test/openai-completions-tool-choice.test.ts +++ b/packages/ai/test/openai-completions-tool-choice.test.ts @@ -1340,7 +1340,7 @@ describe("openai-completions tool_choice", () => { const model = getModel(provider, "mimo-v2.5-pro")!; expect(model.compat?.requiresReasoningContentOnAssistantMessages).toBe(true); expect(model.compat?.thinkingFormat).toBe("deepseek"); - expect(model.compat?.supportsDisabledThinking).toBe(false); + expect(model.compat?.supportsDisabledThinking).toBeUndefined(); expect(model.compat?.maxTokensField).toBeUndefined(); expect(model.compat?.supportsDeveloperRole).toBeUndefined(); } @@ -1413,7 +1413,7 @@ describe("openai-completions tool_choice", () => { const replayedAssistant = params.messages?.find((message) => message.role === "assistant"); expect(replayedAssistant).toMatchObject({ role: "assistant", reasoning_content: "" }); expect(params.thinking).toEqual({ type: "enabled" }); - expect(params.reasoning_effort).toBe("high"); + expect(params.reasoning_effort).toBeUndefined(); }); it("normalizes OpenCode Go reasoning deltas to reasoning_content for replay", async () => { From 6860669c8c5420a666d9bd6d63c3b56923adee74 Mon Sep 17 00:00:00 2001 From: effortprogrammer Date: Mon, 7 Sep 2026 01:21:56 +0900 Subject: [PATCH 5/8] docs(coding-agent): normalize merged tracker spacing --- packages/coding-agent/src/core/changes.md | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/coding-agent/src/core/changes.md b/packages/coding-agent/src/core/changes.md index d9e8f4be84..deda9b5242 100644 --- a/packages/coding-agent/src/core/changes.md +++ b/packages/coding-agent/src/core/changes.md @@ -4948,4 +4948,3 @@ unrelated fallback bus, silently disconnecting `pi.rpc.emit` on trust-requiring - LOW: `_handleRetryableError` fallback admission in packages/coding-agent/src/core/agent-session.ts. - From 3d887210a48b7b28e21966ab21c22fd230eaf535 Mon Sep 17 00:00:00 2001 From: effortprogrammer Date: Mon, 7 Sep 2026 22:47:25 +0900 Subject: [PATCH 6/8] fix(ai): correct Qwen3.8 Token Plan efforts --- .../scripts/scenarios/issue-891-qa.mjs | 77 ++++++++++++------- .../scripts/scenarios/issue-891-tui-qa.mjs | 40 +++++----- packages/ai/changes.md | 18 +++++ packages/ai/scripts/generate-models.ts | 18 ++--- packages/ai/src/providers/data/.manifest.json | 2 +- .../providers/data/alibaba-token-plan.json | 2 +- .../providers/data/qwen-token-plan-cn.json | 2 +- .../src/providers/data/qwen-token-plan.json | 2 +- .../issue-891-thinking-capabilities.test.ts | 37 ++++++--- ...openai-completions-thinking-matrix.test.ts | 54 +++++++++---- .../ai/test/qwen-token-plan-models.test.ts | 76 ++++++++++-------- 11 files changed, 208 insertions(+), 120 deletions(-) diff --git a/.agents/skills/senpi-qa/scripts/scenarios/issue-891-qa.mjs b/.agents/skills/senpi-qa/scripts/scenarios/issue-891-qa.mjs index aa93e93651..63b15327ea 100644 --- a/.agents/skills/senpi-qa/scripts/scenarios/issue-891-qa.mjs +++ b/.agents/skills/senpi-qa/scripts/scenarios/issue-891-qa.mjs @@ -23,8 +23,8 @@ import { TargetRpcClient } from "../lib/target-rpc-client.mjs"; const XIAOMI_PROVIDER = "xiaomi"; const XIAOMI_MODEL = "mimo-v2.5-pro"; -const QWEN_PROVIDER = "qwen-token-plan"; -const QWEN_MODEL = "qwen3.8-max"; +const ALIBABA_PROVIDER = "alibaba-token-plan"; +const ALIBABA_MODEL = "qwen3.8-max"; const ON_OFF_ERROR = `Reasoning effort is not configurable for ${XIAOMI_PROVIDER}/${XIAOMI_MODEL}; this model supports on/off only. Use /reasoning on or /reasoning off.`; function argument(name, fallback) { @@ -39,7 +39,7 @@ function writeOverrides(agentDir, baseUrl) { { providers: { [XIAOMI_PROVIDER]: { baseUrl, apiKey: "xiaomi-local-qa", api: "openai-completions" }, - [QWEN_PROVIDER]: { baseUrl, apiKey: "qwen-local-qa", api: "openai-completions" }, + [ALIBABA_PROVIDER]: { baseUrl, apiKey: "alibaba-local-qa", api: "openai-completions" }, }, }, null, @@ -62,7 +62,13 @@ async function main() { try { server = await startFakeModelServer({ - turns: [{ text: "OFF-WIRE" }, { text: "ON-WIRE" }, { text: "GRADED-WIRE" }], + turns: [ + { text: "OFF-WIRE" }, + { text: "ON-WIRE" }, + { text: "GRADED-LOW-WIRE" }, + { text: "GRADED-MEDIUM-WIRE" }, + { text: "GRADED-XHIGH-WIRE" }, + ], }); writeOverrides(box.agentDir, server.url); client = new TargetRpcClient({ env, cwd: box.cwd, targetRoot: repoRoot(), extraArgs: ["--multi-session"] }); @@ -117,36 +123,51 @@ async function main() { checks.ok("/efforts is refused for an on/off model", effortNotification.message.message === ON_OFF_ERROR); checks.ok("refused Xiaomi effort makes no provider request", server.requests.length === 2); - const openQwen = await client.send({ + const openAlibaba = await client.send({ type: "open_session", cwd: box.cwd, - provider: QWEN_PROVIDER, - modelId: QWEN_MODEL, + provider: ALIBABA_PROVIDER, + modelId: ALIBABA_MODEL, }); - const qwenSession = openQwen.data?.sessionId; - checks.ok("opens the built-in graded Qwen model", openQwen.success === true && !!qwenSession); - const sendQwen = (command) => client.send({ ...command, sessionId: qwenSession }); - - const gradedNotify = client.waitFor( - (event) => event.message.type === "extension_ui_request" && event.message.method === "notify" && event.message.sessionId === qwenSession, - ); - await sendQwen({ type: "prompt", message: "/efforts low" }); - const gradedNotification = await gradedNotify; - checks.ok("graded /efforts low is accepted", gradedNotification.message.message?.startsWith("Reasoning effort: low.")); - - const gradedEnd = client.waitFor((event) => event.message.type === "agent_end" && event.message.sessionId === qwenSession); - await sendQwen({ type: "prompt", message: "Return GRADED-WIRE." }); - await gradedEnd; - checks.ok( - "graded Qwen request preserves its documented low effort", - server.requests[2]?.body?.enable_thinking === true && server.requests[2]?.body?.reasoning_effort === "low", - JSON.stringify(server.requests[2]?.body), - ); + const alibabaSession = openAlibaba.data?.sessionId; + checks.ok("opens the built-in graded Alibaba model", openAlibaba.success === true && !!alibabaSession); + const sendAlibaba = (command) => client.send({ ...command, sessionId: alibabaSession }); + + for (const [effort, requestIndex] of [ + ["low", 2], + ["medium", 3], + ["xhigh", 4], + ]) { + const gradedNotify = client.waitFor( + (event) => + event.message.type === "extension_ui_request" && + event.message.method === "notify" && + event.message.sessionId === alibabaSession, + ); + await sendAlibaba({ type: "prompt", message: `/efforts ${effort}` }); + const gradedNotification = await gradedNotify; + checks.ok( + `graded /efforts ${effort} is accepted`, + gradedNotification.message.message === `Reasoning effort: ${effort}. Available: low, medium, xhigh.`, + ); + + const gradedEnd = client.waitFor( + (event) => event.message.type === "agent_end" && event.message.sessionId === alibabaSession, + ); + await sendAlibaba({ type: "prompt", message: `Return GRADED-${effort.toUpperCase()}-WIRE.` }); + await gradedEnd; + checks.ok( + `graded Alibaba request preserves its documented ${effort} effort`, + server.requests[requestIndex]?.body?.enable_thinking === true && + server.requests[requestIndex]?.body?.reasoning_effort === effort, + JSON.stringify(server.requests[requestIndex]?.body), + ); + } const settings = JSON.parse(readFileSync(join(box.agentDir, "settings.json"), "utf8")); checks.ok( - "valid graded effort persists in sandbox settings", - settings.modelThinkingLevels?.[`${QWEN_PROVIDER}/${QWEN_MODEL}`] === "low", + "valid graded Alibaba effort persists in sandbox settings", + settings.modelThinkingLevels?.[`${ALIBABA_PROVIDER}/${ALIBABA_MODEL}`] === "xhigh", JSON.stringify(settings.modelThinkingLevels), ); writeFileSync( diff --git a/.agents/skills/senpi-qa/scripts/scenarios/issue-891-tui-qa.mjs b/.agents/skills/senpi-qa/scripts/scenarios/issue-891-tui-qa.mjs index a69a777c6f..fb907bd176 100644 --- a/.agents/skills/senpi-qa/scripts/scenarios/issue-891-tui-qa.mjs +++ b/.agents/skills/senpi-qa/scripts/scenarios/issue-891-tui-qa.mjs @@ -3,7 +3,7 @@ * Native-PTY TUI proof for #891 reasoning capabilities. * * Drives the source CLI under Bun inside a sandbox. The built-in Xiaomi and - * Qwen model records remain authoritative; only their sandbox provider URLs + * Alibaba model records remain authoritative; only their sandbox provider URLs * and keys point at the local fake server. * * Usage: @@ -28,7 +28,7 @@ import { teardownPty } from "../lib/tui-resume-teardown.mjs"; const require = createRequire(import.meta.url); const BUN = process.env.SENPI_QA_BUN || "bun"; const XIAOMI = { provider: "xiaomi", model: "mimo-v2.5-pro" }; -const QWEN = { provider: "qwen-token-plan", model: "qwen3.8-max" }; +const ALIBABA = { provider: "alibaba-token-plan", model: "qwen3.8-max" }; const ROWS = 32; const BOOT_TIMEOUT_MS = 60_000; @@ -65,7 +65,7 @@ function writeOverrides(agentDir, baseUrl) { { providers: { [XIAOMI.provider]: { baseUrl, apiKey: "xiaomi-local-qa", api: "openai-completions" }, - [QWEN.provider]: { baseUrl, apiKey: "qwen-local-qa", api: "openai-completions" }, + [ALIBABA.provider]: { baseUrl, apiKey: "alibaba-local-qa", api: "openai-completions" }, }, }, null, @@ -268,27 +268,27 @@ async function main() { captureRun(xiaomi, actions); await closeTui(xiaomi, actions); - const qwen = await openTui({ root, box, bun, env, model: QWEN, actions, name: "qwen", runs }); - await resize(qwen, 120, actions); - await command(qwen, "/efforts low", "Reasoning effort: low. Available: low, medium, xhigh.", actions); - await resize(qwen, 80, actions); - await command(qwen, "/reasoning off", "Reasoning: off.", actions); - await command(qwen, "/reasoning on", "Reasoning: on (low).", actions); - captureRun(qwen, actions); - await closeTui(qwen, actions); + const alibaba = await openTui({ root, box, bun, env, model: ALIBABA, actions, name: "alibaba", runs }); + await resize(alibaba, 120, actions); + await command(alibaba, "/efforts low", "Reasoning effort: low. Available: low, medium, xhigh.", actions); + await resize(alibaba, 80, actions); + await command(alibaba, "/reasoning off", "Reasoning: off.", actions); + await command(alibaba, "/reasoning on", "Reasoning: on (low).", actions); + captureRun(alibaba, actions); + await closeTui(alibaba, actions); const settings = JSON.parse(readFileSync(join(box.agentDir, "settings.json"), "utf8")); checks.ok( - "graded effort persists in sandbox settings", - settings.modelThinkingLevels?.[`${QWEN.provider}/${QWEN.model}`] === "low", + "graded Alibaba effort persists in sandbox settings", + settings.modelThinkingLevels?.[`${ALIBABA.provider}/${ALIBABA.model}`] === "low", JSON.stringify(settings.modelThinkingLevels), ); - const qwenRestart = await openTui({ root, box, bun, env, model: QWEN, actions, name: "qwen-restart", runs }); - await resize(qwenRestart, 120, actions); - await command(qwenRestart, "/reasoning", "Reasoning: on (low).", actions); - captureRun(qwenRestart, actions); - await closeTui(qwenRestart, actions); + const alibabaRestart = await openTui({ root, box, bun, env, model: ALIBABA, actions, name: "alibaba-restart", runs }); + await resize(alibabaRestart, 120, actions); + await command(alibabaRestart, "/reasoning", "Reasoning: on (low).", actions); + captureRun(alibabaRestart, actions); + await closeTui(alibabaRestart, actions); const capturedRaw = (run) => run.stream.raw.slice(0, run.capture.rawCutoff); const capturedEvents = (run) => run.events.slice(0, run.capture.eventCutoff); @@ -296,8 +296,8 @@ async function main() { checks.ok("native PTY ran with Bun >=1.4", true, `${bun.command} ${bun.version}`); checks.ok("on/off model accepted /reasoning off and on", normalized(capturedRaw(xiaomi)).includes("Reasoning: off.") && normalized(capturedRaw(xiaomi)).includes("Reasoning: on (high).")); checks.ok("on/off model refused /efforts low", normalized(capturedRaw(xiaomi)).includes("this model supports on/off only.")); - checks.ok("graded model accepted /efforts low", normalized(capturedRaw(qwen)).includes("Reasoning effort: low. Available: low, medium, xhigh.")); - checks.ok("restart observed the persisted graded level", normalized(capturedRaw(qwenRestart)).includes("Reasoning: on (low).")); + checks.ok("graded Alibaba model accepted /efforts low", normalized(capturedRaw(alibaba)).includes("Reasoning effort: low. Available: low, medium, xhigh.")); + checks.ok("restart observed the persisted graded Alibaba level", normalized(capturedRaw(alibabaRestart)).includes("Reasoning: on (low).")); checks.ok( "captured ANSI prefixes equal ordered PTY output writes", runs.every((run) => capturedEvents(run).some((event) => event.type === "write") && replay(run) === capturedRaw(run)), diff --git a/packages/ai/changes.md b/packages/ai/changes.md index 88d8219308..1f75cd56d6 100644 --- a/packages/ai/changes.md +++ b/packages/ai/changes.md @@ -1,3 +1,21 @@ +## 2026-09-07 - Correct direct Qwen3.8 Token Plan effort controls (#891) + +### What changed + +- `packages/ai/scripts/generate-models.ts` applies the existing documented Qwen3.8 graded map to Flash, Max, and Max Preview on Alibaba Token Plan and to every present Qwen Token Plan Qwen3.8 row. Regenerated `alibaba-token-plan.json`, `qwen-token-plan.json`, `qwen-token-plan-cn.json`, and their manifest now change only the five previously incorrect maps. + +### Why + +- Alibaba's Qwen3.8 OpenAI-compatible API accepts `low`, `medium`, and `xhigh`; `minimal` aliases to low, `high`/`max` alias to xhigh, and off must send only `enable_thinking: false`. The previous catalog selected toggle-only or high/max metadata for five direct rows, causing the existing serializer to clamp requests to the wrong wire value. + +### Why an extension could not handle it + +- Built-in model capabilities are generated and loaded before extension hooks run, while the existing OpenAI Completions serializer consumes the generated thinking map to construct the request. + +### Expected merge conflict zones + +- LOW: Qwen/Alibaba thinking-map selection in `packages/ai/scripts/generate-models.ts` and the three regenerated provider data files. + ## 2026-09-07 - One context window for the whole GPT-6 Astra series ### What changed diff --git a/packages/ai/scripts/generate-models.ts b/packages/ai/scripts/generate-models.ts index ea58d6c6ed..f87d6bfb23 100644 --- a/packages/ai/scripts/generate-models.ts +++ b/packages/ai/scripts/generate-models.ts @@ -298,9 +298,6 @@ const ALIBABA_TOKEN_PLAN_ON_OFF_MODEL_IDS = new Set([ "qwen3.6-plus", "qwen3.7-max", "qwen3.7-plus", - "qwen3.8-flash", - "qwen3.8-max", - "qwen3.8-max-preview", ]); const MOONSHOT_ON_OFF_MODEL_IDS = new Set(["kimi-k2-thinking", "kimi-k2-thinking-turbo", "kimi-k2.5", "kimi-k2.6"]); const XIAOMI_ON_OFF_MODEL_IDS = new Set(["mimo-v2.5", "mimo-v2.5-pro", "mimo-v2.5-pro-ultraspeed"]); @@ -351,6 +348,7 @@ const QWEN_TOKEN_PLAN_QWEN38_THINKING_LEVEL_MAP = { xhigh: "xhigh", max: null, } as const; +const QWEN38_MODEL_IDS = new Set(["qwen3.8-flash", "qwen3.8-max", "qwen3.8-max-preview"]); const QWEN_TOKEN_PLAN_REASONING_EFFORT_UNSUPPORTED_MODEL_IDS = new Set([ "MiniMax-M2.5", "deepseek-v3.2", @@ -2670,7 +2668,7 @@ async function loadModelsDevData(): Promise[]> { ...(supportsReasoningEffort ? { thinkingLevelMap: - modelId === "qwen3.8-max" + QWEN38_MODEL_IDS.has(modelId) ? QWEN_TOKEN_PLAN_QWEN38_THINKING_LEVEL_MAP : QWEN_TOKEN_PLAN_HIGH_MAX_THINKING_LEVEL_MAP, } @@ -2724,11 +2722,13 @@ async function loadModelsDevData(): Promise[]> { } const thinkingLevelMap = - modelId === "kimi-k2.7-code" - ? ALWAYS_ON_THINKING_LEVEL_MAP - : ALIBABA_TOKEN_PLAN_ON_OFF_MODEL_IDS.has(modelId) - ? ON_OFF_THINKING_LEVEL_MAP - : undefined; + QWEN38_MODEL_IDS.has(modelId) + ? QWEN_TOKEN_PLAN_QWEN38_THINKING_LEVEL_MAP + : modelId === "kimi-k2.7-code" + ? ALWAYS_ON_THINKING_LEVEL_MAP + : ALIBABA_TOKEN_PLAN_ON_OFF_MODEL_IDS.has(modelId) + ? ON_OFF_THINKING_LEVEL_MAP + : undefined; models.push({ id: modelId, name: m.name || modelId, diff --git a/packages/ai/src/providers/data/.manifest.json b/packages/ai/src/providers/data/.manifest.json index 40613ee06d..baf7a62913 100644 --- a/packages/ai/src/providers/data/.manifest.json +++ b/packages/ai/src/providers/data/.manifest.json @@ -1 +1 @@ -{"schemaVersion":3,"generatedAt":"2026-09-07T05:14:51.970Z","structureHash":"0df417387a91858721a7ba94c027b8e9f68edc0e934ee8c397db4e6c72ab27a3","files":{"alibaba-token-plan.json":"59a7ab84ef3b0f241ea15bb091390652570b96a0ce2f6619724fbe5a629db969","amazon-bedrock.json":"7f870508a8a7afecf85037af6242762ebdc7774fe29061b9b39d7754f528ec1d","ant-ling.json":"4979fe79d99ed97382d7ce40170c6132e932e77906de1eb54464c042e7d63633","anthropic.json":"e9d883ee35d94dba963320b5496bd7dd368d226cbafcf134bfec66a0a24b3b7f","azure-openai-responses.json":"eebbe078feec3565c7457c6b6c065d3d8931b20b168ea4ffb31a33e93066e9ee","baseten.json":"8f7430af599249a01f446b5b717856dd58d484e76f5dbccf86c0ec7b6661468d","cerebras.json":"9eaa554e1b02f3665f8f63e6432d253bf81351af7c72001054dd8108aa528a52","cloudflare-ai-gateway.json":"244d98311e81b5f33fa736688d135b29add6a8acee466aa3a5988ac5b022d1eb","cloudflare-workers-ai.json":"07ef63208ff7517fd1a80962f18143e21de399640423329490b157f459ccf995","deepseek.json":"e3106724723fd82d48a3ff685da9908a3a7b7b4fd84cc3cfe97a6a23067b6029","fireworks.json":"0b480dcad5ff4072ef299d887f27ed3ed96e2246aa57ffa3bac02ecee9aee331","github-copilot.json":"26cd0af57e17caf7fbd9c0b34da4653e2e29f1ba5a00c1ff996d2549f8b74c05","google-vertex.json":"e1631109172dc1f7d7977570420a5bb86258bdd1088427e244a2c51545c4f24d","google.json":"7619bf03edd2a7acb06a2274a14b13c3a61354288abe029a758401d4de36a8fd","groq.json":"e4728fd72e358cd8f25e9a518e9b49a521ef44523d3debe38a7db9e0663c4077","huggingface.json":"3a004b58d3f801077a81f5be5cdf40c59ce1070c9c68f279e8d6c8902d441b19","kimi-coding.json":"88150f8970f83e17968b02f3b33fac803b96ebf1474e76437689b7d0f1b69363","minimax-cn.json":"65d37e55a6d9585855f94b3fb7739308d107fe248ebd9e1001d1c5d4606ad2c4","minimax.json":"c7dc5765995ae77242916430929c7cc9a782589f7e483e13f7e01663190d028e","mistral.json":"e3a109306644bf2f2fa38fece50b2d3ce1dbe3b87b1f1b9e2d70cce7eb5c0ea1","moonshotai-cn.json":"5152324ad835fe0c42182015dee23ec7896c0fd7c8bd24591d6dc63c10145ab4","moonshotai.json":"f78056e7fcf35b0284bcd5b094b1347f1a65a53e825936f8144c4ce081558f1e","nvidia.json":"7e5d6e027f61e36f8d806d0af311cda93a40e75920b8a0645eddf0ab9f058033","openai-codex.json":"b8f275f5b501456000f6445398faac2189292378b837beeddcdbe1c42a319d22","openai.json":"203a1d6bf61178268edf3d3f0ad4a6408eded401c4472bda4ac0ec73142f38ce","opencode-go.json":"a96abd0cb6484e94136252d681cece347d81cc992122bb2330fa96c661e2e6ad","opencode.json":"9dbb27a6775b06707af80736d0241e22be825d5d4c53750346461502df84dbaa","opengateway.json":"b4a6a22444054baad8c8ccffa23465e7805a292e942865385d8eef1925254fc5","openrouter.json":"8fa8cfee586450ac51b44149ee681fd2f0f38e73c5dfd9e707c666e732699c7f","qwen-token-plan-cn.json":"a3addc5bd8de66c5d676bd11a01442515ea8c786a952f43b885e653950bed3f2","qwen-token-plan-individual.json":"86d1dd467695c6df282c8e2b4384d23323d622a96f0358840eb09e141d0e9da4","qwen-token-plan.json":"37e321a2e0b912d8e9c5cd13dc10a5b3b0638d764f7bb20c3aaab262ee1078ea","together.json":"6010980c9b0af72c60965ae325dbdb21e67c91844a7f7f6f7d71d363f1325f56","vercel-ai-gateway.json":"cd5c5c7e86635a152596514eac68f045e4bd48f529068005d5424196a32c73fe","xai.json":"9973aae022723732b8a7ea12107e6fb8b3f1d0e087ec6bbc2ee18f0820595e19","xiaomi-token-plan-ams.json":"66190c086ddc6d72afae5dc51027ac385ff7bffa3a565fa4c41ac254ca043b55","xiaomi-token-plan-cn.json":"a0e81b80e7bb582a779f9dcea04979eae80b2405bb9f7c0a432a774f908524f1","xiaomi-token-plan-sgp.json":"a70aeb60f510c9116ccec615314032b7a3a2265b1ff93a4fce48e2b4a92ec208","xiaomi.json":"957b4a5fb9d4e63b96f75f33167287c541332b79df2e3a3ff22c911463e12ee2","zai-coding-cn.json":"6b396a967808dd7f7e800990b3d69f04adfd2a1811b8328d1fe7275ae758153d","zai.json":"3a5dd70915c46c676a17362f9f0d018c239a1f2555ea675b682890e3417ebff3"}} +{"schemaVersion":3,"generatedAt":"2026-09-07T13:39:30.141Z","structureHash":"0df417387a91858721a7ba94c027b8e9f68edc0e934ee8c397db4e6c72ab27a3","files":{"alibaba-token-plan.json":"0225691c207792eadd2d860425f9926976f9897fa82cadb49c266155b56b7868","amazon-bedrock.json":"7f870508a8a7afecf85037af6242762ebdc7774fe29061b9b39d7754f528ec1d","ant-ling.json":"4979fe79d99ed97382d7ce40170c6132e932e77906de1eb54464c042e7d63633","anthropic.json":"e9d883ee35d94dba963320b5496bd7dd368d226cbafcf134bfec66a0a24b3b7f","azure-openai-responses.json":"eebbe078feec3565c7457c6b6c065d3d8931b20b168ea4ffb31a33e93066e9ee","baseten.json":"8f7430af599249a01f446b5b717856dd58d484e76f5dbccf86c0ec7b6661468d","cerebras.json":"9eaa554e1b02f3665f8f63e6432d253bf81351af7c72001054dd8108aa528a52","cloudflare-ai-gateway.json":"244d98311e81b5f33fa736688d135b29add6a8acee466aa3a5988ac5b022d1eb","cloudflare-workers-ai.json":"07ef63208ff7517fd1a80962f18143e21de399640423329490b157f459ccf995","deepseek.json":"e3106724723fd82d48a3ff685da9908a3a7b7b4fd84cc3cfe97a6a23067b6029","fireworks.json":"0b480dcad5ff4072ef299d887f27ed3ed96e2246aa57ffa3bac02ecee9aee331","github-copilot.json":"26cd0af57e17caf7fbd9c0b34da4653e2e29f1ba5a00c1ff996d2549f8b74c05","google-vertex.json":"e1631109172dc1f7d7977570420a5bb86258bdd1088427e244a2c51545c4f24d","google.json":"7619bf03edd2a7acb06a2274a14b13c3a61354288abe029a758401d4de36a8fd","groq.json":"e4728fd72e358cd8f25e9a518e9b49a521ef44523d3debe38a7db9e0663c4077","huggingface.json":"3a004b58d3f801077a81f5be5cdf40c59ce1070c9c68f279e8d6c8902d441b19","kimi-coding.json":"88150f8970f83e17968b02f3b33fac803b96ebf1474e76437689b7d0f1b69363","minimax-cn.json":"65d37e55a6d9585855f94b3fb7739308d107fe248ebd9e1001d1c5d4606ad2c4","minimax.json":"c7dc5765995ae77242916430929c7cc9a782589f7e483e13f7e01663190d028e","mistral.json":"e3a109306644bf2f2fa38fece50b2d3ce1dbe3b87b1f1b9e2d70cce7eb5c0ea1","moonshotai-cn.json":"5152324ad835fe0c42182015dee23ec7896c0fd7c8bd24591d6dc63c10145ab4","moonshotai.json":"f78056e7fcf35b0284bcd5b094b1347f1a65a53e825936f8144c4ce081558f1e","nvidia.json":"7e5d6e027f61e36f8d806d0af311cda93a40e75920b8a0645eddf0ab9f058033","openai-codex.json":"b8f275f5b501456000f6445398faac2189292378b837beeddcdbe1c42a319d22","openai.json":"203a1d6bf61178268edf3d3f0ad4a6408eded401c4472bda4ac0ec73142f38ce","opencode-go.json":"a96abd0cb6484e94136252d681cece347d81cc992122bb2330fa96c661e2e6ad","opencode.json":"9dbb27a6775b06707af80736d0241e22be825d5d4c53750346461502df84dbaa","opengateway.json":"b4a6a22444054baad8c8ccffa23465e7805a292e942865385d8eef1925254fc5","openrouter.json":"8fa8cfee586450ac51b44149ee681fd2f0f38e73c5dfd9e707c666e732699c7f","qwen-token-plan-cn.json":"2359af6615b9bfbb44e75e07744b36b4f1de0bb5291fb8ecdb70fadfe0cdf436","qwen-token-plan-individual.json":"86d1dd467695c6df282c8e2b4384d23323d622a96f0358840eb09e141d0e9da4","qwen-token-plan.json":"aae84ce4254599d2217930a8c70ed40fecab952a8338c7c06fffae727dc0bfaf","together.json":"6010980c9b0af72c60965ae325dbdb21e67c91844a7f7f6f7d71d363f1325f56","vercel-ai-gateway.json":"cd5c5c7e86635a152596514eac68f045e4bd48f529068005d5424196a32c73fe","xai.json":"9973aae022723732b8a7ea12107e6fb8b3f1d0e087ec6bbc2ee18f0820595e19","xiaomi-token-plan-ams.json":"66190c086ddc6d72afae5dc51027ac385ff7bffa3a565fa4c41ac254ca043b55","xiaomi-token-plan-cn.json":"a0e81b80e7bb582a779f9dcea04979eae80b2405bb9f7c0a432a774f908524f1","xiaomi-token-plan-sgp.json":"a70aeb60f510c9116ccec615314032b7a3a2265b1ff93a4fce48e2b4a92ec208","xiaomi.json":"957b4a5fb9d4e63b96f75f33167287c541332b79df2e3a3ff22c911463e12ee2","zai-coding-cn.json":"6b396a967808dd7f7e800990b3d69f04adfd2a1811b8328d1fe7275ae758153d","zai.json":"3a5dd70915c46c676a17362f9f0d018c239a1f2555ea675b682890e3417ebff3"}} diff --git a/packages/ai/src/providers/data/alibaba-token-plan.json b/packages/ai/src/providers/data/alibaba-token-plan.json index 8c5785da82..58d544e751 100644 --- a/packages/ai/src/providers/data/alibaba-token-plan.json +++ b/packages/ai/src/providers/data/alibaba-token-plan.json @@ -1 +1 @@ -{"openai-completions":{"MiniMax-M2.5":{"id":"MiniMax-M2.5","name":"MiniMax-M2.5","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":196608,"maxTokens":32768},"deepseek-v3.2":{"id":"deepseek-v3.2","name":"DeepSeek V3.2","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":131072,"maxTokens":65536},"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4-flash-0731":{"id":"deepseek-v4-flash-0731","name":"DeepSeek V4 Flash 0731","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4-pro-0813":{"id":"deepseek-v4-pro-0813","name":"DeepSeek V4 Pro 0813","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"glm-5":{"id":"glm-5","name":"GLM-5","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":16384},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":128000},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":98304},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"qwen3.6-flash":{"id":"qwen3.6-flash","name":"Qwen3.6 Flash","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-max-preview":{"id":"qwen3.8-max-preview","name":"Qwen3.8 Max Preview","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072}}} +{"openai-completions":{"MiniMax-M2.5":{"id":"MiniMax-M2.5","name":"MiniMax-M2.5","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":196608,"maxTokens":32768},"deepseek-v3.2":{"id":"deepseek-v3.2","name":"DeepSeek V3.2","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":131072,"maxTokens":65536},"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4-flash-0731":{"id":"deepseek-v4-flash-0731","name":"DeepSeek V4 Flash 0731","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4-pro-0813":{"id":"deepseek-v4-pro-0813","name":"DeepSeek V4 Pro 0813","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"glm-5":{"id":"glm-5","name":"GLM-5","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":16384},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":128000},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":98304},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"deepseek","supportsReasoningEffort":false},"reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"qwen3.6-flash":{"id":"qwen3.6-flash","name":"Qwen3.6 Flash","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-max-preview":{"id":"qwen3.8-max-preview","name":"Qwen3.8 Max Preview","api":"openai-completions","provider":"alibaba-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","thinkingFormat":"qwen"},"reasoning":true,"thinkingLevelMap":{"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null},"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072}}} diff --git a/packages/ai/src/providers/data/qwen-token-plan-cn.json b/packages/ai/src/providers/data/qwen-token-plan-cn.json index 46c44d2fb4..abedae8737 100644 --- a/packages/ai/src/providers/data/qwen-token-plan-cn.json +++ b/packages/ai/src/providers/data/qwen-token-plan-cn.json @@ -1 +1 @@ -{"openai-completions":{"MiniMax-M2.5":{"id":"MiniMax-M2.5","name":"MiniMax-M2.5","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":196608,"maxTokens":32768},"deepseek-v3.2":{"id":"deepseek-v3.2","name":"DeepSeek V3.2","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":131072,"maxTokens":65536},"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-flash-0731":{"id":"deepseek-v4-flash-0731","name":"DeepSeek V4 Flash 0731","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro-0813":{"id":"deepseek-v4-pro-0813","name":"DeepSeek V4 Pro 0813","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"glm-5":{"id":"glm-5","name":"GLM-5","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":16384},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":128000},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":98304},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"qwen3.6-flash":{"id":"qwen3.6-flash","name":"Qwen3.6 Flash","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072}}} +{"openai-completions":{"MiniMax-M2.5":{"id":"MiniMax-M2.5","name":"MiniMax-M2.5","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":196608,"maxTokens":32768},"deepseek-v3.2":{"id":"deepseek-v3.2","name":"DeepSeek V3.2","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":131072,"maxTokens":65536},"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-flash-0731":{"id":"deepseek-v4-flash-0731","name":"DeepSeek V4 Flash 0731","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro-0813":{"id":"deepseek-v4-pro-0813","name":"DeepSeek V4 Pro 0813","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"glm-5":{"id":"glm-5","name":"GLM-5","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":16384},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":128000},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":98304},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"qwen3.6-flash":{"id":"qwen3.6-flash","name":"Qwen3.6 Flash","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"qwen-token-plan-cn","baseUrl":"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072}}} diff --git a/packages/ai/src/providers/data/qwen-token-plan.json b/packages/ai/src/providers/data/qwen-token-plan.json index 09358d31f3..1f57777aa9 100644 --- a/packages/ai/src/providers/data/qwen-token-plan.json +++ b/packages/ai/src/providers/data/qwen-token-plan.json @@ -1 +1 @@ -{"openai-completions":{"MiniMax-M2.5":{"id":"MiniMax-M2.5","name":"MiniMax-M2.5","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":196608,"maxTokens":32768},"deepseek-v3.2":{"id":"deepseek-v3.2","name":"DeepSeek V3.2","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":131072,"maxTokens":65536},"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-flash-0731":{"id":"deepseek-v4-flash-0731","name":"DeepSeek V4 Flash 0731","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro-0813":{"id":"deepseek-v4-pro-0813","name":"DeepSeek V4 Pro 0813","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"glm-5":{"id":"glm-5","name":"GLM-5","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":16384},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":128000},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":98304},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"qwen3.6-flash":{"id":"qwen3.6-flash","name":"Qwen3.6 Flash","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072}}} +{"openai-completions":{"MiniMax-M2.5":{"id":"MiniMax-M2.5","name":"MiniMax-M2.5","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":196608,"maxTokens":32768},"deepseek-v3.2":{"id":"deepseek-v3.2","name":"DeepSeek V3.2","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":131072,"maxTokens":65536},"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-flash-0731":{"id":"deepseek-v4-flash-0731","name":"DeepSeek V4 Flash 0731","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"deepseek-v4-pro-0813":{"id":"deepseek-v4-pro-0813","name":"DeepSeek V4 Pro 0813","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":384000},"glm-5":{"id":"glm-5","name":"GLM-5","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":16384},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":202752,"maxTokens":128000},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"kimi-k2.5":{"id":"kimi-k2.5","name":"Kimi K2.5","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":98304},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":262144,"maxTokens":262144},"qwen3.6-flash":{"id":"qwen3.6-flash","name":"Qwen3.6 Flash","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":false},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"xhigh":null,"max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"qwen-token-plan","baseUrl":"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1","compat":{"thinkingFormat":"qwen","supportsDeveloperRole":false,"supportsStore":false,"supportsReasoningEffort":true},"thinkingLevelMap":{"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072}}} diff --git a/packages/ai/test/issue-891-thinking-capabilities.test.ts b/packages/ai/test/issue-891-thinking-capabilities.test.ts index 40a3664078..1994f1ff2f 100644 --- a/packages/ai/test/issue-891-thinking-capabilities.test.ts +++ b/packages/ai/test/issue-891-thinking-capabilities.test.ts @@ -1,15 +1,27 @@ import { describe, expect, it } from "vitest"; -import { getModel, getModels, getSupportedThinkingLevels } from "../src/compat.ts"; +import { getModels, getSupportedThinkingLevels } from "../src/compat.ts"; import type { ModelThinkingLevel } from "../src/types.ts"; type CapabilityCase = { - provider: Parameters[0]; + provider: Parameters[0]; id: string; levels: ModelThinkingLevel[]; }; const ON_OFF: ModelThinkingLevel[] = ["off", "high"]; const ALWAYS_ON: ModelThinkingLevel[] = ["high"]; +const QWEN38_GRADED: ModelThinkingLevel[] = ["off", "low", "medium", "xhigh"]; + +const DIRECT_QWEN38_CAPABILITY_CASES: CapabilityCase[] = [ + { provider: "alibaba-token-plan", id: "qwen3.8-flash", levels: QWEN38_GRADED }, + { provider: "alibaba-token-plan", id: "qwen3.8-max", levels: QWEN38_GRADED }, + { provider: "alibaba-token-plan", id: "qwen3.8-max-preview", levels: QWEN38_GRADED }, + { provider: "qwen-token-plan", id: "qwen3.8-flash", levels: QWEN38_GRADED }, + { provider: "qwen-token-plan", id: "qwen3.8-max", levels: QWEN38_GRADED }, + { provider: "qwen-token-plan-cn", id: "qwen3.8-flash", levels: QWEN38_GRADED }, + { provider: "qwen-token-plan-cn", id: "qwen3.8-max", levels: QWEN38_GRADED }, + { provider: "qwen-token-plan-individual", id: "qwen3.8-max", levels: QWEN38_GRADED }, +]; // #891: Every current map-less reasoning row must have an explicit catalog capability. // This is intentionally a complete current-row table: a removed or renamed row fails instead @@ -23,9 +35,9 @@ const CAPABILITY_CASES: CapabilityCase[] = [ { provider: "alibaba-token-plan", id: "qwen3.6-plus", levels: ON_OFF }, { provider: "alibaba-token-plan", id: "qwen3.7-max", levels: ON_OFF }, { provider: "alibaba-token-plan", id: "qwen3.7-plus", levels: ON_OFF }, - { provider: "alibaba-token-plan", id: "qwen3.8-flash", levels: ON_OFF }, - { provider: "alibaba-token-plan", id: "qwen3.8-max", levels: ON_OFF }, - { provider: "alibaba-token-plan", id: "qwen3.8-max-preview", levels: ON_OFF }, + { provider: "alibaba-token-plan", id: "qwen3.8-flash", levels: QWEN38_GRADED }, + { provider: "alibaba-token-plan", id: "qwen3.8-max", levels: QWEN38_GRADED }, + { provider: "alibaba-token-plan", id: "qwen3.8-max-preview", levels: QWEN38_GRADED }, ...(["qwen-token-plan", "qwen-token-plan-cn"] as const).flatMap((provider) => [ { provider, id: "MiniMax-M2.5", levels: ON_OFF }, { provider, id: "deepseek-v3.2", levels: ON_OFF }, @@ -83,11 +95,14 @@ describe("issue #891 generated thinking capabilities", () => { expect(getSupportedThinkingLevels(model)).toEqual(levels); }); - it("keeps documented Qwen reasoning effort controls graded", () => { - const model = getModel("qwen-token-plan", "qwen3.8-max"); + it.each(DIRECT_QWEN38_CAPABILITY_CASES)( + "keeps documented Qwen3.8 reasoning effort controls graded for $provider/$id", + ({ provider, id, levels }) => { + const model = getModels(provider).find((candidate) => candidate.id === id); - expect(model).toBeDefined(); - if (!model) throw new Error("missing qwen-token-plan/qwen3.8-max"); - expect(getSupportedThinkingLevels(model)).toEqual(["off", "low", "medium", "xhigh"]); - }); + expect(model).toBeDefined(); + if (!model) throw new Error(`missing ${provider}/${id}`); + expect(getSupportedThinkingLevels(model)).toEqual(levels); + }, + ); }); diff --git a/packages/ai/test/openai-completions-thinking-matrix.test.ts b/packages/ai/test/openai-completions-thinking-matrix.test.ts index a327e1e088..24113bd117 100644 --- a/packages/ai/test/openai-completions-thinking-matrix.test.ts +++ b/packages/ai/test/openai-completions-thinking-matrix.test.ts @@ -15,6 +15,27 @@ const context: Context = { messages: [{ role: "user", content: "Hello", timestamp: Date.now() }], }; +const DIRECT_QWEN38_MODEL_CASES = [ + { provider: "alibaba-token-plan", id: "qwen3.8-flash" }, + { provider: "alibaba-token-plan", id: "qwen3.8-max" }, + { provider: "alibaba-token-plan", id: "qwen3.8-max-preview" }, + { provider: "qwen-token-plan", id: "qwen3.8-flash" }, + { provider: "qwen-token-plan", id: "qwen3.8-max" }, + { provider: "qwen-token-plan-cn", id: "qwen3.8-flash" }, + { provider: "qwen-token-plan-cn", id: "qwen3.8-max" }, + { provider: "qwen-token-plan-individual", id: "qwen3.8-max" }, +] as const; + +const QWEN38_SELECTOR_CASES = [ + { reasoning: "off", expected: { enable_thinking: false } }, + { reasoning: "minimal", expected: { enable_thinking: true, reasoning_effort: "low" } }, + { reasoning: "low", expected: { enable_thinking: true, reasoning_effort: "low" } }, + { reasoning: "medium", expected: { enable_thinking: true, reasoning_effort: "medium" } }, + { reasoning: "high", expected: { enable_thinking: true, reasoning_effort: "xhigh" } }, + { reasoning: "xhigh", expected: { enable_thinking: true, reasoning_effort: "xhigh" } }, + { reasoning: "max", expected: { enable_thinking: true, reasoning_effort: "xhigh" } }, +] as const; + async function capturePayload( model: Model<"openai-completions">, reasoning?: SimpleStreamOptions["reasoning"], @@ -240,23 +261,22 @@ describe("OpenAI Completions thinking ladder fallbacks", () => { expect(await capturePayload(model)).toMatchObject(off); }); - it("keeps Qwen's documented graded control distinct on the wire", async () => { - const model = getOpenAICompletionsModel("qwen-token-plan", "qwen3.8-max"); - - expect(await captureDirectPayload(model, "low")).toMatchObject({ - enable_thinking: true, - reasoning_effort: "low", - }); - expect(await captureDirectPayload(model, "medium")).toMatchObject({ - enable_thinking: true, - reasoning_effort: "medium", - }); - expect(await captureDirectPayload(model, "xhigh")).toMatchObject({ - enable_thinking: true, - reasoning_effort: "xhigh", - }); - expect(await capturePayload(model)).toMatchObject({ enable_thinking: false }); - }); + it.each(DIRECT_QWEN38_MODEL_CASES)( + "serializes Qwen3.8's documented selector ladder for $provider/$id", + async ({ provider, id }) => { + const model = getOpenAICompletionsModel(provider, id); + + for (const { reasoning, expected } of QWEN38_SELECTOR_CASES) { + const payload = await capturePayload(model, reasoning === "off" ? undefined : reasoning); + + expect(payload).toMatchObject(expected); + expect(payload).not.toHaveProperty("thinking_budget"); + if (reasoning === "off") { + expect(payload).not.toHaveProperty("reasoning_effort"); + } + } + }, + ); it("preserves map-less GPT-5.6 Sol's existing effort behavior", async () => { const model = { diff --git a/packages/ai/test/qwen-token-plan-models.test.ts b/packages/ai/test/qwen-token-plan-models.test.ts index d1dcef09c8..6ad5338cd5 100644 --- a/packages/ai/test/qwen-token-plan-models.test.ts +++ b/packages/ai/test/qwen-token-plan-models.test.ts @@ -109,6 +109,14 @@ const QWEN_REASONING_EFFORT_MODEL_CASES: QwenTokenPlanModelCase[] = [ })), ]; +const QWEN38_THINKING_MODEL_CASES: QwenTokenPlanModelCase[] = [ + { provider: "qwen-token-plan", modelId: "qwen3.8-flash" }, + { provider: "qwen-token-plan", modelId: "qwen3.8-max" }, + { provider: "qwen-token-plan-cn", modelId: "qwen3.8-flash" }, + { provider: "qwen-token-plan-cn", modelId: "qwen3.8-max" }, + { provider: "qwen-token-plan-individual", modelId: "qwen3.8-max" }, +]; + describe("Qwen Token Plan models", () => { it("exposes exactly the documented Individual text models", () => { const modelIds = getModels("qwen-token-plan-individual") @@ -190,12 +198,12 @@ describe("Qwen Token Plan models", () => { }, ); - it.each(["qwen-token-plan", "qwen-token-plan-cn", "qwen-token-plan-individual"] as const)( - "exposes qwen3.8 reasoning_effort levels on %s", - (provider) => { - const model = getModels(provider).find((candidate) => candidate.id === "qwen3.8-max"); + it.each(QWEN38_THINKING_MODEL_CASES)( + "exposes qwen3.8 reasoning_effort levels on $provider/$modelId", + ({ provider, modelId }) => { + const model = getModels(provider).find((candidate) => candidate.id === modelId); expect(model).toBeDefined(); - if (!model) throw new Error(`Missing model: ${provider}/qwen3.8-max`); + if (!model) throw new Error(`Missing model: ${provider}/${modelId}`); expect(model.thinkingLevelMap).toMatchObject({ minimal: null, @@ -248,37 +256,43 @@ describe("Qwen Token Plan models", () => { }, ); - it.each(["qwen-token-plan", "qwen-token-plan-cn", "qwen-token-plan-individual"] as const)( - "sends qwen3.8 max reasoning_effort on %s", - async (provider) => { - const model = getModels(provider).find((candidate) => candidate.id === "qwen3.8-max"); + it.each(QWEN38_THINKING_MODEL_CASES)( + "sends qwen3.8 reasoning_effort on $provider/$modelId", + async ({ provider, modelId }) => { + const model = getModels(provider).find((candidate) => candidate.id === modelId); expect(model).toBeDefined(); - if (!model) throw new Error(`Missing model: ${provider}/qwen3.8-max`); + if (!model) throw new Error(`Missing model: ${provider}/${modelId}`); - let payload: unknown; - await streamSimple( - model, - { - messages: [ - { - role: "user", - content: "Hi", - timestamp: Date.now(), + for (const [reasoning, reasoningEffort] of [ + ["low", "low"], + ["medium", "medium"], + ["xhigh", "xhigh"], + ] as const) { + let payload: unknown; + await streamSimple( + model, + { + messages: [ + { + role: "user", + content: "Hi", + timestamp: Date.now(), + }, + ], + }, + { + apiKey: "test", + reasoning, + onPayload: (params) => { + payload = params; }, - ], - }, - { - apiKey: "test", - reasoning: "xhigh", - onPayload: (params) => { - payload = params; }, - }, - ).result(); + ).result(); - expect(payload).toHaveProperty("enable_thinking", true); - expect(payload).toHaveProperty("reasoning_effort", "xhigh"); - expect(payload).not.toHaveProperty("thinking"); + expect(payload).toHaveProperty("enable_thinking", true); + expect(payload).toHaveProperty("reasoning_effort", reasoningEffort); + expect(payload).not.toHaveProperty("thinking"); + } }, ); }); From 8bc0aabeba5f46c414e7f93d4a994e093ff41f90 Mon Sep 17 00:00:00 2001 From: effortprogrammer Date: Mon, 7 Sep 2026 23:17:39 +0900 Subject: [PATCH 7/8] test(coding-agent): release inspector connections on resume Close each debugger only after its own resume acknowledgement and preserve the two-session fixed-port handoff assertions. Include the erasable-syntax correction in this verified increment. --- .../inspector-endpoint-handoff.test.ts | 98 +++++++++++++++++-- 1 file changed, 91 insertions(+), 7 deletions(-) diff --git a/packages/coding-agent/test/suite/regressions/inspector-endpoint-handoff.test.ts b/packages/coding-agent/test/suite/regressions/inspector-endpoint-handoff.test.ts index 22d5f0c86d..b3b55d4249 100644 --- a/packages/coding-agent/test/suite/regressions/inspector-endpoint-handoff.test.ts +++ b/packages/coding-agent/test/suite/regressions/inspector-endpoint-handoff.test.ts @@ -1,6 +1,7 @@ import { type ChildProcessByStdio, spawn, spawnSync } from "node:child_process"; +import { EventEmitter } from "node:events"; import { createServer } from "node:net"; -import type { Readable } from "node:stream"; +import { PassThrough, type Readable } from "node:stream"; import { fileURLToPath } from "node:url"; import { expect, test } from "vitest"; @@ -19,6 +20,42 @@ interface RunResult { readonly states: readonly InspectorState[]; } +class FakeInspectorSocket extends EventTarget { + static readonly CONNECTING = 0; + static readonly OPEN = 1; + static readonly CLOSED = 3; + static instances: FakeInspectorSocket[] = []; + + readyState = FakeInspectorSocket.CONNECTING; + closeCalls = 0; + readonly sent: string[] = []; + readonly url: string; + + constructor(url: string) { + super(); + this.url = url; + FakeInspectorSocket.instances.push(this); + } + + send(message: string): void { + this.sent.push(message); + } + + close(): void { + this.closeCalls += 1; + this.readyState = FakeInspectorSocket.CLOSED; + } + + open(): void { + this.readyState = FakeInspectorSocket.OPEN; + this.dispatchEvent(new Event("open")); + } + + receive(message: object): void { + this.dispatchEvent(new MessageEvent("message", { data: JSON.stringify(message) })); + } +} + function findFreePort(): Promise { return new Promise((resolve, reject) => { const server = createServer(); @@ -105,6 +142,7 @@ function attachDebugger(url: string, sockets: WebSocket[], states: InspectorStat } if (message.id === 3) { state.resumed = true; + socket.close(); } }); socket.addEventListener("error", () => { @@ -126,7 +164,6 @@ function driveRun(child: ChildProcessByStdio): Promise timer.unref(); child.stdout.on("data", (chunk: Buffer) => { stdout += chunk.toString(); - if (stdout.includes("Usage:")) for (const socket of sockets) socket.close(); }); child.stderr.on("data", (chunk: Buffer) => { stderr += chunk.toString(); @@ -136,11 +173,6 @@ function driveRun(child: ChildProcessByStdio): Promise attached.add(url); attachDebugger(url, sockets, states); } - if (stderr.includes("Waiting for the debugger to disconnect")) { - for (const socket of sockets) { - if (socket.readyState === WebSocket.OPEN) socket.close(); - } - } }); child.once("error", (error) => { clearTimeout(timer); @@ -176,6 +208,58 @@ async function runInspectorHandoff(cliPath: string): Promise<{ result: RunResult throw new Error("Inspector port collided before launch on every attempt"); } +test("closes only the debugger socket acknowledged by its own resume", async () => { + const originalWebSocket = globalThis.WebSocket; + const stdout = new PassThrough(); + const stderr = new PassThrough(); + const child = Object.assign(new EventEmitter(), { + exitCode: null, + stderr, + stdout, + }) as unknown as ChildProcessByStdio; + FakeInspectorSocket.instances = []; + globalThis.WebSocket = FakeInspectorSocket as unknown as typeof WebSocket; + const run = driveRun(child); + + try { + stderr.write(`Debugger listening on ws://127.0.0.1:60457/first +`); + const first = FakeInspectorSocket.instances[0]; + expect(first).toBeDefined(); + first?.open(); + first?.receive({ id: 1 }); + first?.receive({ method: "Debugger.paused" }); + first?.receive({ id: 3 }); + expect(first?.closeCalls).toBe(1); + + stderr.write(`Waiting for the debugger to disconnect... +`); + stderr.write(`Debugger listening on ws://127.0.0.1:60457/second +`); + const second = FakeInspectorSocket.instances[1]; + expect(second).toBeDefined(); + second?.open(); + second?.receive({ id: 1 }); + second?.receive({ method: "Debugger.paused" }); + stderr.write(`Debugger attached. +`); + expect(second?.closeCalls).toBe(0); + second?.receive({ id: 3 }); + expect(second?.closeCalls).toBe(1); + } finally { + child.emit("close", 0); + globalThis.WebSocket = originalWebSocket; + } + + const result = await run; + expect(result.states).toHaveLength(2); + for (const state of result.states) { + expect(state.enabled).toBe(true); + expect(state.paused).toBe(true); + expect(state.resumed).toBe(true); + } +}); + test("classifies only pre-endpoint address conflicts as retryable", () => { const collision = { code: 1, stdout: "", stderr: "EADDRINUSE", states: [] }; const handoffFailure = { From 762d19ad38b6dede47b2c45acaf3572905ee671b Mon Sep 17 00:00:00 2001 From: effortprogrammer Date: Mon, 7 Sep 2026 23:43:25 +0900 Subject: [PATCH 8/8] docs: record verified PR 1431 fixes Document the verified reasoning controls, extension-turn hooks and atomic transcript hydration under Unreleased without changing released history or weakening policy gates. --- packages/ai/CHANGELOG.md | 3 +++ packages/coding-agent/CHANGELOG.md | 2 ++ 2 files changed, 5 insertions(+) diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 61c294d2fb..81730678cd 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -10,6 +10,9 @@ ### Fixed +- Correct built-in reasoning capability maps and preserve Xiaomi's disabled-thinking request control. +- Preserve distinct `low`, `medium`, and `xhigh` efforts for supported Qwen3.8 models on Alibaba and Qwen Token Plan providers. + ### Removed ## [2026.9.7] - 2026-09-07 diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 84d683bd1e..460afd64e3 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -11,6 +11,8 @@ - The GPT-6 Astra series now declares a 600,000-token context window on every provider that serves it. The effective prompt budget no longer depends on the route: the first-party OpenAI catalogs and the opencode, openrouter, github-copilot, and vercel-ai-gateway passthrough catalogs all agree. Set a different budget through model overrides if you want one. ### Fixed +- Run `before_agent_start` for idle extension-triggered turns and wait for deferred recovery before selecting print-mode output. +- Keep progressively hydrated transcript history private until completion so unrelated renders and resizes do not expose partial history. - Fixed deterministic compaction recovery rejecting realistic tool-result images because their Base64 bytes were counted against the token window. Image tokens are now charged separately while text, metadata, and genuine overflow protections remain intact ([#1455](https://github.com/code-yeongyu/senpi/issues/1455) by [@ayden94](https://github.com/ayden94)). - Plugin hook targets are now checked for containment against the filesystem rather than a path-collapsing resolver. A hook path that walked back up through a symlinked directory inside the plugin root could resolve to a file outside that root while still being reported as contained, so it was accepted; containment now resolves through `realpathSync.native`, which agrees with the kernel. Corrective on Node, behaviour-preserving on Bun.