From 69b8ea0d66ce9a57e4692278853fb67cc163a67b Mon Sep 17 00:00:00 2001 From: Luke Parker <10430890+Hona@users.noreply.github.com> Date: Wed, 22 Apr 2026 15:18:51 +1000 Subject: [PATCH 01/92] chore: bump Bun to 1.3.13 (#23791) --- bun.lock | 6 +++--- package.json | 4 ++-- packages/containers/bun-node/Dockerfile | 2 +- packages/ui/src/components/timeline-playground.stories.tsx | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bun.lock b/bun.lock index 77ab24240b..64b32feac4 100644 --- a/bun.lock +++ b/bun.lock @@ -688,7 +688,7 @@ "@tailwindcss/vite": "4.1.11", "@tsconfig/bun": "1.0.9", "@tsconfig/node22": "22.0.2", - "@types/bun": "1.3.11", + "@types/bun": "1.3.12", "@types/cross-spawn": "6.0.6", "@types/luxon": "3.7.1", "@types/node": "22.13.9", @@ -2302,7 +2302,7 @@ "@types/braces": ["@types/braces@3.0.5", "", {}, "sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w=="], - "@types/bun": ["@types/bun@1.3.11", "", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="], + "@types/bun": ["@types/bun@1.3.12", "", { "dependencies": { "bun-types": "1.3.12" } }, "sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A=="], "@types/cacache": ["@types/cacache@20.0.1", "", { "dependencies": { "@types/node": "*", "minipass": "*" } }, "sha512-QlKW3AFoFr/hvPHwFHMIVUH/ZCYeetBNou3PCmxu5LaNDvrtBlPJtIA6uhmU9JRt9oxj7IYoqoLcpxtzpPiTcw=="], @@ -2720,7 +2720,7 @@ "bun-pty": ["bun-pty@0.4.8", "", {}, "sha512-rO70Mrbr13+jxHHHu2YBkk2pNqrJE5cJn29WE++PUr+GFA0hq/VgtQPZANJ8dJo6d7XImvBk37Innt8GM7O28w=="], - "bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="], + "bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="], "bun-webgpu": ["bun-webgpu@0.1.5", "", { "dependencies": { "@webgpu/types": "^0.1.60" }, "optionalDependencies": { "bun-webgpu-darwin-arm64": "^0.1.5", "bun-webgpu-darwin-x64": "^0.1.5", "bun-webgpu-linux-x64": "^0.1.5", "bun-webgpu-win32-x64": "^0.1.5" } }, "sha512-91/K6S5whZKX7CWAm9AylhyKrLGRz6BUiiPiM/kXadSnD4rffljCD/q9cNFftm5YXhx4MvLqw33yEilxogJvwA=="], diff --git a/package.json b/package.json index 06bf9c91ae..f918bcd025 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "AI-powered development tool", "private": true, "type": "module", - "packageManager": "bun@1.3.11", + "packageManager": "bun@1.3.13", "scripts": { "dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts", "dev:desktop": "bun --cwd packages/desktop-electron dev", @@ -30,7 +30,7 @@ "@effect/opentelemetry": "4.0.0-beta.48", "@effect/platform-node": "4.0.0-beta.48", "@npmcli/arborist": "9.4.0", - "@types/bun": "1.3.11", + "@types/bun": "1.3.12", "@types/cross-spawn": "6.0.6", "@octokit/rest": "22.0.0", "@hono/zod-validator": "0.4.2", diff --git a/packages/containers/bun-node/Dockerfile b/packages/containers/bun-node/Dockerfile index 485375dd9f..d6f4729bf5 100644 --- a/packages/containers/bun-node/Dockerfile +++ b/packages/containers/bun-node/Dockerfile @@ -4,7 +4,7 @@ FROM ${REGISTRY}/build/base:24.04 SHELL ["/bin/bash", "-lc"] ARG NODE_VERSION=24.4.0 -ARG BUN_VERSION=1.3.11 +ARG BUN_VERSION=1.3.13 ENV BUN_INSTALL=/opt/bun ENV PATH=/opt/bun/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin diff --git a/packages/ui/src/components/timeline-playground.stories.tsx b/packages/ui/src/components/timeline-playground.stories.tsx index c071db303b..72f5730612 100644 --- a/packages/ui/src/components/timeline-playground.stories.tsx +++ b/packages/ui/src/components/timeline-playground.stories.tsx @@ -318,7 +318,7 @@ const TOOL_SAMPLES = { tool: "bash", input: { command: "bun test --filter session", description: "Run session tests" }, output: - "bun test v1.3.11\n\n✓ session-turn.test.tsx (3 tests) 45ms\n✓ message-part.test.tsx (7 tests) 120ms\n\nTest Suites: 2 passed, 2 total\nTests: 10 passed, 10 total\nTime: 0.89s", + "bun test v1.3.13\n\n✓ session-turn.test.tsx (3 tests) 45ms\n✓ message-part.test.tsx (7 tests) 120ms\n\nTest Suites: 2 passed, 2 total\nTests: 10 passed, 10 total\nTime: 0.89s", title: "Run session tests", metadata: { command: "bun test --filter session" }, }, From 06066dbb7bd05a99526f7b6a5eaa499d1cf47f78 Mon Sep 17 00:00:00 2001 From: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Date: Wed, 22 Apr 2026 13:36:20 +0800 Subject: [PATCH 02/92] fix(app): improve icon override handling in project edit dialog (#23768) --- .../src/components/dialog-edit-project.tsx | 36 ++++++++++--------- packages/app/src/context/layout.tsx | 2 +- .../app/src/pages/layout/sidebar-items.tsx | 4 ++- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/packages/app/src/components/dialog-edit-project.tsx b/packages/app/src/components/dialog-edit-project.tsx index ea5d70065a..621d56646d 100644 --- a/packages/app/src/components/dialog-edit-project.tsx +++ b/packages/app/src/components/dialog-edit-project.tsx @@ -26,8 +26,8 @@ export function DialogEditProject(props: { project: LocalProject }) { const [store, setStore] = createStore({ name: defaultName(), - color: props.project.icon?.color || "pink", - iconUrl: props.project.icon?.override || "", + color: props.project.icon?.color, + iconOverride: props.project.icon?.override, startup: props.project.commands?.start ?? "", dragOver: false, iconHover: false, @@ -39,7 +39,7 @@ export function DialogEditProject(props: { project: LocalProject }) { if (!file.type.startsWith("image/")) return const reader = new FileReader() reader.onload = (e) => { - setStore("iconUrl", e.target?.result as string) + setStore("iconOverride", e.target?.result as string) setStore("iconHover", false) } reader.readAsDataURL(file) @@ -68,7 +68,7 @@ export function DialogEditProject(props: { project: LocalProject }) { } function clearIcon() { - setStore("iconUrl", "") + setStore("iconOverride", "") } const saveMutation = useMutation(() => ({ @@ -81,17 +81,17 @@ export function DialogEditProject(props: { project: LocalProject }) { projectID: props.project.id, directory: props.project.worktree, name, - icon: { color: store.color, override: store.iconUrl }, + icon: { color: store.color || "", override: store.iconOverride || "" }, commands: { start }, }) - globalSync.project.icon(props.project.worktree, store.iconUrl || undefined) + globalSync.project.icon(props.project.worktree, store.iconOverride || undefined) dialog.close() return } globalSync.project.meta(props.project.worktree, { name, - icon: { color: store.color, override: store.iconUrl || undefined }, + icon: { color: store.color || undefined, override: store.iconOverride || undefined }, commands: { start: start || undefined }, }) dialog.close() @@ -130,13 +130,13 @@ export function DialogEditProject(props: { project: LocalProject }) { classList={{ "border-text-interactive-base bg-surface-info-base/20": store.dragOver, "border-border-base hover:border-border-strong": !store.dragOver, - "overflow-hidden": !!store.iconUrl, + "overflow-hidden": !!store.iconOverride, }} onDrop={handleDrop} onDragOver={handleDragOver} onDragLeave={handleDragLeave} onClick={() => { - if (store.iconUrl && store.iconHover) { + if (store.iconOverride && store.iconHover) { clearIcon() } else { iconInput?.click() @@ -144,7 +144,7 @@ export function DialogEditProject(props: { project: LocalProject }) { }} > {language.t("dialog.project.edit.icon.alt")} @@ -165,8 +165,8 @@ export function DialogEditProject(props: { project: LocalProject }) {
@@ -174,8 +174,8 @@ export function DialogEditProject(props: { project: LocalProject }) {
@@ -198,7 +198,7 @@ export function DialogEditProject(props: { project: LocalProject }) {
- +
@@ -215,7 +215,9 @@ export function DialogEditProject(props: { project: LocalProject }) { "bg-transparent border border-transparent hover:bg-surface-base-hover hover:border-border-weak-base": store.color !== color, }} - onClick={() => setStore("color", color)} + onClick={() => { + setStore("color", store.color === color ? undefined : color) + }} > Date: Wed, 22 Apr 2026 06:13:39 +0000 Subject: [PATCH 03/92] chore: update nix node_modules hashes --- nix/hashes.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nix/hashes.json b/nix/hashes.json index 21279a327d..c096046106 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-NczRp8MPppkqP8PQfWMUWJ/Wofvf2YVy5m4i22Pi3jg=", - "aarch64-linux": "sha256-QIxGOu8Fj+sWgc9hKvm1BLiIErxEtd17SPlwZGac9sQ=", - "aarch64-darwin": "sha256-Rb9qbMM+ARn0iBCaZurwcoUBCplbMXEZwrXVKextp3I=", - "x86_64-darwin": "sha256-KVxOKkaVV7W+K4reEk14MTLgmtoqwCYDqDNXNeS6ync=" + "x86_64-linux": "sha256-AgHhYsiygxbsBo3JN4HqHXKAwh8n1qeuSCe2qqxlxW4=", + "aarch64-linux": "sha256-h2lpWRQ5EDYnjpqZXtUAp1mxKLQxJ4m8MspgSY8Ev78=", + "aarch64-darwin": "sha256-xnd91+WyeAqn06run2ajsekxJvTMiLsnqNPe/rR8VTM=", + "x86_64-darwin": "sha256-rXpz45IOjGEk73xhP9VY86eOj2CZBg2l1vzwzTIOOOQ=" } } From 8113a4360e789fb25ac16d5619e732f3152ad3df Mon Sep 17 00:00:00 2001 From: Luke Parker <10430890+Hona@users.noreply.github.com> Date: Wed, 22 Apr 2026 18:03:34 +1000 Subject: [PATCH 04/92] fix: preserve BOM in text tool round-trips (#23797) --- packages/opencode/src/format/index.ts | 17 +++-- packages/opencode/src/patch/index.ts | 18 +++--- packages/opencode/src/tool/apply_patch.ts | 32 +++++++--- packages/opencode/src/tool/edit.ts | 29 ++++++--- packages/opencode/src/tool/write.ts | 15 +++-- packages/opencode/src/util/bom.ts | 31 +++++++++ packages/opencode/test/format/format.test.ts | 34 +++++++++- .../opencode/test/tool/apply_patch.test.ts | 28 +++++++++ packages/opencode/test/tool/edit.test.ts | 63 +++++++++++++++++++ packages/opencode/test/tool/write.test.ts | 48 ++++++++++++++ 10 files changed, 276 insertions(+), 39 deletions(-) create mode 100644 packages/opencode/src/util/bom.ts diff --git a/packages/opencode/src/format/index.ts b/packages/opencode/src/format/index.ts index 85934ce9c9..53a2c10119 100644 --- a/packages/opencode/src/format/index.ts +++ b/packages/opencode/src/format/index.ts @@ -25,7 +25,7 @@ export type Status = z.infer export interface Interface { readonly init: () => Effect.Effect readonly status: () => Effect.Effect - readonly file: (filepath: string) => Effect.Effect + readonly file: (filepath: string) => Effect.Effect } export class Service extends Context.Service()("@opencode/Format") {} @@ -70,16 +70,19 @@ export const layer = Layer.effect( } }), ) - return checks.filter((x) => x.cmd).map((x) => ({ item: x.item, cmd: x.cmd! })) + return checks + .filter((x): x is { item: Formatter.Info; cmd: string[] } => x.cmd !== false) + .map((x) => ({ item: x.item, cmd: x.cmd })) } function formatFile(filepath: string) { return Effect.gen(function* () { log.info("formatting", { file: filepath }) - const ext = path.extname(filepath) + const formatters = yield* Effect.promise(() => getFormatter(path.extname(filepath))) - for (const { item, cmd } of yield* Effect.promise(() => getFormatter(ext))) { - if (cmd === false) continue + if (!formatters.length) return false + + for (const { item, cmd } of formatters) { log.info("running", { command: cmd }) const replaced = cmd.map((x) => x.replace("$FILE", filepath)) const dir = yield* InstanceState.directory @@ -113,6 +116,8 @@ export const layer = Layer.effect( }) } } + + return true }) } @@ -188,7 +193,7 @@ export const layer = Layer.effect( const file = Effect.fn("Format.file")(function* (filepath: string) { const { formatFile } = yield* InstanceState.get(state) - yield* formatFile(filepath) + return yield* formatFile(filepath) }) return Service.of({ init, status, file }) diff --git a/packages/opencode/src/patch/index.ts b/packages/opencode/src/patch/index.ts index 19e1d7555b..3662f9e908 100644 --- a/packages/opencode/src/patch/index.ts +++ b/packages/opencode/src/patch/index.ts @@ -3,6 +3,7 @@ import * as path from "path" import * as fs from "fs/promises" import { readFileSync } from "fs" import { Log } from "../util" +import * as Bom from "../util/bom" const log = Log.create({ service: "patch" }) @@ -305,18 +306,19 @@ export function maybeParseApplyPatch( interface ApplyPatchFileUpdate { unified_diff: string content: string + bom: boolean } export function deriveNewContentsFromChunks(filePath: string, chunks: UpdateFileChunk[]): ApplyPatchFileUpdate { // Read original file content - let originalContent: string + let originalContent: ReturnType try { - originalContent = readFileSync(filePath, "utf-8") + originalContent = Bom.split(readFileSync(filePath, "utf-8")) } catch (error) { throw new Error(`Failed to read file ${filePath}: ${error}`, { cause: error }) } - let originalLines = originalContent.split("\n") + let originalLines = originalContent.text.split("\n") // Drop trailing empty element for consistent line counting if (originalLines.length > 0 && originalLines[originalLines.length - 1] === "") { @@ -331,14 +333,16 @@ export function deriveNewContentsFromChunks(filePath: string, chunks: UpdateFile newLines.push("") } - const newContent = newLines.join("\n") + const next = Bom.split(newLines.join("\n")) + const newContent = next.text // Generate unified diff - const unifiedDiff = generateUnifiedDiff(originalContent, newContent) + const unifiedDiff = generateUnifiedDiff(originalContent.text, newContent) return { unified_diff: unifiedDiff, content: newContent, + bom: originalContent.bom || next.bom, } } @@ -553,13 +557,13 @@ export async function applyHunksToFiles(hunks: Hunk[]): Promise { await fs.mkdir(moveDir, { recursive: true }) } - await fs.writeFile(hunk.move_path, fileUpdate.content, "utf-8") + await fs.writeFile(hunk.move_path, Bom.join(fileUpdate.content, fileUpdate.bom), "utf-8") await fs.unlink(hunk.path) modified.push(hunk.move_path) log.info(`Moved file: ${hunk.path} -> ${hunk.move_path}`) } else { // Regular update - await fs.writeFile(hunk.path, fileUpdate.content, "utf-8") + await fs.writeFile(hunk.path, Bom.join(fileUpdate.content, fileUpdate.bom), "utf-8") modified.push(hunk.path) log.info(`Updated file: ${hunk.path}`) } diff --git a/packages/opencode/src/tool/apply_patch.ts b/packages/opencode/src/tool/apply_patch.ts index 7da7dd255c..e36d5a65d8 100644 --- a/packages/opencode/src/tool/apply_patch.ts +++ b/packages/opencode/src/tool/apply_patch.ts @@ -14,6 +14,7 @@ import { AppFileSystem } from "@opencode-ai/shared/filesystem" import DESCRIPTION from "./apply_patch.txt" import { File } from "../file" import { Format } from "../format" +import * as Bom from "@/util/bom" const PatchParams = z.object({ patchText: z.string().describe("The full patch text that describes all changes to be made"), @@ -59,6 +60,7 @@ export const ApplyPatchTool = Tool.define( diff: string additions: number deletions: number + bom: boolean }> = [] let totalDiff = "" @@ -72,11 +74,12 @@ export const ApplyPatchTool = Tool.define( const oldContent = "" const newContent = hunk.contents.length === 0 || hunk.contents.endsWith("\n") ? hunk.contents : `${hunk.contents}\n` - const diff = trimDiff(createTwoFilesPatch(filePath, filePath, oldContent, newContent)) + const next = Bom.split(newContent) + const diff = trimDiff(createTwoFilesPatch(filePath, filePath, oldContent, next.text)) let additions = 0 let deletions = 0 - for (const change of diffLines(oldContent, newContent)) { + for (const change of diffLines(oldContent, next.text)) { if (change.added) additions += change.count || 0 if (change.removed) deletions += change.count || 0 } @@ -84,11 +87,12 @@ export const ApplyPatchTool = Tool.define( fileChanges.push({ filePath, oldContent, - newContent, + newContent: next.text, type: "add", diff, additions, deletions, + bom: next.bom, }) totalDiff += diff + "\n" @@ -104,13 +108,16 @@ export const ApplyPatchTool = Tool.define( ) } - const oldContent = yield* afs.readFileString(filePath) + const source = yield* Bom.readFile(afs, filePath) + const oldContent = source.text let newContent = oldContent + let bom = source.bom // Apply the update chunks to get new content try { const fileUpdate = Patch.deriveNewContentsFromChunks(filePath, hunk.chunks) newContent = fileUpdate.content + bom = fileUpdate.bom } catch (error) { return yield* Effect.fail(new Error(`apply_patch verification failed: ${error}`)) } @@ -136,6 +143,7 @@ export const ApplyPatchTool = Tool.define( diff, additions, deletions, + bom, }) totalDiff += diff + "\n" @@ -143,8 +151,8 @@ export const ApplyPatchTool = Tool.define( } case "delete": { - const contentToDelete = yield* afs - .readFileString(filePath) + const source = yield* Bom + .readFile(afs, filePath) .pipe( Effect.catch((error) => Effect.fail( @@ -154,6 +162,7 @@ export const ApplyPatchTool = Tool.define( ), ), ) + const contentToDelete = source.text const deleteDiff = trimDiff(createTwoFilesPatch(filePath, filePath, contentToDelete, "")) const deletions = contentToDelete.split("\n").length @@ -166,6 +175,7 @@ export const ApplyPatchTool = Tool.define( diff: deleteDiff, additions: 0, deletions, + bom: source.bom, }) totalDiff += deleteDiff + "\n" @@ -207,12 +217,12 @@ export const ApplyPatchTool = Tool.define( case "add": // Create parent directories (recursive: true is safe on existing/root dirs) - yield* afs.writeWithDirs(change.filePath, change.newContent) + yield* afs.writeWithDirs(change.filePath, Bom.join(change.newContent, change.bom)) updates.push({ file: change.filePath, event: "add" }) break case "update": - yield* afs.writeWithDirs(change.filePath, change.newContent) + yield* afs.writeWithDirs(change.filePath, Bom.join(change.newContent, change.bom)) updates.push({ file: change.filePath, event: "change" }) break @@ -220,7 +230,7 @@ export const ApplyPatchTool = Tool.define( if (change.movePath) { // Create parent directories (recursive: true is safe on existing/root dirs) - yield* afs.writeWithDirs(change.movePath!, change.newContent) + yield* afs.writeWithDirs(change.movePath!, Bom.join(change.newContent, change.bom)) yield* afs.remove(change.filePath) updates.push({ file: change.filePath, event: "unlink" }) updates.push({ file: change.movePath, event: "add" }) @@ -234,7 +244,9 @@ export const ApplyPatchTool = Tool.define( } if (edited) { - yield* format.file(edited) + if (yield* format.file(edited)) { + yield* Bom.syncFile(afs, edited, change.bom) + } yield* bus.publish(File.Event.Edited, { file: edited }) } } diff --git a/packages/opencode/src/tool/edit.ts b/packages/opencode/src/tool/edit.ts index 2c6c2c1308..858d14e043 100644 --- a/packages/opencode/src/tool/edit.ts +++ b/packages/opencode/src/tool/edit.ts @@ -18,6 +18,7 @@ import { Instance } from "../project/instance" import { Snapshot } from "@/snapshot" import { assertExternalDirectoryEffect } from "./external-directory" import { AppFileSystem } from "@opencode-ai/shared/filesystem" +import * as Bom from "@/util/bom" function normalizeLineEndings(text: string): string { return text.replaceAll("\r\n", "\n") @@ -84,7 +85,11 @@ export const EditTool = Tool.define( Effect.gen(function* () { if (params.oldString === "") { const existed = yield* afs.existsSafe(filePath) - contentNew = params.newString + const source = existed ? yield* Bom.readFile(afs, filePath) : { bom: false, text: "" } + const next = Bom.split(params.newString) + const desiredBom = source.bom || next.bom + contentOld = source.text + contentNew = next.text diff = trimDiff(createTwoFilesPatch(filePath, filePath, contentOld, contentNew)) yield* ctx.ask({ permission: "edit", @@ -95,8 +100,10 @@ export const EditTool = Tool.define( diff, }, }) - yield* afs.writeWithDirs(filePath, params.newString) - yield* format.file(filePath) + yield* afs.writeWithDirs(filePath, Bom.join(contentNew, desiredBom)) + if (yield* format.file(filePath)) { + contentNew = yield* Bom.syncFile(afs, filePath, desiredBom) + } yield* bus.publish(File.Event.Edited, { file: filePath }) yield* bus.publish(FileWatcher.Event.Updated, { file: filePath, @@ -108,13 +115,16 @@ export const EditTool = Tool.define( const info = yield* afs.stat(filePath).pipe(Effect.catch(() => Effect.succeed(undefined))) if (!info) throw new Error(`File ${filePath} not found`) if (info.type === "Directory") throw new Error(`Path is a directory, not a file: ${filePath}`) - contentOld = yield* afs.readFileString(filePath) + const source = yield* Bom.readFile(afs, filePath) + contentOld = source.text const ending = detectLineEnding(contentOld) const old = convertToLineEnding(normalizeLineEndings(params.oldString), ending) - const next = convertToLineEnding(normalizeLineEndings(params.newString), ending) + const replacement = convertToLineEnding(normalizeLineEndings(params.newString), ending) - contentNew = replace(contentOld, old, next, params.replaceAll) + const next = Bom.split(replace(contentOld, old, replacement, params.replaceAll)) + const desiredBom = source.bom || next.bom + contentNew = next.text diff = trimDiff( createTwoFilesPatch( @@ -134,14 +144,15 @@ export const EditTool = Tool.define( }, }) - yield* afs.writeWithDirs(filePath, contentNew) - yield* format.file(filePath) + yield* afs.writeWithDirs(filePath, Bom.join(contentNew, desiredBom)) + if (yield* format.file(filePath)) { + contentNew = yield* Bom.syncFile(afs, filePath, desiredBom) + } yield* bus.publish(File.Event.Edited, { file: filePath }) yield* bus.publish(FileWatcher.Event.Updated, { file: filePath, event: "change", }) - contentNew = yield* afs.readFileString(filePath) diff = trimDiff( createTwoFilesPatch( filePath, diff --git a/packages/opencode/src/tool/write.ts b/packages/opencode/src/tool/write.ts index 741091b21d..79ed585198 100644 --- a/packages/opencode/src/tool/write.ts +++ b/packages/opencode/src/tool/write.ts @@ -13,6 +13,7 @@ import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Instance } from "../project/instance" import { trimDiff } from "./edit" import { assertExternalDirectoryEffect } from "./external-directory" +import * as Bom from "@/util/bom" const MAX_PROJECT_DIAGNOSTICS_FILES = 5 @@ -38,9 +39,13 @@ export const WriteTool = Tool.define( yield* assertExternalDirectoryEffect(ctx, filepath) const exists = yield* fs.existsSafe(filepath) - const contentOld = exists ? yield* fs.readFileString(filepath) : "" + const source = exists ? yield* Bom.readFile(fs, filepath) : { bom: false, text: "" } + const next = Bom.split(params.content) + const desiredBom = source.bom || next.bom + const contentOld = source.text + const contentNew = next.text - const diff = trimDiff(createTwoFilesPatch(filepath, filepath, contentOld, params.content)) + const diff = trimDiff(createTwoFilesPatch(filepath, filepath, contentOld, contentNew)) yield* ctx.ask({ permission: "edit", patterns: [path.relative(Instance.worktree, filepath)], @@ -51,8 +56,10 @@ export const WriteTool = Tool.define( }, }) - yield* fs.writeWithDirs(filepath, params.content) - yield* format.file(filepath) + yield* fs.writeWithDirs(filepath, Bom.join(contentNew, desiredBom)) + if (yield* format.file(filepath)) { + yield* Bom.syncFile(fs, filepath, desiredBom) + } yield* bus.publish(File.Event.Edited, { file: filepath }) yield* bus.publish(FileWatcher.Event.Updated, { file: filepath, diff --git a/packages/opencode/src/util/bom.ts b/packages/opencode/src/util/bom.ts new file mode 100644 index 0000000000..484228f3d4 --- /dev/null +++ b/packages/opencode/src/util/bom.ts @@ -0,0 +1,31 @@ +import { Effect } from "effect" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" + +const BOM_CODE = 0xfeff +const BOM = String.fromCharCode(BOM_CODE) + +export function split(text: string) { + if (text.charCodeAt(0) !== BOM_CODE) return { bom: false, text } + return { bom: true, text: text.slice(1) } +} + +export function join(text: string, bom: boolean) { + const stripped = split(text).text + if (!bom) return stripped + return BOM + stripped +} + +export const readFile = Effect.fn("Bom.readFile")(function* (fs: AppFileSystem.Interface, filePath: string) { + return split(new TextDecoder("utf-8", { ignoreBOM: true }).decode(yield* fs.readFile(filePath))) +}) + +export const syncFile = Effect.fn("Bom.syncFile")(function* ( + fs: AppFileSystem.Interface, + filePath: string, + bom: boolean, +) { + const current = yield* readFile(fs, filePath) + if (current.bom === bom) return current.text + yield* fs.writeWithDirs(filePath, join(current.text, bom)) + return current.text +}) diff --git a/packages/opencode/test/format/format.test.ts b/packages/opencode/test/format/format.test.ts index 5530e195b2..2f6f235aa1 100644 --- a/packages/opencode/test/format/format.test.ts +++ b/packages/opencode/test/format/format.test.ts @@ -126,6 +126,24 @@ describe("Format", () => { it.live("service initializes without error", () => provideTmpdirInstance(() => Format.Service.use(() => Effect.void))) + it.live("file() returns false when no formatter runs", () => + provideTmpdirInstance( + (dir) => + Effect.gen(function* () { + const file = `${dir}/test.txt` + yield* Effect.promise(() => Bun.write(file, "x")) + + const formatted = yield* Format.Service.use((fmt) => fmt.file(file)) + expect(formatted).toBe(false) + }), + { + config: { + formatter: false, + }, + }, + ), + ) + it.live("status() initializes formatter state per directory", () => Effect.gen(function* () { const a = yield* provideTmpdirInstance(() => Format.Service.use((fmt) => fmt.status()), { @@ -219,7 +237,7 @@ describe("Format", () => { yield* Format.Service.use((fmt) => Effect.gen(function* () { yield* fmt.init() - yield* fmt.file(file) + expect(yield* fmt.file(file)).toBe(true) }), ) @@ -229,11 +247,21 @@ describe("Format", () => { config: { formatter: { first: { - command: ["sh", "-c", 'sleep 0.05; v=$(cat "$1"); printf \'%sA\' "$v" > "$1"', "sh", "$FILE"], + command: [ + "node", + "-e", + "const fs = require('fs'); const file = process.argv[1]; fs.writeFileSync(file, fs.readFileSync(file, 'utf8') + 'A')", + "$FILE", + ], extensions: [".seq"], }, second: { - command: ["sh", "-c", 'v=$(cat "$1"); printf \'%sB\' "$v" > "$1"', "sh", "$FILE"], + command: [ + "node", + "-e", + "const fs = require('fs'); const file = process.argv[1]; fs.writeFileSync(file, fs.readFileSync(file, 'utf8') + 'B')", + "$FILE", + ], extensions: [".seq"], }, }, diff --git a/packages/opencode/test/tool/apply_patch.test.ts b/packages/opencode/test/tool/apply_patch.test.ts index ebfa9a531e..7ce483726b 100644 --- a/packages/opencode/test/tool/apply_patch.test.ts +++ b/packages/opencode/test/tool/apply_patch.test.ts @@ -195,6 +195,34 @@ describe("tool.apply_patch freeform", () => { }) }) + test("does not invent a first-line diff for BOM files", async () => { + await using fixture = await tmpdir() + const { ctx, calls } = makeCtx() + + await Instance.provide({ + directory: fixture.path, + fn: async () => { + const bom = String.fromCharCode(0xfeff) + const target = path.join(fixture.path, "example.cs") + await fs.writeFile(target, `${bom}using System;\n\nclass Test {}\n`, "utf-8") + + const patchText = "*** Begin Patch\n*** Update File: example.cs\n@@\n class Test {}\n+class Next {}\n*** End Patch" + + await execute({ patchText }, ctx) + + expect(calls.length).toBe(1) + const shown = calls[0].metadata.files[0]?.patch ?? "" + expect(shown).not.toContain(bom) + expect(shown).not.toContain("-using System;") + expect(shown).not.toContain("+using System;") + + const content = await fs.readFile(target, "utf-8") + expect(content.charCodeAt(0)).toBe(0xfeff) + expect(content.slice(1)).toBe("using System;\n\nclass Test {}\nclass Next {}\n") + }, + }) + }) + test("inserts lines with insert-only hunk", async () => { await using fixture = await tmpdir() const { ctx } = makeCtx() diff --git a/packages/opencode/test/tool/edit.test.ts b/packages/opencode/test/tool/edit.test.ts index b5fbc0a67d..82e1b4a7fd 100644 --- a/packages/opencode/test/tool/edit.test.ts +++ b/packages/opencode/test/tool/edit.test.ts @@ -96,6 +96,37 @@ describe("tool.edit", () => { }) }) + test("preserves BOM when oldString is empty on existing files", async () => { + await using tmp = await tmpdir() + const filepath = path.join(tmp.path, "existing.cs") + const bom = String.fromCharCode(0xfeff) + await fs.writeFile(filepath, `${bom}using System;\n`, "utf-8") + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const edit = await resolve() + const result = await Effect.runPromise( + edit.execute( + { + filePath: filepath, + oldString: "", + newString: "using Up;\n", + }, + ctx, + ), + ) + + expect(result.metadata.diff).toContain("-using System;") + expect(result.metadata.diff).toContain("+using Up;") + + const content = await fs.readFile(filepath, "utf-8") + expect(content.charCodeAt(0)).toBe(0xfeff) + expect(content.slice(1)).toBe("using Up;\n") + }, + }) + }) + test("creates new file with nested directories", async () => { await using tmp = await tmpdir() const filepath = path.join(tmp.path, "nested", "dir", "file.txt") @@ -183,6 +214,38 @@ describe("tool.edit", () => { }) }) + test("replaces the first visible line in BOM files", async () => { + await using tmp = await tmpdir() + const filepath = path.join(tmp.path, "existing.cs") + const bom = String.fromCharCode(0xfeff) + await fs.writeFile(filepath, `${bom}using System;\nclass Test {}\n`, "utf-8") + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const edit = await resolve() + const result = await Effect.runPromise( + edit.execute( + { + filePath: filepath, + oldString: "using System;", + newString: "using Up;", + }, + ctx, + ), + ) + + expect(result.metadata.diff).toContain("-using System;") + expect(result.metadata.diff).toContain("+using Up;") + expect(result.metadata.diff).not.toContain(bom) + + const content = await fs.readFile(filepath, "utf-8") + expect(content.charCodeAt(0)).toBe(0xfeff) + expect(content.slice(1)).toBe("using Up;\nclass Test {}\n") + }, + }) + }) + test("throws error when file does not exist", async () => { await using tmp = await tmpdir() const filepath = path.join(tmp.path, "nonexistent.txt") diff --git a/packages/opencode/test/tool/write.test.ts b/packages/opencode/test/tool/write.test.ts index 50d3b57527..36131f9596 100644 --- a/packages/opencode/test/tool/write.test.ts +++ b/packages/opencode/test/tool/write.test.ts @@ -114,6 +114,54 @@ describe("tool.write", () => { ), ) + it.live("preserves BOM when overwriting existing files", () => + provideTmpdirInstance((dir) => + Effect.gen(function* () { + const filepath = path.join(dir, "existing.cs") + const bom = String.fromCharCode(0xfeff) + yield* Effect.promise(() => fs.writeFile(filepath, `${bom}using System;\n`, "utf-8")) + + yield* run({ filePath: filepath, content: "using Up;\n" }) + + const content = yield* Effect.promise(() => fs.readFile(filepath, "utf-8")) + expect(content.charCodeAt(0)).toBe(0xfeff) + expect(content.slice(1)).toBe("using Up;\n") + }), + ), + ) + + it.live("restores BOM after formatter strips it", () => + provideTmpdirInstance( + (dir) => + Effect.gen(function* () { + const filepath = path.join(dir, "formatted.cs") + const bom = String.fromCharCode(0xfeff) + yield* Effect.promise(() => fs.writeFile(filepath, `${bom}using System;\n`, "utf-8")) + + yield* run({ filePath: filepath, content: "using Up;\n" }) + + const content = yield* Effect.promise(() => fs.readFile(filepath, "utf-8")) + expect(content.charCodeAt(0)).toBe(0xfeff) + expect(content.slice(1)).toBe("using Up;\n") + }), + { + config: { + formatter: { + stripbom: { + extensions: [".cs"], + command: [ + "node", + "-e", + "const fs = require('fs'); const file = process.argv[1]; let text = fs.readFileSync(file, 'utf8'); if (text.charCodeAt(0) === 0xfeff) text = text.slice(1); fs.writeFileSync(file, text, 'utf8')", + "$FILE", + ], + }, + }, + }, + }, + ), + ) + it.live("returns diff in metadata for existing files", () => provideTmpdirInstance((dir) => Effect.gen(function* () { From 894e63891483cb0d79f7ca28410dcdfa604d35bf Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Wed, 22 Apr 2026 08:06:06 +0000 Subject: [PATCH 05/92] chore: generate --- packages/opencode/src/tool/apply_patch.ts | 16 +++++++--------- packages/opencode/test/tool/apply_patch.test.ts | 3 ++- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/opencode/src/tool/apply_patch.ts b/packages/opencode/src/tool/apply_patch.ts index e36d5a65d8..a4cf1e853f 100644 --- a/packages/opencode/src/tool/apply_patch.ts +++ b/packages/opencode/src/tool/apply_patch.ts @@ -151,17 +151,15 @@ export const ApplyPatchTool = Tool.define( } case "delete": { - const source = yield* Bom - .readFile(afs, filePath) - .pipe( - Effect.catch((error) => - Effect.fail( - new Error( - `apply_patch verification failed: ${error instanceof Error ? error.message : String(error)}`, - ), + const source = yield* Bom.readFile(afs, filePath).pipe( + Effect.catch((error) => + Effect.fail( + new Error( + `apply_patch verification failed: ${error instanceof Error ? error.message : String(error)}`, ), ), - ) + ), + ) const contentToDelete = source.text const deleteDiff = trimDiff(createTwoFilesPatch(filePath, filePath, contentToDelete, "")) diff --git a/packages/opencode/test/tool/apply_patch.test.ts b/packages/opencode/test/tool/apply_patch.test.ts index 7ce483726b..fa88432136 100644 --- a/packages/opencode/test/tool/apply_patch.test.ts +++ b/packages/opencode/test/tool/apply_patch.test.ts @@ -206,7 +206,8 @@ describe("tool.apply_patch freeform", () => { const target = path.join(fixture.path, "example.cs") await fs.writeFile(target, `${bom}using System;\n\nclass Test {}\n`, "utf-8") - const patchText = "*** Begin Patch\n*** Update File: example.cs\n@@\n class Test {}\n+class Next {}\n*** End Patch" + const patchText = + "*** Begin Patch\n*** Update File: example.cs\n@@\n class Test {}\n+class Next {}\n*** End Patch" await execute({ patchText }, ctx) From 20756e0ee45885db5614dab1867f16cea70ca1ec Mon Sep 17 00:00:00 2001 From: Luke Parker <10430890+Hona@users.noreply.github.com> Date: Wed, 22 Apr 2026 18:17:35 +1000 Subject: [PATCH 06/92] test: fix cross-spawn stderr race on Windows CI (#23808) --- packages/opencode/test/effect/cross-spawn-spawner.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/opencode/test/effect/cross-spawn-spawner.test.ts b/packages/opencode/test/effect/cross-spawn-spawner.test.ts index 5990635aa2..201d998667 100644 --- a/packages/opencode/test/effect/cross-spawn-spawner.test.ts +++ b/packages/opencode/test/effect/cross-spawn-spawner.test.ts @@ -169,7 +169,10 @@ describe("cross-spawn spawner", () => { 'process.stderr.write("stderr\\n", done)', ].join("\n"), ) - const [stdout, stderr] = yield* Effect.all([decodeByteStream(handle.stdout), decodeByteStream(handle.stderr)]) + const [stdout, stderr] = yield* Effect.all( + [decodeByteStream(handle.stdout), decodeByteStream(handle.stderr)], + { concurrency: 2 }, + ) expect(stdout).toBe("stdout") expect(stderr).toBe("stderr") }), From 71d196d3cd06d0efef7a319f43955c7cefc36e09 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Wed, 22 Apr 2026 08:18:44 +0000 Subject: [PATCH 07/92] chore: generate --- packages/opencode/test/effect/cross-spawn-spawner.test.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/opencode/test/effect/cross-spawn-spawner.test.ts b/packages/opencode/test/effect/cross-spawn-spawner.test.ts index 201d998667..b4e52529c1 100644 --- a/packages/opencode/test/effect/cross-spawn-spawner.test.ts +++ b/packages/opencode/test/effect/cross-spawn-spawner.test.ts @@ -169,10 +169,9 @@ describe("cross-spawn spawner", () => { 'process.stderr.write("stderr\\n", done)', ].join("\n"), ) - const [stdout, stderr] = yield* Effect.all( - [decodeByteStream(handle.stdout), decodeByteStream(handle.stderr)], - { concurrency: 2 }, - ) + const [stdout, stderr] = yield* Effect.all([decodeByteStream(handle.stdout), decodeByteStream(handle.stderr)], { + concurrency: 2, + }) expect(stdout).toBe("stdout") expect(stderr).toBe("stderr") }), From d884ab73d5516d301a740b2bdea174f6b485d6dc Mon Sep 17 00:00:00 2001 From: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Date: Wed, 22 Apr 2026 17:09:00 +0800 Subject: [PATCH 08/92] fix: consolidate project avatar source logic (#23819) --- .../src/components/dialog-edit-project.tsx | 20 +++++++++++++------ .../app/src/pages/layout/sidebar-items.tsx | 16 ++++++++------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/packages/app/src/components/dialog-edit-project.tsx b/packages/app/src/components/dialog-edit-project.tsx index 621d56646d..8eb12daf52 100644 --- a/packages/app/src/components/dialog-edit-project.tsx +++ b/packages/app/src/components/dialog-edit-project.tsx @@ -12,6 +12,7 @@ import { type LocalProject, getAvatarColors } from "@/context/layout" import { getFilename } from "@opencode-ai/shared/util/path" import { Avatar } from "@opencode-ai/ui/avatar" import { useLanguage } from "@/context/language" +import { getProjectAvatarSource } from "@/pages/layout/sidebar-items" const AVATAR_COLOR_KEYS = ["pink", "mint", "orange", "purple", "cyan", "lime"] as const @@ -144,7 +145,11 @@ export function DialogEditProject(props: { project: LocalProject }) { }} > } > - {language.t("dialog.project.edit.icon.alt")} + {(src) => ( + {language.t("dialog.project.edit.icon.alt")} + )}
{ + if (store.color === color && !props.project.icon?.url) return setStore("color", store.color === color ? undefined : color) }} > diff --git a/packages/app/src/pages/layout/sidebar-items.tsx b/packages/app/src/pages/layout/sidebar-items.tsx index 88d50db3ed..5170311a7b 100644 --- a/packages/app/src/pages/layout/sidebar-items.tsx +++ b/packages/app/src/pages/layout/sidebar-items.tsx @@ -19,6 +19,14 @@ import { childSessionOnPath, hasProjectPermissions } from "./helpers" const OPENCODE_PROJECT_ID = "4b0ea68d7af9a6031a7ffda7ad66e0cb83315750" +export function getProjectAvatarSource(id?: string, icon?: { color?: string; url?: string; override?: string }) { + return id === OPENCODE_PROJECT_ID + ? "https://opencode.ai/favicon.svg" + : icon?.color + ? undefined + : icon?.override || icon?.url +} + export const ProjectIcon = (props: { project: LocalProject; class?: string; notify?: boolean }): JSX.Element => { const globalSync = useGlobalSync() const notification = useNotification() @@ -42,13 +50,7 @@ export const ProjectIcon = (props: { project: LocalProject; class?: string; noti
Date: Wed, 22 Apr 2026 16:35:13 +0530 Subject: [PATCH 09/92] fix(tui): fail fast on invalid session startup (#23837) --- packages/opencode/src/cli/cmd/tui/attach.ts | 16 ++++++ .../src/cli/cmd/tui/routes/session/index.tsx | 55 ++++++++++++------- packages/opencode/src/cli/cmd/tui/thread.ts | 14 +++++ .../src/cli/cmd/tui/validate-session.ts | 24 ++++++++ packages/opencode/src/util/error.ts | 9 +++ 5 files changed, 97 insertions(+), 21 deletions(-) create mode 100644 packages/opencode/src/cli/cmd/tui/validate-session.ts diff --git a/packages/opencode/src/cli/cmd/tui/attach.ts b/packages/opencode/src/cli/cmd/tui/attach.ts index 9a93f3f57a..cb6b95a56c 100644 --- a/packages/opencode/src/cli/cmd/tui/attach.ts +++ b/packages/opencode/src/cli/cmd/tui/attach.ts @@ -3,6 +3,8 @@ import { UI } from "@/cli/ui" import { tui } from "./app" import { win32DisableProcessedInput, win32InstallCtrlCGuard } from "./win32" import { TuiConfig } from "@/cli/cmd/tui/config/tui" +import { errorMessage } from "@/util/error" +import { validateSession } from "./validate-session" export const AttachCommand = cmd({ command: "attach ", @@ -65,6 +67,20 @@ export const AttachCommand = cmd({ return { Authorization: auth } })() const config = await TuiConfig.get() + + try { + await validateSession({ + url: args.url, + sessionID: args.session, + directory, + headers, + }) + } catch (error) { + UI.error(errorMessage(error)) + process.exitCode = 1 + return + } + await tui({ url: args.url, config, diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 06be5dfbef..2f5da1d231 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -68,6 +68,7 @@ import { Flag } from "@/flag/flag" import { LANGUAGE_EXTENSIONS } from "@/lsp/language" import parsers from "../../../../../../parsers-config.ts" import * as Clipboard from "../../util/clipboard" +import { errorMessage } from "@/util/error" import { Toast, useToast } from "../../ui/toast" import { useKV } from "../../context/kv.tsx" import * as Editor from "../../util/editor" @@ -180,31 +181,43 @@ export function Session() { const toast = useToast() const sdk = useSDK() - createEffect(async () => { - const previousWorkspace = project.workspace.current() - const result = await sdk.client.session.get({ sessionID: route.sessionID }, { throwOnError: true }) - if (!result.data) { + createEffect(() => { + const sessionID = route.sessionID + void (async () => { + const previousWorkspace = project.workspace.current() + const result = await sdk.client.session.get({ sessionID }, { throwOnError: true }) + if (!result.data) { + toast.show({ + message: `Session not found: ${sessionID}`, + variant: "error", + duration: 5000, + }) + navigate({ type: "home" }) + return + } + + if (result.data.workspaceID !== previousWorkspace) { + project.workspace.set(result.data.workspaceID) + + // Sync all the data for this workspace. Note that this + // workspace may not exist anymore which is why this is not + // fatal. If it doesn't we still want to show the session + // (which will be non-interactive) + try { + await sync.bootstrap({ fatal: false }) + } catch {} + } + await sync.session.sync(sessionID) + if (route.sessionID === sessionID && scroll) scroll.scrollBy(100_000) + })().catch((error) => { + if (route.sessionID !== sessionID) return toast.show({ - message: `Session not found: ${route.sessionID}`, + message: errorMessage(error), variant: "error", + duration: 5000, }) navigate({ type: "home" }) - return - } - - if (result.data.workspaceID !== previousWorkspace) { - project.workspace.set(result.data.workspaceID) - - // Sync all the data for this workspace. Note that this - // workspace may not exist anymore which is why this is not - // fatal. If it doesn't we still want to show the session - // (which will be non-interactive) - try { - await sync.bootstrap({ fatal: false }) - } catch (e) {} - } - await sync.session.sync(route.sessionID) - if (scroll) scroll.scrollBy(100_000) + }) }) let lastSwitch: string | undefined = undefined diff --git a/packages/opencode/src/cli/cmd/tui/thread.ts b/packages/opencode/src/cli/cmd/tui/thread.ts index e3e9eb8117..a2a53ecafa 100644 --- a/packages/opencode/src/cli/cmd/tui/thread.ts +++ b/packages/opencode/src/cli/cmd/tui/thread.ts @@ -16,6 +16,7 @@ import { win32DisableProcessedInput, win32InstallCtrlCGuard } from "./win32" import { writeHeapSnapshot } from "v8" import { TuiConfig } from "./config/tui" import { OPENCODE_PROCESS_ROLE, OPENCODE_RUN_ID, ensureRunID, sanitizedProcessEnv } from "@/util/opencode-process" +import { validateSession } from "./validate-session" declare global { const OPENCODE_WORKER_PATH: string @@ -202,6 +203,19 @@ export const TuiThreadCommand = cmd({ events: createEventSource(client), } + try { + await validateSession({ + url: transport.url, + sessionID: args.session, + directory: cwd, + fetch: transport.fetch, + }) + } catch (error) { + UI.error(errorMessage(error)) + process.exitCode = 1 + return + } + setTimeout(() => { client.call("checkUpgrade", { directory: cwd }).catch(() => {}) }, 1000).unref?.() diff --git a/packages/opencode/src/cli/cmd/tui/validate-session.ts b/packages/opencode/src/cli/cmd/tui/validate-session.ts new file mode 100644 index 0000000000..e2a21d51e1 --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/validate-session.ts @@ -0,0 +1,24 @@ +import { createOpencodeClient } from "@opencode-ai/sdk/v2" +import { SessionID } from "@/session/schema" + +export async function validateSession(input: { + url: string + sessionID?: string + directory?: string + fetch?: typeof fetch + headers?: RequestInit["headers"] +}) { + if (!input.sessionID) return + + const result = SessionID.zod.safeParse(input.sessionID) + if (!result.success) { + throw new Error(`Invalid session ID: ${result.error.issues.at(0)?.message ?? "unknown error"}`) + } + + await createOpencodeClient({ + baseUrl: input.url, + directory: input.directory, + fetch: input.fetch, + headers: input.headers, + }).session.get({ sessionID: result.data }, { throwOnError: true }) +} diff --git a/packages/opencode/src/util/error.ts b/packages/opencode/src/util/error.ts index 75fef9fc9a..76cb9c7cf1 100644 --- a/packages/opencode/src/util/error.ts +++ b/packages/opencode/src/util/error.ts @@ -26,6 +26,15 @@ export function errorMessage(error: unknown): string { return error.message } + if ( + isRecord(error) && + isRecord(error.data) && + typeof error.data.message === "string" && + error.data.message + ) { + return error.data.message + } + const text = String(error) if (text && text !== "[object Object]") return text From fa8b7bc4d269ac29310b410b30a9875b33023e66 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Wed, 22 Apr 2026 11:07:04 +0000 Subject: [PATCH 10/92] chore: generate --- packages/opencode/src/util/error.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/opencode/src/util/error.ts b/packages/opencode/src/util/error.ts index 76cb9c7cf1..fbda2dc50e 100644 --- a/packages/opencode/src/util/error.ts +++ b/packages/opencode/src/util/error.ts @@ -26,12 +26,7 @@ export function errorMessage(error: unknown): string { return error.message } - if ( - isRecord(error) && - isRecord(error.data) && - typeof error.data.message === "string" && - error.data.message - ) { + if (isRecord(error) && isRecord(error.data) && typeof error.data.message === "string" && error.data.message) { return error.data.message } From 574b2c21708baf872faa358152c1fa705437aa6c Mon Sep 17 00:00:00 2001 From: Shoubhit Dash Date: Wed, 22 Apr 2026 20:37:32 +0530 Subject: [PATCH 11/92] fix(session): improve session compaction (#23870) --- .../opencode/src/agent/prompt/compaction.txt | 19 +- packages/opencode/src/session/compaction.ts | 198 ++++++++++--- packages/opencode/src/session/message-v2.ts | 14 +- .../opencode/test/session/compaction.test.ts | 279 ++++++++++++++++-- .../opencode/test/session/message-v2.test.ts | 70 +++++ .../test/session/messages-pagination.test.ts | 64 ++++ 6 files changed, 561 insertions(+), 83 deletions(-) diff --git a/packages/opencode/src/agent/prompt/compaction.txt b/packages/opencode/src/agent/prompt/compaction.txt index c5831bb30e..c7cb838bba 100644 --- a/packages/opencode/src/agent/prompt/compaction.txt +++ b/packages/opencode/src/agent/prompt/compaction.txt @@ -1,16 +1,9 @@ -You are a helpful AI assistant tasked with summarizing conversations. +You are an anchored context summarization assistant for coding sessions. -When asked to summarize, provide a detailed but concise summary of the older conversation history. -The most recent turns may be preserved verbatim outside your summary, so focus on information that would still be needed to continue the work with that recent context available. -Focus on information that would be helpful for continuing the conversation, including: -- What was done -- What is currently being worked on -- Which files are being modified -- What needs to be done next -- Key user requests, constraints, or preferences that should persist -- Important technical decisions and why they were made +Summarize only the conversation history you are given. The newest turns may be kept verbatim outside your summary, so focus on the older context that still matters for continuing the work. -Your summary should be comprehensive enough to provide context but concise enough to be quickly understood. +If the prompt includes a block, treat it as the current anchored summary. Update it with the new history by preserving still-true details, removing stale details, and merging in new facts. -Do not respond to any questions in the conversation, only output the summary. -Respond in the same language the user used in the conversation. +Always follow the exact output structure requested by the user prompt. Keep every section, preserve exact file paths and identifiers when known, and prefer terse bullets over paragraphs. + +Do not answer the conversation itself. Do not mention that you are summarizing, compacting, or merging context. Respond in the same language as the conversation. diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts index 037543064e..defdb870d7 100644 --- a/packages/opencode/src/session/compaction.ts +++ b/packages/opencode/src/session/compaction.ts @@ -32,16 +32,105 @@ export const Event = { export const PRUNE_MINIMUM = 20_000 export const PRUNE_PROTECT = 40_000 +const TOOL_OUTPUT_MAX_CHARS = 2_000 const PRUNE_PROTECTED_TOOLS = ["skill"] const DEFAULT_TAIL_TURNS = 2 const MIN_PRESERVE_RECENT_TOKENS = 2_000 const MAX_PRESERVE_RECENT_TOKENS = 8_000 +const SUMMARY_TEMPLATE = `Output exactly this Markdown structure and keep the section order unchanged: +--- +## Goal +- [single-sentence task summary] + +## Constraints & Preferences +- [user constraints, preferences, specs, or "(none)"] + +## Progress +### Done +- [completed work or "(none)"] + +### In Progress +- [current work or "(none)"] + +### Blocked +- [blockers or "(none)"] + +## Key Decisions +- [decision and why, or "(none)"] + +## Next Steps +- [ordered next actions or "(none)"] + +## Critical Context +- [important technical facts, errors, open questions, or "(none)"] + +## Relevant Files +- [file or directory path: why it matters, or "(none)"] +--- + +Rules: +- Keep every section, even when empty. +- Use terse bullets, not prose paragraphs. +- Preserve exact file paths, commands, error strings, and identifiers when known. +- Do not mention the summary process or that context was compacted.` type Turn = { start: number end: number id: MessageID } +type Tail = { + start: number + id: MessageID +} + +type CompletedCompaction = { + userIndex: number + assistantIndex: number + summary: string | undefined +} + +function summaryText(message: MessageV2.WithParts) { + const text = message.parts + .filter((part): part is MessageV2.TextPart => part.type === "text") + .map((part) => part.text.trim()) + .filter(Boolean) + .join("\n\n") + .trim() + return text || undefined +} + +function completedCompactions(messages: MessageV2.WithParts[]) { + const users = new Map() + for (let i = 0; i < messages.length; i++) { + const msg = messages[i] + if (msg.info.role !== "user") continue + if (!msg.parts.some((part) => part.type === "compaction")) continue + users.set(msg.info.id, i) + } + + return messages.flatMap((msg, assistantIndex): CompletedCompaction[] => { + if (msg.info.role !== "assistant") return [] + if (!msg.info.summary || !msg.info.finish || msg.info.error) return [] + const userIndex = users.get(msg.info.parentID) + if (userIndex === undefined) return [] + return [{ userIndex, assistantIndex, summary: summaryText(msg) }] + }) +} + +function buildPrompt(input: { previousSummary?: string; context: string[] }) { + const anchor = input.previousSummary + ? [ + "Update the anchored summary below using the conversation history above.", + "Preserve still-true details, remove stale details, and merge in the new facts.", + "", + input.previousSummary, + "", + ].join("\n") + : "Create a new anchored summary from the conversation history above." + return [anchor, SUMMARY_TEMPLATE, ...input.context].join("\n\n") +} + function preserveRecentBudget(input: { cfg: Config.Info; model: Provider.Model }) { return ( input.cfg.compaction?.preserve_recent_tokens ?? @@ -67,6 +156,31 @@ function turns(messages: MessageV2.WithParts[]) { return result } +function splitTurn(input: { + messages: MessageV2.WithParts[] + turn: Turn + model: Provider.Model + budget: number + estimate: (input: { messages: MessageV2.WithParts[]; model: Provider.Model }) => Effect.Effect +}) { + return Effect.gen(function* () { + if (input.budget <= 0) return undefined + if (input.turn.end - input.turn.start <= 1) return undefined + for (let start = input.turn.start + 1; start < input.turn.end; start++) { + const size = yield* input.estimate({ + messages: input.messages.slice(start, input.turn.end), + model: input.model, + }) + if (size > input.budget) continue + return { + start, + id: input.messages[start]!.info.id, + } satisfies Tail + } + return undefined + }) +} + export interface Interface { readonly isOverflow: (input: { tokens: MessageV2.Assistant["tokens"] @@ -147,18 +261,28 @@ export const layer: Layer.Layer< }), { concurrency: 1 }, ) - if (sizes.at(-1)! > budget) { - log.info("tail fallback", { budget, size: sizes.at(-1) }) - return { head: input.messages, tail_start_id: undefined } - } let total = 0 - let keep: Turn | undefined + let keep: Tail | undefined for (let i = recent.length - 1; i >= 0; i--) { + const turn = recent[i]! const size = sizes[i] - if (total + size > budget) break - total += size - keep = recent[i] + if (total + size <= budget) { + total += size + keep = { start: turn.start, id: turn.id } + continue + } + const remaining = budget - total + const split = yield* splitTurn({ + messages: input.messages, + turn, + model: input.model, + budget: remaining, + estimate, + }) + if (split) keep = split + else if (!keep) log.info("tail fallback", { budget, size, total }) + break } if (!keep || keep.start === 0) return { head: input.messages, tail_start_id: undefined } @@ -192,17 +316,15 @@ export const layer: Layer.Layer< if (msg.info.role === "assistant" && msg.info.summary) break loop for (let partIndex = msg.parts.length - 1; partIndex >= 0; partIndex--) { const part = msg.parts[partIndex] - if (part.type === "tool") - if (part.state.status === "completed") { - if (PRUNE_PROTECTED_TOOLS.includes(part.tool)) continue - if (part.state.time.compacted) break loop - const estimate = Token.estimate(part.state.output) - total += estimate - if (total > PRUNE_PROTECT) { - pruned += estimate - toPrune.push(part) - } - } + if (part.type !== "tool") continue + if (part.state.status !== "completed") continue + if (PRUNE_PROTECTED_TOOLS.includes(part.tool)) continue + if (part.state.time.compacted) break loop + const estimate = Token.estimate(part.state.output) + total += estimate + if (total <= PRUNE_PROTECT) continue + pruned += estimate + toPrune.push(part) } } @@ -263,8 +385,11 @@ export const layer: Layer.Layer< : yield* provider.getModel(userMessage.model.providerID, userMessage.model.modelID) const cfg = yield* config.get() const history = compactionPart && messages.at(-1)?.info.id === input.parentID ? messages.slice(0, -1) : messages + const prior = completedCompactions(history) + const hidden = new Set(prior.flatMap((item) => [item.userIndex, item.assistantIndex])) + const previousSummary = prior.at(-1)?.summary const selected = yield* select({ - messages: history, + messages: history.filter((_, index) => !hidden.has(index)), cfg, model, }) @@ -274,34 +399,13 @@ export const layer: Layer.Layer< { sessionID: input.sessionID }, { context: [], prompt: undefined }, ) - const defaultPrompt = `When constructing the summary, try to stick to this template: ---- -## Goal - -[What goal(s) is the user trying to accomplish?] - -## Instructions - -- [What important instructions did the user give you that are relevant] -- [If there is a plan or spec, include information about it so next agent can continue using it] - -## Discoveries - -[What notable things were learned during this conversation that would be useful for the next agent to know when continuing the work] - -## Accomplished - -[What work has been completed, what work is still in progress, and what work is left?] - -## Relevant files / directories - -[Construct a structured list of relevant files that have been read, edited, or created that pertain to the task at hand. If all the files in a directory are relevant, include the path to the directory.] ----` - - const prompt = compacting.prompt ?? [defaultPrompt, ...compacting.context].join("\n\n") + const nextPrompt = compacting.prompt ?? buildPrompt({ previousSummary, context: compacting.context }) const msgs = structuredClone(selected.head) yield* plugin.trigger("experimental.chat.messages.transform", {}, { messages: msgs }) - const modelMessages = yield* MessageV2.toModelMessagesEffect(msgs, model, { stripMedia: true }) + const modelMessages = yield* MessageV2.toModelMessagesEffect(msgs, model, { + stripMedia: true, + toolOutputMaxChars: TOOL_OUTPUT_MAX_CHARS, + }) const ctx = yield* InstanceState.context const msg: MessageV2.Assistant = { id: MessageID.ascending(), @@ -345,7 +449,7 @@ export const layer: Layer.Layer< ...modelMessages, { role: "user", - content: [{ type: "text", text: prompt }], + content: [{ type: "text", text: nextPrompt }], }, ], model, diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index 123f7b5401..980dd4da84 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -319,6 +319,12 @@ export const ToolStateCompleted = Schema.Struct({ .pipe(withStatics((s) => ({ zod: zod(s) }))) export type ToolStateCompleted = Types.DeepMutable> +function truncateToolOutput(text: string, maxChars?: number) { + if (!maxChars || text.length <= maxChars) return text + const omitted = text.length - maxChars + return `${text.slice(0, maxChars)}\n[Tool output truncated for compaction: omitted ${omitted} chars]` +} + export const ToolStateError = Schema.Struct({ status: Schema.Literal("error"), input: Schema.Record(Schema.String, Schema.Any), @@ -700,7 +706,7 @@ function providerMeta(metadata: Record | undefined) { export const toModelMessagesEffect = Effect.fnUntraced(function* ( input: WithParts[], model: Provider.Model, - options?: { stripMedia?: boolean }, + options?: { stripMedia?: boolean; toolOutputMaxChars?: number }, ) { const result: UIMessage[] = [] const toolNames = new Set() @@ -839,7 +845,9 @@ export const toModelMessagesEffect = Effect.fnUntraced(function* ( if (part.type === "tool") { toolNames.add(part.tool) if (part.state.status === "completed") { - const outputText = part.state.time.compacted ? "[Old tool result content cleared]" : part.state.output + const outputText = part.state.time.compacted + ? "[Old tool result content cleared]" + : truncateToolOutput(part.state.output, options?.toolOutputMaxChars) const attachments = part.state.time.compacted || options?.stripMedia ? [] : (part.state.attachments ?? []) // For providers that don't support media in tool results, extract media files @@ -955,7 +963,7 @@ export const toModelMessagesEffect = Effect.fnUntraced(function* ( export function toModelMessages( input: WithParts[], model: Provider.Model, - options?: { stripMedia?: boolean }, + options?: { stripMedia?: boolean; toolOutputMaxChars?: number }, ): Promise { return Effect.runPromise(toModelMessagesEffect(input, model, options).pipe(Effect.provide(EffectLogger.layer))) } diff --git a/packages/opencode/test/session/compaction.test.ts b/packages/opencode/test/session/compaction.test.ts index 0e2b179f00..2188d8d7cd 100644 --- a/packages/opencode/test/session/compaction.test.ts +++ b/packages/opencode/test/session/compaction.test.ts @@ -143,6 +143,43 @@ async function assistant(sessionID: SessionID, parentID: MessageID, root: string return msg } +async function summaryAssistant(sessionID: SessionID, parentID: MessageID, root: string, text: string) { + const msg: MessageV2.Assistant = { + id: MessageID.ascending(), + role: "assistant", + sessionID, + mode: "compaction", + agent: "compaction", + path: { cwd: root, root }, + cost: 0, + tokens: { + output: 0, + input: 0, + reasoning: 0, + cache: { read: 0, write: 0 }, + }, + modelID: ref.modelID, + providerID: ref.providerID, + parentID, + summary: true, + time: { created: Date.now() }, + finish: "end_turn", + } + await svc.updateMessage(msg) + await svc.updatePart({ + id: PartID.ascending(), + messageID: msg.id, + sessionID, + type: "text", + text, + }) + return msg +} + +async function lastCompactionPart(sessionID: SessionID) { + return (await svc.messages({ sessionID })).at(-2)?.parts.find((item): item is MessageV2.CompactionPart => item.type === "compaction") +} + function fake( input: Parameters[0], result: "continue" | "compact", @@ -946,12 +983,9 @@ describe("session.compaction.process", () => { ), ) - const part = (await svc.messages({ sessionID: session.id })) - .at(-2) - ?.parts.find((item) => item.type === "compaction") - + const part = await lastCompactionPart(session.id) expect(part?.type).toBe("compaction") - if (part?.type === "compaction") expect(part.tail_start_id).toBe(keep.id) + expect(part?.tail_start_id).toBe(keep.id) } finally { await rt.dispose() } @@ -991,12 +1025,9 @@ describe("session.compaction.process", () => { ), ) - const part = (await svc.messages({ sessionID: session.id })) - .at(-2) - ?.parts.find((item) => item.type === "compaction") - + const part = await lastCompactionPart(session.id) expect(part?.type).toBe("compaction") - if (part?.type === "compaction") expect(part.tail_start_id).toBe(keep.id) + expect(part?.tail_start_id).toBe(keep.id) } finally { await rt.dispose() } @@ -1042,12 +1073,9 @@ describe("session.compaction.process", () => { ), ) - const part = (await svc.messages({ sessionID: session.id })) - .at(-2) - ?.parts.find((item) => item.type === "compaction") - + const part = await lastCompactionPart(session.id) expect(part?.type).toBe("compaction") - if (part?.type === "compaction") expect(part.tail_start_id).toBeUndefined() + expect(part?.tail_start_id).toBeUndefined() expect(captured).toContain("yyyy") } finally { await rt.dispose() @@ -1103,12 +1131,9 @@ describe("session.compaction.process", () => { ), ) - const part = (await svc.messages({ sessionID: session.id })) - .at(-2) - ?.parts.find((item) => item.type === "compaction") - + const part = await lastCompactionPart(session.id) expect(part?.type).toBe("compaction") - if (part?.type === "compaction") expect(part.tail_start_id).toBeUndefined() + expect(part?.tail_start_id).toBeUndefined() expect(captured).toContain("recent image turn") expect(captured).toContain("Attached image/png: big.png") } finally { @@ -1118,6 +1143,76 @@ describe("session.compaction.process", () => { }) }) + test("retains a split turn suffix when a later message fits the preserve token budget", async () => { + await using tmp = await tmpdir({ git: true }) + const stub = llm() + let captured = "" + stub.push( + reply("summary", (input) => { + captured = JSON.stringify(input.messages) + }), + ) + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const session = await svc.create({}) + await user(session.id, "older") + const recent = await user(session.id, "recent turn") + const large = await assistant(session.id, recent.id, tmp.path) + await svc.updatePart({ + id: PartID.ascending(), + messageID: large.id, + sessionID: session.id, + type: "text", + text: "z".repeat(2_000), + }) + const keep = await assistant(session.id, recent.id, tmp.path) + await svc.updatePart({ + id: PartID.ascending(), + messageID: keep.id, + sessionID: session.id, + type: "text", + text: "keep tail", + }) + await SessionCompaction.create({ + sessionID: session.id, + agent: "build", + model: ref, + auto: false, + }) + + const rt = liveRuntime(stub.layer, wide(), cfg({ tail_turns: 1, preserve_recent_tokens: 100 })) + try { + const msgs = await svc.messages({ sessionID: session.id }) + const parent = msgs.at(-1)?.info.id + expect(parent).toBeTruthy() + await rt.runPromise( + SessionCompaction.Service.use((svc) => + svc.process({ + parentID: parent!, + messages: msgs, + sessionID: session.id, + auto: false, + }), + ), + ) + + const part = await lastCompactionPart(session.id) + expect(part?.type).toBe("compaction") + expect(part?.tail_start_id).toBe(keep.id) + expect(captured).toContain("zzzz") + expect(captured).not.toContain("keep tail") + + const filtered = MessageV2.filterCompacted(MessageV2.stream(session.id)) + expect(filtered[0]?.info.id).toBe(keep.id) + expect(filtered.map((msg) => msg.info.id)).not.toContain(large.id) + } finally { + await rt.dispose() + } + }, + }) + }) + test("allows plugins to disable synthetic continue prompt", async () => { await using tmp = await tmpdir() await Instance.provide({ @@ -1530,6 +1625,80 @@ describe("session.compaction.process", () => { }) }) + test("anchors repeated compactions with the previous summary", async () => { + const stub = llm() + let captured = "" + stub.push(reply("summary one")) + stub.push( + reply("summary two", (input) => { + captured = JSON.stringify(input.messages) + }), + ) + + await using tmp = await tmpdir({ git: true }) + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const session = await svc.create({}) + await user(session.id, "older context") + await user(session.id, "keep this turn") + await SessionCompaction.create({ + sessionID: session.id, + agent: "build", + model: ref, + auto: false, + }) + + const rt = liveRuntime(stub.layer, wide()) + try { + let msgs = await svc.messages({ sessionID: session.id }) + let parent = msgs.at(-1)?.info.id + expect(parent).toBeTruthy() + await rt.runPromise( + SessionCompaction.Service.use((svc) => + svc.process({ + parentID: parent!, + messages: msgs, + sessionID: session.id, + auto: false, + }), + ), + ) + + await user(session.id, "latest turn") + await SessionCompaction.create({ + sessionID: session.id, + agent: "build", + model: ref, + auto: false, + }) + + msgs = MessageV2.filterCompacted(MessageV2.stream(session.id)) + parent = msgs.at(-1)?.info.id + expect(parent).toBeTruthy() + await rt.runPromise( + SessionCompaction.Service.use((svc) => + svc.process({ + parentID: parent!, + messages: msgs, + sessionID: session.id, + auto: false, + }), + ), + ) + + expect(captured).toContain("") + expect(captured).toContain("summary one") + expect(captured.match(/summary one/g)?.length).toBe(1) + expect(captured).toContain("## Constraints & Preferences") + expect(captured).toContain("## Progress") + } finally { + await rt.dispose() + } + }, + }) + }) + test("keeps recent pre-compaction turns across repeated compactions", async () => { const stub = llm() stub.push(reply("summary one")) @@ -1604,6 +1773,76 @@ describe("session.compaction.process", () => { }, }) }) + + test("ignores previous summaries when sizing the retained tail", async () => { + await using tmp = await tmpdir() + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const session = await svc.create({}) + await user(session.id, "older") + const keep = await user(session.id, "keep this turn") + const keepReply = await assistant(session.id, keep.id, tmp.path) + await svc.updatePart({ + id: PartID.ascending(), + messageID: keepReply.id, + sessionID: session.id, + type: "text", + text: "keep reply", + }) + + await SessionCompaction.create({ + sessionID: session.id, + agent: "build", + model: ref, + auto: false, + }) + const firstCompaction = (await svc.messages({ sessionID: session.id })).at(-1)?.info.id + expect(firstCompaction).toBeTruthy() + await summaryAssistant(session.id, firstCompaction!, tmp.path, "summary ".repeat(800)) + + const recent = await user(session.id, "recent turn") + const recentReply = await assistant(session.id, recent.id, tmp.path) + await svc.updatePart({ + id: PartID.ascending(), + messageID: recentReply.id, + sessionID: session.id, + type: "text", + text: "recent reply", + }) + + await SessionCompaction.create({ + sessionID: session.id, + agent: "build", + model: ref, + auto: false, + }) + + const rt = runtime("continue", Plugin.defaultLayer, wide(), cfg({ tail_turns: 2, preserve_recent_tokens: 500 })) + try { + const msgs = await svc.messages({ sessionID: session.id }) + const parent = msgs.at(-1)?.info.id + expect(parent).toBeTruthy() + await rt.runPromise( + SessionCompaction.Service.use((svc) => + svc.process({ + parentID: parent!, + messages: msgs, + sessionID: session.id, + auto: false, + }), + ), + ) + + const part = await lastCompactionPart(session.id) + expect(part?.type).toBe("compaction") + expect(part?.tail_start_id).toBe(keep.id) + } finally { + await rt.dispose() + } + }, + }) + }) }) describe("util.token.estimate", () => { diff --git a/packages/opencode/test/session/message-v2.test.ts b/packages/opencode/test/session/message-v2.test.ts index 55ae65c560..231d58c21a 100644 --- a/packages/opencode/test/session/message-v2.test.ts +++ b/packages/opencode/test/session/message-v2.test.ts @@ -585,6 +585,76 @@ describe("session.message-v2.toModelMessage", () => { ]) }) + test("truncates tool output when requested", async () => { + const userID = "m-user" + const assistantID = "m-assistant" + + const input: MessageV2.WithParts[] = [ + { + info: userInfo(userID), + parts: [ + { + ...basePart(userID, "u1"), + type: "text", + text: "run tool", + }, + ] as MessageV2.Part[], + }, + { + info: assistantInfo(assistantID, userID), + parts: [ + { + ...basePart(assistantID, "a1"), + type: "tool", + callID: "call-1", + tool: "bash", + state: { + status: "completed", + input: { cmd: "ls" }, + output: "abcdefghij", + title: "Bash", + metadata: {}, + time: { start: 0, end: 1 }, + }, + }, + ] as MessageV2.Part[], + }, + ] + + expect(await MessageV2.toModelMessages(input, model, { toolOutputMaxChars: 4 })).toStrictEqual([ + { + role: "user", + content: [{ type: "text", text: "run tool" }], + }, + { + role: "assistant", + content: [ + { + type: "tool-call", + toolCallId: "call-1", + toolName: "bash", + input: { cmd: "ls" }, + providerExecuted: undefined, + }, + ], + }, + { + role: "tool", + content: [ + { + type: "tool-result", + toolCallId: "call-1", + toolName: "bash", + output: { + type: "text", + value: "abcd\n[Tool output truncated for compaction: omitted 6 chars]", + }, + }, + ], + }, + ]) + }) + test("converts assistant tool error into error-text tool result", async () => { const userID = "m-user" const assistantID = "m-assistant" diff --git a/packages/opencode/test/session/messages-pagination.test.ts b/packages/opencode/test/session/messages-pagination.test.ts index d8dcf5e7cb..df2d18b9f1 100644 --- a/packages/opencode/test/session/messages-pagination.test.ts +++ b/packages/opencode/test/session/messages-pagination.test.ts @@ -837,6 +837,70 @@ describe("MessageV2.filterCompacted", () => { }) }) + test("retains an assistant tail when compaction starts inside a turn", async () => { + await Instance.provide({ + directory: root, + fn: async () => { + const session = await svc.create({}) + + const u1 = await addUser(session.id, "first") + const a1 = await addAssistant(session.id, u1, { finish: "end_turn" }) + await svc.updatePart({ + id: PartID.ascending(), + sessionID: session.id, + messageID: a1, + type: "text", + text: "first reply", + }) + + const u2 = await addUser(session.id, "second") + const a2 = await addAssistant(session.id, u2, { finish: "end_turn" }) + await svc.updatePart({ + id: PartID.ascending(), + sessionID: session.id, + messageID: a2, + type: "text", + text: "second reply", + }) + const a3 = await addAssistant(session.id, u2, { finish: "end_turn" }) + await svc.updatePart({ + id: PartID.ascending(), + sessionID: session.id, + messageID: a3, + type: "text", + text: "tail reply", + }) + + const c1 = await addUser(session.id) + await addCompactionPart(session.id, c1, a3) + const s1 = await addAssistant(session.id, c1, { summary: true, finish: "end_turn" }) + await svc.updatePart({ + id: PartID.ascending(), + sessionID: session.id, + messageID: s1, + type: "text", + text: "summary", + }) + + const u3 = await addUser(session.id, "third") + const a4 = await addAssistant(session.id, u3, { finish: "end_turn" }) + await svc.updatePart({ + id: PartID.ascending(), + sessionID: session.id, + messageID: a4, + type: "text", + text: "third reply", + }) + + const result = MessageV2.filterCompacted(MessageV2.stream(session.id)) + + expect(result.map((item) => item.info.id)).toEqual([a3, c1, s1, u3, a4]) + + await svc.remove(session.id) + }, + }) + }) + test("prefers latest compaction boundary when repeated compactions exist", async () => { await Instance.provide({ directory: root, From 504fd1b373d0b35f39ee40b07fdb6957454de6b1 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Wed, 22 Apr 2026 15:09:51 +0000 Subject: [PATCH 12/92] chore: generate --- packages/opencode/test/session/compaction.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/opencode/test/session/compaction.test.ts b/packages/opencode/test/session/compaction.test.ts index 2188d8d7cd..037613d469 100644 --- a/packages/opencode/test/session/compaction.test.ts +++ b/packages/opencode/test/session/compaction.test.ts @@ -177,7 +177,9 @@ async function summaryAssistant(sessionID: SessionID, parentID: MessageID, root: } async function lastCompactionPart(sessionID: SessionID) { - return (await svc.messages({ sessionID })).at(-2)?.parts.find((item): item is MessageV2.CompactionPart => item.type === "compaction") + return (await svc.messages({ sessionID })) + .at(-2) + ?.parts.find((item): item is MessageV2.CompactionPart => item.type === "compaction") } function fake( From 3a082a0efd5eaa5296c929241bfe565d460c277b Mon Sep 17 00:00:00 2001 From: "Steven T. Cramer" Date: Wed, 22 Apr 2026 23:02:10 +0700 Subject: [PATCH 13/92] fix(project): use git common dir for bare repo project cache (#19054) --- packages/opencode/src/project/project.ts | 12 +-- .../opencode/test/project/project.test.ts | 84 +++++++++++++++++++ 2 files changed, 90 insertions(+), 6 deletions(-) diff --git a/packages/opencode/src/project/project.ts b/packages/opencode/src/project/project.ts index 6a2132274a..d628f87f97 100644 --- a/packages/opencode/src/project/project.ts +++ b/packages/opencode/src/project/project.ts @@ -207,13 +207,13 @@ export const layer: Layer.Layer< vcs: fakeVcs, } } - const worktree = (() => { - const common = resolveGitPath(sandbox, commonDir.text.trim()) - return common === sandbox ? sandbox : pathSvc.dirname(common) - })() + const common = resolveGitPath(sandbox, commonDir.text.trim()) + const bareCheck = yield* git(["config", "--bool", "core.bare"], { cwd: sandbox }) + const isBareRepo = bareCheck.code === 0 && bareCheck.text.trim() === "true" + const worktree = common === sandbox ? sandbox : isBareRepo ? common : pathSvc.dirname(common) if (id == null) { - id = yield* readCachedProjectId(pathSvc.join(worktree, ".git")) + id = yield* readCachedProjectId(common) } if (!id) { @@ -226,7 +226,7 @@ export const layer: Layer.Layer< id = roots[0] ? ProjectID.make(roots[0]) : undefined if (id) { - yield* fs.writeFileString(pathSvc.join(worktree, ".git", "opencode"), id).pipe(Effect.ignore) + yield* fs.writeFileString(pathSvc.join(common, "opencode"), id).pipe(Effect.ignore) } } diff --git a/packages/opencode/test/project/project.test.ts b/packages/opencode/test/project/project.test.ts index 4dc9ee5efa..4664b6c258 100644 --- a/packages/opencode/test/project/project.test.ts +++ b/packages/opencode/test/project/project.test.ts @@ -472,3 +472,87 @@ describe("Project.addSandbox and Project.removeSandbox", () => { expect(events.some((e) => e.payload.type === Project.Event.Updated.type)).toBe(true) }) }) + +describe("Project.fromDirectory with bare repos", () => { + test("worktree from bare repo should cache in bare repo, not parent", async () => { + await using tmp = await tmpdir({ git: true }) + + const parentDir = path.dirname(tmp.path) + const barePath = path.join(parentDir, `bare-${Date.now()}.git`) + const worktreePath = path.join(parentDir, `worktree-${Date.now()}`) + + try { + await $`git clone --bare ${tmp.path} ${barePath}`.quiet() + await $`git worktree add ${worktreePath} HEAD`.cwd(barePath).quiet() + + const { project } = await run((svc) => svc.fromDirectory(worktreePath)) + + expect(project.id).not.toBe(ProjectID.global) + expect(project.worktree).toBe(barePath) + + const correctCache = path.join(barePath, "opencode") + const wrongCache = path.join(parentDir, ".git", "opencode") + + expect(await Bun.file(correctCache).exists()).toBe(true) + expect(await Bun.file(wrongCache).exists()).toBe(false) + } finally { + await $`rm -rf ${barePath} ${worktreePath}`.quiet().nothrow() + } + }) + + test("different bare repos under same parent should not share project ID", async () => { + await using tmp1 = await tmpdir({ git: true }) + await using tmp2 = await tmpdir({ git: true }) + + const parentDir = path.dirname(tmp1.path) + const bareA = path.join(parentDir, `bare-a-${Date.now()}.git`) + const bareB = path.join(parentDir, `bare-b-${Date.now()}.git`) + const worktreeA = path.join(parentDir, `wt-a-${Date.now()}`) + const worktreeB = path.join(parentDir, `wt-b-${Date.now()}`) + + try { + await $`git clone --bare ${tmp1.path} ${bareA}`.quiet() + await $`git clone --bare ${tmp2.path} ${bareB}`.quiet() + await $`git worktree add ${worktreeA} HEAD`.cwd(bareA).quiet() + await $`git worktree add ${worktreeB} HEAD`.cwd(bareB).quiet() + + const { project: projA } = await run((svc) => svc.fromDirectory(worktreeA)) + const { project: projB } = await run((svc) => svc.fromDirectory(worktreeB)) + + expect(projA.id).not.toBe(projB.id) + + const cacheA = path.join(bareA, "opencode") + const cacheB = path.join(bareB, "opencode") + const wrongCache = path.join(parentDir, ".git", "opencode") + + expect(await Bun.file(cacheA).exists()).toBe(true) + expect(await Bun.file(cacheB).exists()).toBe(true) + expect(await Bun.file(wrongCache).exists()).toBe(false) + } finally { + await $`rm -rf ${bareA} ${bareB} ${worktreeA} ${worktreeB}`.quiet().nothrow() + } + }) + + test("bare repo without .git suffix is still detected via core.bare", async () => { + await using tmp = await tmpdir({ git: true }) + + const parentDir = path.dirname(tmp.path) + const barePath = path.join(parentDir, `bare-no-suffix-${Date.now()}`) + const worktreePath = path.join(parentDir, `worktree-${Date.now()}`) + + try { + await $`git clone --bare ${tmp.path} ${barePath}`.quiet() + await $`git worktree add ${worktreePath} HEAD`.cwd(barePath).quiet() + + const { project } = await run((svc) => svc.fromDirectory(worktreePath)) + + expect(project.id).not.toBe(ProjectID.global) + expect(project.worktree).toBe(barePath) + + const correctCache = path.join(barePath, "opencode") + expect(await Bun.file(correctCache).exists()).toBe(true) + } finally { + await $`rm -rf ${barePath} ${worktreePath}`.quiet().nothrow() + } + }) +}) From e9b1d3b940d6369a1c9bd492daf168c933cdfdab Mon Sep 17 00:00:00 2001 From: Jack Date: Thu, 23 Apr 2026 00:28:20 +0800 Subject: [PATCH 14/92] docs: add MiMo V2.5 to Go pages (#23876) --- packages/console/app/src/i18n/ar.ts | 8 ++++---- packages/console/app/src/i18n/br.ts | 8 ++++---- packages/console/app/src/i18n/da.ts | 8 ++++---- packages/console/app/src/i18n/de.ts | 8 ++++---- packages/console/app/src/i18n/en.ts | 8 ++++---- packages/console/app/src/i18n/es.ts | 8 ++++---- packages/console/app/src/i18n/fr.ts | 8 ++++---- packages/console/app/src/i18n/it.ts | 8 ++++---- packages/console/app/src/i18n/ja.ts | 8 ++++---- packages/console/app/src/i18n/ko.ts | 8 ++++---- packages/console/app/src/i18n/no.ts | 8 ++++---- packages/console/app/src/i18n/pl.ts | 8 ++++---- packages/console/app/src/i18n/ru.ts | 8 ++++---- packages/console/app/src/i18n/th.ts | 8 ++++---- packages/console/app/src/i18n/tr.ts | 8 ++++---- packages/console/app/src/i18n/zh.ts | 8 ++++---- packages/console/app/src/i18n/zht.ts | 8 ++++---- packages/console/app/src/routes/go/index.tsx | 4 +++- .../src/routes/workspace/[id]/go/lite-section.tsx | 6 ++++-- packages/web/src/content/docs/ar/go.mdx | 12 ++++++++++-- packages/web/src/content/docs/bs/go.mdx | 12 ++++++++++-- packages/web/src/content/docs/da/go.mdx | 12 ++++++++++-- packages/web/src/content/docs/de/go.mdx | 12 ++++++++++-- packages/web/src/content/docs/es/go.mdx | 12 ++++++++++-- packages/web/src/content/docs/fr/go.mdx | 12 ++++++++++-- packages/web/src/content/docs/go.mdx | 12 ++++++++++-- packages/web/src/content/docs/it/go.mdx | 12 ++++++++++-- packages/web/src/content/docs/ja/go.mdx | 12 ++++++++++-- packages/web/src/content/docs/ko/go.mdx | 12 ++++++++++-- packages/web/src/content/docs/nb/go.mdx | 12 ++++++++++-- packages/web/src/content/docs/pl/go.mdx | 12 ++++++++++-- packages/web/src/content/docs/pt-br/go.mdx | 12 ++++++++++-- packages/web/src/content/docs/ru/go.mdx | 12 ++++++++++-- packages/web/src/content/docs/th/go.mdx | 12 ++++++++++-- packages/web/src/content/docs/tr/go.mdx | 12 ++++++++++-- packages/web/src/content/docs/zh-cn/go.mdx | 12 ++++++++++-- packages/web/src/content/docs/zh-tw/go.mdx | 12 ++++++++++-- 37 files changed, 255 insertions(+), 107 deletions(-) diff --git a/packages/console/app/src/i18n/ar.ts b/packages/console/app/src/i18n/ar.ts index 73c07c6775..a7883cfe4c 100644 --- a/packages/console/app/src/i18n/ar.ts +++ b/packages/console/app/src/i18n/ar.ts @@ -249,7 +249,7 @@ export const dict = { "go.title": "OpenCode Go | نماذج برمجة منخفضة التكلفة للجميع", "go.meta.description": - "يبدأ Go من $5 للشهر الأول، ثم $10/شهر، مع حدود طلب سخية لمدة 5 ساعات لـ GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7.", + "يبدأ Go من $5 للشهر الأول، ثم $10/شهر، مع حدود طلب سخية لمدة 5 ساعات لـ GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7.", "go.hero.title": "نماذج برمجة منخفضة التكلفة للجميع", "go.hero.body": "يجلب Go البرمجة الوكيلة للمبرمجين حول العالم. يوفر حدودًا سخية ووصولًا موثوقًا إلى أقوى النماذج مفتوحة المصدر، حتى تتمكن من البناء باستخدام وكلاء أقوياء دون القلق بشأن التكلفة أو التوفر.", @@ -300,7 +300,7 @@ export const dict = { "go.problem.item2": "حدود سخية ووصول موثوق", "go.problem.item3": "مصمم لأكبر عدد ممكن من المبرمجين", "go.problem.item4": - "يتضمن GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7", + "يتضمن GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7", "go.how.title": "كيف يعمل Go", "go.how.body": "يبدأ Go من $5 للشهر الأول، ثم $10/شهر. يمكنك استخدامه مع OpenCode أو أي وكيل.", "go.how.step1.title": "أنشئ حسابًا", @@ -324,7 +324,7 @@ export const dict = { "go.faq.a2": "يتضمن Go النماذج المدرجة أدناه، مع حدود سخية وإتاحة موثوقة.", "go.faq.q3": "هل Go هو نفسه Zen؟", "go.faq.a3": - "لا. Zen هو الدفع حسب الاستخدام، بينما يبدأ Go من $5 للشهر الأول، ثم $10/شهر، مع حدود سخية ووصول موثوق إلى نماذج المصدر المفتوح GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7.", + "لا. Zen هو الدفع حسب الاستخدام، بينما يبدأ Go من $5 للشهر الأول، ثم $10/شهر، مع حدود سخية ووصول موثوق إلى نماذج المصدر المفتوح GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7.", "go.faq.q4": "كم تكلفة Go؟", "go.faq.a4.p1.beforePricing": "تكلفة Go", "go.faq.a4.p1.pricingLink": "$5 للشهر الأول", @@ -347,7 +347,7 @@ export const dict = { "go.faq.q9": "ما الفرق بين النماذج المجانية وGo؟", "go.faq.a9": - "تشمل النماذج المجانية Big Pickle بالإضافة إلى النماذج الترويجية المتاحة في ذلك الوقت، مع حصة 200 طلب/يوم. يتضمن Go نماذج GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7 مع حصص طلبات أعلى مطبقة عبر نوافذ متجددة (5 ساعات، أسبوعيًا، وشهريًا)، تعادل تقريبًا 12 دولارًا كل 5 ساعات، و30 دولارًا في الأسبوع، و60 دولارًا في الشهر (تختلف أعداد الطلبات الفعلية حسب النموذج والاستخدام).", + "تشمل النماذج المجانية Big Pickle بالإضافة إلى النماذج الترويجية المتاحة في ذلك الوقت، مع حصة 200 طلب/يوم. يتضمن Go نماذج GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7 مع حصص طلبات أعلى مطبقة عبر نوافذ متجددة (5 ساعات، أسبوعيًا، وشهريًا)، تعادل تقريبًا 12 دولارًا كل 5 ساعات، و30 دولارًا في الأسبوع، و60 دولارًا في الشهر (تختلف أعداد الطلبات الفعلية حسب النموذج والاستخدام).", "zen.api.error.rateLimitExceeded": "تم تجاوز حد الطلبات. يرجى المحاولة مرة أخرى لاحقًا.", "zen.api.error.modelNotSupported": "النموذج {{model}} غير مدعوم", diff --git a/packages/console/app/src/i18n/br.ts b/packages/console/app/src/i18n/br.ts index d79b8350ae..cf7b68d259 100644 --- a/packages/console/app/src/i18n/br.ts +++ b/packages/console/app/src/i18n/br.ts @@ -253,7 +253,7 @@ export const dict = { "go.title": "OpenCode Go | Modelos de codificação de baixo custo para todos", "go.meta.description": - "O Go começa em $5 no primeiro mês, depois $10/mês, com limites generosos de solicitação de 5 horas para GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7.", + "O Go começa em $5 no primeiro mês, depois $10/mês, com limites generosos de solicitação de 5 horas para GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7.", "go.hero.title": "Modelos de codificação de baixo custo para todos", "go.hero.body": "O Go traz a codificação com agentes para programadores em todo o mundo. Oferecendo limites generosos e acesso confiável aos modelos de código aberto mais capazes, para que você possa construir com agentes poderosos sem se preocupar com custos ou disponibilidade.", @@ -305,7 +305,7 @@ export const dict = { "go.problem.item2": "Limites generosos e acesso confiável", "go.problem.item3": "Feito para o maior número possível de programadores", "go.problem.item4": - "Inclui GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7", + "Inclui GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7", "go.how.title": "Como o Go funciona", "go.how.body": "O Go começa em $5 no primeiro mês, depois $10/mês. Você pode usá-lo com o OpenCode ou qualquer agente.", @@ -331,7 +331,7 @@ export const dict = { "go.faq.a2": "O Go inclui os modelos listados abaixo, com limites generosos e acesso confiável.", "go.faq.q3": "O Go é o mesmo que o Zen?", "go.faq.a3": - "Não. Zen é pay-as-you-go, enquanto o Go começa em $5 no primeiro mês, depois $10/mês, com limites generosos e acesso confiável aos modelos open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7.", + "Não. Zen é pay-as-you-go, enquanto o Go começa em $5 no primeiro mês, depois $10/mês, com limites generosos e acesso confiável aos modelos open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7.", "go.faq.q4": "Quanto custa o Go?", "go.faq.a4.p1.beforePricing": "O Go custa", "go.faq.a4.p1.pricingLink": "$5 no primeiro mês", @@ -355,7 +355,7 @@ export const dict = { "go.faq.q9": "Qual a diferença entre os modelos gratuitos e o Go?", "go.faq.a9": - "Os modelos gratuitos incluem Big Pickle e modelos promocionais disponíveis no momento, com uma cota de 200 requisições/dia. O Go inclui GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7 com cotas de requisição mais altas aplicadas em janelas móveis (5 horas, semanal e mensal), aproximadamente equivalentes a $12 por 5 horas, $30 por semana e $60 por mês (as contagens reais de requisições variam de acordo com o modelo e o uso).", + "Os modelos gratuitos incluem Big Pickle e modelos promocionais disponíveis no momento, com uma cota de 200 requisições/dia. O Go inclui GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7 com cotas de requisição mais altas aplicadas em janelas móveis (5 horas, semanal e mensal), aproximadamente equivalentes a $12 por 5 horas, $30 por semana e $60 por mês (as contagens reais de requisições variam de acordo com o modelo e o uso).", "zen.api.error.rateLimitExceeded": "Limite de taxa excedido. Por favor, tente novamente mais tarde.", "zen.api.error.modelNotSupported": "Modelo {{model}} não suportado", diff --git a/packages/console/app/src/i18n/da.ts b/packages/console/app/src/i18n/da.ts index e806983967..90eff469a2 100644 --- a/packages/console/app/src/i18n/da.ts +++ b/packages/console/app/src/i18n/da.ts @@ -251,7 +251,7 @@ export const dict = { "go.title": "OpenCode Go | Kodningsmodeller til lav pris for alle", "go.meta.description": - "Go starter ved $5 for den første måned, derefter $10/måned, med generøse 5-timers anmodningsgrænser for GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7.", + "Go starter ved $5 for den første måned, derefter $10/måned, med generøse 5-timers anmodningsgrænser for GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7.", "go.hero.title": "Kodningsmodeller til lav pris for alle", "go.hero.body": "Go bringer agentisk kodning til programmører over hele verden. Med generøse grænser og pålidelig adgang til de mest kapable open source-modeller, så du kan bygge med kraftfulde agenter uden at bekymre dig om omkostninger eller tilgængelighed.", @@ -302,7 +302,7 @@ export const dict = { "go.problem.item2": "Generøse grænser og pålidelig adgang", "go.problem.item3": "Bygget til så mange programmører som muligt", "go.problem.item4": - "Inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7", + "Inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7", "go.how.title": "Hvordan Go virker", "go.how.body": "Go starter ved $5 for den første måned, derefter $10/måned. Du kan bruge det med OpenCode eller enhver agent.", @@ -328,7 +328,7 @@ export const dict = { "go.faq.a2": "Go inkluderer modellerne nedenfor med generøse grænser og pålidelig adgang.", "go.faq.q3": "Er Go det samme som Zen?", "go.faq.a3": - "Nej. Zen er pay-as-you-go, mens Go starter ved $5 for den første måned, derefter $10/måned, med generøse grænser og pålidelig adgang til open source-modellerne GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7.", + "Nej. Zen er pay-as-you-go, mens Go starter ved $5 for den første måned, derefter $10/måned, med generøse grænser og pålidelig adgang til open source-modellerne GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7.", "go.faq.q4": "Hvad koster Go?", "go.faq.a4.p1.beforePricing": "Go koster", "go.faq.a4.p1.pricingLink": "$5 første måned", @@ -351,7 +351,7 @@ export const dict = { "go.faq.q9": "Hvad er forskellen på gratis modeller og Go?", "go.faq.a9": - "Gratis modeller inkluderer Big Pickle plus salgsfremmende modeller tilgængelige på det tidspunkt, med en kvote på 200 forespørgsler/dag. Go inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7 med højere anmodningskvoter håndhævet over rullende vinduer (5-timers, ugentlig og månedlig), nogenlunde svarende til $12 pr. 5 timer, $30 pr. uge og $60 pr. måned (faktiske anmodningstal varierer efter model og brug).", + "Gratis modeller inkluderer Big Pickle plus salgsfremmende modeller tilgængelige på det tidspunkt, med en kvote på 200 forespørgsler/dag. Go inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7 med højere anmodningskvoter håndhævet over rullende vinduer (5-timers, ugentlig og månedlig), nogenlunde svarende til $12 pr. 5 timer, $30 pr. uge og $60 pr. måned (faktiske anmodningstal varierer efter model og brug).", "zen.api.error.rateLimitExceeded": "Hastighedsgrænse overskredet. Prøv venligst igen senere.", "zen.api.error.modelNotSupported": "Model {{model}} understøttes ikke", diff --git a/packages/console/app/src/i18n/de.ts b/packages/console/app/src/i18n/de.ts index bdd47e77cf..af339802fa 100644 --- a/packages/console/app/src/i18n/de.ts +++ b/packages/console/app/src/i18n/de.ts @@ -253,7 +253,7 @@ export const dict = { "go.title": "OpenCode Go | Kostengünstige Coding-Modelle für alle", "go.meta.description": - "Go beginnt bei $5 für den ersten Monat, danach $10/Monat, mit großzügigen 5-Stunden-Anfragelimits für GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 und MiniMax M2.7.", + "Go beginnt bei $5 für den ersten Monat, danach $10/Monat, mit großzügigen 5-Stunden-Anfragelimits für GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 und MiniMax M2.7.", "go.hero.title": "Kostengünstige Coding-Modelle für alle", "go.hero.body": "Go bringt Agentic Coding zu Programmierern auf der ganzen Welt. Mit großzügigen Limits und zuverlässigem Zugang zu den leistungsfähigsten Open-Source-Modellen, damit du mit leistungsstarken Agenten entwickeln kannst, ohne dir Gedanken über Kosten oder Verfügbarkeit zu machen.", @@ -304,7 +304,7 @@ export const dict = { "go.problem.item2": "Großzügige Limits und zuverlässiger Zugang", "go.problem.item3": "Für so viele Programmierer wie möglich gebaut", "go.problem.item4": - "Beinhaltet GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 und MiniMax M2.7", + "Beinhaltet GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 und MiniMax M2.7", "go.how.title": "Wie Go funktioniert", "go.how.body": "Go beginnt bei $5 für den ersten Monat, danach $10/Monat. Du kannst es mit OpenCode oder jedem Agenten nutzen.", @@ -330,7 +330,7 @@ export const dict = { "go.faq.a2": "Go umfasst die unten aufgeführten Modelle mit großzügigen Limits und zuverlässigem Zugriff.", "go.faq.q3": "Ist Go dasselbe wie Zen?", "go.faq.a3": - "Nein. Zen ist Pay-as-you-go, während Go bei $5 für den ersten Monat beginnt, danach $10/Monat, mit großzügigen Limits und zuverlässigem Zugang zu den Open-Source-Modellen GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 und MiniMax M2.7.", + "Nein. Zen ist Pay-as-you-go, während Go bei $5 für den ersten Monat beginnt, danach $10/Monat, mit großzügigen Limits und zuverlässigem Zugang zu den Open-Source-Modellen GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 und MiniMax M2.7.", "go.faq.q4": "Wie viel kostet Go?", "go.faq.a4.p1.beforePricing": "Go kostet", "go.faq.a4.p1.pricingLink": "$5 im ersten Monat", @@ -354,7 +354,7 @@ export const dict = { "go.faq.q9": "Was ist der Unterschied zwischen kostenlosen Modellen und Go?", "go.faq.a9": - "Kostenlose Modelle beinhalten Big Pickle sowie Werbemodelle, die zum jeweiligen Zeitpunkt verfügbar sind, mit einem Kontingent von 200 Anfragen/Tag. Go beinhaltet GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 und MiniMax M2.7 mit höheren Anfragekontingenten, die über rollierende Zeitfenster (5 Stunden, wöchentlich und monatlich) durchgesetzt werden, grob äquivalent zu $12 pro 5 Stunden, $30 pro Woche und $60 pro Monat (tatsächliche Anfragezahlen variieren je nach Modell und Nutzung).", + "Kostenlose Modelle beinhalten Big Pickle sowie Werbemodelle, die zum jeweiligen Zeitpunkt verfügbar sind, mit einem Kontingent von 200 Anfragen/Tag. Go beinhaltet GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 und MiniMax M2.7 mit höheren Anfragekontingenten, die über rollierende Zeitfenster (5 Stunden, wöchentlich und monatlich) durchgesetzt werden, grob äquivalent zu $12 pro 5 Stunden, $30 pro Woche und $60 pro Monat (tatsächliche Anfragezahlen variieren je nach Modell und Nutzung).", "zen.api.error.rateLimitExceeded": "Ratenlimit überschritten. Bitte versuche es später erneut.", "zen.api.error.modelNotSupported": "Modell {{model}} wird nicht unterstützt", diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index a242ff1010..f5cc954e5e 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -248,7 +248,7 @@ export const dict = { "go.title": "OpenCode Go | Low cost coding models for everyone", "go.meta.description": - "Go starts at $5 for your first month, then $10/month, with generous 5-hour request limits for GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, and MiniMax M2.7.", + "Go starts at $5 for your first month, then $10/month, with generous 5-hour request limits for GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, and MiniMax M2.7.", "go.banner.badge": "3x", "go.banner.text": "Kimi K2.6 gets 3× usage limits through April 27", "go.hero.title": "Low cost coding models for everyone", @@ -298,7 +298,7 @@ export const dict = { "go.problem.item2": "Generous limits and reliable access", "go.problem.item3": "Built for as many programmers as possible", "go.problem.item4": - "Includes GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, and MiniMax M2.7", + "Includes GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, and MiniMax M2.7", "go.how.title": "How Go works", "go.how.body": "Go starts at $5 for your first month, then $10/month. You can use it with OpenCode or any agent.", "go.how.step1.title": "Create an account", @@ -323,7 +323,7 @@ export const dict = { "go.faq.a2": "Go includes the models listed below, with generous limits and reliable access.", "go.faq.q3": "Is Go the same as Zen?", "go.faq.a3": - "No. Zen is pay-as-you-go, while Go starts at $5 for your first month, then $10/month, with generous limits and reliable access to open-source models GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, and MiniMax M2.7.", + "No. Zen is pay-as-you-go, while Go starts at $5 for your first month, then $10/month, with generous limits and reliable access to open-source models GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, and MiniMax M2.7.", "go.faq.q4": "How much does Go cost?", "go.faq.a4.p1.beforePricing": "Go costs", "go.faq.a4.p1.pricingLink": "$5 first month", @@ -347,7 +347,7 @@ export const dict = { "go.faq.q9": "What is the difference between free models and Go?", "go.faq.a9": - "Free models include Big Pickle plus promotional models available at the time, with a quota of 200 requests/day. Go includes GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, and MiniMax M2.7 with higher request quotas enforced across rolling windows (5-hour, weekly, and monthly), roughly equivalent to $12 per 5 hours, $30 per week, and $60 per month (actual request counts vary by model and usage).", + "Free models include Big Pickle plus promotional models available at the time, with a quota of 200 requests/day. Go includes GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, and MiniMax M2.7 with higher request quotas enforced across rolling windows (5-hour, weekly, and monthly), roughly equivalent to $12 per 5 hours, $30 per week, and $60 per month (actual request counts vary by model and usage).", "zen.api.error.rateLimitExceeded": "Rate limit exceeded. Please try again later.", "zen.api.error.modelNotSupported": "Model {{model}} not supported", diff --git a/packages/console/app/src/i18n/es.ts b/packages/console/app/src/i18n/es.ts index ddeff684b0..fb718e0541 100644 --- a/packages/console/app/src/i18n/es.ts +++ b/packages/console/app/src/i18n/es.ts @@ -254,7 +254,7 @@ export const dict = { "go.title": "OpenCode Go | Modelos de programación de bajo coste para todos", "go.meta.description": - "Go comienza en $5 el primer mes, luego 10 $/mes, con generosos límites de solicitudes de 5 horas para GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 y MiniMax M2.7.", + "Go comienza en $5 el primer mes, luego 10 $/mes, con generosos límites de solicitudes de 5 horas para GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 y MiniMax M2.7.", "go.hero.title": "Modelos de programación de bajo coste para todos", "go.hero.body": "Go lleva la programación agéntica a programadores de todo el mundo. Ofrece límites generosos y acceso fiable a los modelos de código abierto más capaces, para que puedas crear con agentes potentes sin preocuparte por el coste o la disponibilidad.", @@ -306,7 +306,7 @@ export const dict = { "go.problem.item2": "Límites generosos y acceso fiable", "go.problem.item3": "Creado para tantos programadores como sea posible", "go.problem.item4": - "Incluye GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 y MiniMax M2.7", + "Incluye GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 y MiniMax M2.7", "go.how.title": "Cómo funciona Go", "go.how.body": "Go comienza en $5 el primer mes, luego 10 $/mes. Puedes usarlo con OpenCode o cualquier agente.", "go.how.step1.title": "Crear una cuenta", @@ -331,7 +331,7 @@ export const dict = { "go.faq.a2": "Go incluye los modelos que se indican abajo, con límites generosos y acceso confiable.", "go.faq.q3": "¿Es Go lo mismo que Zen?", "go.faq.a3": - "No. Zen es pago por uso, mientras que Go comienza en $5 el primer mes, luego 10 $/mes, con límites generosos y acceso fiable a los modelos de código abierto GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 y MiniMax M2.7.", + "No. Zen es pago por uso, mientras que Go comienza en $5 el primer mes, luego 10 $/mes, con límites generosos y acceso fiable a los modelos de código abierto GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 y MiniMax M2.7.", "go.faq.q4": "¿Cuánto cuesta Go?", "go.faq.a4.p1.beforePricing": "Go cuesta", "go.faq.a4.p1.pricingLink": "$5 el primer mes", @@ -355,7 +355,7 @@ export const dict = { "go.faq.q9": "¿Cuál es la diferencia entre los modelos gratuitos y Go?", "go.faq.a9": - "Los modelos gratuitos incluyen Big Pickle más modelos promocionales disponibles en el momento, con una cuota de 200 solicitudes/día. Go incluye GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 y MiniMax M2.7 con cuotas de solicitud más altas aplicadas a través de ventanas móviles (5 horas, semanal y mensual), aproximadamente equivalente a 12 $ por 5 horas, 30 $ por semana y 60 $ por mes (los recuentos reales de solicitudes varían según el modelo y el uso).", + "Los modelos gratuitos incluyen Big Pickle más modelos promocionales disponibles en el momento, con una cuota de 200 solicitudes/día. Go incluye GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 y MiniMax M2.7 con cuotas de solicitud más altas aplicadas a través de ventanas móviles (5 horas, semanal y mensual), aproximadamente equivalente a 12 $ por 5 horas, 30 $ por semana y 60 $ por mes (los recuentos reales de solicitudes varían según el modelo y el uso).", "zen.api.error.rateLimitExceeded": "Límite de tasa excedido. Por favor, inténtalo de nuevo más tarde.", "zen.api.error.modelNotSupported": "Modelo {{model}} no soportado", diff --git a/packages/console/app/src/i18n/fr.ts b/packages/console/app/src/i18n/fr.ts index df892c98d3..976d93a29a 100644 --- a/packages/console/app/src/i18n/fr.ts +++ b/packages/console/app/src/i18n/fr.ts @@ -255,7 +255,7 @@ export const dict = { "go.title": "OpenCode Go | Modèles de code à faible coût pour tous", "go.meta.description": - "Go commence à $5 pour le premier mois, puis 10 $/mois, avec des limites de requêtes généreuses sur 5 heures pour GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 et MiniMax M2.7.", + "Go commence à $5 pour le premier mois, puis 10 $/mois, avec des limites de requêtes généreuses sur 5 heures pour GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 et MiniMax M2.7.", "go.hero.title": "Modèles de code à faible coût pour tous", "go.hero.body": "Go apporte le codage agentique aux programmeurs du monde entier. Offrant des limites généreuses et un accès fiable aux modèles open source les plus capables, pour que vous puissiez construire avec des agents puissants sans vous soucier du coût ou de la disponibilité.", @@ -306,7 +306,7 @@ export const dict = { "go.problem.item2": "Limites généreuses et accès fiable", "go.problem.item3": "Conçu pour autant de programmeurs que possible", "go.problem.item4": - "Inclut GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 et MiniMax M2.7", + "Inclut GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 et MiniMax M2.7", "go.how.title": "Comment fonctionne Go", "go.how.body": "Go commence à $5 pour le premier mois, puis 10 $/mois. Vous pouvez l'utiliser avec OpenCode ou n'importe quel agent.", @@ -332,7 +332,7 @@ export const dict = { "go.faq.a2": "Go inclut les modèles ci-dessous, avec des limites généreuses et un accès fiable.", "go.faq.q3": "Est-ce que Go est la même chose que Zen ?", "go.faq.a3": - "Non. Zen est un paiement à l'utilisation, tandis que Go commence à $5 pour le premier mois, puis 10 $/mois, avec des limites généreuses et un accès fiable aux modèles open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 et MiniMax M2.7.", + "Non. Zen est un paiement à l'utilisation, tandis que Go commence à $5 pour le premier mois, puis 10 $/mois, avec des limites généreuses et un accès fiable aux modèles open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 et MiniMax M2.7.", "go.faq.q4": "Combien coûte Go ?", "go.faq.a4.p1.beforePricing": "Go coûte", "go.faq.a4.p1.pricingLink": "$5 le premier mois", @@ -355,7 +355,7 @@ export const dict = { "Oui, vous pouvez utiliser Go avec n'importe quel agent. Suivez les instructions de configuration dans votre agent de code préféré.", "go.faq.q9": "Quelle est la différence entre les modèles gratuits et Go ?", "go.faq.a9": - "Les modèles gratuits incluent Big Pickle ainsi que des modèles promotionnels disponibles à ce moment-là, avec un quota de 200 requêtes/jour. Go inclut GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 et MiniMax M2.7 avec des quotas de requêtes plus élevés appliqués sur des fenêtres glissantes (5 heures, hebdomadaire et mensuelle), à peu près équivalent à 12 $ par 5 heures, 30 $ par semaine et 60 $ par mois (le nombre réel de requêtes varie selon le modèle et l'utilisation).", + "Les modèles gratuits incluent Big Pickle ainsi que des modèles promotionnels disponibles à ce moment-là, avec un quota de 200 requêtes/jour. Go inclut GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 et MiniMax M2.7 avec des quotas de requêtes plus élevés appliqués sur des fenêtres glissantes (5 heures, hebdomadaire et mensuelle), à peu près équivalent à 12 $ par 5 heures, 30 $ par semaine et 60 $ par mois (le nombre réel de requêtes varie selon le modèle et l'utilisation).", "zen.api.error.rateLimitExceeded": "Limite de débit dépassée. Veuillez réessayer plus tard.", "zen.api.error.modelNotSupported": "Modèle {{model}} non pris en charge", diff --git a/packages/console/app/src/i18n/it.ts b/packages/console/app/src/i18n/it.ts index 67a73aaeef..6069ad73ce 100644 --- a/packages/console/app/src/i18n/it.ts +++ b/packages/console/app/src/i18n/it.ts @@ -251,7 +251,7 @@ export const dict = { "go.title": "OpenCode Go | Modelli di coding a basso costo per tutti", "go.meta.description": - "Go inizia a $5 per il primo mese, poi $10/mese, con generosi limiti di richiesta di 5 ore per GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7.", + "Go inizia a $5 per il primo mese, poi $10/mese, con generosi limiti di richiesta di 5 ore per GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7.", "go.hero.title": "Modelli di coding a basso costo per tutti", "go.hero.body": "Go porta il coding agentico ai programmatori di tutto il mondo. Offrendo limiti generosi e un accesso affidabile ai modelli open source più capaci, in modo da poter costruire con agenti potenti senza preoccuparsi dei costi o della disponibilità.", @@ -302,7 +302,7 @@ export const dict = { "go.problem.item2": "Limiti generosi e accesso affidabile", "go.problem.item3": "Costruito per il maggior numero possibile di programmatori", "go.problem.item4": - "Include GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7", + "Include GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7", "go.how.title": "Come funziona Go", "go.how.body": "Go inizia a $5 per il primo mese, poi $10/mese. Puoi usarlo con OpenCode o qualsiasi agente.", "go.how.step1.title": "Crea un account", @@ -327,7 +327,7 @@ export const dict = { "go.faq.a2": "Go include i modelli elencati di seguito, con limiti generosi e accesso affidabile.", "go.faq.q3": "Go è lo stesso di Zen?", "go.faq.a3": - "No. Zen è a consumo, mentre Go inizia a $5 per il primo mese, poi $10/mese, con limiti generosi e accesso affidabile ai modelli open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7.", + "No. Zen è a consumo, mentre Go inizia a $5 per il primo mese, poi $10/mese, con limiti generosi e accesso affidabile ai modelli open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7.", "go.faq.q4": "Quanto costa Go?", "go.faq.a4.p1.beforePricing": "Go costa", "go.faq.a4.p1.pricingLink": "$5 il primo mese", @@ -351,7 +351,7 @@ export const dict = { "go.faq.q9": "Qual è la differenza tra i modelli gratuiti e Go?", "go.faq.a9": - "I modelli gratuiti includono Big Pickle più modelli promozionali disponibili al momento, con una quota di 200 richieste/giorno. Go include GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7 con quote di richiesta più elevate applicate su finestre mobili (5 ore, settimanale e mensile), approssimativamente equivalenti a $12 ogni 5 ore, $30 a settimana e $60 al mese (il conteggio effettivo delle richieste varia in base al modello e all'utilizzo).", + "I modelli gratuiti includono Big Pickle più modelli promozionali disponibili al momento, con una quota di 200 richieste/giorno. Go include GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7 con quote di richiesta più elevate applicate su finestre mobili (5 ore, settimanale e mensile), approssimativamente equivalenti a $12 ogni 5 ore, $30 a settimana e $60 al mese (il conteggio effettivo delle richieste varia in base al modello e all'utilizzo).", "zen.api.error.rateLimitExceeded": "Limite di richieste superato. Riprova più tardi.", "zen.api.error.modelNotSupported": "Modello {{model}} non supportato", diff --git a/packages/console/app/src/i18n/ja.ts b/packages/console/app/src/i18n/ja.ts index 541fdd56c1..dcf2f9b52f 100644 --- a/packages/console/app/src/i18n/ja.ts +++ b/packages/console/app/src/i18n/ja.ts @@ -250,7 +250,7 @@ export const dict = { "go.title": "OpenCode Go | すべての人のための低価格なコーディングモデル", "go.meta.description": - "Goは最初の月$5、その後$10/月で、GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7に対して5時間のゆとりあるリクエスト上限があります。", + "Goは最初の月$5、その後$10/月で、GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7に対して5時間のゆとりあるリクエスト上限があります。", "go.hero.title": "すべての人のための低価格なコーディングモデル", "go.hero.body": "Goは、世界中のプログラマーにエージェント型コーディングをもたらします。最も高性能なオープンソースモデルへの十分な制限と安定したアクセスを提供し、コストや可用性を気にすることなく強力なエージェントで構築できます。", @@ -302,7 +302,7 @@ export const dict = { "go.problem.item2": "十分な制限と安定したアクセス", "go.problem.item3": "できるだけ多くのプログラマーのために構築", "go.problem.item4": - "GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7を含む", + "GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7を含む", "go.how.title": "Goの仕組み", "go.how.body": "Goは最初の月$5、その後$10/月で始まります。OpenCodeまたは任意のエージェントで使えます。", "go.how.step1.title": "アカウントを作成", @@ -327,7 +327,7 @@ export const dict = { "go.faq.a2": "Go には、十分な利用上限と安定したアクセスを備えた、以下のモデルが含まれます。", "go.faq.q3": "GoはZenと同じですか?", "go.faq.a3": - "いいえ。Zenは従量課金制ですが、Goは最初の月$5、その後$10/月で始まり、GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7のオープンソースモデルに対して、ゆとりある上限と信頼できるアクセスを提供します。", + "いいえ。Zenは従量課金制ですが、Goは最初の月$5、その後$10/月で始まり、GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7のオープンソースモデルに対して、ゆとりある上限と信頼できるアクセスを提供します。", "go.faq.q4": "Goの料金は?", "go.faq.a4.p1.beforePricing": "Goは", "go.faq.a4.p1.pricingLink": "最初の月$5", @@ -351,7 +351,7 @@ export const dict = { "go.faq.q9": "無料モデルとGoの違いは何ですか?", "go.faq.a9": - "無料モデルにはBig Pickleと、その時点で利用可能なプロモーションモデルが含まれ、1日200リクエストの制限があります。GoにはGLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7が含まれ、ローリングウィンドウ(5時間、週間、月間)全体でより高いリクエスト制限が適用されます。これは概算で5時間あたり$12、週間$30、月間$60相当です(実際のリクエスト数はモデルと使用状況により異なります)。", + "無料モデルにはBig Pickleと、その時点で利用可能なプロモーションモデルが含まれ、1日200リクエストの制限があります。GoにはGLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7が含まれ、ローリングウィンドウ(5時間、週間、月間)全体でより高いリクエスト制限が適用されます。これは概算で5時間あたり$12、週間$30、月間$60相当です(実際のリクエスト数はモデルと使用状況により異なります)。", "zen.api.error.rateLimitExceeded": "レート制限を超えました。後でもう一度お試しください。", "zen.api.error.modelNotSupported": "モデル {{model}} はサポートされていません", diff --git a/packages/console/app/src/i18n/ko.ts b/packages/console/app/src/i18n/ko.ts index 5d459425be..f2a67fbbae 100644 --- a/packages/console/app/src/i18n/ko.ts +++ b/packages/console/app/src/i18n/ko.ts @@ -247,7 +247,7 @@ export const dict = { "go.title": "OpenCode Go | 모두를 위한 저비용 코딩 모델", "go.meta.description": - "Go는 첫 달 $5, 이후 $10/월로 시작하며, GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7에 대해 넉넉한 5시간 요청 한도를 제공합니다.", + "Go는 첫 달 $5, 이후 $10/월로 시작하며, GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7에 대해 넉넉한 5시간 요청 한도를 제공합니다.", "go.hero.title": "모두를 위한 저비용 코딩 모델", "go.hero.body": "Go는 전 세계 프로그래머들에게 에이전트 코딩을 제공합니다. 가장 유능한 오픈 소스 모델에 대한 넉넉한 한도와 안정적인 액세스를 제공하므로, 비용이나 가용성 걱정 없이 강력한 에이전트로 빌드할 수 있습니다.", @@ -299,7 +299,7 @@ export const dict = { "go.problem.item2": "넉넉한 한도와 안정적인 액세스", "go.problem.item3": "가능한 한 많은 프로그래머를 위해 제작됨", "go.problem.item4": - "GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7 포함", + "GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7 포함", "go.how.title": "Go 작동 방식", "go.how.body": "Go는 첫 달 $5, 이후 $10/월로 시작합니다. OpenCode 또는 어떤 에이전트와도 함께 사용할 수 있습니다.", "go.how.step1.title": "계정 생성", @@ -323,7 +323,7 @@ export const dict = { "go.faq.a2": "Go에는 넉넉한 한도와 안정적인 액세스를 제공하는 아래 모델이 포함됩니다.", "go.faq.q3": "Go는 Zen과 같은가요?", "go.faq.a3": - "아니요. Zen은 종량제인 반면, Go는 첫 달 $5, 이후 $10/월로 시작하며, GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7 오픈 소스 모델에 대한 넉넉한 한도와 안정적인 액세스를 제공합니다.", + "아니요. Zen은 종량제인 반면, Go는 첫 달 $5, 이후 $10/월로 시작하며, GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7 오픈 소스 모델에 대한 넉넉한 한도와 안정적인 액세스를 제공합니다.", "go.faq.q4": "Go 비용은 얼마인가요?", "go.faq.a4.p1.beforePricing": "Go 비용은", "go.faq.a4.p1.pricingLink": "첫 달 $5", @@ -346,7 +346,7 @@ export const dict = { "go.faq.q9": "무료 모델과 Go의 차이점은 무엇인가요?", "go.faq.a9": - "무료 모델에는 Big Pickle과 당시 사용 가능한 프로모션 모델이 포함되며, 하루 200회 요청 할당량이 적용됩니다. Go는 GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7를 포함하며, 롤링 윈도우(5시간, 주간, 월간)에 걸쳐 더 높은 요청 할당량을 적용합니다. 이는 대략 5시간당 $12, 주당 $30, 월 $60에 해당합니다(실제 요청 수는 모델 및 사용량에 따라 다름).", + "무료 모델에는 Big Pickle과 당시 사용 가능한 프로모션 모델이 포함되며, 하루 200회 요청 할당량이 적용됩니다. Go는 GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7를 포함하며, 롤링 윈도우(5시간, 주간, 월간)에 걸쳐 더 높은 요청 할당량을 적용합니다. 이는 대략 5시간당 $12, 주당 $30, 월 $60에 해당합니다(실제 요청 수는 모델 및 사용량에 따라 다름).", "zen.api.error.rateLimitExceeded": "속도 제한을 초과했습니다. 나중에 다시 시도해 주세요.", "zen.api.error.modelNotSupported": "{{model}} 모델은 지원되지 않습니다", diff --git a/packages/console/app/src/i18n/no.ts b/packages/console/app/src/i18n/no.ts index af2b018b00..0207a57760 100644 --- a/packages/console/app/src/i18n/no.ts +++ b/packages/console/app/src/i18n/no.ts @@ -251,7 +251,7 @@ export const dict = { "go.title": "OpenCode Go | Rimelige kodemodeller for alle", "go.meta.description": - "Go starter på $5 for den første måneden, deretter $10/måned, med sjenerøse 5-timers forespørselsgrenser for GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7.", + "Go starter på $5 for den første måneden, deretter $10/måned, med sjenerøse 5-timers forespørselsgrenser for GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7.", "go.hero.title": "Rimelige kodemodeller for alle", "go.hero.body": "Go bringer agent-koding til programmerere over hele verden. Med rause grenser og pålitelig tilgang til de mest kapable åpen kildekode-modellene, kan du bygge med kraftige agenter uten å bekymre deg for kostnader eller tilgjengelighet.", @@ -302,7 +302,7 @@ export const dict = { "go.problem.item2": "Rause grenser og pålitelig tilgang", "go.problem.item3": "Bygget for så mange programmerere som mulig", "go.problem.item4": - "Inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7", + "Inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7", "go.how.title": "Hvordan Go fungerer", "go.how.body": "Go starter på $5 for den første måneden, deretter $10/måned. Du kan bruke det med OpenCode eller hvilken som helst agent.", @@ -328,7 +328,7 @@ export const dict = { "go.faq.a2": "Go inkluderer modellene nedenfor, med høye grenser og pålitelig tilgang.", "go.faq.q3": "Er Go det samme som Zen?", "go.faq.a3": - "Nei. Zen er betaling etter bruk, mens Go starter på $5 for den første måneden, deretter $10/måned, med sjenerøse grenser og pålitelig tilgang til åpen kildekode-modellene GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7.", + "Nei. Zen er betaling etter bruk, mens Go starter på $5 for den første måneden, deretter $10/måned, med sjenerøse grenser og pålitelig tilgang til åpen kildekode-modellene GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7.", "go.faq.q4": "Hva koster Go?", "go.faq.a4.p1.beforePricing": "Go koster", "go.faq.a4.p1.pricingLink": "$5 første måned", @@ -352,7 +352,7 @@ export const dict = { "go.faq.q9": "Hva er forskjellen mellom gratis modeller og Go?", "go.faq.a9": - "Gratis modeller inkluderer Big Pickle pluss kampanjemodeller tilgjengelig på det tidspunktet, med en kvote på 200 forespørsler/dag. Go inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7 med høyere kvoter håndhevet over rullerende vinduer (5 timer, ukentlig og månedlig), omtrent tilsvarende $12 per 5 timer, $30 per uke og $60 per måned (faktiske forespørselsantall varierer etter modell og bruk).", + "Gratis modeller inkluderer Big Pickle pluss kampanjemodeller tilgjengelig på det tidspunktet, med en kvote på 200 forespørsler/dag. Go inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7 med høyere kvoter håndhevet over rullerende vinduer (5 timer, ukentlig og månedlig), omtrent tilsvarende $12 per 5 timer, $30 per uke og $60 per måned (faktiske forespørselsantall varierer etter modell og bruk).", "zen.api.error.rateLimitExceeded": "Rate limit overskredet. Vennligst prøv igjen senere.", "zen.api.error.modelNotSupported": "Modell {{model}} støttes ikke", diff --git a/packages/console/app/src/i18n/pl.ts b/packages/console/app/src/i18n/pl.ts index f2219487bc..554a2d0aab 100644 --- a/packages/console/app/src/i18n/pl.ts +++ b/packages/console/app/src/i18n/pl.ts @@ -252,7 +252,7 @@ export const dict = { "go.title": "OpenCode Go | Niskokosztowe modele do kodowania dla każdego", "go.meta.description": - "Go zaczyna się od $5 za pierwszy miesiąc, potem $10/miesiąc, z hojnymi 5-godzinnymi limitami zapytań dla GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 i MiniMax M2.7.", + "Go zaczyna się od $5 za pierwszy miesiąc, potem $10/miesiąc, z hojnymi 5-godzinnymi limitami zapytań dla GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 i MiniMax M2.7.", "go.hero.title": "Niskokosztowe modele do kodowania dla każdego", "go.hero.body": "Go udostępnia programowanie z agentami programistom na całym świecie. Oferuje hojne limity i niezawodny dostęp do najzdolniejszych modeli open source, dzięki czemu możesz budować za pomocą potężnych agentów, nie martwiąc się o koszty czy dostępność.", @@ -303,7 +303,7 @@ export const dict = { "go.problem.item2": "Hojne limity i niezawodny dostęp", "go.problem.item3": "Stworzony dla jak największej liczby programistów", "go.problem.item4": - "Zawiera GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 i MiniMax M2.7", + "Zawiera GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 i MiniMax M2.7", "go.how.title": "Jak działa Go", "go.how.body": "Go zaczyna się od $5 za pierwszy miesiąc, potem $10/miesiąc. Możesz go używać z OpenCode lub dowolnym agentem.", @@ -329,7 +329,7 @@ export const dict = { "go.faq.a2": "Go obejmuje poniższe modele z wysokimi limitami i niezawodnym dostępem.", "go.faq.q3": "Czy Go to to samo co Zen?", "go.faq.a3": - "Nie. Zen to model płatności za użycie, podczas gdy Go zaczyna się od $5 za pierwszy miesiąc, potem $10/miesiąc, z hojnymi limitami i niezawodnym dostępem do modeli open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 i MiniMax M2.7.", + "Nie. Zen to model płatności za użycie, podczas gdy Go zaczyna się od $5 za pierwszy miesiąc, potem $10/miesiąc, z hojnymi limitami i niezawodnym dostępem do modeli open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 i MiniMax M2.7.", "go.faq.q4": "Ile kosztuje Go?", "go.faq.a4.p1.beforePricing": "Go kosztuje", "go.faq.a4.p1.pricingLink": "$5 za pierwszy miesiąc", @@ -353,7 +353,7 @@ export const dict = { "go.faq.q9": "Jaka jest różnica między darmowymi modelami a Go?", "go.faq.a9": - "Darmowe modele obejmują Big Pickle oraz modele promocyjne dostępne w danym momencie, z limitem 200 zapytań/dzień. Go zawiera GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 i MiniMax M2.7 z wyższymi limitami zapytań egzekwowanymi w oknach kroczących (5-godzinnych, tygodniowych i miesięcznych), w przybliżeniu równoważnymi $12 na 5 godzin, $30 tygodniowo i $60 miesięcznie (rzeczywista liczba zapytań zależy od modelu i użycia).", + "Darmowe modele obejmują Big Pickle oraz modele promocyjne dostępne w danym momencie, z limitem 200 zapytań/dzień. Go zawiera GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 i MiniMax M2.7 z wyższymi limitami zapytań egzekwowanymi w oknach kroczących (5-godzinnych, tygodniowych i miesięcznych), w przybliżeniu równoważnymi $12 na 5 godzin, $30 tygodniowo i $60 miesięcznie (rzeczywista liczba zapytań zależy od modelu i użycia).", "zen.api.error.rateLimitExceeded": "Przekroczono limit zapytań. Spróbuj ponownie później.", "zen.api.error.modelNotSupported": "Model {{model}} nie jest obsługiwany", diff --git a/packages/console/app/src/i18n/ru.ts b/packages/console/app/src/i18n/ru.ts index 8fd76226e4..1e50134199 100644 --- a/packages/console/app/src/i18n/ru.ts +++ b/packages/console/app/src/i18n/ru.ts @@ -255,7 +255,7 @@ export const dict = { "go.title": "OpenCode Go | Недорогие модели для кодинга для всех", "go.meta.description": - "Go начинается с $5 за первый месяц, затем $10/месяц, с щедрыми лимитами запросов за 5 часов для GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 и MiniMax M2.7.", + "Go начинается с $5 за первый месяц, затем $10/месяц, с щедрыми лимитами запросов за 5 часов для GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 и MiniMax M2.7.", "go.hero.title": "Недорогие модели для кодинга для всех", "go.hero.body": "Go открывает доступ к агентам-программистам разработчикам по всему миру. Предлагая щедрые лимиты и надежный доступ к наиболее способным моделям с открытым исходным кодом, вы можете создавать проекты с мощными агентами, не беспокоясь о затратах или доступности.", @@ -307,7 +307,7 @@ export const dict = { "go.problem.item2": "Щедрые лимиты и надежный доступ", "go.problem.item3": "Создан для максимального числа программистов", "go.problem.item4": - "Включает GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 и MiniMax M2.7", + "Включает GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 и MiniMax M2.7", "go.how.title": "Как работает Go", "go.how.body": "Go начинается с $5 за первый месяц, затем $10/месяц. Вы можете использовать его с OpenCode или любым агентом.", @@ -333,7 +333,7 @@ export const dict = { "go.faq.a2": "Go включает перечисленные ниже модели с щедрыми лимитами и надежным доступом.", "go.faq.q3": "Go — это то же самое, что и Zen?", "go.faq.a3": - "Нет. Zen - это оплата по мере использования, в то время как Go начинается с $5 за первый месяц, затем $10/месяц, с щедрыми лимитами и надежным доступом к моделям с открытым исходным кодом GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 и MiniMax M2.7.", + "Нет. Zen - это оплата по мере использования, в то время как Go начинается с $5 за первый месяц, затем $10/месяц, с щедрыми лимитами и надежным доступом к моделям с открытым исходным кодом GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 и MiniMax M2.7.", "go.faq.q4": "Сколько стоит Go?", "go.faq.a4.p1.beforePricing": "Go стоит", "go.faq.a4.p1.pricingLink": "$5 за первый месяц", @@ -357,7 +357,7 @@ export const dict = { "go.faq.q9": "В чем разница между бесплатными моделями и Go?", "go.faq.a9": - "Бесплатные модели включают Big Pickle плюс промо-модели, доступные на данный момент, с квотой 200 запросов/день. Go включает GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 и MiniMax M2.7 с более высокими квотами запросов, применяемыми в скользящих окнах (5 часов, неделя и месяц), что примерно эквивалентно $12 за 5 часов, $30 в неделю и $60 в месяц (фактическое количество запросов зависит от модели и использования).", + "Бесплатные модели включают Big Pickle плюс промо-модели, доступные на данный момент, с квотой 200 запросов/день. Go включает GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 и MiniMax M2.7 с более высокими квотами запросов, применяемыми в скользящих окнах (5 часов, неделя и месяц), что примерно эквивалентно $12 за 5 часов, $30 в неделю и $60 в месяц (фактическое количество запросов зависит от модели и использования).", "zen.api.error.rateLimitExceeded": "Превышен лимит запросов. Пожалуйста, попробуйте позже.", "zen.api.error.modelNotSupported": "Модель {{model}} не поддерживается", diff --git a/packages/console/app/src/i18n/th.ts b/packages/console/app/src/i18n/th.ts index efe535094f..3a2dc4ba4c 100644 --- a/packages/console/app/src/i18n/th.ts +++ b/packages/console/app/src/i18n/th.ts @@ -250,7 +250,7 @@ export const dict = { "go.title": "OpenCode Go | โมเดลเขียนโค้ดราคาประหยัดสำหรับทุกคน", "go.meta.description": - "Go เริ่มต้นที่ $5 สำหรับเดือนแรก จากนั้น $10/เดือน พร้อมขีดจำกัดคำขอ 5 ชั่วโมงที่เอื้อเฟื้อสำหรับ GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 และ MiniMax M2.7", + "Go เริ่มต้นที่ $5 สำหรับเดือนแรก จากนั้น $10/เดือน พร้อมขีดจำกัดคำขอ 5 ชั่วโมงที่เอื้อเฟื้อสำหรับ GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 และ MiniMax M2.7", "go.hero.title": "โมเดลเขียนโค้ดราคาประหยัดสำหรับทุกคน", "go.hero.body": "Go นำการเขียนโค้ดแบบเอเจนต์มาสู่นักเขียนโปรแกรมทั่วโลก เสนอขีดจำกัดที่กว้างขวางและการเข้าถึงโมเดลโอเพนซอร์สที่มีความสามารถสูงสุดได้อย่างน่าเชื่อถือ เพื่อให้คุณสามารถสร้างสรรค์ด้วยเอเจนต์ที่ทรงพลังโดยไม่ต้องกังวลเรื่องค่าใช้จ่ายหรือความพร้อมใช้งาน", @@ -300,7 +300,7 @@ export const dict = { "go.problem.item2": "ขีดจำกัดที่กว้างขวางและการเข้าถึงที่เชื่อถือได้", "go.problem.item3": "สร้างขึ้นเพื่อโปรแกรมเมอร์จำนวนมากที่สุดเท่าที่จะเป็นไปได้", "go.problem.item4": - "รวมถึง GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 และ MiniMax M2.7", + "รวมถึง GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 และ MiniMax M2.7", "go.how.title": "Go ทำงานอย่างไร", "go.how.body": "Go เริ่มต้นที่ $5 สำหรับเดือนแรก จากนั้น $10/เดือน คุณสามารถใช้กับ OpenCode หรือเอเจนต์ใดก็ได้", "go.how.step1.title": "สร้างบัญชี", @@ -325,7 +325,7 @@ export const dict = { "go.faq.a2": "Go รวมโมเดลด้านล่างนี้ พร้อมขีดจำกัดที่มากและการเข้าถึงที่เชื่อถือได้", "go.faq.q3": "Go เหมือนกับ Zen หรือไม่?", "go.faq.a3": - "ไม่ Zen เป็นแบบจ่ายตามการใช้งาน ในขณะที่ Go เริ่มต้นที่ $5 สำหรับเดือนแรก จากนั้น $10/เดือน พร้อมขีดจำกัดที่เอื้อเฟื้อและการเข้าถึงโมเดลโอเพนซอร์ส GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 และ MiniMax M2.7 อย่างเชื่อถือได้", + "ไม่ Zen เป็นแบบจ่ายตามการใช้งาน ในขณะที่ Go เริ่มต้นที่ $5 สำหรับเดือนแรก จากนั้น $10/เดือน พร้อมขีดจำกัดที่เอื้อเฟื้อและการเข้าถึงโมเดลโอเพนซอร์ส GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 และ MiniMax M2.7 อย่างเชื่อถือได้", "go.faq.q4": "Go ราคาเท่าไหร่?", "go.faq.a4.p1.beforePricing": "Go ราคา", "go.faq.a4.p1.pricingLink": "$5 เดือนแรก", @@ -348,7 +348,7 @@ export const dict = { "go.faq.q9": "ความแตกต่างระหว่างโมเดลฟรีและ Go คืออะไร?", "go.faq.a9": - "โมเดลฟรีรวมถึง Big Pickle บวกกับโมเดลโปรโมชั่นที่มีให้ในขณะนั้น ด้วยโควต้า 200 คำขอ/วัน Go รวมถึง GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 และ MiniMax M2.7 ที่มีโควต้าคำขอสูงกว่า ซึ่งบังคับใช้ผ่านช่วงเวลาหมุนเวียน (5 ชั่วโมง, รายสัปดาห์ และรายเดือน) เทียบเท่าประมาณ $12 ต่อ 5 ชั่วโมง, $30 ต่อสัปดาห์ และ $60 ต่อเดือน (จำนวนคำขอจริงจะแตกต่างกันไปตามโมเดลและการใช้งาน)", + "โมเดลฟรีรวมถึง Big Pickle บวกกับโมเดลโปรโมชั่นที่มีให้ในขณะนั้น ด้วยโควต้า 200 คำขอ/วัน Go รวมถึง GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 และ MiniMax M2.7 ที่มีโควต้าคำขอสูงกว่า ซึ่งบังคับใช้ผ่านช่วงเวลาหมุนเวียน (5 ชั่วโมง, รายสัปดาห์ และรายเดือน) เทียบเท่าประมาณ $12 ต่อ 5 ชั่วโมง, $30 ต่อสัปดาห์ และ $60 ต่อเดือน (จำนวนคำขอจริงจะแตกต่างกันไปตามโมเดลและการใช้งาน)", "zen.api.error.rateLimitExceeded": "เกินขีดจำกัดอัตราการใช้งาน กรุณาลองใหม่ในภายหลัง", "zen.api.error.modelNotSupported": "ไม่รองรับโมเดล {{model}}", diff --git a/packages/console/app/src/i18n/tr.ts b/packages/console/app/src/i18n/tr.ts index 114dcbdb0d..e2370f83c2 100644 --- a/packages/console/app/src/i18n/tr.ts +++ b/packages/console/app/src/i18n/tr.ts @@ -253,7 +253,7 @@ export const dict = { "go.title": "OpenCode Go | Herkes için düşük maliyetli kodlama modelleri", "go.meta.description": - "Go ilk ay $5, sonrasında ayda 10$ fiyatıyla başlar; GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 ve MiniMax M2.7 için cömert 5 saatlik istek limitleri sunar.", + "Go ilk ay $5, sonrasında ayda 10$ fiyatıyla başlar; GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 ve MiniMax M2.7 için cömert 5 saatlik istek limitleri sunar.", "go.hero.title": "Herkes için düşük maliyetli kodlama modelleri", "go.hero.body": "Go, dünya çapındaki programcılara ajan tabanlı kodlama getiriyor. En yetenekli açık kaynaklı modellere cömert limitler ve güvenilir erişim sunarak, maliyet veya erişilebilirlik konusunda endişelenmeden güçlü ajanlarla geliştirme yapmanızı sağlar.", @@ -305,7 +305,7 @@ export const dict = { "go.problem.item2": "Cömert limitler ve güvenilir erişim", "go.problem.item3": "Mümkün olduğunca çok programcı için geliştirildi", "go.problem.item4": - "GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 ve MiniMax M2.7 içerir", + "GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 ve MiniMax M2.7 içerir", "go.how.title": "Go nasıl çalışır?", "go.how.body": "Go ilk ay $5, sonrasında ayda 10$ fiyatıyla başlar. OpenCode veya herhangi bir ajanla kullanabilirsiniz.", @@ -331,7 +331,7 @@ export const dict = { "go.faq.a2": "Go, aşağıda listelenen modelleri cömert limitler ve güvenilir erişimle sunar.", "go.faq.q3": "Go, Zen ile aynı mı?", "go.faq.a3": - "Hayır. Zen kullandıkça öde modelidir, Go ise ilk ay $5, sonrasında ayda 10$ fiyatıyla başlar; GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 ve MiniMax M2.7 açık kaynak modellerine cömert limitler ve güvenilir erişim sunar.", + "Hayır. Zen kullandıkça öde modelidir, Go ise ilk ay $5, sonrasında ayda 10$ fiyatıyla başlar; GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 ve MiniMax M2.7 açık kaynak modellerine cömert limitler ve güvenilir erişim sunar.", "go.faq.q4": "Go ne kadar?", "go.faq.a4.p1.beforePricing": "Go'nun maliyeti", "go.faq.a4.p1.pricingLink": "İlk ay $5", @@ -355,7 +355,7 @@ export const dict = { "go.faq.q9": "Ücretsiz modeller ve Go arasındaki fark nedir?", "go.faq.a9": - "Ücretsiz modeller, günlük 200 istek kotası ile Big Pickle ve o sırada mevcut olan promosyonel modelleri içerir. Go ise GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 ve MiniMax M2.7 modellerini; yuvarlanan pencereler (5 saatlik, haftalık ve aylık) üzerinden uygulanan daha yüksek istek kotalarıyla içerir. Bu kotalar kabaca her 5 saatte 12$, haftada 30$ ve ayda 60$ değerine eşdeğerdir (gerçek istek sayıları modele ve kullanıma göre değişir).", + "Ücretsiz modeller, günlük 200 istek kotası ile Big Pickle ve o sırada mevcut olan promosyonel modelleri içerir. Go ise GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 ve MiniMax M2.7 modellerini; yuvarlanan pencereler (5 saatlik, haftalık ve aylık) üzerinden uygulanan daha yüksek istek kotalarıyla içerir. Bu kotalar kabaca her 5 saatte 12$, haftada 30$ ve ayda 60$ değerine eşdeğerdir (gerçek istek sayıları modele ve kullanıma göre değişir).", "zen.api.error.rateLimitExceeded": "İstek limiti aşıldı. Lütfen daha sonra tekrar deneyin.", "zen.api.error.modelNotSupported": "{{model}} modeli desteklenmiyor", diff --git a/packages/console/app/src/i18n/zh.ts b/packages/console/app/src/i18n/zh.ts index 72a2a4570d..649384c23b 100644 --- a/packages/console/app/src/i18n/zh.ts +++ b/packages/console/app/src/i18n/zh.ts @@ -241,7 +241,7 @@ export const dict = { "go.title": "OpenCode Go | 人人可用的低成本编程模型", "go.meta.description": - "Go 首月 $5,之后 $10/月,提供对 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 和 MiniMax M2.7 的 5 小时充裕请求额度。", + "Go 首月 $5,之后 $10/月,提供对 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 和 MiniMax M2.7 的 5 小时充裕请求额度。", "go.hero.title": "人人可用的低成本编程模型", "go.hero.body": "Go 将代理编程带给全世界的程序员。提供充裕的限额和对最强大的开源模型的可靠访问,让您可以利用强大的代理进行构建,而无需担心成本或可用性。", @@ -291,7 +291,7 @@ export const dict = { "go.problem.item2": "充裕的限额和可靠的访问", "go.problem.item3": "为尽可能多的程序员打造", "go.problem.item4": - "包含 GLM-5.1, GLM-5, Kimi K2.5、Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 和 MiniMax M2.7", + "包含 GLM-5.1, GLM-5, Kimi K2.5、Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 和 MiniMax M2.7", "go.how.title": "Go 如何工作", "go.how.body": "Go 起价为首月 $5,之后 $10/月。您可以将其与 OpenCode 或任何代理搭配使用。", "go.how.step1.title": "创建账户", @@ -313,7 +313,7 @@ export const dict = { "go.faq.a2": "Go 包含下方列出的模型,提供充足的限额和可靠的访问。", "go.faq.q3": "Go 和 Zen 一样吗?", "go.faq.a3": - "不。Zen 是按量付费,而 Go 首月 $5,之后 $10/月,提供充裕的额度,并可可靠地访问 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 和 MiniMax M2.7 等开源模型。", + "不。Zen 是按量付费,而 Go 首月 $5,之后 $10/月,提供充裕的额度,并可可靠地访问 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 和 MiniMax M2.7 等开源模型。", "go.faq.q4": "Go 多少钱?", "go.faq.a4.p1.beforePricing": "Go 费用为", "go.faq.a4.p1.pricingLink": "首月 $5", @@ -335,7 +335,7 @@ export const dict = { "go.faq.q9": "免费模型和 Go 之间的区别是什么?", "go.faq.a9": - "免费模型包含 Big Pickle 加上当时可用的促销模型,每天有 200 次请求的配额。Go 包含 GLM-5.1, GLM-5, Kimi K2.5、Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 和 MiniMax M2.7,并在滚动窗口(5 小时、每周和每月)内执行更高的请求配额,大致相当于每 5 小时 $12、每周 $30 和每月 $60(实际请求计数因模型和使用情况而异)。", + "免费模型包含 Big Pickle 加上当时可用的促销模型,每天有 200 次请求的配额。Go 包含 GLM-5.1, GLM-5, Kimi K2.5、Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 和 MiniMax M2.7,并在滚动窗口(5 小时、每周和每月)内执行更高的请求配额,大致相当于每 5 小时 $12、每周 $30 和每月 $60(实际请求计数因模型和使用情况而异)。", "zen.api.error.rateLimitExceeded": "超出速率限制。请稍后重试。", "zen.api.error.modelNotSupported": "不支持模型 {{model}}", diff --git a/packages/console/app/src/i18n/zht.ts b/packages/console/app/src/i18n/zht.ts index caea5c74bb..8e93f989e8 100644 --- a/packages/console/app/src/i18n/zht.ts +++ b/packages/console/app/src/i18n/zht.ts @@ -241,7 +241,7 @@ export const dict = { "go.title": "OpenCode Go | 低成本全民編碼模型", "go.meta.description": - "Go 首月 $5,之後 $10/月,提供對 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 和 MiniMax M2.7 的 5 小時充裕請求額度。", + "Go 首月 $5,之後 $10/月,提供對 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 和 MiniMax M2.7 的 5 小時充裕請求額度。", "go.hero.title": "低成本全民編碼模型", "go.hero.body": "Go 將代理編碼帶給全世界的程式設計師。提供寬裕的限額以及對最強大開源模型的穩定存取,讓你可以使用強大的代理進行構建,而無需擔心成本或可用性。", @@ -291,7 +291,7 @@ export const dict = { "go.problem.item2": "寬裕的限額與穩定存取", "go.problem.item3": "專為盡可能多的程式設計師打造", "go.problem.item4": - "包含 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 與 MiniMax M2.7", + "包含 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 與 MiniMax M2.7", "go.how.title": "Go 如何運作", "go.how.body": "Go 起價為首月 $5,之後 $10/月。您可以將其與 OpenCode 或任何代理搭配使用。", "go.how.step1.title": "建立帳號", @@ -313,7 +313,7 @@ export const dict = { "go.faq.a2": "Go 包含下方列出的模型,提供充足的額度與穩定的存取。", "go.faq.q3": "Go 與 Zen 一樣嗎?", "go.faq.a3": - "不。Zen 是按量付費,而 Go 首月 $5,之後 $10/月,提供充裕的額度,並可可靠地存取 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 和 MiniMax M2.7 等開源模型。", + "不。Zen 是按量付費,而 Go 首月 $5,之後 $10/月,提供充裕的額度,並可可靠地存取 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 和 MiniMax M2.7 等開源模型。", "go.faq.q4": "Go 費用是多少?", "go.faq.a4.p1.beforePricing": "Go 費用為", "go.faq.a4.p1.pricingLink": "首月 $5", @@ -335,7 +335,7 @@ export const dict = { "go.faq.q9": "免費模型與 Go 有什麼區別?", "go.faq.a9": - "免費模型包括 Big Pickle 以及當時可用的促銷模型,配額為 200 次請求/天。Go 包括 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 與 MiniMax M2.7,並在滾動視窗(5 小時、每週和每月)內執行更高的請求配額,大約相當於每 5 小時 $12、每週 $30 和每月 $60(實際請求數因模型和使用情況而異)。", + "免費模型包括 Big Pickle 以及當時可用的促銷模型,配額為 200 次請求/天。Go 包括 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 與 MiniMax M2.7,並在滾動視窗(5 小時、每週和每月)內執行更高的請求配額,大約相當於每 5 小時 $12、每週 $30 和每月 $60(實際請求數因模型和使用情況而異)。", "zen.api.error.rateLimitExceeded": "超出頻率限制。請稍後再試。", "zen.api.error.modelNotSupported": "不支援模型 {{model}}", diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index bae5ddd283..bfaf2969bc 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -29,6 +29,8 @@ const models = [ { name: "Kimi K2.6", provider: "Moonshot AI" }, { name: "MiMo-V2-Pro", provider: "Xiaomi MiMo" }, { name: "MiMo-V2-Omni", provider: "Xiaomi MiMo" }, + { name: "MiMo-V2.5-Pro", provider: "Xiaomi MiMo" }, + { name: "MiMo-V2.5", provider: "Xiaomi MiMo" }, { name: "Qwen3.5 Plus", provider: "Alibaba Cloud Model Studio" }, { name: "Qwen3.6 Plus", provider: "Alibaba Cloud Model Studio" }, { name: "MiniMax M2.7", provider: "MiniMax" }, @@ -60,7 +62,7 @@ function LimitsGraph(props: { href: string }) { const graph = [ { id: "glm-5.1", name: "GLM-5.1", req: 880, d: "100ms" }, { id: "kimi-k2.6", name: "Kimi K2.6 (3x usage)", req: 3450, baseReq: 1150, d: "150ms" }, - { id: "mimo-v2-pro", name: "MiMo-V2-Pro", req: 1290, d: "150ms" }, + { id: "mimo-v2.5-pro", name: "MiMo-V2.5-Pro", req: 1290, d: "150ms" }, { id: "qwen3.6-plus", name: "Qwen3.6 Plus", req: 3300, d: "280ms" }, { id: "minimax-m2.7", name: "MiniMax M2.7", req: 3400, d: "300ms" }, { id: "qwen3.5-plus", name: "Qwen3.5 Plus", req: 10200, d: "360ms" }, diff --git a/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx b/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx index c894ace104..abd417e06b 100644 --- a/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx @@ -289,8 +289,10 @@ export function LiteSection() {
  • Kimi K2.6
  • GLM-5
  • GLM-5.1
  • -
  • Mimo-V2-Pro
  • -
  • Mimo-V2-Omni
  • +
  • MiMo-V2-Pro
  • +
  • MiMo-V2-Omni
  • +
  • MiMo-V2.5-Pro
  • +
  • MiMo-V2.5
  • MiniMax M2.5
  • MiniMax M2.7
  • Qwen3.5 Plus
  • diff --git a/packages/web/src/content/docs/ar/go.mdx b/packages/web/src/content/docs/ar/go.mdx index 179999af86..008c83468d 100644 --- a/packages/web/src/content/docs/ar/go.mdx +++ b/packages/web/src/content/docs/ar/go.mdx @@ -59,6 +59,8 @@ OpenCode Go حاليًا في المرحلة التجريبية. - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **Qwen3.5 Plus** - **Qwen3.6 Plus** @@ -86,8 +88,10 @@ OpenCode Go حاليًا في المرحلة التجريبية. | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -102,6 +106,8 @@ OpenCode Go حاليًا في المرحلة التجريبية. - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request - MiMo-V2-Pro — ‏350 input، و41,000 cached، و250 output tokens لكل طلب - MiMo-V2-Omni — ‏1000 input، و60,000 cached، و140 output tokens لكل طلب +- MiMo-V2.5-Pro — ‏350 input، و41,000 cached، و250 output tokens لكل طلب +- MiMo-V2.5 — ‏1000 input، و60,000 cached، و140 output tokens لكل طلب يمكنك تتبّع استخدامك الحالي في **console**. @@ -131,6 +137,8 @@ OpenCode Go حاليًا في المرحلة التجريبية. | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | diff --git a/packages/web/src/content/docs/bs/go.mdx b/packages/web/src/content/docs/bs/go.mdx index b94a78ee75..ece9c0ca52 100644 --- a/packages/web/src/content/docs/bs/go.mdx +++ b/packages/web/src/content/docs/bs/go.mdx @@ -69,6 +69,8 @@ Trenutna lista modela uključuje: - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **Qwen3.5 Plus** - **Qwen3.6 Plus** @@ -96,8 +98,10 @@ Tabela ispod pruža procijenjeni broj zahtjeva na osnovu tipičnih obrazaca kori | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -112,6 +116,8 @@ Procjene se zasnivaju na zapaženim prosječnim obrascima zahtjeva: - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request - MiMo-V2-Pro — 350 ulaznih, 41,000 keširanih, 250 izlaznih tokena po zahtjevu - MiMo-V2-Omni — 1000 ulaznih, 60,000 keširanih, 140 izlaznih tokena po zahtjevu +- MiMo-V2.5-Pro — 350 ulaznih, 41,000 keširanih, 250 izlaznih tokena po zahtjevu +- MiMo-V2.5 — 1000 ulaznih, 60,000 keširanih, 140 izlaznih tokena po zahtjevu Svoju trenutnu potrošnju možete pratiti u **konzoli**. @@ -143,6 +149,8 @@ Također možete pristupiti Go modelima putem sljedećih API endpointa. | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | diff --git a/packages/web/src/content/docs/da/go.mdx b/packages/web/src/content/docs/da/go.mdx index 0ef5f12226..437e807ecf 100644 --- a/packages/web/src/content/docs/da/go.mdx +++ b/packages/web/src/content/docs/da/go.mdx @@ -69,6 +69,8 @@ Den nuværende liste over modeller inkluderer: - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **Qwen3.5 Plus** - **Qwen3.6 Plus** @@ -96,8 +98,10 @@ Tabellen nedenfor giver et estimeret antal anmodninger baseret på typiske Go-fo | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -112,6 +116,8 @@ Estimaterne er baseret på observerede gennemsnitlige anmodningsmønstre: - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request - MiMo-V2-Pro — 350 input, 41.000 cachelagrede, 250 output-tokens pr. anmodning - MiMo-V2-Omni — 1000 input, 60.000 cachelagrede, 140 output-tokens pr. anmodning +- MiMo-V2.5-Pro — 350 input, 41.000 cachelagrede, 250 output-tokens pr. anmodning +- MiMo-V2.5 — 1000 input, 60.000 cachelagrede, 140 output-tokens pr. anmodning Du kan spore dit nuværende forbrug i **konsollen**. @@ -143,6 +149,8 @@ Du kan også få adgang til Go-modeller gennem følgende API-endpoints. | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | diff --git a/packages/web/src/content/docs/de/go.mdx b/packages/web/src/content/docs/de/go.mdx index 269f6231ee..8f60af1e9f 100644 --- a/packages/web/src/content/docs/de/go.mdx +++ b/packages/web/src/content/docs/de/go.mdx @@ -61,6 +61,8 @@ Die aktuelle Liste der Modelle umfasst: - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **Qwen3.5 Plus** - **Qwen3.6 Plus** @@ -88,8 +90,10 @@ Die folgende Tabelle zeigt eine geschätzte Anzahl von Anfragen basierend auf ty | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -104,6 +108,8 @@ Die Schätzungen basieren auf beobachteten durchschnittlichen Anfragemustern: - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request - MiMo-V2-Pro — 350 Input-, 41.000 Cached-, 250 Output-Tokens pro Anfrage - MiMo-V2-Omni — 1.000 Input-, 60.000 Cached-, 140 Output-Tokens pro Anfrage +- MiMo-V2.5-Pro — 350 Input-, 41.000 Cached-, 250 Output-Tokens pro Anfrage +- MiMo-V2.5 — 1.000 Input-, 60.000 Cached-, 140 Output-Tokens pro Anfrage Du kannst deine aktuelle Nutzung in der **Console** verfolgen. @@ -133,6 +139,8 @@ Du kannst auf die Go-Modelle auch über die folgenden API-Endpunkte zugreifen. | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | diff --git a/packages/web/src/content/docs/es/go.mdx b/packages/web/src/content/docs/es/go.mdx index e70e3dd1f9..1d4cf709c4 100644 --- a/packages/web/src/content/docs/es/go.mdx +++ b/packages/web/src/content/docs/es/go.mdx @@ -69,6 +69,8 @@ La lista actual de modelos incluye: - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **Qwen3.5 Plus** - **Qwen3.6 Plus** @@ -96,8 +98,10 @@ La siguiente tabla proporciona una cantidad estimada de peticiones basada en los | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -112,6 +116,8 @@ Las estimaciones se basan en los patrones de peticiones promedio observados: - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request - MiMo-V2-Pro — 350 tokens de entrada, 41,000 en caché, 250 tokens de salida por petición - MiMo-V2-Omni — 1000 tokens de entrada, 60,000 en caché, 140 tokens de salida por petición +- MiMo-V2.5-Pro — 350 tokens de entrada, 41,000 en caché, 250 tokens de salida por petición +- MiMo-V2.5 — 1000 tokens de entrada, 60,000 en caché, 140 tokens de salida por petición Puedes realizar un seguimiento de tu uso actual en la **consola**. @@ -143,6 +149,8 @@ También puedes acceder a los modelos de Go a través de los siguientes endpoint | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | diff --git a/packages/web/src/content/docs/fr/go.mdx b/packages/web/src/content/docs/fr/go.mdx index 5527d9d865..b288ff1bf9 100644 --- a/packages/web/src/content/docs/fr/go.mdx +++ b/packages/web/src/content/docs/fr/go.mdx @@ -59,6 +59,8 @@ La liste actuelle des modèles comprend : - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **Qwen3.5 Plus** - **Qwen3.6 Plus** @@ -86,8 +88,10 @@ Le tableau ci-dessous fournit une estimation du nombre de requêtes basée sur d | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -102,6 +106,8 @@ Les estimations sont basées sur les modèles de requêtes moyens observés : - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request - MiMo-V2-Pro — 350 tokens en entrée, 41,000 en cache, 250 tokens en sortie par requête - MiMo-V2-Omni — 1000 tokens en entrée, 60,000 en cache, 140 tokens en sortie par requête +- MiMo-V2.5-Pro — 350 tokens en entrée, 41,000 en cache, 250 tokens en sortie par requête +- MiMo-V2.5 — 1000 tokens en entrée, 60,000 en cache, 140 tokens en sortie par requête Vous pouvez suivre votre utilisation actuelle dans la **console**. @@ -131,6 +137,8 @@ Vous pouvez également accéder aux modèles Go via les points de terminaison d' | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | diff --git a/packages/web/src/content/docs/go.mdx b/packages/web/src/content/docs/go.mdx index a39b6f7d24..cd3e2c8445 100644 --- a/packages/web/src/content/docs/go.mdx +++ b/packages/web/src/content/docs/go.mdx @@ -69,6 +69,8 @@ The current list of models includes: - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **MiniMax M2.7** - **Qwen3.5 Plus** @@ -96,8 +98,10 @@ The table below provides an estimated request count based on typical Go usage pa | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -110,6 +114,8 @@ Estimates are based on observed average request patterns: - MiniMax M2.7/M2.5 — 300 input, 55,000 cached, 125 output tokens per request - MiMo-V2-Pro — 350 input, 41,000 cached, 250 output tokens per request - MiMo-V2-Omni — 1000 input, 60,000 cached, 140 output tokens per request +- MiMo-V2.5-Pro — 350 input, 41,000 cached, 250 output tokens per request +- MiMo-V2.5 — 1000 input, 60,000 cached, 140 output tokens per request - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -143,6 +149,8 @@ You can also access Go models through the following API endpoints. | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | diff --git a/packages/web/src/content/docs/it/go.mdx b/packages/web/src/content/docs/it/go.mdx index 6cdf7ac6cf..9cf04d77d6 100644 --- a/packages/web/src/content/docs/it/go.mdx +++ b/packages/web/src/content/docs/it/go.mdx @@ -67,6 +67,8 @@ L'elenco attuale dei modelli include: - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **Qwen3.5 Plus** - **Qwen3.6 Plus** @@ -94,8 +96,10 @@ La tabella seguente fornisce una stima del conteggio delle richieste in base a p | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -110,6 +114,8 @@ Le stime si basano sui pattern medi di richieste osservati: - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request - MiMo-V2-Pro — 350 di input, 41.000 in cache, 250 token di output per richiesta - MiMo-V2-Omni — 1000 di input, 60.000 in cache, 140 token di output per richiesta +- MiMo-V2.5-Pro — 350 di input, 41.000 in cache, 250 token di output per richiesta +- MiMo-V2.5 — 1000 di input, 60.000 in cache, 140 token di output per richiesta Puoi monitorare il tuo utilizzo attuale nella **console**. @@ -141,6 +147,8 @@ Puoi anche accedere ai modelli Go tramite i seguenti endpoint API. | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | diff --git a/packages/web/src/content/docs/ja/go.mdx b/packages/web/src/content/docs/ja/go.mdx index f122d2367b..40c1dbf36e 100644 --- a/packages/web/src/content/docs/ja/go.mdx +++ b/packages/web/src/content/docs/ja/go.mdx @@ -59,6 +59,8 @@ OpenCode Goをサブスクライブできるのは、1つのワークスペー - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **Qwen3.5 Plus** - **Qwen3.6 Plus** @@ -86,8 +88,10 @@ OpenCode Goには以下の制限が含まれています: | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -102,6 +106,8 @@ OpenCode Goには以下の制限が含まれています: - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request - MiMo-V2-Pro — リクエストあたり 入力 350トークン、キャッシュ 41,000トークン、出力 250トークン - MiMo-V2-Omni — リクエストあたり 入力 1000トークン、キャッシュ 60,000トークン、出力 140トークン +- MiMo-V2.5-Pro — リクエストあたり 入力 350トークン、キャッシュ 41,000トークン、出力 250トークン +- MiMo-V2.5 — リクエストあたり 入力 1000トークン、キャッシュ 60,000トークン、出力 140トークン 現在の利用状況は**コンソール**で追跡できます。 @@ -131,6 +137,8 @@ Zen残高にクレジットがある場合は、コンソールで**Use balance* | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | diff --git a/packages/web/src/content/docs/ko/go.mdx b/packages/web/src/content/docs/ko/go.mdx index cd0b1b8da2..4b3dbd27d0 100644 --- a/packages/web/src/content/docs/ko/go.mdx +++ b/packages/web/src/content/docs/ko/go.mdx @@ -59,6 +59,8 @@ workspace당 한 명의 멤버만 OpenCode Go를 구독할 수 있습니다. - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **Qwen3.5 Plus** - **Qwen3.6 Plus** @@ -86,8 +88,10 @@ OpenCode Go에는 다음과 같은 한도가 포함됩니다. | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -102,6 +106,8 @@ OpenCode Go에는 다음과 같은 한도가 포함됩니다. - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request - MiMo-V2-Pro — 요청당 입력 350, 캐시 41,000, 출력 토큰 250 - MiMo-V2-Omni — 요청당 입력 1000, 캐시 60,000, 출력 토큰 140 +- MiMo-V2.5-Pro — 요청당 입력 350, 캐시 41,000, 출력 토큰 250 +- MiMo-V2.5 — 요청당 입력 1000, 캐시 60,000, 출력 토큰 140 현재 사용량은 **console**에서 확인할 수 있습니다. @@ -131,6 +137,8 @@ Zen 잔액에 크레딧도 있다면, console에서 **Use balance** 옵션을 | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | diff --git a/packages/web/src/content/docs/nb/go.mdx b/packages/web/src/content/docs/nb/go.mdx index 776cc0c92d..f062683e87 100644 --- a/packages/web/src/content/docs/nb/go.mdx +++ b/packages/web/src/content/docs/nb/go.mdx @@ -69,6 +69,8 @@ Den nåværende listen over modeller inkluderer: - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **Qwen3.5 Plus** - **Qwen3.6 Plus** @@ -96,8 +98,10 @@ Tabellen nedenfor gir et estimert antall forespørsler basert på typiske bruksm | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -112,6 +116,8 @@ Estimatene er basert på observerte gjennomsnittlige forespørselsmønstre: - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request - MiMo-V2-Pro — 350 input, 41 000 bufret, 250 output-tokens per forespørsel - MiMo-V2-Omni — 1000 input, 60 000 bufret, 140 output-tokens per forespørsel +- MiMo-V2.5-Pro — 350 input, 41 000 bufret, 250 output-tokens per forespørsel +- MiMo-V2.5 — 1000 input, 60 000 bufret, 140 output-tokens per forespørsel Du kan spore din nåværende bruk i **konsollen**. @@ -143,6 +149,8 @@ Du kan også få tilgang til Go-modeller gjennom følgende API-endepunkter. | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | diff --git a/packages/web/src/content/docs/pl/go.mdx b/packages/web/src/content/docs/pl/go.mdx index d99f5e0986..12abb29bc1 100644 --- a/packages/web/src/content/docs/pl/go.mdx +++ b/packages/web/src/content/docs/pl/go.mdx @@ -63,6 +63,8 @@ Obecna lista modeli obejmuje: - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **Qwen3.5 Plus** - **Qwen3.6 Plus** @@ -90,8 +92,10 @@ Poniższa tabela przedstawia szacunkową liczbę żądań na podstawie typowych | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -106,6 +110,8 @@ Szacunki opierają się na zaobserwowanych średnich wzorcach żądań: - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request - MiMo-V2-Pro — 350 tokenów wejściowych, 41 000 w pamięci podręcznej, 250 tokenów wyjściowych na żądanie - MiMo-V2-Omni — 1000 tokenów wejściowych, 60 000 w pamięci podręcznej, 140 tokenów wyjściowych na żądanie +- MiMo-V2.5-Pro — 350 tokenów wejściowych, 41 000 w pamięci podręcznej, 250 tokenów wyjściowych na żądanie +- MiMo-V2.5 — 1000 tokenów wejściowych, 60 000 w pamięci podręcznej, 140 tokenów wyjściowych na żądanie Możesz śledzić swoje bieżące zużycie w **konsoli**. @@ -135,6 +141,8 @@ Możesz również uzyskać dostęp do modeli Go za pośrednictwem następującyc | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | diff --git a/packages/web/src/content/docs/pt-br/go.mdx b/packages/web/src/content/docs/pt-br/go.mdx index 631038298a..b41cb0d0e7 100644 --- a/packages/web/src/content/docs/pt-br/go.mdx +++ b/packages/web/src/content/docs/pt-br/go.mdx @@ -69,6 +69,8 @@ A lista atual de modelos inclui: - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **Qwen3.5 Plus** - **Qwen3.6 Plus** @@ -96,8 +98,10 @@ A tabela abaixo fornece uma contagem estimada de requisições com base nos padr | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -112,6 +116,8 @@ As estimativas baseiam-se nos padrões médios de requisições observados: - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request - MiMo-V2-Pro — 350 tokens de entrada, 41.000 em cache, 250 tokens de saída por requisição - MiMo-V2-Omni — 1000 tokens de entrada, 60.000 em cache, 140 tokens de saída por requisição +- MiMo-V2.5-Pro — 350 tokens de entrada, 41.000 em cache, 250 tokens de saída por requisição +- MiMo-V2.5 — 1000 tokens de entrada, 60.000 em cache, 140 tokens de saída por requisição Você pode acompanhar o seu uso atual no **console**. @@ -143,6 +149,8 @@ Você também pode acessar os modelos do Go através dos seguintes endpoints de | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | diff --git a/packages/web/src/content/docs/ru/go.mdx b/packages/web/src/content/docs/ru/go.mdx index 60f01c2b53..62ce99ef9e 100644 --- a/packages/web/src/content/docs/ru/go.mdx +++ b/packages/web/src/content/docs/ru/go.mdx @@ -69,6 +69,8 @@ OpenCode Go работает так же, как и любой другой пр - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **Qwen3.5 Plus** - **Qwen3.6 Plus** @@ -96,8 +98,10 @@ OpenCode Go включает следующие лимиты: | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -112,6 +116,8 @@ OpenCode Go включает следующие лимиты: - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request - MiMo-V2-Pro — 350 входных, 41,000 кешированных, 250 выходных токенов на запрос - MiMo-V2-Omni — 1000 входных, 60,000 кешированных, 140 выходных токенов на запрос +- MiMo-V2.5-Pro — 350 входных, 41,000 кешированных, 250 выходных токенов на запрос +- MiMo-V2.5 — 1000 входных, 60,000 кешированных, 140 выходных токенов на запрос Вы можете отслеживать текущее использование в **консоли**. @@ -143,6 +149,8 @@ OpenCode Go включает следующие лимиты: | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | diff --git a/packages/web/src/content/docs/th/go.mdx b/packages/web/src/content/docs/th/go.mdx index 3af1eadc9f..84ce3546c1 100644 --- a/packages/web/src/content/docs/th/go.mdx +++ b/packages/web/src/content/docs/th/go.mdx @@ -59,6 +59,8 @@ OpenCode Go ทำงานเหมือนกับผู้ให้บร - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **Qwen3.5 Plus** - **Qwen3.6 Plus** @@ -86,8 +88,10 @@ OpenCode Go มีขีดจำกัดดังต่อไปนี้: | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -102,6 +106,8 @@ OpenCode Go มีขีดจำกัดดังต่อไปนี้: - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request - MiMo-V2-Pro — 350 input, 41,000 cached, 250 output tokens ต่อ request - MiMo-V2-Omni — 1000 input, 60,000 cached, 140 output tokens ต่อ request +- MiMo-V2.5-Pro — 350 input, 41,000 cached, 250 output tokens ต่อ request +- MiMo-V2.5 — 1000 input, 60,000 cached, 140 output tokens ต่อ request คุณสามารถติดตามการใช้งานปัจจุบันของคุณได้ใน **console** @@ -131,6 +137,8 @@ OpenCode Go มีขีดจำกัดดังต่อไปนี้: | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | diff --git a/packages/web/src/content/docs/tr/go.mdx b/packages/web/src/content/docs/tr/go.mdx index e962c06807..edd102685b 100644 --- a/packages/web/src/content/docs/tr/go.mdx +++ b/packages/web/src/content/docs/tr/go.mdx @@ -59,6 +59,8 @@ Mevcut model listesi şunları içerir: - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **Qwen3.5 Plus** - **Qwen3.6 Plus** @@ -86,8 +88,10 @@ Aşağıdaki tablo, tipik Go kullanım modellerine dayalı tahmini bir istek say | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -102,6 +106,8 @@ Tahminler, gözlemlenen ortalama istek modellerine dayanmaktadır: - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request - MiMo-V2-Pro — İstek başına 350 girdi, 41.000 önbelleğe alınmış, 250 çıktı token'ı - MiMo-V2-Omni — İstek başına 1000 girdi, 60.000 önbelleğe alınmış, 140 çıktı token'ı +- MiMo-V2.5-Pro — İstek başına 350 girdi, 41.000 önbelleğe alınmış, 250 çıktı token'ı +- MiMo-V2.5 — İstek başına 1000 girdi, 60.000 önbelleğe alınmış, 140 çıktı token'ı Mevcut kullanımınızı **konsoldan** takip edebilirsiniz. @@ -131,6 +137,8 @@ Go modellerine aşağıdaki API uç noktaları aracılığıyla da erişebilirsi | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | diff --git a/packages/web/src/content/docs/zh-cn/go.mdx b/packages/web/src/content/docs/zh-cn/go.mdx index ac3b5f9bf5..0c1cf98274 100644 --- a/packages/web/src/content/docs/zh-cn/go.mdx +++ b/packages/web/src/content/docs/zh-cn/go.mdx @@ -59,6 +59,8 @@ OpenCode Go 的工作方式与 OpenCode 中的其他提供商一样。 - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **Qwen3.5 Plus** - **Qwen3.6 Plus** @@ -86,8 +88,10 @@ OpenCode Go 包含以下限制: | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -99,6 +103,8 @@ OpenCode Go 包含以下限制: - Kimi K2.5/K2.6 — 每次请求 870 个输入 token,55,000 个缓存 token,200 个输出 token - MiMo-V2-Pro — 每次请求 350 个输入 token,41,000 个缓存 token,250 个输出 token - MiMo-V2-Omni — 每次请求 1000 个输入 token,60,000 个缓存 token,140 个输出 token +- MiMo-V2.5-Pro — 每次请求 350 个输入 token,41,000 个缓存 token,250 个输出 token +- MiMo-V2.5 — 每次请求 1000 个输入 token,60,000 个缓存 token,140 个输出 token - MiniMax M2.7/M2.5 — 每次请求 300 个输入 token,55,000 个缓存 token,125 个输出 token - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -131,6 +137,8 @@ OpenCode Go 包含以下限制: | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | diff --git a/packages/web/src/content/docs/zh-tw/go.mdx b/packages/web/src/content/docs/zh-tw/go.mdx index 0621a66940..c1016028ba 100644 --- a/packages/web/src/content/docs/zh-tw/go.mdx +++ b/packages/web/src/content/docs/zh-tw/go.mdx @@ -59,6 +59,8 @@ OpenCode Go 的運作方式與 OpenCode 中的任何其他供應商相同。 - **Kimi K2.6** - **MiMo-V2-Pro** - **MiMo-V2-Omni** +- **MiMo-V2.5-Pro** +- **MiMo-V2.5** - **MiniMax M2.5** - **Qwen3.5 Plus** - **Qwen3.6 Plus** @@ -86,8 +88,10 @@ OpenCode Go 包含以下限制: | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | @@ -102,6 +106,8 @@ OpenCode Go 包含以下限制: - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request - MiMo-V2-Pro — 每次請求 350 個輸入 token、41,000 個快取 token、250 個輸出 token - MiMo-V2-Omni — 每次請求 1000 個輸入 token、60,000 個快取 token、140 個輸出 token +- MiMo-V2.5-Pro — 每次請求 350 個輸入 token、41,000 個快取 token、250 個輸出 token +- MiMo-V2.5 — 每次請求 1000 個輸入 token、60,000 個快取 token、140 個輸出 token 您可以在 **console** 中追蹤您目前的使用量。 @@ -131,6 +137,8 @@ OpenCode Go 包含以下限制: | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | From 5d133f2785aada81d65b14e3f86f14063900596c Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Wed, 22 Apr 2026 16:29:44 +0000 Subject: [PATCH 15/92] chore: generate --- packages/web/src/content/docs/ar/go.mdx | 54 +++++++++++----------- packages/web/src/content/docs/bs/go.mdx | 54 +++++++++++----------- packages/web/src/content/docs/da/go.mdx | 54 +++++++++++----------- packages/web/src/content/docs/de/go.mdx | 54 +++++++++++----------- packages/web/src/content/docs/es/go.mdx | 54 +++++++++++----------- packages/web/src/content/docs/fr/go.mdx | 54 +++++++++++----------- packages/web/src/content/docs/go.mdx | 54 +++++++++++----------- packages/web/src/content/docs/it/go.mdx | 54 +++++++++++----------- packages/web/src/content/docs/ja/go.mdx | 54 +++++++++++----------- packages/web/src/content/docs/ko/go.mdx | 54 +++++++++++----------- packages/web/src/content/docs/nb/go.mdx | 54 +++++++++++----------- packages/web/src/content/docs/pl/go.mdx | 54 +++++++++++----------- packages/web/src/content/docs/pt-br/go.mdx | 54 +++++++++++----------- packages/web/src/content/docs/ru/go.mdx | 54 +++++++++++----------- packages/web/src/content/docs/th/go.mdx | 54 +++++++++++----------- packages/web/src/content/docs/tr/go.mdx | 54 +++++++++++----------- packages/web/src/content/docs/zh-cn/go.mdx | 54 +++++++++++----------- packages/web/src/content/docs/zh-tw/go.mdx | 54 +++++++++++----------- 18 files changed, 486 insertions(+), 486 deletions(-) diff --git a/packages/web/src/content/docs/ar/go.mdx b/packages/web/src/content/docs/ar/go.mdx index 008c83468d..785ea35b66 100644 --- a/packages/web/src/content/docs/ar/go.mdx +++ b/packages/web/src/content/docs/ar/go.mdx @@ -82,20 +82,20 @@ OpenCode Go حاليًا في المرحلة التجريبية. يوضح الجدول أدناه عددًا تقديريًا للطلبات بناءً على أنماط استخدام Go المعتادة: -| Model | الطلبات لكل 5 ساعات | الطلبات في الأسبوع | الطلبات في الشهر | -| ------------ | ------------------- | ------------------ | ---------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | الطلبات لكل 5 ساعات | الطلبات في الأسبوع | الطلبات في الشهر | +| ------------- | ------------------- | ------------------ | ---------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | تستند التقديرات إلى متوسطات أنماط الطلبات المرصودة: @@ -129,20 +129,20 @@ OpenCode Go حاليًا في المرحلة التجريبية. يمكنك أيضًا الوصول إلى نماذج Go عبر نقاط نهاية API التالية. -| Model | Model ID | Endpoint | AI SDK Package | -| ------------ | ------------ | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Model | Model ID | Endpoint | AI SDK Package | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | يستخدم [model id](/docs/config/#models) في إعدادات OpenCode لديك التنسيق `opencode-go/`. على سبيل المثال، بالنسبة إلى Kimi K2.6، ستستخدم `opencode-go/kimi-k2.6` في إعداداتك. diff --git a/packages/web/src/content/docs/bs/go.mdx b/packages/web/src/content/docs/bs/go.mdx index ece9c0ca52..523f1ef8ed 100644 --- a/packages/web/src/content/docs/bs/go.mdx +++ b/packages/web/src/content/docs/bs/go.mdx @@ -92,20 +92,20 @@ Ograničenja su definisana u dolarskoj vrijednosti. To znači da vaš stvarni br Tabela ispod pruža procijenjeni broj zahtjeva na osnovu tipičnih obrazaca korištenja Go pretplate: -| Model | zahtjeva na 5 sati | zahtjeva sedmično | zahtjeva mjesečno | -| ------------ | ------------------ | ----------------- | ----------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | zahtjeva na 5 sati | zahtjeva sedmično | zahtjeva mjesečno | +| ------------- | ------------------ | ----------------- | ----------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | Procjene se zasnivaju na zapaženim prosječnim obrascima zahtjeva: @@ -141,20 +141,20 @@ nakon što dostignete ograničenja upotrebe umjesto blokiranja zahtjeva. Također možete pristupiti Go modelima putem sljedećih API endpointa. -| Model | Model ID | Endpoint | AI SDK Paket | -| ------------ | ------------ | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Model | Model ID | Endpoint | AI SDK Paket | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | [Model id](/docs/config/#models) u vašoj OpenCode konfiguraciji koristi format `opencode-go/`. Na primjer, za Kimi K2.6, koristili biste diff --git a/packages/web/src/content/docs/da/go.mdx b/packages/web/src/content/docs/da/go.mdx index 437e807ecf..86a834b984 100644 --- a/packages/web/src/content/docs/da/go.mdx +++ b/packages/web/src/content/docs/da/go.mdx @@ -92,20 +92,20 @@ Grænserne er defineret i dollarværdi. Det betyder, at dit faktiske antal anmod Tabellen nedenfor giver et estimeret antal anmodninger baseret på typiske Go-forbrugsmønstre: -| Model | anmodninger pr. 5 timer | anmodninger pr. uge | anmodninger pr. måned | -| ------------ | ----------------------- | ------------------- | --------------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | anmodninger pr. 5 timer | anmodninger pr. uge | anmodninger pr. måned | +| ------------- | ----------------------- | ------------------- | --------------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | Estimaterne er baseret på observerede gennemsnitlige anmodningsmønstre: @@ -141,20 +141,20 @@ når du har nået dine forbrugsgrænser, i stedet for at blokere anmodninger. Du kan også få adgang til Go-modeller gennem følgende API-endpoints. -| Model | Model ID | Endpoint | AI SDK Package | -| ------------ | ------------ | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Model | Model ID | Endpoint | AI SDK Package | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | Dit [model id](/docs/config/#models) i din OpenCode config bruger formatet `opencode-go/`. For eksempel for Kimi K2.6, vil du diff --git a/packages/web/src/content/docs/de/go.mdx b/packages/web/src/content/docs/de/go.mdx index 8f60af1e9f..49c0efda58 100644 --- a/packages/web/src/content/docs/de/go.mdx +++ b/packages/web/src/content/docs/de/go.mdx @@ -84,20 +84,20 @@ Limits sind in Dollarwerten definiert. Das bedeutet, dass die tatsächliche Anza Die folgende Tabelle zeigt eine geschätzte Anzahl von Anfragen basierend auf typischen Go-Nutzungsmustern: -| Model | Anfragen pro 5 Stunden | Anfragen pro Woche | Anfragen pro Monat | -| ------------ | ---------------------- | ------------------ | ------------------ | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | Anfragen pro 5 Stunden | Anfragen pro Woche | Anfragen pro Monat | +| ------------- | ---------------------- | ------------------ | ------------------ | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | Die Schätzungen basieren auf beobachteten durchschnittlichen Anfragemustern: @@ -131,20 +131,20 @@ Wenn du auch Guthaben auf deinem Zen-Konto hast, kannst du in der Console die Op Du kannst auf die Go-Modelle auch über die folgenden API-Endpunkte zugreifen. -| Modell | Modell-ID | Endpunkt | AI SDK Package | -| ------------ | ------------ | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Modell | Modell-ID | Endpunkt | AI SDK Package | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | Die [Modell-ID](/docs/config/#models) in deiner OpenCode Config verwendet das Format `opencode-go/`. Für Kimi K2.6 würdest du beispielsweise `opencode-go/kimi-k2.6` in deiner Config verwenden. diff --git a/packages/web/src/content/docs/es/go.mdx b/packages/web/src/content/docs/es/go.mdx index 1d4cf709c4..a541171caf 100644 --- a/packages/web/src/content/docs/es/go.mdx +++ b/packages/web/src/content/docs/es/go.mdx @@ -92,20 +92,20 @@ Los límites se definen en valor en dólares. Esto significa que tu cantidad rea La siguiente tabla proporciona una cantidad estimada de peticiones basada en los patrones típicos de uso de Go: -| Model | peticiones por 5 horas | peticiones por semana | peticiones por mes | -| ------------ | ---------------------- | --------------------- | ------------------ | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | peticiones por 5 horas | peticiones por semana | peticiones por mes | +| ------------- | ---------------------- | --------------------- | ------------------ | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | Las estimaciones se basan en los patrones de peticiones promedio observados: @@ -141,20 +141,20 @@ después de que hayas alcanzado tus límites de uso en lugar de bloquear las pet También puedes acceder a los modelos de Go a través de los siguientes endpoints de la API. -| Modelo | ID del modelo | Endpoint | Paquete de AI SDK | -| ------------ | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Modelo | ID del modelo | Endpoint | Paquete de AI SDK | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | El [ID del modelo](/docs/config/#models) en tu configuración de OpenCode usa el formato `opencode-go/`. Por ejemplo, para Kimi K2.6, usarías diff --git a/packages/web/src/content/docs/fr/go.mdx b/packages/web/src/content/docs/fr/go.mdx index b288ff1bf9..5f55128ed4 100644 --- a/packages/web/src/content/docs/fr/go.mdx +++ b/packages/web/src/content/docs/fr/go.mdx @@ -82,20 +82,20 @@ Les limites sont définies en valeur monétaire (dollars). Cela signifie que vot Le tableau ci-dessous fournit une estimation du nombre de requêtes basée sur des modèles d'utilisation typiques de Go : -| Model | requêtes par 5 heures | requêtes par semaine | requêtes par mois | -| ------------ | --------------------- | -------------------- | ----------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | requêtes par 5 heures | requêtes par semaine | requêtes par mois | +| ------------- | --------------------- | -------------------- | ----------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | Les estimations sont basées sur les modèles de requêtes moyens observés : @@ -129,20 +129,20 @@ Si vous avez également des crédits sur votre solde Zen, vous pouvez activer l' Vous pouvez également accéder aux modèles Go via les points de terminaison d'API suivants. -| Modèle | ID de modèle | Point de terminaison | Package AI SDK | -| ------------ | ------------ | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Modèle | ID de modèle | Point de terminaison | Package AI SDK | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | L'[ID de modèle](/docs/config/#models) dans votre configuration OpenCode utilise le format `opencode-go/`. Par exemple, pour Kimi K2.6, vous utiliseriez `opencode-go/kimi-k2.6` dans votre configuration. diff --git a/packages/web/src/content/docs/go.mdx b/packages/web/src/content/docs/go.mdx index cd3e2c8445..946c70de30 100644 --- a/packages/web/src/content/docs/go.mdx +++ b/packages/web/src/content/docs/go.mdx @@ -92,20 +92,20 @@ Limits are defined in dollar value. This means your actual request count depends The table below provides an estimated request count based on typical Go usage patterns: -| Model | requests per 5 hour | requests per week | requests per month | -| ------------ | ------------------- | ----------------- | ------------------ | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | requests per 5 hour | requests per week | requests per month | +| ------------- | ------------------- | ----------------- | ------------------ | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | Estimates are based on observed average request patterns: @@ -141,20 +141,20 @@ after you've reached your usage limits instead of blocking requests. You can also access Go models through the following API endpoints. -| Model | Model ID | Endpoint | AI SDK Package | -| ------------ | ------------ | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Model | Model ID | Endpoint | AI SDK Package | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | The [model id](/docs/config/#models) in your OpenCode config uses the format `opencode-go/`. For example, for Kimi K2.6, you would diff --git a/packages/web/src/content/docs/it/go.mdx b/packages/web/src/content/docs/it/go.mdx index 9cf04d77d6..341a22c4cb 100644 --- a/packages/web/src/content/docs/it/go.mdx +++ b/packages/web/src/content/docs/it/go.mdx @@ -90,20 +90,20 @@ I limiti sono definiti in valore in dollari. Questo significa che il conteggio e La tabella seguente fornisce una stima del conteggio delle richieste in base a pattern di utilizzo tipici di Go: -| Model | richieste ogni 5 ore | richieste a settimana | richieste al mese | -| ------------ | -------------------- | --------------------- | ----------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | richieste ogni 5 ore | richieste a settimana | richieste al mese | +| ------------- | -------------------- | --------------------- | ----------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | Le stime si basano sui pattern medi di richieste osservati: @@ -139,20 +139,20 @@ dopo che avrai raggiunto i limiti di utilizzo invece di bloccare le richieste. Puoi anche accedere ai modelli Go tramite i seguenti endpoint API. -| Modello | ID Modello | Endpoint | Pacchetto AI SDK | -| ------------ | ------------ | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Modello | ID Modello | Endpoint | Pacchetto AI SDK | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | Il [model id](/docs/config/#models) nella tua OpenCode config utilizza il formato `opencode-go/`. Ad esempio, per Kimi K2.6, useresti diff --git a/packages/web/src/content/docs/ja/go.mdx b/packages/web/src/content/docs/ja/go.mdx index 40c1dbf36e..ddd5a66803 100644 --- a/packages/web/src/content/docs/ja/go.mdx +++ b/packages/web/src/content/docs/ja/go.mdx @@ -82,20 +82,20 @@ OpenCode Goには以下の制限が含まれています: 以下の表は、一般的なGoの利用パターンに基づいた推定リクエスト数を示しています: -| Model | 5時間あたりのリクエスト数 | 週間リクエスト数 | 月間リクエスト数 | -| ------------ | ------------------------- | ---------------- | ---------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | 5時間あたりのリクエスト数 | 週間リクエスト数 | 月間リクエスト数 | +| ------------- | ------------------------- | ---------------- | ---------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | 推定値は、観測された平均的なリクエストパターンに基づいています: @@ -129,20 +129,20 @@ Zen残高にクレジットがある場合は、コンソールで**Use balance* 以下のAPIエンドポイントを通じて、Goモデルにアクセスすることもできます。 -| Model | Model ID | Endpoint | AI SDK Package | -| ------------ | ------------ | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Model | Model ID | Endpoint | AI SDK Package | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | OpenCode設定の[model id](/docs/config/#models)は、`opencode-go/`という形式を使用します。たとえば、Kimi K2.6の場合は、設定で`opencode-go/kimi-k2.6`を使用します。 diff --git a/packages/web/src/content/docs/ko/go.mdx b/packages/web/src/content/docs/ko/go.mdx index 4b3dbd27d0..da787040fb 100644 --- a/packages/web/src/content/docs/ko/go.mdx +++ b/packages/web/src/content/docs/ko/go.mdx @@ -82,20 +82,20 @@ OpenCode Go에는 다음과 같은 한도가 포함됩니다. 아래 표는 일반적인 Go 사용 패턴을 기준으로 한 예상 요청 횟수를 보여줍니다. -| Model | 5시간당 요청 횟수 | 주간 요청 횟수 | 월간 요청 횟수 | -| ------------ | ----------------- | -------------- | -------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | 5시간당 요청 횟수 | 주간 요청 횟수 | 월간 요청 횟수 | +| ------------- | ----------------- | -------------- | -------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | 예상치는 관찰된 평균 요청 패턴을 기준으로 합니다. @@ -129,20 +129,20 @@ Zen 잔액에 크레딧도 있다면, console에서 **Use balance** 옵션을 다음 API 엔드포인트를 통해서도 Go 모델에 액세스할 수 있습니다. -| 모델 | 모델 ID | 엔드포인트 | AI SDK 패키지 | -| ------------ | ------------ | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| 모델 | 모델 ID | 엔드포인트 | AI SDK 패키지 | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | OpenCode config의 [model id](/docs/config/#models)는 `opencode-go/` 형식을 사용합니다. 예를 들어 Kimi K2.6의 경우 config에서 `opencode-go/kimi-k2.6`를 사용하면 됩니다. diff --git a/packages/web/src/content/docs/nb/go.mdx b/packages/web/src/content/docs/nb/go.mdx index f062683e87..95c05417cf 100644 --- a/packages/web/src/content/docs/nb/go.mdx +++ b/packages/web/src/content/docs/nb/go.mdx @@ -92,20 +92,20 @@ Grensene er definert i dollarverdi. Dette betyr at ditt faktiske antall forespø Tabellen nedenfor gir et estimert antall forespørsler basert på typiske bruksmønstre for Go: -| Model | forespørsler per 5 timer | forespørsler per uke | forespørsler per måned | -| ------------ | ------------------------ | -------------------- | ---------------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | forespørsler per 5 timer | forespørsler per uke | forespørsler per måned | +| ------------- | ------------------------ | -------------------- | ---------------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | Estimatene er basert på observerte gjennomsnittlige forespørselsmønstre: @@ -141,20 +141,20 @@ etter at du har nådd bruksgrensene dine, i stedet for å blokkere forespørsler Du kan også få tilgang til Go-modeller gjennom følgende API-endepunkter. -| Modell | Modell-ID | Endepunkt | AI SDK Package | -| ------------ | ------------ | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Modell | Modell-ID | Endepunkt | AI SDK Package | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | [Modell-ID-en](/docs/config/#models) i din OpenCode-konfigurasjon bruker formatet `opencode-go/`. For eksempel, for Kimi K2.6, vil du diff --git a/packages/web/src/content/docs/pl/go.mdx b/packages/web/src/content/docs/pl/go.mdx index 12abb29bc1..9ae3ea34b8 100644 --- a/packages/web/src/content/docs/pl/go.mdx +++ b/packages/web/src/content/docs/pl/go.mdx @@ -86,20 +86,20 @@ Limity są zdefiniowane w wartości w dolarach. Oznacza to, że rzeczywista licz Poniższa tabela przedstawia szacunkową liczbę żądań na podstawie typowych wzorców korzystania z Go: -| Model | żądania na 5 godzin | żądania na tydzień | żądania na miesiąc | -| ------------ | ------------------- | ------------------ | ------------------ | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | żądania na 5 godzin | żądania na tydzień | żądania na miesiąc | +| ------------- | ------------------- | ------------------ | ------------------ | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | Szacunki opierają się na zaobserwowanych średnich wzorcach żądań: @@ -133,20 +133,20 @@ Jeśli masz również środki na swoim saldzie Zen, możesz włączyć opcję ** Możesz również uzyskać dostęp do modeli Go za pośrednictwem następujących punktów końcowych API. -| Model | ID modelu | Punkt końcowy | Pakiet AI SDK | -| ------------ | ------------ | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Model | ID modelu | Punkt końcowy | Pakiet AI SDK | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | [ID modelu](/docs/config/#models) w Twojej konfiguracji OpenCode używa formatu `opencode-go/`. Na przykład dla Kimi K2.6 należy użyć diff --git a/packages/web/src/content/docs/pt-br/go.mdx b/packages/web/src/content/docs/pt-br/go.mdx index b41cb0d0e7..7d4d90ed51 100644 --- a/packages/web/src/content/docs/pt-br/go.mdx +++ b/packages/web/src/content/docs/pt-br/go.mdx @@ -92,20 +92,20 @@ Os limites são definidos em valor em dólares. Isso significa que a sua contage A tabela abaixo fornece uma contagem estimada de requisições com base nos padrões típicos de uso do Go: -| Model | requisições por 5 horas | requisições por semana | requisições por mês | -| ------------ | ----------------------- | ---------------------- | ------------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | requisições por 5 horas | requisições por semana | requisições por mês | +| ------------- | ----------------------- | ---------------------- | ------------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | As estimativas baseiam-se nos padrões médios de requisições observados: @@ -141,20 +141,20 @@ após você atingir os seus limites de uso em vez de bloquear as requisições. Você também pode acessar os modelos do Go através dos seguintes endpoints de API. -| Modelo | ID do Modelo | Endpoint | Pacote do AI SDK | -| ------------ | ------------ | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Modelo | ID do Modelo | Endpoint | Pacote do AI SDK | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | O [ID do modelo](/docs/config/#models) na sua configuração do OpenCode usa o formato `opencode-go/`. Por exemplo, para o Kimi K2.6, você usaria diff --git a/packages/web/src/content/docs/ru/go.mdx b/packages/web/src/content/docs/ru/go.mdx index 62ce99ef9e..a8d33f296d 100644 --- a/packages/web/src/content/docs/ru/go.mdx +++ b/packages/web/src/content/docs/ru/go.mdx @@ -92,20 +92,20 @@ OpenCode Go включает следующие лимиты: В таблице ниже приведено примерное количество запросов на основе типичных сценариев использования Go: -| Model | запросов за 5 часов | запросов в неделю | запросов в месяц | -| ------------ | ------------------- | ----------------- | ---------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | запросов за 5 часов | запросов в неделю | запросов в месяц | +| ------------- | ------------------- | ----------------- | ---------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | Оценки основаны на наблюдаемых средних показателях запросов: @@ -141,20 +141,20 @@ OpenCode Go включает следующие лимиты: Вы также можете получить доступ к моделям Go через следующие API-эндпоинты. -| Модель | ID модели | Эндпоинт | Пакет AI SDK | -| ------------ | ------------ | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Модель | ID модели | Эндпоинт | Пакет AI SDK | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | [ID модели](/docs/config/#models) в вашем конфиге OpenCode использует формат `opencode-go/`. Например, для Kimi K2.6 вам нужно diff --git a/packages/web/src/content/docs/th/go.mdx b/packages/web/src/content/docs/th/go.mdx index 84ce3546c1..fb0262c958 100644 --- a/packages/web/src/content/docs/th/go.mdx +++ b/packages/web/src/content/docs/th/go.mdx @@ -82,20 +82,20 @@ OpenCode Go มีขีดจำกัดดังต่อไปนี้: ตารางด้านล่างแสดงจำนวน request โดยประมาณตามรูปแบบการใช้งานปกติของ Go: -| Model | requests ต่อ 5 ชั่วโมง | requests ต่อสัปดาห์ | requests ต่อเดือน | -| ------------ | ---------------------- | ------------------- | ----------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | requests ต่อ 5 ชั่วโมง | requests ต่อสัปดาห์ | requests ต่อเดือน | +| ------------- | ---------------------- | ------------------- | ----------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | การประมาณการอ้างอิงจากรูปแบบการใช้งาน request โดยเฉลี่ยที่สังเกตพบ: @@ -129,20 +129,20 @@ OpenCode Go มีขีดจำกัดดังต่อไปนี้: คุณสามารถเข้าถึงโมเดลของ Go ผ่าน API endpoints ต่อไปนี้ได้เช่นกัน -| Model | Model ID | Endpoint | AI SDK Package | -| ------------ | ------------ | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Model | Model ID | Endpoint | AI SDK Package | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | [model id](/docs/config/#models) ใน OpenCode config ของคุณจะใช้รูปแบบ `opencode-go/` ตัวอย่างเช่น สำหรับ Kimi K2.6 คุณจะใช้ `opencode-go/kimi-k2.6` ใน config ของคุณ diff --git a/packages/web/src/content/docs/tr/go.mdx b/packages/web/src/content/docs/tr/go.mdx index edd102685b..96a1ca3e2f 100644 --- a/packages/web/src/content/docs/tr/go.mdx +++ b/packages/web/src/content/docs/tr/go.mdx @@ -82,20 +82,20 @@ Limitler dolar değeri üzerinden belirlenmiştir. Bu, gerçek istek sayınızı Aşağıdaki tablo, tipik Go kullanım modellerine dayalı tahmini bir istek sayısı sunmaktadır: -| Model | 5 saatte bir istek | haftalık istek | aylık istek | -| ------------ | ------------------ | -------------- | ----------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | 5 saatte bir istek | haftalık istek | aylık istek | +| ------------- | ------------------ | -------------- | ----------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | Tahminler, gözlemlenen ortalama istek modellerine dayanmaktadır: @@ -129,20 +129,20 @@ Eğer Zen bakiyenizde kredileriniz varsa, konsoldan **Bakiye kullan (Use balance Go modellerine aşağıdaki API uç noktaları aracılığıyla da erişebilirsiniz. -| Model | Model ID | Uç Nokta | AI SDK Paketi | -| ------------ | ------------ | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Model | Model ID | Uç Nokta | AI SDK Paketi | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | OpenCode yapılandırmanızdaki [model id](/docs/config/#models) formatı `opencode-go/` şeklindedir. Örneğin, Kimi K2.6 için yapılandırmanızda `opencode-go/kimi-k2.6` kullanmalısınız. diff --git a/packages/web/src/content/docs/zh-cn/go.mdx b/packages/web/src/content/docs/zh-cn/go.mdx index 0c1cf98274..f52f5b572e 100644 --- a/packages/web/src/content/docs/zh-cn/go.mdx +++ b/packages/web/src/content/docs/zh-cn/go.mdx @@ -82,20 +82,20 @@ OpenCode Go 包含以下限制: 下表提供了基于典型 Go 使用模式的预估请求数: -| Model | 每 5 小时请求数 | 每周请求数 | 每月请求数 | -| ------------ | --------------- | ---------- | ---------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | 每 5 小时请求数 | 每周请求数 | 每月请求数 | +| ------------- | --------------- | ---------- | ---------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | 预估值基于观察到的平均请求模式: @@ -129,20 +129,20 @@ OpenCode Go 包含以下限制: 你也可以通过以下 API 端点访问 Go 模型。 -| 模型 | 模型 ID | 端点 | AI SDK 包 | -| ------------ | ------------ | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| 模型 | 模型 ID | 端点 | AI SDK 包 | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | 你 OpenCode 配置中的 [模型 ID](/docs/config/#models) 使用 `opencode-go/` 格式。例如,对于 Kimi K2.6,你将在配置中使用 `opencode-go/kimi-k2.6`。 diff --git a/packages/web/src/content/docs/zh-tw/go.mdx b/packages/web/src/content/docs/zh-tw/go.mdx index c1016028ba..481c08cec5 100644 --- a/packages/web/src/content/docs/zh-tw/go.mdx +++ b/packages/web/src/content/docs/zh-tw/go.mdx @@ -82,20 +82,20 @@ OpenCode Go 包含以下限制: 下表提供了基於典型 Go 使用模式的預估請求次數: -| Model | 每 5 小時請求數 | 每週請求數 | 每月請求數 | -| ------------ | --------------- | ---------- | ---------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | 每 5 小時請求數 | 每週請求數 | 每月請求數 | +| ------------- | --------------- | ---------- | ---------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | 預估值是基於觀察到的平均請求模式: @@ -129,20 +129,20 @@ OpenCode Go 包含以下限制: 您也可以透過以下 API 端點存取 Go 模型。 -| 模型 | 模型 ID | 端點 | AI SDK 套件 | -| ------------ | ------------ | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| 模型 | 模型 ID | 端點 | AI SDK 套件 | +| ------------- | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | 您的 OpenCode 設定中的 [model id](/docs/config/#models) 使用 `opencode-go/` 格式。例如,Kimi K2.6 在設定中應使用 `opencode-go/kimi-k2.6`。 From 58db41b4b9fac2bfcf1f935cc114b3e4a069eade Mon Sep 17 00:00:00 2001 From: Caleb Norton Date: Wed, 22 Apr 2026 17:47:59 -0500 Subject: [PATCH 16/92] chore: update nix bun version (#23881) --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 805be8739b..1c8e62bd82 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1773909469, - "narHash": "sha256-vglVrLfHjFIzIdV9A27Ugul6rh3I1qHbbitGW7dk420=", + "lastModified": 1776683584, + "narHash": "sha256-NuTLMrr10Tng72hurYG8jYQ4XKK8wnpJmOGcPiis96g=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "7149c06513f335be57f26fcbbbe34afda923882b", + "rev": "9dd5558b06dbdacbf635a3dd36dce1b1a7ee3a89", "type": "github" }, "original": { From e383df4b17eecd6e6718e43c17438aa2eb818ee9 Mon Sep 17 00:00:00 2001 From: Luke Parker <10430890+Hona@users.noreply.github.com> Date: Thu, 23 Apr 2026 09:24:11 +1000 Subject: [PATCH 17/92] feat: support pull diagnostics in the LSP client (C#, Kotlin, etc) (#23771) --- packages/opencode/src/cli/cmd/debug/lsp.ts | 3 +- packages/opencode/src/lsp/client.ts | 574 +++++++++++++++--- packages/opencode/src/lsp/lsp.ts | 16 +- packages/opencode/src/lsp/server.ts | 2 +- packages/opencode/src/npm/index.ts | 15 +- packages/opencode/src/tool/apply_patch.ts | 2 +- packages/opencode/src/tool/edit.ts | 2 +- packages/opencode/src/tool/lsp.ts | 2 +- packages/opencode/src/tool/read.ts | 2 +- packages/opencode/src/tool/write.ts | 2 +- .../test/fixture/lsp/fake-lsp-server.js | 220 ++++++- packages/opencode/test/lsp/client.test.ts | 404 +++++++++++- 12 files changed, 1123 insertions(+), 121 deletions(-) diff --git a/packages/opencode/src/cli/cmd/debug/lsp.ts b/packages/opencode/src/cli/cmd/debug/lsp.ts index 185cab9c75..47db6358b6 100644 --- a/packages/opencode/src/cli/cmd/debug/lsp.ts +++ b/packages/opencode/src/cli/cmd/debug/lsp.ts @@ -23,8 +23,7 @@ const DiagnosticsCommand = cmd({ const out = await AppRuntime.runPromise( LSP.Service.use((lsp) => Effect.gen(function* () { - yield* lsp.touchFile(args.file, true) - yield* Effect.sleep(1000) + yield* lsp.touchFile(args.file, "full") return yield* lsp.diagnostics() }), ), diff --git a/packages/opencode/src/lsp/client.ts b/packages/opencode/src/lsp/client.ts index b20e8ae7f0..b0418ca3f5 100644 --- a/packages/opencode/src/lsp/client.ts +++ b/packages/opencode/src/lsp/client.ts @@ -14,6 +14,16 @@ import { withTimeout } from "../util/timeout" import { Filesystem } from "../util" const DIAGNOSTICS_DEBOUNCE_MS = 150 +const DIAGNOSTICS_DOCUMENT_WAIT_TIMEOUT_MS = 5_000 +const DIAGNOSTICS_FULL_WAIT_TIMEOUT_MS = 10_000 +const DIAGNOSTICS_REQUEST_TIMEOUT_MS = 3_000 + +const INITIALIZE_TIMEOUT_MS = 45_000 + +// LSP spec constants +const FILE_CHANGE_CREATED = 1 +const FILE_CHANGE_CHANGED = 2 +const TEXT_DOCUMENT_SYNC_INCREMENTAL = 2 const log = Log.create({ service: "lsp.client" }) @@ -38,48 +48,194 @@ export const Event = { ), } +type DocumentDiagnosticReport = { + items?: Diagnostic[] + relatedDocuments?: Record +} + +type WorkspaceDiagnosticReport = { + items?: { + uri?: string + items?: Diagnostic[] + }[] +} + +type DiagnosticRequestResult = { + handled: boolean + matched: boolean + byFile: Map +} + +type CapabilityRegistration = { + id: string + method: string + registerOptions?: { + identifier?: string + workspaceDiagnostics?: boolean + } +} + +type ServerCapabilities = { + textDocumentSync?: + | number + | { + change?: number + } + diagnosticProvider?: unknown + [key: string]: unknown +} + +function getFilePath(uri: string) { + if (!uri.startsWith("file://")) return + return Filesystem.normalizePath(fileURLToPath(uri)) +} + +function getSyncKind(capabilities?: ServerCapabilities) { + if (!capabilities) return + const sync = capabilities.textDocumentSync + if (typeof sync === "number") return sync + return sync?.change +} + +function endPosition(text: string) { + const lines = text.split(/\r\n|\r|\n/) + return { + line: lines.length - 1, + character: lines.at(-1)?.length ?? 0, + } +} + +function dedupeDiagnostics(items: Diagnostic[]) { + const seen = new Set() + return items.filter((item) => { + const key = JSON.stringify({ + code: item.code, + severity: item.severity, + message: item.message, + source: item.source, + range: item.range, + }) + if (seen.has(key)) return false + seen.add(key) + return true + }) +} + +function configurationValue(settings: unknown, section?: string) { + if (!section) return settings ?? null + const result = section.split(".").reduce((acc, key) => { + if (!acc || typeof acc !== "object" || !(key in acc)) return undefined + return (acc as Record)[key] + }, settings) + return result ?? null +} + +// TypeScript's built-in LSP pushes diagnostics aggressively on first open. +// We seed the push cache on the very first publish so waitForFreshPush can +// resolve immediately instead of waiting for a second debounced push. +function shouldSeedDiagnosticsOnFirstPush(serverID: string) { + return serverID === "typescript" +} + export async function create(input: { serverID: string; server: LSPServer.Handle; root: string; directory: string }) { - const l = log.clone().tag("serverID", input.serverID) - l.info("starting client") + const logger = log.clone().tag("serverID", input.serverID) + logger.info("starting client") const connection = createMessageConnection( new StreamMessageReader(input.server.process.stdout as any), new StreamMessageWriter(input.server.process.stdin as any), ) + // Server stderr can contain both real errors and routine informational logs, + // which is normal stderr practice for some tools. Keep the raw stream at + // debug so users can opt in with --print-logs --log-level DEBUG without + // polluting normal logs. + input.server.process.stderr?.on("data", (data: Buffer) => { + const text = data.toString().trim() + if (text) logger.debug("server stderr", { text: text.slice(0, 1000) }) + }) + + // --- Connection state --- + + const pushDiagnostics = new Map() + const pullDiagnostics = new Map() + const published = new Map() + const diagnosticRegistrations = new Map() + const registrationListeners = new Set<() => void>() + const mergedDiagnostics = (filePath: string) => + dedupeDiagnostics([...(pushDiagnostics.get(filePath) ?? []), ...(pullDiagnostics.get(filePath) ?? [])]) + const updatePushDiagnostics = (filePath: string, next: Diagnostic[]) => { + pushDiagnostics.set(filePath, next) + Bus.publish(Event.Diagnostics, { path: filePath, serverID: input.serverID }) + } + const updatePullDiagnostics = (filePath: string, next: Diagnostic[]) => { + pullDiagnostics.set(filePath, next) + } + const emitRegistrationChange = () => { + for (const listener of [...registrationListeners]) listener() + } + + // --- LSP connection handlers --- - const diagnostics = new Map() connection.onNotification("textDocument/publishDiagnostics", (params) => { - const filePath = Filesystem.normalizePath(fileURLToPath(params.uri)) - l.info("textDocument/publishDiagnostics", { + const filePath = getFilePath(params.uri) + if (!filePath) return + logger.info("textDocument/publishDiagnostics", { path: filePath, count: params.diagnostics.length, + version: params.version, }) - const exists = diagnostics.has(filePath) - diagnostics.set(filePath, params.diagnostics) - if (!exists && input.serverID === "typescript") return - Bus.publish(Event.Diagnostics, { path: filePath, serverID: input.serverID }) + published.set(filePath, { + at: Date.now(), + version: typeof params.version === "number" ? params.version : undefined, + }) + if (shouldSeedDiagnosticsOnFirstPush(input.serverID) && !pushDiagnostics.has(filePath)) { + pushDiagnostics.set(filePath, params.diagnostics) + return + } + updatePushDiagnostics(filePath, params.diagnostics) }) connection.onRequest("window/workDoneProgress/create", (params) => { - l.info("window/workDoneProgress/create", params) + logger.info("window/workDoneProgress/create", params) return null }) - connection.onRequest("workspace/configuration", async () => { - // Return server initialization options - return [input.server.initialization ?? {}] + connection.onRequest("workspace/configuration", async (params) => { + const items = (params as { items?: { section?: string }[] }).items ?? [] + return items.map((item) => configurationValue(input.server.initialization, item.section)) + }) + connection.onRequest("client/registerCapability", async (params) => { + const registrations = (params as { registrations?: CapabilityRegistration[] }).registrations ?? [] + let changed = false + for (const registration of registrations) { + if (registration.method !== "textDocument/diagnostic") continue + diagnosticRegistrations.set(registration.id, registration) + changed = true + } + if (changed) emitRegistrationChange() + }) + connection.onRequest("client/unregisterCapability", async (params) => { + const registrations = (params as { unregisterations?: { id: string; method: string }[] }).unregisterations ?? [] + let changed = false + for (const registration of registrations) { + if (registration.method !== "textDocument/diagnostic") continue + diagnosticRegistrations.delete(registration.id) + changed = true + } + if (changed) emitRegistrationChange() }) - connection.onRequest("client/registerCapability", async () => {}) - connection.onRequest("client/unregisterCapability", async () => {}) connection.onRequest("workspace/workspaceFolders", async () => [ { name: "workspace", uri: pathToFileURL(input.root).href, }, ]) + connection.onRequest("workspace/diagnostic/refresh", async () => null) connection.listen() - l.info("sending initialize") - await withTimeout( - connection.sendRequest("initialize", { + // --- Initialize handshake --- + + logger.info("sending initialize") + const initialized = await withTimeout( + connection.sendRequest<{ capabilities?: ServerCapabilities }>("initialize", { rootUri: pathToFileURL(input.root).href, processId: input.server.process.pid, workspaceFolders: [ @@ -100,21 +256,28 @@ export async function create(input: { serverID: string; server: LSPServer.Handle didChangeWatchedFiles: { dynamicRegistration: true, }, + diagnostics: { + refreshSupport: false, + }, }, textDocument: { synchronization: { didOpen: true, didChange: true, }, + diagnostic: { + dynamicRegistration: true, + relatedDocumentSupport: true, + }, publishDiagnostics: { - versionSupport: true, + versionSupport: false, }, }, }, }), - 45_000, + INITIALIZE_TIMEOUT_MS, ).catch((err) => { - l.error("initialize error", { error: err }) + logger.error("initialize error", { error: err }) throw new InitializeError( { serverID: input.serverID }, { @@ -123,6 +286,9 @@ export async function create(input: { serverID: string; server: LSPServer.Handle ) }) + const syncKind = getSyncKind(initialized.capabilities) + const hasStaticPullDiagnostics = Boolean(initialized.capabilities?.diagnosticProvider) + await connection.sendNotification("initialized", {}) if (input.server.initialization) { @@ -131,9 +297,271 @@ export async function create(input: { serverID: string; server: LSPServer.Handle }) } - const files: { - [path: string]: number - } = {} + const files: Record = {} + + // --- Diagnostic helpers --- + + const mergeResults = (filePath: string, results: DiagnosticRequestResult[]) => { + const handled = results.some((result) => result.handled) + const matched = results.some((result) => result.matched) + if (!handled) return { handled: false, matched: false } + + const merged = new Map() + for (const result of results) { + for (const [target, items] of result.byFile.entries()) { + const existing = merged.get(target) ?? [] + merged.set(target, existing.concat(items)) + } + } + + if (matched && !merged.has(filePath)) merged.set(filePath, []) + for (const [target, items] of merged.entries()) { + updatePullDiagnostics(target, dedupeDiagnostics(items)) + } + + return { handled, matched } + } + + async function requestDiagnosticReport(filePath: string, identifier?: string): Promise { + const report = await withTimeout( + connection.sendRequest("textDocument/diagnostic", { + ...(identifier ? { identifier } : {}), + textDocument: { + uri: pathToFileURL(filePath).href, + }, + }), + DIAGNOSTICS_REQUEST_TIMEOUT_MS, + ).catch(() => null) + if (!report) return { handled: false, matched: false, byFile: new Map() } + + const byFile = new Map() + const push = (target: string, items: Diagnostic[]) => { + const existing = byFile.get(target) ?? [] + byFile.set(target, existing.concat(items)) + } + + let handled = false + let matched = false + if (Array.isArray(report.items)) { + push(filePath, report.items) + handled = true + matched = true + } + for (const [uri, related] of Object.entries(report.relatedDocuments ?? {})) { + const relatedPath = getFilePath(uri) + if (!relatedPath || !Array.isArray(related.items)) continue + push(relatedPath, related.items) + handled = true + matched = matched || relatedPath === filePath + } + + return { handled, matched, byFile } + } + + async function requestWorkspaceDiagnosticReport(filePath: string, identifier?: string): Promise { + const report = await withTimeout( + connection.sendRequest("workspace/diagnostic", { + ...(identifier ? { identifier } : {}), + previousResultIds: [], + }), + DIAGNOSTICS_REQUEST_TIMEOUT_MS, + ).catch(() => null) + if (!report) return { handled: false, matched: false, byFile: new Map() } + + const byFile = new Map() + let matched = false + for (const item of report.items ?? []) { + const relatedPath = item.uri ? getFilePath(item.uri) : undefined + if (!relatedPath || !Array.isArray(item.items)) continue + const existing = byFile.get(relatedPath) ?? [] + byFile.set(relatedPath, existing.concat(item.items)) + matched = matched || relatedPath === filePath + } + + return { handled: true, matched, byFile } + } + + function documentPullState() { + const documentRegistrations = [...diagnosticRegistrations.values()].filter( + (registration) => registration.registerOptions?.workspaceDiagnostics !== true, + ) + return { + documentIdentifiers: [...new Set(documentRegistrations.flatMap((registration) => registration.registerOptions?.identifier ?? []))], + supported: hasStaticPullDiagnostics || documentRegistrations.length > 0, + } + } + + function workspacePullState() { + const workspaceRegistrations = [...diagnosticRegistrations.values()].filter( + (registration) => registration.registerOptions?.workspaceDiagnostics === true, + ) + return { + workspaceIdentifiers: [...new Set(workspaceRegistrations.flatMap((registration) => registration.registerOptions?.identifier ?? []))], + supported: workspaceRegistrations.length > 0, + } + } + + const hasCurrentFileDiagnostics = (filePath: string, results: DiagnosticRequestResult[]) => + results.some((result) => (result.byFile.get(filePath)?.length ?? 0) > 0) + + async function requestDiagnostics( + filePath: string, + requests: Promise[], + done: (results: DiagnosticRequestResult[]) => boolean, + ) { + if (!requests.length) return { handled: false, matched: false } + + const results: DiagnosticRequestResult[] = [] + return new Promise<{ handled: boolean; matched: boolean }>((resolve) => { + let pending = requests.length + let resolved = false + const finish = (merged: { handled: boolean; matched: boolean }, force = false) => { + if (resolved) return + if (!force && !done(results)) return + resolved = true + resolve(merged) + } + + for (const request of requests) { + request.then((result) => { + results.push(result) + pending -= 1 + const merged = mergeResults(filePath, results) + finish(merged) + if (pending === 0) finish(merged, true) + }) + } + }) + } + + // LATENCY-CRITICAL: dispatch identifier pulls in parallel and unblock once one + // batch already produced diagnostics for the current file. Let slower pulls keep + // merging in the background; do not sequence identifier-by-identifier, and do + // not add a post-match settle/debounce delay. See PR #23771. + async function requestDocumentDiagnostics(filePath: string) { + const state = documentPullState() + if (!state.supported) return { handled: false, matched: false } + return requestDiagnostics( + filePath, + [ + requestDiagnosticReport(filePath), + ...state.documentIdentifiers.map((identifier) => requestDiagnosticReport(filePath, identifier)), + ], + (results) => hasCurrentFileDiagnostics(filePath, results), + ) + } + + async function requestFullDiagnostics(filePath: string) { + const documentState = documentPullState() + const workspaceState = workspacePullState() + if (!documentState.supported && !workspaceState.supported) return { handled: false, matched: false } + return mergeResults( + filePath, + await Promise.all([ + ...(documentState.supported ? [requestDiagnosticReport(filePath)] : []), + ...documentState.documentIdentifiers.map((identifier) => requestDiagnosticReport(filePath, identifier)), + ...(workspaceState.supported ? [requestWorkspaceDiagnosticReport(filePath)] : []), + ...workspaceState.workspaceIdentifiers.map((identifier) => requestWorkspaceDiagnosticReport(filePath, identifier)), + ]), + ) + } + + function waitForRegistrationChange(timeout: number) { + if (timeout <= 0) return Promise.resolve(false) + return new Promise((resolve) => { + let finished = false + let timer: ReturnType | undefined + const finish = (result: boolean) => { + if (finished) return + finished = true + if (timer) clearTimeout(timer) + registrationListeners.delete(listener) + resolve(result) + } + const listener = () => finish(true) + registrationListeners.add(listener) + timer = setTimeout(() => finish(false), timeout) + }) + } + + function waitForFreshPush(request: { path: string; version: number; after: number; timeout: number }) { + if (request.timeout <= 0) return Promise.resolve(false) + return new Promise((resolve) => { + let finished = false + let debounceTimer: ReturnType | undefined + let timeoutTimer: ReturnType | undefined + let unsub: (() => void) | undefined + const finish = (result: boolean) => { + if (finished) return + finished = true + if (debounceTimer) clearTimeout(debounceTimer) + if (timeoutTimer) clearTimeout(timeoutTimer) + unsub?.() + resolve(result) + } + const schedule = () => { + const hit = published.get(request.path) + if (!hit) return + if (typeof hit.version === "number" && hit.version !== request.version) return + if (hit.at < request.after && hit.version !== request.version) return + if (debounceTimer) clearTimeout(debounceTimer) + debounceTimer = setTimeout(() => finish(true), Math.max(0, DIAGNOSTICS_DEBOUNCE_MS - (Date.now() - hit.at))) + } + + timeoutTimer = setTimeout(() => finish(false), request.timeout) + unsub = Bus.subscribe(Event.Diagnostics, (event) => { + if (event.properties.path !== request.path || event.properties.serverID !== input.serverID) return + schedule() + }) + schedule() + }) + } + + async function waitForDocumentDiagnostics(request: { path: string; version: number; after?: number }) { + const startedAt = request.after ?? Date.now() + const pushWait = waitForFreshPush({ + path: request.path, + version: request.version, + after: startedAt, + timeout: DIAGNOSTICS_DOCUMENT_WAIT_TIMEOUT_MS, + }) + + while (Date.now() - startedAt < DIAGNOSTICS_DOCUMENT_WAIT_TIMEOUT_MS) { + const result = await requestDocumentDiagnostics(request.path) + if (result.matched) return + const remaining = DIAGNOSTICS_DOCUMENT_WAIT_TIMEOUT_MS - (Date.now() - startedAt) + if (remaining <= 0) return + const next = await Promise.race([ + pushWait.then((ready) => (ready ? "push" : "timeout" as const)), + waitForRegistrationChange(remaining).then((changed) => (changed ? "registration" : "timeout" as const)), + ]) + if (next !== "registration") return + } + } + + async function waitForFullDiagnostics(request: { path: string; version: number; after?: number }) { + const startedAt = request.after ?? Date.now() + const pushWait = waitForFreshPush({ + path: request.path, + version: request.version, + after: startedAt, + timeout: DIAGNOSTICS_FULL_WAIT_TIMEOUT_MS, + }) + + while (Date.now() - startedAt < DIAGNOSTICS_FULL_WAIT_TIMEOUT_MS) { + const result = await requestFullDiagnostics(request.path) + if (result.handled || result.matched) return + const remaining = DIAGNOSTICS_FULL_WAIT_TIMEOUT_MS - (Date.now() - startedAt) + if (remaining <= 0) return + const next = await Promise.race([ + pushWait.then((ready) => (ready ? "push" : "timeout" as const)), + waitForRegistrationChange(remaining).then((changed) => (changed ? "registration" : "timeout" as const)), + ]) + if (next !== "registration") return + } + } + + // --- Public API --- const result = { root: input.root, @@ -145,26 +573,32 @@ export async function create(input: { serverID: string; server: LSPServer.Handle }, notify: { async open(request: { path: string }) { - request.path = path.isAbsolute(request.path) ? request.path : path.resolve(input.directory, request.path) + request.path = Filesystem.normalizePath( + path.isAbsolute(request.path) ? request.path : path.resolve(input.directory, request.path), + ) const text = await Filesystem.readText(request.path) const extension = path.extname(request.path) const languageId = LANGUAGE_EXTENSIONS[extension] ?? "plaintext" - const version = files[request.path] - if (version !== undefined) { - log.info("workspace/didChangeWatchedFiles", request) + const document = files[request.path] + if (document !== undefined) { + // Do not wipe diagnostics on didChange. Some servers (e.g. clangd) only + // re-emit diagnostics when the content actually changes, so clearing + // here would lose errors for no-op touchFile calls. Let the server's + // next push/pull overwrite naturally. + logger.info("workspace/didChangeWatchedFiles", request) await connection.sendNotification("workspace/didChangeWatchedFiles", { changes: [ { uri: pathToFileURL(request.path).href, - type: 2, // Changed + type: FILE_CHANGE_CHANGED, }, ], }) - const next = version + 1 - files[request.path] = next - log.info("textDocument/didChange", { + const next = document.version + 1 + files[request.path] = { version: next, text } + logger.info("textDocument/didChange", { path: request.path, version: next, }) @@ -173,23 +607,35 @@ export async function create(input: { serverID: string; server: LSPServer.Handle uri: pathToFileURL(request.path).href, version: next, }, - contentChanges: [{ text }], + contentChanges: + syncKind === TEXT_DOCUMENT_SYNC_INCREMENTAL + ? [ + { + range: { + start: { line: 0, character: 0 }, + end: endPosition(document.text), + }, + text, + }, + ] + : [{ text }], }) - return + return next } - log.info("workspace/didChangeWatchedFiles", request) + logger.info("workspace/didChangeWatchedFiles", request) await connection.sendNotification("workspace/didChangeWatchedFiles", { changes: [ { uri: pathToFileURL(request.path).href, - type: 1, // Created + type: FILE_CHANGE_CREATED, }, ], }) - log.info("textDocument/didOpen", request) - diagnostics.delete(request.path) + logger.info("textDocument/didOpen", request) + pushDiagnostics.delete(request.path) + pullDiagnostics.delete(request.path) await connection.sendNotification("textDocument/didOpen", { textDocument: { uri: pathToFileURL(request.path).href, @@ -198,52 +644,42 @@ export async function create(input: { serverID: string; server: LSPServer.Handle text, }, }) - files[request.path] = 0 - return + files[request.path] = { version: 0, text } + return 0 }, }, get diagnostics() { - return diagnostics + const result = new Map() + for (const key of new Set([...pushDiagnostics.keys(), ...pullDiagnostics.keys()])) { + result.set(key, mergedDiagnostics(key)) + } + return result }, - async waitForDiagnostics(request: { path: string }) { + async waitForDiagnostics(request: { path: string; version: number; mode?: "document" | "full"; after?: number }) { const normalizedPath = Filesystem.normalizePath( path.isAbsolute(request.path) ? request.path : path.resolve(input.directory, request.path), ) - log.info("waiting for diagnostics", { path: normalizedPath }) - let unsub: () => void - let debounceTimer: ReturnType | undefined - return await withTimeout( - new Promise((resolve) => { - unsub = Bus.subscribe(Event.Diagnostics, (event) => { - if (event.properties.path === normalizedPath && event.properties.serverID === result.serverID) { - // Debounce to allow LSP to send follow-up diagnostics (e.g., semantic after syntax) - if (debounceTimer) clearTimeout(debounceTimer) - debounceTimer = setTimeout(() => { - log.info("got diagnostics", { path: normalizedPath }) - unsub?.() - resolve() - }, DIAGNOSTICS_DEBOUNCE_MS) - } - }) - }), - 3000, - ) - .catch(() => {}) - .finally(() => { - if (debounceTimer) clearTimeout(debounceTimer) - unsub?.() - }) + logger.info("waiting for diagnostics", { + path: normalizedPath, + mode: request.mode ?? "full", + version: request.version, + }) + if (request.mode === "document") { + await waitForDocumentDiagnostics({ path: normalizedPath, version: request.version, after: request.after }) + return + } + await waitForFullDiagnostics({ path: normalizedPath, version: request.version, after: request.after }) }, async shutdown() { - l.info("shutting down") + logger.info("shutting down") connection.end() connection.dispose() await Process.stop(input.server.process) - l.info("shutdown") + logger.info("shutdown") }, } - l.info("initialized") + logger.info("initialized") return result } diff --git a/packages/opencode/src/lsp/lsp.ts b/packages/opencode/src/lsp/lsp.ts index 833285e7b5..4c46cd9aa7 100644 --- a/packages/opencode/src/lsp/lsp.ts +++ b/packages/opencode/src/lsp/lsp.ts @@ -136,7 +136,7 @@ export interface Interface { readonly init: () => Effect.Effect readonly status: () => Effect.Effect readonly hasClients: (file: string) => Effect.Effect - readonly touchFile: (input: string, waitForDiagnostics?: boolean) => Effect.Effect + readonly touchFile: (input: string, diagnostics?: "document" | "full") => Effect.Effect readonly diagnostics: () => Effect.Effect> readonly hover: (input: LocInput) => Effect.Effect readonly definition: (input: LocInput) => Effect.Effect @@ -358,15 +358,21 @@ export const layer = Layer.effect( }) }) - const touchFile = Effect.fn("LSP.touchFile")(function* (input: string, waitForDiagnostics?: boolean) { + const touchFile = Effect.fn("LSP.touchFile")(function* (input: string, diagnostics?: "document" | "full") { log.info("touching file", { file: input }) const clients = yield* getClients(input) yield* Effect.promise(() => Promise.all( clients.map(async (client) => { - const wait = waitForDiagnostics ? client.waitForDiagnostics({ path: input }) : Promise.resolve() - await client.notify.open({ path: input }) - return wait + const after = Date.now() + const version = await client.notify.open({ path: input }) + if (!diagnostics) return + return client.waitForDiagnostics({ + path: input, + version, + mode: diagnostics, + after, + }) }), ).catch((err) => { log.error("failed to touch file", { err, file: input }) diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts index 8bb70a5116..a0cb8fe388 100644 --- a/packages/opencode/src/lsp/server.ts +++ b/packages/opencode/src/lsp/server.ts @@ -490,7 +490,7 @@ export const Pyright: Info = { const args = [] if (!binary) { if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - const resolved = await Npm.which("pyright") + const resolved = await Npm.which("pyright", "pyright-langserver") if (!resolved) return binary = resolved } diff --git a/packages/opencode/src/npm/index.ts b/packages/opencode/src/npm/index.ts index 477e99e06a..fc8497d20b 100644 --- a/packages/opencode/src/npm/index.ts +++ b/packages/opencode/src/npm/index.ts @@ -34,7 +34,7 @@ export interface Interface { }, ) => Effect.Effect readonly outdated: (pkg: string, cachedVersion: string) => Effect.Effect - readonly which: (pkg: string) => Effect.Effect> + readonly which: (pkg: string, bin?: string) => Effect.Effect> } export class Service extends Context.Service()("@opencode/Npm") {} @@ -207,7 +207,7 @@ export const layer = Layer.effect( return }, Effect.scoped) - const which = Effect.fn("Npm.which")(function* (pkg: string) { + const which = Effect.fn("Npm.which")(function* (pkg: string, bin?: string) { const dir = directory(pkg) const binDir = path.join(dir, "node_modules", ".bin") @@ -215,6 +215,9 @@ export const layer = Layer.effect( const files = yield* fs.readDirectory(binDir).pipe(Effect.catch(() => Effect.succeed([] as string[]))) if (files.length === 0) return Option.none() + // Caller picked a specific bin (e.g. pyright exposes both `pyright` and + // `pyright-langserver`); trust the hint if the package provides it. + if (bin) return files.includes(bin) ? Option.some(bin) : Option.none() if (files.length === 1) return Option.some(files[0]) const pkgJson = yield* afs.readJson(path.join(dir, "node_modules", pkg, "package.json")).pipe(Effect.option) @@ -223,11 +226,11 @@ export const layer = Layer.effect( const parsed = pkgJson.value as { bin?: string | Record } if (parsed?.bin) { const unscoped = pkg.startsWith("@") ? pkg.split("/")[1] : pkg - const bin = parsed.bin - if (typeof bin === "string") return Option.some(unscoped) - const keys = Object.keys(bin) + const parsedBin = parsed.bin + if (typeof parsedBin === "string") return Option.some(unscoped) + const keys = Object.keys(parsedBin) if (keys.length === 1) return Option.some(keys[0]) - return bin[unscoped] ? Option.some(unscoped) : Option.some(keys[0]) + return parsedBin[unscoped] ? Option.some(unscoped) : Option.some(keys[0]) } } diff --git a/packages/opencode/src/tool/apply_patch.ts b/packages/opencode/src/tool/apply_patch.ts index a4cf1e853f..33112c43c5 100644 --- a/packages/opencode/src/tool/apply_patch.ts +++ b/packages/opencode/src/tool/apply_patch.ts @@ -258,7 +258,7 @@ export const ApplyPatchTool = Tool.define( for (const change of fileChanges) { if (change.type === "delete") continue const target = change.movePath ?? change.filePath - yield* lsp.touchFile(target, true) + yield* lsp.touchFile(target, "document") } const diagnostics = yield* lsp.diagnostics() diff --git a/packages/opencode/src/tool/edit.ts b/packages/opencode/src/tool/edit.ts index 858d14e043..35dd85b476 100644 --- a/packages/opencode/src/tool/edit.ts +++ b/packages/opencode/src/tool/edit.ts @@ -186,7 +186,7 @@ export const EditTool = Tool.define( }) let output = "Edit applied successfully." - yield* lsp.touchFile(filePath, true) + yield* lsp.touchFile(filePath, "document") const diagnostics = yield* lsp.diagnostics() const normalizedFilePath = AppFileSystem.normalizePath(filePath) const block = LSP.Diagnostic.report(filePath, diagnostics[normalizedFilePath] ?? []) diff --git a/packages/opencode/src/tool/lsp.ts b/packages/opencode/src/tool/lsp.ts index 263bfe81d2..0a0edc61ed 100644 --- a/packages/opencode/src/tool/lsp.ts +++ b/packages/opencode/src/tool/lsp.ts @@ -55,7 +55,7 @@ export const LspTool = Tool.define( const available = yield* lsp.hasClients(file) if (!available) throw new Error("No LSP server available for this file type.") - yield* lsp.touchFile(file, true) + yield* lsp.touchFile(file, "document") const result: unknown[] = yield* (() => { switch (args.operation) { diff --git a/packages/opencode/src/tool/read.ts b/packages/opencode/src/tool/read.ts index c9b3048626..a9b95346a1 100644 --- a/packages/opencode/src/tool/read.ts +++ b/packages/opencode/src/tool/read.ts @@ -75,7 +75,7 @@ export const ReadTool = Tool.define( }) const warm = Effect.fn("ReadTool.warm")(function* (filepath: string) { - yield* lsp.touchFile(filepath, false).pipe(Effect.ignore, Effect.forkIn(scope)) + yield* lsp.touchFile(filepath).pipe(Effect.ignore, Effect.forkIn(scope)) }) const readSample = Effect.fn("ReadTool.readSample")(function* ( diff --git a/packages/opencode/src/tool/write.ts b/packages/opencode/src/tool/write.ts index 79ed585198..80198f4555 100644 --- a/packages/opencode/src/tool/write.ts +++ b/packages/opencode/src/tool/write.ts @@ -67,7 +67,7 @@ export const WriteTool = Tool.define( }) let output = "Wrote file successfully." - yield* lsp.touchFile(filepath, true) + yield* lsp.touchFile(filepath, "document") const diagnostics = yield* lsp.diagnostics() const normalizedFilepath = AppFileSystem.normalizePath(filepath) let projectDiagnosticsCount = 0 diff --git a/packages/opencode/test/fixture/lsp/fake-lsp-server.js b/packages/opencode/test/fixture/lsp/fake-lsp-server.js index be62f96f38..e6818009e1 100644 --- a/packages/opencode/test/fixture/lsp/fake-lsp-server.js +++ b/packages/opencode/test/fixture/lsp/fake-lsp-server.js @@ -1,7 +1,23 @@ // Simple JSON-RPC 2.0 LSP-like fake server over stdio -// Implements a minimal LSP handshake and triggers a request upon notification let nextId = 1 +let readBuffer = Buffer.alloc(0) +let lastChange = null +let initializeParams = null +let diagnosticRequestCount = 0 +let registeredCapability = false +const pendingClientRequests = new Map() +let pullConfig = { + delayMs: 0, + registerOn: undefined, + registrations: [], + documentDiagnostics: [], + documentDiagnosticsByIdentifier: {}, + documentDelayMsByIdentifier: {}, + workspaceDiagnostics: [], + workspaceDiagnosticsByIdentifier: {}, + workspaceDelayMsByIdentifier: {}, +} function encode(message) { const json = JSON.stringify(message) @@ -14,29 +30,19 @@ function decodeFrames(buffer) { let idx while ((idx = buffer.indexOf("\r\n\r\n")) !== -1) { const header = buffer.slice(0, idx).toString("utf8") - const m = /Content-Length:\s*(\d+)/i.exec(header) - const len = m ? parseInt(m[1], 10) : 0 + const match = /Content-Length:\s*(\d+)/i.exec(header) + const length = match ? parseInt(match[1], 10) : 0 const bodyStart = idx + 4 - const bodyEnd = bodyStart + len + const bodyEnd = bodyStart + length if (buffer.length < bodyEnd) break - const body = buffer.slice(bodyStart, bodyEnd).toString("utf8") - results.push(body) + results.push(buffer.slice(bodyStart, bodyEnd).toString("utf8")) buffer = buffer.slice(bodyEnd) } return { messages: results, rest: buffer } } -let readBuffer = Buffer.alloc(0) - -process.stdin.on("data", (chunk) => { - readBuffer = Buffer.concat([readBuffer, chunk]) - const { messages, rest } = decodeFrames(readBuffer) - readBuffer = rest - for (const m of messages) handle(m) -}) - -function send(msg) { - process.stdout.write(encode(msg)) +function send(message) { + process.stdout.write(encode(message)) } function sendRequest(method, params) { @@ -45,6 +51,50 @@ function sendRequest(method, params) { return id } +function sendResponse(id, result) { + send({ jsonrpc: "2.0", id, result }) +} + +function sendNotification(method, params) { + send({ jsonrpc: "2.0", method, params }) +} + +function maybeRegister(method) { + if (pullConfig.registerOn !== method || registeredCapability) return + registeredCapability = true + sendRequest("client/registerCapability", { + registrations: pullConfig.registrations.map((registration, index) => ({ + id: registration.id ?? `pull-${index}`, + method: registration.method ?? "textDocument/diagnostic", + registerOptions: registration.registerOptions ?? registration, + })), + }) +} + +function delayed(id, result, delayMs = pullConfig.delayMs) { + if (!delayMs) { + sendResponse(id, result) + return + } + setTimeout(() => sendResponse(id, result), delayMs) +} + +function diagnosticsForIdentifier(identifier) { + return pullConfig.documentDiagnosticsByIdentifier[identifier] ?? pullConfig.documentDiagnostics +} + +function workspaceDiagnosticsForIdentifier(identifier) { + return pullConfig.workspaceDiagnosticsByIdentifier[identifier] ?? pullConfig.workspaceDiagnostics +} + +function documentDelayForIdentifier(identifier) { + return pullConfig.documentDelayMsByIdentifier[identifier] ?? pullConfig.delayMs +} + +function workspaceDelayForIdentifier(identifier) { + return pullConfig.workspaceDelayMsByIdentifier[identifier] ?? pullConfig.delayMs +} + function handle(raw) { let data try { @@ -52,24 +102,148 @@ function handle(raw) { } catch { return } + + if (typeof data.method === "undefined" && typeof data.id !== "undefined") { + const pending = pendingClientRequests.get(data.id) + if (!pending) return + pendingClientRequests.delete(data.id) + sendResponse(pending, data.result ?? null) + return + } + if (data.method === "initialize") { - send({ jsonrpc: "2.0", id: data.id, result: { capabilities: {} } }) + initializeParams = data.params + sendResponse(data.id, { + capabilities: { + textDocumentSync: { + change: 2, + }, + }, + }) return } - if (data.method === "initialized") { + + if (data.method === "test/get-initialize-params") { + sendResponse(data.id, initializeParams) return } - if (data.method === "workspace/didChangeConfiguration") { + + if (data.method === "test/request-configuration") { + const id = sendRequest("workspace/configuration", data.params) + pendingClientRequests.set(id, data.id) return } + + if (data.method === "initialized" || data.method === "workspace/didChangeConfiguration") { + return + } + + if (data.method === "textDocument/didOpen") { + maybeRegister("didOpen") + return + } + + if (data.method === "textDocument/didChange") { + lastChange = data.params + maybeRegister("didChange") + return + } + if (data.method === "test/trigger") { const method = data.params && data.params.method + if (method === "client/registerCapability") { + sendRequest(method, { + registrations: [ + { + id: "test-diagnostic-registration", + method: "textDocument/diagnostic", + registerOptions: { identifier: "syntax" }, + }, + ], + }) + return + } + if (method === "client/unregisterCapability") { + sendRequest(method, { + unregisterations: [{ id: "test-diagnostic-registration", method: "textDocument/diagnostic" }], + }) + return + } if (method) sendRequest(method, {}) return } - if (typeof data.id !== "undefined") { - // Respond OK to any request from client to keep transport flowing - send({ jsonrpc: "2.0", id: data.id, result: null }) + + if (data.method === "test/configure-pull-diagnostics") { + pullConfig = { + delayMs: data.params?.delayMs ?? 0, + registerOn: data.params?.registerOn, + registrations: data.params?.registrations ?? [], + documentDiagnostics: data.params?.documentDiagnostics ?? [], + documentDiagnosticsByIdentifier: data.params?.documentDiagnosticsByIdentifier ?? {}, + documentDelayMsByIdentifier: data.params?.documentDelayMsByIdentifier ?? {}, + workspaceDiagnostics: data.params?.workspaceDiagnostics ?? [], + workspaceDiagnosticsByIdentifier: data.params?.workspaceDiagnosticsByIdentifier ?? {}, + workspaceDelayMsByIdentifier: data.params?.workspaceDelayMsByIdentifier ?? {}, + } + registeredCapability = false + sendResponse(data.id, null) return } + + if (data.method === "test/register-configured-pull-diagnostics") { + maybeRegister(undefined) + sendResponse(data.id, null) + return + } + + if (data.method === "test/publish-diagnostics") { + sendNotification("textDocument/publishDiagnostics", data.params) + return + } + + if (data.method === "test/get-last-change") { + sendResponse(data.id, lastChange) + return + } + + if (data.method === "test/get-diagnostic-request-count") { + sendResponse(data.id, diagnosticRequestCount) + return + } + + if (data.method === "textDocument/diagnostic") { + diagnosticRequestCount += 1 + delayed( + data.id, + { + kind: "full", + items: diagnosticsForIdentifier(data.params?.identifier ?? ""), + }, + documentDelayForIdentifier(data.params?.identifier ?? ""), + ) + return + } + + if (data.method === "workspace/diagnostic") { + diagnosticRequestCount += 1 + delayed( + data.id, + { + items: workspaceDiagnosticsForIdentifier(data.params?.identifier ?? ""), + }, + workspaceDelayForIdentifier(data.params?.identifier ?? ""), + ) + return + } + + if (typeof data.id !== "undefined") { + sendResponse(data.id, null) + } } + +process.stdin.on("data", (chunk) => { + readBuffer = Buffer.concat([readBuffer, chunk]) + const { messages, rest } = decodeFrames(readBuffer) + readBuffer = rest + for (const message of messages) handle(message) +}) diff --git a/packages/opencode/test/lsp/client.test.ts b/packages/opencode/test/lsp/client.test.ts index d6eaa317f9..4862f68394 100644 --- a/packages/opencode/test/lsp/client.test.ts +++ b/packages/opencode/test/lsp/client.test.ts @@ -1,11 +1,12 @@ -import { describe, expect, test, beforeEach } from "bun:test" +import { beforeEach, describe, expect, test } from "bun:test" import path from "path" +import { pathToFileURL } from "url" +import { tmpdir } from "../fixture/fixture" import { LSPClient } from "../../src/lsp" import { LSPServer } from "../../src/lsp" import { Instance } from "../../src/project/instance" import { Log } from "../../src/util" -// Minimal fake LSP server that speaks JSON-RPC over stdio function spawnFakeServer() { const { spawn } = require("child_process") const serverPath = path.join(__dirname, "../fixture/lsp/fake-lsp-server.js") @@ -39,10 +40,8 @@ describe("LSPClient interop", () => { method: "workspace/workspaceFolders", }) - await new Promise((r) => setTimeout(r, 100)) - + await new Promise((resolve) => setTimeout(resolve, 100)) expect(client.connection).toBeDefined() - await client.shutdown() }) @@ -64,10 +63,8 @@ describe("LSPClient interop", () => { method: "client/registerCapability", }) - await new Promise((r) => setTimeout(r, 100)) - + await new Promise((resolve) => setTimeout(resolve, 100)) expect(client.connection).toBeDefined() - await client.shutdown() }) @@ -89,10 +86,397 @@ describe("LSPClient interop", () => { method: "client/unregisterCapability", }) - await new Promise((r) => setTimeout(r, 100)) - + await new Promise((resolve) => setTimeout(resolve, 100)) expect(client.connection).toBeDefined() + await client.shutdown() + }) + + test("initialize does not overclaim unsupported diagnostics capabilities", async () => { + const handle = spawnFakeServer() as any + + const client = await Instance.provide({ + directory: process.cwd(), + fn: () => + LSPClient.create({ + serverID: "fake", + server: handle as unknown as LSPServer.Handle, + root: process.cwd(), + directory: process.cwd(), + }), + }) + + const params = await client.connection.sendRequest("test/get-initialize-params", {}) + expect(params.capabilities.workspace.diagnostics.refreshSupport).toBe(false) + expect(params.capabilities.textDocument.publishDiagnostics.versionSupport).toBe(false) await client.shutdown() }) + + test("workspace/configuration returns one result per requested item", async () => { + const handle = spawnFakeServer() as any + const initialization = { + alpha: { + beta: 1, + }, + gamma: true, + } + + const client = await Instance.provide({ + directory: process.cwd(), + fn: () => + LSPClient.create({ + serverID: "fake", + server: { + ...(handle as unknown as LSPServer.Handle), + initialization, + }, + root: process.cwd(), + directory: process.cwd(), + }), + }) + + const response = await client.connection.sendRequest("test/request-configuration", { + items: [{ section: "alpha" }, { section: "alpha.beta" }, { section: "missing" }, {}], + }) + + expect(response).toEqual([{ beta: 1 }, 1, null, initialization]) + + await client.shutdown() + }) + + test("sends ranged didChange for incremental sync servers", async () => { + const handle = spawnFakeServer() as any + await using tmp = await tmpdir() + const file = path.join(tmp.path, "client.ts") + await Bun.write(file, "first\n") + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const client = await LSPClient.create({ + serverID: "fake", + server: handle as unknown as LSPServer.Handle, + root: tmp.path, + directory: tmp.path, + }) + + await client.notify.open({ path: file }) + await Bun.write(file, "second\nthird\n") + await client.notify.open({ path: file }) + + const change = await client.connection.sendRequest<{ + textDocument: { version: number } + contentChanges: { + range?: { start: { line: number; character: number }; end: { line: number; character: number } } + text: string + }[] + }>("test/get-last-change", {}) + expect(change.textDocument.version).toBe(1) + expect(change.contentChanges).toEqual([ + { + range: { + start: { line: 0, character: 0 }, + end: { line: 1, character: 0 }, + }, + text: "second\nthird\n", + }, + ]) + + await client.shutdown() + }, + }) + }) + + test("document mode falls back to push diagnostics", async () => { + const handle = spawnFakeServer() as any + await using tmp = await tmpdir() + const file = path.join(tmp.path, "client.ts") + await Bun.write(file, "const x = 1\n") + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const client = await LSPClient.create({ + serverID: "fake", + server: handle as unknown as LSPServer.Handle, + root: tmp.path, + directory: tmp.path, + }) + + const version = await client.notify.open({ path: file }) + const wait = client.waitForDiagnostics({ path: file, version, mode: "document" }) + await client.connection.sendNotification("test/publish-diagnostics", { + uri: pathToFileURL(file).href, + version, + diagnostics: [ + { + range: { + start: { line: 0, character: 0 }, + end: { line: 0, character: 5 }, + }, + message: "push diagnostic", + severity: 1, + }, + ], + }) + await wait + + const diagnostics = client.diagnostics.get(file) ?? [] + expect(diagnostics).toHaveLength(1) + expect(diagnostics[0]?.message).toBe("push diagnostic") + + const count = await client.connection.sendRequest("test/get-diagnostic-request-count", {}) + expect(count).toBe(0) + + await client.shutdown() + }, + }) + }) + + test("document mode accepts matching push diagnostics published before waiting", async () => { + const handle = spawnFakeServer() as any + await using tmp = await tmpdir() + const file = path.join(tmp.path, "client.ts") + await Bun.write(file, "const x = 1\n") + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const client = await LSPClient.create({ + serverID: "fake", + server: handle as unknown as LSPServer.Handle, + root: tmp.path, + directory: tmp.path, + }) + + const version = await client.notify.open({ path: file }) + await client.connection.sendNotification("test/publish-diagnostics", { + uri: pathToFileURL(file).href, + version, + diagnostics: [ + { + range: { + start: { line: 0, character: 0 }, + end: { line: 0, character: 5 }, + }, + message: "push diagnostic", + severity: 1, + }, + ], + }) + + for (let i = 0; i < 20 && (client.diagnostics.get(file)?.length ?? 0) === 0; i++) { + await new Promise((resolve) => setTimeout(resolve, 25)) + } + + expect(client.diagnostics.get(file)?.[0]?.message).toBe("push diagnostic") + + const started = Date.now() + await client.waitForDiagnostics({ path: file, version, mode: "document" }) + expect(Date.now() - started).toBeLessThan(1_000) + + await client.shutdown() + }, + }) + }) + + test("document mode waits for pull diagnostics", async () => { + const handle = spawnFakeServer() as any + await using tmp = await tmpdir() + const file = path.join(tmp.path, "client.cs") + await Bun.write(file, "class C {}\n") + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const client = await LSPClient.create({ + serverID: "fake", + server: handle as unknown as LSPServer.Handle, + root: tmp.path, + directory: tmp.path, + }) + + await client.connection.sendRequest("test/configure-pull-diagnostics", { + registerOn: "didOpen", + registrations: [{ identifier: "DocumentCompilerSemantic" }], + documentDiagnosticsByIdentifier: { + DocumentCompilerSemantic: [ + { + range: { + start: { line: 0, character: 0 }, + end: { line: 0, character: 5 }, + }, + message: "pull diagnostic", + severity: 1, + }, + ], + }, + }) + + const version = await client.notify.open({ path: file }) + await client.waitForDiagnostics({ path: file, version, mode: "document" }) + + const diagnostics = client.diagnostics.get(file) ?? [] + expect(diagnostics).toHaveLength(1) + expect(diagnostics[0]?.message).toBe("pull diagnostic") + + const count = await client.connection.sendRequest("test/get-diagnostic-request-count", {}) + expect(count).toBeGreaterThan(0) + + await client.shutdown() + }, + }) + }) + + test("document mode does not wait for the slowest pull identifier after current-file diagnostics arrive", async () => { + const handle = spawnFakeServer() as any + await using tmp = await tmpdir() + const file = path.join(tmp.path, "client.cs") + await Bun.write(file, "class C {}\n") + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const client = await LSPClient.create({ + serverID: "fake", + server: handle as unknown as LSPServer.Handle, + root: tmp.path, + directory: tmp.path, + }) + + await client.connection.sendRequest("test/configure-pull-diagnostics", { + registrations: [{ identifier: "fast" }, { identifier: "slow" }], + documentDiagnosticsByIdentifier: { + fast: [ + { + range: { + start: { line: 0, character: 0 }, + end: { line: 0, character: 5 }, + }, + message: "fast diagnostic", + severity: 1, + }, + ], + slow: [], + }, + documentDelayMsByIdentifier: { + slow: 2_500, + }, + }) + + const version = await client.notify.open({ path: file }) + await client.connection.sendRequest("test/register-configured-pull-diagnostics", {}) + await new Promise((resolve) => setTimeout(resolve, 100)) + const started = Date.now() + await client.waitForDiagnostics({ path: file, version, mode: "document" }) + + expect(Date.now() - started).toBeLessThan(1_000) + expect(client.diagnostics.get(file)?.[0]?.message).toBe("fast diagnostic") + expect(await client.connection.sendRequest("test/get-diagnostic-request-count", {})).toBeGreaterThan(1) + + await client.shutdown() + }, + }) + }) + + test("full mode includes workspace pull diagnostics", async () => { + const handle = spawnFakeServer() as any + await using tmp = await tmpdir() + const file = path.join(tmp.path, "client.cs") + const related = path.join(tmp.path, "other.cs") + await Bun.write(file, "class C {}\n") + await Bun.write(related, "class D {}\n") + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const client = await LSPClient.create({ + serverID: "fake", + server: handle as unknown as LSPServer.Handle, + root: tmp.path, + directory: tmp.path, + }) + + await client.connection.sendRequest("test/configure-pull-diagnostics", { + registerOn: "didOpen", + registrations: [ + { identifier: "DocumentCompilerSemantic" }, + { identifier: "WorkspaceDocumentsAndProject", workspaceDiagnostics: true }, + ], + documentDiagnosticsByIdentifier: { + DocumentCompilerSemantic: [ + { + range: { + start: { line: 0, character: 0 }, + end: { line: 0, character: 5 }, + }, + message: "current file", + severity: 1, + }, + ], + }, + workspaceDiagnosticsByIdentifier: { + WorkspaceDocumentsAndProject: [ + { + uri: pathToFileURL(related).href, + items: [ + { + range: { + start: { line: 0, character: 0 }, + end: { line: 0, character: 5 }, + }, + message: "workspace file", + severity: 1, + }, + ], + }, + ], + }, + }) + + const version = await client.notify.open({ path: file }) + await client.waitForDiagnostics({ path: file, version, mode: "full" }) + + expect(client.diagnostics.get(file)?.[0]?.message).toBe("current file") + expect(client.diagnostics.get(related)?.[0]?.message).toBe("workspace file") + + await client.shutdown() + }, + }) + }) + + test("full mode treats an empty workspace pull response as handled", async () => { + const handle = spawnFakeServer() as any + await using tmp = await tmpdir() + const file = path.join(tmp.path, "client.cs") + await Bun.write(file, "class C {}\n") + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const client = await LSPClient.create({ + serverID: "fake", + server: handle as unknown as LSPServer.Handle, + root: tmp.path, + directory: tmp.path, + }) + + await client.connection.sendRequest("test/configure-pull-diagnostics", { + registerOn: "didOpen", + registrations: [{ identifier: "WorkspaceDocumentsAndProject", workspaceDiagnostics: true }], + workspaceDiagnosticsByIdentifier: { + WorkspaceDocumentsAndProject: [], + }, + }) + + const version = await client.notify.open({ path: file }) + const started = Date.now() + await client.waitForDiagnostics({ path: file, version, mode: "full" }) + + expect(Date.now() - started).toBeLessThan(1_000) + + await client.shutdown() + }, + }) + }) }) From 1cd4c92242ea75460100a0d69855a90938e07832 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Wed, 22 Apr 2026 23:25:07 +0000 Subject: [PATCH 18/92] chore: generate --- packages/opencode/src/lsp/client.ts | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/opencode/src/lsp/client.ts b/packages/opencode/src/lsp/client.ts index b0418ca3f5..f6d5110a6c 100644 --- a/packages/opencode/src/lsp/client.ts +++ b/packages/opencode/src/lsp/client.ts @@ -358,7 +358,10 @@ export async function create(input: { serverID: string; server: LSPServer.Handle return { handled, matched, byFile } } - async function requestWorkspaceDiagnosticReport(filePath: string, identifier?: string): Promise { + async function requestWorkspaceDiagnosticReport( + filePath: string, + identifier?: string, + ): Promise { const report = await withTimeout( connection.sendRequest("workspace/diagnostic", { ...(identifier ? { identifier } : {}), @@ -386,7 +389,9 @@ export async function create(input: { serverID: string; server: LSPServer.Handle (registration) => registration.registerOptions?.workspaceDiagnostics !== true, ) return { - documentIdentifiers: [...new Set(documentRegistrations.flatMap((registration) => registration.registerOptions?.identifier ?? []))], + documentIdentifiers: [ + ...new Set(documentRegistrations.flatMap((registration) => registration.registerOptions?.identifier ?? [])), + ], supported: hasStaticPullDiagnostics || documentRegistrations.length > 0, } } @@ -396,7 +401,9 @@ export async function create(input: { serverID: string; server: LSPServer.Handle (registration) => registration.registerOptions?.workspaceDiagnostics === true, ) return { - workspaceIdentifiers: [...new Set(workspaceRegistrations.flatMap((registration) => registration.registerOptions?.identifier ?? []))], + workspaceIdentifiers: [ + ...new Set(workspaceRegistrations.flatMap((registration) => registration.registerOptions?.identifier ?? [])), + ], supported: workspaceRegistrations.length > 0, } } @@ -461,7 +468,9 @@ export async function create(input: { serverID: string; server: LSPServer.Handle ...(documentState.supported ? [requestDiagnosticReport(filePath)] : []), ...documentState.documentIdentifiers.map((identifier) => requestDiagnosticReport(filePath, identifier)), ...(workspaceState.supported ? [requestWorkspaceDiagnosticReport(filePath)] : []), - ...workspaceState.workspaceIdentifiers.map((identifier) => requestWorkspaceDiagnosticReport(filePath, identifier)), + ...workspaceState.workspaceIdentifiers.map((identifier) => + requestWorkspaceDiagnosticReport(filePath, identifier), + ), ]), ) } @@ -532,8 +541,8 @@ export async function create(input: { serverID: string; server: LSPServer.Handle const remaining = DIAGNOSTICS_DOCUMENT_WAIT_TIMEOUT_MS - (Date.now() - startedAt) if (remaining <= 0) return const next = await Promise.race([ - pushWait.then((ready) => (ready ? "push" : "timeout" as const)), - waitForRegistrationChange(remaining).then((changed) => (changed ? "registration" : "timeout" as const)), + pushWait.then((ready) => (ready ? "push" : ("timeout" as const))), + waitForRegistrationChange(remaining).then((changed) => (changed ? "registration" : ("timeout" as const))), ]) if (next !== "registration") return } @@ -554,8 +563,8 @@ export async function create(input: { serverID: string; server: LSPServer.Handle const remaining = DIAGNOSTICS_FULL_WAIT_TIMEOUT_MS - (Date.now() - startedAt) if (remaining <= 0) return const next = await Promise.race([ - pushWait.then((ready) => (ready ? "push" : "timeout" as const)), - waitForRegistrationChange(remaining).then((changed) => (changed ? "registration" : "timeout" as const)), + pushWait.then((ready) => (ready ? "push" : ("timeout" as const))), + waitForRegistrationChange(remaining).then((changed) => (changed ? "registration" : ("timeout" as const))), ]) if (next !== "registration") return } From 6387b35a2d5b36fc1ac4dd3270fa2da66cca8111 Mon Sep 17 00:00:00 2001 From: Luke Parker <10430890+Hona@users.noreply.github.com> Date: Thu, 23 Apr 2026 10:08:14 +1000 Subject: [PATCH 19/92] log session sdk errors (#23652) --- packages/app/src/context/global-sync.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/app/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx index 313ff29659..7c819918c0 100644 --- a/packages/app/src/context/global-sync.tsx +++ b/packages/app/src/context/global-sync.tsx @@ -295,6 +295,19 @@ function createGlobalSync() { const event = e.details const recent = bootingRoot || Date.now() - bootedAt < 1500 + if (event.type === "session.error") { + const error = event.properties.error + if (error?.name !== "MessageAbortedError") { + console.error("[global-sync] session error", { + scope: directory === "global" ? "global" : "workspace", + directory: directory === "global" ? undefined : directory, + project: directory === "global" ? undefined : getFilename(directory), + sessionID: event.properties.sessionID, + error, + }) + } + } + if (directory === "global") { applyGlobalEvent({ event, From ac26394fcb280592a8ecddf903a3a7116c841f39 Mon Sep 17 00:00:00 2001 From: Luke Parker <10430890+Hona@users.noreply.github.com> Date: Thu, 23 Apr 2026 11:19:36 +1000 Subject: [PATCH 20/92] fix(beta): PR resolvers/smoke check should typecheck all pacakges (#23913) --- script/beta.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/script/beta.ts b/script/beta.ts index 34d9dab1f8..7c558d1e7e 100755 --- a/script/beta.ts +++ b/script/beta.ts @@ -61,7 +61,7 @@ async function typecheck() { console.log(" Running typecheck...") try { - await $`bun typecheck`.cwd("packages/opencode") + await $`bun typecheck` return true } catch (err) { console.log(`Typecheck failed: ${err}`) @@ -113,7 +113,7 @@ async function fix(pr: PR, files: string[], prs: PR[], applied: number[], idx: n "If bun.lock is conflicted, do not hand-merge it. Delete bun.lock and run bun install after the code conflicts are resolved.", "If a PR already deleted a file/directory, do not re-add it, instead apply changes in the new semantic location.", "If a PR already changed an import, keep that change.", - "After resolving the conflicts, run `bun typecheck` in `packages/opencode`.", + "After resolving the conflicts, run `bun typecheck` at the repo root.", "If typecheck fails, you may also update any files reported by typecheck.", "Keep any non-conflict edits narrowly scoped to restoring a valid merged state for the current PR batch.", "Fix any merge-caused typecheck errors before finishing.", @@ -149,7 +149,7 @@ async function smoke(prs: PR[], applied: number[]) { const prompt = [ "The beta merge batch is complete.", `Merged PRs on HEAD:\n${done}`, - "Run `bun typecheck` in `packages/opencode`.", + "Run `bun typecheck` at the repo root.", "Run `./script/build.ts --single` in `packages/opencode`.", "Fix any merge-caused issues until both commands pass.", "Do not create a commit.", From 97300085437899af8af6c2bbf6ebc6bdab110174 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Thu, 23 Apr 2026 00:29:56 -0400 Subject: [PATCH 21/92] tweak: codex model logic (#23925) --- packages/opencode/src/plugin/codex.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/opencode/src/plugin/codex.ts b/packages/opencode/src/plugin/codex.ts index c61cb78509..e05111fc6a 100644 --- a/packages/opencode/src/plugin/codex.ts +++ b/packages/opencode/src/plugin/codex.ts @@ -378,6 +378,8 @@ export async function CodexAuthPlugin(input: PluginInput): Promise { for (const [modelId, model] of Object.entries(provider.models)) { if (modelId.includes("codex")) continue if (allowedModels.has(model.api.id)) continue + const match = model.api.id.match(/^gpt-(\d+\.\d+)/) + if (match && parseFloat(match[1]) > 5.4) continue delete provider.models[modelId] } From df27baa00d0de032a7213b043d3b04f939362baa Mon Sep 17 00:00:00 2001 From: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Date: Thu, 23 Apr 2026 13:15:02 +0800 Subject: [PATCH 22/92] refactor: remove redundant pending check from working memo (#23929) --- packages/app/src/pages/session/message-timeline.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/src/pages/session/message-timeline.tsx b/packages/app/src/pages/session/message-timeline.tsx index 9e0fed11cc..fa57cabaec 100644 --- a/packages/app/src/pages/session/message-timeline.tsx +++ b/packages/app/src/pages/session/message-timeline.tsx @@ -259,7 +259,7 @@ export function MessageTimeline(props: { if (!id) return idle return sync.data.session_status[id] ?? idle }) - const working = createMemo(() => !!pending() || sessionStatus().type !== "idle") + const working = createMemo(() => sessionStatus().type !== "idle") const tint = createMemo(() => messageAgentColor(sessionMessages(), sync.data.agent)) const [timeoutDone, setTimeoutDone] = createSignal(true) From 871789ce64f179d5efa3031afbce3789e27e99b5 Mon Sep 17 00:00:00 2001 From: opencode Date: Thu, 23 Apr 2026 05:45:21 +0000 Subject: [PATCH 23/92] sync release versions for v1.14.21 --- bun.lock | 32 +++++++++++++------------- packages/app/package.json | 2 +- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop-electron/package.json | 2 +- packages/desktop/package.json | 2 +- packages/enterprise/package.json | 2 +- packages/extensions/zed/extension.toml | 12 +++++----- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/shared/package.json | 2 +- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 19 files changed, 39 insertions(+), 39 deletions(-) diff --git a/bun.lock b/bun.lock index 64b32feac4..addecfff27 100644 --- a/bun.lock +++ b/bun.lock @@ -29,7 +29,7 @@ }, "packages/app": { "name": "@opencode-ai/app", - "version": "1.14.20", + "version": "1.14.21", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -83,7 +83,7 @@ }, "packages/console/app": { "name": "@opencode-ai/console-app", - "version": "1.14.20", + "version": "1.14.21", "dependencies": { "@cloudflare/vite-plugin": "1.15.2", "@ibm/plex": "6.4.1", @@ -117,7 +117,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.14.20", + "version": "1.14.21", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -144,7 +144,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.14.20", + "version": "1.14.21", "dependencies": { "@ai-sdk/anthropic": "3.0.64", "@ai-sdk/openai": "3.0.48", @@ -168,7 +168,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.14.20", + "version": "1.14.21", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -192,7 +192,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.14.20", + "version": "1.14.21", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -225,7 +225,7 @@ }, "packages/desktop-electron": { "name": "@opencode-ai/desktop-electron", - "version": "1.14.20", + "version": "1.14.21", "dependencies": { "drizzle-orm": "catalog:", "effect": "catalog:", @@ -269,7 +269,7 @@ }, "packages/enterprise": { "name": "@opencode-ai/enterprise", - "version": "1.14.20", + "version": "1.14.21", "dependencies": { "@opencode-ai/shared": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -298,7 +298,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.14.20", + "version": "1.14.21", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "catalog:", @@ -314,7 +314,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.14.20", + "version": "1.14.21", "bin": { "opencode": "./bin/opencode", }, @@ -459,7 +459,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.14.20", + "version": "1.14.21", "dependencies": { "@opencode-ai/sdk": "workspace:*", "effect": "catalog:", @@ -494,7 +494,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.14.20", + "version": "1.14.21", "dependencies": { "cross-spawn": "catalog:", }, @@ -509,7 +509,7 @@ }, "packages/shared": { "name": "@opencode-ai/shared", - "version": "1.14.20", + "version": "1.14.21", "bin": { "opencode": "./bin/opencode", }, @@ -533,7 +533,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.14.20", + "version": "1.14.21", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -568,7 +568,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.14.20", + "version": "1.14.21", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -617,7 +617,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.14.20", + "version": "1.14.21", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/app/package.json b/packages/app/package.json index f461459fcb..7572f0b228 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "1.14.20", + "version": "1.14.21", "description": "", "type": "module", "exports": { diff --git a/packages/console/app/package.json b/packages/console/app/package.json index d8c9434bfa..1182f17948 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-app", - "version": "1.14.20", + "version": "1.14.21", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 090e5c59d9..f79ef3ecb0 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.14.20", + "version": "1.14.21", "private": true, "type": "module", "license": "MIT", diff --git a/packages/console/function/package.json b/packages/console/function/package.json index a2e0c5f03a..c3c549004d 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.14.20", + "version": "1.14.21", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 7aa0cb7574..f4c59c1967 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.14.20", + "version": "1.14.21", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop-electron/package.json b/packages/desktop-electron/package.json index 155e43f5e9..3f5ca841b0 100644 --- a/packages/desktop-electron/package.json +++ b/packages/desktop-electron/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop-electron", "private": true, - "version": "1.14.20", + "version": "1.14.21", "type": "module", "license": "MIT", "homepage": "https://opencode.ai", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index a3b6eac6b0..0e349f81c3 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop", "private": true, - "version": "1.14.20", + "version": "1.14.21", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/enterprise/package.json b/packages/enterprise/package.json index 0168636506..77b0ec2002 100644 --- a/packages/enterprise/package.json +++ b/packages/enterprise/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/enterprise", - "version": "1.14.20", + "version": "1.14.21", "private": true, "type": "module", "license": "MIT", diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index cee69b11af..5a9d2dc1ac 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The open source coding agent." -version = "1.14.20" +version = "1.14.21" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/anomalyco/opencode" @@ -11,26 +11,26 @@ name = "OpenCode" icon = "./icons/opencode.svg" [agent_servers.opencode.targets.darwin-aarch64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.20/opencode-darwin-arm64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.21/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.20/opencode-darwin-x64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.21/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.20/opencode-linux-arm64.tar.gz" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.21/opencode-linux-arm64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.20/opencode-linux-x64.tar.gz" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.21/opencode-linux-x64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.20/opencode-windows-x64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.21/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index 4e920b6889..925e458cf0 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.14.20", + "version": "1.14.21", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index dcd0a9ad6c..cd9c0f0a83 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.14.20", + "version": "1.14.21", "name": "opencode", "type": "module", "license": "MIT", diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 64d12eb42d..d719010661 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.14.20", + "version": "1.14.21", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index a6ba6ee9f4..3d07efef49 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.14.20", + "version": "1.14.21", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/shared/package.json b/packages/shared/package.json index 22a8c9c071..117c12b981 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.14.20", + "version": "1.14.21", "name": "@opencode-ai/shared", "type": "module", "license": "MIT", diff --git a/packages/slack/package.json b/packages/slack/package.json index 7a016907ae..2eb380dc74 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.14.20", + "version": "1.14.21", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/ui/package.json b/packages/ui/package.json index dcf57345e8..a15918dc85 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.14.20", + "version": "1.14.21", "type": "module", "license": "MIT", "exports": { diff --git a/packages/web/package.json b/packages/web/package.json index 8fd33564d7..9924f2e516 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -2,7 +2,7 @@ "name": "@opencode-ai/web", "type": "module", "license": "MIT", - "version": "1.14.20", + "version": "1.14.21", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 720c70196d..a43348670b 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.14.20", + "version": "1.14.21", "publisher": "sst-dev", "repository": { "type": "git", From a419f1c50f4efaf2119991eee1d9bc2eef78cb8f Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 23 Apr 2026 02:56:41 -0400 Subject: [PATCH 24/92] zen: hy3 preview --- packages/web/src/content/docs/ar/zen.mdx | 8 ++++++-- packages/web/src/content/docs/bs/zen.mdx | 8 ++++++-- packages/web/src/content/docs/da/zen.mdx | 8 ++++++-- packages/web/src/content/docs/de/zen.mdx | 8 ++++++-- packages/web/src/content/docs/es/zen.mdx | 8 ++++++-- packages/web/src/content/docs/fr/zen.mdx | 8 ++++++-- packages/web/src/content/docs/it/zen.mdx | 8 ++++++-- packages/web/src/content/docs/ja/zen.mdx | 8 ++++++-- packages/web/src/content/docs/ko/zen.mdx | 8 ++++++-- packages/web/src/content/docs/nb/zen.mdx | 8 ++++++-- packages/web/src/content/docs/pl/zen.mdx | 8 ++++++-- packages/web/src/content/docs/pt-br/zen.mdx | 8 ++++++-- packages/web/src/content/docs/ru/zen.mdx | 8 ++++++-- packages/web/src/content/docs/th/zen.mdx | 8 ++++++-- packages/web/src/content/docs/tr/zen.mdx | 8 ++++++-- packages/web/src/content/docs/zen.mdx | 8 ++++++-- packages/web/src/content/docs/zh-cn/zen.mdx | 8 ++++++-- packages/web/src/content/docs/zh-tw/zen.mdx | 8 ++++++-- 18 files changed, 108 insertions(+), 36 deletions(-) diff --git a/packages/web/src/content/docs/ar/zen.mdx b/packages/web/src/content/docs/ar/zen.mdx index c30cf3287f..f85c15ea96 100644 --- a/packages/web/src/content/docs/ar/zen.mdx +++ b/packages/web/src/content/docs/ar/zen.mdx @@ -85,8 +85,8 @@ OpenCode Zen هي بوابة AI تتيح لك الوصول إلى هذه الن | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -96,6 +96,7 @@ OpenCode Zen هي بوابة AI تتيح لك الوصول إلى هذه الن | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | يستخدم [معرّف النموذج](/docs/config/#models) في إعدادات OpenCode الصيغة `opencode/`. على سبيل المثال، بالنسبة إلى GPT 5.4، ستستخدم `opencode/gpt-5.4` في إعداداتك. @@ -121,6 +122,7 @@ https://opencode.ai/zen/v1/models | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -170,6 +172,7 @@ https://opencode.ai/zen/v1/models - MiniMax M2.5 Free متاح على OpenCode لفترة محدودة. يستخدم الفريق هذه الفترة لجمع الملاحظات وتحسين النموذج. - Ling 2.6 Flash Free متاح على OpenCode لفترة محدودة. يستخدم الفريق هذه الفترة لجمع الملاحظات وتحسين النموذج. +- Hy3 Preview Flash Free متاح على OpenCode لفترة محدودة. يستخدم الفريق هذه الفترة لجمع الملاحظات وتحسين النموذج. - Nemotron 3 Super Free متاح على OpenCode لفترة محدودة. يستخدم الفريق هذه الفترة لجمع الملاحظات وتحسين النموذج. - Big Pickle نموذج خفي ومتاح مجانا على OpenCode لفترة محدودة. يستخدم الفريق هذه الفترة لجمع الملاحظات وتحسين النموذج. @@ -214,6 +217,7 @@ https://opencode.ai/zen/v1/models - Big Pickle: خلال فترته المجانية، قد تُستخدم البيانات المجمعة لتحسين النموذج. - MiniMax M2.5 Free: خلال فترته المجانية، قد تُستخدم البيانات المجمعة لتحسين النموذج. - Ling 2.6 Flash Free: خلال فترته المجانية، قد تُستخدم البيانات المجمعة لتحسين النموذج. +- Hy3 Preview Free: خلال فترته المجانية، قد تُستخدم البيانات المجمعة لتحسين النموذج. - Nemotron 3 Super Free (نقاط نهاية NVIDIA المجانية): يُقدَّم بموجب [شروط خدمة النسخة التجريبية من واجهة NVIDIA API](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf). للاستخدام التجريبي فقط، وليس للإنتاج أو البيانات الحساسة. تقوم NVIDIA بتسجيل المطالبات والمخرجات لتحسين نماذجها وخدماتها. لا ترسل بيانات شخصية أو سرية. - OpenAI APIs: يتم الاحتفاظ بالطلبات لمدة 30 يوما وفقا لـ [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data). - Anthropic APIs: يتم الاحتفاظ بالطلبات لمدة 30 يوما وفقا لـ [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage). diff --git a/packages/web/src/content/docs/bs/zen.mdx b/packages/web/src/content/docs/bs/zen.mdx index b6fc90fa03..026e145adc 100644 --- a/packages/web/src/content/docs/bs/zen.mdx +++ b/packages/web/src/content/docs/bs/zen.mdx @@ -90,8 +90,8 @@ Našim modelima možete pristupiti i preko sljedećih API endpointa. | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -101,6 +101,7 @@ Našim modelima možete pristupiti i preko sljedećih API endpointa. | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | [model id](/docs/config/#models) u vašoj OpenCode konfiguraciji koristi format @@ -128,6 +129,7 @@ Podržavamo pay-as-you-go model. Ispod su cijene **po 1M tokena**. | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -177,6 +179,7 @@ Besplatni modeli: - MiniMax M2.5 Free je dostupan na OpenCode ograničeno vrijeme. Tim koristi ovo vrijeme da prikupi povratne informacije i poboljša model. - Ling 2.6 Flash Free je dostupan na OpenCode ograničeno vrijeme. Tim koristi ovo vrijeme da prikupi povratne informacije i poboljša model. +- Hy3 Preview Free je dostupan na OpenCode ograničeno vrijeme. Tim koristi ovo vrijeme da prikupi povratne informacije i poboljša model. - Nemotron 3 Super Free je dostupan na OpenCode ograničeno vrijeme. Tim koristi ovo vrijeme da prikupi povratne informacije i poboljša model. - Big Pickle je stealth model koji je besplatan na OpenCode ograničeno vrijeme. Tim koristi ovo vrijeme da prikupi povratne informacije i poboljša model. @@ -226,6 +229,7 @@ i ne koriste vaše podatke za treniranje modela, uz sljedeće izuzetke: - Big Pickle: Tokom besplatnog perioda, prikupljeni podaci mogu se koristiti za poboljšanje modela. - MiniMax M2.5 Free: Tokom besplatnog perioda, prikupljeni podaci mogu se koristiti za poboljšanje modela. - Ling 2.6 Flash Free: Tokom besplatnog perioda, prikupljeni podaci mogu se koristiti za poboljšanje modela. +- Hy3 Preview Free: Tokom besplatnog perioda, prikupljeni podaci mogu se koristiti za poboljšanje modela. - Nemotron 3 Super Free (besplatni NVIDIA endpointi): Dostupan je prema [NVIDIA API Trial Terms of Service](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf). Samo za probnu upotrebu, nije za produkciju niti osjetljive podatke. NVIDIA bilježi promptove i izlaze radi poboljšanja svojih modela i usluga. Nemojte slati lične ili povjerljive podatke. - OpenAI APIs: Requests are retained for 30 days in accordance with [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data). - Anthropic APIs: Requests are retained for 30 days in accordance with [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage). diff --git a/packages/web/src/content/docs/da/zen.mdx b/packages/web/src/content/docs/da/zen.mdx index ea5189ec21..b5c9f469f3 100644 --- a/packages/web/src/content/docs/da/zen.mdx +++ b/packages/web/src/content/docs/da/zen.mdx @@ -90,8 +90,8 @@ Du kan også få adgang til vores modeller gennem følgende API-endpoints. | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -101,6 +101,7 @@ Du kan også få adgang til vores modeller gennem følgende API-endpoints. | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | [model id](/docs/config/#models) i din OpenCode-konfiguration @@ -128,6 +129,7 @@ Vi understøtter en pay-as-you-go-model. Nedenfor er priserne **pr. 1M tokens**. | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -177,6 +179,7 @@ De gratis modeller: - MiniMax M2.5 Free er tilgængelig på OpenCode i en begrænset periode. Teamet bruger denne tid til at indsamle feedback og forbedre modellen. - Ling 2.6 Flash Free er tilgængelig på OpenCode i en begrænset periode. Teamet bruger denne tid til at indsamle feedback og forbedre modellen. +- Hy3 Preview Free er tilgængelig på OpenCode i en begrænset periode. Teamet bruger denne tid til at indsamle feedback og forbedre modellen. - Nemotron 3 Super Free er tilgængelig på OpenCode i en begrænset periode. Teamet bruger denne tid til at indsamle feedback og forbedre modellen. - Big Pickle er en stealth-model, som er gratis på OpenCode i en begrænset periode. Teamet bruger denne tid til at indsamle feedback og forbedre modellen. @@ -224,6 +227,7 @@ Alle vores modeller hostes i US. Vores udbydere følger en nul-opbevaringspoliti - Big Pickle: I den gratis periode kan indsamlede data blive brugt til at forbedre modellen. - MiniMax M2.5 Free: I den gratis periode kan indsamlede data blive brugt til at forbedre modellen. - Ling 2.6 Flash Free: I den gratis periode kan indsamlede data blive brugt til at forbedre modellen. +- Hy3 Preview Free: I den gratis periode kan indsamlede data blive brugt til at forbedre modellen. - Nemotron 3 Super Free (gratis NVIDIA-endpoints): Leveres under [NVIDIA API Trial Terms of Service](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf). Kun til prøvebrug, ikke til produktion eller følsomme data. Prompts og outputs logges af NVIDIA for at forbedre deres modeller og tjenester. Indsend ikke personlige eller fortrolige data. - OpenAI APIs: Anmodninger opbevares i 30 dage i overensstemmelse med [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data). - Anthropic APIs: Anmodninger opbevares i 30 dage i overensstemmelse med [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage). diff --git a/packages/web/src/content/docs/de/zen.mdx b/packages/web/src/content/docs/de/zen.mdx index b8a09497c1..2fd012dd1b 100644 --- a/packages/web/src/content/docs/de/zen.mdx +++ b/packages/web/src/content/docs/de/zen.mdx @@ -81,8 +81,8 @@ Du kannst auch über die folgenden API-Endpunkte auf unsere Modelle zugreifen. | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -92,6 +92,7 @@ Du kannst auch über die folgenden API-Endpunkte auf unsere Modelle zugreifen. | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | Die [Model-ID](/docs/config/#models) in deiner OpenCode-Konfiguration verwendet das Format `opencode/`. Für GPT 5.4 würdest du zum Beispiel `opencode/gpt-5.4` in deiner Konfiguration verwenden. @@ -117,6 +118,7 @@ Wir unterstützen ein Pay-as-you-go-Modell. Unten findest du die Preise **pro 1M | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -166,6 +168,7 @@ Die kostenlosen Modelle: - MiniMax M2.5 Free ist für begrenzte Zeit auf OpenCode verfügbar. Das Team nutzt diese Zeit, um Feedback zu sammeln und das Modell zu verbessern. - Ling 2.6 Flash Free ist für begrenzte Zeit auf OpenCode verfügbar. Das Team nutzt diese Zeit, um Feedback zu sammeln und das Modell zu verbessern. +- Hy3 Preview Flash Free ist für begrenzte Zeit auf OpenCode verfügbar. Das Team nutzt diese Zeit, um Feedback zu sammeln und das Modell zu verbessern. - Nemotron 3 Super Free ist für begrenzte Zeit auf OpenCode verfügbar. Das Team nutzt diese Zeit, um Feedback zu sammeln und das Modell zu verbessern. - Big Pickle ist ein Stealth-Modell, das für begrenzte Zeit kostenlos auf OpenCode verfügbar ist. Das Team nutzt diese Zeit, um Feedback zu sammeln und das Modell zu verbessern. @@ -210,6 +213,7 @@ Alle unsere Modelle werden in den USA gehostet. Unsere Provider folgen einer Zer - Big Pickle: Während des kostenlosen Zeitraums können gesammelte Daten zur Verbesserung des Modells verwendet werden. - MiniMax M2.5 Free: Während des kostenlosen Zeitraums können gesammelte Daten zur Verbesserung des Modells verwendet werden. - Ling 2.6 Flash Free: Während des kostenlosen Zeitraums können gesammelte Daten zur Verbesserung des Modells verwendet werden. +- Hy3 Preview Free: Während des kostenlosen Zeitraums können gesammelte Daten zur Verbesserung des Modells verwendet werden. - Nemotron 3 Super Free (kostenlose NVIDIA-Endpunkte): Bereitgestellt gemäß den [NVIDIA API Trial Terms of Service](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf). Nur für Testzwecke, nicht für Produktion oder sensible Daten. Eingaben und Ausgaben werden von NVIDIA protokolliert, um seine Modelle und Dienste zu verbessern. Übermitteln Sie keine personenbezogenen oder vertraulichen Daten. - OpenAI APIs: Anfragen werden in Übereinstimmung mit [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data) 30 Tage lang gespeichert. - Anthropic APIs: Anfragen werden in Übereinstimmung mit [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage) 30 Tage lang gespeichert. diff --git a/packages/web/src/content/docs/es/zen.mdx b/packages/web/src/content/docs/es/zen.mdx index b8999a050f..82ed07a23b 100644 --- a/packages/web/src/content/docs/es/zen.mdx +++ b/packages/web/src/content/docs/es/zen.mdx @@ -90,8 +90,8 @@ También puedes acceder a nuestros modelos a través de los siguientes endpoints | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -101,6 +101,7 @@ También puedes acceder a nuestros modelos a través de los siguientes endpoints | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | El [identificador del modelo](/docs/config/#models) en tu configuración de OpenCode @@ -128,6 +129,7 @@ Admitimos un modelo de pago por uso. A continuación se muestran los precios **p | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -177,6 +179,7 @@ Los modelos gratuitos: - MiniMax M2.5 Free está disponible en OpenCode por tiempo limitado. El equipo está usando este tiempo para recopilar comentarios y mejorar el modelo. - Ling 2.6 Flash Free está disponible en OpenCode por tiempo limitado. El equipo está usando este tiempo para recopilar comentarios y mejorar el modelo. +- Hy3 Preview Flash Free está disponible en OpenCode por tiempo limitado. El equipo está usando este tiempo para recopilar comentarios y mejorar el modelo. - Nemotron 3 Super Free está disponible en OpenCode por tiempo limitado. El equipo está usando este tiempo para recopilar comentarios y mejorar el modelo. - Big Pickle es un modelo stealth que es gratuito en OpenCode por tiempo limitado. El equipo está usando este tiempo para recopilar comentarios y mejorar el modelo. @@ -224,6 +227,7 @@ Todos nuestros modelos están alojados en US. Nuestros proveedores siguen una po - Big Pickle: Durante su período gratuito, los datos recopilados pueden usarse para mejorar el modelo. - MiniMax M2.5 Free: Durante su período gratuito, los datos recopilados pueden usarse para mejorar el modelo. - Ling 2.6 Flash Free: Durante su período gratuito, los datos recopilados pueden usarse para mejorar el modelo. +- Hy3 Preview Free: Durante su período gratuito, los datos recopilados pueden usarse para mejorar el modelo. - Nemotron 3 Super Free (endpoints gratuitos de NVIDIA): Se ofrece bajo los [NVIDIA API Trial Terms of Service](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf). Solo para uso de prueba, no para producción ni datos sensibles. NVIDIA registra los prompts y las salidas para mejorar sus modelos y servicios. No envíes datos personales ni confidenciales. - OpenAI APIs: Las solicitudes se conservan durante 30 días de acuerdo con [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data). - Anthropic APIs: Las solicitudes se conservan durante 30 días de acuerdo con [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage). diff --git a/packages/web/src/content/docs/fr/zen.mdx b/packages/web/src/content/docs/fr/zen.mdx index ab759f053d..0b2bcf94aa 100644 --- a/packages/web/src/content/docs/fr/zen.mdx +++ b/packages/web/src/content/docs/fr/zen.mdx @@ -81,8 +81,8 @@ Vous pouvez également accéder à nos modèles via les points de terminaison AP | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -92,6 +92,7 @@ Vous pouvez également accéder à nos modèles via les points de terminaison AP | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | Le [model id](/docs/config/#models) dans votre configuration OpenCode utilise le format `opencode/`. Par exemple, pour GPT 5.4, vous utiliseriez `opencode/gpt-5.4` dans votre configuration. @@ -117,6 +118,7 @@ Nous prenons en charge un modèle de paiement à l'utilisation. Vous trouverez c | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -166,6 +168,7 @@ Les modèles gratuits : - MiniMax M2.5 Free est disponible sur OpenCode pour une durée limitée. L'équipe utilise cette période pour recueillir des retours et améliorer le modèle. - Ling 2.6 Flash Free est disponible sur OpenCode pour une durée limitée. L'équipe utilise cette période pour recueillir des retours et améliorer le modèle. +- Hy3 Preview Free est disponible sur OpenCode pour une durée limitée. L'équipe utilise cette période pour recueillir des retours et améliorer le modèle. - Nemotron 3 Super Free est disponible sur OpenCode pour une durée limitée. L'équipe utilise cette période pour recueillir des retours et améliorer le modèle. - Big Pickle est un modèle stealth gratuit sur OpenCode pour une durée limitée. L'équipe utilise cette période pour recueillir des retours et améliorer le modèle. @@ -210,6 +213,7 @@ Tous nos modèles sont hébergés aux US. Nos fournisseurs suivent une politique - Big Pickle : Pendant sa période gratuite, les données collectées peuvent être utilisées pour améliorer le modèle. - MiniMax M2.5 Free : Pendant sa période gratuite, les données collectées peuvent être utilisées pour améliorer le modèle. - Ling 2.6 Flash Free : Pendant sa période gratuite, les données collectées peuvent être utilisées pour améliorer le modèle. +- Hy3 Preview Free : Pendant sa période gratuite, les données collectées peuvent être utilisées pour améliorer le modèle. - Nemotron 3 Super Free (endpoints NVIDIA gratuits) : Fourni dans le cadre des [NVIDIA API Trial Terms of Service](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf). Réservé à un usage d'essai, pas à la production ni aux données sensibles. Les prompts et les sorties sont journalisés par NVIDIA pour améliorer ses modèles et services. N'envoyez pas de données personnelles ou confidentielles. - OpenAI APIs : Les requêtes sont conservées pendant 30 jours conformément à [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data). - Anthropic APIs : Les requêtes sont conservées pendant 30 jours conformément à [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage). diff --git a/packages/web/src/content/docs/it/zen.mdx b/packages/web/src/content/docs/it/zen.mdx index 38c69b021e..14ddb891d3 100644 --- a/packages/web/src/content/docs/it/zen.mdx +++ b/packages/web/src/content/docs/it/zen.mdx @@ -90,8 +90,8 @@ Puoi anche accedere ai nostri modelli tramite i seguenti endpoint API. | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -101,6 +101,7 @@ Puoi anche accedere ai nostri modelli tramite i seguenti endpoint API. | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | Il [model id](/docs/config/#models) nella config di OpenCode @@ -128,6 +129,7 @@ Supportiamo un modello pay-as-you-go. Qui sotto trovi i prezzi **per 1M token**. | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -177,6 +179,7 @@ I modelli gratuiti: - MiniMax M2.5 Free è disponibile su OpenCode per un periodo limitato. Il team usa questo periodo per raccogliere feedback e migliorare il modello. - Ling 2.6 Flash Free è disponibile su OpenCode per un periodo limitato. Il team usa questo periodo per raccogliere feedback e migliorare il modello. +- Hy3 Preview Flash Free è disponibile su OpenCode per un periodo limitato. Il team usa questo periodo per raccogliere feedback e migliorare il modello. - Nemotron 3 Super Free è disponibile su OpenCode per un periodo limitato. Il team usa questo periodo per raccogliere feedback e migliorare il modello. - Big Pickle è un modello stealth che è gratuito su OpenCode per un periodo limitato. Il team usa questo periodo per raccogliere feedback e migliorare il modello. @@ -224,6 +227,7 @@ Tutti i nostri modelli sono ospitati negli US. I nostri provider seguono una pol - Big Pickle: durante il periodo gratuito, i dati raccolti possono essere usati per migliorare il modello. - MiniMax M2.5 Free: durante il periodo gratuito, i dati raccolti possono essere usati per migliorare il modello. - Ling 2.6 Flash Free: durante il periodo gratuito, i dati raccolti possono essere usati per migliorare il modello. +- Hy3 Preview Free: durante il periodo gratuito, i dati raccolti possono essere usati per migliorare il modello. - Nemotron 3 Super Free (endpoint NVIDIA gratuiti): fornito secondo i [NVIDIA API Trial Terms of Service](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf). Solo per uso di prova, non per produzione o dati sensibili. NVIDIA registra prompt e output per migliorare i propri modelli e servizi. Non inviare dati personali o riservati. - OpenAI APIs: le richieste vengono conservate per 30 giorni in conformità con [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data). - Anthropic APIs: le richieste vengono conservate per 30 giorni in conformità con [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage). diff --git a/packages/web/src/content/docs/ja/zen.mdx b/packages/web/src/content/docs/ja/zen.mdx index 8f95473d6d..ee84dc9172 100644 --- a/packages/web/src/content/docs/ja/zen.mdx +++ b/packages/web/src/content/docs/ja/zen.mdx @@ -81,8 +81,8 @@ OpenCode Zen は、OpenCode のほかのプロバイダーと同じように動 | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -92,6 +92,7 @@ OpenCode Zen は、OpenCode のほかのプロバイダーと同じように動 | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | OpenCode 設定で使う [model id](/docs/config/#models) は `opencode/` 形式です。たとえば、GPT 5.4 では設定に `opencode/gpt-5.4` を使用します。 @@ -117,6 +118,7 @@ https://opencode.ai/zen/v1/models | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -166,6 +168,7 @@ https://opencode.ai/zen/v1/models - MiniMax M2.5 Free は期間限定で OpenCode で利用できます。チームはこの期間中にフィードバックを集め、モデルを改善しています。 - Ling 2.6 Flash Free は期間限定で OpenCode で利用できます。チームはこの期間中にフィードバックを集め、モデルを改善しています。 +- Hy3 Preview Flash Free は期間限定で OpenCode で利用できます。チームはこの期間中にフィードバックを集め、モデルを改善しています。 - Nemotron 3 Super Free は期間限定で OpenCode で利用できます。チームはこの期間中にフィードバックを集め、モデルを改善しています。 - Big Pickle はステルスモデルで、期間限定で OpenCode で無料提供されています。チームはこの期間中にフィードバックを集め、モデルを改善しています。 @@ -210,6 +213,7 @@ https://opencode.ai/zen/v1/models - Big Pickle: 無料提供期間中、収集されたデータがモデル改善に使われる場合があります。 - MiniMax M2.5 Free: 無料提供期間中、収集されたデータがモデル改善に使われる場合があります。 - Ling 2.6 Flash Free: 無料提供期間中、収集されたデータがモデル改善に使われる場合があります。 +- Hy3 Preview Free: 無料提供期間中、収集されたデータがモデル改善に使われる場合があります。 - Nemotron 3 Super Free(NVIDIA の無料エンドポイント): [NVIDIA API Trial Terms of Service](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf) に基づいて提供されます。試用専用であり、本番環境や機密性の高いデータには使用しないでください。プロンプトと出力は、NVIDIA が自社のモデルとサービスを改善するために記録します。個人情報や機密データは送信しないでください。 - OpenAI APIs: リクエストは [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data) に従って 30 日間保持されます。 - Anthropic APIs: リクエストは [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage) に従って 30 日間保持されます。 diff --git a/packages/web/src/content/docs/ko/zen.mdx b/packages/web/src/content/docs/ko/zen.mdx index 59d7448061..416ec9f20b 100644 --- a/packages/web/src/content/docs/ko/zen.mdx +++ b/packages/web/src/content/docs/ko/zen.mdx @@ -81,8 +81,8 @@ OpenCode Zen은 OpenCode의 다른 provider와 똑같이 작동합니다. | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -92,6 +92,7 @@ OpenCode Zen은 OpenCode의 다른 provider와 똑같이 작동합니다. | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | OpenCode config에서 사용하는 [모델 ID](/docs/config/#models)는 `opencode/` 형식입니다. 예를 들어 GPT 5.4를 사용하려면 config에서 `opencode/gpt-5.4`를 사용하면 됩니다. @@ -117,6 +118,7 @@ https://opencode.ai/zen/v1/models | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -166,6 +168,7 @@ https://opencode.ai/zen/v1/models - MiniMax M2.5 Free는 한정된 기간 동안 OpenCode에서 제공됩니다. 팀은 이 기간에 피드백을 수집하고 모델을 개선합니다. - Ling 2.6 Flash Free는 한정된 기간 동안 OpenCode에서 제공됩니다. 팀은 이 기간에 피드백을 수집하고 모델을 개선합니다. +- Hy3 Preview Flash Free는 한정된 기간 동안 OpenCode에서 제공됩니다. 팀은 이 기간에 피드백을 수집하고 모델을 개선합니다. - Nemotron 3 Super Free는 한정된 기간 동안 OpenCode에서 제공됩니다. 팀은 이 기간에 피드백을 수집하고 모델을 개선합니다. - Big Pickle은 한정된 기간 동안 OpenCode에서 무료로 제공되는 stealth model입니다. 팀은 이 기간에 피드백을 수집하고 모델을 개선합니다. @@ -210,6 +213,7 @@ https://opencode.ai/zen/v1/models - Big Pickle: 무료 제공 기간에는 수집된 데이터가 모델 개선에 사용될 수 있습니다. - MiniMax M2.5 Free: 무료 제공 기간에는 수집된 데이터가 모델 개선에 사용될 수 있습니다. - Ling 2.6 Flash Free: 무료 제공 기간에는 수집된 데이터가 모델 개선에 사용될 수 있습니다. +- Hy3 Preview Free: 무료 제공 기간에는 수집된 데이터가 모델 개선에 사용될 수 있습니다. - Nemotron 3 Super Free(NVIDIA 무료 엔드포인트): [NVIDIA API Trial Terms of Service](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf)에 따라 제공됩니다. 평가판 전용이며 프로덕션 환경이나 민감한 데이터에는 사용할 수 없습니다. NVIDIA는 자사 모델과 서비스를 개선하기 위해 프롬프트와 출력을 기록합니다. 개인 정보나 기밀 데이터는 제출하지 마세요. - OpenAI APIs: 요청은 [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data)에 따라 30일 동안 보관됩니다. - Anthropic APIs: 요청은 [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage)에 따라 30일 동안 보관됩니다. diff --git a/packages/web/src/content/docs/nb/zen.mdx b/packages/web/src/content/docs/nb/zen.mdx index 15c942732a..25689ef8c4 100644 --- a/packages/web/src/content/docs/nb/zen.mdx +++ b/packages/web/src/content/docs/nb/zen.mdx @@ -90,8 +90,8 @@ Du kan også få tilgang til modellene våre gjennom følgende API-endepunkter. | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -101,6 +101,7 @@ Du kan også få tilgang til modellene våre gjennom følgende API-endepunkter. | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | [modell-id](/docs/config/#models) i OpenCode-konfigurasjonen din @@ -128,6 +129,7 @@ Vi støtter en pay-as-you-go-modell. Nedenfor er prisene **per 1M tokens**. | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -177,6 +179,7 @@ Gratis-modellene: - MiniMax M2.5 Free er tilgjengelig på OpenCode i en begrenset periode. Teamet bruker denne tiden til å samle inn tilbakemeldinger og forbedre modellen. - Ling 2.6 Flash Free er tilgjengelig på OpenCode i en begrenset periode. Teamet bruker denne tiden til å samle inn tilbakemeldinger og forbedre modellen. +- Hy3 Preview Free er tilgjengelig på OpenCode i en begrenset periode. Teamet bruker denne tiden til å samle inn tilbakemeldinger og forbedre modellen. - Nemotron 3 Super Free er tilgjengelig på OpenCode i en begrenset periode. Teamet bruker denne tiden til å samle inn tilbakemeldinger og forbedre modellen. - Big Pickle er en stealth-modell som er gratis på OpenCode i en begrenset periode. Teamet bruker denne tiden til å samle inn tilbakemeldinger og forbedre modellen. @@ -224,6 +227,7 @@ Alle modellene våre hostes i US. Leverandørene våre følger en policy for zer - Big Pickle: I gratisperioden kan innsamlede data brukes til å forbedre modellen. - MiniMax M2.5 Free: I gratisperioden kan innsamlede data brukes til å forbedre modellen. - Ling 2.6 Flash Free: I gratisperioden kan innsamlede data brukes til å forbedre modellen. +- Hy3 Preview Free: I gratisperioden kan innsamlede data brukes til å forbedre modellen. - Nemotron 3 Super Free (gratis NVIDIA-endepunkter): Leveres under [NVIDIA API Trial Terms of Service](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf). Kun for prøvebruk, ikke for produksjon eller sensitive data. Prompter og svar logges av NVIDIA for å forbedre modellene og tjenestene deres. Ikke send inn personopplysninger eller konfidensielle data. - OpenAI APIs: Forespørsler lagres i 30 dager i samsvar med [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data). - Anthropic APIs: Forespørsler lagres i 30 dager i samsvar med [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage). diff --git a/packages/web/src/content/docs/pl/zen.mdx b/packages/web/src/content/docs/pl/zen.mdx index 483a3cedfd..023f22da29 100644 --- a/packages/web/src/content/docs/pl/zen.mdx +++ b/packages/web/src/content/docs/pl/zen.mdx @@ -90,8 +90,8 @@ Możesz też uzyskać dostęp do naszych modeli przez poniższe endpointy API. | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -101,6 +101,7 @@ Możesz też uzyskać dostęp do naszych modeli przez poniższe endpointy API. | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | [ID modelu](/docs/config/#models) w Twojej konfiguracji OpenCode używa formatu @@ -128,6 +129,7 @@ Obsługujemy model pay-as-you-go. Poniżej znajdują się ceny **za 1M tokenów* | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -178,6 +180,7 @@ Darmowe modele: - MiniMax M2.5 Free jest dostępny w OpenCode przez ograniczony czas. Zespół wykorzystuje ten czas do zbierania opinii i ulepszania modelu. - Ling 2.6 Flash Free jest dostępny w OpenCode przez ograniczony czas. Zespół wykorzystuje ten czas do zbierania opinii i ulepszania modelu. +- Hy3 Preview Flash Free jest dostępny w OpenCode przez ograniczony czas. Zespół wykorzystuje ten czas do zbierania opinii i ulepszania modelu. - Nemotron 3 Super Free jest dostępny w OpenCode przez ograniczony czas. Zespół wykorzystuje ten czas do zbierania opinii i ulepszania modelu. - Big Pickle to stealth model, który jest darmowy w OpenCode przez ograniczony czas. Zespół wykorzystuje ten czas do zbierania opinii i ulepszania modelu. @@ -225,6 +228,7 @@ Wszystkie nasze modele są hostowane w US. Nasi dostawcy stosują politykę zero - Big Pickle: W czasie darmowego okresu zebrane dane mogą być wykorzystywane do ulepszania modelu. - MiniMax M2.5 Free: W czasie darmowego okresu zebrane dane mogą być wykorzystywane do ulepszania modelu. - Ling 2.6 Flash Free: W czasie darmowego okresu zebrane dane mogą być wykorzystywane do ulepszania modelu. +- Hy3 Preview Free: W czasie darmowego okresu zebrane dane mogą być wykorzystywane do ulepszania modelu. - Nemotron 3 Super Free (darmowe endpointy NVIDIA): Udostępniany zgodnie z [NVIDIA API Trial Terms of Service](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf). Tylko do użytku próbnego, nie do produkcji ani danych wrażliwych. NVIDIA rejestruje prompty i odpowiedzi, aby ulepszać swoje modele i usługi. Nie przesyłaj danych osobowych ani poufnych. - OpenAI APIs: Żądania są przechowywane przez 30 dni zgodnie z [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data). - Anthropic APIs: Żądania są przechowywane przez 30 dni zgodnie z [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage). diff --git a/packages/web/src/content/docs/pt-br/zen.mdx b/packages/web/src/content/docs/pt-br/zen.mdx index 1112066e27..05fabd40ce 100644 --- a/packages/web/src/content/docs/pt-br/zen.mdx +++ b/packages/web/src/content/docs/pt-br/zen.mdx @@ -81,8 +81,8 @@ Você também pode acessar nossos modelos pelos seguintes endpoints de API. | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -92,6 +92,7 @@ Você também pode acessar nossos modelos pelos seguintes endpoints de API. | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | O [model id](/docs/config/#models) na sua configuração do OpenCode usa o formato `opencode/`. Por exemplo, para GPT 5.4, você usaria `opencode/gpt-5.4` na sua configuração. @@ -117,6 +118,7 @@ Oferecemos um modelo pay-as-you-go. Abaixo estão os preços **por 1M tokens**. | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -166,6 +168,7 @@ Os modelos gratuitos: - MiniMax M2.5 Free está disponível no OpenCode por tempo limitado. A equipe está usando esse período para coletar feedback e melhorar o modelo. - Ling 2.6 Flash Free está disponível no OpenCode por tempo limitado. A equipe está usando esse período para coletar feedback e melhorar o modelo. +- Hy3 Preview Free está disponível no OpenCode por tempo limitado. A equipe está usando esse período para coletar feedback e melhorar o modelo. - Nemotron 3 Super Free está disponível no OpenCode por tempo limitado. A equipe está usando esse período para coletar feedback e melhorar o modelo. - Big Pickle é um modelo stealth que está gratuito no OpenCode por tempo limitado. A equipe está usando esse período para coletar feedback e melhorar o modelo. @@ -210,6 +213,7 @@ Todos os nossos modelos são hospedados nos US. Nossos provedores seguem uma pol - Big Pickle: Durante seu período gratuito, os dados coletados podem ser usados para melhorar o modelo. - MiniMax M2.5 Free: Durante seu período gratuito, os dados coletados podem ser usados para melhorar o modelo. - Ling 2.6 Flash Free: Durante seu período gratuito, os dados coletados podem ser usados para melhorar o modelo. +- Hy3 Preview Free: Durante seu período gratuito, os dados coletados podem ser usados para melhorar o modelo. - Nemotron 3 Super Free (endpoints gratuitos da NVIDIA): Fornecido sob os [NVIDIA API Trial Terms of Service](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf). Apenas para uso de avaliação, não para produção nem dados sensíveis. A NVIDIA registra prompts e saídas para melhorar seus modelos e serviços. Não envie dados pessoais ou confidenciais. - OpenAI APIs: As solicitações são retidas por 30 dias de acordo com [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data). - Anthropic APIs: As solicitações são retidas por 30 dias de acordo com [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage). diff --git a/packages/web/src/content/docs/ru/zen.mdx b/packages/web/src/content/docs/ru/zen.mdx index 27d81354eb..13184ecf77 100644 --- a/packages/web/src/content/docs/ru/zen.mdx +++ b/packages/web/src/content/docs/ru/zen.mdx @@ -90,8 +90,8 @@ OpenCode Zen работает как любой другой провайдер | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -101,6 +101,7 @@ OpenCode Zen работает как любой другой провайдер | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | [идентификатор модели](/docs/config/#models) в вашей конфигурации OpenCode @@ -128,6 +129,7 @@ https://opencode.ai/zen/v1/models | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -177,6 +179,7 @@ https://opencode.ai/zen/v1/models - MiniMax M2.5 Free доступна в OpenCode ограниченное время. Команда использует это время, чтобы собирать отзывы и улучшать модель. - Ling 2.6 Flash Free доступна в OpenCode ограниченное время. Команда использует это время, чтобы собирать отзывы и улучшать модель. +- Hy3 Preview Flash Free доступна в OpenCode ограниченное время. Команда использует это время, чтобы собирать отзывы и улучшать модель. - Nemotron 3 Super Free доступна в OpenCode ограниченное время. Команда использует это время, чтобы собирать отзывы и улучшать модель. - Big Pickle — это скрытая модель, которая доступна бесплатно в OpenCode ограниченное время. Команда использует это время, чтобы собирать отзывы и улучшать модель. @@ -224,6 +227,7 @@ https://opencode.ai/zen/v1/models - Big Pickle: во время бесплатного периода собранные данные могут использоваться для улучшения модели. - MiniMax M2.5 Free: во время бесплатного периода собранные данные могут использоваться для улучшения модели. - Ling 2.6 Flash Free: во время бесплатного периода собранные данные могут использоваться для улучшения модели. +- Hy3 Preview Free: во время бесплатного периода собранные данные могут использоваться для улучшения модели. - Nemotron 3 Super Free (бесплатные эндпоинты NVIDIA): предоставляется в соответствии с [NVIDIA API Trial Terms of Service](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf). Только для пробного использования, не для продакшена и не для чувствительных данных. NVIDIA логирует запросы и ответы, чтобы улучшать свои модели и сервисы. Не отправляйте персональные или конфиденциальные данные. - OpenAI APIs: запросы хранятся 30 дней в соответствии с [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data). - Anthropic APIs: запросы хранятся 30 дней в соответствии с [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage). diff --git a/packages/web/src/content/docs/th/zen.mdx b/packages/web/src/content/docs/th/zen.mdx index 78de61a9ba..b75e6d5fd6 100644 --- a/packages/web/src/content/docs/th/zen.mdx +++ b/packages/web/src/content/docs/th/zen.mdx @@ -83,8 +83,8 @@ OpenCode Zen ทำงานเหมือน provider อื่น ๆ ใน | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -94,6 +94,7 @@ OpenCode Zen ทำงานเหมือน provider อื่น ๆ ใน | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | [model id](/docs/config/#models) ใน OpenCode config ของคุณใช้รูปแบบ `opencode/` ตัวอย่างเช่น สำหรับ GPT 5.4 คุณจะใช้ `opencode/gpt-5.4` ใน config ของคุณ @@ -119,6 +120,7 @@ https://opencode.ai/zen/v1/models | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -168,6 +170,7 @@ https://opencode.ai/zen/v1/models - MiniMax M2.5 Free เปิดให้ใช้บน OpenCode ในช่วงเวลาจำกัด ทีมกำลังใช้ช่วงเวลานี้เพื่อเก็บ feedback และปรับปรุงโมเดล - Ling 2.6 Flash Free เปิดให้ใช้บน OpenCode ในช่วงเวลาจำกัด ทีมกำลังใช้ช่วงเวลานี้เพื่อเก็บ feedback และปรับปรุงโมเดล +- Hy3 Preview Free เปิดให้ใช้บน OpenCode ในช่วงเวลาจำกัด ทีมกำลังใช้ช่วงเวลานี้เพื่อเก็บ feedback และปรับปรุงโมเดล - Nemotron 3 Super Free เปิดให้ใช้บน OpenCode ในช่วงเวลาจำกัด ทีมกำลังใช้ช่วงเวลานี้เพื่อเก็บ feedback และปรับปรุงโมเดล - Big Pickle เป็น stealth model ที่ใช้งานฟรีบน OpenCode ในช่วงเวลาจำกัด ทีมกำลังใช้ช่วงเวลานี้เพื่อเก็บ feedback และปรับปรุงโมเดล @@ -212,6 +215,7 @@ https://opencode.ai/zen/v1/models - Big Pickle: ระหว่างช่วงที่เปิดให้ใช้ฟรี ข้อมูลที่เก็บรวบรวมอาจถูกนำไปใช้เพื่อปรับปรุงโมเดล - MiniMax M2.5 Free: ระหว่างช่วงที่เปิดให้ใช้ฟรี ข้อมูลที่เก็บรวบรวมอาจถูกนำไปใช้เพื่อปรับปรุงโมเดล - Ling 2.6 Flash Free: ระหว่างช่วงที่เปิดให้ใช้ฟรี ข้อมูลที่เก็บรวบรวมอาจถูกนำไปใช้เพื่อปรับปรุงโมเดล +- Hy3 Preview Free: ระหว่างช่วงที่เปิดให้ใช้ฟรี ข้อมูลที่เก็บรวบรวมอาจถูกนำไปใช้เพื่อปรับปรุงโมเดล - Nemotron 3 Super Free (endpoint ฟรีของ NVIDIA): ให้บริการภายใต้ [NVIDIA API Trial Terms of Service](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf) ใช้สำหรับการทดลองเท่านั้น ไม่เหมาะสำหรับ production หรือข้อมูลที่อ่อนไหว NVIDIA จะบันทึก prompt และ output เพื่อนำไปปรับปรุงโมเดลและบริการของตน โปรดอย่าส่งข้อมูลส่วนบุคคลหรือข้อมูลลับ. - OpenAI APIs: คำขอจะถูกเก็บไว้เป็นเวลา 30 วันตาม [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data). - Anthropic APIs: คำขอจะถูกเก็บไว้เป็นเวลา 30 วันตาม [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage). diff --git a/packages/web/src/content/docs/tr/zen.mdx b/packages/web/src/content/docs/tr/zen.mdx index 409c11a218..a3a1781f0b 100644 --- a/packages/web/src/content/docs/tr/zen.mdx +++ b/packages/web/src/content/docs/tr/zen.mdx @@ -81,8 +81,8 @@ Modellerimize aşağıdaki API uç noktaları aracılığıyla da erişebilirsin | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -92,6 +92,7 @@ Modellerimize aşağıdaki API uç noktaları aracılığıyla da erişebilirsin | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | OpenCode yapılandırmanızdaki [model id](/docs/config/#models) `opencode/` biçimini kullanır. Örneğin, GPT 5.4 için yapılandırmanızda `opencode/gpt-5.4` kullanırsınız. @@ -117,6 +118,7 @@ Kullandıkça öde modelini destekliyoruz. Aşağıda **1M token başına** fiya | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -166,6 +168,7 @@ Kredi kartı ücretleri maliyet üzerinden yansıtılır (%4.4 + işlem başına - MiniMax M2.5 Free, sınırlı bir süre için OpenCode'da ücretsizdir. Ekip bu süreyi geri bildirim toplamak ve modeli iyileştirmek için kullanıyor. - Ling 2.6 Flash Free, sınırlı bir süre için OpenCode'da ücretsizdir. Ekip bu süreyi geri bildirim toplamak ve modeli iyileştirmek için kullanıyor. +- Hy3 Preview Free, sınırlı bir süre için OpenCode'da ücretsizdir. Ekip bu süreyi geri bildirim toplamak ve modeli iyileştirmek için kullanıyor. - Nemotron 3 Super Free, sınırlı bir süre için OpenCode'da ücretsizdir. Ekip bu süreyi geri bildirim toplamak ve modeli iyileştirmek için kullanıyor. - Big Pickle, sınırlı bir süre için OpenCode'da ücretsiz olan gizli bir modeldir. Ekip bu süreyi geri bildirim toplamak ve modeli iyileştirmek için kullanıyor. @@ -210,6 +213,7 @@ Tüm modellerimiz US'de barındırılıyor. Sağlayıcılarımız zero-retention - Big Pickle: Ücretsiz döneminde toplanan veriler modeli iyileştirmek için kullanılabilir. - MiniMax M2.5 Free: Ücretsiz döneminde toplanan veriler modeli iyileştirmek için kullanılabilir. - Ling 2.6 Flash Free: Ücretsiz döneminde toplanan veriler modeli iyileştirmek için kullanılabilir. +- Hy3 Preview Free: Ücretsiz döneminde toplanan veriler modeli iyileştirmek için kullanılabilir. - Nemotron 3 Super Free (ücretsiz NVIDIA uç noktaları): [NVIDIA API Trial Terms of Service](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf) kapsamında sunulur. Yalnızca deneme amaçlıdır; üretim veya hassas veriler için uygun değildir. NVIDIA, modellerini ve hizmetlerini geliştirmek için promptları ve çıktıları kaydeder. Kişisel veya gizli veri göndermeyin. - OpenAI APIs: İstekler [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data) uyarınca 30 gün boyunca saklanır. - Anthropic APIs: İstekler [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage) uyarınca 30 gün boyunca saklanır. diff --git a/packages/web/src/content/docs/zen.mdx b/packages/web/src/content/docs/zen.mdx index 1c59c00f74..d208d3ae5c 100644 --- a/packages/web/src/content/docs/zen.mdx +++ b/packages/web/src/content/docs/zen.mdx @@ -90,8 +90,8 @@ You can also access our models through the following API endpoints. | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -101,6 +101,7 @@ You can also access our models through the following API endpoints. | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | The [model id](/docs/config/#models) in your OpenCode config @@ -128,6 +129,7 @@ We support a pay-as-you-go model. Below are the prices **per 1M tokens**. | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -177,6 +179,7 @@ The free models: - MiniMax M2.5 Free is available on OpenCode for a limited time. The team is using this time to collect feedback and improve the model. - Ling 2.6 Flash Free is available on OpenCode for a limited time. The team is using this time to collect feedback and improve the model. +- Hy3 Preview Flash Free is available on OpenCode for a limited time. The team is using this time to collect feedback and improve the model. - Nemotron 3 Super Free is available on OpenCode for a limited time. The team is using this time to collect feedback and improve the model. - Big Pickle is a stealth model that's free on OpenCode for a limited time. The team is using this time to collect feedback and improve the model. @@ -224,6 +227,7 @@ All our models are hosted in the US. Our providers follow a zero-retention polic - Big Pickle: During its free period, collected data may be used to improve the model. - MiniMax M2.5 Free: During its free period, collected data may be used to improve the model. - Ling 2.6 Flash Free: During its free period, collected data may be used to improve the model. +- Hy3 Preview Free: During its free period, collected data may be used to improve the model. - Nemotron 3 Super Free (NVIDIA free endpoints): Provided under the [NVIDIA API Trial Terms of Service](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf). Trial use only — not for production or sensitive data. Prompts and outputs are logged by NVIDIA to improve its models and services. Do not submit personal or confidential data. - OpenAI APIs: Requests are retained for 30 days in accordance with [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data). - Anthropic APIs: Requests are retained for 30 days in accordance with [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage). diff --git a/packages/web/src/content/docs/zh-cn/zen.mdx b/packages/web/src/content/docs/zh-cn/zen.mdx index 017c5b6c9c..510b936667 100644 --- a/packages/web/src/content/docs/zh-cn/zen.mdx +++ b/packages/web/src/content/docs/zh-cn/zen.mdx @@ -81,8 +81,8 @@ OpenCode Zen 的工作方式与 OpenCode 中的任何其他提供商相同。 | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -92,6 +92,7 @@ OpenCode Zen 的工作方式与 OpenCode 中的任何其他提供商相同。 | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | 在你的 OpenCode 配置中,[模型 ID](/docs/config/#models) 使用 `opencode/` 格式。例如,对于 GPT 5.4,你需要在配置中使用 `opencode/gpt-5.4`。 @@ -117,6 +118,7 @@ https://opencode.ai/zen/v1/models | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -166,6 +168,7 @@ https://opencode.ai/zen/v1/models - MiniMax M2.5 Free 目前在 OpenCode 上限时免费提供。团队正在利用这段时间收集反馈并改进模型。 - Ling 2.6 Flash Free 目前在 OpenCode 上限时免费提供。团队正在利用这段时间收集反馈并改进模型。 +- Hy3 Preview Flash Free 目前在 OpenCode 上限时免费提供。团队正在利用这段时间收集反馈并改进模型。 - Nemotron 3 Super Free 目前在 OpenCode 上限时免费提供。团队正在利用这段时间收集反馈并改进模型。 - Big Pickle 是一个隐身模型,目前在 OpenCode 上限时免费提供。团队正在利用这段时间收集反馈并改进模型。 @@ -210,6 +213,7 @@ https://opencode.ai/zen/v1/models - Big Pickle:在免费期间,收集的数据可能会被用于改进模型。 - MiniMax M2.5 Free:在免费期间,收集的数据可能会被用于改进模型。 - Ling 2.6 Flash Free:在免费期间,收集的数据可能会被用于改进模型。 +- Hy3 Preview Free:在免费期间,收集的数据可能会被用于改进模型。 - Nemotron 3 Super Free(NVIDIA 免费端点):根据 [NVIDIA API Trial Terms of Service](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf) 提供。仅供试用,不适用于生产环境或敏感数据。NVIDIA 会记录提示词和输出内容,以改进其模型和服务。请勿提交个人或机密数据。 - OpenAI APIs:请求会根据 [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data) 保留 30 天。 - Anthropic APIs:请求会根据 [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage) 保留 30 天。 diff --git a/packages/web/src/content/docs/zh-tw/zen.mdx b/packages/web/src/content/docs/zh-tw/zen.mdx index 0afaf10b66..3634b6eca5 100644 --- a/packages/web/src/content/docs/zh-tw/zen.mdx +++ b/packages/web/src/content/docs/zh-tw/zen.mdx @@ -85,8 +85,8 @@ OpenCode Zen 的運作方式和 OpenCode 中的其他供應商一樣。 | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -96,6 +96,7 @@ OpenCode Zen 的運作方式和 OpenCode 中的其他供應商一樣。 | Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Ling 2.6 Flash | ling-2.6-flash | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | OpenCode 設定中的 [模型 ID](/docs/config/#models) 會使用 `opencode/` @@ -122,6 +123,7 @@ https://opencode.ai/zen/v1/models | Big Pickle | Free | Free | Free | - | | MiniMax M2.5 Free | Free | Free | Free | - | | Ling 2.6 Flash Free | Free | Free | Free | - | +| Hy3 Preview Free | Free | Free | Free | - | | Nemotron 3 Super Free | Free | Free | Free | - | | MiniMax M2.7 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | @@ -172,6 +174,7 @@ https://opencode.ai/zen/v1/models - MiniMax M2.5 Free 在 OpenCode 上限時提供。團隊正在利用這段時間收集回饋並改進模型。 - Ling 2.6 Flash Free 在 OpenCode 上限時提供。團隊正在利用這段時間收集回饋並改進模型。 +- Hy3 Preview Free 在 OpenCode 上限時提供。團隊正在利用這段時間收集回饋並改進模型。 - Nemotron 3 Super Free 在 OpenCode 上限時提供。團隊正在利用這段時間收集回饋並改進模型。 - Big Pickle 是一個隱身模型,在 OpenCode 上限時免費提供。團隊正在利用這段時間收集回饋並改進模型。 @@ -217,6 +220,7 @@ https://opencode.ai/zen/v1/models - Big Pickle: 在免費期間,收集到的資料可能會用於改進模型。 - MiniMax M2.5 Free: 在免費期間,收集到的資料可能會用於改進模型。 - Ling 2.6 Flash Free: 在免費期間,收集到的資料可能會用於改進模型。 +- Hy3 Preview Free: 在免費期間,收集到的資料可能會用於改進模型。 - Nemotron 3 Super Free(NVIDIA 免費端點):依據 [NVIDIA API Trial Terms of Service](https://assets.ngc.nvidia.com/products/api-catalog/legal/NVIDIA%20API%20Trial%20Terms%20of%20Service.pdf) 提供。僅供試用,不適用於正式環境或敏感資料。NVIDIA 會記錄提示詞與輸出內容,以改進其模型與服務。請勿提交個人或機密資料。 - OpenAI APIs: 請求會依據 [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data) 保留 30 天。 - Anthropic APIs: 請求會依據 [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage) 保留 30 天。 From 785f3589abb5b43d4e7d6d27e308188d961787de Mon Sep 17 00:00:00 2001 From: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Date: Thu, 23 Apr 2026 17:32:01 +0800 Subject: [PATCH 25/92] fix: add keyed prop to Show components for proper reactivity (#23935) --- packages/app/src/pages/layout/sidebar-items.tsx | 4 ++-- packages/app/src/pages/session/message-timeline.tsx | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/app/src/pages/layout/sidebar-items.tsx b/packages/app/src/pages/layout/sidebar-items.tsx index 5170311a7b..4c36eefa59 100644 --- a/packages/app/src/pages/layout/sidebar-items.tsx +++ b/packages/app/src/pages/layout/sidebar-items.tsx @@ -269,10 +269,10 @@ export const SessionItem = (props: SessionItemProps): JSX.Element => {
    - + {(child) => (
    - +
    )}
    diff --git a/packages/app/src/pages/session/message-timeline.tsx b/packages/app/src/pages/session/message-timeline.tsx index fa57cabaec..592ca774e6 100644 --- a/packages/app/src/pages/session/message-timeline.tsx +++ b/packages/app/src/pages/session/message-timeline.tsx @@ -812,7 +812,7 @@ export function MessageTimeline(props: {
    - + {(id) => (
    @@ -878,12 +878,12 @@ export function MessageTimeline(props: { - void archiveSession(id())}> + void archiveSession(id)}> {language.t("common.archive")} dialog.show(() => )} + onSelect={() => dialog.show(() => )} > {language.t("common.delete")} From 6002500bc0a65aab3da7310797b5498ac0dae18c Mon Sep 17 00:00:00 2001 From: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Date: Thu, 23 Apr 2026 18:57:04 +0800 Subject: [PATCH 26/92] feat(project): add icon_url_override field to projects (#23955) --- packages/app/src/context/global-sync.tsx | 35 +- .../src/context/global-sync/child-store.ts | 8 +- packages/app/src/context/layout.tsx | 34 +- .../app/src/pages/layout/sidebar-items.tsx | 4 +- .../migration.sql | 2 + .../snapshot.json | 1481 +++++++++++++++++ packages/opencode/src/project/project.sql.ts | 1 + packages/opencode/src/project/project.ts | 11 +- .../opencode/src/storage/json-migration.ts | 1 + .../opencode/test/project/project.test.ts | 45 +- 10 files changed, 1545 insertions(+), 77 deletions(-) create mode 100644 packages/opencode/migration/20260423070820_add_icon_url_override/migration.sql create mode 100644 packages/opencode/migration/20260423070820_add_icon_url_override/snapshot.json diff --git a/packages/app/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx index 7c819918c0..b742667d72 100644 --- a/packages/app/src/context/global-sync.tsx +++ b/packages/app/src/context/global-sync.tsx @@ -10,9 +10,8 @@ import type { import { showToast } from "@opencode-ai/ui/toast" import { getFilename } from "@opencode-ai/shared/util/path" import { batch, createContext, getOwner, onCleanup, onMount, type ParentProps, untrack, useContext } from "solid-js" -import { createStore, produce, reconcile, unwrap } from "solid-js/store" +import { createStore, produce, reconcile } from "solid-js/store" import { useLanguage } from "@/context/language" -import { Persist, persisted } from "@/utils/persist" import type { InitError } from "../pages/error" import { useGlobalSDK } from "./global-sdk" import { bootstrapDirectory, bootstrapGlobal, clearProviderRev } from "./global-sync/bootstrap" @@ -24,7 +23,6 @@ import { estimateRootSessionTotal, loadRootSessionsWithFallback } from "./global import { trimSessions } from "./global-sync/session-trim" import type { ProjectMeta } from "./global-sync/types" import { SESSION_RECENT_LIMIT } from "./global-sync/types" -import { sanitizeProject } from "./global-sync/utils" import { formatServerError } from "@/utils/server-errors" import { queryOptions, skipToken, useQueryClient } from "@tanstack/solid-query" @@ -56,15 +54,10 @@ function createGlobalSync() { const sessionLoads = new Map>() const sessionMeta = new Map() - const [projectCache, setProjectCache, projectInit] = persisted( - Persist.global("globalSync.project", ["globalSync.project.v1"]), - createStore({ value: [] as Project[] }), - ) - const [globalStore, setGlobalStore] = createStore({ ready: false, path: { state: "", config: "", worktree: "", directory: "", home: "" }, - project: projectCache.value, + project: [], session_todo: {}, provider: { all: [], connected: [], default: {} }, provider_auth: {}, @@ -73,32 +66,18 @@ function createGlobalSync() { }) const queryClient = useQueryClient() - let active = true - let projectWritten = false let bootedAt = 0 let bootingRoot = false let eventFrame: number | undefined let eventTimer: ReturnType | undefined - onCleanup(() => { - active = false - }) onCleanup(() => { if (eventFrame !== undefined) cancelAnimationFrame(eventFrame) if (eventTimer !== undefined) clearTimeout(eventTimer) }) - const cacheProjects = () => { - setProjectCache( - "value", - untrack(() => globalStore.project.map(sanitizeProject)), - ) - } - const setProjects = (next: Project[] | ((draft: Project[]) => Project[])) => { - projectWritten = true setGlobalStore("project", next) - cacheProjects() } const setBootStore = ((...input: unknown[]) => { @@ -117,16 +96,6 @@ function createGlobalSync() { return (setGlobalStore as (...args: unknown[]) => unknown)(...input) }) as typeof setGlobalStore - if (projectInit instanceof Promise) { - void projectInit.then(() => { - if (!active) return - if (projectWritten) return - const cached = projectCache.value - if (cached.length === 0) return - setGlobalStore("project", cached) - }) - } - const setSessionTodo = (sessionID: string, todos: Todo[] | undefined) => { if (!sessionID) return if (!todos) { diff --git a/packages/app/src/context/global-sync/child-store.ts b/packages/app/src/context/global-sync/child-store.ts index c92d2ae570..f3b613a7f2 100644 --- a/packages/app/src/context/global-sync/child-store.ts +++ b/packages/app/src/context/global-sync/child-store.ts @@ -156,13 +156,12 @@ export function createChildStoreManager(input: { const init = () => createRoot((dispose) => { - const initialMeta = meta[0].value const initialIcon = icon[0].value const pathQuery = useQuery(() => loadPathQuery(directory)) const child = createStore({ project: "", - projectMeta: initialMeta, + projectMeta: undefined, icon: initialIcon, provider_ready: false, provider: { all: [], connected: [], default: {} }, @@ -208,11 +207,6 @@ export function createChildStoreManager(input: { child[1]("vcs", (value) => value ?? cached) }) - onPersistedInit(meta[2], () => { - if (child[0].projectMeta !== initialMeta) return - child[1]("projectMeta", meta[0].value) - }) - onPersistedInit(icon[2], () => { if (child[0].icon !== initialIcon) return child[1]("icon", icon[0].value) diff --git a/packages/app/src/context/layout.tsx b/packages/app/src/context/layout.tsx index 90e357bd33..97d9cacbbe 100644 --- a/packages/app/src/context/layout.tsx +++ b/packages/app/src/context/layout.tsx @@ -391,37 +391,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( ? globalSync.data.project.find((x) => x.id === projectID) : globalSync.data.project.find((x) => x.worktree === project.worktree) - const local = childStore.projectMeta - const localOverride = - local?.name !== undefined || - local?.commands?.start !== undefined || - local?.icon?.override !== undefined || - local?.icon?.color !== undefined - - const base = { - ...metadata, - ...project, - icon: { - url: metadata?.icon?.url, - override: metadata?.icon?.override ?? childStore.icon, - color: metadata?.icon?.color, - }, - } - - const isGlobal = projectID === "global" || (metadata?.id === undefined && localOverride) - if (!isGlobal) return base - - return { - ...base, - id: base.id ?? "global", - name: local?.name, - commands: local?.commands, - icon: { - url: base.icon?.url, - override: local?.icon?.override, - color: local?.icon?.color, - }, - } + return { ...metadata, ...project } } const roots = createMemo(() => { @@ -516,7 +486,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( } for (const project of projects) { - if (project.icon?.color || project.icon.url) continue + if (project.icon?.color || project.icon?.override || project.icon?.url) continue const worktree = project.worktree const existing = colors[worktree] const color = existing ?? pickAvailableColor(used) diff --git a/packages/app/src/pages/layout/sidebar-items.tsx b/packages/app/src/pages/layout/sidebar-items.tsx index 4c36eefa59..9a9a1d7fca 100644 --- a/packages/app/src/pages/layout/sidebar-items.tsx +++ b/packages/app/src/pages/layout/sidebar-items.tsx @@ -22,9 +22,7 @@ const OPENCODE_PROJECT_ID = "4b0ea68d7af9a6031a7ffda7ad66e0cb83315750" export function getProjectAvatarSource(id?: string, icon?: { color?: string; url?: string; override?: string }) { return id === OPENCODE_PROJECT_ID ? "https://opencode.ai/favicon.svg" - : icon?.color - ? undefined - : icon?.override || icon?.url + : (icon?.override ?? (icon?.color ? undefined : icon?.url)) } export const ProjectIcon = (props: { project: LocalProject; class?: string; notify?: boolean }): JSX.Element => { diff --git a/packages/opencode/migration/20260423070820_add_icon_url_override/migration.sql b/packages/opencode/migration/20260423070820_add_icon_url_override/migration.sql new file mode 100644 index 0000000000..e28a1d4e98 --- /dev/null +++ b/packages/opencode/migration/20260423070820_add_icon_url_override/migration.sql @@ -0,0 +1,2 @@ +ALTER TABLE `project` ADD `icon_url_override` text; +UPDATE `project` SET `icon_url_override` = `icon_url` WHERE `icon_url` IS NOT NULL; diff --git a/packages/opencode/migration/20260423070820_add_icon_url_override/snapshot.json b/packages/opencode/migration/20260423070820_add_icon_url_override/snapshot.json new file mode 100644 index 0000000000..318a2bb538 --- /dev/null +++ b/packages/opencode/migration/20260423070820_add_icon_url_override/snapshot.json @@ -0,0 +1,1481 @@ +{ + "version": "7", + "dialect": "sqlite", + "id": "66cbe0d7-def0-451b-b88a-7608513a9b44", + "prevIds": [ + "30b928c5-deef-472c-856d-b5b5064bf6d4" + ], + "ddl": [ + { + "name": "account_state", + "entityType": "tables" + }, + { + "name": "account", + "entityType": "tables" + }, + { + "name": "control_account", + "entityType": "tables" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "name": "project", + "entityType": "tables" + }, + { + "name": "message", + "entityType": "tables" + }, + { + "name": "part", + "entityType": "tables" + }, + { + "name": "permission", + "entityType": "tables" + }, + { + "name": "session_entry", + "entityType": "tables" + }, + { + "name": "session", + "entityType": "tables" + }, + { + "name": "todo", + "entityType": "tables" + }, + { + "name": "session_share", + "entityType": "tables" + }, + { + "name": "event_sequence", + "entityType": "tables" + }, + { + "name": "event", + "entityType": "tables" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "account_state" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "active_account_id", + "entityType": "columns", + "table": "account_state" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "active_org_id", + "entityType": "columns", + "table": "account_state" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "email", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "url", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "access_token", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "refresh_token", + "entityType": "columns", + "table": "account" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "token_expiry", + "entityType": "columns", + "table": "account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "email", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "url", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "access_token", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "refresh_token", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "token_expiry", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "active", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "type", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": "''", + "generated": null, + "name": "name", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "branch", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "directory", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "extra", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "project_id", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "worktree", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "vcs", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "icon_url", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "icon_url_override", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "icon_color", + "entityType": "columns", + "table": "project" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "project" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "project" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_initialized", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "sandboxes", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "commands", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "message" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "message" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "message" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "message" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "data", + "entityType": "columns", + "table": "message" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "part" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "message_id", + "entityType": "columns", + "table": "part" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "part" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "part" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "part" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "data", + "entityType": "columns", + "table": "part" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "project_id", + "entityType": "columns", + "table": "permission" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "permission" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "permission" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "data", + "entityType": "columns", + "table": "permission" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "session_entry" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "session_entry" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "type", + "entityType": "columns", + "table": "session_entry" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "session_entry" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "session_entry" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "data", + "entityType": "columns", + "table": "session_entry" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "project_id", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "parent_id", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "slug", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "directory", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "title", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "version", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "share_url", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "summary_additions", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "summary_deletions", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "summary_files", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "summary_diffs", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "revert", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "permission", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_compacting", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_archived", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "todo" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "content", + "entityType": "columns", + "table": "todo" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "status", + "entityType": "columns", + "table": "todo" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "priority", + "entityType": "columns", + "table": "todo" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "position", + "entityType": "columns", + "table": "todo" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "todo" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "todo" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "secret", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "url", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "aggregate_id", + "entityType": "columns", + "table": "event_sequence" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "seq", + "entityType": "columns", + "table": "event_sequence" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "event" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "aggregate_id", + "entityType": "columns", + "table": "event" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "seq", + "entityType": "columns", + "table": "event" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "type", + "entityType": "columns", + "table": "event" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "data", + "entityType": "columns", + "table": "event" + }, + { + "columns": [ + "active_account_id" + ], + "tableTo": "account", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "nameExplicit": false, + "name": "fk_account_state_active_account_id_account_id_fk", + "entityType": "fks", + "table": "account_state" + }, + { + "columns": [ + "project_id" + ], + "tableTo": "project", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_workspace_project_id_project_id_fk", + "entityType": "fks", + "table": "workspace" + }, + { + "columns": [ + "session_id" + ], + "tableTo": "session", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_message_session_id_session_id_fk", + "entityType": "fks", + "table": "message" + }, + { + "columns": [ + "message_id" + ], + "tableTo": "message", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_part_message_id_message_id_fk", + "entityType": "fks", + "table": "part" + }, + { + "columns": [ + "project_id" + ], + "tableTo": "project", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_permission_project_id_project_id_fk", + "entityType": "fks", + "table": "permission" + }, + { + "columns": [ + "session_id" + ], + "tableTo": "session", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_session_entry_session_id_session_id_fk", + "entityType": "fks", + "table": "session_entry" + }, + { + "columns": [ + "project_id" + ], + "tableTo": "project", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_session_project_id_project_id_fk", + "entityType": "fks", + "table": "session" + }, + { + "columns": [ + "session_id" + ], + "tableTo": "session", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_todo_session_id_session_id_fk", + "entityType": "fks", + "table": "todo" + }, + { + "columns": [ + "session_id" + ], + "tableTo": "session", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_session_share_session_id_session_id_fk", + "entityType": "fks", + "table": "session_share" + }, + { + "columns": [ + "aggregate_id" + ], + "tableTo": "event_sequence", + "columnsTo": [ + "aggregate_id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_event_aggregate_id_event_sequence_aggregate_id_fk", + "entityType": "fks", + "table": "event" + }, + { + "columns": [ + "email", + "url" + ], + "nameExplicit": false, + "name": "control_account_pk", + "entityType": "pks", + "table": "control_account" + }, + { + "columns": [ + "session_id", + "position" + ], + "nameExplicit": false, + "name": "todo_pk", + "entityType": "pks", + "table": "todo" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "account_state_pk", + "table": "account_state", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "account_pk", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "workspace_pk", + "table": "workspace", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "project_pk", + "table": "project", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "message_pk", + "table": "message", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "part_pk", + "table": "part", + "entityType": "pks" + }, + { + "columns": [ + "project_id" + ], + "nameExplicit": false, + "name": "permission_pk", + "table": "permission", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "session_entry_pk", + "table": "session_entry", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "session_pk", + "table": "session", + "entityType": "pks" + }, + { + "columns": [ + "session_id" + ], + "nameExplicit": false, + "name": "session_share_pk", + "table": "session_share", + "entityType": "pks" + }, + { + "columns": [ + "aggregate_id" + ], + "nameExplicit": false, + "name": "event_sequence_pk", + "table": "event_sequence", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "event_pk", + "table": "event", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "session_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + }, + { + "value": "id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "message_session_time_created_id_idx", + "entityType": "indexes", + "table": "message" + }, + { + "columns": [ + { + "value": "message_id", + "isExpression": false + }, + { + "value": "id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "part_message_id_id_idx", + "entityType": "indexes", + "table": "part" + }, + { + "columns": [ + { + "value": "session_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "part_session_idx", + "entityType": "indexes", + "table": "part" + }, + { + "columns": [ + { + "value": "session_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "session_entry_session_idx", + "entityType": "indexes", + "table": "session_entry" + }, + { + "columns": [ + { + "value": "session_id", + "isExpression": false + }, + { + "value": "type", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "session_entry_session_type_idx", + "entityType": "indexes", + "table": "session_entry" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "session_entry_time_created_idx", + "entityType": "indexes", + "table": "session_entry" + }, + { + "columns": [ + { + "value": "project_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "session_project_idx", + "entityType": "indexes", + "table": "session" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "session_workspace_idx", + "entityType": "indexes", + "table": "session" + }, + { + "columns": [ + { + "value": "parent_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "session_parent_idx", + "entityType": "indexes", + "table": "session" + }, + { + "columns": [ + { + "value": "session_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "todo_session_idx", + "entityType": "indexes", + "table": "todo" + } + ], + "renames": [] +} \ No newline at end of file diff --git a/packages/opencode/src/project/project.sql.ts b/packages/opencode/src/project/project.sql.ts index efbc400b5e..2d486114a3 100644 --- a/packages/opencode/src/project/project.sql.ts +++ b/packages/opencode/src/project/project.sql.ts @@ -8,6 +8,7 @@ export const ProjectTable = sqliteTable("project", { vcs: text(), name: text(), icon_url: text(), + icon_url_override: text(), icon_color: text(), ...Timestamps, time_initialized: integer(), diff --git a/packages/opencode/src/project/project.ts b/packages/opencode/src/project/project.ts index d628f87f97..ab60cff7aa 100644 --- a/packages/opencode/src/project/project.ts +++ b/packages/opencode/src/project/project.ts @@ -60,7 +60,13 @@ type Row = typeof ProjectTable.$inferSelect export function fromRow(row: Row): Info { const icon = - row.icon_url || row.icon_color ? { url: row.icon_url ?? undefined, color: row.icon_color ?? undefined } : undefined + row.icon_url || row.icon_url_override || row.icon_color + ? { + url: row.icon_url ?? undefined, + override: row.icon_url_override ?? undefined, + color: row.icon_color ?? undefined, + } + : undefined return { id: row.id, worktree: row.worktree, @@ -289,6 +295,7 @@ export const layer: Layer.Layer< vcs: result.vcs ?? null, name: result.name, icon_url: result.icon?.url, + icon_url_override: result.icon?.override, icon_color: result.icon?.color, time_created: result.time.created, time_updated: result.time.updated, @@ -303,6 +310,7 @@ export const layer: Layer.Layer< vcs: result.vcs ?? null, name: result.name, icon_url: result.icon?.url, + icon_url_override: result.icon?.override, icon_color: result.icon?.color, time_updated: result.time.updated, time_initialized: result.time.initialized, @@ -365,6 +373,7 @@ export const layer: Layer.Layer< .set({ name: input.name, icon_url: input.icon?.url, + icon_url_override: input.icon?.override, icon_color: input.icon?.color, commands: input.commands, time_updated: Date.now(), diff --git a/packages/opencode/src/storage/json-migration.ts b/packages/opencode/src/storage/json-migration.ts index 12133ce435..05588db0f6 100644 --- a/packages/opencode/src/storage/json-migration.ts +++ b/packages/opencode/src/storage/json-migration.ts @@ -168,6 +168,7 @@ export async function run(db: SQLiteBunDatabase | NodeSQLiteDatabase { expect(updated).toBeDefined() expect(updated!.icon).toBeUndefined() }) + + test("should not discover favicon when override is set", async () => { + await using tmp = await tmpdir({ git: true }) + const { project } = await run((svc) => svc.fromDirectory(tmp.path)) + + await run((svc) => + svc.update({ + projectID: project.id, + icon: { override: "data:image/png;base64,override" }, + }), + ) + + const updatedProject = await run((svc) => svc.get(project.id)) + if (!updatedProject) throw new Error("Project not found") + + const pngData = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]) + await Bun.write(path.join(tmp.path, "favicon.png"), pngData) + + await run((svc) => svc.discover(updatedProject)) + + const updated = Project.get(project.id) + expect(updated).toBeDefined() + expect(updated!.icon?.override).toBe("data:image/png;base64,override") + expect(updated!.icon?.url).toBeUndefined() + }) }) describe("Project.update", () => { @@ -332,6 +357,23 @@ describe("Project.update", () => { expect(fromDb?.icon?.color).toBe("#ff0000") }) + test("should update icon override", async () => { + await using tmp = await tmpdir({ git: true }) + const { project } = await run((svc) => svc.fromDirectory(tmp.path)) + + const updated = await run((svc) => + svc.update({ + projectID: project.id, + icon: { override: "data:image/png;base64,abc123" }, + }), + ) + + expect(updated.icon?.override).toBe("data:image/png;base64,abc123") + + const fromDb = Project.get(project.id) + expect(fromDb?.icon?.override).toBe("data:image/png;base64,abc123") + }) + test("should update commands", async () => { await using tmp = await tmpdir({ git: true }) const { project } = await run((svc) => svc.fromDirectory(tmp.path)) @@ -389,13 +431,14 @@ describe("Project.update", () => { svc.update({ projectID: project.id, name: "Multi Update", - icon: { url: "https://example.com/favicon.ico", color: "#00ff00" }, + icon: { url: "https://example.com/favicon.ico", override: "data:image/png;base64,abc123", color: "#00ff00" }, commands: { start: "make start" }, }), ) expect(updated.name).toBe("Multi Update") expect(updated.icon?.url).toBe("https://example.com/favicon.ico") + expect(updated.icon?.override).toBe("data:image/png;base64,abc123") expect(updated.icon?.color).toBe("#00ff00") expect(updated.commands?.start).toBe("make start") }) From 3ae74cb0471b0a642c128d88d14649df673297b3 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Thu, 23 Apr 2026 10:58:14 +0000 Subject: [PATCH 27/92] chore: generate --- .../snapshot.json | 144 +++++------------- 1 file changed, 36 insertions(+), 108 deletions(-) diff --git a/packages/opencode/migration/20260423070820_add_icon_url_override/snapshot.json b/packages/opencode/migration/20260423070820_add_icon_url_override/snapshot.json index 318a2bb538..06dae8e44b 100644 --- a/packages/opencode/migration/20260423070820_add_icon_url_override/snapshot.json +++ b/packages/opencode/migration/20260423070820_add_icon_url_override/snapshot.json @@ -2,9 +2,7 @@ "version": "7", "dialect": "sqlite", "id": "66cbe0d7-def0-451b-b88a-7608513a9b44", - "prevIds": [ - "30b928c5-deef-472c-856d-b5b5064bf6d4" - ], + "prevIds": ["30b928c5-deef-472c-856d-b5b5064bf6d4"], "ddl": [ { "name": "account_state", @@ -1043,13 +1041,9 @@ "table": "event" }, { - "columns": [ - "active_account_id" - ], + "columns": ["active_account_id"], "tableTo": "account", - "columnsTo": [ - "id" - ], + "columnsTo": ["id"], "onUpdate": "NO ACTION", "onDelete": "SET NULL", "nameExplicit": false, @@ -1058,13 +1052,9 @@ "table": "account_state" }, { - "columns": [ - "project_id" - ], + "columns": ["project_id"], "tableTo": "project", - "columnsTo": [ - "id" - ], + "columnsTo": ["id"], "onUpdate": "NO ACTION", "onDelete": "CASCADE", "nameExplicit": false, @@ -1073,13 +1063,9 @@ "table": "workspace" }, { - "columns": [ - "session_id" - ], + "columns": ["session_id"], "tableTo": "session", - "columnsTo": [ - "id" - ], + "columnsTo": ["id"], "onUpdate": "NO ACTION", "onDelete": "CASCADE", "nameExplicit": false, @@ -1088,13 +1074,9 @@ "table": "message" }, { - "columns": [ - "message_id" - ], + "columns": ["message_id"], "tableTo": "message", - "columnsTo": [ - "id" - ], + "columnsTo": ["id"], "onUpdate": "NO ACTION", "onDelete": "CASCADE", "nameExplicit": false, @@ -1103,13 +1085,9 @@ "table": "part" }, { - "columns": [ - "project_id" - ], + "columns": ["project_id"], "tableTo": "project", - "columnsTo": [ - "id" - ], + "columnsTo": ["id"], "onUpdate": "NO ACTION", "onDelete": "CASCADE", "nameExplicit": false, @@ -1118,13 +1096,9 @@ "table": "permission" }, { - "columns": [ - "session_id" - ], + "columns": ["session_id"], "tableTo": "session", - "columnsTo": [ - "id" - ], + "columnsTo": ["id"], "onUpdate": "NO ACTION", "onDelete": "CASCADE", "nameExplicit": false, @@ -1133,13 +1107,9 @@ "table": "session_entry" }, { - "columns": [ - "project_id" - ], + "columns": ["project_id"], "tableTo": "project", - "columnsTo": [ - "id" - ], + "columnsTo": ["id"], "onUpdate": "NO ACTION", "onDelete": "CASCADE", "nameExplicit": false, @@ -1148,13 +1118,9 @@ "table": "session" }, { - "columns": [ - "session_id" - ], + "columns": ["session_id"], "tableTo": "session", - "columnsTo": [ - "id" - ], + "columnsTo": ["id"], "onUpdate": "NO ACTION", "onDelete": "CASCADE", "nameExplicit": false, @@ -1163,13 +1129,9 @@ "table": "todo" }, { - "columns": [ - "session_id" - ], + "columns": ["session_id"], "tableTo": "session", - "columnsTo": [ - "id" - ], + "columnsTo": ["id"], "onUpdate": "NO ACTION", "onDelete": "CASCADE", "nameExplicit": false, @@ -1178,13 +1140,9 @@ "table": "session_share" }, { - "columns": [ - "aggregate_id" - ], + "columns": ["aggregate_id"], "tableTo": "event_sequence", - "columnsTo": [ - "aggregate_id" - ], + "columnsTo": ["aggregate_id"], "onUpdate": "NO ACTION", "onDelete": "CASCADE", "nameExplicit": false, @@ -1193,128 +1151,98 @@ "table": "event" }, { - "columns": [ - "email", - "url" - ], + "columns": ["email", "url"], "nameExplicit": false, "name": "control_account_pk", "entityType": "pks", "table": "control_account" }, { - "columns": [ - "session_id", - "position" - ], + "columns": ["session_id", "position"], "nameExplicit": false, "name": "todo_pk", "entityType": "pks", "table": "todo" }, { - "columns": [ - "id" - ], + "columns": ["id"], "nameExplicit": false, "name": "account_state_pk", "table": "account_state", "entityType": "pks" }, { - "columns": [ - "id" - ], + "columns": ["id"], "nameExplicit": false, "name": "account_pk", "table": "account", "entityType": "pks" }, { - "columns": [ - "id" - ], + "columns": ["id"], "nameExplicit": false, "name": "workspace_pk", "table": "workspace", "entityType": "pks" }, { - "columns": [ - "id" - ], + "columns": ["id"], "nameExplicit": false, "name": "project_pk", "table": "project", "entityType": "pks" }, { - "columns": [ - "id" - ], + "columns": ["id"], "nameExplicit": false, "name": "message_pk", "table": "message", "entityType": "pks" }, { - "columns": [ - "id" - ], + "columns": ["id"], "nameExplicit": false, "name": "part_pk", "table": "part", "entityType": "pks" }, { - "columns": [ - "project_id" - ], + "columns": ["project_id"], "nameExplicit": false, "name": "permission_pk", "table": "permission", "entityType": "pks" }, { - "columns": [ - "id" - ], + "columns": ["id"], "nameExplicit": false, "name": "session_entry_pk", "table": "session_entry", "entityType": "pks" }, { - "columns": [ - "id" - ], + "columns": ["id"], "nameExplicit": false, "name": "session_pk", "table": "session", "entityType": "pks" }, { - "columns": [ - "session_id" - ], + "columns": ["session_id"], "nameExplicit": false, "name": "session_share_pk", "table": "session_share", "entityType": "pks" }, { - "columns": [ - "aggregate_id" - ], + "columns": ["aggregate_id"], "nameExplicit": false, "name": "event_sequence_pk", "table": "event_sequence", "entityType": "pks" }, { - "columns": [ - "id" - ], + "columns": ["id"], "nameExplicit": false, "name": "event_pk", "table": "event", @@ -1478,4 +1406,4 @@ } ], "renames": [] -} \ No newline at end of file +} From 9b6db08d2144c33ec34cd88026774f847ec79761 Mon Sep 17 00:00:00 2001 From: Simon Klee Date: Thu, 23 Apr 2026 13:02:40 +0200 Subject: [PATCH 28/92] chore: add to TEAM_MEMBERS (#23975) --- .github/TEAM_MEMBERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/TEAM_MEMBERS b/.github/TEAM_MEMBERS index 22c9a923d3..3b8519d3bb 100644 --- a/.github/TEAM_MEMBERS +++ b/.github/TEAM_MEMBERS @@ -13,3 +13,4 @@ R44VC0RP rekram1-node RhysSullivan thdxr +simonklee From 38deb0f3eeedb9da68f80b398a694622602162bb Mon Sep 17 00:00:00 2001 From: Shoubhit Dash Date: Thu, 23 Apr 2026 19:54:01 +0530 Subject: [PATCH 29/92] fix(npm): respect npmrc config (#24001) --- packages/opencode/src/npm/index.ts | 38 ++++++++++++++++++++++++++++-- packages/opencode/test/npm.test.ts | 37 +++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/npm/index.ts b/packages/opencode/src/npm/index.ts index fc8497d20b..d6322d5488 100644 --- a/packages/opencode/src/npm/index.ts +++ b/packages/opencode/src/npm/index.ts @@ -1,8 +1,11 @@ export * as Npm from "." import path from "path" +import { fileURLToPath } from "url" import npa from "npm-package-arg" import semver from "semver" +import Config from "@npmcli/config" +import { definitions, flatten, nerfDarts, shorthands } from "@npmcli/config/lib/definitions/index.js" import { Effect, Schema, Context, Layer, Option, FileSystem } from "effect" import { NodeFileSystem } from "@effect/platform-node" import { AppFileSystem } from "@opencode-ai/shared/filesystem" @@ -40,12 +43,39 @@ export interface Interface { export class Service extends Context.Service()("@opencode/Npm") {} const illegal = process.platform === "win32" ? new Set(["<", ">", ":", '"', "|", "?", "*"]) : undefined +const npmPath = fileURLToPath(new URL("../..", import.meta.url)) export function sanitize(pkg: string) { if (!illegal) return pkg return Array.from(pkg, (char) => (illegal.has(char) || char.charCodeAt(0) < 32 ? "_" : char)).join("") } +const loadOptions = (dir: string) => + Effect.tryPromise({ + try: async () => { + const config = new Config({ + npmPath, + cwd: dir, + env: { ...process.env }, + argv: [process.execPath, process.execPath], + execPath: process.execPath, + platform: process.platform, + definitions, + flatten, + nerfDarts, + shorthands, + warn: false, + }) + await config.load() + return config.flat + }, + catch: (cause) => + new InstallFailedError({ + cause, + dir, + }), + }) + const resolveEntryPoint = (name: string, dir: string): EntryPoint => { let entrypoint: Option.Option try { @@ -81,7 +111,10 @@ export const layer = Layer.effect( Effect.gen(function* () { yield* flock.acquire(`npm-install:${input.dir}`) const { Arborist } = yield* Effect.promise(() => import("@npmcli/arborist")) + const add = input.add ?? [] + const npmOptions = yield* loadOptions(input.dir) const arborist = new Arborist({ + ...npmOptions, path: input.dir, binLinks: true, progress: false, @@ -91,14 +124,15 @@ export const layer = Layer.effect( return yield* Effect.tryPromise({ try: () => arborist.reify({ - add: input?.add || [], + ...npmOptions, + add, save: true, saveType: "prod", }), catch: (cause) => new InstallFailedError({ cause, - add: input?.add, + add, dir: input.dir, }), }) as Effect.Effect diff --git a/packages/opencode/test/npm.test.ts b/packages/opencode/test/npm.test.ts index 61e3ca6ddf..a8ec92c2a7 100644 --- a/packages/opencode/test/npm.test.ts +++ b/packages/opencode/test/npm.test.ts @@ -1,7 +1,18 @@ +import fs from "fs/promises" +import path from "path" import { describe, expect, test } from "bun:test" import { Npm } from "../src/npm" +import { tmpdir } from "./fixture/fixture" const win = process.platform === "win32" +const writePackage = (dir: string, pkg: Record) => + Bun.write( + path.join(dir, "package.json"), + JSON.stringify({ + version: "1.0.0", + ...pkg, + }), + ) describe("Npm.sanitize", () => { test("keeps normal scoped package specs unchanged", () => { @@ -16,3 +27,29 @@ describe("Npm.sanitize", () => { expect(Npm.sanitize(spec)).toBe(expected) }) }) + +describe("Npm.install", () => { + test("respects omit from project .npmrc", async () => { + await using tmp = await tmpdir() + + await writePackage(tmp.path, { + name: "fixture", + dependencies: { + "prod-pkg": "file:./prod-pkg", + }, + devDependencies: { + "dev-pkg": "file:./dev-pkg", + }, + }) + await Bun.write(path.join(tmp.path, ".npmrc"), "omit=dev\n") + await fs.mkdir(path.join(tmp.path, "prod-pkg")) + await fs.mkdir(path.join(tmp.path, "dev-pkg")) + await writePackage(path.join(tmp.path, "prod-pkg"), { name: "prod-pkg" }) + await writePackage(path.join(tmp.path, "dev-pkg"), { name: "dev-pkg" }) + + await Npm.install(tmp.path) + + await expect(fs.stat(path.join(tmp.path, "node_modules", "prod-pkg"))).resolves.toBeDefined() + await expect(fs.stat(path.join(tmp.path, "node_modules", "dev-pkg"))).rejects.toThrow() + }) +}) From bbf67d0fff28b8d26d7ffb11c347f519308944b0 Mon Sep 17 00:00:00 2001 From: James Long Date: Thu, 23 Apr 2026 11:24:40 -0400 Subject: [PATCH 30/92] fix(tui): render all non-synthetic text parts of a user message (#24009) --- .../src/cli/cmd/tui/routes/session/index.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 2f5da1d231..c04e58acec 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -1250,7 +1250,17 @@ function UserMessage(props: { }) { const ctx = use() const local = useLocal() - const text = createMemo(() => props.parts.flatMap((x) => (x.type === "text" && !x.synthetic ? [x] : []))[0]) + const text = createMemo(() => { + const texts = props.parts + .map((x) => { + if (x.type === "text" && !x.synthetic) { + return x.text + } + return null + }) + .filter(Boolean) + return texts.join("\n\n") + }) const files = createMemo(() => props.parts.flatMap((x) => (x.type === "file" ? [x] : []))) const { theme } = useTheme() const [hover, setHover] = createSignal(false) @@ -1285,7 +1295,7 @@ function UserMessage(props: { backgroundColor={hover() ? theme.backgroundElement : theme.backgroundPanel} flexShrink={0} > - {text()?.text} + {text()} From 0517ab4695e6918a379d1e44cc6cd04a9dc80c06 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 23 Apr 2026 11:30:02 -0400 Subject: [PATCH 31/92] refactor(session): migrate session domain to Effect Schema (#24005) --- packages/opencode/specs/effect/schema.md | 21 +- packages/opencode/src/acp/agent.ts | 4 +- packages/opencode/src/cli/cmd/import.ts | 5 +- .../server/routes/instance/experimental.ts | 2 +- .../src/server/routes/instance/session.ts | 72 ++-- packages/opencode/src/session/message.ts | 353 +++++++++--------- packages/opencode/src/session/projectors.ts | 2 +- packages/opencode/src/session/prompt.ts | 149 ++++---- packages/opencode/src/session/revert.ts | 17 +- packages/opencode/src/session/session.ts | 193 +++++----- packages/opencode/src/session/status.ts | 42 +-- packages/opencode/src/session/summary.ts | 14 +- packages/opencode/src/session/todo.ts | 24 +- packages/opencode/src/tool/todo.ts | 15 +- packages/opencode/src/util/effect-zod.ts | 27 ++ .../test/server/global-session-list.test.ts | 2 +- .../opencode/test/session/compaction.test.ts | 2 +- .../test/session/schema-decoding.test.ts | 310 +++++++++++++++ 18 files changed, 812 insertions(+), 442 deletions(-) create mode 100644 packages/opencode/test/session/schema-decoding.test.ts diff --git a/packages/opencode/specs/effect/schema.md b/packages/opencode/specs/effect/schema.md index 9ff6859cee..3f2c3b4c96 100644 --- a/packages/opencode/specs/effect/schema.md +++ b/packages/opencode/specs/effect/schema.md @@ -159,6 +159,7 @@ Schema at source. These are the highest-priority next targets. Each is a small, self-contained schema module with a clear domain. +- [x] `src/account/schema.ts` - [x] `src/control-plane/schema.ts` - [x] `src/permission/schema.ts` - [x] `src/project/schema.ts` @@ -166,8 +167,10 @@ schema module with a clear domain. - [x] `src/pty/schema.ts` - [x] `src/question/schema.ts` - [x] `src/session/schema.ts` +- [x] `src/storage/schema.ts` - [x] `src/sync/schema.ts` - [x] `src/tool/schema.ts` +- [x] `src/util/schema.ts` ### Session domain @@ -248,15 +251,15 @@ Possible later tightening after the Schema-first migration is stable: - promote repeated opaque strings and timestamp numbers into branded/newtype leaf schemas where that adds domain value without changing the wire format -- [ ] `src/session/compaction.ts` -- [ ] `src/session/message-v2.ts` -- [ ] `src/session/message.ts` -- [ ] `src/session/prompt.ts` -- [ ] `src/session/revert.ts` -- [ ] `src/session/session.ts` -- [ ] `src/session/status.ts` -- [ ] `src/session/summary.ts` -- [ ] `src/session/todo.ts` +- [x] `src/session/compaction.ts` +- [x] `src/session/message-v2.ts` +- [x] `src/session/message.ts` +- [x] `src/session/prompt.ts` +- [x] `src/session/revert.ts` +- [x] `src/session/session.ts` +- [x] `src/session/status.ts` +- [x] `src/session/summary.ts` +- [x] `src/session/todo.ts` ### Provider domain diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts index f12328153b..672b93f6ce 100644 --- a/packages/opencode/src/acp/agent.ts +++ b/packages/opencode/src/acp/agent.ts @@ -372,7 +372,7 @@ export class Agent implements ACPAgent { } if (part.tool === "todowrite") { - const parsedTodos = z.array(Todo.Info).safeParse(JSON.parse(part.state.output)) + const parsedTodos = z.array(Todo.Info.zod).safeParse(JSON.parse(part.state.output)) if (parsedTodos.success) { await this.connection .sessionUpdate({ @@ -901,7 +901,7 @@ export class Agent implements ACPAgent { } if (part.tool === "todowrite") { - const parsedTodos = z.array(Todo.Info).safeParse(JSON.parse(part.state.output)) + const parsedTodos = z.array(Todo.Info.zod).safeParse(JSON.parse(part.state.output)) if (parsedTodos.success) { await this.connection .sessionUpdate({ diff --git a/packages/opencode/src/cli/cmd/import.ts b/packages/opencode/src/cli/cmd/import.ts index 309ec6d950..e52120f1af 100644 --- a/packages/opencode/src/cli/cmd/import.ts +++ b/packages/opencode/src/cli/cmd/import.ts @@ -11,6 +11,7 @@ import { ShareNext } from "../../share" import { EOL } from "os" import { Filesystem } from "../../util" import { AppRuntime } from "@/effect/app-runtime" +import { Schema } from "effect" /** Discriminated union returned by the ShareNext API (GET /api/shares/:id/data) */ export type ShareData = @@ -154,10 +155,10 @@ export const ImportCommand = cmd({ return } - const info = Session.Info.parse({ + const info = Schema.decodeUnknownSync(Session.Info)({ ...exportData.info, projectID: Instance.project.id, - }) + }) as Session.Info const row = Session.toRow(info) Database.use((db) => db diff --git a/packages/opencode/src/server/routes/instance/experimental.ts b/packages/opencode/src/server/routes/instance/experimental.ts index 9c86494987..93a5d98c94 100644 --- a/packages/opencode/src/server/routes/instance/experimental.ts +++ b/packages/opencode/src/server/routes/instance/experimental.ts @@ -335,7 +335,7 @@ export const ExperimentalRoutes = lazy(() => description: "List of sessions", content: { "application/json": { - schema: resolver(Session.GlobalInfo.array()), + schema: resolver(Session.GlobalInfo.zod.array()), }, }, }, diff --git a/packages/opencode/src/server/routes/instance/session.ts b/packages/opencode/src/server/routes/instance/session.ts index 8d03024260..4f4f8ed86e 100644 --- a/packages/opencode/src/server/routes/instance/session.ts +++ b/packages/opencode/src/server/routes/instance/session.ts @@ -23,6 +23,7 @@ import { PermissionID } from "@/permission/schema" import { ModelID, ProviderID } from "@/provider/schema" import { errors } from "../../error" import { lazy } from "@/util/lazy" +import { zodObject } from "@/util/effect-zod" import { Bus } from "@/bus" import { NamedError } from "@opencode-ai/shared/util/error" import { jsonRequest, runRequest } from "./trace" @@ -42,7 +43,7 @@ export const SessionRoutes = lazy(() => description: "List of sessions", content: { "application/json": { - schema: resolver(Session.Info.array()), + schema: resolver(Session.Info.zod.array()), }, }, }, @@ -87,7 +88,7 @@ export const SessionRoutes = lazy(() => description: "Get session status", content: { "application/json": { - schema: resolver(z.record(z.string(), SessionStatus.Info)), + schema: resolver(z.record(z.string(), SessionStatus.Info.zod)), }, }, }, @@ -112,7 +113,7 @@ export const SessionRoutes = lazy(() => description: "Get session", content: { "application/json": { - schema: resolver(Session.Info), + schema: resolver(Session.Info.zod), }, }, }, @@ -122,7 +123,7 @@ export const SessionRoutes = lazy(() => validator( "param", z.object({ - sessionID: Session.GetInput, + sessionID: Session.GetInput.zod, }), ), async (c) => { @@ -145,7 +146,7 @@ export const SessionRoutes = lazy(() => description: "List of children", content: { "application/json": { - schema: resolver(Session.Info.array()), + schema: resolver(Session.Info.zod.array()), }, }, }, @@ -155,7 +156,7 @@ export const SessionRoutes = lazy(() => validator( "param", z.object({ - sessionID: Session.ChildrenInput, + sessionID: Session.ChildrenInput.zod, }), ), async (c) => { @@ -177,7 +178,7 @@ export const SessionRoutes = lazy(() => description: "Todo list", content: { "application/json": { - schema: resolver(Todo.Info.array()), + schema: resolver(Todo.Info.zod.array()), }, }, }, @@ -210,13 +211,13 @@ export const SessionRoutes = lazy(() => description: "Successfully created session", content: { "application/json": { - schema: resolver(Session.Info), + schema: resolver(Session.Info.zod), }, }, }, }, }), - validator("json", Session.CreateInput), + validator("json", Session.CreateInput.zod), async (c) => jsonRequest("SessionRoutes.create", c, function* () { const body = c.req.valid("json") ?? {} @@ -245,7 +246,7 @@ export const SessionRoutes = lazy(() => validator( "param", z.object({ - sessionID: Session.RemoveInput, + sessionID: Session.RemoveInput.zod, }), ), async (c) => @@ -267,7 +268,7 @@ export const SessionRoutes = lazy(() => description: "Successfully updated session", content: { "application/json": { - schema: resolver(Session.Info), + schema: resolver(Session.Info.zod), }, }, }, @@ -375,7 +376,7 @@ export const SessionRoutes = lazy(() => description: "200", content: { "application/json": { - schema: resolver(Session.Info), + schema: resolver(Session.Info.zod), }, }, }, @@ -384,14 +385,14 @@ export const SessionRoutes = lazy(() => validator( "param", z.object({ - sessionID: Session.ForkInput.shape.sessionID, + sessionID: SessionID.zod, }), ), - validator("json", Session.ForkInput.omit({ sessionID: true })), + validator("json", zodObject(Session.ForkInput).omit({ sessionID: true })), async (c) => jsonRequest("SessionRoutes.fork", c, function* () { const sessionID = c.req.valid("param").sessionID - const body = c.req.valid("json") + const body = c.req.valid("json") as { messageID?: MessageID } const svc = yield* Session.Service return yield* svc.fork({ ...body, sessionID }) }), @@ -438,7 +439,7 @@ export const SessionRoutes = lazy(() => description: "Successfully shared session", content: { "application/json": { - schema: resolver(Session.Info), + schema: resolver(Session.Info.zod), }, }, }, @@ -480,18 +481,13 @@ export const SessionRoutes = lazy(() => validator( "param", z.object({ - sessionID: SessionSummary.DiffInput.shape.sessionID, - }), - ), - validator( - "query", - z.object({ - messageID: SessionSummary.DiffInput.shape.messageID, + sessionID: SessionID.zod, }), ), + validator("query", zodObject(SessionSummary.DiffInput).omit({ sessionID: true })), async (c) => jsonRequest("SessionRoutes.diff", c, function* () { - const query = c.req.valid("query") + const query = c.req.valid("query") as Omit const params = c.req.valid("param") const summary = yield* SessionSummary.Service return yield* summary.diff({ @@ -511,7 +507,7 @@ export const SessionRoutes = lazy(() => description: "Successfully unshared session", content: { "application/json": { - schema: resolver(Session.Info), + schema: resolver(Session.Info.zod), }, }, }, @@ -872,7 +868,7 @@ export const SessionRoutes = lazy(() => sessionID: SessionID.zod, }), ), - validator("json", SessionPrompt.PromptInput.omit({ sessionID: true })), + validator("json", zodObject(SessionPrompt.PromptInput).omit({ sessionID: true })), async (c) => { c.status(200) c.header("Content-Type", "application/json") @@ -910,7 +906,7 @@ export const SessionRoutes = lazy(() => sessionID: SessionID.zod, }), ), - validator("json", SessionPrompt.PromptInput.omit({ sessionID: true })), + validator("json", zodObject(SessionPrompt.PromptInput).omit({ sessionID: true })), async (c) => { const sessionID = c.req.valid("param").sessionID const body = c.req.valid("json") @@ -960,11 +956,11 @@ export const SessionRoutes = lazy(() => sessionID: SessionID.zod, }), ), - validator("json", SessionPrompt.CommandInput.omit({ sessionID: true })), + validator("json", zodObject(SessionPrompt.CommandInput).omit({ sessionID: true })), async (c) => jsonRequest("SessionRoutes.command", c, function* () { const sessionID = c.req.valid("param").sessionID - const body = c.req.valid("json") + const body = c.req.valid("json") as Omit const svc = yield* SessionPrompt.Service return yield* svc.command({ ...body, sessionID }) }), @@ -993,11 +989,11 @@ export const SessionRoutes = lazy(() => sessionID: SessionID.zod, }), ), - validator("json", SessionPrompt.ShellInput.omit({ sessionID: true })), + validator("json", zodObject(SessionPrompt.ShellInput).omit({ sessionID: true })), async (c) => jsonRequest("SessionRoutes.shell", c, function* () { const sessionID = c.req.valid("param").sessionID - const body = c.req.valid("json") + const body = c.req.valid("json") as Omit const svc = yield* SessionPrompt.Service return yield* svc.shell({ ...body, sessionID }) }), @@ -1013,7 +1009,7 @@ export const SessionRoutes = lazy(() => description: "Updated session", content: { "application/json": { - schema: resolver(Session.Info), + schema: resolver(Session.Info.zod), }, }, }, @@ -1026,16 +1022,14 @@ export const SessionRoutes = lazy(() => sessionID: SessionID.zod, }), ), - validator("json", SessionRevert.RevertInput.omit({ sessionID: true })), + validator("json", zodObject(SessionRevert.RevertInput).omit({ sessionID: true })), async (c) => { const sessionID = c.req.valid("param").sessionID - log.info("revert", c.req.valid("json")) + const body = c.req.valid("json") as Omit + log.info("revert", body) return jsonRequest("SessionRoutes.revert", c, function* () { const svc = yield* SessionRevert.Service - return yield* svc.revert({ - sessionID, - ...c.req.valid("json"), - }) + return yield* svc.revert({ sessionID, ...body }) }) }, ) @@ -1050,7 +1044,7 @@ export const SessionRoutes = lazy(() => description: "Updated session", content: { "application/json": { - schema: resolver(Session.Info), + schema: resolver(Session.Info.zod), }, }, }, diff --git a/packages/opencode/src/session/message.ts b/packages/opencode/src/session/message.ts index ced04b8e9d..b1b2453431 100644 --- a/packages/opencode/src/session/message.ts +++ b/packages/opencode/src/session/message.ts @@ -1,191 +1,192 @@ -import z from "zod" +import { Schema } from "effect" import { SessionID } from "./schema" import { ModelID, ProviderID } from "../provider/schema" -import { NamedError } from "@opencode-ai/shared/util/error" +import { zod } from "@/util/effect-zod" +import { withStatics } from "@/util/schema" +import { namedSchemaError } from "@/util/named-schema-error" -export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({})) -export const AuthError = NamedError.create( - "ProviderAuthError", - z.object({ - providerID: z.string(), - message: z.string(), - }), -) - -export const ToolCall = z - .object({ - state: z.literal("call"), - step: z.number().optional(), - toolCallId: z.string(), - toolName: z.string(), - args: z.custom>(), - }) - .meta({ - ref: "ToolCall", - }) -export type ToolCall = z.infer - -export const ToolPartialCall = z - .object({ - state: z.literal("partial-call"), - step: z.number().optional(), - toolCallId: z.string(), - toolName: z.string(), - args: z.custom>(), - }) - .meta({ - ref: "ToolPartialCall", - }) -export type ToolPartialCall = z.infer - -export const ToolResult = z - .object({ - state: z.literal("result"), - step: z.number().optional(), - toolCallId: z.string(), - toolName: z.string(), - args: z.custom>(), - result: z.string(), - }) - .meta({ - ref: "ToolResult", - }) -export type ToolResult = z.infer - -export const ToolInvocation = z.discriminatedUnion("state", [ToolCall, ToolPartialCall, ToolResult]).meta({ - ref: "ToolInvocation", +export const OutputLengthError = namedSchemaError("MessageOutputLengthError", {}) +export const AuthError = namedSchemaError("ProviderAuthError", { + providerID: Schema.String, + message: Schema.String, }) -export type ToolInvocation = z.infer -export const TextPart = z - .object({ - type: z.literal("text"), - text: z.string(), - }) - .meta({ - ref: "TextPart", - }) -export type TextPart = z.infer +const AuthErrorEffect = Schema.Struct({ + name: Schema.Literal("ProviderAuthError"), + data: Schema.Struct({ + providerID: Schema.String, + message: Schema.String, + }), +}) -export const ReasoningPart = z - .object({ - type: z.literal("reasoning"), - text: z.string(), - providerMetadata: z.record(z.string(), z.any()).optional(), - }) - .meta({ - ref: "ReasoningPart", - }) -export type ReasoningPart = z.infer +const OutputLengthErrorEffect = Schema.Struct({ + name: Schema.Literal("MessageOutputLengthError"), + data: Schema.Struct({}), +}) -export const ToolInvocationPart = z - .object({ - type: z.literal("tool-invocation"), - toolInvocation: ToolInvocation, - }) - .meta({ - ref: "ToolInvocationPart", - }) -export type ToolInvocationPart = z.infer +const UnknownErrorEffect = Schema.Struct({ + name: Schema.Literal("UnknownError"), + data: Schema.Struct({ + message: Schema.String, + }), +}) -export const SourceUrlPart = z - .object({ - type: z.literal("source-url"), - sourceId: z.string(), - url: z.string(), - title: z.string().optional(), - providerMetadata: z.record(z.string(), z.any()).optional(), - }) - .meta({ - ref: "SourceUrlPart", - }) -export type SourceUrlPart = z.infer +export const ToolCall = Schema.Struct({ + state: Schema.Literal("call"), + step: Schema.optional(Schema.Number), + toolCallId: Schema.String, + toolName: Schema.String, + args: Schema.Unknown, +}) + .annotate({ identifier: "ToolCall" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type ToolCall = Schema.Schema.Type -export const FilePart = z - .object({ - type: z.literal("file"), - mediaType: z.string(), - filename: z.string().optional(), - url: z.string(), - }) - .meta({ - ref: "FilePart", - }) -export type FilePart = z.infer +export const ToolPartialCall = Schema.Struct({ + state: Schema.Literal("partial-call"), + step: Schema.optional(Schema.Number), + toolCallId: Schema.String, + toolName: Schema.String, + args: Schema.Unknown, +}) + .annotate({ identifier: "ToolPartialCall" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type ToolPartialCall = Schema.Schema.Type -export const StepStartPart = z - .object({ - type: z.literal("step-start"), - }) - .meta({ - ref: "StepStartPart", - }) -export type StepStartPart = z.infer +export const ToolResult = Schema.Struct({ + state: Schema.Literal("result"), + step: Schema.optional(Schema.Number), + toolCallId: Schema.String, + toolName: Schema.String, + args: Schema.Unknown, + result: Schema.String, +}) + .annotate({ identifier: "ToolResult" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type ToolResult = Schema.Schema.Type -export const MessagePart = z - .discriminatedUnion("type", [TextPart, ReasoningPart, ToolInvocationPart, SourceUrlPart, FilePart, StepStartPart]) - .meta({ - ref: "MessagePart", - }) -export type MessagePart = z.infer +export const ToolInvocation = Schema.Union([ToolCall, ToolPartialCall, ToolResult]) + .annotate({ identifier: "ToolInvocation", discriminator: "state" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type ToolInvocation = Schema.Schema.Type -export const Info = z - .object({ - id: z.string(), - role: z.enum(["user", "assistant"]), - parts: z.array(MessagePart), - metadata: z - .object({ - time: z.object({ - created: z.number(), - completed: z.number().optional(), +export const TextPart = Schema.Struct({ + type: Schema.Literal("text"), + text: Schema.String, +}) + .annotate({ identifier: "TextPart" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type TextPart = Schema.Schema.Type + +export const ReasoningPart = Schema.Struct({ + type: Schema.Literal("reasoning"), + text: Schema.String, + providerMetadata: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)), +}) + .annotate({ identifier: "ReasoningPart" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type ReasoningPart = Schema.Schema.Type + +export const ToolInvocationPart = Schema.Struct({ + type: Schema.Literal("tool-invocation"), + toolInvocation: ToolInvocation, +}) + .annotate({ identifier: "ToolInvocationPart" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type ToolInvocationPart = Schema.Schema.Type + +export const SourceUrlPart = Schema.Struct({ + type: Schema.Literal("source-url"), + sourceId: Schema.String, + url: Schema.String, + title: Schema.optional(Schema.String), + providerMetadata: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)), +}) + .annotate({ identifier: "SourceUrlPart" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type SourceUrlPart = Schema.Schema.Type + +export const FilePart = Schema.Struct({ + type: Schema.Literal("file"), + mediaType: Schema.String, + filename: Schema.optional(Schema.String), + url: Schema.String, +}) + .annotate({ identifier: "FilePart" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type FilePart = Schema.Schema.Type + +export const StepStartPart = Schema.Struct({ + type: Schema.Literal("step-start"), +}) + .annotate({ identifier: "StepStartPart" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type StepStartPart = Schema.Schema.Type + +export const MessagePart = Schema.Union([ + TextPart, + ReasoningPart, + ToolInvocationPart, + SourceUrlPart, + FilePart, + StepStartPart, +]) + .annotate({ identifier: "MessagePart", discriminator: "type" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type MessagePart = Schema.Schema.Type + +export const Info = Schema.Struct({ + id: Schema.String, + role: Schema.Literals(["user", "assistant"]), + parts: Schema.Array(MessagePart), + metadata: Schema.Struct({ + time: Schema.Struct({ + created: Schema.Number, + completed: Schema.optional(Schema.Number), + }), + error: Schema.optional(Schema.Union([AuthErrorEffect, UnknownErrorEffect, OutputLengthErrorEffect])), + sessionID: SessionID, + tool: Schema.Record( + Schema.String, + Schema.StructWithRest( + Schema.Struct({ + title: Schema.String, + snapshot: Schema.optional(Schema.String), + time: Schema.Struct({ + start: Schema.Number, + end: Schema.Number, + }), }), - error: z - .discriminatedUnion("name", [AuthError.Schema, NamedError.Unknown.Schema, OutputLengthError.Schema]) - .optional(), - sessionID: SessionID.zod, - tool: z.record( - z.string(), - z - .object({ - title: z.string(), - snapshot: z.string().optional(), - time: z.object({ - start: z.number(), - end: z.number(), - }), - }) - .catchall(z.any()), - ), - assistant: z - .object({ - system: z.string().array(), - modelID: ModelID.zod, - providerID: ProviderID.zod, - path: z.object({ - cwd: z.string(), - root: z.string(), - }), - cost: z.number(), - summary: z.boolean().optional(), - tokens: z.object({ - input: z.number(), - output: z.number(), - reasoning: z.number(), - cache: z.object({ - read: z.number(), - write: z.number(), - }), - }), - }) - .optional(), - snapshot: z.string().optional(), - }) - .meta({ ref: "MessageMetadata" }), - }) - .meta({ - ref: "Message", - }) -export type Info = z.infer + [Schema.Record(Schema.String, Schema.Unknown)], + ), + ), + assistant: Schema.optional( + Schema.Struct({ + system: Schema.Array(Schema.String), + modelID: ModelID, + providerID: ProviderID, + path: Schema.Struct({ + cwd: Schema.String, + root: Schema.String, + }), + cost: Schema.Number, + summary: Schema.optional(Schema.Boolean), + tokens: Schema.Struct({ + input: Schema.Number, + output: Schema.Number, + reasoning: Schema.Number, + cache: Schema.Struct({ + read: Schema.Number, + write: Schema.Number, + }), + }), + }), + ), + snapshot: Schema.optional(Schema.String), + }).annotate({ identifier: "MessageMetadata" }), +}) + .annotate({ identifier: "Message" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type Info = Schema.Schema.Type export * as Message from "./message" diff --git a/packages/opencode/src/session/projectors.ts b/packages/opencode/src/session/projectors.ts index fb8354dda1..b55f9dcc7a 100644 --- a/packages/opencode/src/session/projectors.ts +++ b/packages/opencode/src/session/projectors.ts @@ -62,7 +62,7 @@ export function toPartialRow(info: DeepPartial) { export default [ SyncEvent.project(Session.Event.Created, (db, data) => { - db.insert(SessionTable).values(Session.toRow(data.info)).run() + db.insert(SessionTable).values(Session.toRow(data.info as Session.Info)).run() }), SyncEvent.project(Session.Event.Updated, (db, data) => { diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 508c72cc8f..0f48eb64ec 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -43,7 +43,9 @@ import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Truncate } from "@/tool" import { decodeDataUrl } from "@/util/data-url" import { Process } from "@/util" -import { Cause, Effect, Exit, Layer, Option, Scope, Context } from "effect" +import { Cause, Effect, Exit, Layer, Option, Scope, Context, Schema } from "effect" +import { zod } from "@/util/effect-zod" +import { withStatics } from "@/util/schema" import { EffectLogger } from "@/effect" import { InstanceState } from "@/effect" import { TaskTool, type TaskPromptOps } from "@/tool/task" @@ -69,7 +71,7 @@ const elog = EffectLogger.create({ service: "session.prompt" }) export interface Interface { readonly cancel: (sessionID: SessionID) => Effect.Effect readonly prompt: (input: PromptInput) => Effect.Effect - readonly loop: (input: z.infer) => Effect.Effect + readonly loop: (input: LoopInput) => Effect.Effect readonly shell: (input: ShellInput) => Effect.Effect readonly command: (input: CommandInput) => Effect.Effect readonly resolvePromptParts: (template: string) => Effect.Effect @@ -1532,9 +1534,9 @@ NOTE: At any point in time through this workflow you should feel free to ask the }, ) - const loop: (input: z.infer) => Effect.Effect = Effect.fn( - "SessionPrompt.loop", - )(function* (input: z.infer) { + const loop: (input: LoopInput) => Effect.Effect = Effect.fn("SessionPrompt.loop")(function* ( + input: LoopInput, + ) { return yield* state.ensureRunning(input.sessionID, lastAssistant(input.sessionID), runLoop(input.sessionID)) }) @@ -1701,91 +1703,88 @@ export const defaultLayer = Layer.suspend(() => ), ), ) -export const PromptInput = z.object({ - sessionID: SessionID.zod, - messageID: MessageID.zod.optional(), - model: z - .object({ - providerID: ProviderID.zod, - modelID: ModelID.zod, - }) - .optional(), - agent: z.string().optional(), - noReply: z.boolean().optional(), - tools: z - .record(z.string(), z.boolean()) - .optional() - .describe("@deprecated tools and permissions have been merged, you can set permissions on the session itself now"), - format: MessageV2.Format.zod.optional(), - system: z.string().optional(), - variant: z.string().optional(), - parts: z.array( - z.discriminatedUnion("type", [ - MessageV2.TextPartInput.zod as unknown as z.ZodObject, - MessageV2.FilePartInput.zod as unknown as z.ZodObject, - MessageV2.AgentPartInput.zod as unknown as z.ZodObject, - MessageV2.SubtaskPartInput.zod as unknown as z.ZodObject, - ]), - ), +const ModelRef = Schema.Struct({ + providerID: ProviderID, + modelID: ModelID, }) + +export const PromptInput = Schema.Struct({ + sessionID: SessionID, + messageID: Schema.optional(MessageID), + model: Schema.optional(ModelRef), + agent: Schema.optional(Schema.String), + noReply: Schema.optional(Schema.Boolean), + tools: Schema.optional(Schema.Record(Schema.String, Schema.Boolean)).annotate({ + description: + "@deprecated tools and permissions have been merged, you can set permissions on the session itself now", + }), + format: Schema.optional(MessageV2.Format), + system: Schema.optional(Schema.String), + variant: Schema.optional(Schema.String), + parts: Schema.Array( + Schema.Union([ + MessageV2.TextPartInput, + MessageV2.FilePartInput, + MessageV2.AgentPartInput, + MessageV2.SubtaskPartInput, + ]).annotate({ discriminator: "type" }), + ), +}).pipe(withStatics((s) => ({ zod: zod(s) }))) // `z.discriminatedUnion` erases the discriminated members' shapes back to -// `{}` because the derived `.zod` on each input is typed as an opaque -// `z.ZodType`. Restore the precise `parts` type from the exported Schema -// input types so callers see a proper tagged union. +// `{}` when walked from the generic `z.ZodType` input. Restore the precise +// `parts` type from the exported Schema input types so callers see a proper +// tagged union. type PartInputUnion = | MessageV2.TextPartInput | MessageV2.FilePartInput | MessageV2.AgentPartInput | MessageV2.SubtaskPartInput -export type PromptInput = Omit, "parts"> & { +export type PromptInput = Omit, "parts"> & { parts: PartInputUnion[] } -export const LoopInput = z.object({ - sessionID: SessionID.zod, -}) +export class LoopInput extends Schema.Class("SessionPrompt.LoopInput")({ + sessionID: SessionID, +}) { + static readonly zod = zod(this) +} -export const ShellInput = z.object({ - sessionID: SessionID.zod, - messageID: MessageID.zod.optional(), - agent: z.string(), - model: z - .object({ - providerID: ProviderID.zod, - modelID: ModelID.zod, - }) - .optional(), - command: z.string(), -}) -export type ShellInput = z.infer +export const ShellInput = Schema.Struct({ + sessionID: SessionID, + messageID: Schema.optional(MessageID), + agent: Schema.String, + model: Schema.optional(ModelRef), + command: Schema.String, +}).pipe(withStatics((s) => ({ zod: zod(s) }))) +export type ShellInput = Schema.Schema.Type -export const CommandInput = z.object({ - messageID: MessageID.zod.optional(), - sessionID: SessionID.zod, - agent: z.string().optional(), - model: z.string().optional(), - arguments: z.string(), - command: z.string(), - variant: z.string().optional(), - // Inlined (no `.meta({ ref })`) to keep the original SDK output — the +export const CommandInput = Schema.Struct({ + messageID: Schema.optional(MessageID), + sessionID: SessionID, + agent: Schema.optional(Schema.String), + model: Schema.optional(Schema.String), + arguments: Schema.String, + command: Schema.String, + variant: Schema.optional(Schema.String), + // Inlined (no identifier annotation) to keep the original SDK output — the // PromptInput call site below references FilePartInput by ref via the // Schema export in message-v2.ts. - parts: z - .array( - z.discriminatedUnion("type", [ - z.object({ - id: PartID.zod.optional(), - type: z.literal("file"), - mime: z.string(), - filename: z.string().optional(), - url: z.string(), - source: MessageV2.FilePartSource.zod.optional(), + parts: Schema.optional( + Schema.Array( + Schema.Union([ + Schema.Struct({ + id: Schema.optional(PartID), + type: Schema.Literal("file"), + mime: Schema.String, + filename: Schema.optional(Schema.String), + url: Schema.String, + source: Schema.optional(MessageV2.FilePartSource), }), - ]), - ) - .optional(), -}) -export type CommandInput = z.infer + ]).annotate({ discriminator: "type" }), + ), + ), +}).pipe(withStatics((s) => ({ zod: zod(s) }))) +export type CommandInput = Schema.Schema.Type /** @internal Exported for testing */ export function createStructuredOutputTool(input: { diff --git a/packages/opencode/src/session/revert.ts b/packages/opencode/src/session/revert.ts index c7e5220f12..e1db26510d 100644 --- a/packages/opencode/src/session/revert.ts +++ b/packages/opencode/src/session/revert.ts @@ -1,10 +1,11 @@ -import z from "zod" -import { Effect, Layer, Context } from "effect" +import { Effect, Layer, Context, Schema } from "effect" import { Bus } from "../bus" import { Snapshot } from "../snapshot" import { Storage } from "@/storage" import { SyncEvent } from "../sync" import { Log } from "../util" +import { zod } from "@/util/effect-zod" +import { withStatics } from "@/util/schema" import * as Session from "./session" import { MessageV2 } from "./message-v2" import { SessionID, MessageID, PartID } from "./schema" @@ -13,12 +14,12 @@ import { SessionSummary } from "./summary" const log = Log.create({ service: "session.revert" }) -export const RevertInput = z.object({ - sessionID: SessionID.zod, - messageID: MessageID.zod, - partID: PartID.zod.optional(), -}) -export type RevertInput = z.infer +export const RevertInput = Schema.Struct({ + sessionID: SessionID, + messageID: MessageID, + partID: Schema.optional(PartID), +}).pipe(withStatics((s) => ({ zod: zod(s) }))) +export type RevertInput = Schema.Schema.Type export interface Interface { readonly revert: (input: RevertInput) => Effect.Effect diff --git a/packages/opencode/src/session/session.ts b/packages/opencode/src/session/session.ts index a7607798ba..d2bdbccb7d 100644 --- a/packages/opencode/src/session/session.ts +++ b/packages/opencode/src/session/session.ts @@ -27,7 +27,9 @@ import { SessionID, MessageID, PartID } from "./schema" import type { Provider } from "@/provider" import { Permission } from "@/permission" import { Global } from "@/global" -import { Effect, Layer, Option, Context } from "effect" +import { Effect, Layer, Option, Context, Schema, Types } from "effect" +import { zod, zodObject } from "@/util/effect-zod" +import { withStatics } from "@/util/schema" const log = Log.create({ service: "session" }) @@ -114,91 +116,104 @@ function getForkedTitle(title: string): string { return `${title} (fork #1)` } -export const Info = z - .object({ - id: SessionID.zod, - slug: z.string(), - projectID: ProjectID.zod, - workspaceID: WorkspaceID.zod.optional(), - directory: z.string(), - parentID: SessionID.zod.optional(), - summary: z - .object({ - additions: z.number(), - deletions: z.number(), - files: z.number(), - diffs: Snapshot.FileDiff.zod.array().optional(), - }) - .optional(), - share: z - .object({ - url: z.string(), - }) - .optional(), - title: z.string(), - version: z.string(), - time: z.object({ - created: z.number(), - updated: z.number(), - compacting: z.number().optional(), - archived: z.number().optional(), - }), - permission: Permission.Ruleset.zod.optional(), - revert: z - .object({ - messageID: MessageID.zod, - partID: PartID.zod.optional(), - snapshot: z.string().optional(), - diff: z.string().optional(), - }) - .optional(), - }) - .meta({ - ref: "Session", - }) -export type Info = z.output - -export const ProjectInfo = z - .object({ - id: ProjectID.zod, - name: z.string().optional(), - worktree: z.string(), - }) - .meta({ - ref: "ProjectSummary", - }) -export type ProjectInfo = z.output - -export const GlobalInfo = Info.extend({ - project: ProjectInfo.nullable(), -}).meta({ - ref: "GlobalSession", +const Summary = Schema.Struct({ + additions: Schema.Number, + deletions: Schema.Number, + files: Schema.Number, + diffs: Schema.optional(Schema.Array(Snapshot.FileDiff)), }) -export type GlobalInfo = z.output -export const CreateInput = z - .object({ - parentID: SessionID.zod.optional(), - title: z.string().optional(), - permission: Info.shape.permission, - workspaceID: WorkspaceID.zod.optional(), - }) - .optional() -export type CreateInput = z.output - -export const ForkInput = z.object({ sessionID: SessionID.zod, messageID: MessageID.zod.optional() }) -export const GetInput = SessionID.zod -export const ChildrenInput = SessionID.zod -export const RemoveInput = SessionID.zod -export const SetTitleInput = z.object({ sessionID: SessionID.zod, title: z.string() }) -export const SetArchivedInput = z.object({ sessionID: SessionID.zod, time: z.number().optional() }) -export const SetPermissionInput = z.object({ sessionID: SessionID.zod, permission: Permission.Ruleset.zod }) -export const SetRevertInput = z.object({ - sessionID: SessionID.zod, - revert: Info.shape.revert, - summary: Info.shape.summary, +const Share = Schema.Struct({ + url: Schema.String, }) -export const MessagesInput = z.object({ sessionID: SessionID.zod, limit: z.number().optional() }) + +const Time = Schema.Struct({ + created: Schema.Number, + updated: Schema.Number, + compacting: Schema.optional(Schema.Number), + archived: Schema.optional(Schema.Number), +}) + +const Revert = Schema.Struct({ + messageID: MessageID, + partID: Schema.optional(PartID), + snapshot: Schema.optional(Schema.String), + diff: Schema.optional(Schema.String), +}) + +export const Info = Schema.Struct({ + id: SessionID, + slug: Schema.String, + projectID: ProjectID, + workspaceID: Schema.optional(WorkspaceID), + directory: Schema.String, + parentID: Schema.optional(SessionID), + summary: Schema.optional(Summary), + share: Schema.optional(Share), + title: Schema.String, + version: Schema.String, + time: Time, + permission: Schema.optional(Permission.Ruleset), + revert: Schema.optional(Revert), +}) + .annotate({ identifier: "Session" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type Info = Types.DeepMutable> + +export const ProjectInfo = Schema.Struct({ + id: ProjectID, + name: Schema.optional(Schema.String), + worktree: Schema.String, +}) + .annotate({ identifier: "ProjectSummary" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type ProjectInfo = Types.DeepMutable> + +export const GlobalInfo = Schema.Struct({ + ...Info.fields, + project: Schema.NullOr(ProjectInfo), +}) + .annotate({ identifier: "GlobalSession" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type GlobalInfo = Types.DeepMutable> + +export const CreateInput = Schema.optional( + Schema.Struct({ + parentID: Schema.optional(SessionID), + title: Schema.optional(Schema.String), + permission: Schema.optional(Permission.Ruleset), + workspaceID: Schema.optional(WorkspaceID), + }), +).pipe(withStatics((s) => ({ zod: zod(s) }))) +export type CreateInput = Types.DeepMutable> + +export const ForkInput = Schema.Struct({ + sessionID: SessionID, + messageID: Schema.optional(MessageID), +}).pipe(withStatics((s) => ({ zod: zod(s) }))) +export const GetInput = SessionID +export const ChildrenInput = SessionID +export const RemoveInput = SessionID +export const SetTitleInput = Schema.Struct({ sessionID: SessionID, title: Schema.String }).pipe( + withStatics((s) => ({ zod: zod(s) })), +) +export const SetArchivedInput = Schema.Struct({ + sessionID: SessionID, + time: Schema.optional(Schema.Number), +}).pipe(withStatics((s) => ({ zod: zod(s) }))) +export const SetPermissionInput = Schema.Struct({ + sessionID: SessionID, + permission: Permission.Ruleset, +}).pipe(withStatics((s) => ({ zod: zod(s) }))) +export const SetRevertInput = Schema.Struct({ + sessionID: SessionID, + revert: Schema.optional(Revert), + summary: Schema.optional(Summary), +}).pipe(withStatics((s) => ({ zod: zod(s) }))) +export const MessagesInput = Schema.Struct({ + sessionID: SessionID, + limit: Schema.optional(Schema.Number), +}).pipe(withStatics((s) => ({ zod: zod(s) }))) export const Event = { Created: SyncEvent.define({ @@ -207,7 +222,7 @@ export const Event = { aggregate: "sessionID", schema: z.object({ sessionID: SessionID.zod, - info: Info, + info: Info.zod, }), }), Updated: SyncEvent.define({ @@ -216,14 +231,14 @@ export const Event = { aggregate: "sessionID", schema: z.object({ sessionID: SessionID.zod, - info: updateSchema(Info).extend({ - share: updateSchema(Info.shape.share.unwrap()).optional(), - time: updateSchema(Info.shape.time).optional(), + info: updateSchema(zodObject(Info)).extend({ + share: updateSchema(zodObject(Share)).optional(), + time: updateSchema(zodObject(Time)).optional(), }), }), busSchema: z.object({ sessionID: SessionID.zod, - info: Info, + info: Info.zod, }), }), Deleted: SyncEvent.define({ @@ -232,7 +247,7 @@ export const Event = { aggregate: "sessionID", schema: z.object({ sessionID: SessionID.zod, - info: Info, + info: Info.zod, }), }), Diff: BusEvent.define( diff --git a/packages/opencode/src/session/status.ts b/packages/opencode/src/session/status.ts index 7f46c70a8a..b9b9fd7e74 100644 --- a/packages/opencode/src/session/status.ts +++ b/packages/opencode/src/session/status.ts @@ -2,35 +2,35 @@ import { BusEvent } from "@/bus/bus-event" import { Bus } from "@/bus" import { InstanceState } from "@/effect" import { SessionID } from "./schema" -import { Effect, Layer, Context } from "effect" +import { zod } from "@/util/effect-zod" +import { withStatics } from "@/util/schema" +import { Effect, Layer, Context, Schema } from "effect" import z from "zod" -export const Info = z - .union([ - z.object({ - type: z.literal("idle"), - }), - z.object({ - type: z.literal("retry"), - attempt: z.number(), - message: z.string(), - next: z.number(), - }), - z.object({ - type: z.literal("busy"), - }), - ]) - .meta({ - ref: "SessionStatus", - }) -export type Info = z.infer +export const Info = Schema.Union([ + Schema.Struct({ + type: Schema.Literal("idle"), + }), + Schema.Struct({ + type: Schema.Literal("retry"), + attempt: Schema.Number, + message: Schema.String, + next: Schema.Number, + }), + Schema.Struct({ + type: Schema.Literal("busy"), + }), +]) + .annotate({ identifier: "SessionStatus" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type Info = Schema.Schema.Type export const Event = { Status: BusEvent.define( "session.status", z.object({ sessionID: SessionID.zod, - status: Info, + status: Info.zod, }), ), // deprecated diff --git a/packages/opencode/src/session/summary.ts b/packages/opencode/src/session/summary.ts index 70b3102f6e..04a24d2c2b 100644 --- a/packages/opencode/src/session/summary.ts +++ b/packages/opencode/src/session/summary.ts @@ -1,8 +1,9 @@ -import z from "zod" -import { Effect, Layer, Context } from "effect" +import { Effect, Layer, Context, Schema } from "effect" import { Bus } from "@/bus" import { Snapshot } from "@/snapshot" import { Storage } from "@/storage" +import { zod } from "@/util/effect-zod" +import { withStatics } from "@/util/schema" import * as Session from "./session" import { MessageV2 } from "./message-v2" import { SessionID, MessageID } from "./schema" @@ -155,9 +156,10 @@ export const defaultLayer = Layer.suspend(() => ), ) -export const DiffInput = z.object({ - sessionID: SessionID.zod, - messageID: MessageID.zod.optional(), -}) +export const DiffInput = Schema.Struct({ + sessionID: SessionID, + messageID: Schema.optional(MessageID), +}).pipe(withStatics((s) => ({ zod: zod(s) }))) +export type DiffInput = Schema.Schema.Type export * as SessionSummary from "./summary" diff --git a/packages/opencode/src/session/todo.ts b/packages/opencode/src/session/todo.ts index 4840f86a3d..257b586ed7 100644 --- a/packages/opencode/src/session/todo.ts +++ b/packages/opencode/src/session/todo.ts @@ -1,26 +1,30 @@ import { BusEvent } from "@/bus/bus-event" import { Bus } from "@/bus" import { SessionID } from "./schema" -import { Effect, Layer, Context } from "effect" +import { zod } from "@/util/effect-zod" +import { withStatics } from "@/util/schema" +import { Effect, Layer, Context, Schema } from "effect" import z from "zod" import { Database, eq, asc } from "../storage" import { TodoTable } from "./session.sql" -export const Info = z - .object({ - content: z.string().describe("Brief description of the task"), - status: z.string().describe("Current status of the task: pending, in_progress, completed, cancelled"), - priority: z.string().describe("Priority level of the task: high, medium, low"), - }) - .meta({ ref: "Todo" }) -export type Info = z.infer +export const Info = Schema.Struct({ + content: Schema.String.annotate({ description: "Brief description of the task" }), + status: Schema.String.annotate({ + description: "Current status of the task: pending, in_progress, completed, cancelled", + }), + priority: Schema.String.annotate({ description: "Priority level of the task: high, medium, low" }), +}) + .annotate({ identifier: "Todo" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type Info = Schema.Schema.Type export const Event = { Updated: BusEvent.define( "todo.updated", z.object({ sessionID: SessionID.zod, - todos: z.array(Info), + todos: z.array(Info.zod), }), ), } diff --git a/packages/opencode/src/tool/todo.ts b/packages/opencode/src/tool/todo.ts index 5090f17a7c..c08fb04119 100644 --- a/packages/opencode/src/tool/todo.ts +++ b/packages/opencode/src/tool/todo.ts @@ -4,8 +4,21 @@ import * as Tool from "./tool" import DESCRIPTION_WRITE from "./todowrite.txt" import { Todo } from "../session/todo" +// Parameters are kept inline rather than derived from Todo.Info because +// Tool.define requires z.ZodObject-typed parameters for execute() inference, +// and zodObject(Todo.Info) returns ZodObject — reaching into .shape would +// erase field types. Tool schemas migrate to Effect Schema as a separate slice +// per specs/effect/schema.md. const parameters = z.object({ - todos: z.array(z.object(Todo.Info.shape)).describe("The updated todo list"), + todos: z + .array( + z.object({ + content: z.string().describe("Brief description of the task"), + status: z.string().describe("Current status of the task: pending, in_progress, completed, cancelled"), + priority: z.string().describe("Priority level of the task: high, medium, low"), + }), + ) + .describe("The updated todo list"), }) type Metadata = { diff --git a/packages/opencode/src/util/effect-zod.ts b/packages/opencode/src/util/effect-zod.ts index f6d2c5e5c0..edbbf4d542 100644 --- a/packages/opencode/src/util/effect-zod.ts +++ b/packages/opencode/src/util/effect-zod.ts @@ -22,6 +22,33 @@ export function zod(schema: S): z.ZodType> } +/** + * Derive a Zod value from an Effect Schema (or a Schema-backed export with a + * `.zod` static) and narrow the result to `z.ZodObject` so `.shape`, + * `.omit`, `.extend`, and friends are accessible. + * + * The `zod()` walker returns `z.ZodType` because not every AST node decodes + * to an object; this helper keeps the "I started from a `Schema.Struct`" cast + * in one place instead of sprinkling `as unknown as z.ZodObject` across + * call sites. + * + * The return is intentionally loose — carrying Schema field types through the + * mapped `.omit()` / `.extend()` surface triggers brand-intersection + * explosions for branded primitives (`string & Brand<"SessionID">` extends + * `object` via the brand and gets walked into the prototype by `DeepPartial`, + * `updateSchema`, etc.), and zod's inference through `z.ZodType` + * wrappers also can't reconstruct `T` cleanly. Consumers that care about the + * post-`.omit()` shape should cast `c.req.valid(...)` to the expected type. + */ +export function zodObject(schema: S): z.ZodObject { + const derived: z.ZodTypeAny = "zod" in schema && isZodType(schema.zod) ? schema.zod : walk(schema.ast) + return derived as unknown as z.ZodObject +} + +function isZodType(value: unknown): value is z.ZodTypeAny { + return typeof value === "object" && value !== null && "_zod" in value +} + function walk(ast: SchemaAST.AST): z.ZodTypeAny { const cached = walkCache.get(ast) if (cached) return cached diff --git a/packages/opencode/test/server/global-session-list.test.ts b/packages/opencode/test/server/global-session-list.test.ts index d0f71b8fd3..03b1a0346a 100644 --- a/packages/opencode/test/server/global-session-list.test.ts +++ b/packages/opencode/test/server/global-session-list.test.ts @@ -18,7 +18,7 @@ const svc = { create(input?: SessionNs.CreateInput) { return run(SessionNs.Service.use((svc) => svc.create(input))) }, - setArchived(input: z.output) { + setArchived(input: z.output) { return run(SessionNs.Service.use((svc) => svc.setArchived(input))) }, } diff --git a/packages/opencode/test/session/compaction.test.ts b/packages/opencode/test/session/compaction.test.ts index 037613d469..4fe9c15511 100644 --- a/packages/opencode/test/session/compaction.test.ts +++ b/packages/opencode/test/session/compaction.test.ts @@ -38,7 +38,7 @@ const svc = { create(input?: SessionNs.CreateInput) { return run(SessionNs.Service.use((svc) => svc.create(input))) }, - messages(input: z.output) { + messages(input: z.output) { return run(SessionNs.Service.use((svc) => svc.messages(input))) }, updateMessage(msg: T) { diff --git a/packages/opencode/test/session/schema-decoding.test.ts b/packages/opencode/test/session/schema-decoding.test.ts new file mode 100644 index 0000000000..5894b26154 --- /dev/null +++ b/packages/opencode/test/session/schema-decoding.test.ts @@ -0,0 +1,310 @@ +import { describe, expect, test } from "bun:test" +import { Schema } from "effect" + +import { Session } from "../../src/session" +import { SessionPrompt } from "../../src/session/prompt" +import { SessionRevert } from "../../src/session/revert" +import { SessionStatus } from "../../src/session/status" +import { SessionSummary } from "../../src/session/summary" +import { Todo } from "../../src/session/todo" +import { SessionID, MessageID, PartID } from "../../src/session/schema" +import { ProjectID } from "../../src/project/schema" +import { WorkspaceID } from "../../src/control-plane/schema" + +// Covers the session-domain Effect Schema migration. For each migrated +// schema we assert: +// 1. The Effect decoder (`Schema.decodeUnknownSync`) accepts valid input. +// 2. The derived Zod (`X.zod.parse`) accepts the same input and returns the +// same shape. +// 3. Clearly-invalid input is rejected by both paths. +// +// The point is to lock down the Schema <-> Zod bridge so a future edit to +// any input schema can't silently drop or widen a field on one side. + +// Representative valid IDs — the branded schemas require the right prefix +// (see src/id/id.ts). +const sessionID = SessionID.zod.parse("ses_01J5Y5H0AH4Q4NXJ6P4C3P5V2K") +const sessionIDChild = SessionID.zod.parse("ses_01J5Y5H0AH4Q4NXJ6P4C3P5V2L") +const messageID = MessageID.zod.parse("msg_01J5Y5H0AH4Q4NXJ6P4C3P5V2M") +const partID = PartID.zod.parse("prt_01J5Y5H0AH4Q4NXJ6P4C3P5V2N") +const projectID = ProjectID.zod.parse("proj-alpha") +const workspaceID = WorkspaceID.zod.parse("wrk-primary") + +function decodeUnknown(schema: S) { + const decode = Schema.decodeUnknownSync(schema as any) + return (input: unknown): Schema.Schema.Type => decode(input) as Schema.Schema.Type +} + +describe("Session.Info", () => { + const decode = decodeUnknown(Session.Info) + + test("accepts minimal session", () => { + const input = { + id: sessionID, + slug: "hello", + projectID, + directory: "/tmp/proj", + title: "First session", + version: "0.1.0", + time: { created: 1, updated: 2 }, + } + expect(decode(input)).toEqual(input) + expect(Session.Info.zod.parse(input)).toEqual(input) + }) + + test("round-trips every optional field", () => { + const input = { + id: sessionID, + slug: "fullshape", + projectID, + workspaceID, + directory: "/tmp/proj", + parentID: sessionIDChild, + summary: { + additions: 10, + deletions: 5, + files: 2, + diffs: [{ additions: 1, deletions: 0, file: "a.ts", patch: "--- a/a.ts" }], + }, + share: { url: "https://share.example.com/s/1" }, + title: "Full session", + version: "1.0.0", + time: { created: 100, updated: 200, compacting: 150, archived: 300 }, + permission: [{ action: "allow" as const, pattern: "*", permission: "read" }], + revert: { + messageID, + partID, + snapshot: "snap-1", + diff: "diff-1", + }, + } + expect(decode(input)).toEqual(input) + expect(Session.Info.zod.parse(input)).toEqual(input) + }) + + test("rejects unbranded session id", () => { + const bad = { id: "not-a-session-id" } as unknown + expect(() => decode(bad)).toThrow() + expect(() => Session.Info.zod.parse(bad)).toThrow() + }) + + test("rejects missing required fields", () => { + const bad = { id: sessionID } as unknown + expect(() => decode(bad)).toThrow() + expect(() => Session.Info.zod.parse(bad)).toThrow() + }) +}) + +describe("Session.ProjectInfo", () => { + const decode = decodeUnknown(Session.ProjectInfo) + + test("accepts with and without optional name", () => { + const noName = { id: projectID, worktree: "/tmp/wt" } + const withName = { ...noName, name: "alpha" } + expect(decode(noName)).toEqual(noName) + expect(decode(withName)).toEqual(withName) + expect(Session.ProjectInfo.zod.parse(noName)).toEqual(noName) + expect(Session.ProjectInfo.zod.parse(withName)).toEqual(withName) + }) +}) + +describe("Session.GlobalInfo", () => { + const decode = decodeUnknown(Session.GlobalInfo) + + test("accepts null project", () => { + const input = { + id: sessionID, + slug: "global", + projectID, + directory: "/tmp/proj", + title: "global", + version: "0", + time: { created: 0, updated: 0 }, + project: null, + } + expect(decode(input)).toEqual(input) + expect(Session.GlobalInfo.zod.parse(input)).toEqual(input) + }) + + test("accepts populated project", () => { + const input = { + id: sessionID, + slug: "global", + projectID, + directory: "/tmp/proj", + title: "global", + version: "0", + time: { created: 0, updated: 0 }, + project: { id: projectID, worktree: "/tmp/wt", name: "alpha" }, + } + expect(decode(input)).toEqual(input) + expect(Session.GlobalInfo.zod.parse(input)).toEqual(input) + }) +}) + +describe("Session input schemas", () => { + test("CreateInput accepts undefined and populated forms", () => { + const decode = decodeUnknown(Session.CreateInput) + expect(decode(undefined)).toBeUndefined() + expect(Session.CreateInput.zod.parse(undefined)).toBeUndefined() + + const populated = { + parentID: sessionID, + title: "child", + permission: [{ action: "ask" as const, pattern: "*", permission: "bash" }], + workspaceID, + } + expect(decode(populated)).toEqual(populated) + expect(Session.CreateInput.zod.parse(populated)).toEqual(populated) + }) + + test("ForkInput round-trips", () => { + const decode = decodeUnknown(Session.ForkInput) + const input = { sessionID, messageID } + expect(decode(input)).toEqual(input) + expect(Session.ForkInput.zod.parse(input)).toEqual(input) + // messageID is optional + const bare = { sessionID } + expect(decode(bare)).toEqual(bare) + expect(Session.ForkInput.zod.parse(bare)).toEqual(bare) + }) + + test("SetTitleInput rejects missing title", () => { + expect(() => decodeUnknown(Session.SetTitleInput)({ sessionID })).toThrow() + expect(() => Session.SetTitleInput.zod.parse({ sessionID })).toThrow() + }) + + test("SetArchivedInput accepts both with and without time", () => { + const decode = decodeUnknown(Session.SetArchivedInput) + expect(decode({ sessionID })).toEqual({ sessionID }) + expect(decode({ sessionID, time: 123 })).toEqual({ sessionID, time: 123 }) + }) + + test("SetPermissionInput requires a ruleset", () => { + const decode = decodeUnknown(Session.SetPermissionInput) + const input = { sessionID, permission: [{ action: "deny" as const, pattern: "*", permission: "write" }] } + expect(decode(input)).toEqual(input) + expect(() => decode({ sessionID })).toThrow() + }) + + test("MessagesInput accepts optional limit", () => { + const decode = decodeUnknown(Session.MessagesInput) + expect(decode({ sessionID })).toEqual({ sessionID }) + expect(decode({ sessionID, limit: 50 })).toEqual({ sessionID, limit: 50 }) + }) +}) + +describe("SessionRevert.RevertInput", () => { + const decode = decodeUnknown(SessionRevert.RevertInput) + + test("messageID is required, partID is optional", () => { + const withPart = { sessionID, messageID, partID } + expect(decode(withPart)).toEqual(withPart) + expect(SessionRevert.RevertInput.zod.parse(withPart)).toEqual(withPart) + + const noPart = { sessionID, messageID } + expect(decode(noPart)).toEqual(noPart) + expect(SessionRevert.RevertInput.zod.parse(noPart)).toEqual(noPart) + + expect(() => decode({ sessionID })).toThrow() + expect(() => SessionRevert.RevertInput.zod.parse({ sessionID })).toThrow() + }) +}) + +describe("SessionSummary.DiffInput", () => { + const decode = decodeUnknown(SessionSummary.DiffInput) + + test("messageID optional", () => { + expect(decode({ sessionID })).toEqual({ sessionID }) + expect(decode({ sessionID, messageID })).toEqual({ sessionID, messageID }) + }) +}) + +describe("SessionStatus.Info", () => { + const decode = decodeUnknown(SessionStatus.Info) + + test("idle / busy discriminators", () => { + expect(decode({ type: "idle" })).toEqual({ type: "idle" }) + expect(decode({ type: "busy" })).toEqual({ type: "busy" }) + expect(SessionStatus.Info.zod.parse({ type: "idle" })).toEqual({ type: "idle" }) + }) + + test("retry carries attempt/message/next", () => { + const input = { type: "retry" as const, attempt: 1, message: "transient", next: 500 } + expect(decode(input)).toEqual(input) + expect(SessionStatus.Info.zod.parse(input)).toEqual(input) + }) + + test("rejects unknown type", () => { + expect(() => decode({ type: "bogus" })).toThrow() + expect(() => SessionStatus.Info.zod.parse({ type: "bogus" })).toThrow() + }) +}) + +describe("Todo.Info", () => { + const decode = decodeUnknown(Todo.Info) + + test("three-field round-trip", () => { + const input = { content: "do a thing", status: "pending", priority: "high" } + expect(decode(input)).toEqual(input) + expect(Todo.Info.zod.parse(input)).toEqual(input) + }) +}) + +describe("SessionPrompt input schemas", () => { + test("LoopInput is just sessionID", () => { + const decode = decodeUnknown(SessionPrompt.LoopInput) + expect(decode({ sessionID })).toEqual({ sessionID }) + expect(SessionPrompt.LoopInput.zod.parse({ sessionID } as unknown)).toEqual({ sessionID }) + }) + + test("ShellInput requires agent + command", () => { + const decode = decodeUnknown(SessionPrompt.ShellInput) + const expected = { sessionID, agent: "build", command: "echo hi" } + const input: unknown = expected + expect(decode(input)).toEqual(expected) + expect(SessionPrompt.ShellInput.zod.parse(input as unknown)).toEqual(expected) + expect(() => decode({ sessionID })).toThrow() + }) + + test("PromptInput accepts a text part and a file part", () => { + const decode = decodeUnknown(SessionPrompt.PromptInput) + const expected = { + sessionID, + parts: [ + { type: "text" as const, text: "hello" }, + { type: "file" as const, mime: "image/png", url: "data:image/png;base64,AAAA" }, + ], + } + const input: unknown = expected + const decoded = decode(input) + expect(decoded.parts).toHaveLength(2) + expect(decoded.parts[0]).toMatchObject({ type: "text", text: "hello" }) + expect(decoded.parts[1]).toMatchObject({ type: "file", mime: "image/png" }) + + const viaZod = SessionPrompt.PromptInput.zod.parse(input) + expect(viaZod.parts).toHaveLength(2) + }) + + test("PromptInput rejects unknown part type", () => { + const decode = decodeUnknown(SessionPrompt.PromptInput) + const bad = { + sessionID, + parts: [{ type: "nonsense", payload: 42 }], + } + expect(() => decode(bad)).toThrow() + expect(() => SessionPrompt.PromptInput.zod.parse(bad)).toThrow() + }) + + test("CommandInput round-trips core fields", () => { + const decode = decodeUnknown(SessionPrompt.CommandInput) + const expected = { + sessionID, + arguments: "--flag", + command: "deploy", + } + const input: unknown = expected + expect(decode(input)).toEqual(expected) + expect(SessionPrompt.CommandInput.zod.parse(input)).toEqual(expected) + }) +}) From 2cd89d64e9c392a59cda5871d5b2c1ef0929ff7e Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Thu, 23 Apr 2026 15:31:16 +0000 Subject: [PATCH 32/92] chore: generate --- packages/opencode/src/session/projectors.ts | 4 +- packages/sdk/openapi.json | 50 ++++++++++----------- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/packages/opencode/src/session/projectors.ts b/packages/opencode/src/session/projectors.ts index b55f9dcc7a..7b3b0a7f21 100644 --- a/packages/opencode/src/session/projectors.ts +++ b/packages/opencode/src/session/projectors.ts @@ -62,7 +62,9 @@ export function toPartialRow(info: DeepPartial) { export default [ SyncEvent.project(Session.Event.Created, (db, data) => { - db.insert(SessionTable).values(Session.toRow(data.info as Session.Info)).run() + db.insert(SessionTable) + .values(Session.toRow(data.info as Session.Info)) + .run() }), SyncEvent.project(Session.Event.Updated, (db, data) => { diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index d9954d915f..55570d47dd 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -4174,34 +4174,30 @@ "parts": { "type": "array", "items": { - "anyOf": [ - { - "type": "object", - "properties": { - "id": { - "type": "string", - "pattern": "^prt.*" - }, - "type": { - "type": "string", - "const": "file" - }, - "mime": { - "type": "string" - }, - "filename": { - "type": "string" - }, - "url": { - "type": "string" - }, - "source": { - "$ref": "#/components/schemas/FilePartSource" - } - }, - "required": ["type", "mime", "url"] + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^prt.*" + }, + "type": { + "type": "string", + "const": "file" + }, + "mime": { + "type": "string" + }, + "filename": { + "type": "string" + }, + "url": { + "type": "string" + }, + "source": { + "$ref": "#/components/schemas/FilePartSource" } - ] + }, + "required": ["type", "mime", "url"] } } }, From eb7555d3c62a3b3cb61fc87bc124ee7309e9aaab Mon Sep 17 00:00:00 2001 From: opencode Date: Thu, 23 Apr 2026 15:56:49 +0000 Subject: [PATCH 33/92] sync release versions for v1.14.22 --- bun.lock | 32 +++++++++++++------------- packages/app/package.json | 2 +- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop-electron/package.json | 2 +- packages/desktop/package.json | 2 +- packages/enterprise/package.json | 2 +- packages/extensions/zed/extension.toml | 12 +++++----- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/shared/package.json | 2 +- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 19 files changed, 39 insertions(+), 39 deletions(-) diff --git a/bun.lock b/bun.lock index addecfff27..06a5cfdb4c 100644 --- a/bun.lock +++ b/bun.lock @@ -29,7 +29,7 @@ }, "packages/app": { "name": "@opencode-ai/app", - "version": "1.14.21", + "version": "1.14.22", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -83,7 +83,7 @@ }, "packages/console/app": { "name": "@opencode-ai/console-app", - "version": "1.14.21", + "version": "1.14.22", "dependencies": { "@cloudflare/vite-plugin": "1.15.2", "@ibm/plex": "6.4.1", @@ -117,7 +117,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.14.21", + "version": "1.14.22", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -144,7 +144,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.14.21", + "version": "1.14.22", "dependencies": { "@ai-sdk/anthropic": "3.0.64", "@ai-sdk/openai": "3.0.48", @@ -168,7 +168,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.14.21", + "version": "1.14.22", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -192,7 +192,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.14.21", + "version": "1.14.22", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -225,7 +225,7 @@ }, "packages/desktop-electron": { "name": "@opencode-ai/desktop-electron", - "version": "1.14.21", + "version": "1.14.22", "dependencies": { "drizzle-orm": "catalog:", "effect": "catalog:", @@ -269,7 +269,7 @@ }, "packages/enterprise": { "name": "@opencode-ai/enterprise", - "version": "1.14.21", + "version": "1.14.22", "dependencies": { "@opencode-ai/shared": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -298,7 +298,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.14.21", + "version": "1.14.22", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "catalog:", @@ -314,7 +314,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.14.21", + "version": "1.14.22", "bin": { "opencode": "./bin/opencode", }, @@ -459,7 +459,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.14.21", + "version": "1.14.22", "dependencies": { "@opencode-ai/sdk": "workspace:*", "effect": "catalog:", @@ -494,7 +494,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.14.21", + "version": "1.14.22", "dependencies": { "cross-spawn": "catalog:", }, @@ -509,7 +509,7 @@ }, "packages/shared": { "name": "@opencode-ai/shared", - "version": "1.14.21", + "version": "1.14.22", "bin": { "opencode": "./bin/opencode", }, @@ -533,7 +533,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.14.21", + "version": "1.14.22", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -568,7 +568,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.14.21", + "version": "1.14.22", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -617,7 +617,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.14.21", + "version": "1.14.22", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/app/package.json b/packages/app/package.json index 7572f0b228..0ab5e304a2 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "1.14.21", + "version": "1.14.22", "description": "", "type": "module", "exports": { diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 1182f17948..3d37527508 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-app", - "version": "1.14.21", + "version": "1.14.22", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/console/core/package.json b/packages/console/core/package.json index f79ef3ecb0..70d44b3820 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.14.21", + "version": "1.14.22", "private": true, "type": "module", "license": "MIT", diff --git a/packages/console/function/package.json b/packages/console/function/package.json index c3c549004d..55791a3072 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.14.21", + "version": "1.14.22", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index f4c59c1967..4966bf3e63 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.14.21", + "version": "1.14.22", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop-electron/package.json b/packages/desktop-electron/package.json index 3f5ca841b0..a528a9a3ac 100644 --- a/packages/desktop-electron/package.json +++ b/packages/desktop-electron/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop-electron", "private": true, - "version": "1.14.21", + "version": "1.14.22", "type": "module", "license": "MIT", "homepage": "https://opencode.ai", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 0e349f81c3..32b63fff13 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop", "private": true, - "version": "1.14.21", + "version": "1.14.22", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/enterprise/package.json b/packages/enterprise/package.json index 77b0ec2002..e4428f0cb2 100644 --- a/packages/enterprise/package.json +++ b/packages/enterprise/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/enterprise", - "version": "1.14.21", + "version": "1.14.22", "private": true, "type": "module", "license": "MIT", diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 5a9d2dc1ac..6449b8df65 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The open source coding agent." -version = "1.14.21" +version = "1.14.22" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/anomalyco/opencode" @@ -11,26 +11,26 @@ name = "OpenCode" icon = "./icons/opencode.svg" [agent_servers.opencode.targets.darwin-aarch64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.21/opencode-darwin-arm64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.22/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.21/opencode-darwin-x64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.22/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.21/opencode-linux-arm64.tar.gz" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.22/opencode-linux-arm64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.21/opencode-linux-x64.tar.gz" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.22/opencode-linux-x64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.21/opencode-windows-x64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.22/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index 925e458cf0..5b06d03685 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.14.21", + "version": "1.14.22", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index cd9c0f0a83..ea8724ceb8 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.14.21", + "version": "1.14.22", "name": "opencode", "type": "module", "license": "MIT", diff --git a/packages/plugin/package.json b/packages/plugin/package.json index d719010661..ee8210ec14 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.14.21", + "version": "1.14.22", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 3d07efef49..62a50b7434 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.14.21", + "version": "1.14.22", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/shared/package.json b/packages/shared/package.json index 117c12b981..48ae0fb78d 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.14.21", + "version": "1.14.22", "name": "@opencode-ai/shared", "type": "module", "license": "MIT", diff --git a/packages/slack/package.json b/packages/slack/package.json index 2eb380dc74..a3516932ab 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.14.21", + "version": "1.14.22", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/ui/package.json b/packages/ui/package.json index a15918dc85..ba0fb01494 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.14.21", + "version": "1.14.22", "type": "module", "license": "MIT", "exports": { diff --git a/packages/web/package.json b/packages/web/package.json index 9924f2e516..818cdf721e 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -2,7 +2,7 @@ "name": "@opencode-ai/web", "type": "module", "license": "MIT", - "version": "1.14.21", + "version": "1.14.22", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index a43348670b..e238b36702 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.14.21", + "version": "1.14.22", "publisher": "sst-dev", "repository": { "type": "git", From 9df7c78ebe051a3e71ec6aa27e38a4baa0bbb4bc Mon Sep 17 00:00:00 2001 From: Shoubhit Dash Date: Thu, 23 Apr 2026 21:28:54 +0530 Subject: [PATCH 34/92] fix(npm): respect npmrc for version lookups (#24016) --- packages/opencode/src/installation/index.ts | 19 +++-- packages/opencode/src/npm/index.ts | 56 ++++++++----- .../test/installation/installation.test.ts | 46 ++++++++-- packages/opencode/test/npm.test.ts | 84 +++++++++++++++++++ 4 files changed, 171 insertions(+), 34 deletions(-) diff --git a/packages/opencode/src/installation/index.ts b/packages/opencode/src/installation/index.ts index babde9dc47..e39b14b8f3 100644 --- a/packages/opencode/src/installation/index.ts +++ b/packages/opencode/src/installation/index.ts @@ -132,6 +132,15 @@ export const layer: Layer.Layer Effect.succeed({ code: ChildProcessSpawner.ExitCode(1), stdout: "", stderr: "" })), ) + const viewVersion = Effect.fnUntraced(function* (method: "npm" | "pnpm" | "bun", spec: string) { + const args = method === "bun" ? ["pm", "view", spec, "version", "--json"] : ["view", spec, "version", "--json"] + const result = yield* run([method, ...args]) + if (result.code !== 0 || !result.stdout.trim()) { + return yield* new UpgradeFailedError({ stderr: result.stderr || result.stdout || `Failed to resolve ${spec}` }) + } + return yield* Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.String))(result.stdout) + }) + const getBrewFormula = Effect.fnUntraced(function* () { const tapFormula = yield* text(["brew", "list", "--formula", "anomalyco/tap/opencode"]) if (tapFormula.includes("opencode")) return "anomalyco/tap/opencode" @@ -217,15 +226,7 @@ export const layer: Layer.Layer()("NpmInstallFailedError", { @@ -106,7 +108,36 @@ export const layer = Layer.effect( const global = yield* Global.Service const fs = yield* FileSystem.FileSystem const flock = yield* EffectFlock.Service + const spawner = yield* ChildProcessSpawner.ChildProcessSpawner const directory = (pkg: string) => path.join(global.cache, "packages", sanitize(pkg)) + const runView = Effect.fnUntraced( + function* (cmd: string[]) { + const handle = yield* spawner.spawn( + ChildProcess.make(cmd[0], cmd.slice(1), { + extendEnv: true, + }), + ) + const [stdout, stderr] = yield* Effect.all( + [Stream.mkString(Stream.decodeText(handle.stdout)), Stream.mkString(Stream.decodeText(handle.stderr))], + { concurrency: 2 }, + ) + const code = yield* handle.exitCode + if (code !== 0 || !stdout.trim()) { + return yield* Effect.fail(stderr || stdout || `Failed to run ${cmd.join(" ")}`) + } + return yield* Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.String))(stdout) + }, + Effect.scoped, + ) + const viewLatestVersion = Effect.fnUntraced(function* (pkg: string) { + return yield* runView(["npm", "view", pkg, "dist-tags.latest", "--json"]).pipe( + Effect.catch(() => + runView(["pnpm", "view", pkg, "dist-tags.latest", "--json"]).pipe( + Effect.catch(() => runView(["bun", "pm", "view", pkg, "dist-tags.latest", "--json"])), + ), + ), + ) + }) const reify = (input: { dir: string; add?: string[] }) => Effect.gen(function* () { yield* flock.acquire(`npm-install:${input.dir}`) @@ -143,29 +174,15 @@ export const layer = Layer.effect( ) const outdated = Effect.fn("Npm.outdated")(function* (pkg: string, cachedVersion: string) { - const response = yield* Effect.tryPromise({ - try: () => fetch(`https://registry.npmjs.org/${pkg}`), - catch: () => undefined, - }).pipe(Effect.orElseSucceed(() => undefined)) - - if (!response || !response.ok) { - return false - } - - const data = yield* Effect.tryPromise({ - try: () => response.json() as Promise<{ "dist-tags"?: { latest?: string } }>, - catch: () => undefined, - }).pipe(Effect.orElseSucceed(() => undefined)) - - const latestVersion = data?.["dist-tags"]?.latest - if (!latestVersion) { + const latestVersion = yield* viewLatestVersion(pkg).pipe(Effect.option) + if (Option.isNone(latestVersion)) { return false } const range = /[\s^~*xX<>|=]/.test(cachedVersion) - if (range) return !semver.satisfies(latestVersion, cachedVersion) + if (range) return !semver.satisfies(latestVersion.value, cachedVersion) - return semver.lt(cachedVersion, latestVersion) + return semver.lt(cachedVersion, latestVersion.value) }) const add = Effect.fn("Npm.add")(function* (pkg: string) { @@ -304,6 +321,7 @@ export const defaultLayer = layer.pipe( Layer.provide(AppFileSystem.layer), Layer.provide(Global.layer), Layer.provide(NodeFileSystem.layer), + Layer.provide(CrossSpawnSpawner.defaultLayer), ) const { runPromise } = makeRuntime(Service, defaultLayer) diff --git a/packages/opencode/test/installation/installation.test.ts b/packages/opencode/test/installation/installation.test.ts index 2b04c38585..0d3e92989d 100644 --- a/packages/opencode/test/installation/installation.test.ts +++ b/packages/opencode/test/installation/installation.test.ts @@ -3,6 +3,7 @@ import { Effect, Layer, Stream } from "effect" import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" import { Installation } from "../../src/installation" +import { InstallationChannel } from "../../src/installation/version" const encoder = new TextEncoder() @@ -68,11 +69,15 @@ describe("installation", () => { expect(result).toBe("4.0.0-beta.1") }) - test("reads npm registry versions", async () => { + test("reads npm versions via npm view", async () => { + const calls: string[][] = [] const layer = testLayer( - () => jsonResponse({ version: "1.5.0" }), + () => { + throw new Error("unexpected http request") + }, (cmd, args) => { - if (cmd === "npm" && args.includes("registry")) return "https://registry.npmjs.org\n" + calls.push([cmd, ...args]) + if (cmd === "npm" && args[0] === "view") return '"1.5.0"\n' return "" }, ) @@ -81,18 +86,47 @@ describe("installation", () => { Installation.Service.use((svc) => svc.latest("npm")).pipe(Effect.provide(layer)), ) expect(result).toBe("1.5.0") + expect(calls).toContainEqual(["npm", "view", `opencode-ai@${InstallationChannel}`, "version", "--json"]) }) - test("reads npm registry versions for bun method", async () => { + test("reads npm versions via bun pm view", async () => { + const calls: string[][] = [] const layer = testLayer( - () => jsonResponse({ version: "1.6.0" }), - () => "", + () => { + throw new Error("unexpected http request") + }, + (cmd, args) => { + calls.push([cmd, ...args]) + if (cmd === "bun" && args[0] === "pm") return '"1.6.0"\n' + return "" + }, ) const result = await Effect.runPromise( Installation.Service.use((svc) => svc.latest("bun")).pipe(Effect.provide(layer)), ) expect(result).toBe("1.6.0") + expect(calls).toContainEqual(["bun", "pm", "view", `opencode-ai@${InstallationChannel}`, "version", "--json"]) + }) + + test("reads npm versions via pnpm view", async () => { + const calls: string[][] = [] + const layer = testLayer( + () => { + throw new Error("unexpected http request") + }, + (cmd, args) => { + calls.push([cmd, ...args]) + if (cmd === "pnpm" && args[0] === "view") return '"1.7.0"\n' + return "" + }, + ) + + const result = await Effect.runPromise( + Installation.Service.use((svc) => svc.latest("pnpm")).pipe(Effect.provide(layer)), + ) + expect(result).toBe("1.7.0") + expect(calls).toContainEqual(["pnpm", "view", `opencode-ai@${InstallationChannel}`, "version", "--json"]) }) test("reads scoop manifest versions", async () => { diff --git a/packages/opencode/test/npm.test.ts b/packages/opencode/test/npm.test.ts index a8ec92c2a7..b7680bb70d 100644 --- a/packages/opencode/test/npm.test.ts +++ b/packages/opencode/test/npm.test.ts @@ -1,10 +1,50 @@ import fs from "fs/promises" import path from "path" import { describe, expect, test } from "bun:test" +import { Effect, Layer, Stream } from "effect" +import { NodeFileSystem } from "@effect/platform-node" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" +import { Global } from "@opencode-ai/shared/global" +import { EffectFlock } from "@opencode-ai/shared/util/effect-flock" +import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" import { Npm } from "../src/npm" import { tmpdir } from "./fixture/fixture" const win = process.platform === "win32" +const encoder = new TextEncoder() +function mockSpawner(handler: (cmd: string, args: readonly string[]) => string = () => "") { + const spawner = ChildProcessSpawner.make((command) => { + const std = ChildProcess.isStandardCommand(command) ? command : undefined + const output = handler(std?.command ?? "", std?.args ?? []) + return Effect.succeed( + ChildProcessSpawner.makeHandle({ + pid: ChildProcessSpawner.ProcessId(0), + exitCode: Effect.succeed(ChildProcessSpawner.ExitCode(0)), + isRunning: Effect.succeed(false), + kill: () => Effect.void, + stdin: { [Symbol.for("effect/Sink/TypeId")]: Symbol.for("effect/Sink/TypeId") } as any, + stdout: output ? Stream.make(encoder.encode(output)) : Stream.empty, + stderr: Stream.empty, + all: Stream.empty, + getInputFd: () => ({ [Symbol.for("effect/Sink/TypeId")]: Symbol.for("effect/Sink/TypeId") }) as any, + getOutputFd: () => Stream.empty, + unref: Effect.succeed(Effect.void), + }), + ) + }) + return Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner) +} + +function testLayer(spawnHandler?: (cmd: string, args: readonly string[]) => string) { + return Npm.layer.pipe( + Layer.provide(mockSpawner(spawnHandler)), + Layer.provide(EffectFlock.layer), + Layer.provide(AppFileSystem.layer), + Layer.provide(Global.layer), + Layer.provide(NodeFileSystem.layer), + ) +} + const writePackage = (dir: string, pkg: Record) => Bun.write( path.join(dir, "package.json"), @@ -53,3 +93,47 @@ describe("Npm.install", () => { await expect(fs.stat(path.join(tmp.path, "node_modules", "dev-pkg"))).rejects.toThrow() }) }) + +describe("Npm.outdated", () => { + test("checks latest via npm view", async () => { + const calls: string[][] = [] + const layer = testLayer((cmd, args) => { + calls.push([cmd, ...args]) + if (cmd === "npm" && args[0] === "view") return '"2.0.0"\n' + return "" + }) + + const result = await Effect.runPromise(Npm.Service.use((svc) => svc.outdated("example", "1.0.0")).pipe(Effect.provide(layer))) + + expect(result).toBe(true) + expect(calls).toContainEqual(["npm", "view", "example", "dist-tags.latest", "--json"]) + }) + + test("keeps range comparison behavior", async () => { + const layer = testLayer((cmd, args) => { + if (cmd === "npm" && args[0] === "view") return '"2.3.0"\n' + return "" + }) + + const result = await Effect.runPromise( + Npm.Service.use((svc) => svc.outdated("example", "^2.0.0")).pipe(Effect.provide(layer)), + ) + + expect(result).toBe(false) + }) + + test("falls back when npm view is unavailable", async () => { + const calls: string[][] = [] + const layer = testLayer((cmd, args) => { + calls.push([cmd, ...args]) + if (cmd === "pnpm" && args[0] === "view") return '"2.0.0"\n' + return "" + }) + + const result = await Effect.runPromise(Npm.Service.use((svc) => svc.outdated("example", "1.0.0")).pipe(Effect.provide(layer))) + + expect(result).toBe(true) + expect(calls).toContainEqual(["npm", "view", "example", "dist-tags.latest", "--json"]) + expect(calls).toContainEqual(["pnpm", "view", "example", "dist-tags.latest", "--json"]) + }) +}) From 353532b1c16bd5677efd2c352f502178f0c5094c Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Thu, 23 Apr 2026 16:00:01 +0000 Subject: [PATCH 35/92] chore: generate --- packages/opencode/src/installation/index.ts | 4 ++- packages/opencode/src/npm/index.ts | 35 ++++++++++----------- packages/opencode/test/npm.test.ts | 8 +++-- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/packages/opencode/src/installation/index.ts b/packages/opencode/src/installation/index.ts index e39b14b8f3..787f9ea8c5 100644 --- a/packages/opencode/src/installation/index.ts +++ b/packages/opencode/src/installation/index.ts @@ -136,7 +136,9 @@ export const layer: Layer.Layer path.join(global.cache, "packages", sanitize(pkg)) - const runView = Effect.fnUntraced( - function* (cmd: string[]) { - const handle = yield* spawner.spawn( - ChildProcess.make(cmd[0], cmd.slice(1), { - extendEnv: true, - }), - ) - const [stdout, stderr] = yield* Effect.all( - [Stream.mkString(Stream.decodeText(handle.stdout)), Stream.mkString(Stream.decodeText(handle.stderr))], - { concurrency: 2 }, - ) - const code = yield* handle.exitCode - if (code !== 0 || !stdout.trim()) { - return yield* Effect.fail(stderr || stdout || `Failed to run ${cmd.join(" ")}`) - } - return yield* Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.String))(stdout) - }, - Effect.scoped, - ) + const runView = Effect.fnUntraced(function* (cmd: string[]) { + const handle = yield* spawner.spawn( + ChildProcess.make(cmd[0], cmd.slice(1), { + extendEnv: true, + }), + ) + const [stdout, stderr] = yield* Effect.all( + [Stream.mkString(Stream.decodeText(handle.stdout)), Stream.mkString(Stream.decodeText(handle.stderr))], + { concurrency: 2 }, + ) + const code = yield* handle.exitCode + if (code !== 0 || !stdout.trim()) { + return yield* Effect.fail(stderr || stdout || `Failed to run ${cmd.join(" ")}`) + } + return yield* Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.String))(stdout) + }, Effect.scoped) const viewLatestVersion = Effect.fnUntraced(function* (pkg: string) { return yield* runView(["npm", "view", pkg, "dist-tags.latest", "--json"]).pipe( Effect.catch(() => diff --git a/packages/opencode/test/npm.test.ts b/packages/opencode/test/npm.test.ts index b7680bb70d..b27d668c8c 100644 --- a/packages/opencode/test/npm.test.ts +++ b/packages/opencode/test/npm.test.ts @@ -103,7 +103,9 @@ describe("Npm.outdated", () => { return "" }) - const result = await Effect.runPromise(Npm.Service.use((svc) => svc.outdated("example", "1.0.0")).pipe(Effect.provide(layer))) + const result = await Effect.runPromise( + Npm.Service.use((svc) => svc.outdated("example", "1.0.0")).pipe(Effect.provide(layer)), + ) expect(result).toBe(true) expect(calls).toContainEqual(["npm", "view", "example", "dist-tags.latest", "--json"]) @@ -130,7 +132,9 @@ describe("Npm.outdated", () => { return "" }) - const result = await Effect.runPromise(Npm.Service.use((svc) => svc.outdated("example", "1.0.0")).pipe(Effect.provide(layer))) + const result = await Effect.runPromise( + Npm.Service.use((svc) => svc.outdated("example", "1.0.0")).pipe(Effect.provide(layer)), + ) expect(result).toBe(true) expect(calls).toContainEqual(["npm", "view", "example", "dist-tags.latest", "--json"]) From c50d65b4d6b956cad44663d9d31b7b5eb01c8e57 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 23 Apr 2026 12:43:08 -0400 Subject: [PATCH 36/92] refactor(sync): make session events schema-first (#24019) --- packages/opencode/src/bus/index.ts | 24 ++++++-- packages/opencode/src/server/projectors.ts | 3 +- packages/opencode/src/session/message-v2.ts | 44 ++++++++------ packages/opencode/src/session/projectors.ts | 2 +- packages/opencode/src/session/session.ts | 65 ++++++++++++++------- packages/opencode/src/share/share-next.ts | 2 +- packages/opencode/src/sync/index.ts | 44 ++++++++++---- packages/opencode/test/sync/index.test.ts | 6 +- packages/sdk/js/src/v2/gen/types.gen.ts | 32 +++++----- 9 files changed, 141 insertions(+), 81 deletions(-) diff --git a/packages/opencode/src/bus/index.ts b/packages/opencode/src/bus/index.ts index 8a9579b599..a2f9f5ccba 100644 --- a/packages/opencode/src/bus/index.ts +++ b/packages/opencode/src/bus/index.ts @@ -1,5 +1,5 @@ import z from "zod" -import { Effect, Exit, Layer, PubSub, Scope, Context, Stream } from "effect" +import { Effect, Exit, Layer, PubSub, Scope, Context, Stream, Schema as EffectSchema, Types } from "effect" import { EffectBridge } from "@/effect" import { Log } from "../util" import { BusEvent } from "./bus-event" @@ -9,6 +9,12 @@ import { makeRuntime } from "@/effect/run-service" const log = Log.create({ service: "bus" }) +type BusProperties = D extends { + effectProperties: infer Properties extends EffectSchema.Top +} + ? Types.DeepMutable> + : z.infer + export const InstanceDisposed = BusEvent.define( "server.instance.disposed", z.object({ @@ -18,7 +24,7 @@ export const InstanceDisposed = BusEvent.define( type Payload = { type: D["type"] - properties: z.infer + properties: BusProperties } type State = { @@ -29,7 +35,7 @@ type State = { export interface Interface { readonly publish: ( def: D, - properties: z.output, + properties: BusProperties, ) => Effect.Effect readonly subscribe: (def: D) => Stream.Stream> readonly subscribeAll: () => Stream.Stream @@ -79,7 +85,10 @@ export const layer = Layer.effect( }) } - function publish(def: D, properties: z.output) { + function publish( + def: D, + properties: BusProperties, + ) { return Effect.gen(function* () { const s = yield* InstanceState.get(state) const payload: Payload = { type: def.type, properties } @@ -175,13 +184,16 @@ const { runPromise, runSync } = makeRuntime(Service, layer) // runSync is safe here because the subscribe chain (InstanceState.get, PubSub.subscribe, // Scope.make, Effect.forkScoped) is entirely synchronous. If any step becomes async, this will throw. -export async function publish(def: D, properties: z.output) { +export async function publish( + def: D, + properties: BusProperties, +) { return runPromise((svc) => svc.publish(def, properties)) } export function subscribe( def: D, - callback: (event: { type: D["type"]; properties: z.infer }) => unknown, + callback: (event: Payload) => unknown, ) { return runSync((svc) => svc.subscribeCallback(def, callback)) } diff --git a/packages/opencode/src/server/projectors.ts b/packages/opencode/src/server/projectors.ts index cfecce5265..18c273d587 100644 --- a/packages/opencode/src/server/projectors.ts +++ b/packages/opencode/src/server/projectors.ts @@ -1,4 +1,3 @@ -import z from "zod" import sessionProjectors from "../session/projectors" import { SyncEvent } from "@/sync" import { Session } from "@/session" @@ -10,7 +9,7 @@ export function initProjectors() { projectors: sessionProjectors, convertEvent: (type, data) => { if (type === "session.updated") { - const id = (data as z.infer).sessionID + const id = (data as SyncEvent.Event["data"]).sessionID const row = Database.use((db) => db.select().from(SessionTable).where(eq(SessionTable.id, id)).get()) if (!row) return data diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index 980dd4da84..a4b25d95ea 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -576,34 +576,46 @@ export const Info = Object.assign(_Info, { }) export type Info = User | Assistant +const UpdatedEventSchema = Schema.Struct({ + sessionID: SessionID, + info: _Info, +}) + +const RemovedEventSchema = Schema.Struct({ + sessionID: SessionID, + messageID: MessageID, +}) + +const PartUpdatedEventSchema = Schema.Struct({ + sessionID: SessionID, + part: _Part, + time: Schema.Number, +}) + +const PartRemovedEventSchema = Schema.Struct({ + sessionID: SessionID, + messageID: MessageID, + partID: PartID, +}) + export const Event = { Updated: SyncEvent.define({ type: "message.updated", version: 1, aggregate: "sessionID", - schema: z.object({ - sessionID: SessionID.zod, - info: Info.zod, - }), + schema: UpdatedEventSchema, }), Removed: SyncEvent.define({ type: "message.removed", version: 1, aggregate: "sessionID", - schema: z.object({ - sessionID: SessionID.zod, - messageID: MessageID.zod, - }), + schema: RemovedEventSchema, }), PartUpdated: SyncEvent.define({ type: "message.part.updated", version: 1, aggregate: "sessionID", - schema: z.object({ - sessionID: SessionID.zod, - part: Part.zod, - time: z.number(), - }), + schema: PartUpdatedEventSchema, }), PartDelta: BusEvent.define( "message.part.delta", @@ -619,11 +631,7 @@ export const Event = { type: "message.part.removed", version: 1, aggregate: "sessionID", - schema: z.object({ - sessionID: SessionID.zod, - messageID: MessageID.zod, - partID: PartID.zod, - }), + schema: PartRemovedEventSchema, }), } diff --git a/packages/opencode/src/session/projectors.ts b/packages/opencode/src/session/projectors.ts index 7b3b0a7f21..3a5fd0d8c9 100644 --- a/packages/opencode/src/session/projectors.ts +++ b/packages/opencode/src/session/projectors.ts @@ -71,7 +71,7 @@ export default [ const info = data.info const row = db .update(SessionTable) - .set(toPartialRow(info)) + .set(toPartialRow(info as Session.Patch)) .where(eq(SessionTable.id, data.sessionID)) .returning() .get() diff --git a/packages/opencode/src/session/session.ts b/packages/opencode/src/session/session.ts index d2bdbccb7d..1e046fdf79 100644 --- a/packages/opencode/src/session/session.ts +++ b/packages/opencode/src/session/session.ts @@ -15,7 +15,6 @@ import { PartTable, SessionTable } from "./session.sql" import { ProjectTable } from "../project/project.sql" import { Storage } from "@/storage" import { Log } from "../util" -import { updateSchema } from "../util/update-schema" import { MessageV2 } from "./message-v2" import { Instance } from "../project/instance" import { InstanceState } from "@/effect" @@ -28,7 +27,7 @@ import type { Provider } from "@/provider" import { Permission } from "@/permission" import { Global } from "@/global" import { Effect, Layer, Option, Context, Schema, Types } from "effect" -import { zod, zodObject } from "@/util/effect-zod" +import { zod } from "@/util/effect-zod" import { withStatics } from "@/util/schema" const log = Log.create({ service: "session" }) @@ -215,40 +214,62 @@ export const MessagesInput = Schema.Struct({ limit: Schema.optional(Schema.Number), }).pipe(withStatics((s) => ({ zod: zod(s) }))) +const CreatedEventSchema = Schema.Struct({ + sessionID: SessionID, + info: Info, +}) + +const UpdatedShare = Schema.Struct({ + url: Schema.optional(Schema.NullOr(Schema.String)), +}) + +const UpdatedTime = Schema.Struct({ + created: Schema.optional(Schema.NullOr(Schema.Number)), + updated: Schema.optional(Schema.NullOr(Schema.Number)), + compacting: Schema.optional(Schema.NullOr(Schema.Number)), + archived: Schema.optional(Schema.NullOr(Schema.Number)), +}) + +const UpdatedInfo = Schema.Struct({ + id: Schema.optional(Schema.NullOr(SessionID)), + slug: Schema.optional(Schema.NullOr(Schema.String)), + projectID: Schema.optional(Schema.NullOr(ProjectID)), + workspaceID: Schema.optional(Schema.NullOr(WorkspaceID)), + directory: Schema.optional(Schema.NullOr(Schema.String)), + parentID: Schema.optional(Schema.NullOr(SessionID)), + summary: Schema.optional(Schema.NullOr(Summary)), + share: Schema.optional(UpdatedShare), + title: Schema.optional(Schema.NullOr(Schema.String)), + version: Schema.optional(Schema.NullOr(Schema.String)), + time: Schema.optional(UpdatedTime), + permission: Schema.optional(Schema.NullOr(Permission.Ruleset)), + revert: Schema.optional(Schema.NullOr(Revert)), +}) + +const UpdatedEventSchema = Schema.Struct({ + sessionID: SessionID, + info: UpdatedInfo, +}) + export const Event = { Created: SyncEvent.define({ type: "session.created", version: 1, aggregate: "sessionID", - schema: z.object({ - sessionID: SessionID.zod, - info: Info.zod, - }), + schema: CreatedEventSchema, }), Updated: SyncEvent.define({ type: "session.updated", version: 1, aggregate: "sessionID", - schema: z.object({ - sessionID: SessionID.zod, - info: updateSchema(zodObject(Info)).extend({ - share: updateSchema(zodObject(Share)).optional(), - time: updateSchema(zodObject(Time)).optional(), - }), - }), - busSchema: z.object({ - sessionID: SessionID.zod, - info: Info.zod, - }), + schema: UpdatedEventSchema, + busSchema: CreatedEventSchema, }), Deleted: SyncEvent.define({ type: "session.deleted", version: 1, aggregate: "sessionID", - schema: z.object({ - sessionID: SessionID.zod, - info: Info.zod, - }), + schema: CreatedEventSchema, }), Diff: BusEvent.define( "session.diff", @@ -394,7 +415,7 @@ export interface Interface { export class Service extends Context.Service()("@opencode/Session") {} -type Patch = z.infer["info"] +export type Patch = Types.DeepMutable["data"]["info"]> const db = (fn: (d: Parameters[0] extends (trx: infer D) => any ? D : never) => T) => Effect.sync(() => Database.use(fn)) diff --git a/packages/opencode/src/share/share-next.ts b/packages/opencode/src/share/share-next.ts index 2622f4f7f0..f26a085c22 100644 --- a/packages/opencode/src/share/share-next.ts +++ b/packages/opencode/src/share/share-next.ts @@ -181,7 +181,7 @@ export const layer = Layer.effect( yield* watch(Session.Event.Updated, (evt) => Effect.gen(function* () { - const info = yield* session.get(evt.properties.sessionID) + const info = evt.properties.info yield* sync(info.id, [{ type: "session", data: info }]) }), ) diff --git a/packages/opencode/src/sync/index.ts b/packages/opencode/src/sync/index.ts index 125d8c9550..5a4078402d 100644 --- a/packages/opencode/src/sync/index.ts +++ b/packages/opencode/src/sync/index.ts @@ -1,5 +1,4 @@ import z from "zod" -import type { ZodObject } from "zod" import { Database, eq } from "@/storage" import { GlobalBus } from "@/bus/global" import { Bus as ProjectBus } from "@/bus" @@ -9,11 +8,16 @@ import { EventSequenceTable, EventTable } from "./event.sql" import { WorkspaceContext } from "@/control-plane/workspace-context" import { EventID } from "./schema" import { Flag } from "@/flag/flag" +import { Schema as EffectSchema, Types } from "effect" +import { zodObject } from "@/util/effect-zod" +import { isRecord } from "@/util/record" -export type Definition = { +export type Definition = { type: string version: number aggregate: string + effectSchema: Schema + effectProperties: BusSchema schema: z.ZodObject // This is temporary and only exists for compatibility with bus @@ -25,9 +29,13 @@ export type Event = { id: string seq: number aggregateID: string - data: z.infer + data: Types.DeepMutable> } +export type Properties = Types.DeepMutable< + EffectSchema.Schema.Type +> + export type SerializedEvent = Event & { type: string } type ProjectorFunc = (db: Database.TxOrDb, data: unknown) => void @@ -36,7 +44,12 @@ export const registry = new Map() let projectors: Map | undefined const versions = new Map() let frozen = false -let convertEvent: (type: string, event: Event["data"]) => Promise> | Record +let convertEvent: (type: string, event: Event["data"]) => Promise | unknown + +function asRecord(input: unknown) { + if (isRecord(input)) return input + throw new Error(`SyncEvent.convertEvent must return an object, got: ${JSON.stringify(input)}`) +} export function reset() { frozen = false @@ -54,7 +67,7 @@ export function init(input: { projectors: Array<[Definition, ProjectorFunc]>; co for (let [type, version] of versions.entries()) { let def = registry.get(versionedType(type, version))! - BusEvent.define(def.type, def.properties || def.schema) + BusEvent.define(def.type, def.properties) } // Freeze the system so it clearly errors if events are defined @@ -72,19 +85,26 @@ export function versionedType(type: string, version?: number) { export function define< Type extends string, Agg extends string, - Schema extends ZodObject>>, - BusSchema extends ZodObject = Schema, ->(input: { type: Type; version: number; aggregate: Agg; schema: Schema; busSchema?: BusSchema }) { + Schema extends EffectSchema.Top, + BusSchema extends EffectSchema.Top = Schema, +>(input: { type: Type; version: number; aggregate: Agg; schema: Schema; busSchema?: BusSchema }): Definition< + Schema, + BusSchema +> { if (frozen) { throw new Error("Error defining sync event: sync system has been frozen") } + const effectProperties = (input.busSchema ?? input.schema) as BusSchema + const def = { type: input.type, version: input.version, aggregate: input.aggregate, - schema: input.schema, - properties: input.busSchema ? input.busSchema : input.schema, + effectSchema: input.schema, + effectProperties, + schema: zodObject(input.schema), + properties: zodObject(effectProperties), } versions.set(def.type, Math.max(def.version, versions.get(def.type) || 0)) @@ -143,10 +163,10 @@ function process(def: Def, event: Event, options: { const result = convertEvent(def.type, event.data) if (result instanceof Promise) { void result.then((data) => { - void ProjectBus.publish({ type: def.type, properties: def.schema }, data) + void ProjectBus.publish({ type: def.type, properties: def.properties }, asRecord(data)) }) } else { - void ProjectBus.publish({ type: def.type, properties: def.schema }, result) + void ProjectBus.publish({ type: def.type, properties: def.properties }, asRecord(result)) } GlobalBus.emit("event", { diff --git a/packages/opencode/test/sync/index.test.ts b/packages/opencode/test/sync/index.test.ts index 866bcaa31a..d50f0d7c94 100644 --- a/packages/opencode/test/sync/index.test.ts +++ b/packages/opencode/test/sync/index.test.ts @@ -1,6 +1,6 @@ import { describe, test, expect, beforeEach, afterEach, afterAll } from "bun:test" import { tmpdir } from "../fixture/fixture" -import z from "zod" +import { Schema } from "effect" import { Bus } from "../../src/bus" import { Instance } from "../../src/project/instance" import { SyncEvent } from "../../src/sync" @@ -43,13 +43,13 @@ describe("SyncEvent", () => { type: "item.created", version: 1, aggregate: "id", - schema: z.object({ id: z.string(), name: z.string() }), + schema: Schema.Struct({ id: Schema.String, name: Schema.String }), }) const Sent = SyncEvent.define({ type: "item.sent", version: 1, aggregate: "item_id", - schema: z.object({ item_id: z.string(), to: z.string() }), + schema: Schema.Struct({ item_id: Schema.String, to: Schema.String }), }) SyncEvent.init({ diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 1fcab2eda6..d28ce25794 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -1058,31 +1058,31 @@ export type SyncEventSessionUpdated = { data: { sessionID: string info: { - id: string | null - slug: string | null - projectID: string | null - workspaceID: string | null - directory: string | null - parentID: string | null - summary: { + id?: string | null + slug?: string | null + projectID?: string | null + workspaceID?: string | null + directory?: string | null + parentID?: string | null + summary?: { additions: number deletions: number files: number diffs?: Array } | null share?: { - url: string | null + url?: string | null } - title: string | null - version: string | null + title?: string | null + version?: string | null time?: { - created: number | null - updated: number | null - compacting: number | null - archived: number | null + created?: number | null + updated?: number | null + compacting?: number | null + archived?: number | null } - permission: PermissionRuleset | null - revert: { + permission?: PermissionRuleset | null + revert?: { messageID: string partID?: string snapshot?: string From aed03078f88af5c28035a28b6edbbf10228a49ed Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Thu, 23 Apr 2026 16:44:32 +0000 Subject: [PATCH 37/92] chore: generate --- packages/opencode/src/bus/index.ts | 20 ++++---------------- packages/opencode/src/sync/index.ts | 16 +++++++++++----- packages/sdk/openapi.json | 21 +++------------------ 3 files changed, 18 insertions(+), 39 deletions(-) diff --git a/packages/opencode/src/bus/index.ts b/packages/opencode/src/bus/index.ts index a2f9f5ccba..9183ff72a4 100644 --- a/packages/opencode/src/bus/index.ts +++ b/packages/opencode/src/bus/index.ts @@ -33,10 +33,7 @@ type State = { } export interface Interface { - readonly publish: ( - def: D, - properties: BusProperties, - ) => Effect.Effect + readonly publish: (def: D, properties: BusProperties) => Effect.Effect readonly subscribe: (def: D) => Stream.Stream> readonly subscribeAll: () => Stream.Stream readonly subscribeCallback: ( @@ -85,10 +82,7 @@ export const layer = Layer.effect( }) } - function publish( - def: D, - properties: BusProperties, - ) { + function publish(def: D, properties: BusProperties) { return Effect.gen(function* () { const s = yield* InstanceState.get(state) const payload: Payload = { type: def.type, properties } @@ -184,17 +178,11 @@ const { runPromise, runSync } = makeRuntime(Service, layer) // runSync is safe here because the subscribe chain (InstanceState.get, PubSub.subscribe, // Scope.make, Effect.forkScoped) is entirely synchronous. If any step becomes async, this will throw. -export async function publish( - def: D, - properties: BusProperties, -) { +export async function publish(def: D, properties: BusProperties) { return runPromise((svc) => svc.publish(def, properties)) } -export function subscribe( - def: D, - callback: (event: Payload) => unknown, -) { +export function subscribe(def: D, callback: (event: Payload) => unknown) { return runSync((svc) => svc.subscribeCallback(def, callback)) } diff --git a/packages/opencode/src/sync/index.ts b/packages/opencode/src/sync/index.ts index 5a4078402d..482ad4fbb6 100644 --- a/packages/opencode/src/sync/index.ts +++ b/packages/opencode/src/sync/index.ts @@ -12,7 +12,10 @@ import { Schema as EffectSchema, Types } from "effect" import { zodObject } from "@/util/effect-zod" import { isRecord } from "@/util/record" -export type Definition = { +export type Definition< + Schema extends EffectSchema.Top = EffectSchema.Top, + BusSchema extends EffectSchema.Top = Schema, +> = { type: string version: number aggregate: string @@ -87,10 +90,13 @@ export function define< Agg extends string, Schema extends EffectSchema.Top, BusSchema extends EffectSchema.Top = Schema, ->(input: { type: Type; version: number; aggregate: Agg; schema: Schema; busSchema?: BusSchema }): Definition< - Schema, - BusSchema -> { +>(input: { + type: Type + version: number + aggregate: Agg + schema: Schema + busSchema?: BusSchema +}): Definition { if (frozen) { throw new Error("Error defining sync event: sync system has been frozen") } diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 55570d47dd..e54648e198 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -10570,8 +10570,7 @@ } ] } - }, - "required": ["url"] + } }, "title": { "anyOf": [ @@ -10636,8 +10635,7 @@ } ] } - }, - "required": ["created", "updated", "compacting", "archived"] + } }, "permission": { "anyOf": [ @@ -10676,20 +10674,7 @@ } ] } - }, - "required": [ - "id", - "slug", - "projectID", - "workspaceID", - "directory", - "parentID", - "summary", - "title", - "version", - "permission", - "revert" - ] + } } }, "required": ["sessionID", "info"] From 8b2f8355b22414a768c4a594d7a7101a4f72b00f Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 23 Apr 2026 12:54:46 -0400 Subject: [PATCH 38/92] docs(schema): mark sync/index.ts migrated with compat-bridge note (#24024) --- packages/opencode/specs/effect/schema.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/opencode/specs/effect/schema.md b/packages/opencode/specs/effect/schema.md index 3f2c3b4c96..0abdd9ed66 100644 --- a/packages/opencode/specs/effect/schema.md +++ b/packages/opencode/specs/effect/schema.md @@ -147,6 +147,17 @@ import `z` do so only for local `ZodOverride` bridges or for `z.ZodType` type annotations — the `export const ` values are all Effect Schema at source. +A file is considered "done" when: + +- its exported schema values (`Info`, `Input`, `Event`, `Definition`, etc.) + are authored as Effect Schema +- any remaining zod is either a derived compat bridge (via `zod()` / + `zodObject()`), a `z.ZodType` type annotation, or a documented + `ZodOverride` escape hatch — never a hand-written parallel source of truth + +Files that meet this bar but still carry a compat bridge are checked off +with an inline note describing the bridge and what unblocks its removal. + - [x] skills, formatter, console-state, mcp, lsp, permission (leaves), model-id, command, plugin, provider - [x] server, layout - [x] keybinds @@ -365,7 +376,7 @@ piecewise. - [ ] `src/snapshot/index.ts` - [ ] `src/storage/db.ts` - [ ] `src/storage/storage.ts` -- [ ] `src/sync/index.ts` +- [x] `src/sync/index.ts` — public API (`SyncEvent.define`) is Schema-first; still stores derived zod `schema`/`properties` on each `Definition` as a compat bridge for `BusEvent` until `bus/bus-event.ts` migrates - [ ] `src/util/fn.ts` - [ ] `src/util/log.ts` - [ ] `src/util/update-schema.ts` From 1e439b8226a66dcec0d65751f5cdb50a2b7bc979 Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 23 Apr 2026 13:13:26 -0400 Subject: [PATCH 39/92] sync --- packages/console/app/src/routes/zen/util/handler.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/console/app/src/routes/zen/util/handler.ts b/packages/console/app/src/routes/zen/util/handler.ts index d9dc450012..87d4a4d0ab 100644 --- a/packages/console/app/src/routes/zen/util/handler.ts +++ b/packages/console/app/src/routes/zen/util/handler.ts @@ -187,6 +187,8 @@ export async function handler( // Try another provider => stop retrying if using fallback provider if ( res.status !== 200 && + // ie. 400 error is usually provider error like malformed request + res.status !== 400 && // ie. openai 404 error: Item with id 'msg_0ead8b004a3b165d0069436a6b6834819896da85b63b196a3f' not found. res.status !== 404 && // ie. cannot change codex model providers mid-session @@ -226,7 +228,7 @@ export async function handler( logger.debug("STATUS: " + res.status + " " + res.statusText) // Handle non-streaming response - if (!isStream || res.status === 429) { + if (!isStream || [400, 404, 429].includes(res.status)) { const json = await res.json() await rateLimiter?.track() if (json.usage) { @@ -238,6 +240,9 @@ export async function handler( await reload(billingSource, authInfo, costInfo) json.cost = calculateOccurredCost(billingSource, costInfo) } + if (res.status === 400) { + logger.metric({ "error.response": JSON.stringify(json) }) + } if (json.error?.message) { json.error.message = `Error from provider${providerInfo.displayName ? ` (${providerInfo.displayName})` : ""}: ${json.error.message}` } @@ -393,7 +398,7 @@ export async function handler( type: "error", error: { type: "error", - message: error.message, + message: "Internal server error", }, }), { status: 500 }, From 93940a1859530b8fe46df376e7d7ba74fcd3e0d1 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 23 Apr 2026 13:17:33 -0400 Subject: [PATCH 40/92] refactor(provider): migrate provider domain to Effect Schema (#24027) --- packages/opencode/specs/effect/schema.md | 6 +- packages/opencode/src/provider/auth.ts | 23 ++-- packages/opencode/src/provider/models.ts | 150 ++++++++++----------- packages/opencode/src/provider/provider.ts | 27 ++-- 4 files changed, 93 insertions(+), 113 deletions(-) diff --git a/packages/opencode/specs/effect/schema.md b/packages/opencode/specs/effect/schema.md index 0abdd9ed66..0d451f4a99 100644 --- a/packages/opencode/specs/effect/schema.md +++ b/packages/opencode/specs/effect/schema.md @@ -274,9 +274,9 @@ Possible later tightening after the Schema-first migration is stable: ### Provider domain -- [ ] `src/provider/auth.ts` -- [ ] `src/provider/models.ts` -- [ ] `src/provider/provider.ts` +- [x] `src/provider/auth.ts` +- [x] `src/provider/models.ts` +- [x] `src/provider/provider.ts` ### Tool schemas diff --git a/packages/opencode/src/provider/auth.ts b/packages/opencode/src/provider/auth.ts index 5d8b2765de..0b4ac995a8 100644 --- a/packages/opencode/src/provider/auth.ts +++ b/packages/opencode/src/provider/auth.ts @@ -1,13 +1,12 @@ import type { AuthOAuthResult, Hooks } from "@opencode-ai/plugin" -import { NamedError } from "@opencode-ai/shared/util/error" import { Auth } from "@/auth" import { InstanceState } from "@/effect" import { zod } from "@/util/effect-zod" +import { namedSchemaError } from "@/util/named-schema-error" import { withStatics } from "@/util/schema" import { Plugin } from "../plugin" import { ProviderID } from "./schema" import { Array as Arr, Effect, Layer, Record, Result, Context, Schema } from "effect" -import z from "zod" const When = Schema.Struct({ key: Schema.String, @@ -70,22 +69,16 @@ export const CallbackInput = Schema.Struct({ }).pipe(withStatics((s) => ({ zod: zod(s) }))) export type CallbackInput = Schema.Schema.Type -export const OauthMissing = NamedError.create("ProviderAuthOauthMissing", z.object({ providerID: ProviderID.zod })) +export const OauthMissing = namedSchemaError("ProviderAuthOauthMissing", { providerID: ProviderID }) -export const OauthCodeMissing = NamedError.create( - "ProviderAuthOauthCodeMissing", - z.object({ providerID: ProviderID.zod }), -) +export const OauthCodeMissing = namedSchemaError("ProviderAuthOauthCodeMissing", { providerID: ProviderID }) -export const OauthCallbackFailed = NamedError.create("ProviderAuthOauthCallbackFailed", z.object({})) +export const OauthCallbackFailed = namedSchemaError("ProviderAuthOauthCallbackFailed", {}) -export const ValidationFailed = NamedError.create( - "ProviderAuthValidationFailed", - z.object({ - field: z.string(), - message: z.string(), - }), -) +export const ValidationFailed = namedSchemaError("ProviderAuthValidationFailed", { + field: Schema.String, + message: Schema.String, +}) export type Error = | Auth.AuthError diff --git a/packages/opencode/src/provider/models.ts b/packages/opencode/src/provider/models.ts index 2924666c0e..36c4d8c23c 100644 --- a/packages/opencode/src/provider/models.ts +++ b/packages/opencode/src/provider/models.ts @@ -1,7 +1,7 @@ import { Global } from "../global" import { Log } from "../util" import path from "path" -import z from "zod" +import { Schema } from "effect" import { Installation } from "../installation" import { Flag } from "../flag/flag" import { lazy } from "@/util/lazy" @@ -21,91 +21,85 @@ const filepath = path.join( ) const ttl = 5 * 60 * 1000 -type JsonValue = string | number | boolean | null | { [key: string]: JsonValue } | JsonValue[] - -const JsonValue: z.ZodType = z.lazy(() => - z.union([z.string(), z.number(), z.boolean(), z.null(), z.array(JsonValue), z.record(z.string(), JsonValue)]), -) - -const Cost = z.object({ - input: z.number(), - output: z.number(), - cache_read: z.number().optional(), - cache_write: z.number().optional(), - context_over_200k: z - .object({ - input: z.number(), - output: z.number(), - cache_read: z.number().optional(), - cache_write: z.number().optional(), - }) - .optional(), +const Cost = Schema.Struct({ + input: Schema.Number, + output: Schema.Number, + cache_read: Schema.optional(Schema.Number), + cache_write: Schema.optional(Schema.Number), + context_over_200k: Schema.optional( + Schema.Struct({ + input: Schema.Number, + output: Schema.Number, + cache_read: Schema.optional(Schema.Number), + cache_write: Schema.optional(Schema.Number), + }), + ), }) -export const Model = z.object({ - id: z.string(), - name: z.string(), - family: z.string().optional(), - release_date: z.string(), - attachment: z.boolean(), - reasoning: z.boolean(), - temperature: z.boolean(), - tool_call: z.boolean(), - interleaved: z - .union([ - z.literal(true), - z - .object({ - field: z.enum(["reasoning_content", "reasoning_details"]), - }) - .strict(), - ]) - .optional(), - cost: Cost.optional(), - limit: z.object({ - context: z.number(), - input: z.number().optional(), - output: z.number(), +export const Model = Schema.Struct({ + id: Schema.String, + name: Schema.String, + family: Schema.optional(Schema.String), + release_date: Schema.String, + attachment: Schema.Boolean, + reasoning: Schema.Boolean, + temperature: Schema.Boolean, + tool_call: Schema.Boolean, + interleaved: Schema.optional( + Schema.Union([ + Schema.Literal(true), + Schema.Struct({ + field: Schema.Literals(["reasoning_content", "reasoning_details"]), + }), + ]), + ), + cost: Schema.optional(Cost), + limit: Schema.Struct({ + context: Schema.Number, + input: Schema.optional(Schema.Number), + output: Schema.Number, }), - modalities: z - .object({ - input: z.array(z.enum(["text", "audio", "image", "video", "pdf"])), - output: z.array(z.enum(["text", "audio", "image", "video", "pdf"])), - }) - .optional(), - experimental: z - .object({ - modes: z - .record( - z.string(), - z.object({ - cost: Cost.optional(), - provider: z - .object({ - body: z.record(z.string(), JsonValue).optional(), - headers: z.record(z.string(), z.string()).optional(), - }) - .optional(), + modalities: Schema.optional( + Schema.Struct({ + input: Schema.Array(Schema.Literals(["text", "audio", "image", "video", "pdf"])), + output: Schema.Array(Schema.Literals(["text", "audio", "image", "video", "pdf"])), + }), + ), + experimental: Schema.optional( + Schema.Struct({ + modes: Schema.optional( + Schema.Record( + Schema.String, + Schema.Struct({ + cost: Schema.optional(Cost), + provider: Schema.optional( + Schema.Struct({ + body: Schema.optional(Schema.Record(Schema.String, Schema.MutableJson)), + headers: Schema.optional(Schema.Record(Schema.String, Schema.String)), + }), + ), }), - ) - .optional(), - }) - .optional(), - status: z.enum(["alpha", "beta", "deprecated"]).optional(), - provider: z.object({ npm: z.string().optional(), api: z.string().optional() }).optional(), + ), + ), + }), + ), + status: Schema.optional(Schema.Literals(["alpha", "beta", "deprecated"])), + provider: Schema.optional( + Schema.Struct({ npm: Schema.optional(Schema.String), api: Schema.optional(Schema.String) }), + ), }) -export type Model = z.infer +export type Model = Schema.Schema.Type -export const Provider = z.object({ - api: z.string().optional(), - name: z.string(), - env: z.array(z.string()), - id: z.string(), - npm: z.string().optional(), - models: z.record(z.string(), Model), +export const Provider = Schema.Struct({ + api: Schema.optional(Schema.String), + name: Schema.String, + env: Schema.Array(Schema.String), + id: Schema.String, + npm: Schema.optional(Schema.String), + models: Schema.Record(Schema.String, Model), }) -export type Provider = z.infer +export type Provider = Schema.Schema.Type function url() { return Flag.OPENCODE_MODELS_URL || "https://models.dev" diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index d643f25373..d826f6b350 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -1,4 +1,3 @@ -import z from "zod" import os from "os" import fuzzysort from "fuzzysort" import { Config } from "../config" @@ -8,7 +7,6 @@ import { Log } from "../util" import { Npm } from "../npm" import { Hash } from "@opencode-ai/shared/util/hash" import { Plugin } from "../plugin" -import { NamedError } from "@opencode-ai/shared/util/error" import { type LanguageModelV3 } from "@ai-sdk/provider" import * as ModelsDev from "./models" import { Auth } from "../auth" @@ -16,6 +14,7 @@ import { Env } from "../env" import { InstallationVersion } from "../installation/version" import { Flag } from "../flag/flag" import { zod } from "@/util/effect-zod" +import { namedSchemaError } from "@/util/named-schema-error" import { iife } from "@/util/iife" import { Global } from "../global" import path from "path" @@ -1047,7 +1046,7 @@ export function fromModelsDevProvider(provider: ModelsDev.Provider): Info { id: ProviderID.make(provider.id), source: "custom", name: provider.name, - env: provider.env ?? [], + env: [...(provider.env ?? [])], options: {}, models, } @@ -1713,18 +1712,12 @@ export function parseModel(model: string) { } } -export const ModelNotFoundError = NamedError.create( - "ProviderModelNotFoundError", - z.object({ - providerID: ProviderID.zod, - modelID: ModelID.zod, - suggestions: z.array(z.string()).optional(), - }), -) +export const ModelNotFoundError = namedSchemaError("ProviderModelNotFoundError", { + providerID: ProviderID, + modelID: ModelID, + suggestions: Schema.optional(Schema.Array(Schema.String)), +}) -export const InitError = NamedError.create( - "ProviderInitError", - z.object({ - providerID: ProviderID.zod, - }), -) +export const InitError = namedSchemaError("ProviderInitError", { + providerID: ProviderID, +}) From 0590452456a746457d5255e2ce3ecd9c5a4a621d Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 23 Apr 2026 13:22:48 -0400 Subject: [PATCH 41/92] refactor(schema): use Schema.Int and consolidate PositiveInt/NonNegativeInt (#24029) --- packages/opencode/src/config/agent.ts | 3 +-- packages/opencode/src/config/config.ts | 5 +---- packages/opencode/src/config/provider.ts | 4 +--- packages/opencode/src/config/server.ts | 4 ++-- packages/opencode/src/session/message-v2.ts | 20 +++++++++----------- packages/opencode/src/util/schema.ts | 10 ++++++++++ 6 files changed, 24 insertions(+), 22 deletions(-) diff --git a/packages/opencode/src/config/agent.ts b/packages/opencode/src/config/agent.ts index 85021407c7..2978916b57 100644 --- a/packages/opencode/src/config/agent.ts +++ b/packages/opencode/src/config/agent.ts @@ -4,6 +4,7 @@ import { Schema } from "effect" import z from "zod" import { Bus } from "@/bus" import { zod } from "@/util/effect-zod" +import { PositiveInt } from "@/util/schema" import { Log } from "../util" import { NamedError } from "@opencode-ai/shared/util/error" import { Glob } from "@opencode-ai/shared/util/glob" @@ -15,8 +16,6 @@ import { ConfigPermission } from "./permission" const log = Log.create({ service: "config" }) -const PositiveInt = Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(0)) - const Color = Schema.Union([ Schema.String.check(Schema.isPattern(/^#[0-9a-fA-F]{6}$/)), Schema.Literals(["primary", "secondary", "accent", "success", "warning", "error", "info"]), diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 5423ba3baf..9814017d10 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -25,7 +25,7 @@ import { Context, Duration, Effect, Exit, Fiber, Layer, Option, Schema } from "e import { EffectFlock } from "@opencode-ai/shared/util/effect-flock" import { InstanceRef } from "@/effect/instance-ref" import { zod, ZodOverride } from "@/util/effect-zod" -import { withStatics } from "@/util/schema" +import { NonNegativeInt, PositiveInt, withStatics } from "@/util/schema" import { ConfigAgent } from "./agent" import { ConfigCommand } from "./command" import { ConfigFormatter } from "./formatter" @@ -88,9 +88,6 @@ export type Layout = ConfigLayout.Layout const AgentRef = Schema.Any.annotate({ [ZodOverride]: ConfigAgent.Info }) const LogLevelRef = Schema.Any.annotate({ [ZodOverride]: Log.Level }) -const PositiveInt = Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(0)) -const NonNegativeInt = Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) - // The Effect Schema is the canonical source of truth. The `.zod` compatibility // surface is derived so existing Hono validators keep working without a parallel // Zod definition. diff --git a/packages/opencode/src/config/provider.ts b/packages/opencode/src/config/provider.ts index bd6ae35996..cd7469435c 100644 --- a/packages/opencode/src/config/provider.ts +++ b/packages/opencode/src/config/provider.ts @@ -1,8 +1,6 @@ import { Schema } from "effect" import { zod } from "@/util/effect-zod" -import { withStatics } from "@/util/schema" - -const PositiveInt = Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(0)) +import { PositiveInt, withStatics } from "@/util/schema" export const Model = Schema.Struct({ id: Schema.optional(Schema.String), diff --git a/packages/opencode/src/config/server.ts b/packages/opencode/src/config/server.ts index 3ce4fe6262..3f13698269 100644 --- a/packages/opencode/src/config/server.ts +++ b/packages/opencode/src/config/server.ts @@ -1,9 +1,9 @@ import { Schema } from "effect" import { zod } from "@/util/effect-zod" -import { withStatics } from "@/util/schema" +import { PositiveInt, withStatics } from "@/util/schema" export const Server = Schema.Struct({ - port: Schema.optional(Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(0))).annotate({ + port: Schema.optional(PositiveInt).annotate({ description: "Port to listen on", }), hostname: Schema.optional(Schema.String).annotate({ description: "Hostname to listen on" }), diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index a4b25d95ea..c5a35c7b41 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -17,7 +17,7 @@ import type { Provider } from "@/provider" import { ModelID, ProviderID } from "@/provider/schema" import { Effect, Schema, Types } from "effect" import { zod, ZodOverride } from "@/util/effect-zod" -import { withStatics } from "@/util/schema" +import { NonNegativeInt, withStatics } from "@/util/schema" import { namedSchemaError } from "@/util/named-schema-error" import { EffectLogger } from "@/effect" @@ -64,9 +64,7 @@ export class OutputFormatText extends Schema.Class("OutputForm export class OutputFormatJsonSchema extends Schema.Class("OutputFormatJsonSchema")({ type: Schema.Literal("json_schema"), schema: Schema.Record(Schema.String, Schema.Any).annotate({ identifier: "JSONSchema" }), - retryCount: Schema.Number.check(Schema.isInt()) - .check(Schema.isGreaterThanOrEqualTo(0)) - .pipe(Schema.optional, Schema.withDecodingDefault(Effect.succeed(2))), + retryCount: NonNegativeInt.pipe(Schema.optional, Schema.withDecodingDefault(Effect.succeed(2))), }) { static readonly zod = zod(this) } @@ -138,8 +136,8 @@ export type ReasoningPart = Types.DeepMutable ({ zod: zod(s) }))) @@ -196,8 +194,8 @@ export const AgentPart = Schema.Struct({ source: Schema.optional( Schema.Struct({ value: Schema.String, - start: Schema.Number.check(Schema.isInt()), - end: Schema.Number.check(Schema.isInt()), + start: Schema.Int, + end: Schema.Int, }), ), }) @@ -501,8 +499,8 @@ export const AgentPartInput = Schema.Struct({ source: Schema.optional( Schema.Struct({ value: Schema.String, - start: Schema.Number.check(Schema.isInt()), - end: Schema.Number.check(Schema.isInt()), + start: Schema.Int, + end: Schema.Int, }), ), }) diff --git a/packages/opencode/src/util/schema.ts b/packages/opencode/src/util/schema.ts index 405f6a7182..7f94ee5d1e 100644 --- a/packages/opencode/src/util/schema.ts +++ b/packages/opencode/src/util/schema.ts @@ -1,5 +1,15 @@ import { Schema } from "effect" +/** + * Integer greater than zero. + */ +export const PositiveInt = Schema.Int.check(Schema.isGreaterThan(0)) + +/** + * Integer greater than or equal to zero. + */ +export const NonNegativeInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)) + /** * Attach static methods to a schema object. Designed to be used with `.pipe()`: * From cd93533b1f5eae9362a485b0072f98a05d1ca161 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 23 Apr 2026 15:37:44 -0400 Subject: [PATCH 42/92] refactor(bus): migrate BusEvent to Effect Schema (#24040) --- packages/opencode/src/bus/bus-event.ts | 20 +++-- packages/opencode/src/bus/index.ts | 13 +--- packages/opencode/src/cli/cmd/tui/event.ts | 26 +++---- .../opencode/src/cli/cmd/tui/ui/toast.tsx | 4 +- packages/opencode/src/command/index.ts | 12 +-- packages/opencode/src/config/config.ts | 25 +------ .../opencode/src/control-plane/workspace.ts | 28 +++---- packages/opencode/src/file/index.ts | 6 +- packages/opencode/src/file/watcher.ts | 8 +- packages/opencode/src/ide/index.ts | 5 +- packages/opencode/src/installation/index.ts | 8 +- packages/opencode/src/lsp/client.ts | 7 +- packages/opencode/src/lsp/lsp.ts | 2 +- packages/opencode/src/mcp/index.ts | 12 +-- packages/opencode/src/permission/index.ts | 14 ++-- packages/opencode/src/project/project.ts | 2 +- packages/opencode/src/project/vcs.ts | 6 +- packages/opencode/src/pty/index.ts | 75 ++++++++++--------- packages/opencode/src/question/index.ts | 8 +- packages/opencode/src/server/event.ts | 6 +- .../src/server/routes/control/workspace.ts | 3 +- packages/opencode/src/server/routes/global.ts | 4 +- .../src/server/routes/instance/pty.ts | 16 ++-- .../src/server/routes/instance/tui.ts | 22 +++--- packages/opencode/src/session/compaction.ts | 6 +- packages/opencode/src/session/message-v2.ts | 12 +-- packages/opencode/src/session/session.ts | 15 ++-- packages/opencode/src/session/status.ts | 10 +-- packages/opencode/src/session/todo.ts | 6 +- packages/opencode/src/sync/index.ts | 60 +++++++-------- packages/opencode/src/util/effect-zod.ts | 17 +++-- packages/opencode/src/util/schema.ts | 47 ++++++++++-- packages/opencode/src/worktree/index.ts | 12 +-- packages/opencode/test/bus/bus-effect.test.ts | 7 +- .../opencode/test/bus/bus-integration.test.ts | 6 +- packages/opencode/test/bus/bus.test.ts | 6 +- .../opencode/test/session/session.test.ts | 5 +- 37 files changed, 281 insertions(+), 260 deletions(-) diff --git a/packages/opencode/src/bus/bus-event.ts b/packages/opencode/src/bus/bus-event.ts index efaed94406..f27d263354 100644 --- a/packages/opencode/src/bus/bus-event.ts +++ b/packages/opencode/src/bus/bus-event.ts @@ -1,15 +1,19 @@ import z from "zod" -import type { ZodType } from "zod" +import { Schema } from "effect" +import { zodObject } from "@/util/effect-zod" -export type Definition = ReturnType +export type Definition = { + type: Type + properties: Properties +} const registry = new Map() -export function define(type: Type, properties: Properties) { - const result = { - type, - properties, - } +export function define( + type: Type, + properties: Properties, +): Definition { + const result = { type, properties } registry.set(type, result) return result } @@ -21,7 +25,7 @@ export function payloads() { return z .object({ type: z.literal(type), - properties: def.properties, + properties: zodObject(def.properties), }) .meta({ ref: `Event.${def.type}`, diff --git a/packages/opencode/src/bus/index.ts b/packages/opencode/src/bus/index.ts index 9183ff72a4..12251f26c7 100644 --- a/packages/opencode/src/bus/index.ts +++ b/packages/opencode/src/bus/index.ts @@ -1,5 +1,4 @@ -import z from "zod" -import { Effect, Exit, Layer, PubSub, Scope, Context, Stream, Schema as EffectSchema, Types } from "effect" +import { Effect, Exit, Layer, PubSub, Scope, Context, Stream, Schema } from "effect" import { EffectBridge } from "@/effect" import { Log } from "../util" import { BusEvent } from "./bus-event" @@ -9,16 +8,12 @@ import { makeRuntime } from "@/effect/run-service" const log = Log.create({ service: "bus" }) -type BusProperties = D extends { - effectProperties: infer Properties extends EffectSchema.Top -} - ? Types.DeepMutable> - : z.infer +type BusProperties> = Schema.Schema.Type export const InstanceDisposed = BusEvent.define( "server.instance.disposed", - z.object({ - directory: z.string(), + Schema.Struct({ + directory: Schema.String, }), ) diff --git a/packages/opencode/src/cli/cmd/tui/event.ts b/packages/opencode/src/cli/cmd/tui/event.ts index fa164d53e8..ab85b1e645 100644 --- a/packages/opencode/src/cli/cmd/tui/event.ts +++ b/packages/opencode/src/cli/cmd/tui/event.ts @@ -1,14 +1,14 @@ import { BusEvent } from "@/bus/bus-event" import { SessionID } from "@/session/schema" -import z from "zod" +import { Schema } from "effect" export const TuiEvent = { - PromptAppend: BusEvent.define("tui.prompt.append", z.object({ text: z.string() })), + PromptAppend: BusEvent.define("tui.prompt.append", Schema.Struct({ text: Schema.String })), CommandExecute: BusEvent.define( "tui.command.execute", - z.object({ - command: z.union([ - z.enum([ + Schema.Struct({ + command: Schema.Union([ + Schema.Literals([ "session.list", "session.new", "session.share", @@ -26,23 +26,23 @@ export const TuiEvent = { "prompt.submit", "agent.cycle", ]), - z.string(), + Schema.String, ]), }), ), ToastShow: BusEvent.define( "tui.toast.show", - z.object({ - title: z.string().optional(), - message: z.string(), - variant: z.enum(["info", "success", "warning", "error"]), - duration: z.number().default(5000).optional().describe("Duration in milliseconds"), + Schema.Struct({ + title: Schema.optional(Schema.String), + message: Schema.String, + variant: Schema.Literals(["info", "success", "warning", "error"]), + duration: Schema.optional(Schema.Number).annotate({ description: "Duration in milliseconds" }), }), ), SessionSelect: BusEvent.define( "tui.session.select", - z.object({ - sessionID: SessionID.zod.describe("Session ID to navigate to"), + Schema.Struct({ + sessionID: SessionID.annotate({ description: "Session ID to navigate to" }), }), ), } diff --git a/packages/opencode/src/cli/cmd/tui/ui/toast.tsx b/packages/opencode/src/cli/cmd/tui/ui/toast.tsx index f534d90b77..69674ba7ce 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/toast.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/toast.tsx @@ -4,10 +4,10 @@ import { useTheme } from "@tui/context/theme" import { useTerminalDimensions } from "@opentui/solid" import { SplitBorder } from "../component/border" import { TextAttributes } from "@opentui/core" -import z from "zod" +import { Schema } from "effect" import { type TuiEvent } from "../event" -export type ToastOptions = z.infer +export type ToastOptions = Schema.Schema.Type export function Toast() { const toast = useToast() diff --git a/packages/opencode/src/command/index.ts b/packages/opencode/src/command/index.ts index 27ba357ecc..478a12f664 100644 --- a/packages/opencode/src/command/index.ts +++ b/packages/opencode/src/command/index.ts @@ -3,7 +3,7 @@ import { InstanceState } from "@/effect" import { EffectBridge } from "@/effect" import type { InstanceContext } from "@/project/instance" import { SessionID, MessageID } from "@/session/schema" -import { Effect, Layer, Context } from "effect" +import { Effect, Layer, Context, Schema } from "effect" import z from "zod" import { Config } from "../config" import { MCP } from "../mcp" @@ -18,11 +18,11 @@ type State = { export const Event = { Executed: BusEvent.define( "command.executed", - z.object({ - name: z.string(), - sessionID: SessionID.zod, - arguments: z.string(), - messageID: MessageID.zod, + Schema.Struct({ + name: Schema.String, + sessionID: SessionID, + arguments: Schema.String, + messageID: MessageID, }), ), } diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 9814017d10..eab199232a 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -25,7 +25,7 @@ import { Context, Duration, Effect, Exit, Fiber, Layer, Option, Schema } from "e import { EffectFlock } from "@opencode-ai/shared/util/effect-flock" import { InstanceRef } from "@/effect/instance-ref" import { zod, ZodOverride } from "@/util/effect-zod" -import { NonNegativeInt, PositiveInt, withStatics } from "@/util/schema" +import { NonNegativeInt, PositiveInt, withStatics, type DeepMutable } from "@/util/schema" import { ConfigAgent } from "./agent" import { ConfigCommand } from "./command" import { ConfigFormatter } from "./formatter" @@ -249,26 +249,9 @@ export const Info = Schema.Struct({ })), ) -// Schema.Struct produces readonly types by default, but the service code -// below mutates Info objects directly (e.g. `config.mode = ...`). Strip the -// readonly recursively so callers get the same mutable shape zod inferred. -// -// `Types.DeepMutable` from effect-smol would be a drop-in, but its fallback -// branch `{ -readonly [K in keyof T]: ... }` collapses `unknown` to `{}` -// (since `keyof unknown = never`), which widens `Record` -// fields like `ConfigPlugin.Options`. The local version gates on -// `extends object` so `unknown` passes through. -// -// Tuple branch preserves `ConfigPlugin.Spec`'s `readonly [string, Options]` -// shape (otherwise the general array branch widens it to an array). -type DeepMutable = T extends readonly [unknown, ...unknown[]] - ? { -readonly [K in keyof T]: DeepMutable } - : T extends readonly (infer U)[] - ? DeepMutable[] - : T extends object - ? { -readonly [K in keyof T]: DeepMutable } - : T - +// Uses the shared `DeepMutable` from `@/util/schema`. See the definition +// there for why the local variant is needed over `Types.DeepMutable` from +// effect-smol (the upstream version collapses `unknown` to `{}`). export type Info = DeepMutable> & { // plugin_origins is derived state, not a persisted config field. It keeps each winning plugin spec together // with the file and scope it came from so later runtime code can make location-sensitive decisions. diff --git a/packages/opencode/src/control-plane/workspace.ts b/packages/opencode/src/control-plane/workspace.ts index eb689df025..8519cb06c1 100644 --- a/packages/opencode/src/control-plane/workspace.ts +++ b/packages/opencode/src/control-plane/workspace.ts @@ -1,4 +1,5 @@ import z from "zod" +import { Schema } from "effect" import { setTimeout as sleep } from "node:timers/promises" import { fn } from "@/util/fn" import { Database, asc, eq, inArray } from "@/storage" @@ -25,36 +26,37 @@ import { errorData } from "@/util/error" import { AppRuntime } from "@/effect/app-runtime" import { waitEvent } from "./util" import { WorkspaceContext } from "./workspace-context" +import { NonNegativeInt } from "@/util/schema" export const Info = WorkspaceInfo.meta({ ref: "Workspace", }) export type Info = z.infer -export const ConnectionStatus = z.object({ - workspaceID: WorkspaceID.zod, - status: z.enum(["connected", "connecting", "disconnected", "error"]), +export const ConnectionStatus = Schema.Struct({ + workspaceID: WorkspaceID, + status: Schema.Literals(["connected", "connecting", "disconnected", "error"]), }) -export type ConnectionStatus = z.infer +export type ConnectionStatus = Schema.Schema.Type -const Restore = z.object({ - workspaceID: WorkspaceID.zod, - sessionID: SessionID.zod, - total: z.number().int().min(0), - step: z.number().int().min(0), +const Restore = Schema.Struct({ + workspaceID: WorkspaceID, + sessionID: SessionID, + total: NonNegativeInt, + step: NonNegativeInt, }) export const Event = { Ready: BusEvent.define( "workspace.ready", - z.object({ - name: z.string(), + Schema.Struct({ + name: Schema.String, }), ), Failed: BusEvent.define( "workspace.failed", - z.object({ - message: z.string(), + Schema.Struct({ + message: Schema.String, }), ), Restore: BusEvent.define("workspace.restore", Restore), diff --git a/packages/opencode/src/file/index.ts b/packages/opencode/src/file/index.ts index af4fbf76c8..ca791e4128 100644 --- a/packages/opencode/src/file/index.ts +++ b/packages/opencode/src/file/index.ts @@ -3,7 +3,7 @@ import { InstanceState } from "@/effect" import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Git } from "@/git" -import { Effect, Layer, Context, Scope } from "effect" +import { Effect, Layer, Context, Schema, Scope } from "effect" import * as Stream from "effect/Stream" import { formatPatch, structuredPatch } from "diff" import fuzzysort from "fuzzysort" @@ -76,8 +76,8 @@ export type Content = z.infer export const Event = { Edited: BusEvent.define( "file.edited", - z.object({ - file: z.string(), + Schema.Struct({ + file: Schema.String, }), ), } diff --git a/packages/opencode/src/file/watcher.ts b/packages/opencode/src/file/watcher.ts index dc20333758..0ac98b9c2d 100644 --- a/packages/opencode/src/file/watcher.ts +++ b/packages/opencode/src/file/watcher.ts @@ -1,4 +1,4 @@ -import { Cause, Effect, Layer, Context } from "effect" +import { Cause, Effect, Layer, Context, Schema } from "effect" // @ts-ignore import { createWrapper } from "@parcel/watcher/wrapper" import type ParcelWatcher from "@parcel/watcher" @@ -25,9 +25,9 @@ const SUBSCRIBE_TIMEOUT_MS = 10_000 export const Event = { Updated: BusEvent.define( "file.watcher.updated", - z.object({ - file: z.string(), - event: z.union([z.literal("add"), z.literal("change"), z.literal("unlink")]), + Schema.Struct({ + file: Schema.String, + event: Schema.Literals(["add", "change", "unlink"]), }), ), } diff --git a/packages/opencode/src/ide/index.ts b/packages/opencode/src/ide/index.ts index ee80c34741..f9ce1ec635 100644 --- a/packages/opencode/src/ide/index.ts +++ b/packages/opencode/src/ide/index.ts @@ -1,5 +1,6 @@ import { BusEvent } from "@/bus/bus-event" import z from "zod" +import { Schema } from "effect" import { NamedError } from "@opencode-ai/shared/util/error" import { Log } from "../util" import { Process } from "@/util" @@ -17,8 +18,8 @@ const log = Log.create({ service: "ide" }) export const Event = { Installed: BusEvent.define( "ide.installed", - z.object({ - ide: z.string(), + Schema.Struct({ + ide: Schema.String, }), ), } diff --git a/packages/opencode/src/installation/index.ts b/packages/opencode/src/installation/index.ts index 787f9ea8c5..bb3de3f3b5 100644 --- a/packages/opencode/src/installation/index.ts +++ b/packages/opencode/src/installation/index.ts @@ -21,14 +21,14 @@ export type ReleaseType = "patch" | "minor" | "major" export const Event = { Updated: BusEvent.define( "installation.updated", - z.object({ - version: z.string(), + Schema.Struct({ + version: Schema.String, }), ), UpdateAvailable: BusEvent.define( "installation.update-available", - z.object({ - version: z.string(), + Schema.Struct({ + version: Schema.String, }), ), } diff --git a/packages/opencode/src/lsp/client.ts b/packages/opencode/src/lsp/client.ts index f6d5110a6c..e8050babfd 100644 --- a/packages/opencode/src/lsp/client.ts +++ b/packages/opencode/src/lsp/client.ts @@ -8,6 +8,7 @@ import { Log } from "../util" import { Process } from "../util" import { LANGUAGE_EXTENSIONS } from "./language" import z from "zod" +import { Schema } from "effect" import type * as LSPServer from "./server" import { NamedError } from "@opencode-ai/shared/util/error" import { withTimeout } from "../util/timeout" @@ -41,9 +42,9 @@ export const InitializeError = NamedError.create( export const Event = { Diagnostics: BusEvent.define( "lsp.client.diagnostics", - z.object({ - serverID: z.string(), - path: z.string(), + Schema.Struct({ + serverID: Schema.String, + path: Schema.String, }), ), } diff --git a/packages/opencode/src/lsp/lsp.ts b/packages/opencode/src/lsp/lsp.ts index 4c46cd9aa7..7741ff60e5 100644 --- a/packages/opencode/src/lsp/lsp.ts +++ b/packages/opencode/src/lsp/lsp.ts @@ -19,7 +19,7 @@ import { zod, ZodOverride } from "@/util/effect-zod" const log = Log.create({ service: "lsp" }) export const Event = { - Updated: BusEvent.define("lsp.updated", z.object({})), + Updated: BusEvent.define("lsp.updated", Schema.Struct({})), } const Position = Schema.Struct({ diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts index 09fcfc756a..385d7782a6 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -25,7 +25,7 @@ import { BusEvent } from "../bus/bus-event" import { Bus } from "@/bus" import { TuiEvent } from "@/cli/cmd/tui/event" import open from "open" -import { Effect, Exit, Layer, Option, Context, Stream } from "effect" +import { Effect, Exit, Layer, Option, Context, Schema, Stream } from "effect" import { EffectBridge } from "@/effect" import { InstanceState } from "@/effect" import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" @@ -47,16 +47,16 @@ export type Resource = z.infer export const ToolsChanged = BusEvent.define( "mcp.tools.changed", - z.object({ - server: z.string(), + Schema.Struct({ + server: Schema.String, }), ) export const BrowserOpenFailed = BusEvent.define( "mcp.browser.open.failed", - z.object({ - mcpName: z.string(), - url: z.string(), + Schema.Struct({ + mcpName: Schema.String, + url: Schema.String, }), ) diff --git a/packages/opencode/src/permission/index.ts b/packages/opencode/src/permission/index.ts index 6943b3d93b..05c832016d 100644 --- a/packages/opencode/src/permission/index.ts +++ b/packages/opencode/src/permission/index.ts @@ -73,16 +73,14 @@ export class Approval extends Schema.Class("PermissionApproval")({ } export const Event = { - Asked: BusEvent.define("permission.asked", Request.zod), + Asked: BusEvent.define("permission.asked", Request), Replied: BusEvent.define( "permission.replied", - zod( - Schema.Struct({ - sessionID: SessionID, - requestID: PermissionID, - reply: Reply, - }), - ), + Schema.Struct({ + sessionID: SessionID, + requestID: PermissionID, + reply: Reply, + }), ), } diff --git a/packages/opencode/src/project/project.ts b/packages/opencode/src/project/project.ts index ab60cff7aa..70a9590640 100644 --- a/packages/opencode/src/project/project.ts +++ b/packages/opencode/src/project/project.ts @@ -53,7 +53,7 @@ export const Info = Schema.Struct({ export type Info = Types.DeepMutable> export const Event = { - Updated: BusEvent.define("project.updated", Info.zod), + Updated: BusEvent.define("project.updated", Info), } type Row = typeof ProjectTable.$inferSelect diff --git a/packages/opencode/src/project/vcs.ts b/packages/opencode/src/project/vcs.ts index ba028f7e8e..e8c6ff2ac7 100644 --- a/packages/opencode/src/project/vcs.ts +++ b/packages/opencode/src/project/vcs.ts @@ -1,4 +1,4 @@ -import { Effect, Layer, Context, Stream, Scope } from "effect" +import { Effect, Layer, Context, Schema, Stream, Scope } from "effect" import { formatPatch, structuredPatch } from "diff" import path from "path" import { Bus } from "@/bus" @@ -107,8 +107,8 @@ export type Mode = z.infer export const Event = { BranchUpdated: BusEvent.define( "vcs.branch.updated", - z.object({ - branch: z.string().optional(), + Schema.Struct({ + branch: Schema.optional(Schema.String), }), ), } diff --git a/packages/opencode/src/pty/index.ts b/packages/opencode/src/pty/index.ts index 3d00de596a..604fa77fbb 100644 --- a/packages/opencode/src/pty/index.ts +++ b/packages/opencode/src/pty/index.ts @@ -3,13 +3,14 @@ import { Bus } from "@/bus" import { InstanceState } from "@/effect" import { Instance } from "@/project/instance" import type { Proc } from "#pty" -import z from "zod" import { Log } from "../util" import { lazy } from "@opencode-ai/shared/util/lazy" import { Shell } from "@/shell/shell" import { Plugin } from "@/plugin" import { PtyID } from "./schema" -import { Effect, Layer, Context } from "effect" +import { Effect, Layer, Context, Schema, Types } from "effect" +import { zod } from "@/util/effect-zod" +import { withStatics } from "@/util/schema" import { EffectBridge } from "@/effect" const log = Log.create({ service: "pty" }) @@ -53,47 +54,47 @@ const meta = (cursor: number) => { const pty = lazy(() => import("#pty")) -export const Info = z - .object({ - id: PtyID.zod, - title: z.string(), - command: z.string(), - args: z.array(z.string()), - cwd: z.string(), - status: z.enum(["running", "exited"]), - pid: z.number(), - }) - .meta({ ref: "Pty" }) - -export type Info = z.infer - -export const CreateInput = z.object({ - command: z.string().optional(), - args: z.array(z.string()).optional(), - cwd: z.string().optional(), - title: z.string().optional(), - env: z.record(z.string(), z.string()).optional(), +export const Info = Schema.Struct({ + id: PtyID, + title: Schema.String, + command: Schema.String, + args: Schema.Array(Schema.String), + cwd: Schema.String, + status: Schema.Literals(["running", "exited"]), + pid: Schema.Number, }) + .annotate({ identifier: "Pty" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) -export type CreateInput = z.infer +export type Info = Types.DeepMutable> -export const UpdateInput = z.object({ - title: z.string().optional(), - size: z - .object({ - rows: z.number(), - cols: z.number(), - }) - .optional(), -}) +export const CreateInput = Schema.Struct({ + command: Schema.optional(Schema.String), + args: Schema.optional(Schema.Array(Schema.String)), + cwd: Schema.optional(Schema.String), + title: Schema.optional(Schema.String), + env: Schema.optional(Schema.Record(Schema.String, Schema.String)), +}).pipe(withStatics((s) => ({ zod: zod(s) }))) -export type UpdateInput = z.infer +export type CreateInput = Types.DeepMutable> + +export const UpdateInput = Schema.Struct({ + title: Schema.optional(Schema.String), + size: Schema.optional( + Schema.Struct({ + rows: Schema.Number, + cols: Schema.Number, + }), + ), +}).pipe(withStatics((s) => ({ zod: zod(s) }))) + +export type UpdateInput = Types.DeepMutable> export const Event = { - Created: BusEvent.define("pty.created", z.object({ info: Info })), - Updated: BusEvent.define("pty.updated", z.object({ info: Info })), - Exited: BusEvent.define("pty.exited", z.object({ id: PtyID.zod, exitCode: z.number() })), - Deleted: BusEvent.define("pty.deleted", z.object({ id: PtyID.zod })), + Created: BusEvent.define("pty.created", Schema.Struct({ info: Info })), + Updated: BusEvent.define("pty.updated", Schema.Struct({ info: Info })), + Exited: BusEvent.define("pty.exited", Schema.Struct({ id: PtyID, exitCode: Schema.Number })), + Deleted: BusEvent.define("pty.deleted", Schema.Struct({ id: PtyID })), } export interface Interface { diff --git a/packages/opencode/src/question/index.ts b/packages/opencode/src/question/index.ts index 3b377c9827..626c71826c 100644 --- a/packages/opencode/src/question/index.ts +++ b/packages/opencode/src/question/index.ts @@ -94,9 +94,9 @@ class Rejected extends Schema.Class("QuestionRejected")({ }) {} export const Event = { - Asked: BusEvent.define("question.asked", Request.zod), - Replied: BusEvent.define("question.replied", zod(Replied)), - Rejected: BusEvent.define("question.rejected", zod(Rejected)), + Asked: BusEvent.define("question.asked", Request), + Replied: BusEvent.define("question.replied", Replied), + Rejected: BusEvent.define("question.rejected", Rejected), } export class RejectedError extends Schema.TaggedErrorClass()("QuestionRejectedError", {}) { @@ -194,7 +194,7 @@ export const layer = Layer.effect( yield* bus.publish(Event.Replied, { sessionID: existing.info.sessionID, requestID: existing.info.id, - answers: input.answers, + answers: input.answers.map((a) => [...a]), }) yield* Deferred.succeed(existing.deferred, input.answers) }) diff --git a/packages/opencode/src/server/event.ts b/packages/opencode/src/server/event.ts index 49325b2bb6..d5f10f47db 100644 --- a/packages/opencode/src/server/event.ts +++ b/packages/opencode/src/server/event.ts @@ -1,7 +1,7 @@ import { BusEvent } from "@/bus/bus-event" -import z from "zod" +import { Schema } from "effect" export const Event = { - Connected: BusEvent.define("server.connected", z.object({})), - Disposed: BusEvent.define("global.disposed", z.object({})), + Connected: BusEvent.define("server.connected", Schema.Struct({})), + Disposed: BusEvent.define("global.disposed", Schema.Struct({})), } diff --git a/packages/opencode/src/server/routes/control/workspace.ts b/packages/opencode/src/server/routes/control/workspace.ts index 9ff747b68a..d48c687f31 100644 --- a/packages/opencode/src/server/routes/control/workspace.ts +++ b/packages/opencode/src/server/routes/control/workspace.ts @@ -3,6 +3,7 @@ import { describeRoute, resolver, validator } from "hono-openapi" import z from "zod" import { listAdaptors } from "@/control-plane/adaptors" import { Workspace } from "@/control-plane/workspace" +import { zodObject } from "@/util/effect-zod" import { Instance } from "@/project/instance" import { errors } from "../../error" import { lazy } from "@/util/lazy" @@ -107,7 +108,7 @@ export const WorkspaceRoutes = lazy(() => description: "Workspace status", content: { "application/json": { - schema: resolver(z.array(Workspace.ConnectionStatus)), + schema: resolver(z.array(zodObject(Workspace.ConnectionStatus))), }, }, }, diff --git a/packages/opencode/src/server/routes/global.ts b/packages/opencode/src/server/routes/global.ts index 54f9972e02..a1199a4691 100644 --- a/packages/opencode/src/server/routes/global.ts +++ b/packages/opencode/src/server/routes/global.ts @@ -1,7 +1,7 @@ import { Hono, type Context } from "hono" import { describeRoute, resolver, validator } from "hono-openapi" import { streamSSE } from "hono/streaming" -import { Effect } from "effect" +import { Effect, Schema } from "effect" import z from "zod" import { BusEvent } from "@/bus/bus-event" import { SyncEvent } from "@/sync" @@ -18,7 +18,7 @@ import { errors } from "../error" const log = Log.create({ service: "server" }) -export const GlobalDisposedEvent = BusEvent.define("global.disposed", z.object({})) +export const GlobalDisposedEvent = BusEvent.define("global.disposed", Schema.Struct({})) async function streamEvents(c: Context, subscribe: (q: AsyncQueue) => () => void) { return streamSSE(c, async (stream) => { diff --git a/packages/opencode/src/server/routes/instance/pty.ts b/packages/opencode/src/server/routes/instance/pty.ts index a25b66e9ff..51c4699241 100644 --- a/packages/opencode/src/server/routes/instance/pty.ts +++ b/packages/opencode/src/server/routes/instance/pty.ts @@ -23,7 +23,7 @@ export function PtyRoutes(upgradeWebSocket: UpgradeWebSocket) { description: "List of sessions", content: { "application/json": { - schema: resolver(Pty.Info.array()), + schema: resolver(Pty.Info.zod.array()), }, }, }, @@ -46,18 +46,18 @@ export function PtyRoutes(upgradeWebSocket: UpgradeWebSocket) { description: "Created session", content: { "application/json": { - schema: resolver(Pty.Info), + schema: resolver(Pty.Info.zod), }, }, }, ...errors(400), }, }), - validator("json", Pty.CreateInput), + validator("json", Pty.CreateInput.zod), async (c) => jsonRequest("PtyRoutes.create", c, function* () { const pty = yield* Pty.Service - return yield* pty.create(c.req.valid("json")) + return yield* pty.create(c.req.valid("json") as Pty.CreateInput) }), ) .get( @@ -71,7 +71,7 @@ export function PtyRoutes(upgradeWebSocket: UpgradeWebSocket) { description: "Session info", content: { "application/json": { - schema: resolver(Pty.Info), + schema: resolver(Pty.Info.zod), }, }, }, @@ -105,7 +105,7 @@ export function PtyRoutes(upgradeWebSocket: UpgradeWebSocket) { description: "Updated session", content: { "application/json": { - schema: resolver(Pty.Info), + schema: resolver(Pty.Info.zod), }, }, }, @@ -113,11 +113,11 @@ export function PtyRoutes(upgradeWebSocket: UpgradeWebSocket) { }, }), validator("param", z.object({ ptyID: PtyID.zod })), - validator("json", Pty.UpdateInput), + validator("json", Pty.UpdateInput.zod), async (c) => jsonRequest("PtyRoutes.update", c, function* () { const pty = yield* Pty.Service - return yield* pty.update(c.req.valid("param").ptyID, c.req.valid("json")) + return yield* pty.update(c.req.valid("param").ptyID, c.req.valid("json") as Pty.UpdateInput) }), ) .delete( diff --git a/packages/opencode/src/server/routes/instance/tui.ts b/packages/opencode/src/server/routes/instance/tui.ts index d6add67b97..a610590e87 100644 --- a/packages/opencode/src/server/routes/instance/tui.ts +++ b/packages/opencode/src/server/routes/instance/tui.ts @@ -1,9 +1,12 @@ import { Hono, type Context } from "hono" import { describeRoute, validator, resolver } from "hono-openapi" +import { Schema } from "effect" import z from "zod" import { Bus } from "@/bus" import { Session } from "@/session" +import type { SessionID } from "@/session/schema" import { TuiEvent } from "@/cli/cmd/tui/event" +import { zodObject } from "@/util/effect-zod" import { AsyncQueue } from "@/util/queue" import { errors } from "../../error" import { lazy } from "@/util/lazy" @@ -96,9 +99,9 @@ export const TuiRoutes = lazy(() => ...errors(400), }, }), - validator("json", TuiEvent.PromptAppend.properties), + validator("json", zodObject(TuiEvent.PromptAppend.properties)), async (c) => { - await Bus.publish(TuiEvent.PromptAppend, c.req.valid("json")) + await Bus.publish(TuiEvent.PromptAppend, c.req.valid("json") as { text: string }) return c.json(true) }, ) @@ -305,9 +308,9 @@ export const TuiRoutes = lazy(() => }, }, }), - validator("json", TuiEvent.ToastShow.properties), + validator("json", zodObject(TuiEvent.ToastShow.properties)), async (c) => { - await Bus.publish(TuiEvent.ToastShow, c.req.valid("json")) + await Bus.publish(TuiEvent.ToastShow, c.req.valid("json") as Schema.Schema.Type) return c.json(true) }, ) @@ -336,7 +339,7 @@ export const TuiRoutes = lazy(() => return z .object({ type: z.literal(def.type), - properties: def.properties, + properties: zodObject(def.properties), }) .meta({ ref: `Event.${def.type}`, @@ -345,8 +348,9 @@ export const TuiRoutes = lazy(() => ), ), async (c) => { - const evt = c.req.valid("json") - await Bus.publish(Object.values(TuiEvent).find((def) => def.type === evt.type)!, evt.properties) + const evt = c.req.valid("json") as { type: string; properties: Record } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + await Bus.publish(Object.values(TuiEvent).find((def) => def.type === evt.type)! as any, evt.properties as any) return c.json(true) }, ) @@ -368,9 +372,9 @@ export const TuiRoutes = lazy(() => ...errors(400, 404), }, }), - validator("json", TuiEvent.SessionSelect.properties), + validator("json", zodObject(TuiEvent.SessionSelect.properties)), async (c) => { - const { sessionID } = c.req.valid("json") + const { sessionID } = c.req.valid("json") as { sessionID: SessionID } await runRequest( "TuiRoutes.sessionSelect", c, diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts index defdb870d7..dc126e6837 100644 --- a/packages/opencode/src/session/compaction.ts +++ b/packages/opencode/src/session/compaction.ts @@ -13,7 +13,7 @@ import { Plugin } from "@/plugin" import { Config } from "@/config" import { NotFoundError } from "@/storage" import { ModelID, ProviderID } from "@/provider/schema" -import { Effect, Layer, Context } from "effect" +import { Effect, Layer, Context, Schema } from "effect" import { InstanceState } from "@/effect" import { isOverflow as overflow, usable } from "./overflow" import { makeRuntime } from "@/effect/run-service" @@ -24,8 +24,8 @@ const log = Log.create({ service: "session.compaction" }) export const Event = { Compacted: BusEvent.define( "session.compacted", - z.object({ - sessionID: SessionID.zod, + Schema.Struct({ + sessionID: SessionID, }), ), } diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index c5a35c7b41..d04645b736 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -617,12 +617,12 @@ export const Event = { }), PartDelta: BusEvent.define( "message.part.delta", - z.object({ - sessionID: SessionID.zod, - messageID: MessageID.zod, - partID: PartID.zod, - field: z.string(), - delta: z.string(), + Schema.Struct({ + sessionID: SessionID, + messageID: MessageID, + partID: PartID, + field: Schema.String, + delta: Schema.String, }), ), PartRemoved: SyncEvent.define({ diff --git a/packages/opencode/src/session/session.ts b/packages/opencode/src/session/session.ts index 1e046fdf79..f4fe3bf8bd 100644 --- a/packages/opencode/src/session/session.ts +++ b/packages/opencode/src/session/session.ts @@ -273,17 +273,18 @@ export const Event = { }), Diff: BusEvent.define( "session.diff", - z.object({ - sessionID: SessionID.zod, - diff: Snapshot.FileDiff.zod.array(), + Schema.Struct({ + sessionID: SessionID, + diff: Schema.Array(Snapshot.FileDiff), }), ), Error: BusEvent.define( "session.error", - z.object({ - sessionID: SessionID.zod.optional(), - // z.lazy defers access to break circular dep: session → message-v2 → provider → plugin → session - error: z.lazy(() => (MessageV2.Assistant.zod as unknown as z.ZodObject).shape.error), + Schema.Struct({ + sessionID: Schema.optional(SessionID), + // Reuses MessageV2.Assistant.fields.error (already Schema.optional) so + // the derived zod keeps the same discriminated-union shape on the bus. + error: MessageV2.Assistant.fields.error, }), ), } diff --git a/packages/opencode/src/session/status.ts b/packages/opencode/src/session/status.ts index b9b9fd7e74..e5165a7879 100644 --- a/packages/opencode/src/session/status.ts +++ b/packages/opencode/src/session/status.ts @@ -28,16 +28,16 @@ export type Info = Schema.Schema.Type export const Event = { Status: BusEvent.define( "session.status", - z.object({ - sessionID: SessionID.zod, - status: Info.zod, + Schema.Struct({ + sessionID: SessionID, + status: Info, }), ), // deprecated Idle: BusEvent.define( "session.idle", - z.object({ - sessionID: SessionID.zod, + Schema.Struct({ + sessionID: SessionID, }), ), } diff --git a/packages/opencode/src/session/todo.ts b/packages/opencode/src/session/todo.ts index 257b586ed7..c3a9b106b1 100644 --- a/packages/opencode/src/session/todo.ts +++ b/packages/opencode/src/session/todo.ts @@ -22,9 +22,9 @@ export type Info = Schema.Schema.Type export const Event = { Updated: BusEvent.define( "todo.updated", - z.object({ - sessionID: SessionID.zod, - todos: z.array(Info.zod), + Schema.Struct({ + sessionID: SessionID, + todos: Schema.Array(Info), }), ), } diff --git a/packages/opencode/src/sync/index.ts b/packages/opencode/src/sync/index.ts index 482ad4fbb6..35a5abd0b1 100644 --- a/packages/opencode/src/sync/index.ts +++ b/packages/opencode/src/sync/index.ts @@ -8,51 +8,48 @@ import { EventSequenceTable, EventTable } from "./event.sql" import { WorkspaceContext } from "@/control-plane/workspace-context" import { EventID } from "./schema" import { Flag } from "@/flag/flag" -import { Schema as EffectSchema, Types } from "effect" +import { Schema as EffectSchema } from "effect" import { zodObject } from "@/util/effect-zod" -import { isRecord } from "@/util/record" +import type { DeepMutable } from "@/util/schema" + +// Keep `Event["data"]` mutable because projectors mutate the persisted shape +// when writing to the database. Bus payloads (`Properties`) stay readonly — +// subscribers only read. export type Definition< + Type extends string = string, Schema extends EffectSchema.Top = EffectSchema.Top, BusSchema extends EffectSchema.Top = Schema, > = { - type: string + type: Type version: number aggregate: string - effectSchema: Schema - effectProperties: BusSchema - schema: z.ZodObject - - // This is temporary and only exists for compatibility with bus - // event definitions - properties: z.ZodObject + schema: Schema + // Bus event payload schema. Defaults to `schema` unless `busSchema` was + // passed at definition time (see `session.updated`, whose projector + // expands the persisted data to a `{ sessionID, info }` bus payload). + properties: BusSchema } export type Event = { id: string seq: number aggregateID: string - data: Types.DeepMutable> + data: DeepMutable> } -export type Properties = Types.DeepMutable< - EffectSchema.Schema.Type -> +export type Properties = EffectSchema.Schema.Type export type SerializedEvent = Event & { type: string } type ProjectorFunc = (db: Database.TxOrDb, data: unknown) => void +type ConvertEvent = (type: string, data: Event["data"]) => unknown | Promise export const registry = new Map() let projectors: Map | undefined const versions = new Map() let frozen = false -let convertEvent: (type: string, event: Event["data"]) => Promise | unknown - -function asRecord(input: unknown) { - if (isRecord(input)) return input - throw new Error(`SyncEvent.convertEvent must return an object, got: ${JSON.stringify(input)}`) -} +let convertEvent: ConvertEvent export function reset() { frozen = false @@ -60,7 +57,7 @@ export function reset() { convertEvent = (_, data) => data } -export function init(input: { projectors: Array<[Definition, ProjectorFunc]>; convertEvent?: typeof convertEvent }) { +export function init(input: { projectors: Array<[Definition, ProjectorFunc]>; convertEvent?: ConvertEvent }) { projectors = new Map(input.projectors) // Install all the latest event defs to the bus. We only ever emit @@ -76,7 +73,7 @@ export function init(input: { projectors: Array<[Definition, ProjectorFunc]>; co // Freeze the system so it clearly errors if events are defined // after `init` which would cause bugs frozen = true - convertEvent = input.convertEvent || ((_, data) => data) + convertEvent = input.convertEvent ?? ((_, data) => data) } export function versionedType(type: A): A @@ -96,21 +93,17 @@ export function define< aggregate: Agg schema: Schema busSchema?: BusSchema -}): Definition { +}): Definition { if (frozen) { throw new Error("Error defining sync event: sync system has been frozen") } - const effectProperties = (input.busSchema ?? input.schema) as BusSchema - const def = { type: input.type, version: input.version, aggregate: input.aggregate, - effectSchema: input.schema, - effectProperties, - schema: zodObject(input.schema), - properties: zodObject(effectProperties), + schema: input.schema, + properties: (input.busSchema ?? input.schema) as BusSchema, } versions.set(def.type, Math.max(def.version, versions.get(def.type) || 0)) @@ -167,12 +160,11 @@ function process(def: Def, event: Event, options: { Database.effect(() => { if (options?.publish) { const result = convertEvent(def.type, event.data) + const publish = (data: unknown) => ProjectBus.publish(def, data as Properties) if (result instanceof Promise) { - void result.then((data) => { - void ProjectBus.publish({ type: def.type, properties: def.properties }, asRecord(data)) - }) + void result.then(publish) } else { - void ProjectBus.publish({ type: def.type, properties: def.properties }, asRecord(result)) + void publish(result) } GlobalBus.emit("event", { @@ -292,7 +284,7 @@ export function payloads() { id: z.string(), seq: z.number(), aggregateID: z.literal(def.aggregate), - data: def.schema, + data: zodObject(def.schema), }) .meta({ ref: `SyncEvent.${def.type}`, diff --git a/packages/opencode/src/util/effect-zod.ts b/packages/opencode/src/util/effect-zod.ts index edbbf4d542..24ff9a10e1 100644 --- a/packages/opencode/src/util/effect-zod.ts +++ b/packages/opencode/src/util/effect-zod.ts @@ -59,8 +59,17 @@ function walk(ast: SchemaAST.AST): z.ZodTypeAny { function walkUncached(ast: SchemaAST.AST): z.ZodTypeAny { const override = (ast.annotations as any)?.[ZodOverride] as z.ZodTypeAny | undefined - if (override) return override + // `description` annotations layer on top of an override so callers can + // reuse a shared override schema (e.g. `SessionID`) and still add a + // per-field description on the outer wrapper. + const base = override ?? bodyWithChecks(ast) + const desc = SchemaAST.resolveDescription(ast) + const ref = SchemaAST.resolveIdentifier(ast) + const described = desc ? base.describe(desc) : base + return ref ? described.meta({ ref }) : described +} +function bodyWithChecks(ast: SchemaAST.AST): z.ZodTypeAny { // Schema.Class wraps its fields in a Declaration AST plus an encoding that // constructs the class instance. For the Zod derivation we want the plain // field shape (the decoded/consumer view), not the class instance — so @@ -74,11 +83,7 @@ function walkUncached(ast: SchemaAST.AST): z.ZodTypeAny { const hasEncoding = ast.encoding?.length && ast._tag !== "Declaration" const hasTransform = hasEncoding && !(SchemaAST.isOptional(ast) && extractDefault(ast) !== undefined) const base = hasTransform ? encoded(ast) : body(ast) - const checked = ast.checks?.length ? applyChecks(base, ast.checks, ast) : base - const desc = SchemaAST.resolveDescription(ast) - const ref = SchemaAST.resolveIdentifier(ast) - const described = desc ? checked.describe(desc) : checked - return ref ? described.meta({ ref }) : described + return ast.checks?.length ? applyChecks(base, ast.checks, ast) : base } // Walk the encoded side and apply each link's decode to produce the decoded diff --git a/packages/opencode/src/util/schema.ts b/packages/opencode/src/util/schema.ts index 7f94ee5d1e..0c50482bbd 100644 --- a/packages/opencode/src/util/schema.ts +++ b/packages/opencode/src/util/schema.ts @@ -10,6 +10,34 @@ export const PositiveInt = Schema.Int.check(Schema.isGreaterThan(0)) */ export const NonNegativeInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)) +/** + * Strip `readonly` from a nested type. Stand-in for `effect`'s `Types.DeepMutable` + * until `effect:core/x228my` ("Types.DeepMutable widens unknown to `{}`") lands. + * + * The upstream version falls through `unknown` into `{ -readonly [K in keyof T]: ... }` + * where `keyof unknown = never`, so `unknown` collapses to `{}`. This local + * version gates the object branch on `extends object` (which `unknown` does + * not) so `unknown` passes through untouched. + * + * Primitive bailout matches upstream — without it, branded strings like + * `string & Brand<"SessionID">` fall into the object branch and get their + * prototype methods walked. + * + * Tuple branch preserves readonly tuples (e.g. `ConfigPlugin.Spec`'s + * `readonly [string, Options]`); the general array branch would otherwise + * widen them to unbounded arrays. + */ +// eslint-disable-next-line @typescript-eslint/ban-types +export type DeepMutable = T extends string | number | boolean | bigint | symbol | Function + ? T + : T extends readonly [unknown, ...unknown[]] + ? { -readonly [K in keyof T]: DeepMutable } + : T extends readonly (infer U)[] + ? DeepMutable[] + : T extends object + ? { -readonly [K in keyof T]: DeepMutable } + : T + /** * Attach static methods to a schema object. Designed to be used with `.pipe()`: * @@ -26,13 +54,16 @@ export const withStatics = (schema: S): S & M => Object.assign(schema, methods(schema)) -declare const NewtypeBrand: unique symbol -type NewtypeBrand = { readonly [NewtypeBrand]: Tag } - /** * Nominal wrapper for scalar types. The class itself is a valid schema — * pass it directly to `Schema.decode`, `Schema.decodeEffect`, etc. * + * Overrides `~type.make` on the derived `Schema.Opaque` so `Schema.Schema.Type` + * of a field using this newtype resolves to `Self` rather than the underlying + * branded phantom. Without that override, passing a class instance to code + * typed against `Schema.Schema.Type` would require a cast even + * though the values are structurally equivalent at runtime. + * * @example * class QuestionID extends Newtype()("QuestionID", Schema.String) { * static make(id: string): QuestionID { @@ -44,10 +75,8 @@ type NewtypeBrand = { readonly [NewtypeBrand]: Tag } */ export function Newtype() { return (tag: Tag, schema: S) => { - type Branded = NewtypeBrand - abstract class Base { - declare readonly [NewtypeBrand]: Tag + declare readonly _newtype: Tag static make(value: Schema.Schema.Type): Self { return value as unknown as Self @@ -56,8 +85,10 @@ export function Newtype() { Object.setPrototypeOf(Base, schema) - return Base as unknown as (abstract new (_: never) => Branded) & { + return Base as unknown as (abstract new (_: never) => { readonly _newtype: Tag }) & { readonly make: (value: Schema.Schema.Type) => Self - } & Omit, "make"> + } & Omit, "make" | "~type.make"> & { + readonly "~type.make": Self + } } } diff --git a/packages/opencode/src/worktree/index.ts b/packages/opencode/src/worktree/index.ts index bbebeaa496..e122fe453b 100644 --- a/packages/opencode/src/worktree/index.ts +++ b/packages/opencode/src/worktree/index.ts @@ -13,7 +13,7 @@ import { errorMessage } from "../util/error" import { BusEvent } from "@/bus/bus-event" import { GlobalBus } from "@/bus/global" import { Git } from "@/git" -import { Effect, Layer, Path, Scope, Context, Stream } from "effect" +import { Effect, Layer, Path, Schema, Scope, Context, Stream } from "effect" import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" import { NodePath } from "@effect/platform-node" import { AppFileSystem } from "@opencode-ai/shared/filesystem" @@ -26,15 +26,15 @@ const log = Log.create({ service: "worktree" }) export const Event = { Ready: BusEvent.define( "worktree.ready", - z.object({ - name: z.string(), - branch: z.string(), + Schema.Struct({ + name: Schema.String, + branch: Schema.String, }), ), Failed: BusEvent.define( "worktree.failed", - z.object({ - message: z.string(), + Schema.Struct({ + message: Schema.String, }), ), } diff --git a/packages/opencode/test/bus/bus-effect.test.ts b/packages/opencode/test/bus/bus-effect.test.ts index 6f96a89c87..3d602ae6fd 100644 --- a/packages/opencode/test/bus/bus-effect.test.ts +++ b/packages/opencode/test/bus/bus-effect.test.ts @@ -1,6 +1,5 @@ import { describe, expect } from "bun:test" -import { Deferred, Effect, Layer, Stream } from "effect" -import z from "zod" +import { Deferred, Effect, Layer, Schema, Stream } from "effect" import { Bus } from "../../src/bus" import { BusEvent } from "../../src/bus/bus-event" import { Instance } from "../../src/project/instance" @@ -9,8 +8,8 @@ import { provideInstance, provideTmpdirInstance, tmpdirScoped } from "../fixture import { testEffect } from "../lib/effect" const TestEvent = { - Ping: BusEvent.define("test.effect.ping", z.object({ value: z.number() })), - Pong: BusEvent.define("test.effect.pong", z.object({ message: z.string() })), + Ping: BusEvent.define("test.effect.ping", Schema.Struct({ value: Schema.Number })), + Pong: BusEvent.define("test.effect.pong", Schema.Struct({ message: Schema.String })), } const node = CrossSpawnSpawner.defaultLayer diff --git a/packages/opencode/test/bus/bus-integration.test.ts b/packages/opencode/test/bus/bus-integration.test.ts index e42bd5299e..2808344577 100644 --- a/packages/opencode/test/bus/bus-integration.test.ts +++ b/packages/opencode/test/bus/bus-integration.test.ts @@ -1,11 +1,11 @@ import { afterEach, describe, expect, test } from "bun:test" -import z from "zod" +import { Schema } from "effect" import { Bus } from "../../src/bus" import { BusEvent } from "../../src/bus/bus-event" import { Instance } from "../../src/project/instance" import { tmpdir } from "../fixture/fixture" -const TestEvent = BusEvent.define("test.integration", z.object({ value: z.number() })) +const TestEvent = BusEvent.define("test.integration", Schema.Struct({ value: Schema.Number })) function withInstance(directory: string, fn: () => Promise) { return Instance.provide({ directory, fn }) @@ -42,7 +42,7 @@ describe("Bus integration: acquireRelease subscriber pattern", () => { await using tmp = await tmpdir() const received: Array<{ type: string; value?: number }> = [] - const OtherEvent = BusEvent.define("test.other", z.object({ value: z.number() })) + const OtherEvent = BusEvent.define("test.other", Schema.Struct({ value: Schema.Number })) await withInstance(tmp.path, async () => { Bus.subscribeAll((evt) => { diff --git a/packages/opencode/test/bus/bus.test.ts b/packages/opencode/test/bus/bus.test.ts index 3df179787d..cdacdd5179 100644 --- a/packages/opencode/test/bus/bus.test.ts +++ b/packages/opencode/test/bus/bus.test.ts @@ -1,13 +1,13 @@ import { afterEach, describe, expect, test } from "bun:test" -import z from "zod" +import { Schema } from "effect" import { Bus } from "../../src/bus" import { BusEvent } from "../../src/bus/bus-event" import { Instance } from "../../src/project/instance" import { tmpdir } from "../fixture/fixture" const TestEvent = { - Ping: BusEvent.define("test.ping", z.object({ value: z.number() })), - Pong: BusEvent.define("test.pong", z.object({ message: z.string() })), + Ping: BusEvent.define("test.ping", Schema.Struct({ value: Schema.Number })), + Pong: BusEvent.define("test.pong", Schema.Struct({ message: Schema.String })), } function withInstance(directory: string, fn: () => Promise) { diff --git a/packages/opencode/test/session/session.test.ts b/packages/opencode/test/session/session.test.ts index f63ad9beed..d4a1d711d8 100644 --- a/packages/opencode/test/session/session.test.ts +++ b/packages/opencode/test/session/session.test.ts @@ -111,9 +111,12 @@ describe("step-finish token propagation via Bus event", () => { mode: "", } as unknown as MessageV2.Info) + // Bus subscribers receive readonly Schema.Type payloads; `MessageV2.Part` + // is the mutable domain type. Cast bridges the two — safe because the + // test only reads the value afterwards. let received: MessageV2.Part | undefined const unsub = Bus.subscribe(MessageV2.Event.PartUpdated, (event) => { - received = event.properties.part + received = event.properties.part as MessageV2.Part }) const tokens = { From 24892559ae10e8df5bde8211b7e4c7a6851f3de6 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Thu, 23 Apr 2026 19:38:54 +0000 Subject: [PATCH 43/92] chore: generate --- .../opencode/src/server/routes/instance/tui.ts | 5 ++++- packages/sdk/openapi.json | 18 ++---------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/packages/opencode/src/server/routes/instance/tui.ts b/packages/opencode/src/server/routes/instance/tui.ts index a610590e87..932cf509eb 100644 --- a/packages/opencode/src/server/routes/instance/tui.ts +++ b/packages/opencode/src/server/routes/instance/tui.ts @@ -310,7 +310,10 @@ export const TuiRoutes = lazy(() => }), validator("json", zodObject(TuiEvent.ToastShow.properties)), async (c) => { - await Bus.publish(TuiEvent.ToastShow, c.req.valid("json") as Schema.Schema.Type) + await Bus.publish( + TuiEvent.ToastShow, + c.req.valid("json") as Schema.Schema.Type, + ) return c.json(true) }, ) diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index e54648e198..0c3d189722 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -6804,7 +6804,6 @@ }, "duration": { "description": "Duration in milliseconds", - "default": 5000, "type": "number" } }, @@ -7638,20 +7637,8 @@ "type": "string" }, "event": { - "anyOf": [ - { - "type": "string", - "const": "add" - }, - { - "type": "string", - "const": "change" - }, - { - "type": "string", - "const": "unlink" - } - ] + "type": "string", + "enum": ["add", "change", "unlink"] } }, "required": ["file", "event"] @@ -8507,7 +8494,6 @@ }, "duration": { "description": "Duration in milliseconds", - "default": 5000, "type": "number" } }, From 3910a6e527c87f514c479a1c1c3d6d5f4d1aa315 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 23 Apr 2026 16:09:34 -0400 Subject: [PATCH 44/92] refactor(tool): migrate tool framework + all 18 built-in tools to Effect Schema (#23244) --- .../server/routes/instance/experimental.ts | 3 +- packages/opencode/src/session/prompt.ts | 3 +- packages/opencode/src/tool/apply_patch.ts | 13 +- packages/opencode/src/tool/bash.ts | 26 +- packages/opencode/src/tool/codesearch.ts | 35 +- packages/opencode/src/tool/edit.ts | 19 +- packages/opencode/src/tool/glob.ts | 20 +- packages/opencode/src/tool/grep.ts | 18 +- packages/opencode/src/tool/invalid.ts | 13 +- packages/opencode/src/tool/lsp.ts | 21 +- packages/opencode/src/tool/plan.ts | 7 +- packages/opencode/src/tool/question.ts | 13 +- packages/opencode/src/tool/read.ts | 26 +- packages/opencode/src/tool/registry.ts | 12 +- packages/opencode/src/tool/skill.ts | 9 +- packages/opencode/src/tool/task.ts | 27 +- packages/opencode/src/tool/todo.ts | 37 +- packages/opencode/src/tool/tool.ts | 55 +- packages/opencode/src/tool/webfetch.ts | 22 +- packages/opencode/src/tool/websearch.ts | 35 +- packages/opencode/src/tool/write.ts | 14 +- packages/opencode/src/util/effect-zod.ts | 11 + .../__snapshots__/parameters.test.ts.snap | 495 ++++++++++++++++++ .../opencode/test/tool/parameters.test.ts | 260 +++++++++ .../opencode/test/tool/tool-define.test.ts | 46 +- 25 files changed, 1035 insertions(+), 205 deletions(-) create mode 100644 packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap create mode 100644 packages/opencode/test/tool/parameters.test.ts diff --git a/packages/opencode/src/server/routes/instance/experimental.ts b/packages/opencode/src/server/routes/instance/experimental.ts index 93a5d98c94..f13003cb4e 100644 --- a/packages/opencode/src/server/routes/instance/experimental.ts +++ b/packages/opencode/src/server/routes/instance/experimental.ts @@ -1,6 +1,7 @@ import { Hono } from "hono" import { describeRoute, validator, resolver } from "hono-openapi" import z from "zod" +import * as EffectZod from "@/util/effect-zod" import { ProviderID, ModelID } from "@/provider/schema" import { ToolRegistry } from "@/tool" import { Worktree } from "@/worktree" @@ -213,7 +214,7 @@ export const ExperimentalRoutes = lazy(() => tools.map((t) => ({ id: t.id, description: t.description, - parameters: z.toJSONSchema(t.parameters), + parameters: EffectZod.toJsonSchema(t.parameters), })), ) }, diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 0f48eb64ec..5f3530bcef 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -1,6 +1,7 @@ import path from "path" import os from "os" import z from "zod" +import * as EffectZod from "@/util/effect-zod" import { SessionID, MessageID, PartID } from "./schema" import { MessageV2 } from "./message-v2" import { Log } from "../util" @@ -405,7 +406,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the providerID: input.model.providerID, agent: input.agent, })) { - const schema = ProviderTransform.schema(input.model, z.toJSONSchema(item.parameters)) + const schema = ProviderTransform.schema(input.model, EffectZod.toJsonSchema(item.parameters)) tools[item.id] = tool({ description: item.description, inputSchema: jsonSchema(schema), diff --git a/packages/opencode/src/tool/apply_patch.ts b/packages/opencode/src/tool/apply_patch.ts index 33112c43c5..effc428c71 100644 --- a/packages/opencode/src/tool/apply_patch.ts +++ b/packages/opencode/src/tool/apply_patch.ts @@ -1,6 +1,5 @@ -import z from "zod" import * as path from "path" -import { Effect } from "effect" +import { Effect, Schema } from "effect" import * as Tool from "./tool" import { Bus } from "../bus" import { FileWatcher } from "../file/watcher" @@ -16,8 +15,8 @@ import { File } from "../file" import { Format } from "../format" import * as Bom from "@/util/bom" -const PatchParams = z.object({ - patchText: z.string().describe("The full patch text that describes all changes to be made"), +export const Parameters = Schema.Struct({ + patchText: Schema.String.annotate({ description: "The full patch text that describes all changes to be made" }), }) export const ApplyPatchTool = Tool.define( @@ -28,7 +27,7 @@ export const ApplyPatchTool = Tool.define( const format = yield* Format.Service const bus = yield* Bus.Service - const run = Effect.fn("ApplyPatchTool.execute")(function* (params: z.infer, ctx: Tool.Context) { + const run = Effect.fn("ApplyPatchTool.execute")(function* (params: Schema.Schema.Type, ctx: Tool.Context) { if (!params.patchText) { return yield* Effect.fail(new Error("patchText is required")) } @@ -297,8 +296,8 @@ export const ApplyPatchTool = Tool.define( return { description: DESCRIPTION, - parameters: PatchParams, - execute: (params: z.infer, ctx: Tool.Context) => run(params, ctx).pipe(Effect.orDie), + parameters: Parameters, + execute: (params: Schema.Schema.Type, ctx: Tool.Context) => run(params, ctx).pipe(Effect.orDie), } }), ) diff --git a/packages/opencode/src/tool/bash.ts b/packages/opencode/src/tool/bash.ts index 6260b22216..2d4d59b1bf 100644 --- a/packages/opencode/src/tool/bash.ts +++ b/packages/opencode/src/tool/bash.ts @@ -1,4 +1,4 @@ -import z from "zod" +import { Schema } from "effect" import os from "os" import { createWriteStream } from "node:fs" import * as Tool from "./tool" @@ -50,20 +50,16 @@ const FILES = new Set([ const FLAGS = new Set(["-destination", "-literalpath", "-path"]) const SWITCHES = new Set(["-confirm", "-debug", "-force", "-nonewline", "-recurse", "-verbose", "-whatif"]) -const Parameters = z.object({ - command: z.string().describe("The command to execute"), - timeout: z.number().describe("Optional timeout in milliseconds").optional(), - workdir: z - .string() - .describe( - `The working directory to run the command in. Defaults to the current directory. Use this instead of 'cd' commands.`, - ) - .optional(), - description: z - .string() - .describe( +export const Parameters = Schema.Struct({ + command: Schema.String.annotate({ description: "The command to execute" }), + timeout: Schema.optional(Schema.Number).annotate({ description: "Optional timeout in milliseconds" }), + workdir: Schema.optional(Schema.String).annotate({ + description: `The working directory to run the command in. Defaults to the current directory. Use this instead of 'cd' commands.`, + }), + description: Schema.String.annotate({ + description: "Clear, concise description of what this command does in 5-10 words. Examples:\nInput: ls\nOutput: Lists files in current directory\n\nInput: git status\nOutput: Shows working tree status\n\nInput: npm install\nOutput: Installs package dependencies\n\nInput: mkdir foo\nOutput: Creates directory 'foo'", - ), + }), }) type Part = { @@ -587,7 +583,7 @@ export const BashTool = Tool.define( .replaceAll("${maxLines}", String(Truncate.MAX_LINES)) .replaceAll("${maxBytes}", String(Truncate.MAX_BYTES)), parameters: Parameters, - execute: (params: z.infer, ctx: Tool.Context) => + execute: (params: Schema.Schema.Type, ctx: Tool.Context) => Effect.gen(function* () { const cwd = params.workdir ? yield* resolvePath(params.workdir, Instance.directory, shell) diff --git a/packages/opencode/src/tool/codesearch.ts b/packages/opencode/src/tool/codesearch.ts index ac9961e250..e10d21175e 100644 --- a/packages/opencode/src/tool/codesearch.ts +++ b/packages/opencode/src/tool/codesearch.ts @@ -1,10 +1,23 @@ -import z from "zod" -import { Effect } from "effect" +import { Effect, Schema } from "effect" import { HttpClient } from "effect/unstable/http" import * as Tool from "./tool" import * as McpExa from "./mcp-exa" import DESCRIPTION from "./codesearch.txt" +export const Parameters = Schema.Struct({ + query: Schema.String.annotate({ + description: + "Search query to find relevant context for APIs, Libraries, and SDKs. For example, 'React useState hook examples', 'Python pandas dataframe filtering', 'Express.js middleware', 'Next js partial prerendering configuration'", + }), + tokensNum: Schema.Number.check(Schema.isGreaterThanOrEqualTo(1000)) + .check(Schema.isLessThanOrEqualTo(50000)) + .pipe(Schema.optional, Schema.withDecodingDefault(Effect.succeed(5000))) + .annotate({ + description: + "Number of tokens to return (1000-50000). Default is 5000 tokens. Adjust this value based on how much context you need - use lower values for focused queries and higher values for comprehensive documentation.", + }), +}) + export const CodeSearchTool = Tool.define( "codesearch", Effect.gen(function* () { @@ -12,21 +25,7 @@ export const CodeSearchTool = Tool.define( return { description: DESCRIPTION, - parameters: z.object({ - query: z - .string() - .describe( - "Search query to find relevant context for APIs, Libraries, and SDKs. For example, 'React useState hook examples', 'Python pandas dataframe filtering', 'Express.js middleware', 'Next js partial prerendering configuration'", - ), - tokensNum: z - .number() - .min(1000) - .max(50000) - .default(5000) - .describe( - "Number of tokens to return (1000-50000). Default is 5000 tokens. Adjust this value based on how much context you need - use lower values for focused queries and higher values for comprehensive documentation.", - ), - }), + parameters: Parameters, execute: (params: { query: string; tokensNum: number }, ctx: Tool.Context) => Effect.gen(function* () { yield* ctx.ask({ @@ -45,7 +44,7 @@ export const CodeSearchTool = Tool.define( McpExa.CodeArgs, { query: params.query, - tokensNum: params.tokensNum || 5000, + tokensNum: params.tokensNum, }, "30 seconds", ) diff --git a/packages/opencode/src/tool/edit.ts b/packages/opencode/src/tool/edit.ts index 35dd85b476..cfff5a0a30 100644 --- a/packages/opencode/src/tool/edit.ts +++ b/packages/opencode/src/tool/edit.ts @@ -3,9 +3,8 @@ // https://github.com/google-gemini/gemini-cli/blob/main/packages/core/src/utils/editCorrector.ts // https://github.com/cline/cline/blob/main/evals/diff-edits/diff-apply/diff-06-26-25.ts -import z from "zod" import * as path from "path" -import { Effect, Semaphore } from "effect" +import { Effect, Schema, Semaphore } from "effect" import * as Tool from "./tool" import { LSP } from "../lsp" import { createTwoFilesPatch, diffLines } from "diff" @@ -45,11 +44,15 @@ function lock(filePath: string) { return next } -const Parameters = z.object({ - filePath: z.string().describe("The absolute path to the file to modify"), - oldString: z.string().describe("The text to replace"), - newString: z.string().describe("The text to replace it with (must be different from oldString)"), - replaceAll: z.boolean().optional().describe("Replace all occurrences of oldString (default false)"), +export const Parameters = Schema.Struct({ + filePath: Schema.String.annotate({ description: "The absolute path to the file to modify" }), + oldString: Schema.String.annotate({ description: "The text to replace" }), + newString: Schema.String.annotate({ + description: "The text to replace it with (must be different from oldString)", + }), + replaceAll: Schema.optional(Schema.Boolean).annotate({ + description: "Replace all occurrences of oldString (default false)", + }), }) export const EditTool = Tool.define( @@ -63,7 +66,7 @@ export const EditTool = Tool.define( return { description: DESCRIPTION, parameters: Parameters, - execute: (params: z.infer, ctx: Tool.Context) => + execute: (params: Schema.Schema.Type, ctx: Tool.Context) => Effect.gen(function* () { if (!params.filePath) { throw new Error("filePath is required") diff --git a/packages/opencode/src/tool/glob.ts b/packages/opencode/src/tool/glob.ts index 673bb9cc8f..aeecfecb72 100644 --- a/packages/opencode/src/tool/glob.ts +++ b/packages/opencode/src/tool/glob.ts @@ -1,6 +1,5 @@ import path from "path" -import z from "zod" -import { Effect, Option } from "effect" +import { Effect, Option, Schema } from "effect" import * as Stream from "effect/Stream" import { InstanceState } from "@/effect" import { AppFileSystem } from "@opencode-ai/shared/filesystem" @@ -9,6 +8,13 @@ import { assertExternalDirectoryEffect } from "./external-directory" import DESCRIPTION from "./glob.txt" import * as Tool from "./tool" +export const Parameters = Schema.Struct({ + pattern: Schema.String.annotate({ description: "The glob pattern to match files against" }), + path: Schema.optional(Schema.String).annotate({ + description: `The directory to search in. If not specified, the current working directory will be used. IMPORTANT: Omit this field to use the default directory. DO NOT enter "undefined" or "null" - simply omit it for the default behavior. Must be a valid directory path if provided.`, + }), +}) + export const GlobTool = Tool.define( "glob", Effect.gen(function* () { @@ -17,15 +23,7 @@ export const GlobTool = Tool.define( return { description: DESCRIPTION, - parameters: z.object({ - pattern: z.string().describe("The glob pattern to match files against"), - path: z - .string() - .optional() - .describe( - `The directory to search in. If not specified, the current working directory will be used. IMPORTANT: Omit this field to use the default directory. DO NOT enter "undefined" or "null" - simply omit it for the default behavior. Must be a valid directory path if provided.`, - ), - }), + parameters: Parameters, execute: (params: { pattern: string; path?: string }, ctx: Tool.Context) => Effect.gen(function* () { const ins = yield* InstanceState.context diff --git a/packages/opencode/src/tool/grep.ts b/packages/opencode/src/tool/grep.ts index caa75edad5..4160054311 100644 --- a/packages/opencode/src/tool/grep.ts +++ b/packages/opencode/src/tool/grep.ts @@ -1,5 +1,5 @@ import path from "path" -import z from "zod" +import { Schema } from "effect" import { Effect, Option } from "effect" import { InstanceState } from "@/effect" import { AppFileSystem } from "@opencode-ai/shared/filesystem" @@ -10,6 +10,16 @@ import * as Tool from "./tool" const MAX_LINE_LENGTH = 2000 +export const Parameters = Schema.Struct({ + pattern: Schema.String.annotate({ description: "The regex pattern to search for in file contents" }), + path: Schema.optional(Schema.String).annotate({ + description: "The directory to search in. Defaults to the current working directory.", + }), + include: Schema.optional(Schema.String).annotate({ + description: 'File pattern to include in the search (e.g. "*.js", "*.{ts,tsx}")', + }), +}) + export const GrepTool = Tool.define( "grep", Effect.gen(function* () { @@ -18,11 +28,7 @@ export const GrepTool = Tool.define( return { description: DESCRIPTION, - parameters: z.object({ - pattern: z.string().describe("The regex pattern to search for in file contents"), - path: z.string().optional().describe("The directory to search in. Defaults to the current working directory."), - include: z.string().optional().describe('File pattern to include in the search (e.g. "*.js", "*.{ts,tsx}")'), - }), + parameters: Parameters, execute: (params: { pattern: string; path?: string; include?: string }, ctx: Tool.Context) => Effect.gen(function* () { const empty = { diff --git a/packages/opencode/src/tool/invalid.ts b/packages/opencode/src/tool/invalid.ts index aca3618b6d..b8d145d0be 100644 --- a/packages/opencode/src/tool/invalid.ts +++ b/packages/opencode/src/tool/invalid.ts @@ -1,15 +1,16 @@ -import z from "zod" -import { Effect } from "effect" +import { Effect, Schema } from "effect" import * as Tool from "./tool" +export const Parameters = Schema.Struct({ + tool: Schema.String, + error: Schema.String, +}) + export const InvalidTool = Tool.define( "invalid", Effect.succeed({ description: "Do not use", - parameters: z.object({ - tool: z.string(), - error: z.string(), - }), + parameters: Parameters, execute: (params: { tool: string; error: string }) => Effect.succeed({ title: "Invalid Tool", diff --git a/packages/opencode/src/tool/lsp.ts b/packages/opencode/src/tool/lsp.ts index 0a0edc61ed..29c6a8d843 100644 --- a/packages/opencode/src/tool/lsp.ts +++ b/packages/opencode/src/tool/lsp.ts @@ -1,5 +1,4 @@ -import z from "zod" -import { Effect } from "effect" +import { Effect, Schema } from "effect" import * as Tool from "./tool" import path from "path" import { LSP } from "../lsp" @@ -21,6 +20,17 @@ const operations = [ "outgoingCalls", ] as const +export const Parameters = Schema.Struct({ + operation: Schema.Literals(operations).annotate({ description: "The LSP operation to perform" }), + filePath: Schema.String.annotate({ description: "The absolute or relative path to the file" }), + line: Schema.Number.check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(1)) + .annotate({ description: "The line number (1-based, as shown in editors)" }), + character: Schema.Number.check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(1)) + .annotate({ description: "The character offset (1-based, as shown in editors)" }), +}) + export const LspTool = Tool.define( "lsp", Effect.gen(function* () { @@ -29,12 +39,7 @@ export const LspTool = Tool.define( return { description: DESCRIPTION, - parameters: z.object({ - operation: z.enum(operations).describe("The LSP operation to perform"), - filePath: z.string().describe("The absolute or relative path to the file"), - line: z.number().int().min(1).describe("The line number (1-based, as shown in editors)"), - character: z.number().int().min(1).describe("The character offset (1-based, as shown in editors)"), - }), + parameters: Parameters, execute: ( args: { operation: (typeof operations)[number]; filePath: string; line: number; character: number }, ctx: Tool.Context, diff --git a/packages/opencode/src/tool/plan.ts b/packages/opencode/src/tool/plan.ts index fd7276e09c..8e2f11360e 100644 --- a/packages/opencode/src/tool/plan.ts +++ b/packages/opencode/src/tool/plan.ts @@ -1,6 +1,5 @@ -import z from "zod" import path from "path" -import { Effect } from "effect" +import { Effect, Schema } from "effect" import * as Tool from "./tool" import { Question } from "../question" import { Session } from "../session" @@ -17,6 +16,8 @@ function getLastModel(sessionID: SessionID) { return undefined } +export const Parameters = Schema.Struct({}) + export const PlanExitTool = Tool.define( "plan_exit", Effect.gen(function* () { @@ -26,7 +27,7 @@ export const PlanExitTool = Tool.define( return { description: EXIT_DESCRIPTION, - parameters: z.object({}), + parameters: Parameters, execute: (_params: {}, ctx: Tool.Context) => Effect.gen(function* () { const info = yield* session.get(ctx.sessionID) diff --git a/packages/opencode/src/tool/question.ts b/packages/opencode/src/tool/question.ts index e5bb33aa69..51f1e71e28 100644 --- a/packages/opencode/src/tool/question.ts +++ b/packages/opencode/src/tool/question.ts @@ -1,26 +1,25 @@ -import z from "zod" -import { Effect } from "effect" +import { Effect, Schema } from "effect" import * as Tool from "./tool" import { Question } from "../question" import DESCRIPTION from "./question.txt" -const parameters = z.object({ - questions: z.array(Question.Prompt.zod).describe("Questions to ask"), +export const Parameters = Schema.Struct({ + questions: Schema.mutable(Schema.Array(Question.Prompt)).annotate({ description: "Questions to ask" }), }) type Metadata = { answers: ReadonlyArray } -export const QuestionTool = Tool.define( +export const QuestionTool = Tool.define( "question", Effect.gen(function* () { const question = yield* Question.Service return { description: DESCRIPTION, - parameters, - execute: (params: z.infer, ctx: Tool.Context) => + parameters: Parameters, + execute: (params: Schema.Schema.Type, ctx: Tool.Context) => Effect.gen(function* () { const answers = yield* question.ask({ sessionID: ctx.sessionID, diff --git a/packages/opencode/src/tool/read.ts b/packages/opencode/src/tool/read.ts index a9b95346a1..e7bfc6af33 100644 --- a/packages/opencode/src/tool/read.ts +++ b/packages/opencode/src/tool/read.ts @@ -1,5 +1,4 @@ -import z from "zod" -import { Effect, Option, Scope } from "effect" +import { Effect, Option, Schema, Scope } from "effect" import { createReadStream } from "fs" import * as path from "path" import { createInterface } from "readline" @@ -19,10 +18,19 @@ const MAX_BYTES = 50 * 1024 const MAX_BYTES_LABEL = `${MAX_BYTES / 1024} KB` const SAMPLE_BYTES = 4096 -const parameters = z.object({ - filePath: z.string().describe("The absolute path to the file or directory to read"), - offset: z.coerce.number().describe("The line number to start reading from (1-indexed)").optional(), - limit: z.coerce.number().describe("The maximum number of lines to read (defaults to 2000)").optional(), +// `offset` and `limit` were originally `z.coerce.number()` — the runtime +// coercion was useful when the tool was called from a shell but serves no +// purpose in the LLM tool-call path (the model emits typed JSON). The JSON +// Schema output is identical (`type: "number"`), so the LLM view is +// unchanged; purely CLI-facing uses must now send numbers rather than strings. +export const Parameters = Schema.Struct({ + filePath: Schema.String.annotate({ description: "The absolute path to the file or directory to read" }), + offset: Schema.optional(Schema.Number).annotate({ + description: "The line number to start reading from (1-indexed)", + }), + limit: Schema.optional(Schema.Number).annotate({ + description: "The maximum number of lines to read (defaults to 2000)", + }), }) export const ReadTool = Tool.define( @@ -140,7 +148,7 @@ export const ReadTool = Tool.define( return nonPrintableCount / bytes.length > 0.3 } - const run = Effect.fn("ReadTool.execute")(function* (params: z.infer, ctx: Tool.Context) { + const run = Effect.fn("ReadTool.execute")(function* (params: Schema.Schema.Type, ctx: Tool.Context) { if (params.offset !== undefined && params.offset < 1) { return yield* Effect.fail(new Error("offset must be greater than or equal to 1")) } @@ -275,8 +283,8 @@ export const ReadTool = Tool.define( return { description: DESCRIPTION, - parameters, - execute: (params: z.infer, ctx: Tool.Context) => run(params, ctx).pipe(Effect.orDie), + parameters: Parameters, + execute: (params: Schema.Schema.Type, ctx: Tool.Context) => run(params, ctx).pipe(Effect.orDie), } }), ) diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts index 0211e33bcb..539ad63202 100644 --- a/packages/opencode/src/tool/registry.ts +++ b/packages/opencode/src/tool/registry.ts @@ -15,7 +15,9 @@ import { SkillTool } from "./skill" import * as Tool from "./tool" import { Config } from "../config" import { type ToolContext as PluginToolContext, type ToolDefinition } from "@opencode-ai/plugin" +import { Schema } from "effect" import z from "zod" +import { ZodOverride } from "@/util/effect-zod" import { Plugin } from "../plugin" import { Provider } from "../provider" import { ProviderID, type ModelID } from "../provider/schema" @@ -120,9 +122,17 @@ export const layer: Layer.Layer< const custom: Tool.Def[] = [] function fromPlugin(id: string, def: ToolDefinition): Tool.Def { + // Plugin tools define their args as a raw Zod shape. Wrap the + // derived Zod object in a `Schema.declare` so it slots into the + // Schema-typed framework, and annotate with `ZodOverride` so the + // walker emits the original Zod object for LLM JSON Schema. + const zodParams = z.object(def.args) + const parameters = Schema.declare((u): u is unknown => zodParams.safeParse(u).success).annotate({ + [ZodOverride]: zodParams, + }) return { id, - parameters: z.object(def.args), + parameters, description: def.description, execute: (args, toolCtx) => Effect.gen(function* () { diff --git a/packages/opencode/src/tool/skill.ts b/packages/opencode/src/tool/skill.ts index d86faec2b4..8c41077be5 100644 --- a/packages/opencode/src/tool/skill.ts +++ b/packages/opencode/src/tool/skill.ts @@ -1,15 +1,14 @@ import path from "path" import { pathToFileURL } from "url" -import z from "zod" -import { Effect } from "effect" +import { Effect, Schema } from "effect" import * as Stream from "effect/Stream" import { Ripgrep } from "../file/ripgrep" import { Skill } from "../skill" import * as Tool from "./tool" import DESCRIPTION from "./skill.txt" -const Parameters = z.object({ - name: z.string().describe("The name of the skill from available_skills"), +export const Parameters = Schema.Struct({ + name: Schema.String.annotate({ description: "The name of the skill from available_skills" }), }) export const SkillTool = Tool.define( @@ -21,7 +20,7 @@ export const SkillTool = Tool.define( return { description: DESCRIPTION, parameters: Parameters, - execute: (params: z.infer, ctx: Tool.Context) => + execute: (params: Schema.Schema.Type, ctx: Tool.Context) => Effect.gen(function* () { const info = yield* skill.get(params.name) if (!info) { diff --git a/packages/opencode/src/tool/task.ts b/packages/opencode/src/tool/task.ts index 3da0664f3d..98f6bdd98f 100644 --- a/packages/opencode/src/tool/task.ts +++ b/packages/opencode/src/tool/task.ts @@ -1,13 +1,12 @@ import * as Tool from "./tool" import DESCRIPTION from "./task.txt" -import z from "zod" import { Session } from "../session" import { SessionID, MessageID } from "../session/schema" import { MessageV2 } from "../session/message-v2" import { Agent } from "../agent/agent" import type { SessionPrompt } from "../session/prompt" import { Config } from "../config" -import { Effect } from "effect" +import { Effect, Schema } from "effect" export interface TaskPromptOps { cancel(sessionID: SessionID): void @@ -17,17 +16,15 @@ export interface TaskPromptOps { const id = "task" -const parameters = z.object({ - description: z.string().describe("A short (3-5 words) description of the task"), - prompt: z.string().describe("The task for the agent to perform"), - subagent_type: z.string().describe("The type of specialized agent to use for this task"), - task_id: z - .string() - .describe( +export const Parameters = Schema.Struct({ + description: Schema.String.annotate({ description: "A short (3-5 words) description of the task" }), + prompt: Schema.String.annotate({ description: "The task for the agent to perform" }), + subagent_type: Schema.String.annotate({ description: "The type of specialized agent to use for this task" }), + task_id: Schema.optional(Schema.String).annotate({ + description: "This should only be set if you mean to resume a previous task (you can pass a prior task_id and the task will continue the same subagent session as before instead of creating a fresh one)", - ) - .optional(), - command: z.string().describe("The command that triggered this task").optional(), + }), + command: Schema.optional(Schema.String).annotate({ description: "The command that triggered this task" }), }) export const TaskTool = Tool.define( @@ -37,7 +34,7 @@ export const TaskTool = Tool.define( const config = yield* Config.Service const sessions = yield* Session.Service - const run = Effect.fn("TaskTool.execute")(function* (params: z.infer, ctx: Tool.Context) { + const run = Effect.fn("TaskTool.execute")(function* (params: Schema.Schema.Type, ctx: Tool.Context) { const cfg = yield* config.get() if (!ctx.extra?.bypassAgentCheck) { @@ -168,8 +165,8 @@ export const TaskTool = Tool.define( return { description: DESCRIPTION, - parameters, - execute: (params: z.infer, ctx: Tool.Context) => run(params, ctx).pipe(Effect.orDie), + parameters: Parameters, + execute: (params: Schema.Schema.Type, ctx: Tool.Context) => run(params, ctx).pipe(Effect.orDie), } }), ) diff --git a/packages/opencode/src/tool/todo.ts b/packages/opencode/src/tool/todo.ts index c08fb04119..c493d3a71a 100644 --- a/packages/opencode/src/tool/todo.ts +++ b/packages/opencode/src/tool/todo.ts @@ -1,39 +1,34 @@ -import z from "zod" -import { Effect } from "effect" +import { Effect, Schema } from "effect" import * as Tool from "./tool" import DESCRIPTION_WRITE from "./todowrite.txt" import { Todo } from "../session/todo" -// Parameters are kept inline rather than derived from Todo.Info because -// Tool.define requires z.ZodObject-typed parameters for execute() inference, -// and zodObject(Todo.Info) returns ZodObject — reaching into .shape would -// erase field types. Tool schemas migrate to Effect Schema as a separate slice -// per specs/effect/schema.md. -const parameters = z.object({ - todos: z - .array( - z.object({ - content: z.string().describe("Brief description of the task"), - status: z.string().describe("Current status of the task: pending, in_progress, completed, cancelled"), - priority: z.string().describe("Priority level of the task: high, medium, low"), - }), - ) - .describe("The updated todo list"), +// Todo.Info is still a zod schema (session/todo.ts). Inline the field shape +// here rather than referencing its `.shape` — the LLM-visible JSON Schema is +// identical, and it removes the last zod dependency from this tool. +const TodoItem = Schema.Struct({ + content: Schema.String.annotate({ description: "Brief description of the task" }), + status: Schema.String.annotate({ description: "Current status of the task: pending, in_progress, completed, cancelled" }), + priority: Schema.String.annotate({ description: "Priority level of the task: high, medium, low" }), +}) + +export const Parameters = Schema.Struct({ + todos: Schema.mutable(Schema.Array(TodoItem)).annotate({ description: "The updated todo list" }), }) type Metadata = { todos: Todo.Info[] } -export const TodoWriteTool = Tool.define( +export const TodoWriteTool = Tool.define( "todowrite", Effect.gen(function* () { const todo = yield* Todo.Service return { description: DESCRIPTION_WRITE, - parameters, - execute: (params: z.infer, ctx: Tool.Context) => + parameters: Parameters, + execute: (params: Schema.Schema.Type, ctx: Tool.Context) => Effect.gen(function* () { yield* ctx.ask({ permission: "todowrite", @@ -55,6 +50,6 @@ export const TodoWriteTool = Tool.define + } satisfies Tool.DefWithoutID }), ) diff --git a/packages/opencode/src/tool/tool.ts b/packages/opencode/src/tool/tool.ts index 179149afd2..c9115e9ff1 100644 --- a/packages/opencode/src/tool/tool.ts +++ b/packages/opencode/src/tool/tool.ts @@ -1,5 +1,4 @@ -import z from "zod" -import { Effect } from "effect" +import { Effect, Schema } from "effect" import type { MessageV2 } from "../session/message-v2" import type { Permission } from "../permission" import type { SessionID, MessageID } from "../session/schema" @@ -32,29 +31,33 @@ export interface ExecuteResult { attachments?: Omit[] } -export interface Def { +export interface Def = Schema.Decoder, M extends Metadata = Metadata> { id: string description: string parameters: Parameters - execute(args: z.infer, ctx: Context): Effect.Effect> - formatValidationError?(error: z.ZodError): string + execute(args: Schema.Schema.Type, ctx: Context): Effect.Effect> + formatValidationError?(error: unknown): string } -export type DefWithoutID = Omit< +export type DefWithoutID = Schema.Decoder, M extends Metadata = Metadata> = Omit< Def, "id" > -export interface Info { +export interface Info = Schema.Decoder, M extends Metadata = Metadata> { id: string init: () => Effect.Effect> } -type Init = +type Init, M extends Metadata> = | DefWithoutID | (() => Effect.Effect>) export type InferParameters = - T extends Info ? z.infer

    : T extends Effect.Effect, any, any> ? z.infer

    : never + T extends Info + ? Schema.Schema.Type

    + : T extends Effect.Effect, any, any> + ? Schema.Schema.Type

    + : never export type InferMetadata = T extends Info ? M : T extends Effect.Effect, any, any> ? M : never @@ -65,7 +68,7 @@ export type InferDef = ? Def : never -function wrap( +function wrap, Result extends Metadata>( id: string, init: Init, truncate: Truncate.Interface, @@ -74,6 +77,10 @@ function wrap( return () => Effect.gen(function* () { const toolInfo = typeof init === "function" ? { ...(yield* init()) } : { ...init } + // Compile the parser closure once per tool init; `decodeUnknownEffect` + // allocates a new closure per call, so hoisting avoids re-closing it for + // every LLM tool invocation. + const decode = Schema.decodeUnknownEffect(toolInfo.parameters) const execute = toolInfo.execute toolInfo.execute = (args, ctx) => { const attrs = { @@ -83,19 +90,17 @@ function wrap( ...(ctx.callID ? { "tool.call_id": ctx.callID } : {}), } return Effect.gen(function* () { - yield* Effect.try({ - try: () => toolInfo.parameters.parse(args), - catch: (error) => { - if (error instanceof z.ZodError && toolInfo.formatValidationError) { - return new Error(toolInfo.formatValidationError(error), { cause: error }) - } - return new Error( - `The ${id} tool was called with invalid arguments: ${error}.\nPlease rewrite the input so it satisfies the expected schema.`, - { cause: error }, - ) - }, - }) - const result = yield* execute(args, ctx) + const decoded = yield* decode(args).pipe( + Effect.mapError((error) => + toolInfo.formatValidationError + ? new Error(toolInfo.formatValidationError(error), { cause: error }) + : new Error( + `The ${id} tool was called with invalid arguments: ${error}.\nPlease rewrite the input so it satisfies the expected schema.`, + { cause: error }, + ), + ), + ) + const result = yield* execute(decoded as Schema.Schema.Type, ctx) if (result.metadata.truncated !== undefined) { return result } @@ -116,7 +121,7 @@ function wrap( }) } -export function define( +export function define, Result extends Metadata, R, ID extends string = string>( id: ID, init: Effect.Effect, never, R>, ): Effect.Effect, never, R | Truncate.Service | Agent.Service> & { id: ID } { @@ -131,7 +136,7 @@ export function define(info: Info): Effect.Effect> { +export function init

    , M extends Metadata>(info: Info): Effect.Effect> { return Effect.gen(function* () { const init = yield* info.init() return { diff --git a/packages/opencode/src/tool/webfetch.ts b/packages/opencode/src/tool/webfetch.ts index 1d988b8d4f..d2561a1301 100644 --- a/packages/opencode/src/tool/webfetch.ts +++ b/packages/opencode/src/tool/webfetch.ts @@ -1,5 +1,4 @@ -import z from "zod" -import { Effect } from "effect" +import { Effect, Schema } from "effect" import { HttpClient, HttpClientRequest } from "effect/unstable/http" import * as Tool from "./tool" import TurndownService from "turndown" @@ -10,13 +9,14 @@ const MAX_RESPONSE_SIZE = 5 * 1024 * 1024 // 5MB const DEFAULT_TIMEOUT = 30 * 1000 // 30 seconds const MAX_TIMEOUT = 120 * 1000 // 2 minutes -const parameters = z.object({ - url: z.string().describe("The URL to fetch content from"), - format: z - .enum(["text", "markdown", "html"]) - .default("markdown") - .describe("The format to return the content in (text, markdown, or html). Defaults to markdown."), - timeout: z.number().describe("Optional timeout in seconds (max 120)").optional(), +export const Parameters = Schema.Struct({ + url: Schema.String.annotate({ description: "The URL to fetch content from" }), + format: Schema.Literals(["text", "markdown", "html"]) + .pipe(Schema.optional, Schema.withDecodingDefault(Effect.succeed("markdown" as const))) + .annotate({ + description: "The format to return the content in (text, markdown, or html). Defaults to markdown.", + }), + timeout: Schema.optional(Schema.Number).annotate({ description: "Optional timeout in seconds (max 120)" }), }) export const WebFetchTool = Tool.define( @@ -27,8 +27,8 @@ export const WebFetchTool = Tool.define( return { description: DESCRIPTION, - parameters, - execute: (params: z.infer, ctx: Tool.Context) => + parameters: Parameters, + execute: (params: Schema.Schema.Type, ctx: Tool.Context) => Effect.gen(function* () { if (!params.url.startsWith("http://") && !params.url.startsWith("https://")) { throw new Error("URL must start with http:// or https://") diff --git a/packages/opencode/src/tool/websearch.ts b/packages/opencode/src/tool/websearch.ts index 34cefd031f..ff4c696a25 100644 --- a/packages/opencode/src/tool/websearch.ts +++ b/packages/opencode/src/tool/websearch.ts @@ -1,27 +1,24 @@ -import z from "zod" -import { Effect } from "effect" +import { Effect, Schema } from "effect" import { HttpClient } from "effect/unstable/http" import * as Tool from "./tool" import * as McpExa from "./mcp-exa" import DESCRIPTION from "./websearch.txt" -const Parameters = z.object({ - query: z.string().describe("Websearch query"), - numResults: z.number().optional().describe("Number of search results to return (default: 8)"), - livecrawl: z - .enum(["fallback", "preferred"]) - .optional() - .describe( +export const Parameters = Schema.Struct({ + query: Schema.String.annotate({ description: "Websearch query" }), + numResults: Schema.optional(Schema.Number).annotate({ + description: "Number of search results to return (default: 8)", + }), + livecrawl: Schema.optional(Schema.Literals(["fallback", "preferred"])).annotate({ + description: "Live crawl mode - 'fallback': use live crawling as backup if cached content unavailable, 'preferred': prioritize live crawling (default: 'fallback')", - ), - type: z - .enum(["auto", "fast", "deep"]) - .optional() - .describe("Search type - 'auto': balanced search (default), 'fast': quick results, 'deep': comprehensive search"), - contextMaxCharacters: z - .number() - .optional() - .describe("Maximum characters for context string optimized for LLMs (default: 10000)"), + }), + type: Schema.optional(Schema.Literals(["auto", "fast", "deep"])).annotate({ + description: "Search type - 'auto': balanced search (default), 'fast': quick results, 'deep': comprehensive search", + }), + contextMaxCharacters: Schema.optional(Schema.Number).annotate({ + description: "Maximum characters for context string optimized for LLMs (default: 10000)", + }), }) export const WebSearchTool = Tool.define( @@ -34,7 +31,7 @@ export const WebSearchTool = Tool.define( return DESCRIPTION.replace("{{year}}", new Date().getFullYear().toString()) }, parameters: Parameters, - execute: (params: z.infer, ctx: Tool.Context) => + execute: (params: Schema.Schema.Type, ctx: Tool.Context) => Effect.gen(function* () { yield* ctx.ask({ permission: "websearch", diff --git a/packages/opencode/src/tool/write.ts b/packages/opencode/src/tool/write.ts index 80198f4555..b52f4a164c 100644 --- a/packages/opencode/src/tool/write.ts +++ b/packages/opencode/src/tool/write.ts @@ -1,4 +1,4 @@ -import z from "zod" +import { Schema } from "effect" import * as path from "path" import { Effect } from "effect" import * as Tool from "./tool" @@ -17,6 +17,13 @@ import * as Bom from "@/util/bom" const MAX_PROJECT_DIAGNOSTICS_FILES = 5 +export const Parameters = Schema.Struct({ + content: Schema.String.annotate({ description: "The content to write to the file" }), + filePath: Schema.String.annotate({ + description: "The absolute path to the file to write (must be absolute, not relative)", + }), +}) + export const WriteTool = Tool.define( "write", Effect.gen(function* () { @@ -27,10 +34,7 @@ export const WriteTool = Tool.define( return { description: DESCRIPTION, - parameters: z.object({ - content: z.string().describe("The content to write to the file"), - filePath: z.string().describe("The absolute path to the file to write (must be absolute, not relative)"), - }), + parameters: Parameters, execute: (params: { content: string; filePath: string }, ctx: Tool.Context) => Effect.gen(function* () { const filepath = path.isAbsolute(params.filePath) diff --git a/packages/opencode/src/util/effect-zod.ts b/packages/opencode/src/util/effect-zod.ts index 24ff9a10e1..2bbad2dd75 100644 --- a/packages/opencode/src/util/effect-zod.ts +++ b/packages/opencode/src/util/effect-zod.ts @@ -49,6 +49,17 @@ function isZodType(value: unknown): value is z.ZodTypeAny { return typeof value === "object" && value !== null && "_zod" in value } +/** + * Emit a JSON Schema for a tool/route parameter schema — derives the zod form + * via the walker so Effect Schema inputs flow through the same zod-openapi + * pipeline the LLM/SDK layer already depends on. `io: "input"` mirrors what + * `session/prompt.ts` has always passed to `ai`'s `jsonSchema()` helper. + */ +export function toJsonSchema(schema: S) { + return z.toJSONSchema(zod(schema), { io: "input" }) +} + + function walk(ast: SchemaAST.AST): z.ZodTypeAny { const cached = walkCache.get(ast) if (cached) return cached diff --git a/packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap b/packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap new file mode 100644 index 0000000000..eb3fe6cce4 --- /dev/null +++ b/packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap @@ -0,0 +1,495 @@ +// Bun Snapshot v1, https://bun.sh/docs/test/snapshots + +exports[`tool parameters JSON Schema (wire shape) apply_patch 1`] = ` +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "patchText": { + "description": "The full patch text that describes all changes to be made", + "type": "string", + }, + }, + "required": [ + "patchText", + ], + "type": "object", +} +`; + +exports[`tool parameters JSON Schema (wire shape) bash 1`] = ` +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "command": { + "description": "The command to execute", + "type": "string", + }, + "description": { + "description": +"Clear, concise description of what this command does in 5-10 words. Examples: +Input: ls +Output: Lists files in current directory + +Input: git status +Output: Shows working tree status + +Input: npm install +Output: Installs package dependencies + +Input: mkdir foo +Output: Creates directory 'foo'" +, + "type": "string", + }, + "timeout": { + "description": "Optional timeout in milliseconds", + "type": "number", + }, + "workdir": { + "description": "The working directory to run the command in. Defaults to the current directory. Use this instead of 'cd' commands.", + "type": "string", + }, + }, + "required": [ + "command", + "description", + ], + "type": "object", +} +`; + +exports[`tool parameters JSON Schema (wire shape) codesearch 1`] = ` +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "query": { + "description": "Search query to find relevant context for APIs, Libraries, and SDKs. For example, 'React useState hook examples', 'Python pandas dataframe filtering', 'Express.js middleware', 'Next js partial prerendering configuration'", + "type": "string", + }, + "tokensNum": { + "default": 5000, + "description": "Number of tokens to return (1000-50000). Default is 5000 tokens. Adjust this value based on how much context you need - use lower values for focused queries and higher values for comprehensive documentation.", + "maximum": 50000, + "minimum": 1000, + "type": "number", + }, + }, + "required": [ + "query", + ], + "type": "object", +} +`; + +exports[`tool parameters JSON Schema (wire shape) edit 1`] = ` +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "filePath": { + "description": "The absolute path to the file to modify", + "type": "string", + }, + "newString": { + "description": "The text to replace it with (must be different from oldString)", + "type": "string", + }, + "oldString": { + "description": "The text to replace", + "type": "string", + }, + "replaceAll": { + "description": "Replace all occurrences of oldString (default false)", + "type": "boolean", + }, + }, + "required": [ + "filePath", + "oldString", + "newString", + ], + "type": "object", +} +`; + +exports[`tool parameters JSON Schema (wire shape) glob 1`] = ` +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "path": { + "description": "The directory to search in. If not specified, the current working directory will be used. IMPORTANT: Omit this field to use the default directory. DO NOT enter "undefined" or "null" - simply omit it for the default behavior. Must be a valid directory path if provided.", + "type": "string", + }, + "pattern": { + "description": "The glob pattern to match files against", + "type": "string", + }, + }, + "required": [ + "pattern", + ], + "type": "object", +} +`; + +exports[`tool parameters JSON Schema (wire shape) grep 1`] = ` +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "include": { + "description": "File pattern to include in the search (e.g. "*.js", "*.{ts,tsx}")", + "type": "string", + }, + "path": { + "description": "The directory to search in. Defaults to the current working directory.", + "type": "string", + }, + "pattern": { + "description": "The regex pattern to search for in file contents", + "type": "string", + }, + }, + "required": [ + "pattern", + ], + "type": "object", +} +`; + +exports[`tool parameters JSON Schema (wire shape) invalid 1`] = ` +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "error": { + "type": "string", + }, + "tool": { + "type": "string", + }, + }, + "required": [ + "tool", + "error", + ], + "type": "object", +} +`; + +exports[`tool parameters JSON Schema (wire shape) lsp 1`] = ` +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "character": { + "description": "The character offset (1-based, as shown in editors)", + "maximum": 9007199254740991, + "minimum": 1, + "type": "integer", + }, + "filePath": { + "description": "The absolute or relative path to the file", + "type": "string", + }, + "line": { + "description": "The line number (1-based, as shown in editors)", + "maximum": 9007199254740991, + "minimum": 1, + "type": "integer", + }, + "operation": { + "description": "The LSP operation to perform", + "enum": [ + "goToDefinition", + "findReferences", + "hover", + "documentSymbol", + "workspaceSymbol", + "goToImplementation", + "prepareCallHierarchy", + "incomingCalls", + "outgoingCalls", + ], + "type": "string", + }, + }, + "required": [ + "operation", + "filePath", + "line", + "character", + ], + "type": "object", +} +`; + + +exports[`tool parameters JSON Schema (wire shape) plan 1`] = ` +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": {}, + "type": "object", +} +`; + +exports[`tool parameters JSON Schema (wire shape) question 1`] = ` +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "questions": { + "description": "Questions to ask", + "items": { + "properties": { + "header": { + "description": "Very short label (max 30 chars)", + "type": "string", + }, + "multiple": { + "description": "Allow selecting multiple choices", + "type": "boolean", + }, + "options": { + "description": "Available choices", + "items": { + "properties": { + "description": { + "description": "Explanation of choice", + "type": "string", + }, + "label": { + "description": "Display text (1-5 words, concise)", + "type": "string", + }, + }, + "ref": "QuestionOption", + "required": [ + "label", + "description", + ], + "type": "object", + }, + "type": "array", + }, + "question": { + "description": "Complete question", + "type": "string", + }, + }, + "ref": "QuestionPrompt", + "required": [ + "question", + "header", + "options", + ], + "type": "object", + }, + "type": "array", + }, + }, + "required": [ + "questions", + ], + "type": "object", +} +`; + +exports[`tool parameters JSON Schema (wire shape) read 1`] = ` +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "filePath": { + "description": "The absolute path to the file or directory to read", + "type": "string", + }, + "limit": { + "description": "The maximum number of lines to read (defaults to 2000)", + "type": "number", + }, + "offset": { + "description": "The line number to start reading from (1-indexed)", + "type": "number", + }, + }, + "required": [ + "filePath", + ], + "type": "object", +} +`; + +exports[`tool parameters JSON Schema (wire shape) skill 1`] = ` +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "name": { + "description": "The name of the skill from available_skills", + "type": "string", + }, + }, + "required": [ + "name", + ], + "type": "object", +} +`; + +exports[`tool parameters JSON Schema (wire shape) task 1`] = ` +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "command": { + "description": "The command that triggered this task", + "type": "string", + }, + "description": { + "description": "A short (3-5 words) description of the task", + "type": "string", + }, + "prompt": { + "description": "The task for the agent to perform", + "type": "string", + }, + "subagent_type": { + "description": "The type of specialized agent to use for this task", + "type": "string", + }, + "task_id": { + "description": "This should only be set if you mean to resume a previous task (you can pass a prior task_id and the task will continue the same subagent session as before instead of creating a fresh one)", + "type": "string", + }, + }, + "required": [ + "description", + "prompt", + "subagent_type", + ], + "type": "object", +} +`; + +exports[`tool parameters JSON Schema (wire shape) todo 1`] = ` +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "todos": { + "description": "The updated todo list", + "items": { + "properties": { + "content": { + "description": "Brief description of the task", + "type": "string", + }, + "priority": { + "description": "Priority level of the task: high, medium, low", + "type": "string", + }, + "status": { + "description": "Current status of the task: pending, in_progress, completed, cancelled", + "type": "string", + }, + }, + "required": [ + "content", + "status", + "priority", + ], + "type": "object", + }, + "type": "array", + }, + }, + "required": [ + "todos", + ], + "type": "object", +} +`; + +exports[`tool parameters JSON Schema (wire shape) webfetch 1`] = ` +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "format": { + "default": "markdown", + "description": "The format to return the content in (text, markdown, or html). Defaults to markdown.", + "enum": [ + "text", + "markdown", + "html", + ], + "type": "string", + }, + "timeout": { + "description": "Optional timeout in seconds (max 120)", + "type": "number", + }, + "url": { + "description": "The URL to fetch content from", + "type": "string", + }, + }, + "required": [ + "url", + ], + "type": "object", +} +`; + +exports[`tool parameters JSON Schema (wire shape) websearch 1`] = ` +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "contextMaxCharacters": { + "description": "Maximum characters for context string optimized for LLMs (default: 10000)", + "type": "number", + }, + "livecrawl": { + "description": "Live crawl mode - 'fallback': use live crawling as backup if cached content unavailable, 'preferred': prioritize live crawling (default: 'fallback')", + "enum": [ + "fallback", + "preferred", + ], + "type": "string", + }, + "numResults": { + "description": "Number of search results to return (default: 8)", + "type": "number", + }, + "query": { + "description": "Websearch query", + "type": "string", + }, + "type": { + "description": "Search type - 'auto': balanced search (default), 'fast': quick results, 'deep': comprehensive search", + "enum": [ + "auto", + "fast", + "deep", + ], + "type": "string", + }, + }, + "required": [ + "query", + ], + "type": "object", +} +`; + +exports[`tool parameters JSON Schema (wire shape) write 1`] = ` +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "content": { + "description": "The content to write to the file", + "type": "string", + }, + "filePath": { + "description": "The absolute path to the file to write (must be absolute, not relative)", + "type": "string", + }, + }, + "required": [ + "content", + "filePath", + ], + "type": "object", +} +`; diff --git a/packages/opencode/test/tool/parameters.test.ts b/packages/opencode/test/tool/parameters.test.ts new file mode 100644 index 0000000000..8ea008a457 --- /dev/null +++ b/packages/opencode/test/tool/parameters.test.ts @@ -0,0 +1,260 @@ +import { describe, expect, test } from "bun:test" +import { Result, Schema } from "effect" +import { toJsonSchema } from "../../src/util/effect-zod" + +// Each tool exports its parameters schema at module scope so this test can +// import them without running the tool's Effect-based init. The JSON Schema +// snapshot captures what the LLM sees; the parse assertions pin down the +// accepts/rejects contract. `toJsonSchema` is the same helper `session/ +// prompt.ts` uses to emit tool schemas to the LLM, so the snapshots stay +// byte-identical regardless of whether a tool has migrated from zod to Schema. + +import { Parameters as ApplyPatch } from "../../src/tool/apply_patch" +import { Parameters as Bash } from "../../src/tool/bash" +import { Parameters as CodeSearch } from "../../src/tool/codesearch" +import { Parameters as Edit } from "../../src/tool/edit" +import { Parameters as Glob } from "../../src/tool/glob" +import { Parameters as Grep } from "../../src/tool/grep" +import { Parameters as Invalid } from "../../src/tool/invalid" +import { Parameters as Lsp } from "../../src/tool/lsp" +import { Parameters as Plan } from "../../src/tool/plan" +import { Parameters as Question } from "../../src/tool/question" +import { Parameters as Read } from "../../src/tool/read" +import { Parameters as Skill } from "../../src/tool/skill" +import { Parameters as Task } from "../../src/tool/task" +import { Parameters as Todo } from "../../src/tool/todo" +import { Parameters as WebFetch } from "../../src/tool/webfetch" +import { Parameters as WebSearch } from "../../src/tool/websearch" +import { Parameters as Write } from "../../src/tool/write" + +const parse = >(schema: S, input: unknown): S["Type"] => + Schema.decodeUnknownSync(schema)(input) + +const accepts = (schema: Schema.Decoder, input: unknown): boolean => + Result.isSuccess(Schema.decodeUnknownResult(schema)(input)) + +describe("tool parameters", () => { + describe("JSON Schema (wire shape)", () => { + test("apply_patch", () => expect(toJsonSchema(ApplyPatch)).toMatchSnapshot()) + test("bash", () => expect(toJsonSchema(Bash)).toMatchSnapshot()) + test("codesearch", () => expect(toJsonSchema(CodeSearch)).toMatchSnapshot()) + test("edit", () => expect(toJsonSchema(Edit)).toMatchSnapshot()) + test("glob", () => expect(toJsonSchema(Glob)).toMatchSnapshot()) + test("grep", () => expect(toJsonSchema(Grep)).toMatchSnapshot()) + test("invalid", () => expect(toJsonSchema(Invalid)).toMatchSnapshot()) + test("lsp", () => expect(toJsonSchema(Lsp)).toMatchSnapshot()) + test("plan", () => expect(toJsonSchema(Plan)).toMatchSnapshot()) + test("question", () => expect(toJsonSchema(Question)).toMatchSnapshot()) + test("read", () => expect(toJsonSchema(Read)).toMatchSnapshot()) + test("skill", () => expect(toJsonSchema(Skill)).toMatchSnapshot()) + test("task", () => expect(toJsonSchema(Task)).toMatchSnapshot()) + test("todo", () => expect(toJsonSchema(Todo)).toMatchSnapshot()) + test("webfetch", () => expect(toJsonSchema(WebFetch)).toMatchSnapshot()) + test("websearch", () => expect(toJsonSchema(WebSearch)).toMatchSnapshot()) + test("write", () => expect(toJsonSchema(Write)).toMatchSnapshot()) + }) + + describe("apply_patch", () => { + test("accepts patchText", () => { + expect(parse(ApplyPatch, { patchText: "*** Begin Patch\n*** End Patch" })).toEqual({ + patchText: "*** Begin Patch\n*** End Patch", + }) + }) + test("rejects missing patchText", () => { + expect(accepts(ApplyPatch, {})).toBe(false) + }) + test("rejects non-string patchText", () => { + expect(accepts(ApplyPatch, { patchText: 123 })).toBe(false) + }) + }) + + describe("bash", () => { + test("accepts minimum: command + description", () => { + expect(parse(Bash, { command: "ls", description: "list" })).toEqual({ command: "ls", description: "list" }) + }) + test("accepts optional timeout + workdir", () => { + const parsed = parse(Bash, { command: "ls", description: "list", timeout: 5000, workdir: "/tmp" }) + expect(parsed.timeout).toBe(5000) + expect(parsed.workdir).toBe("/tmp") + }) + test("rejects missing description (required by zod)", () => { + expect(accepts(Bash, { command: "ls" })).toBe(false) + }) + test("rejects missing command", () => { + expect(accepts(Bash, { description: "list" })).toBe(false) + }) + }) + + describe("codesearch", () => { + test("accepts query; tokensNum defaults to 5000", () => { + expect(parse(CodeSearch, { query: "hooks" })).toEqual({ query: "hooks", tokensNum: 5000 }) + }) + test("accepts override tokensNum", () => { + expect(parse(CodeSearch, { query: "hooks", tokensNum: 10000 }).tokensNum).toBe(10000) + }) + test("rejects tokensNum under 1000", () => { + expect(accepts(CodeSearch, { query: "x", tokensNum: 500 })).toBe(false) + }) + test("rejects tokensNum over 50000", () => { + expect(accepts(CodeSearch, { query: "x", tokensNum: 60000 })).toBe(false) + }) + }) + + describe("edit", () => { + test("accepts all four fields", () => { + expect(parse(Edit, { filePath: "/a", oldString: "x", newString: "y", replaceAll: true })).toEqual({ + filePath: "/a", + oldString: "x", + newString: "y", + replaceAll: true, + }) + }) + test("replaceAll is optional", () => { + const parsed = parse(Edit, { filePath: "/a", oldString: "x", newString: "y" }) + expect(parsed.replaceAll).toBeUndefined() + }) + test("rejects missing filePath", () => { + expect(accepts(Edit, { oldString: "x", newString: "y" })).toBe(false) + }) + }) + + describe("glob", () => { + test("accepts pattern-only", () => { + expect(parse(Glob, { pattern: "**/*.ts" })).toEqual({ pattern: "**/*.ts" }) + }) + test("accepts optional path", () => { + expect(parse(Glob, { pattern: "**/*.ts", path: "/tmp" }).path).toBe("/tmp") + }) + test("rejects missing pattern", () => { + expect(accepts(Glob, {})).toBe(false) + }) + }) + + describe("grep", () => { + test("accepts pattern-only", () => { + expect(parse(Grep, { pattern: "TODO" })).toEqual({ pattern: "TODO" }) + }) + test("accepts optional path + include", () => { + const parsed = parse(Grep, { pattern: "TODO", path: "/tmp", include: "*.ts" }) + expect(parsed.path).toBe("/tmp") + expect(parsed.include).toBe("*.ts") + }) + test("rejects missing pattern", () => { + expect(accepts(Grep, {})).toBe(false) + }) + }) + + describe("invalid", () => { + test("accepts tool + error", () => { + expect(parse(Invalid, { tool: "foo", error: "bar" })).toEqual({ tool: "foo", error: "bar" }) + }) + test("rejects missing fields", () => { + expect(accepts(Invalid, { tool: "foo" })).toBe(false) + expect(accepts(Invalid, { error: "bar" })).toBe(false) + }) + }) + + describe("lsp", () => { + test("accepts all fields", () => { + const parsed = parse(Lsp, { operation: "hover", filePath: "/a.ts", line: 1, character: 1 }) + expect(parsed.operation).toBe("hover") + }) + test("rejects line < 1", () => { + expect(accepts(Lsp, { operation: "hover", filePath: "/a.ts", line: 0, character: 1 })).toBe(false) + }) + test("rejects character < 1", () => { + expect(accepts(Lsp, { operation: "hover", filePath: "/a.ts", line: 1, character: 0 })).toBe(false) + }) + test("rejects unknown operation", () => { + expect(accepts(Lsp, { operation: "bogus", filePath: "/a.ts", line: 1, character: 1 })).toBe(false) + }) + }) + + describe("plan", () => { + test("accepts empty object", () => { + expect(parse(Plan, {})).toEqual({}) + }) + }) + + describe("question", () => { + test("accepts questions array", () => { + const parsed = parse(Question, { + questions: [ + { + question: "pick one", + header: "Header", + custom: false, + options: [{ label: "a", description: "desc" }], + }, + ], + }) + expect(parsed.questions.length).toBe(1) + }) + test("rejects missing questions", () => { + expect(accepts(Question, {})).toBe(false) + }) + }) + + describe("read", () => { + test("accepts filePath-only", () => { + expect(parse(Read, { filePath: "/a" }).filePath).toBe("/a") + }) + test("accepts optional offset + limit", () => { + const parsed = parse(Read, { filePath: "/a", offset: 10, limit: 100 }) + expect(parsed.offset).toBe(10) + expect(parsed.limit).toBe(100) + }) + }) + + describe("skill", () => { + test("accepts name", () => { + expect(parse(Skill, { name: "foo" }).name).toBe("foo") + }) + test("rejects missing name", () => { + expect(accepts(Skill, {})).toBe(false) + }) + }) + + describe("task", () => { + test("accepts description + prompt + subagent_type", () => { + const parsed = parse(Task, { description: "d", prompt: "p", subagent_type: "general" }) + expect(parsed.subagent_type).toBe("general") + }) + test("rejects missing prompt", () => { + expect(accepts(Task, { description: "d", subagent_type: "general" })).toBe(false) + }) + }) + + describe("todo", () => { + test("accepts todos array", () => { + const parsed = parse(Todo, { + todos: [{ id: "t1", content: "do x", status: "pending", priority: "medium" }], + }) + expect(parsed.todos.length).toBe(1) + }) + test("rejects missing todos", () => { + expect(accepts(Todo, {})).toBe(false) + }) + }) + + describe("webfetch", () => { + test("accepts url-only", () => { + expect(parse(WebFetch, { url: "https://example.com" }).url).toBe("https://example.com") + }) + }) + + describe("websearch", () => { + test("accepts query", () => { + expect(parse(WebSearch, { query: "opencode" }).query).toBe("opencode") + }) + }) + + describe("write", () => { + test("accepts content + filePath", () => { + expect(parse(Write, { content: "hi", filePath: "/a" })).toEqual({ content: "hi", filePath: "/a" }) + }) + test("rejects missing filePath", () => { + expect(accepts(Write, { content: "hi" })).toBe(false) + }) + }) +}) diff --git a/packages/opencode/test/tool/tool-define.test.ts b/packages/opencode/test/tool/tool-define.test.ts index 00d1e039a7..283708767d 100644 --- a/packages/opencode/test/tool/tool-define.test.ts +++ b/packages/opencode/test/tool/tool-define.test.ts @@ -1,13 +1,13 @@ import { describe, test, expect } from "bun:test" -import { Effect, Layer, ManagedRuntime } from "effect" -import z from "zod" +import { Effect, Layer, ManagedRuntime, Schema } from "effect" import { Agent } from "../../src/agent/agent" +import { MessageID, SessionID } from "../../src/session/schema" import { Tool } from "../../src/tool" import { Truncate } from "../../src/tool" const runtime = ManagedRuntime.make(Layer.mergeAll(Truncate.defaultLayer, Agent.defaultLayer)) -const params = z.object({ input: z.string() }) +const params = Schema.Struct({ input: Schema.String }) function makeTool(id: string, executeFn?: () => void) { return { @@ -56,4 +56,44 @@ describe("Tool.define", () => { expect(first).not.toBe(second) }) + + test("execute receives decoded parameters", async () => { + const parameters = Schema.Struct({ + count: Schema.NumberFromString.pipe(Schema.optional, Schema.withDecodingDefaultType(Effect.succeed(5))), + }) + const calls: Array> = [] + const info = await runtime.runPromise( + Tool.define( + "test-decoded", + Effect.succeed({ + description: "test tool", + parameters, + execute(args: Schema.Schema.Type) { + calls.push(args) + return Effect.succeed({ title: "test", output: "ok", metadata: { truncated: false } }) + }, + }), + ), + ) + const ctx: Tool.Context = { + sessionID: SessionID.descending(), + messageID: MessageID.ascending(), + agent: "build", + abort: new AbortController().signal, + messages: [], + metadata() { + return Effect.void + }, + ask() { + return Effect.void + }, + } + const tool = await Effect.runPromise(info.init()) + const execute = tool.execute as unknown as (args: unknown, ctx: Tool.Context) => ReturnType + + await Effect.runPromise(execute({}, ctx)) + await Effect.runPromise(execute({ count: "7" }, ctx)) + + expect(calls).toEqual([{ count: 5 }, { count: 7 }]) + }) }) From 3f8c659056c3ddf3e9074efb8a1ea57018c356ab Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Thu, 23 Apr 2026 20:10:56 +0000 Subject: [PATCH 45/92] chore: generate --- packages/opencode/src/tool/apply_patch.ts | 8 +++++-- packages/opencode/src/tool/read.ts | 8 +++++-- packages/opencode/src/tool/task.ts | 8 +++++-- packages/opencode/src/tool/todo.ts | 4 +++- packages/opencode/src/tool/tool.ts | 29 ++++++++++++++++------- packages/opencode/src/util/effect-zod.ts | 1 - 6 files changed, 42 insertions(+), 16 deletions(-) diff --git a/packages/opencode/src/tool/apply_patch.ts b/packages/opencode/src/tool/apply_patch.ts index effc428c71..72f24a3f60 100644 --- a/packages/opencode/src/tool/apply_patch.ts +++ b/packages/opencode/src/tool/apply_patch.ts @@ -27,7 +27,10 @@ export const ApplyPatchTool = Tool.define( const format = yield* Format.Service const bus = yield* Bus.Service - const run = Effect.fn("ApplyPatchTool.execute")(function* (params: Schema.Schema.Type, ctx: Tool.Context) { + const run = Effect.fn("ApplyPatchTool.execute")(function* ( + params: Schema.Schema.Type, + ctx: Tool.Context, + ) { if (!params.patchText) { return yield* Effect.fail(new Error("patchText is required")) } @@ -297,7 +300,8 @@ export const ApplyPatchTool = Tool.define( return { description: DESCRIPTION, parameters: Parameters, - execute: (params: Schema.Schema.Type, ctx: Tool.Context) => run(params, ctx).pipe(Effect.orDie), + execute: (params: Schema.Schema.Type, ctx: Tool.Context) => + run(params, ctx).pipe(Effect.orDie), } }), ) diff --git a/packages/opencode/src/tool/read.ts b/packages/opencode/src/tool/read.ts index e7bfc6af33..d0995626c0 100644 --- a/packages/opencode/src/tool/read.ts +++ b/packages/opencode/src/tool/read.ts @@ -148,7 +148,10 @@ export const ReadTool = Tool.define( return nonPrintableCount / bytes.length > 0.3 } - const run = Effect.fn("ReadTool.execute")(function* (params: Schema.Schema.Type, ctx: Tool.Context) { + const run = Effect.fn("ReadTool.execute")(function* ( + params: Schema.Schema.Type, + ctx: Tool.Context, + ) { if (params.offset !== undefined && params.offset < 1) { return yield* Effect.fail(new Error("offset must be greater than or equal to 1")) } @@ -284,7 +287,8 @@ export const ReadTool = Tool.define( return { description: DESCRIPTION, parameters: Parameters, - execute: (params: Schema.Schema.Type, ctx: Tool.Context) => run(params, ctx).pipe(Effect.orDie), + execute: (params: Schema.Schema.Type, ctx: Tool.Context) => + run(params, ctx).pipe(Effect.orDie), } }), ) diff --git a/packages/opencode/src/tool/task.ts b/packages/opencode/src/tool/task.ts index 98f6bdd98f..5cb0dc6a83 100644 --- a/packages/opencode/src/tool/task.ts +++ b/packages/opencode/src/tool/task.ts @@ -34,7 +34,10 @@ export const TaskTool = Tool.define( const config = yield* Config.Service const sessions = yield* Session.Service - const run = Effect.fn("TaskTool.execute")(function* (params: Schema.Schema.Type, ctx: Tool.Context) { + const run = Effect.fn("TaskTool.execute")(function* ( + params: Schema.Schema.Type, + ctx: Tool.Context, + ) { const cfg = yield* config.get() if (!ctx.extra?.bypassAgentCheck) { @@ -166,7 +169,8 @@ export const TaskTool = Tool.define( return { description: DESCRIPTION, parameters: Parameters, - execute: (params: Schema.Schema.Type, ctx: Tool.Context) => run(params, ctx).pipe(Effect.orDie), + execute: (params: Schema.Schema.Type, ctx: Tool.Context) => + run(params, ctx).pipe(Effect.orDie), } }), ) diff --git a/packages/opencode/src/tool/todo.ts b/packages/opencode/src/tool/todo.ts index c493d3a71a..18d21cf61e 100644 --- a/packages/opencode/src/tool/todo.ts +++ b/packages/opencode/src/tool/todo.ts @@ -8,7 +8,9 @@ import { Todo } from "../session/todo" // identical, and it removes the last zod dependency from this tool. const TodoItem = Schema.Struct({ content: Schema.String.annotate({ description: "Brief description of the task" }), - status: Schema.String.annotate({ description: "Current status of the task: pending, in_progress, completed, cancelled" }), + status: Schema.String.annotate({ + description: "Current status of the task: pending, in_progress, completed, cancelled", + }), priority: Schema.String.annotate({ description: "Priority level of the task: high, medium, low" }), }) diff --git a/packages/opencode/src/tool/tool.ts b/packages/opencode/src/tool/tool.ts index c9115e9ff1..7e753cb9bc 100644 --- a/packages/opencode/src/tool/tool.ts +++ b/packages/opencode/src/tool/tool.ts @@ -31,19 +31,25 @@ export interface ExecuteResult { attachments?: Omit[] } -export interface Def = Schema.Decoder, M extends Metadata = Metadata> { +export interface Def< + Parameters extends Schema.Decoder = Schema.Decoder, + M extends Metadata = Metadata, +> { id: string description: string parameters: Parameters execute(args: Schema.Schema.Type, ctx: Context): Effect.Effect> formatValidationError?(error: unknown): string } -export type DefWithoutID = Schema.Decoder, M extends Metadata = Metadata> = Omit< - Def, - "id" -> +export type DefWithoutID< + Parameters extends Schema.Decoder = Schema.Decoder, + M extends Metadata = Metadata, +> = Omit, "id"> -export interface Info = Schema.Decoder, M extends Metadata = Metadata> { +export interface Info< + Parameters extends Schema.Decoder = Schema.Decoder, + M extends Metadata = Metadata, +> { id: string init: () => Effect.Effect> } @@ -121,7 +127,12 @@ function wrap, Result extends Metadat }) } -export function define, Result extends Metadata, R, ID extends string = string>( +export function define< + Parameters extends Schema.Decoder, + Result extends Metadata, + R, + ID extends string = string, +>( id: ID, init: Effect.Effect, never, R>, ): Effect.Effect, never, R | Truncate.Service | Agent.Service> & { id: ID } { @@ -136,7 +147,9 @@ export function define, Result extend ) } -export function init

    , M extends Metadata>(info: Info): Effect.Effect> { +export function init

    , M extends Metadata>( + info: Info, +): Effect.Effect> { return Effect.gen(function* () { const init = yield* info.init() return { diff --git a/packages/opencode/src/util/effect-zod.ts b/packages/opencode/src/util/effect-zod.ts index 2bbad2dd75..332a5c76eb 100644 --- a/packages/opencode/src/util/effect-zod.ts +++ b/packages/opencode/src/util/effect-zod.ts @@ -59,7 +59,6 @@ export function toJsonSchema(schema: S) { return z.toJSONSchema(zod(schema), { io: "input" }) } - function walk(ast: SchemaAST.AST): z.ZodTypeAny { const cached = walkCache.get(ast) if (cached) return cached From 98ea5b6e7e907b6d4eb52b294b9a7770bbd0f18e Mon Sep 17 00:00:00 2001 From: James Long Date: Thu, 23 Apr 2026 16:19:19 -0400 Subject: [PATCH 46/92] feat(tui): support builtin protocol for handling context from editors (#24034) --- packages/opencode/src/cli/cmd/tui/app.tsx | 5 +- .../cmd/tui/component/prompt/autocomplete.tsx | 104 ++++-- .../cli/cmd/tui/component/prompt/index.tsx | 50 ++- .../src/cli/cmd/tui/context/editor.ts | 318 ++++++++++++++++++ 4 files changed, 448 insertions(+), 29 deletions(-) create mode 100644 packages/opencode/src/cli/cmd/tui/context/editor.ts diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 2b31d078cb..eb5cb44e8d 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -24,6 +24,7 @@ import { DialogProvider as DialogProviderList } from "@tui/component/dialog-prov import { ErrorComponent } from "@tui/component/error-component" import { PluginRouteMissing } from "@tui/component/plugin-route-missing" import { ProjectProvider } from "@tui/context/project" +import { EditorContextProvider } from "@tui/context/editor" import { useEvent } from "@tui/context/event" import { SDKProvider, useSDK } from "@tui/context/sdk" import { StartupLoading } from "@tui/component/startup-loading" @@ -177,7 +178,9 @@ export function tui(input: { - + + + diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx index 305d076223..4a5e1a4ca6 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -1,9 +1,11 @@ import type { BoxRenderable, TextareaRenderable, KeyEvent, ScrollBoxRenderable } from "@opentui/core" import { pathToFileURL } from "bun" import fuzzysort from "fuzzysort" +import path from "path" import { firstBy } from "remeda" import { createMemo, createResource, createEffect, onMount, onCleanup, Index, Show, createSignal } from "solid-js" import { createStore } from "solid-js/store" +import { useEditorContext } from "@tui/context/editor" import { useSDK } from "@tui/context/sdk" import { useSync } from "@tui/context/sync" import { getScrollAcceleration } from "../../util/scroll" @@ -77,6 +79,7 @@ export function Autocomplete(props: { agentStyleId: number promptPartTypeId: () => number }) { + const editor = useEditorContext() const sdk = useSDK() const sync = useSync() const command = useCommandDialog() @@ -221,6 +224,70 @@ export function Autocomplete(props: { } } + function createFilePart(item: string, lineRange?: { startLine: number; endLine?: number }) { + const baseDir = (sync.path.directory || process.cwd()).replace(/\/+$/, "") + const fullPath = path.isAbsolute(item) ? item : path.join(baseDir, item) + const urlObj = pathToFileURL(fullPath) + const filename = + lineRange && !item.endsWith("/") + ? `${item}#${lineRange.startLine}${lineRange.endLine ? `-${lineRange.endLine}` : ""}` + : item + + if (lineRange && !item.endsWith("/")) { + urlObj.searchParams.set("start", String(lineRange.startLine)) + if (lineRange.endLine !== undefined) { + urlObj.searchParams.set("end", String(lineRange.endLine)) + } + } + + return { + filename, + url: urlObj.href, + part: { + type: "file" as const, + mime: "text/plain", + filename, + url: urlObj.href, + source: { + type: "file" as const, + text: { + start: 0, + end: 0, + value: "", + }, + path: item, + }, + }, + } + } + + function normalizeMentionPath(filePath: string) { + const baseDir = sync.path.directory || process.cwd() + const absolute = path.resolve(filePath) + const relative = path.relative(baseDir, absolute) + + if (relative && !relative.startsWith("..") && !path.isAbsolute(relative)) { + return relative.split(path.sep).join("/") + } + + return absolute.split(path.sep).join("/") + } + + function insertFileMention(input: { filePath: string; lineStart: number; lineEnd: number }) { + const item = normalizeMentionPath(input.filePath) + const lineRange = { + startLine: input.lineStart, + endLine: input.lineEnd > input.lineStart ? input.lineEnd : undefined, + } + const { filename, part } = createFilePart(item, lineRange) + const index = store.visible === "@" ? store.index : props.input().cursorOffset + + command.keybinds(true) + setStore("visible", false) + setStore("index", index) + insertPart(filename, part) + } + const [files] = createResource( () => search(), async (query) => { @@ -250,18 +317,7 @@ export function Autocomplete(props: { const width = props.anchor().width - 4 options.push( ...sortedFiles.map((item): AutocompleteOption => { - const baseDir = (sync.path.directory || process.cwd()).replace(/\/+$/, "") - const fullPath = `${baseDir}/${item}` - const urlObj = pathToFileURL(fullPath) - let filename = item - if (lineRange && !item.endsWith("/")) { - filename = `${item}#${lineRange.startLine}${lineRange.endLine ? `-${lineRange.endLine}` : ""}` - urlObj.searchParams.set("start", String(lineRange.startLine)) - if (lineRange.endLine !== undefined) { - urlObj.searchParams.set("end", String(lineRange.endLine)) - } - } - const url = urlObj.href + const { filename, url, part } = createFilePart(item, lineRange) const isDir = item.endsWith("/") return { @@ -270,21 +326,7 @@ export function Autocomplete(props: { isDirectory: isDir, path: item, onSelect: () => { - insertPart(filename, { - type: "file", - mime: "text/plain", - filename, - url, - source: { - type: "file", - text: { - start: 0, - end: 0, - value: "", - }, - path: item, - }, - }) + insertPart(filename, part) }, } }), @@ -501,6 +543,14 @@ export function Autocomplete(props: { } onMount(() => { + const unsubscribeMention = editor.onMention((mention) => { + insertFileMention(mention) + }) + + onCleanup(() => { + unsubscribeMention() + }) + props.ref({ get visible() { return store.visible diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index 2e08e66a4a..5288a819b3 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -12,6 +12,7 @@ import { useRoute } from "@tui/context/route" import { useProject } from "@tui/context/project" import { useSync } from "@tui/context/sync" import { useEvent } from "@tui/context/event" +import { useEditorContext } from "@tui/context/editor" import { MessageID, PartID } from "@/session/schema" import { createStore, produce, unwrap } from "solid-js/store" import { useKeybind } from "@tui/context/keybind" @@ -21,7 +22,7 @@ import { usePromptStash } from "./stash" import { DialogStash } from "../dialog-stash" import { type AutocompleteRef, Autocomplete } from "./autocomplete" import { useCommandDialog } from "../dialog-command" -import { useRenderer, type JSX } from "@opentui/solid" +import { useRenderer, useTerminalDimensions, type JSX } from "@opentui/solid" import * as Editor from "@tui/util/editor" import { useExit } from "../../context/exit" import * as Clipboard from "../../util/clipboard" @@ -94,6 +95,7 @@ export function Prompt(props: PromptProps) { const local = useLocal() const args = useArgs() const sdk = useSDK() + const editor = useEditorContext() const route = useRoute() const project = useProject() const sync = useSync() @@ -104,11 +106,34 @@ export function Prompt(props: PromptProps) { const stash = usePromptStash() const command = useCommandDialog() const renderer = useRenderer() + const dimensions = useTerminalDimensions() const { theme, syntax } = useTheme() const kv = useKV() const animationsEnabled = createMemo(() => kv.get("animations_enabled", true)) const list = createMemo(() => props.placeholders?.normal ?? []) const shell = createMemo(() => props.placeholders?.shell ?? []) + const editorPath = createMemo(() => editor.selection()?.filePath) + const editorSelectionLabel = createMemo(() => { + const selection = editor.selection()?.selection + if (!selection) return + if (selection.start.line === selection.end.line && selection.start.character === selection.end.character) return + if (selection.start.line === selection.end.line) return `#${selection.start.line}` + return `#${selection.start.line}-${selection.end.line}` + }) + const editorFileLabel = createMemo(() => { + const value = editorPath() + if (!value) return + const filename = path.basename(value) + const file = /^index\.[^./]+$/.test(filename) + ? [path.basename(path.dirname(value)), filename].filter(Boolean).join("/") + : filename + return `${file.split(path.sep).join("/")}${editorSelectionLabel() ?? ""}` + }) + const editorFileLabelDisplay = createMemo(() => { + const file = editorFileLabel() + if (!file) return + return Locale.truncateMiddle(file, Math.max(12, Math.min(48, Math.floor(dimensions().width / 3)))) + }) const [auto, setAuto] = createSignal() const currentProviderLabel = createMemo(() => local.model.parsed().provider) const hasRightContent = createMemo(() => Boolean(props.right)) @@ -721,6 +746,27 @@ export function Prompt(props: PromptProps) { // Capture mode before it gets reset const currentMode = store.mode const variant = local.model.variant.current() + const editorSelection = editor.selection() + const editorParts = editorSelection + ? [ + { + id: PartID.ascending(), + type: "text" as const, + text: (() => { + const start = editorSelection.selection.start + const end = editorSelection.selection.end + if (start.line === end.line && start.character === end.character) { + return `Note: The user opened the file "${editorSelection.filePath}".` + } + if (start.line === end.line) { + return `Note: The user selected line ${start.line} from "${editorSelection.filePath}": ${editorSelection.text}` + } + return `Note: The user selected lines ${start.line} to ${end.line} from "${editorSelection.filePath}": ${editorSelection.text}` + })(), + synthetic: true, + }, + ] + : [] if (store.mode === "shell") { void sdk.client.session.shell({ @@ -773,6 +819,7 @@ export function Prompt(props: PromptProps) { model: selectedModel, variant, parts: [ + ...editorParts, { id: PartID.ascending(), type: "text", @@ -1332,6 +1379,7 @@ export function Prompt(props: PromptProps) { + {(file) => {file()}} diff --git a/packages/opencode/src/cli/cmd/tui/context/editor.ts b/packages/opencode/src/cli/cmd/tui/context/editor.ts new file mode 100644 index 0000000000..663b0f0fac --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/context/editor.ts @@ -0,0 +1,318 @@ +import { readdirSync, readFileSync, statSync } from "node:fs" +import os from "node:os" +import path from "node:path" +import { onCleanup, onMount } from "solid-js" +import { createStore } from "solid-js/store" +import z from "zod" +import { createSimpleContext } from "./helper" + +const MCP_PROTOCOL_VERSION = "2025-11-25" + +const JsonRpcMessageSchema = z.object({ + id: z.union([z.number(), z.string(), z.null()]).optional(), + method: z.string().optional(), + params: z.unknown().optional(), + result: z.unknown().optional(), + error: z + .object({ + code: z.number().optional(), + message: z.string().optional(), + }) + .optional(), +}) + +const PositionSchema = z.object({ + line: z.number(), + character: z.number(), +}) + +const EditorSelectionSchema = z.object({ + text: z.string(), + filePath: z.string(), + selection: z.object({ + start: PositionSchema, + end: PositionSchema, + }), +}) + +const EditorMentionSchema = z.object({ + filePath: z.string(), + lineStart: z.number(), + lineEnd: z.number(), +}) + +const EditorServerInfoSchema = z.object({ + protocolVersion: z.string().optional(), + serverInfo: z + .object({ + name: z.string().optional(), + version: z.string().optional(), + }) + .optional(), +}) + +type JsonRpcMessage = z.infer +export type EditorSelection = z.infer +export type EditorMention = z.infer +type EditorServerInfo = z.infer + +type EditorConnection = { + url: string + authToken?: string + source: string +} + +type EditorLockFile = { + port: number + authToken?: string + transport?: string + workspaceFolders: string[] + mtimeMs: number +} + +export const { use: useEditorContext, provider: EditorContextProvider } = createSimpleContext({ + name: "EditorContext", + init: () => { + const mentionListeners = new Set<(mention: EditorMention) => void>() + const [store, setStore] = createStore<{ + status: "disabled" | "connecting" | "connected" + selection: EditorSelection | undefined + server: EditorServerInfo | undefined + }>({ + status: "disabled", + selection: undefined, + server: undefined, + }) + + onMount(() => { + let socket: WebSocket | undefined + let closed = false + let reconnect: ReturnType | undefined + let attempt = 0 + let requestID = 0 + const pending = new Map() + + const send = (payload: JsonRpcMessage) => { + if (!socket || socket.readyState !== WebSocket.OPEN) return + socket.send(JSON.stringify({ jsonrpc: "2.0", ...payload })) + } + + const request = (method: string, params?: unknown) => { + requestID += 1 + pending.set(requestID, method) + send({ id: requestID, method, params }) + } + + const scheduleReconnect = (delay: number) => { + if (closed) return + if (reconnect) clearTimeout(reconnect) + reconnect = setTimeout(connect, delay) + } + + const connect = () => { + if (closed) return + + const connection = resolveEditorConnection() + if (!connection) { + setStore("status", "disabled") + scheduleReconnect(1000) + return + } + + setStore("status", "connecting") + const current = openEditorSocket(connection) + socket = current + + current.addEventListener("open", () => { + if (socket !== current) { + current.close() + return + } + + attempt = 0 + setStore("status", "connected") + request("initialize", { + protocolVersion: MCP_PROTOCOL_VERSION, + capabilities: {}, + clientInfo: { name: "opencode", version: "0.0.0" }, + }) + }) + + current.addEventListener("message", (event) => { + const message = parseMessage(event.data) + if (!message) return + + const selection = message.method === "selection_changed" ? EditorSelectionSchema.safeParse(message.params) : undefined + if (selection?.success) { + setStore("selection", selection.data) + return + } + + const mention = message.method === "at_mentioned" ? EditorMentionSchema.safeParse(message.params) : undefined + if (mention?.success) { + mentionListeners.forEach((listener) => listener(mention.data)) + return + } + + if (typeof message.id !== "number") return + + const method = pending.get(message.id) + if (!method) return + + pending.delete(message.id) + if (message.error) return + + const initialize = method === "initialize" ? EditorServerInfoSchema.safeParse(message.result) : undefined + if (initialize?.success) { + setStore("server", initialize.data) + send({ method: "notifications/initialized" }) + return + } + }) + + current.addEventListener("close", () => { + if (socket !== current) return + + socket = undefined + pending.clear() + if (closed) return + + setStore("status", "connecting") + attempt += 1 + const delay = Math.min(1000 * 2 ** (attempt - 1), 30000) + scheduleReconnect(delay) + }) + } + + scheduleReconnect(0) + + onCleanup(() => { + closed = true + if (reconnect) clearTimeout(reconnect) + socket?.close() + }) + }) + + return { + enabled() { + return Boolean(resolveEditorConnection()) + }, + connected() { + return store.status === "connected" + }, + selection() { + return store.selection + }, + onMention(listener: (mention: EditorMention) => void) { + mentionListeners.add(listener) + return () => mentionListeners.delete(listener) + }, + server() { + return store.server + }, + } + }, +}) + +function parsePort(value: string | undefined) { + if (!value) return + + const parsed = Number.parseInt(value, 10) + if (!Number.isInteger(parsed) || parsed <= 0 || parsed > 65535) return + return parsed +} + +function resolveEditorConnection(): EditorConnection | undefined { + const lock = resolveEditorLockFile() + if (lock) { + return { + url: `ws://127.0.0.1:${lock.port}`, + authToken: lock.authToken, + source: `lock:${lock.port}`, + } + } + + const port = parsePort(process.env.CLAUDE_CODE_SSE_PORT || process.env.OPENCODE_EDITOR_SSE_PORT) + if (!port) return + return { + url: `ws://127.0.0.1:${port}`, + source: `env:${port}`, + } +} + +function resolveEditorLockFile() { + const directory = path.join(os.homedir(), ".claude", "ide") + let entries: string[] + + try { + entries = readdirSync(directory) + } catch { + return + } + + const cwd = process.cwd() + const locks = entries + .filter((entry) => entry.endsWith(".lock")) + .map((entry) => readEditorLockFile(path.join(directory, entry))) + .filter((entry): entry is EditorLockFile => Boolean(entry)) + .sort((left, right) => scoreEditorLock(right, cwd) - scoreEditorLock(left, cwd)) + + return locks[0] +} + +function readEditorLockFile(filePath: string): EditorLockFile | undefined { + const port = parsePort(path.basename(filePath, ".lock")) + if (!port) return + + try { + const parsed = JSON.parse(readFileSync(filePath, "utf-8")) as unknown + if (!isRecord(parsed)) return + if (parsed.transport !== undefined && parsed.transport !== "ws") return + + return { + port, + authToken: typeof parsed.authToken === "string" ? parsed.authToken : undefined, + transport: typeof parsed.transport === "string" ? parsed.transport : undefined, + workspaceFolders: Array.isArray(parsed.workspaceFolders) + ? parsed.workspaceFolders.filter((value): value is string => typeof value === "string") + : [], + mtimeMs: statSync(filePath).mtimeMs, + } + } catch { + return + } +} + +function scoreEditorLock(lock: EditorLockFile, cwd: string) { + const workspaceMatch = lock.workspaceFolders.some((folder) => pathContains(folder, cwd)) ? 1 : 0 + return workspaceMatch * 1_000_000_000_000 + lock.mtimeMs +} + +function pathContains(parent: string, child: string) { + const relative = path.relative(path.resolve(parent), path.resolve(child)) + return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative)) +} + +function openEditorSocket(connection: EditorConnection) { + if (!connection.authToken) return new WebSocket(connection.url) + + return new WebSocket(connection.url, { + headers: { + "x-claude-code-ide-authorization": connection.authToken, + }, + } as any) +} + +function parseMessage(value: unknown) { + if (typeof value !== "string") return + + try { + return JsonRpcMessageSchema.parse(JSON.parse(value)) + } catch { + return + } +} + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value) +} From 4c3e65c87728b04888ccbf3879aca13a3857bb08 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Thu, 23 Apr 2026 20:20:26 +0000 Subject: [PATCH 47/92] chore: generate --- packages/opencode/src/cli/cmd/tui/context/editor.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/cli/cmd/tui/context/editor.ts b/packages/opencode/src/cli/cmd/tui/context/editor.ts index 663b0f0fac..4e6c97f6e5 100644 --- a/packages/opencode/src/cli/cmd/tui/context/editor.ts +++ b/packages/opencode/src/cli/cmd/tui/context/editor.ts @@ -142,7 +142,8 @@ export const { use: useEditorContext, provider: EditorContextProvider } = create const message = parseMessage(event.data) if (!message) return - const selection = message.method === "selection_changed" ? EditorSelectionSchema.safeParse(message.params) : undefined + const selection = + message.method === "selection_changed" ? EditorSelectionSchema.safeParse(message.params) : undefined if (selection?.success) { setStore("selection", selection.data) return From 814e83ffecfddeb60cc88bba03b0c00629eecf5e Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 23 Apr 2026 16:23:45 -0400 Subject: [PATCH 48/92] docs: update effect schema migration tracker (#24054) --- packages/opencode/specs/effect/schema.md | 50 ++++++++++++------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/opencode/specs/effect/schema.md b/packages/opencode/specs/effect/schema.md index 0d451f4a99..04f994e310 100644 --- a/packages/opencode/specs/effect/schema.md +++ b/packages/opencode/specs/effect/schema.md @@ -254,8 +254,8 @@ Working rule for this cluster: 5. Errors and event payloads last - `NamedError.create(...)` shapes can stay temporarily if converting them to `Schema.TaggedErrorClass` would force unrelated churn - - `SyncEvent.define(...)` and `BusEvent.define(...)` payloads can keep using - derived `.zod` until the sync/bus layers are migrated + - `SyncEvent.define(...)` and `BusEvent.define(...)` payloads can use + derived `.zod` at remaining zod-based HTTP/OpenAPI boundaries Possible later tightening after the Schema-first migration is stable: @@ -284,25 +284,25 @@ Each tool declares its parameters via a zod schema. Tools are consumed by both the in-process runtime and the AI SDK's tool-calling layer, so the emitted JSON Schema must stay byte-identical. -- [ ] `src/tool/apply_patch.ts` -- [ ] `src/tool/bash.ts` -- [ ] `src/tool/codesearch.ts` -- [ ] `src/tool/edit.ts` -- [ ] `src/tool/glob.ts` -- [ ] `src/tool/grep.ts` -- [ ] `src/tool/invalid.ts` -- [ ] `src/tool/lsp.ts` -- [ ] `src/tool/plan.ts` -- [ ] `src/tool/question.ts` -- [ ] `src/tool/read.ts` -- [ ] `src/tool/registry.ts` -- [ ] `src/tool/skill.ts` -- [ ] `src/tool/task.ts` -- [ ] `src/tool/todo.ts` -- [ ] `src/tool/tool.ts` -- [ ] `src/tool/webfetch.ts` -- [ ] `src/tool/websearch.ts` -- [ ] `src/tool/write.ts` +- [x] `src/tool/apply_patch.ts` +- [x] `src/tool/bash.ts` +- [x] `src/tool/codesearch.ts` +- [x] `src/tool/edit.ts` +- [x] `src/tool/glob.ts` +- [x] `src/tool/grep.ts` +- [x] `src/tool/invalid.ts` +- [x] `src/tool/lsp.ts` +- [x] `src/tool/plan.ts` +- [x] `src/tool/question.ts` +- [x] `src/tool/read.ts` +- [x] `src/tool/registry.ts` +- [x] `src/tool/skill.ts` +- [x] `src/tool/task.ts` +- [x] `src/tool/todo.ts` +- [x] `src/tool/tool.ts` +- [x] `src/tool/webfetch.ts` +- [x] `src/tool/websearch.ts` +- [x] `src/tool/write.ts` ### HTTP route boundaries @@ -313,8 +313,8 @@ which means touching them is largely mechanical once the domain side is done. - [ ] `src/server/error.ts` -- [ ] `src/server/event.ts` -- [ ] `src/server/projectors.ts` +- [x] `src/server/event.ts` +- [x] `src/server/projectors.ts` - [ ] `src/server/routes/control/index.ts` - [ ] `src/server/routes/control/workspace.ts` - [ ] `src/server/routes/global.ts` @@ -346,7 +346,7 @@ piecewise. - [ ] `src/acp/agent.ts` - [ ] `src/agent/agent.ts` -- [ ] `src/bus/bus-event.ts` +- [x] `src/bus/bus-event.ts` - [ ] `src/bus/index.ts` - [ ] `src/cli/cmd/tui/config/tui-migrate.ts` - [ ] `src/cli/cmd/tui/config/tui-schema.ts` @@ -376,7 +376,7 @@ piecewise. - [ ] `src/snapshot/index.ts` - [ ] `src/storage/db.ts` - [ ] `src/storage/storage.ts` -- [x] `src/sync/index.ts` — public API (`SyncEvent.define`) is Schema-first; still stores derived zod `schema`/`properties` on each `Definition` as a compat bridge for `BusEvent` until `bus/bus-event.ts` migrates +- [x] `src/sync/index.ts` — public API (`SyncEvent.define`) is Schema-first; `payloads()` still derives zod for the remaining HTTP/OpenAPI boundary - [ ] `src/util/fn.ts` - [ ] `src/util/log.ts` - [ ] `src/util/update-schema.ts` From 31d01d404afd4f82628b3f388d5c73debf250ffd Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 23 Apr 2026 16:48:56 -0400 Subject: [PATCH 49/92] refactor(control-plane): migrate workspace DTO schemas (#24056) --- packages/opencode/specs/effect/schema.md | 6 +-- .../src/control-plane/adaptors/index.ts | 8 +--- .../src/control-plane/adaptors/worktree.ts | 20 +++++----- packages/opencode/src/control-plane/types.ts | 31 +++++++++----- .../opencode/src/control-plane/workspace.ts | 40 +++++++++---------- .../src/server/routes/control/workspace.ts | 27 +++++-------- 6 files changed, 67 insertions(+), 65 deletions(-) diff --git a/packages/opencode/specs/effect/schema.md b/packages/opencode/specs/effect/schema.md index 04f994e310..0319df4a0e 100644 --- a/packages/opencode/specs/effect/schema.md +++ b/packages/opencode/specs/effect/schema.md @@ -354,9 +354,9 @@ piecewise. - [ ] `src/cli/cmd/tui/event.ts` - [ ] `src/cli/ui.ts` - [ ] `src/command/index.ts` -- [ ] `src/control-plane/adaptors/worktree.ts` -- [ ] `src/control-plane/types.ts` -- [ ] `src/control-plane/workspace.ts` +- [x] `src/control-plane/adaptors/worktree.ts` +- [x] `src/control-plane/types.ts` +- [x] `src/control-plane/workspace.ts` - [ ] `src/file/index.ts` - [ ] `src/file/ripgrep.ts` - [ ] `src/file/watcher.ts` diff --git a/packages/opencode/src/control-plane/adaptors/index.ts b/packages/opencode/src/control-plane/adaptors/index.ts index 291e392eab..651d09cc21 100644 --- a/packages/opencode/src/control-plane/adaptors/index.ts +++ b/packages/opencode/src/control-plane/adaptors/index.ts @@ -1,12 +1,6 @@ import { lazy } from "@/util/lazy" import type { ProjectID } from "@/project/schema" -import type { WorkspaceAdaptor } from "../types" - -export type WorkspaceAdaptorEntry = { - type: string - name: string - description: string -} +import type { WorkspaceAdaptor, WorkspaceAdaptorEntry } from "../types" const BUILTIN: Record Promise> = { worktree: lazy(async () => (await import("./worktree")).WorktreeAdaptor), diff --git a/packages/opencode/src/control-plane/adaptors/worktree.ts b/packages/opencode/src/control-plane/adaptors/worktree.ts index 2bfb7debaa..8d421b9a33 100644 --- a/packages/opencode/src/control-plane/adaptors/worktree.ts +++ b/packages/opencode/src/control-plane/adaptors/worktree.ts @@ -1,13 +1,15 @@ -import z from "zod" +import { Schema } from "effect" import { AppRuntime } from "@/effect/app-runtime" import { Worktree } from "@/worktree" import { type WorkspaceAdaptor, WorkspaceInfo } from "../types" +import { zod } from "@/util/effect-zod" +import { withStatics } from "@/util/schema" -const WorktreeConfig = z.object({ - name: WorkspaceInfo.shape.name, - branch: WorkspaceInfo.shape.branch.unwrap(), - directory: WorkspaceInfo.shape.directory.unwrap(), -}) +const WorktreeConfig = Schema.Struct({ + name: WorkspaceInfo.fields.name, + branch: Schema.String, + directory: Schema.String, +}).pipe(withStatics((s) => ({ zod: zod(s) }))) export const WorktreeAdaptor: WorkspaceAdaptor = { name: "Worktree", @@ -22,7 +24,7 @@ export const WorktreeAdaptor: WorkspaceAdaptor = { } }, async create(info) { - const config = WorktreeConfig.parse(info) + const config = WorktreeConfig.zod.parse(info) await AppRuntime.runPromise( Worktree.Service.use((svc) => svc.createFromInfo({ @@ -34,11 +36,11 @@ export const WorktreeAdaptor: WorkspaceAdaptor = { ) }, async remove(info) { - const config = WorktreeConfig.parse(info) + const config = WorktreeConfig.zod.parse(info) await AppRuntime.runPromise(Worktree.Service.use((svc) => svc.remove({ directory: config.directory }))) }, target(info) { - const config = WorktreeConfig.parse(info) + const config = WorktreeConfig.zod.parse(info) return { type: "local", directory: config.directory, diff --git a/packages/opencode/src/control-plane/types.ts b/packages/opencode/src/control-plane/types.ts index 07acd5ce58..af16c04902 100644 --- a/packages/opencode/src/control-plane/types.ts +++ b/packages/opencode/src/control-plane/types.ts @@ -1,17 +1,28 @@ -import z from "zod" +import { Schema } from "effect" import { ProjectID } from "@/project/schema" import { WorkspaceID } from "./schema" +import { zod } from "@/util/effect-zod" +import { type DeepMutable, withStatics } from "@/util/schema" -export const WorkspaceInfo = z.object({ - id: WorkspaceID.zod, - type: z.string(), - name: z.string(), - branch: z.string().nullable(), - directory: z.string().nullable(), - extra: z.unknown().nullable(), - projectID: ProjectID.zod, +export const WorkspaceInfo = Schema.Struct({ + id: WorkspaceID, + type: Schema.String, + name: Schema.String, + branch: Schema.NullOr(Schema.String), + directory: Schema.NullOr(Schema.String), + extra: Schema.NullOr(Schema.Unknown), + projectID: ProjectID, }) -export type WorkspaceInfo = z.infer + .annotate({ identifier: "Workspace" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type WorkspaceInfo = DeepMutable> + +export const WorkspaceAdaptorEntry = Schema.Struct({ + type: Schema.String, + name: Schema.String, + description: Schema.String, +}).pipe(withStatics((s) => ({ zod: zod(s) }))) +export type WorkspaceAdaptorEntry = Schema.Schema.Type export type Target = | { diff --git a/packages/opencode/src/control-plane/workspace.ts b/packages/opencode/src/control-plane/workspace.ts index 8519cb06c1..107f2d9903 100644 --- a/packages/opencode/src/control-plane/workspace.ts +++ b/packages/opencode/src/control-plane/workspace.ts @@ -1,4 +1,3 @@ -import z from "zod" import { Schema } from "effect" import { setTimeout as sleep } from "node:timers/promises" import { fn } from "@/util/fn" @@ -16,7 +15,7 @@ import { ProjectID } from "@/project/schema" import { Slug } from "@opencode-ai/shared/util/slug" import { WorkspaceTable } from "./workspace.sql" import { getAdaptor } from "./adaptors" -import { WorkspaceInfo } from "./types" +import { type WorkspaceInfo, WorkspaceInfo as WorkspaceInfoSchema } from "./types" import { WorkspaceID } from "./schema" import { parseSSE } from "./sse" import { Session } from "@/session" @@ -26,12 +25,11 @@ import { errorData } from "@/util/error" import { AppRuntime } from "@/effect/app-runtime" import { waitEvent } from "./util" import { WorkspaceContext } from "./workspace-context" -import { NonNegativeInt } from "@/util/schema" +import { NonNegativeInt, withStatics } from "@/util/schema" +import { zod as effectZod, zodObject } from "@/util/effect-zod" -export const Info = WorkspaceInfo.meta({ - ref: "Workspace", -}) -export type Info = z.infer +export const Info = WorkspaceInfoSchema +export type Info = WorkspaceInfo export const ConnectionStatus = Schema.Struct({ workspaceID: WorkspaceID, @@ -75,15 +73,16 @@ function fromRow(row: typeof WorkspaceTable.$inferSelect): Info { } } -const CreateInput = z.object({ - id: WorkspaceID.zod.optional(), - type: Info.shape.type, - branch: Info.shape.branch, - projectID: ProjectID.zod, - extra: Info.shape.extra, -}) +export const CreateInput = Schema.Struct({ + id: Schema.optional(WorkspaceID), + type: Info.fields.type, + branch: Info.fields.branch, + projectID: ProjectID, + extra: Info.fields.extra, +}).pipe(withStatics((s) => ({ zod: effectZod(s), zodObject: zodObject(s) }))) +export type CreateInput = Schema.Schema.Type -export const create = fn(CreateInput, async (input) => { +export const create = fn(CreateInput.zod, async (input) => { const id = WorkspaceID.ascending(input.id) const adaptor = await getAdaptor(input.projectID, input.type) @@ -139,12 +138,13 @@ export const create = fn(CreateInput, async (input) => { return info }) -const SessionRestoreInput = z.object({ - workspaceID: WorkspaceID.zod, - sessionID: SessionID.zod, -}) +export const SessionRestoreInput = Schema.Struct({ + workspaceID: WorkspaceID, + sessionID: SessionID, +}).pipe(withStatics((s) => ({ zod: effectZod(s), zodObject: zodObject(s) }))) +export type SessionRestoreInput = Schema.Schema.Type -export const sessionRestore = fn(SessionRestoreInput, async (input) => { +export const sessionRestore = fn(SessionRestoreInput.zod, async (input) => { log.info("session restore requested", { workspaceID: input.workspaceID, sessionID: input.sessionID, diff --git a/packages/opencode/src/server/routes/control/workspace.ts b/packages/opencode/src/server/routes/control/workspace.ts index d48c687f31..ffbaa6009c 100644 --- a/packages/opencode/src/server/routes/control/workspace.ts +++ b/packages/opencode/src/server/routes/control/workspace.ts @@ -3,6 +3,7 @@ import { describeRoute, resolver, validator } from "hono-openapi" import z from "zod" import { listAdaptors } from "@/control-plane/adaptors" import { Workspace } from "@/control-plane/workspace" +import { WorkspaceAdaptorEntry } from "@/control-plane/types" import { zodObject } from "@/util/effect-zod" import { Instance } from "@/project/instance" import { errors } from "../../error" @@ -26,13 +27,7 @@ export const WorkspaceRoutes = lazy(() => content: { "application/json": { schema: resolver( - z.array( - z.object({ - type: z.string(), - name: z.string(), - description: z.string(), - }), - ), + z.array(zodObject(WorkspaceAdaptorEntry)), ), }, }, @@ -54,7 +49,7 @@ export const WorkspaceRoutes = lazy(() => description: "Workspace created", content: { "application/json": { - schema: resolver(Workspace.Info), + schema: resolver(Workspace.Info.zod), }, }, }, @@ -63,12 +58,12 @@ export const WorkspaceRoutes = lazy(() => }), validator( "json", - Workspace.create.schema.omit({ + Workspace.CreateInput.zodObject.omit({ projectID: true, }), ), async (c) => { - const body = c.req.valid("json") + const body = c.req.valid("json") as Omit const workspace = await Workspace.create({ projectID: Instance.project.id, ...body, @@ -87,7 +82,7 @@ export const WorkspaceRoutes = lazy(() => description: "Workspaces", content: { "application/json": { - schema: resolver(z.array(Workspace.Info)), + schema: resolver(z.array(Workspace.Info.zod)), }, }, }, @@ -130,7 +125,7 @@ export const WorkspaceRoutes = lazy(() => description: "Workspace removed", content: { "application/json": { - schema: resolver(Workspace.Info.optional()), + schema: resolver(Workspace.Info.zod.optional()), }, }, }, @@ -140,7 +135,7 @@ export const WorkspaceRoutes = lazy(() => validator( "param", z.object({ - id: Workspace.Info.shape.id, + id: zodObject(Workspace.Info).shape.id, }), ), async (c) => { @@ -170,11 +165,11 @@ export const WorkspaceRoutes = lazy(() => ...errors(400), }, }), - validator("param", z.object({ id: Workspace.Info.shape.id })), - validator("json", Workspace.sessionRestore.schema.omit({ workspaceID: true })), + validator("param", z.object({ id: zodObject(Workspace.Info).shape.id })), + validator("json", Workspace.SessionRestoreInput.zodObject.omit({ workspaceID: true })), async (c) => { const { id } = c.req.valid("param") - const body = c.req.valid("json") + const body = c.req.valid("json") as Omit log.info("session restore route requested", { workspaceID: id, sessionID: body.sessionID, From a771859362ab61983671ca9a82ec1ccfa34fc689 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Thu, 23 Apr 2026 20:50:19 +0000 Subject: [PATCH 50/92] chore: generate --- packages/opencode/src/server/routes/control/workspace.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/opencode/src/server/routes/control/workspace.ts b/packages/opencode/src/server/routes/control/workspace.ts index ffbaa6009c..bf5584347d 100644 --- a/packages/opencode/src/server/routes/control/workspace.ts +++ b/packages/opencode/src/server/routes/control/workspace.ts @@ -26,9 +26,7 @@ export const WorkspaceRoutes = lazy(() => description: "Workspace adaptors", content: { "application/json": { - schema: resolver( - z.array(zodObject(WorkspaceAdaptorEntry)), - ), + schema: resolver(z.array(zodObject(WorkspaceAdaptorEntry))), }, }, }, From 87321942fee25786448f02284ebeaee1caf4e86c Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Thu, 23 Apr 2026 17:08:46 -0400 Subject: [PATCH 51/92] chore: update copilot readme to symlink to an agents md to prevent dumbass agents from touching these files (#24057) --- packages/opencode/src/provider/sdk/copilot/AGENTS.md | 1 + packages/opencode/src/provider/sdk/copilot/README.md | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 120000 packages/opencode/src/provider/sdk/copilot/AGENTS.md diff --git a/packages/opencode/src/provider/sdk/copilot/AGENTS.md b/packages/opencode/src/provider/sdk/copilot/AGENTS.md new file mode 120000 index 0000000000..42061c01a1 --- /dev/null +++ b/packages/opencode/src/provider/sdk/copilot/AGENTS.md @@ -0,0 +1 @@ +README.md \ No newline at end of file diff --git a/packages/opencode/src/provider/sdk/copilot/README.md b/packages/opencode/src/provider/sdk/copilot/README.md index 8ce03d6140..d1051a4da0 100644 --- a/packages/opencode/src/provider/sdk/copilot/README.md +++ b/packages/opencode/src/provider/sdk/copilot/README.md @@ -1,5 +1,5 @@ This is a temporary package used primarily for GitHub Copilot compatibility. -Avoid making changes to these files unless you only want to affect the Copilot provider. +These DO NOT apply for openai-compatible providers or majority of providers supporting completions/responses apis. THIS IS ONLY FOR GITHUB COPILOT!!! -Also, this should ONLY be used for the Copilot provider. +Avoid making edits to these files From 334ab4707c809172e77619ae7d6b22c5577c7238 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Thu, 23 Apr 2026 17:31:43 -0400 Subject: [PATCH 52/92] fix: account for additional openai retry case (#24063) --- packages/opencode/src/provider/error.ts | 12 ++++++++-- .../opencode/test/session/message-v2.test.ts | 24 +++++++++++++++++++ packages/opencode/test/session/retry.test.ts | 22 +++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/provider/error.ts b/packages/opencode/src/provider/error.ts index a2409559f5..a4f629caf3 100644 --- a/packages/opencode/src/provider/error.ts +++ b/packages/opencode/src/provider/error.ts @@ -111,12 +111,13 @@ export type ParsedStreamError = | { type: "api_error" message: string - isRetryable: false + isRetryable: boolean responseBody: string } export function parseStreamError(input: unknown): ParsedStreamError | undefined { - const body = json(input) + const raw = json(input) + const body = typeof raw?.message === "string" ? (json(raw.message) ?? raw) : raw if (!body) return const responseBody = JSON.stringify(body) @@ -150,6 +151,13 @@ export function parseStreamError(input: unknown): ParsedStreamError | undefined isRetryable: false, responseBody, } + case "server_error": + return { + type: "api_error", + message: typeof body?.error?.message === "string" ? body?.error?.message : "Server error.", + isRetryable: true, + responseBody, + } } } diff --git a/packages/opencode/test/session/message-v2.test.ts b/packages/opencode/test/session/message-v2.test.ts index 231d58c21a..abada013df 100644 --- a/packages/opencode/test/session/message-v2.test.ts +++ b/packages/opencode/test/session/message-v2.test.ts @@ -1075,6 +1075,30 @@ describe("session.message-v2.fromError", () => { }) }) + test("serializes OpenAI response server_error stream chunks as retryable APIError", () => { + const body = { + type: "error", + sequence_number: 2, + error: { + type: "server_error", + code: "server_error", + message: + "An error occurred while processing your request. You can retry your request, or contact us through our help center at help.openai.com if the error persists. Please include the request ID req_77eccd008d984bf6bf82d1b2c2b68715 in your message.", + param: null, + }, + } + const result = MessageV2.fromError({ message: JSON.stringify(body) }, { providerID }) + + expect(result).toStrictEqual({ + name: "APIError", + data: { + message: body.error.message, + isRetryable: true, + responseBody: JSON.stringify(body), + }, + }) + }) + test("detects context overflow from APICallError provider messages", () => { const cases = [ "prompt is too long: 213462 tokens > 200000 maximum", diff --git a/packages/opencode/test/session/retry.test.ts b/packages/opencode/test/session/retry.test.ts index ade2647869..6ca8775f30 100644 --- a/packages/opencode/test/session/retry.test.ts +++ b/packages/opencode/test/session/retry.test.ts @@ -294,4 +294,26 @@ describe("session.message-v2.fromError", () => { const result = MessageV2.fromError(error, { providerID: ProviderID.make("openai") }) as MessageV2.APIError expect(result.data.isRetryable).toBe(true) }) + + test("converts OpenAI server_error stream chunks to retryable APIError", () => { + const result = MessageV2.fromError( + { + message: JSON.stringify({ + type: "error", + sequence_number: 2, + error: { + type: "server_error", + code: "server_error", + message: "An error occurred while processing your request.", + param: null, + }, + }), + }, + { providerID: ProviderID.make("openai") }, + ) + + expect(MessageV2.APIError.isInstance(result)).toBe(true) + expect((result as MessageV2.APIError).data.isRetryable).toBe(true) + expect(SessionRetry.retryable(result)).toBe("An error occurred while processing your request.") + }) }) From e50a688ca309ba4c992fd8e47b5b75a11aef025e Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 23 Apr 2026 17:32:02 -0400 Subject: [PATCH 53/92] feat(httpapi): bridge workspace read endpoints (#24062) --- packages/opencode/specs/effect/http-api.md | 4 +- .../server/routes/instance/httpapi/server.ts | 3 + .../routes/instance/httpapi/workspace.ts | 82 +++++++++++++++++++ packages/opencode/src/server/server.ts | 25 ++++-- .../test/server/httpapi-workspace.test.ts | 55 +++++++++++++ 5 files changed, 160 insertions(+), 9 deletions(-) create mode 100644 packages/opencode/src/server/routes/instance/httpapi/workspace.ts create mode 100644 packages/opencode/test/server/httpapi-workspace.test.ts diff --git a/packages/opencode/specs/effect/http-api.md b/packages/opencode/specs/effect/http-api.md index d882857ba1..6c80dc65a2 100644 --- a/packages/opencode/specs/effect/http-api.md +++ b/packages/opencode/specs/effect/http-api.md @@ -409,7 +409,7 @@ Current instance route inventory: - `project` - `bridged` (partial) bridged endpoints: `GET /project`, `GET /project/current` defer git-init mutation first -- `workspace` - `next` +- `workspace` - `bridged` best small reads: `GET /experimental/workspace/adaptor`, `GET /experimental/workspace`, `GET /experimental/workspace/status` defer create/remove mutations first - `file` - `later` @@ -448,7 +448,7 @@ Recommended near-term sequence: - [x] port `config` providers read endpoint - [x] port `project` read endpoints (`GET /project`, `GET /project/current`) - [x] port `GET /config` full read endpoint -- [ ] port `workspace` read endpoints +- [x] port `workspace` read endpoints - [ ] port `file` JSON read endpoints - [ ] decide when to remove the flag and make Effect routes the default diff --git a/packages/opencode/src/server/routes/instance/httpapi/server.ts b/packages/opencode/src/server/routes/instance/httpapi/server.ts index d012e2c166..7b131d4000 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/server.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/server.ts @@ -14,6 +14,7 @@ import { PermissionApi, permissionHandlers } from "./permission" import { ProjectApi, projectHandlers } from "./project" import { ProviderApi, providerHandlers } from "./provider" import { QuestionApi, questionHandlers } from "./question" +import { WorkspaceApi, workspaceHandlers } from "./workspace" import { memoMap } from "@/effect/memo-map" const Query = Schema.Struct({ @@ -112,6 +113,7 @@ const PermissionSecured = PermissionApi.middleware(Authorization) const ProjectSecured = ProjectApi.middleware(Authorization) const ProviderSecured = ProviderApi.middleware(Authorization) const ConfigSecured = ConfigApi.middleware(Authorization) +const WorkspaceSecured = WorkspaceApi.middleware(Authorization) export const routes = Layer.mergeAll( HttpApiBuilder.layer(ConfigSecured).pipe(Layer.provide(configHandlers)), @@ -119,6 +121,7 @@ export const routes = Layer.mergeAll( HttpApiBuilder.layer(QuestionSecured).pipe(Layer.provide(questionHandlers)), HttpApiBuilder.layer(PermissionSecured).pipe(Layer.provide(permissionHandlers)), HttpApiBuilder.layer(ProviderSecured).pipe(Layer.provide(providerHandlers)), + HttpApiBuilder.layer(WorkspaceSecured).pipe(Layer.provide(workspaceHandlers)), ).pipe( Layer.provide(auth), Layer.provide(normalize), diff --git a/packages/opencode/src/server/routes/instance/httpapi/workspace.ts b/packages/opencode/src/server/routes/instance/httpapi/workspace.ts new file mode 100644 index 0000000000..596545073e --- /dev/null +++ b/packages/opencode/src/server/routes/instance/httpapi/workspace.ts @@ -0,0 +1,82 @@ +import { listAdaptors } from "@/control-plane/adaptors" +import { Workspace } from "@/control-plane/workspace" +import { WorkspaceAdaptorEntry } from "@/control-plane/types" +import * as InstanceState from "@/effect/instance-state" +import { Effect, Layer, Schema } from "effect" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" + +const root = "/experimental/workspace" +export const WorkspacePaths = { + adaptors: `${root}/adaptor`, + list: root, + status: `${root}/status`, +} as const + +export const WorkspaceApi = HttpApi.make("workspace") + .add( + HttpApiGroup.make("workspace") + .add( + HttpApiEndpoint.get("adaptors", WorkspacePaths.adaptors, { + success: Schema.Array(WorkspaceAdaptorEntry), + }).annotateMerge( + OpenApi.annotations({ + identifier: "experimental.workspace.adaptor.list", + summary: "List workspace adaptors", + description: "List all available workspace adaptors for the current project.", + }), + ), + HttpApiEndpoint.get("list", WorkspacePaths.list, { + success: Schema.Array(Workspace.Info), + }).annotateMerge( + OpenApi.annotations({ + identifier: "experimental.workspace.list", + summary: "List workspaces", + description: "List all workspaces.", + }), + ), + HttpApiEndpoint.get("status", WorkspacePaths.status, { + success: Schema.Array(Workspace.ConnectionStatus), + }).annotateMerge( + OpenApi.annotations({ + identifier: "experimental.workspace.status", + summary: "Workspace status", + description: "Get connection status for workspaces in the current project.", + }), + ), + ) + .annotateMerge( + OpenApi.annotations({ + title: "workspace", + description: "Experimental HttpApi workspace routes.", + }), + ), + ) + .annotateMerge( + OpenApi.annotations({ + title: "opencode experimental HttpApi", + version: "0.0.1", + description: "Experimental HttpApi surface for selected instance routes.", + }), + ) + +export const workspaceHandlers = Layer.unwrap( + Effect.gen(function* () { + const adaptors = Effect.fn("WorkspaceHttpApi.adaptors")(function* () { + const ctx = yield* InstanceState.context + return yield* Effect.promise(() => listAdaptors(ctx.project.id)) + }) + + const list = Effect.fn("WorkspaceHttpApi.list")(function* () { + return Workspace.list((yield* InstanceState.context).project) + }) + + const status = Effect.fn("WorkspaceHttpApi.status")(function* () { + const ids = new Set(Workspace.list((yield* InstanceState.context).project).map((item) => item.id)) + return Workspace.status().filter((item) => ids.has(item.workspaceID)) + }) + + return HttpApiBuilder.group(WorkspaceApi, "workspace", (handlers) => + handlers.handle("adaptors", adaptors).handle("list", list).handle("status", status), + ) + }), +) diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index 8b1f1aee10..d74de559dc 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -16,6 +16,9 @@ import { GlobalRoutes } from "./routes/global" import { WorkspaceRouterMiddleware } from "./workspace" import { InstanceMiddleware } from "./routes/instance/middleware" import { WorkspaceRoutes } from "./routes/control/workspace" +import { ExperimentalHttpApiServer } from "./routes/instance/httpapi/server" +import { WorkspacePaths } from "./routes/instance/httpapi/workspace" +import { Context } from "effect" // @ts-ignore This global is needed to prevent ai-sdk from logging warnings to stdout https://github.com/vercel/ai/blob/2dc67e0ef538307f21368db32d5a12345d98831b/packages/ai/src/logger/log-warnings.ts#L85 globalThis.AI_SDK_LOG_WARNINGS = false @@ -54,16 +57,24 @@ function create(opts: { cors?: string[] }) { } } + const workspaceApp = new Hono() + const workspaceLegacyApp = new Hono() + .use(InstanceMiddleware()) + .route("/experimental/workspace", WorkspaceRoutes()) + .use(WorkspaceRouterMiddleware(runtime.upgradeWebSocket)) + if (Flag.OPENCODE_EXPERIMENTAL_HTTPAPI) { + const handler = ExperimentalHttpApiServer.webHandler().handler + const context = Context.empty() as Context.Context + workspaceApp.get(WorkspacePaths.adaptors, (c) => handler(c.req.raw, context)) + workspaceApp.get(WorkspacePaths.list, (c) => handler(c.req.raw, context)) + workspaceApp.get(WorkspacePaths.status, (c) => handler(c.req.raw, context)) + } + workspaceApp.route("/", workspaceLegacyApp) + return { app: app .route("/", ControlPlaneRoutes()) - .route( - "/", - new Hono() - .use(InstanceMiddleware()) - .route("/experimental/workspace", WorkspaceRoutes()) - .use(WorkspaceRouterMiddleware(runtime.upgradeWebSocket)), - ) + .route("/", workspaceApp) .route("/", InstanceRoutes(runtime.upgradeWebSocket)) .route("/", UIRoutes()), runtime, diff --git a/packages/opencode/test/server/httpapi-workspace.test.ts b/packages/opencode/test/server/httpapi-workspace.test.ts new file mode 100644 index 0000000000..8256d8330f --- /dev/null +++ b/packages/opencode/test/server/httpapi-workspace.test.ts @@ -0,0 +1,55 @@ +import { afterEach, describe, expect, test } from "bun:test" +import { Context } from "effect" +import { ExperimentalHttpApiServer } from "../../src/server/routes/instance/httpapi/server" +import { WorkspacePaths } from "../../src/server/routes/instance/httpapi/workspace" +import { Log } from "../../src/util" +import { resetDatabase } from "../fixture/db" +import { tmpdir } from "../fixture/fixture" +import { Instance } from "../../src/project/instance" + +void Log.init({ print: false }) + +const context = Context.empty() as Context.Context + +function request(path: string, directory: string) { + return ExperimentalHttpApiServer.webHandler().handler( + new Request(`http://localhost${path}`, { + headers: { + "x-opencode-directory": directory, + }, + }), + context, + ) +} + +afterEach(async () => { + await Instance.disposeAll() + await resetDatabase() +}) + +describe("workspace HttpApi", () => { + test("serves read endpoints", async () => { + await using tmp = await tmpdir({ git: true }) + + const [adaptors, workspaces, status] = await Promise.all([ + request(WorkspacePaths.adaptors, tmp.path), + request(WorkspacePaths.list, tmp.path), + request(WorkspacePaths.status, tmp.path), + ]) + + expect(adaptors.status).toBe(200) + expect(await adaptors.json()).toEqual([ + { + type: "worktree", + name: "Worktree", + description: "Create a git worktree", + }, + ]) + + expect(workspaces.status).toBe(200) + expect(await workspaces.json()).toEqual([]) + + expect(status.status).toBe(200) + expect(await status.json()).toEqual([]) + }) +}) From f8c6ddd4cb08aab493fcaab69d44c5085083152e Mon Sep 17 00:00:00 2001 From: rahul Date: Thu, 23 Apr 2026 17:43:33 -0400 Subject: [PATCH 54/92] feat(truncate): allow configuring tool output truncation limits (#23770) Co-authored-by: rgs_ramp Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> --- packages/opencode/src/config/config.ts | 13 ++++ packages/opencode/src/tool/bash.ts | 17 ++--- packages/opencode/src/tool/truncate.ts | 24 +++++-- .../opencode/test/tool/truncation.test.ts | 64 +++++++++++++++++++ 4 files changed, 106 insertions(+), 12 deletions(-) diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index eab199232a..f1ceb1b4ed 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -201,6 +201,19 @@ export const Info = Schema.Struct({ url: Schema.optional(Schema.String).annotate({ description: "Enterprise URL" }), }), ), + tool_output: Schema.optional( + Schema.Struct({ + max_lines: Schema.optional(PositiveInt).annotate({ + description: "Maximum lines of tool output before it is truncated and saved to disk (default: 2000)", + }), + max_bytes: Schema.optional(PositiveInt).annotate({ + description: "Maximum bytes of tool output before it is truncated and saved to disk (default: 51200)", + }), + }), + ).annotate({ + description: + "Thresholds for truncating tool output. When output exceeds either limit, the full text is written to the truncation directory and a preview is returned.", + }), compaction: Schema.optional( Schema.Struct({ auto: Schema.optional(Schema.Boolean).annotate({ diff --git a/packages/opencode/src/tool/bash.ts b/packages/opencode/src/tool/bash.ts index 2d4d59b1bf..0a7e1a6dc2 100644 --- a/packages/opencode/src/tool/bash.ts +++ b/packages/opencode/src/tool/bash.ts @@ -416,9 +416,8 @@ export const BashTool = Tool.define( }, ctx: Tool.Context, ) { - const bytes = Truncate.MAX_BYTES - const lines = Truncate.MAX_LINES - const keep = bytes * 2 + const limits = yield* trunc.limits() + const keep = limits.maxBytes * 2 let full = "" let last = "" const list: Chunk[] = [] @@ -458,7 +457,7 @@ export const BashTool = Tool.define( sink?.write(chunk) } else { full += chunk - if (Buffer.byteLength(full, "utf-8") > bytes) { + if (Buffer.byteLength(full, "utf-8") > limits.maxBytes) { return trunc.write(full).pipe( Effect.andThen((next) => Effect.sync(() => { @@ -525,7 +524,7 @@ export const BashTool = Tool.define( } if (aborted) meta.push("User aborted the command") const raw = list.map((item) => item.text).join("") - const end = tail(raw, lines, bytes) + const end = tail(raw, limits.maxLines, limits.maxBytes) if (end.cut) cut = true if (!file && end.cut) { file = yield* trunc.write(raw) @@ -566,7 +565,7 @@ export const BashTool = Tool.define( }) return () => - Effect.sync(() => { + Effect.gen(function* () { const shell = Shell.acceptable() const name = Shell.name(shell) const chain = @@ -575,13 +574,15 @@ export const BashTool = Tool.define( : "If the commands depend on each other and must run sequentially, use a single Bash call with '&&' to chain them together (e.g., `git add . && git commit -m \"message\" && git push`). For instance, if one operation must complete before another starts (like mkdir before cp, Write before Bash for git operations, or git add before git commit), run these operations sequentially instead." log.info("bash tool using shell", { shell }) + const limits = yield* trunc.limits() + return { description: DESCRIPTION.replaceAll("${directory}", Instance.directory) .replaceAll("${os}", process.platform) .replaceAll("${shell}", name) .replaceAll("${chaining}", chain) - .replaceAll("${maxLines}", String(Truncate.MAX_LINES)) - .replaceAll("${maxBytes}", String(Truncate.MAX_BYTES)), + .replaceAll("${maxLines}", String(limits.maxLines)) + .replaceAll("${maxBytes}", String(limits.maxBytes)), parameters: Parameters, execute: (params: Schema.Schema.Type, ctx: Tool.Context) => Effect.gen(function* () { diff --git a/packages/opencode/src/tool/truncate.ts b/packages/opencode/src/tool/truncate.ts index d990e7adf7..e0d846858e 100644 --- a/packages/opencode/src/tool/truncate.ts +++ b/packages/opencode/src/tool/truncate.ts @@ -1,9 +1,10 @@ import { NodePath } from "@effect/platform-node" -import { Cause, Duration, Effect, Layer, Schedule, Context } from "effect" +import { Cause, Duration, Effect, Layer, Option, Schedule, Context } from "effect" import path from "path" import type { Agent } from "../agent/agent" import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { evaluate } from "@/permission/evaluate" +import { Config } from "../config" import { Identifier } from "../id/id" import { Log } from "../util" import { ToolID } from "./schema" @@ -38,6 +39,10 @@ export interface Interface { * to the truncation directory and returns a preview plus a hint to inspect the saved file. */ readonly output: (text: string, options?: Options, agent?: Agent.Info) => Effect.Effect + /** + * Resolved truncation limits: values from `tool_output` in opencode config, or MAX_LINES / MAX_BYTES if unset. + */ + readonly limits: () => Effect.Effect<{ maxLines: number; maxBytes: number }> } export class Service extends Context.Service()("@opencode/Truncate") {} @@ -68,9 +73,20 @@ export const layer = Layer.effect( return file }) + const limits = Effect.fn("Truncate.limits")(function* () { + const configSvc = yield* Effect.serviceOption(Config.Service) + if (Option.isNone(configSvc)) return { maxLines: MAX_LINES, maxBytes: MAX_BYTES } + const cfg = yield* configSvc.value.get().pipe(Effect.catch(() => Effect.succeed(undefined))) + return { + maxLines: cfg?.tool_output?.max_lines ?? MAX_LINES, + maxBytes: cfg?.tool_output?.max_bytes ?? MAX_BYTES, + } + }) + const output = Effect.fn("Truncate.output")(function* (text: string, options: Options = {}, agent?: Agent.Info) { - const maxLines = options.maxLines ?? MAX_LINES - const maxBytes = options.maxBytes ?? MAX_BYTES + const resolved = yield* limits() + const maxLines = options.maxLines ?? resolved.maxLines + const maxBytes = options.maxBytes ?? resolved.maxBytes const direction = options.direction ?? "head" const lines = text.split("\n") const totalBytes = Buffer.byteLength(text, "utf-8") @@ -135,7 +151,7 @@ export const layer = Layer.effect( Effect.forkScoped, ) - return Service.of({ cleanup, write, output }) + return Service.of({ cleanup, write, output, limits }) }), ) diff --git a/packages/opencode/test/tool/truncation.test.ts b/packages/opencode/test/tool/truncation.test.ts index d3cec4cd9e..369ad2d581 100644 --- a/packages/opencode/test/tool/truncation.test.ts +++ b/packages/opencode/test/tool/truncation.test.ts @@ -2,6 +2,7 @@ import { describe, test, expect } from "bun:test" import { NodeFileSystem } from "@effect/platform-node" import { Effect, FileSystem, Layer } from "effect" import { Truncate } from "../../src/tool" +import { Config } from "../../src/config" import { Identifier } from "../../src/id/id" import { Process } from "../../src/util" import { Filesystem } from "../../src/util" @@ -14,6 +15,14 @@ const ROOT = path.resolve(import.meta.dir, "..", "..") const it = testEffect(Layer.mergeAll(Truncate.defaultLayer, NodeFileSystem.layer)) +const configuredLayer = (cfg: Config.Info) => + Layer.mergeAll( + Truncate.defaultLayer, + NodeFileSystem.layer, + Layer.mock(Config.Service)({ get: () => Effect.succeed(cfg) }), + ) +const configuredIt = (cfg: Config.Info) => testEffect(configuredLayer(cfg)) + describe("Truncate", () => { describe("output", () => { it.live("truncates large json file by bytes", () => @@ -94,6 +103,61 @@ describe("Truncate", () => { expect(Truncate.MAX_BYTES).toBe(50 * 1024) }) + it.live("limits() falls back to MAX_LINES/MAX_BYTES when Config is not provided", () => + Effect.gen(function* () { + const svc = yield* Truncate.Service + const resolved = yield* svc.limits() + expect(resolved.maxLines).toBe(Truncate.MAX_LINES) + expect(resolved.maxBytes).toBe(Truncate.MAX_BYTES) + }), + ) + + describe("with tool_output config", () => { + const limitsIt = configuredIt({ tool_output: { max_lines: 123, max_bytes: 456 } }) + limitsIt.live("limits() reflects config overrides", () => + Effect.gen(function* () { + const resolved = yield* (yield* Truncate.Service).limits() + expect(resolved.maxLines).toBe(123) + expect(resolved.maxBytes).toBe(456) + }), + ) + + // Huge byte budget isolates line truncation. 100 lines against max_lines: 10 + // proves the configured line limit is what `output()` enforces. + const lineIt = configuredIt({ tool_output: { max_lines: 10, max_bytes: 1024 * 1024 } }) + lineIt.live("output() truncates to configured max_lines", () => + Effect.gen(function* () { + const content = Array.from({ length: 100 }, (_, i) => `line${i}`).join("\n") + const result = yield* (yield* Truncate.Service).output(content) + expect(result.truncated).toBe(true) + expect(result.content).toContain("...90 lines truncated...") + }), + ) + + // Huge line budget isolates byte truncation. + const byteIt = configuredIt({ tool_output: { max_lines: 1_000_000, max_bytes: 100 } }) + byteIt.live("output() truncates to configured max_bytes", () => + Effect.gen(function* () { + const content = "a".repeat(1000) + const result = yield* (yield* Truncate.Service).output(content) + expect(result.truncated).toBe(true) + expect(result.content).toContain("bytes truncated...") + }), + ) + + const overrideIt = configuredIt({ tool_output: { max_lines: 10, max_bytes: 100 } }) + overrideIt.live("per-call options still override config", () => + Effect.gen(function* () { + const content = Array.from({ length: 50 }, (_, i) => `line${i}`).join("\n") + const result = yield* (yield* Truncate.Service).output(content, { + maxLines: 1000, + maxBytes: 1024 * 1024, + }) + expect(result.truncated).toBe(false) + }), + ) + }) + it.live("large single-line file truncates with byte message", () => Effect.gen(function* () { const svc = yield* Truncate.Service From 5c5069b6227ce6c4cbc1b6daca65da69daf43f84 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Thu, 23 Apr 2026 21:44:44 +0000 Subject: [PATCH 55/92] chore: generate --- packages/sdk/js/src/v2/gen/types.gen.ts | 13 +++++++++++++ packages/sdk/openapi.json | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index d28ce25794..40e661b46a 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -1633,6 +1633,19 @@ export type Config = { */ url?: string } + /** + * Thresholds for truncating tool output. When output exceeds either limit, the full text is written to the truncation directory and a preview is returned. + */ + tool_output?: { + /** + * Maximum lines of tool output before it is truncated and saved to disk (default: 2000) + */ + max_lines?: number + /** + * Maximum bytes of tool output before it is truncated and saved to disk (default: 51200) + */ + max_bytes?: number + } compaction?: { /** * Enable automatic compaction when context is full (default: true) diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 0c3d189722..cd7b381d83 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -11822,6 +11822,24 @@ } } }, + "tool_output": { + "description": "Thresholds for truncating tool output. When output exceeds either limit, the full text is written to the truncation directory and a preview is returned.", + "type": "object", + "properties": { + "max_lines": { + "description": "Maximum lines of tool output before it is truncated and saved to disk (default: 2000)", + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + }, + "max_bytes": { + "description": "Maximum bytes of tool output before it is truncated and saved to disk (default: 51200)", + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + } + } + }, "compaction": { "type": "object", "properties": { From 3bfe6a1ef6cf41bc7f05339d63ab8d6032c6e8e1 Mon Sep 17 00:00:00 2001 From: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Date: Fri, 24 Apr 2026 12:50:34 +0800 Subject: [PATCH 56/92] ci: add platform-specific bun install flags (#23822) --- .github/actions/setup-bun/action.yml | 9 +++++++-- .github/workflows/publish.yml | 8 ++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/actions/setup-bun/action.yml b/.github/actions/setup-bun/action.yml index d1e3bfc25d..9859174a2e 100644 --- a/.github/actions/setup-bun/action.yml +++ b/.github/actions/setup-bun/action.yml @@ -1,5 +1,10 @@ name: "Setup Bun" description: "Setup Bun with caching and install dependencies" +inputs: + install-flags: + description: "Additional flags to pass to 'bun install'" + required: false + default: "" runs: using: "composite" steps: @@ -46,8 +51,8 @@ runs: # e.g. ./patches/ for standard-openapi # https://github.com/oven-sh/bun/issues/28147 if [ "$RUNNER_OS" = "Windows" ]; then - bun install --linker hoisted + bun install --linker hoisted ${{ inputs.install-flags }} else - bun install + bun install ${{ inputs.install-flags }} fi shell: bash diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index af008f6b17..6cb6af0a8d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -402,12 +402,14 @@ jobs: fail-fast: false matrix: settings: - - host: macos-latest + - host: macos-26-intel target: x86_64-apple-darwin platform_flag: --mac --x64 - - host: macos-latest + bun_install_flags: --os=darwin --cpu=x64 + - host: macos-26 target: aarch64-apple-darwin platform_flag: --mac --arm64 + bun_install_flags: --os=darwin --cpu=arm64 # github-hosted: blacksmith lacks ARM64 MSVC cross-compilation toolchain - host: "windows-2025" target: aarch64-pc-windows-msvc @@ -437,6 +439,8 @@ jobs: run: echo "${{ secrets.APPLE_API_KEY_PATH }}" > $RUNNER_TEMP/apple-api-key.p8 - uses: ./.github/actions/setup-bun + with: + install-flags: ${{ matrix.settings.bun_install_flags }} - name: Azure login if: runner.os == 'Windows' From 2e156b8990a1e72cfb231eadafe76e4e60c096ea Mon Sep 17 00:00:00 2001 From: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Date: Fri, 24 Apr 2026 13:27:36 +0800 Subject: [PATCH 57/92] fix(desktop): avoid relaunching without installing updates (#23806) --- .../app/src/components/settings-general.tsx | 5 ++--- packages/app/src/context/platform.tsx | 6 +++--- packages/app/src/pages/error.tsx | 5 ++--- packages/app/src/pages/layout.tsx | 5 ++--- packages/desktop-electron/src/main/index.ts | 21 +++++++++++++++---- .../desktop-electron/src/renderer/index.tsx | 2 +- packages/desktop/src/index.tsx | 9 ++++++-- 7 files changed, 34 insertions(+), 19 deletions(-) diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx index 13651aac06..86b8c317c9 100644 --- a/packages/app/src/components/settings-general.tsx +++ b/packages/app/src/components/settings-general.tsx @@ -129,13 +129,12 @@ export const SettingsGeneral: Component = () => { } const actions = - platform.update && platform.restart + platform.updateAndRestart ? [ { label: language.t("toast.update.action.installRestart"), onClick: async () => { - await platform.update!() - await platform.restart!() + await platform.updateAndRestart!() }, }, { diff --git a/packages/app/src/context/platform.tsx b/packages/app/src/context/platform.tsx index 3bdc46391b..fd89bf51ba 100644 --- a/packages/app/src/context/platform.tsx +++ b/packages/app/src/context/platform.tsx @@ -49,11 +49,11 @@ export type Platform = { /** Storage mechanism, defaults to localStorage */ storage?: (name?: string) => SyncStorage | AsyncStorage - /** Check for updates (Tauri only) */ + /** Check for a downloadable desktop update */ checkUpdate?(): Promise - /** Install updates (Tauri only) */ - update?(): Promise + /** Install the downloaded update using the platform restart flow */ + updateAndRestart?(): Promise /** Fetch override */ fetch?: typeof fetch diff --git a/packages/app/src/pages/error.tsx b/packages/app/src/pages/error.tsx index 11284b3d2d..ba0045ec93 100644 --- a/packages/app/src/pages/error.tsx +++ b/packages/app/src/pages/error.tsx @@ -244,10 +244,9 @@ export const ErrorPage: Component = (props) => { } async function installUpdate() { - if (!platform.update || !platform.restart) return + if (!platform.updateAndRestart) return await platform - .update() - .then(() => platform.restart!()) + .updateAndRestart() .then(() => setStore("actionError", undefined)) .catch((err) => { setStore("actionError", formatError(err, language.t)) diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx index 3d3bd5e97b..ac5cf104aa 100644 --- a/packages/app/src/pages/layout.tsx +++ b/packages/app/src/pages/layout.tsx @@ -366,7 +366,7 @@ export default function Layout(props: ParentProps) { const useUpdatePolling = () => onMount(() => { - if (!platform.checkUpdate || !platform.update || !platform.restart) return + if (!platform.checkUpdate || !platform.updateAndRestart) return let toastId: number | undefined let interval: ReturnType | undefined @@ -384,8 +384,7 @@ export default function Layout(props: ParentProps) { { label: language.t("toast.update.action.installRestart"), onClick: async () => { - await platform.update!() - await platform.restart!() + await platform.updateAndRestart!() }, }, { diff --git a/packages/desktop-electron/src/main/index.ts b/packages/desktop-electron/src/main/index.ts index ae9f581186..c9f16606ae 100644 --- a/packages/desktop-electron/src/main/index.ts +++ b/packages/desktop-electron/src/main/index.ts @@ -337,11 +337,16 @@ function setupAutoUpdater() { }) } -let updateReady = false +let downloadedUpdateVersion: string | undefined async function checkUpdate() { if (!UPDATER_ENABLED) return { updateAvailable: false } - updateReady = false + if (downloadedUpdateVersion) { + logger.log("returning cached downloaded update", { + version: downloadedUpdateVersion, + }) + return { updateAvailable: true, version: downloadedUpdateVersion } + } logger.log("checking for updates", { currentVersion: app.getVersion(), channel: autoUpdater.channel, @@ -367,7 +372,7 @@ async function checkUpdate() { logger.log("update available", { version }) await autoUpdater.downloadUpdate() logger.log("update download completed", { version }) - updateReady = true + downloadedUpdateVersion = version return { updateAvailable: true, version } } catch (error) { logger.error("update check failed", error) @@ -376,7 +381,15 @@ async function checkUpdate() { } async function installUpdate() { - if (!updateReady) return + if (!downloadedUpdateVersion) { + logger.log("install update skipped", { + reason: "no downloaded update ready", + }) + return + } + logger.log("installing downloaded update", { + version: downloadedUpdateVersion, + }) killSidecar() autoUpdater.quitAndInstall() } diff --git a/packages/desktop-electron/src/renderer/index.tsx b/packages/desktop-electron/src/renderer/index.tsx index 56fe9fa513..91ea1ae077 100644 --- a/packages/desktop-electron/src/renderer/index.tsx +++ b/packages/desktop-electron/src/renderer/index.tsx @@ -170,7 +170,7 @@ const createPlatform = (): Platform => { return window.api.checkUpdate() }, - update: async () => { + updateAndRestart: async () => { const config = await window.api.getWindowConfig().catch(() => ({ updaterEnabled: false })) if (!config.updaterEnabled) return await window.api.installUpdate() diff --git a/packages/desktop/src/index.tsx b/packages/desktop/src/index.tsx index d6a0ad74f8..a760cb4091 100644 --- a/packages/desktop/src/index.tsx +++ b/packages/desktop/src/index.tsx @@ -297,10 +297,15 @@ const createPlatform = (): Platform => { return { updateAvailable: true, version: next.version } }, - update: async () => { + updateAndRestart: async () => { if (!UPDATER_ENABLED || !update) return if (ostype() === "windows") await commands.killSidecar().catch(() => undefined) - await update.install().catch(() => undefined) + const installed = await update + .install() + .then(() => true) + .catch(() => false) + if (!installed) return + await relaunch() }, restart: async () => { From 6c1268f3b18ed289bc524ed10add8c3caa6131d2 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Fri, 24 Apr 2026 05:28:43 +0000 Subject: [PATCH 58/92] chore: generate --- .../app/src/components/settings-general.tsx | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx index 86b8c317c9..f38442379d 100644 --- a/packages/app/src/components/settings-general.tsx +++ b/packages/app/src/components/settings-general.tsx @@ -128,26 +128,25 @@ export const SettingsGeneral: Component = () => { return } - const actions = - platform.updateAndRestart - ? [ - { - label: language.t("toast.update.action.installRestart"), - onClick: async () => { - await platform.updateAndRestart!() - }, + const actions = platform.updateAndRestart + ? [ + { + label: language.t("toast.update.action.installRestart"), + onClick: async () => { + await platform.updateAndRestart!() }, - { - label: language.t("toast.update.action.notYet"), - onClick: "dismiss" as const, - }, - ] - : [ - { - label: language.t("toast.update.action.notYet"), - onClick: "dismiss" as const, - }, - ] + }, + { + label: language.t("toast.update.action.notYet"), + onClick: "dismiss" as const, + }, + ] + : [ + { + label: language.t("toast.update.action.notYet"), + onClick: "dismiss" as const, + }, + ] showToast({ persistent: true, From 4712f0f3c185fc3a348e2609689130fd2d901954 Mon Sep 17 00:00:00 2001 From: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Date: Fri, 24 Apr 2026 14:04:55 +0800 Subject: [PATCH 59/92] feat(prompt): add shell mode UI with cancel button, custom icon, and example placeholder (#24105) --- packages/app/src/components/prompt-input.tsx | 27 ++++++++++++------- .../components/prompt-input/placeholder.ts | 2 +- packages/app/src/i18n/ar.ts | 2 +- packages/app/src/i18n/br.ts | 2 +- packages/app/src/i18n/bs.ts | 2 +- packages/app/src/i18n/da.ts | 2 +- packages/app/src/i18n/de.ts | 2 +- packages/app/src/i18n/en.ts | 2 +- packages/app/src/i18n/es.ts | 2 +- packages/app/src/i18n/fr.ts | 2 +- packages/app/src/i18n/ja.ts | 2 +- packages/app/src/i18n/ko.ts | 2 +- packages/app/src/i18n/no.ts | 2 +- packages/app/src/i18n/pl.ts | 2 +- packages/app/src/i18n/ru.ts | 2 +- packages/app/src/i18n/th.ts | 2 +- packages/app/src/i18n/tr.ts | 2 +- packages/app/src/i18n/zh.ts | 2 +- packages/app/src/i18n/zht.ts | 2 +- .../.storybook/mocks/app/context/language.ts | 2 +- packages/ui/src/components/icon.tsx | 4 ++- 21 files changed, 40 insertions(+), 29 deletions(-) diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index 06c91c2922..8b69f3b2ab 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -270,7 +270,7 @@ export const PromptInput: Component = (props) => { const buttonsSpring = useSpring(() => (store.mode === "normal" ? 1 : 0), { visualDuration: 0.2, bounce: 0 }) const motion = (value: number) => ({ opacity: value, - transform: `scale(${0.95 + value * 0.05})`, + transform: `scale(${0.98 + value * 0.02})`, filter: `blur(${(1 - value) * 2}px)`, "pointer-events": value > 0.5 ? ("auto" as const) : ("none" as const), }) @@ -345,7 +345,7 @@ export const PromptInput: Component = (props) => { promptPlaceholder({ mode: store.mode, commentCount: commentCount(), - example: suggest() ? language.t(EXAMPLES[store.placeholder]) : "", + example: suggest() ? (store.mode === "shell" ? "git status" : language.t(EXAMPLES[store.placeholder])) : "", suggest: suggest(), t: (key, params) => language.t(key as Parameters[0], params as never), }), @@ -1403,12 +1403,11 @@ export const PromptInput: Component = (props) => { @@ -1451,14 +1450,24 @@ export const PromptInput: Component = (props) => {

    - {language.t("prompt.mode.shell")} -
    + + {language.t("prompt.mode.shell")} +
    +
    diff --git a/packages/app/src/components/prompt-input/placeholder.ts b/packages/app/src/components/prompt-input/placeholder.ts index 395fee51b1..6669f13614 100644 --- a/packages/app/src/components/prompt-input/placeholder.ts +++ b/packages/app/src/components/prompt-input/placeholder.ts @@ -7,7 +7,7 @@ type PromptPlaceholderInput = { } export function promptPlaceholder(input: PromptPlaceholderInput) { - if (input.mode === "shell") return input.t("prompt.placeholder.shell") + if (input.mode === "shell") return input.t("prompt.placeholder.shell", { example: input.example }) if (input.commentCount > 1) return input.t("prompt.placeholder.summarizeComments") if (input.commentCount === 1) return input.t("prompt.placeholder.summarizeComment") if (!input.suggest) return input.t("prompt.placeholder.simple") diff --git a/packages/app/src/i18n/ar.ts b/packages/app/src/i18n/ar.ts index efb2919a5b..702210e4d3 100644 --- a/packages/app/src/i18n/ar.ts +++ b/packages/app/src/i18n/ar.ts @@ -210,7 +210,7 @@ export const dict = { "common.saving": "جارٍ الحفظ...", "common.default": "افتراضي", "common.attachment": "مرفق", - "prompt.placeholder.shell": "أدخل أمر shell...", + "prompt.placeholder.shell": "أدخل أمر shell... {{example}}", "prompt.placeholder.normal": 'اسأل أي شيء... "{{example}}"', "prompt.placeholder.simple": "اسأل أي شيء...", "prompt.placeholder.summarizeComments": "لخّص التعليقات…", diff --git a/packages/app/src/i18n/br.ts b/packages/app/src/i18n/br.ts index 022d012984..b414fff36e 100644 --- a/packages/app/src/i18n/br.ts +++ b/packages/app/src/i18n/br.ts @@ -210,7 +210,7 @@ export const dict = { "common.saving": "Salvando...", "common.default": "Padrão", "common.attachment": "anexo", - "prompt.placeholder.shell": "Digite comando do shell...", + "prompt.placeholder.shell": "Digite comando do shell... {{example}}", "prompt.placeholder.normal": 'Pergunte qualquer coisa... "{{example}}"', "prompt.placeholder.simple": "Pergunte qualquer coisa...", "prompt.placeholder.summarizeComments": "Resumir comentários…", diff --git a/packages/app/src/i18n/bs.ts b/packages/app/src/i18n/bs.ts index 15d8376ab6..e316f87da2 100644 --- a/packages/app/src/i18n/bs.ts +++ b/packages/app/src/i18n/bs.ts @@ -228,7 +228,7 @@ export const dict = { "common.default": "Podrazumijevano", "common.attachment": "prilog", - "prompt.placeholder.shell": "Unesi shell naredbu...", + "prompt.placeholder.shell": "Unesi shell naredbu... {{example}}", "prompt.placeholder.normal": 'Pitaj bilo šta... "{{example}}"', "prompt.placeholder.simple": "Pitaj bilo šta...", "prompt.placeholder.summarizeComments": "Sažmi komentare…", diff --git a/packages/app/src/i18n/da.ts b/packages/app/src/i18n/da.ts index 03cfe2b786..d368f292d2 100644 --- a/packages/app/src/i18n/da.ts +++ b/packages/app/src/i18n/da.ts @@ -226,7 +226,7 @@ export const dict = { "common.default": "Standard", "common.attachment": "vedhæftning", - "prompt.placeholder.shell": "Indtast shell-kommando...", + "prompt.placeholder.shell": "Indtast shell-kommando... {{example}}", "prompt.placeholder.normal": 'Spørg om hvad som helst... "{{example}}"', "prompt.placeholder.simple": "Spørg om hvad som helst...", "prompt.placeholder.summarizeComments": "Opsummér kommentarer…", diff --git a/packages/app/src/i18n/de.ts b/packages/app/src/i18n/de.ts index ccb88e9f41..a2b049c880 100644 --- a/packages/app/src/i18n/de.ts +++ b/packages/app/src/i18n/de.ts @@ -215,7 +215,7 @@ export const dict = { "common.saving": "Speichert...", "common.default": "Standard", "common.attachment": "Anhang", - "prompt.placeholder.shell": "Shell-Befehl eingeben...", + "prompt.placeholder.shell": "Shell-Befehl eingeben... {{example}}", "prompt.placeholder.normal": 'Fragen Sie alles... "{{example}}"', "prompt.placeholder.simple": "Fragen Sie alles...", "prompt.placeholder.summarizeComments": "Kommentare zusammenfassen…", diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts index ed80b38ce4..7326f7c8bb 100644 --- a/packages/app/src/i18n/en.ts +++ b/packages/app/src/i18n/en.ts @@ -230,7 +230,7 @@ export const dict = { "common.default": "Default", "common.attachment": "attachment", - "prompt.placeholder.shell": "Enter shell command...", + "prompt.placeholder.shell": "Enter shell command... {{example}}", "prompt.placeholder.normal": 'Ask anything... "{{example}}"', "prompt.placeholder.simple": "Ask anything...", "prompt.placeholder.summarizeComments": "Summarize comments…", diff --git a/packages/app/src/i18n/es.ts b/packages/app/src/i18n/es.ts index 0b4789c2aa..8dc644bb8e 100644 --- a/packages/app/src/i18n/es.ts +++ b/packages/app/src/i18n/es.ts @@ -227,7 +227,7 @@ export const dict = { "common.default": "Predeterminado", "common.attachment": "adjunto", - "prompt.placeholder.shell": "Introduce comando de shell...", + "prompt.placeholder.shell": "Introduce comando de shell... {{example}}", "prompt.placeholder.normal": 'Pregunta cualquier cosa... "{{example}}"', "prompt.placeholder.simple": "Pregunta cualquier cosa...", "prompt.placeholder.summarizeComments": "Resumir comentarios…", diff --git a/packages/app/src/i18n/fr.ts b/packages/app/src/i18n/fr.ts index 4d73f626b2..1b4916c7d9 100644 --- a/packages/app/src/i18n/fr.ts +++ b/packages/app/src/i18n/fr.ts @@ -210,7 +210,7 @@ export const dict = { "common.saving": "Enregistrement...", "common.default": "Défaut", "common.attachment": "pièce jointe", - "prompt.placeholder.shell": "Entrez une commande shell...", + "prompt.placeholder.shell": "Entrez une commande shell... {{example}}", "prompt.placeholder.normal": 'Demandez n\'importe quoi... "{{example}}"', "prompt.placeholder.simple": "Demandez n'importe quoi...", "prompt.placeholder.summarizeComments": "Résumer les commentaires…", diff --git a/packages/app/src/i18n/ja.ts b/packages/app/src/i18n/ja.ts index 493b1f17ff..979f94203d 100644 --- a/packages/app/src/i18n/ja.ts +++ b/packages/app/src/i18n/ja.ts @@ -209,7 +209,7 @@ export const dict = { "common.saving": "保存中...", "common.default": "デフォルト", "common.attachment": "添付ファイル", - "prompt.placeholder.shell": "シェルコマンドを入力...", + "prompt.placeholder.shell": "シェルコマンドを入力... {{example}}", "prompt.placeholder.normal": '何でも聞いてください... "{{example}}"', "prompt.placeholder.simple": "何でも聞いてください...", "prompt.placeholder.summarizeComments": "コメントを要約…", diff --git a/packages/app/src/i18n/ko.ts b/packages/app/src/i18n/ko.ts index 0218cc1a9e..56ce374a96 100644 --- a/packages/app/src/i18n/ko.ts +++ b/packages/app/src/i18n/ko.ts @@ -209,7 +209,7 @@ export const dict = { "common.saving": "저장 중...", "common.default": "기본값", "common.attachment": "첨부 파일", - "prompt.placeholder.shell": "셸 명령어 입력...", + "prompt.placeholder.shell": "셸 명령어 입력... {{example}}", "prompt.placeholder.normal": '무엇이든 물어보세요... "{{example}}"', "prompt.placeholder.simple": "무엇이든 물어보세요...", "prompt.placeholder.summarizeComments": "댓글 요약…", diff --git a/packages/app/src/i18n/no.ts b/packages/app/src/i18n/no.ts index 43aa844200..d14dd6f98b 100644 --- a/packages/app/src/i18n/no.ts +++ b/packages/app/src/i18n/no.ts @@ -230,7 +230,7 @@ export const dict = { "common.default": "Standard", "common.attachment": "vedlegg", - "prompt.placeholder.shell": "Skriv inn shell-kommando...", + "prompt.placeholder.shell": "Skriv inn shell-kommando... {{example}}", "prompt.placeholder.normal": 'Spør om hva som helst... "{{example}}"', "prompt.placeholder.simple": "Spør om hva som helst...", "prompt.placeholder.summarizeComments": "Oppsummer kommentarer…", diff --git a/packages/app/src/i18n/pl.ts b/packages/app/src/i18n/pl.ts index 6c6d4dddc1..9859ea0ae6 100644 --- a/packages/app/src/i18n/pl.ts +++ b/packages/app/src/i18n/pl.ts @@ -211,7 +211,7 @@ export const dict = { "common.saving": "Zapisywanie...", "common.default": "Domyślny", "common.attachment": "załącznik", - "prompt.placeholder.shell": "Wpisz polecenie terminala...", + "prompt.placeholder.shell": "Wpisz polecenie terminala... {{example}}", "prompt.placeholder.normal": 'Zapytaj o cokolwiek... "{{example}}"', "prompt.placeholder.simple": "Zapytaj o cokolwiek...", "prompt.placeholder.summarizeComments": "Podsumuj komentarze…", diff --git a/packages/app/src/i18n/ru.ts b/packages/app/src/i18n/ru.ts index e0b094877a..6e6ca32030 100644 --- a/packages/app/src/i18n/ru.ts +++ b/packages/app/src/i18n/ru.ts @@ -227,7 +227,7 @@ export const dict = { "common.default": "По умолчанию", "common.attachment": "вложение", - "prompt.placeholder.shell": "Введите команду оболочки...", + "prompt.placeholder.shell": "Введите команду оболочки... {{example}}", "prompt.placeholder.normal": 'Спросите что угодно... "{{example}}"', "prompt.placeholder.simple": "Спросите что угодно...", "prompt.placeholder.summarizeComments": "Суммировать комментарии…", diff --git a/packages/app/src/i18n/th.ts b/packages/app/src/i18n/th.ts index 8a15f29c0b..84e5d3ff21 100644 --- a/packages/app/src/i18n/th.ts +++ b/packages/app/src/i18n/th.ts @@ -227,7 +227,7 @@ export const dict = { "common.default": "ค่าเริ่มต้น", "common.attachment": "ไฟล์แนบ", - "prompt.placeholder.shell": "ป้อนคำสั่งเชลล์...", + "prompt.placeholder.shell": "ป้อนคำสั่งเชลล์... {{example}}", "prompt.placeholder.normal": 'ถามอะไรก็ได้... "{{example}}"', "prompt.placeholder.simple": "ถามอะไรก็ได้...", "prompt.placeholder.summarizeComments": "สรุปความคิดเห็น…", diff --git a/packages/app/src/i18n/tr.ts b/packages/app/src/i18n/tr.ts index f20c05000d..06e233cb51 100644 --- a/packages/app/src/i18n/tr.ts +++ b/packages/app/src/i18n/tr.ts @@ -232,7 +232,7 @@ export const dict = { "common.default": "Varsayılan", "common.attachment": "ek", - "prompt.placeholder.shell": "Kabuk komutu girin...", + "prompt.placeholder.shell": "Kabuk komutu girin... {{example}}", "prompt.placeholder.normal": 'Bir şeyler sorun... "{{example}}"', "prompt.placeholder.simple": "Bir şeyler sorun...", "prompt.placeholder.summarizeComments": "Yorumları özetle…", diff --git a/packages/app/src/i18n/zh.ts b/packages/app/src/i18n/zh.ts index 05310df965..fa83707e8d 100644 --- a/packages/app/src/i18n/zh.ts +++ b/packages/app/src/i18n/zh.ts @@ -249,7 +249,7 @@ export const dict = { "common.default": "默认", "common.attachment": "附件", - "prompt.placeholder.shell": "输入 shell 命令...", + "prompt.placeholder.shell": "输入 shell 命令... {{example}}", "prompt.placeholder.normal": '随便问点什么... "{{example}}"', "prompt.placeholder.simple": "随便问点什么...", "prompt.placeholder.summarizeComments": "总结评论…", diff --git a/packages/app/src/i18n/zht.ts b/packages/app/src/i18n/zht.ts index 43681c7793..e9d265acc0 100644 --- a/packages/app/src/i18n/zht.ts +++ b/packages/app/src/i18n/zht.ts @@ -227,7 +227,7 @@ export const dict = { "common.default": "預設", "common.attachment": "附件", - "prompt.placeholder.shell": "輸入 shell 命令...", + "prompt.placeholder.shell": "輸入 shell 命令... {{example}}", "prompt.placeholder.normal": '隨便問點什麼... "{{example}}"', "prompt.placeholder.simple": "隨便問點什麼...", "prompt.placeholder.summarizeComments": "摘要評論…", diff --git a/packages/storybook/.storybook/mocks/app/context/language.ts b/packages/storybook/.storybook/mocks/app/context/language.ts index c3317ca2e9..df28d79fbd 100644 --- a/packages/storybook/.storybook/mocks/app/context/language.ts +++ b/packages/storybook/.storybook/mocks/app/context/language.ts @@ -5,7 +5,7 @@ const dict: Record = { "prompt.loading": "Loading prompt...", "prompt.placeholder.normal": "Ask anything...", "prompt.placeholder.simple": "Ask anything...", - "prompt.placeholder.shell": "Run a shell command...", + "prompt.placeholder.shell": "Run a shell command... {{example}}", "prompt.placeholder.summarizeComment": "Summarize this comment", "prompt.placeholder.summarizeComments": "Summarize these comments", "prompt.action.attachFile": "Attach files", diff --git a/packages/ui/src/components/icon.tsx b/packages/ui/src/components/icon.tsx index 08726d0ff2..2e4d1f53b7 100644 --- a/packages/ui/src/components/icon.tsx +++ b/packages/ui/src/components/icon.tsx @@ -102,6 +102,7 @@ const icons = { link: ``, providers: ``, models: ``, + "arrow-undo-down": ``, } export interface IconProps extends ComponentProps<"svg"> { @@ -111,7 +112,8 @@ export interface IconProps extends ComponentProps<"svg"> { export function Icon(props: IconProps) { const [local, others] = splitProps(props, ["name", "size", "class", "classList"]) - const viewBox = () => (local.name === "magnifying-glass" ? "0 0 16 16" : "0 0 20 20") + const viewBox = () => + local.name === "magnifying-glass" || local.name === "arrow-undo-down" ? "0 0 16 16" : "0 0 20 20" return (
    Date: Fri, 24 Apr 2026 02:01:37 -0400 Subject: [PATCH 60/92] sync --- .../console/app/src/routes/zen/util/provider/anthropic.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/console/app/src/routes/zen/util/provider/anthropic.ts b/packages/console/app/src/routes/zen/util/provider/anthropic.ts index de49cddc1b..d93bc58d82 100644 --- a/packages/console/app/src/routes/zen/util/provider/anthropic.ts +++ b/packages/console/app/src/routes/zen/util/provider/anthropic.ts @@ -53,9 +53,7 @@ export const anthropicHelper: ProviderHelper = ({ reqModel, providerModel }) => anthropic_version: "bedrock-2023-05-31", anthropic_beta: supports1m ? ["context-1m-2025-08-07"] : undefined, } - : { - service_tier: "standard_only", - }), + : {}), }), createBinaryStreamDecoder: () => { if (!isBedrock) return undefined From a4bd88ab9702e1275438540812c1fb7de3ce87b5 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 24 Apr 2026 02:09:14 -0400 Subject: [PATCH 61/92] zen: deepseek v4 pro --- packages/web/src/content/docs/ar/providers.mdx | 2 +- packages/web/src/content/docs/bs/providers.mdx | 2 +- packages/web/src/content/docs/da/providers.mdx | 2 +- packages/web/src/content/docs/de/providers.mdx | 2 +- packages/web/src/content/docs/es/providers.mdx | 2 +- packages/web/src/content/docs/fr/providers.mdx | 2 +- packages/web/src/content/docs/it/providers.mdx | 2 +- packages/web/src/content/docs/ja/providers.mdx | 2 +- packages/web/src/content/docs/ko/providers.mdx | 2 +- packages/web/src/content/docs/nb/providers.mdx | 2 +- packages/web/src/content/docs/pl/providers.mdx | 2 +- packages/web/src/content/docs/providers.mdx | 2 +- packages/web/src/content/docs/pt-br/providers.mdx | 2 +- packages/web/src/content/docs/ru/providers.mdx | 2 +- packages/web/src/content/docs/th/providers.mdx | 2 +- packages/web/src/content/docs/tr/providers.mdx | 2 +- packages/web/src/content/docs/zh-cn/providers.mdx | 2 +- packages/web/src/content/docs/zh-tw/providers.mdx | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/web/src/content/docs/ar/providers.mdx b/packages/web/src/content/docs/ar/providers.mdx index 951d6701cb..a43357d107 100644 --- a/packages/web/src/content/docs/ar/providers.mdx +++ b/packages/web/src/content/docs/ar/providers.mdx @@ -575,7 +575,7 @@ OpenCode Go هي خطة اشتراك منخفضة التكلفة توفّر وص └ enter ``` -4. شغّل الأمر `/models` لاختيار نموذج من DeepSeek مثل _DeepSeek Reasoner_. +4. شغّل الأمر `/models` لاختيار نموذج من DeepSeek مثل _DeepSeek V4 Pro_. ```txt /models diff --git a/packages/web/src/content/docs/bs/providers.mdx b/packages/web/src/content/docs/bs/providers.mdx index 1aae0a93a9..306653f75a 100644 --- a/packages/web/src/content/docs/bs/providers.mdx +++ b/packages/web/src/content/docs/bs/providers.mdx @@ -580,7 +580,7 @@ Također možete dodati modele kroz svoju opencode konfiguraciju. └ enter ``` -4. Pokrenite naredbu `/models` da odaberete DeepSeek model kao što je _DeepSeek Reasoner_. +4. Pokrenite naredbu `/models` da odaberete DeepSeek model kao što je _DeepSeek V4 Pro_. ```txt /models diff --git a/packages/web/src/content/docs/da/providers.mdx b/packages/web/src/content/docs/da/providers.mdx index bcd82c8454..0bc9baa5fa 100644 --- a/packages/web/src/content/docs/da/providers.mdx +++ b/packages/web/src/content/docs/da/providers.mdx @@ -571,7 +571,7 @@ Cloudflare AI Gateway lader dig få adgang til modeller fra OpenAI, Anthropic, W └ enter ``` -4. Kør kommandoen `/models` for at vælge en DeepSeek-model som _DeepSeek Reasoner_. +4. Kør kommandoen `/models` for at vælge en DeepSeek-model som _DeepSeek V4 Pro_. ```txt /models diff --git a/packages/web/src/content/docs/de/providers.mdx b/packages/web/src/content/docs/de/providers.mdx index c012a78fc2..41a15fa0b9 100644 --- a/packages/web/src/content/docs/de/providers.mdx +++ b/packages/web/src/content/docs/de/providers.mdx @@ -577,7 +577,7 @@ Mit dem Cloudflare AI Gateway können Sie über einen einheitlichen Endpunkt auf └ enter ``` -4. Führen Sie den Befehl `/models` aus, um ein DeepSeek-Modell wie _DeepSeek Reasoner_ auszuwählen. +4. Führen Sie den Befehl `/models` aus, um ein DeepSeek-Modell wie _DeepSeek V4 Pro_ auszuwählen. ```txt /models diff --git a/packages/web/src/content/docs/es/providers.mdx b/packages/web/src/content/docs/es/providers.mdx index b812971409..f325a0cd4c 100644 --- a/packages/web/src/content/docs/es/providers.mdx +++ b/packages/web/src/content/docs/es/providers.mdx @@ -578,7 +578,7 @@ Cloudflare AI Gateway le permite acceder a modelos de OpenAI, Anthropic, Workers └ enter ``` -4. Ejecute el comando `/models` para seleccionar un modelo de DeepSeek como _DeepSeek Reasoner_. +4. Ejecute el comando `/models` para seleccionar un modelo de DeepSeek como _DeepSeek V4 Pro_. ```txt /models diff --git a/packages/web/src/content/docs/fr/providers.mdx b/packages/web/src/content/docs/fr/providers.mdx index d7b0657971..2896df9592 100644 --- a/packages/web/src/content/docs/fr/providers.mdx +++ b/packages/web/src/content/docs/fr/providers.mdx @@ -581,7 +581,7 @@ Vous pouvez également ajouter des modèles via votre configuration opencode. └ enter ``` -4. Exécutez la commande `/models` pour sélectionner un modèle DeepSeek tel que _DeepSeek Reasoner_. +4. Exécutez la commande `/models` pour sélectionner un modèle DeepSeek tel que _DeepSeek V4 Pro_. ```txt /models diff --git a/packages/web/src/content/docs/it/providers.mdx b/packages/web/src/content/docs/it/providers.mdx index 58bb28407f..26bf19fd6f 100644 --- a/packages/web/src/content/docs/it/providers.mdx +++ b/packages/web/src/content/docs/it/providers.mdx @@ -555,7 +555,7 @@ Cloudflare AI Gateway ti permette di accedere a modelli di OpenAI, Anthropic, Wo └ enter ``` -4. Esegui il comando `/models` per selezionare un modello DeepSeek come _DeepSeek Reasoner_. +4. Esegui il comando `/models` per selezionare un modello DeepSeek come _DeepSeek V4 Pro_. ```txt /models diff --git a/packages/web/src/content/docs/ja/providers.mdx b/packages/web/src/content/docs/ja/providers.mdx index f7e88d8c5d..9fbb301ba5 100644 --- a/packages/web/src/content/docs/ja/providers.mdx +++ b/packages/web/src/content/docs/ja/providers.mdx @@ -585,7 +585,7 @@ OpenCode 設定を通じてモデルを追加することもできます。 └ enter ``` -4. `/models` コマンドを実行して、_DeepSeek Reasoner_ のような DeepSeek モデルを選択します。 +4. `/models` コマンドを実行して、_DeepSeek V4 Pro_ のような DeepSeek モデルを選択します。 ```txt /models diff --git a/packages/web/src/content/docs/ko/providers.mdx b/packages/web/src/content/docs/ko/providers.mdx index ccbbc48386..ad4aaae7e6 100644 --- a/packages/web/src/content/docs/ko/providers.mdx +++ b/packages/web/src/content/docs/ko/providers.mdx @@ -581,7 +581,7 @@ Cloudflare AI Gateway는 OpenAI, Anthropic, Workers AI 등의 모델에 액세 └ enter ``` -4. `/models` 명령을 실행하여 DeepSeek 모델(예: _DeepSeek Reasoner_)을 선택하십시오. +4. `/models` 명령을 실행하여 DeepSeek 모델(예: _DeepSeek V4 Pro_)을 선택하십시오. ```txt /models diff --git a/packages/web/src/content/docs/nb/providers.mdx b/packages/web/src/content/docs/nb/providers.mdx index 9e025a96f8..ea6f1cc1ab 100644 --- a/packages/web/src/content/docs/nb/providers.mdx +++ b/packages/web/src/content/docs/nb/providers.mdx @@ -579,7 +579,7 @@ Cloudflare AI Gateway lar deg få tilgang til modeller fra OpenAI, Anthropic, Wo └ enter ``` -4. Kjør kommandoen `/models` for å velge en DeepSeek-modell som _DeepSeek Reasoner_. +4. Kjør kommandoen `/models` for å velge en DeepSeek-modell som _DeepSeek V4 Pro_. ```txt /models diff --git a/packages/web/src/content/docs/pl/providers.mdx b/packages/web/src/content/docs/pl/providers.mdx index aeb6272331..e2b4c70e6f 100644 --- a/packages/web/src/content/docs/pl/providers.mdx +++ b/packages/web/src/content/docs/pl/providers.mdx @@ -577,7 +577,7 @@ Cloudflare AI Gateway umożliwia dostęp do modeli z OpenAI, Anthropic, Workers └ enter ``` -4. Uruchom polecenie `/models`, aby wybrać model DeepSeek, np. _DeepSeek Reasoner_. +4. Uruchom polecenie `/models`, aby wybrać model DeepSeek, np. _DeepSeek V4 Pro_. ```txt /models diff --git a/packages/web/src/content/docs/providers.mdx b/packages/web/src/content/docs/providers.mdx index 030a50ba00..752f6c054f 100644 --- a/packages/web/src/content/docs/providers.mdx +++ b/packages/web/src/content/docs/providers.mdx @@ -648,7 +648,7 @@ Cloudflare Workers AI lets you run AI models on Cloudflare's global network dire └ enter ``` -4. Run the `/models` command to select a DeepSeek model like _DeepSeek Reasoner_. +4. Run the `/models` command to select a DeepSeek model like _DeepSeek V4 Pro_. ```txt /models diff --git a/packages/web/src/content/docs/pt-br/providers.mdx b/packages/web/src/content/docs/pt-br/providers.mdx index 4424a55fc0..58305a2737 100644 --- a/packages/web/src/content/docs/pt-br/providers.mdx +++ b/packages/web/src/content/docs/pt-br/providers.mdx @@ -581,7 +581,7 @@ O Cloudflare AI Gateway permite que você acesse modelos do OpenAI, Anthropic, W └ enter ``` -4. Execute o comando `/models` para selecionar um modelo DeepSeek como _DeepSeek Reasoner_. +4. Execute o comando `/models` para selecionar um modelo DeepSeek como _DeepSeek V4 Pro_. ```txt /models diff --git a/packages/web/src/content/docs/ru/providers.mdx b/packages/web/src/content/docs/ru/providers.mdx index 1cb3873c32..144ce2ac5a 100644 --- a/packages/web/src/content/docs/ru/providers.mdx +++ b/packages/web/src/content/docs/ru/providers.mdx @@ -577,7 +577,7 @@ Cloudflare AI Gateway позволяет вам получать доступ к └ enter ``` -4. Запустите команду `/models`, чтобы выбрать модель DeepSeek, например _DeepSeek Reasoner_. +4. Запустите команду `/models`, чтобы выбрать модель DeepSeek, например _DeepSeek V4 Pro_. ```txt /models diff --git a/packages/web/src/content/docs/th/providers.mdx b/packages/web/src/content/docs/th/providers.mdx index 73489b96ad..c4fdb5ce34 100644 --- a/packages/web/src/content/docs/th/providers.mdx +++ b/packages/web/src/content/docs/th/providers.mdx @@ -577,7 +577,7 @@ Cloudflare AI Gateway ช่วยให้คุณเข้าถึงโม └ enter ``` -4. รันคำสั่ง `/models` เพื่อเลือกโมเดล DeepSeek เช่น _DeepSeek Reasoner_ +4. รันคำสั่ง `/models` เพื่อเลือกโมเดล DeepSeek เช่น _DeepSeek V4 Pro_ ```txt /models diff --git a/packages/web/src/content/docs/tr/providers.mdx b/packages/web/src/content/docs/tr/providers.mdx index 871f9e128c..cf073e3095 100644 --- a/packages/web/src/content/docs/tr/providers.mdx +++ b/packages/web/src/content/docs/tr/providers.mdx @@ -579,7 +579,7 @@ Cloudflare AI Gateway, OpenAI, Anthropic, Workers AI ve daha fazlasındaki model └ enter ``` -4. _DeepSeek Reasoner_ gibi bir DeepSeek modeli seçmek için `/models` komutunu çalıştırın. +4. _DeepSeek V4 Pro_ gibi bir DeepSeek modeli seçmek için `/models` komutunu çalıştırın. ```txt /models diff --git a/packages/web/src/content/docs/zh-cn/providers.mdx b/packages/web/src/content/docs/zh-cn/providers.mdx index 25b7d03a4d..e22ba3ad80 100644 --- a/packages/web/src/content/docs/zh-cn/providers.mdx +++ b/packages/web/src/content/docs/zh-cn/providers.mdx @@ -551,7 +551,7 @@ Cloudflare AI Gateway 允许你通过统一端点访问来自 OpenAI、Anthropic └ enter ``` -4. 执行 `/models` 命令选择 DeepSeek 模型,例如 _DeepSeek Reasoner_。 +4. 执行 `/models` 命令选择 DeepSeek 模型,例如 _DeepSeek V4 Pro_。 ```txt /models diff --git a/packages/web/src/content/docs/zh-tw/providers.mdx b/packages/web/src/content/docs/zh-tw/providers.mdx index 1024444d18..8af6f01d4a 100644 --- a/packages/web/src/content/docs/zh-tw/providers.mdx +++ b/packages/web/src/content/docs/zh-tw/providers.mdx @@ -572,7 +572,7 @@ Cloudflare AI Gateway 允許您透過統一端點存取來自 OpenAI、Anthropic └ enter ``` -4. 執行 `/models` 指令選擇 DeepSeek 模型,例如 _DeepSeek Reasoner_。 +4. 執行 `/models` 指令選擇 DeepSeek 模型,例如 _DeepSeek V4 Pro_。 ```txt /models From f033d2d8fbb76d654e30697c99e4b7a0beb2be8a Mon Sep 17 00:00:00 2001 From: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Date: Fri, 24 Apr 2026 15:20:53 +0800 Subject: [PATCH 62/92] fix(app): conditionally show model variant selector (#24115) --- packages/app/src/components/prompt-input.tsx | 54 ++++++++++---------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index 8b69f3b2ab..0a18096164 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -1574,33 +1574,35 @@ export const PromptInput: Component = (props) => {
    -
    - 2}> +
    - (x === "default" ? language.t("common.default") : x)} + onSelect={(value) => { + local.model.variant.set(value === "default" ? undefined : value) + restoreFocus() + }} + class="capitalize max-w-[160px] text-text-base" + valueClass="truncate text-13-regular text-text-base" + triggerStyle={control()} + triggerProps={{ "data-action": "prompt-model-variant" }} + variant="ghost" + /> + +
    +
    From 2cda629c8d28baae41cf8c861a95453b9271adf6 Mon Sep 17 00:00:00 2001 From: Simon Klee Date: Fri, 24 Apr 2026 13:00:11 +0200 Subject: [PATCH 63/92] test(prompt): align shell placeholder expectation (#24147) --- packages/app/src/components/prompt-input/placeholder.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/src/components/prompt-input/placeholder.test.ts b/packages/app/src/components/prompt-input/placeholder.test.ts index 5f6aa59e9a..d4caead0d2 100644 --- a/packages/app/src/components/prompt-input/placeholder.test.ts +++ b/packages/app/src/components/prompt-input/placeholder.test.ts @@ -12,7 +12,7 @@ describe("promptPlaceholder", () => { suggest: true, t, }) - expect(value).toBe("prompt.placeholder.shell") + expect(value).toBe("prompt.placeholder.shell:example") }) test("returns summarize placeholders for comment context", () => { From a882e958b3d9bf736d9e16d65989265999674150 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Fri, 24 Apr 2026 08:34:48 -0400 Subject: [PATCH 64/92] fix: deepseek variants (#24157) --- packages/opencode/src/provider/transform.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index 1d84c7c931..6f24370ab0 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -405,7 +405,10 @@ export function variants(model: Provider.Model): Record Date: Fri, 24 Apr 2026 20:42:57 +0800 Subject: [PATCH 65/92] fix: preserve empty reasoning_content for DeepSeek V4 thinking mode (#24146) Co-authored-by: Simon Klee --- packages/opencode/src/provider/transform.ts | 25 +++++++++------------ 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index 6f24370ab0..0a2fc7fc26 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -185,24 +185,19 @@ function normalizeMessages( // Filter out reasoning parts from content const filteredContent = msg.content.filter((part: any) => part.type !== "reasoning") - // Include reasoning_content | reasoning_details directly on the message for all assistant messages - if (reasoningText) { - return { - ...msg, - content: filteredContent, - providerOptions: { - ...msg.providerOptions, - openaiCompatible: { - ...msg.providerOptions?.openaiCompatible, - [field]: reasoningText, - }, - }, - } - } - + // Include reasoning_content | reasoning_details directly on the message for all assistant messages. + // Always set the field even when empty — some providers (e.g. DeepSeek) may return empty + // reasoning_content which still needs to be sent back in subsequent requests. return { ...msg, content: filteredContent, + providerOptions: { + ...msg.providerOptions, + openaiCompatible: { + ...msg.providerOptions?.openaiCompatible, + [field]: reasoningText, + }, + }, } } From f8e939d96fe2f2f3e347fdfd8a8f567ceb6edb01 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Fri, 24 Apr 2026 08:48:52 -0400 Subject: [PATCH 66/92] fix: support `max` for deepseek (#24163) --- packages/opencode/src/provider/transform.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index 0a2fc7fc26..7fcfcd2501 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -529,7 +529,11 @@ export function variants(model: Provider.Model): Record [effort, { reasoningEffort: effort }])) + const efforts = [...WIDELY_SUPPORTED_EFFORTS] + if (model.api.id.includes("deepseek-v4")) { + efforts.push("max") + } + return Object.fromEntries(efforts.map((effort) => [effort, { reasoningEffort: effort }])) case "@ai-sdk/azure": // https://v5.ai-sdk.dev/providers/ai-sdk-providers/azure From 9f7ecd65e5534451f8feeb2ef45e1cefb4fc8484 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Fri, 24 Apr 2026 09:12:05 -0400 Subject: [PATCH 67/92] feat(httpapi): bridge file read endpoints (#24098) --- packages/opencode/specs/effect/http-api.md | 7 +- packages/opencode/src/file/index.ts | 102 +++++++++--------- .../src/server/routes/instance/file.ts | 6 +- .../server/routes/instance/httpapi/file.ts | 84 +++++++++++++++ .../server/routes/instance/httpapi/server.ts | 3 + .../src/server/routes/instance/index.ts | 4 + .../opencode/test/server/httpapi-file.test.ts | 57 ++++++++++ 7 files changed, 203 insertions(+), 60 deletions(-) create mode 100644 packages/opencode/src/server/routes/instance/httpapi/file.ts create mode 100644 packages/opencode/test/server/httpapi-file.test.ts diff --git a/packages/opencode/specs/effect/http-api.md b/packages/opencode/specs/effect/http-api.md index 6c80dc65a2..771c8b987d 100644 --- a/packages/opencode/specs/effect/http-api.md +++ b/packages/opencode/specs/effect/http-api.md @@ -412,8 +412,9 @@ Current instance route inventory: - `workspace` - `bridged` best small reads: `GET /experimental/workspace/adaptor`, `GET /experimental/workspace`, `GET /experimental/workspace/status` defer create/remove mutations first -- `file` - `later` - good JSON-only candidate set, but larger than the current first-wave slices +- `file` - `bridged` (partial) + bridged endpoints: `GET /file`, `GET /file/content`, `GET /file/status` + defer search endpoints first - `mcp` - `later` has JSON-only endpoints, but interactive OAuth/auth flows make it a worse early fit - `session` - `defer` @@ -449,7 +450,7 @@ Recommended near-term sequence: - [x] port `project` read endpoints (`GET /project`, `GET /project/current`) - [x] port `GET /config` full read endpoint - [x] port `workspace` read endpoints -- [ ] port `file` JSON read endpoints +- [x] port `file` JSON read endpoints - [ ] decide when to remove the flag and make Effect routes the default ## Rule of thumb diff --git a/packages/opencode/src/file/index.ts b/packages/opencode/src/file/index.ts index ca791e4128..05e2ce359a 100644 --- a/packages/opencode/src/file/index.ts +++ b/packages/opencode/src/file/index.ts @@ -9,69 +9,63 @@ import { formatPatch, structuredPatch } from "diff" import fuzzysort from "fuzzysort" import ignore from "ignore" import path from "path" -import z from "zod" import { Global } from "../global" import { Instance } from "../project/instance" import { Log } from "../util" import { Protected } from "./protected" import { Ripgrep } from "./ripgrep" +import { zod } from "@/util/effect-zod" +import { type DeepMutable, withStatics } from "@/util/schema" -export const Info = z - .object({ - path: z.string(), - added: z.number().int(), - removed: z.number().int(), - status: z.enum(["added", "deleted", "modified"]), - }) - .meta({ - ref: "File", - }) +export const Info = Schema.Struct({ + path: Schema.String, + added: Schema.Int, + removed: Schema.Int, + status: Schema.Literals(["added", "deleted", "modified"]), +}) + .annotate({ identifier: "File" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type Info = DeepMutable> -export type Info = z.infer +export const Node = Schema.Struct({ + name: Schema.String, + path: Schema.String, + absolute: Schema.String, + type: Schema.Literals(["file", "directory"]), + ignored: Schema.Boolean, +}) + .annotate({ identifier: "FileNode" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type Node = DeepMutable> -export const Node = z - .object({ - name: z.string(), - path: z.string(), - absolute: z.string(), - type: z.enum(["file", "directory"]), - ignored: z.boolean(), - }) - .meta({ - ref: "FileNode", - }) -export type Node = z.infer +const Hunk = Schema.Struct({ + oldStart: Schema.Number, + oldLines: Schema.Number, + newStart: Schema.Number, + newLines: Schema.Number, + lines: Schema.Array(Schema.String), +}) -export const Content = z - .object({ - type: z.enum(["text", "binary"]), - content: z.string(), - diff: z.string().optional(), - patch: z - .object({ - oldFileName: z.string(), - newFileName: z.string(), - oldHeader: z.string().optional(), - newHeader: z.string().optional(), - hunks: z.array( - z.object({ - oldStart: z.number(), - oldLines: z.number(), - newStart: z.number(), - newLines: z.number(), - lines: z.array(z.string()), - }), - ), - index: z.string().optional(), - }) - .optional(), - encoding: z.literal("base64").optional(), - mimeType: z.string().optional(), - }) - .meta({ - ref: "FileContent", - }) -export type Content = z.infer +const Patch = Schema.Struct({ + oldFileName: Schema.String, + newFileName: Schema.String, + oldHeader: Schema.optional(Schema.String), + newHeader: Schema.optional(Schema.String), + hunks: Schema.Array(Hunk), + index: Schema.optional(Schema.String), +}) + +export const Content = Schema.Struct({ + type: Schema.Literals(["text", "binary"]), + content: Schema.String, + diff: Schema.optional(Schema.String), + patch: Schema.optional(Patch), + encoding: Schema.optional(Schema.Literal("base64")), + mimeType: Schema.optional(Schema.String), +}) + .annotate({ identifier: "FileContent" }) + .pipe(withStatics((s) => ({ zod: zod(s) }))) +export type Content = DeepMutable> export const Event = { Edited: BusEvent.define( diff --git a/packages/opencode/src/server/routes/instance/file.ts b/packages/opencode/src/server/routes/instance/file.ts index f92fe6e7e5..661322127e 100644 --- a/packages/opencode/src/server/routes/instance/file.ts +++ b/packages/opencode/src/server/routes/instance/file.ts @@ -117,7 +117,7 @@ export const FileRoutes = lazy(() => description: "Files and directories", content: { "application/json": { - schema: resolver(File.Node.array()), + schema: resolver(File.Node.zod.array()), }, }, }, @@ -146,7 +146,7 @@ export const FileRoutes = lazy(() => description: "File content", content: { "application/json": { - schema: resolver(File.Content), + schema: resolver(File.Content.zod), }, }, }, @@ -175,7 +175,7 @@ export const FileRoutes = lazy(() => description: "File status", content: { "application/json": { - schema: resolver(File.Info.array()), + schema: resolver(File.Info.zod.array()), }, }, }, diff --git a/packages/opencode/src/server/routes/instance/httpapi/file.ts b/packages/opencode/src/server/routes/instance/httpapi/file.ts new file mode 100644 index 0000000000..eaf43862ad --- /dev/null +++ b/packages/opencode/src/server/routes/instance/httpapi/file.ts @@ -0,0 +1,84 @@ +import { File } from "@/file" +import { Effect, Layer, Schema } from "effect" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" + +const FileQuery = Schema.Struct({ + path: Schema.String, +}) + +export const FilePaths = { + list: "/file", + content: "/file/content", + status: "/file/status", +} as const + +export const FileApi = HttpApi.make("file") + .add( + HttpApiGroup.make("file") + .add( + HttpApiEndpoint.get("list", FilePaths.list, { + query: FileQuery, + success: Schema.Array(File.Node), + }).annotateMerge( + OpenApi.annotations({ + identifier: "file.list", + summary: "List files", + description: "List files and directories in a specified path.", + }), + ), + HttpApiEndpoint.get("content", FilePaths.content, { + query: FileQuery, + success: File.Content, + }).annotateMerge( + OpenApi.annotations({ + identifier: "file.read", + summary: "Read file", + description: "Read the content of a specified file.", + }), + ), + HttpApiEndpoint.get("status", FilePaths.status, { + success: Schema.Array(File.Info), + }).annotateMerge( + OpenApi.annotations({ + identifier: "file.status", + summary: "Get file status", + description: "Get the git status of all files in the project.", + }), + ), + ) + .annotateMerge( + OpenApi.annotations({ + title: "file", + description: "Experimental HttpApi file routes.", + }), + ), + ) + .annotateMerge( + OpenApi.annotations({ + title: "opencode experimental HttpApi", + version: "0.0.1", + description: "Experimental HttpApi surface for selected instance routes.", + }), + ) + +export const fileHandlers = Layer.unwrap( + Effect.gen(function* () { + const svc = yield* File.Service + + const list = Effect.fn("FileHttpApi.list")(function* (ctx: { query: { path: string } }) { + return yield* svc.list(ctx.query.path) + }) + + const content = Effect.fn("FileHttpApi.content")(function* (ctx: { query: { path: string } }) { + return yield* svc.read(ctx.query.path) + }) + + const status = Effect.fn("FileHttpApi.status")(function* () { + return yield* svc.status() + }) + + return HttpApiBuilder.group(FileApi, "file", (handlers) => + handlers.handle("list", list).handle("content", content).handle("status", status), + ) + }), +).pipe(Layer.provide(File.defaultLayer)) diff --git a/packages/opencode/src/server/routes/instance/httpapi/server.ts b/packages/opencode/src/server/routes/instance/httpapi/server.ts index 7b131d4000..c57320c103 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/server.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/server.ts @@ -10,6 +10,7 @@ import { Instance } from "@/project/instance" import { lazy } from "@/util/lazy" import { Filesystem } from "@/util" import { ConfigApi, configHandlers } from "./config" +import { FileApi, fileHandlers } from "./file" import { PermissionApi, permissionHandlers } from "./permission" import { ProjectApi, projectHandlers } from "./project" import { ProviderApi, providerHandlers } from "./provider" @@ -114,9 +115,11 @@ const ProjectSecured = ProjectApi.middleware(Authorization) const ProviderSecured = ProviderApi.middleware(Authorization) const ConfigSecured = ConfigApi.middleware(Authorization) const WorkspaceSecured = WorkspaceApi.middleware(Authorization) +const FileSecured = FileApi.middleware(Authorization) export const routes = Layer.mergeAll( HttpApiBuilder.layer(ConfigSecured).pipe(Layer.provide(configHandlers)), + HttpApiBuilder.layer(FileSecured).pipe(Layer.provide(fileHandlers)), HttpApiBuilder.layer(ProjectSecured).pipe(Layer.provide(projectHandlers)), HttpApiBuilder.layer(QuestionSecured).pipe(Layer.provide(questionHandlers)), HttpApiBuilder.layer(PermissionSecured).pipe(Layer.provide(permissionHandlers)), diff --git a/packages/opencode/src/server/routes/instance/index.ts b/packages/opencode/src/server/routes/instance/index.ts index e8a038fabc..fba150116c 100644 --- a/packages/opencode/src/server/routes/instance/index.ts +++ b/packages/opencode/src/server/routes/instance/index.ts @@ -16,6 +16,7 @@ import { QuestionRoutes } from "./question" import { PermissionRoutes } from "./permission" import { Flag } from "@/flag/flag" import { ExperimentalHttpApiServer } from "./httpapi/server" +import { FilePaths } from "./httpapi/file" import { ProjectRoutes } from "./project" import { SessionRoutes } from "./session" import { PtyRoutes } from "./pty" @@ -48,6 +49,9 @@ export const InstanceRoutes = (upgrade: UpgradeWebSocket): Hono => { app.post("/provider/:providerID/oauth/callback", (c) => handler(c.req.raw, context)) app.get("/project", (c) => handler(c.req.raw, context)) app.get("/project/current", (c) => handler(c.req.raw, context)) + app.get(FilePaths.list, (c) => handler(c.req.raw, context)) + app.get(FilePaths.content, (c) => handler(c.req.raw, context)) + app.get(FilePaths.status, (c) => handler(c.req.raw, context)) } return app diff --git a/packages/opencode/test/server/httpapi-file.test.ts b/packages/opencode/test/server/httpapi-file.test.ts new file mode 100644 index 0000000000..5a9058cb69 --- /dev/null +++ b/packages/opencode/test/server/httpapi-file.test.ts @@ -0,0 +1,57 @@ +import { afterEach, describe, expect, test } from "bun:test" +import { Context } from "effect" +import path from "path" +import { ExperimentalHttpApiServer } from "../../src/server/routes/instance/httpapi/server" +import { FilePaths } from "../../src/server/routes/instance/httpapi/file" +import { Instance } from "../../src/project/instance" +import { Log } from "../../src/util" +import { resetDatabase } from "../fixture/db" +import { tmpdir } from "../fixture/fixture" + +void Log.init({ print: false }) + +const context = Context.empty() as Context.Context + +function request(route: string, directory: string, query?: Record) { + const url = new URL(`http://localhost${route}`) + for (const [key, value] of Object.entries(query ?? {})) { + url.searchParams.set(key, value) + } + return ExperimentalHttpApiServer.webHandler().handler( + new Request(url, { + headers: { + "x-opencode-directory": directory, + }, + }), + context, + ) +} + +afterEach(async () => { + await Instance.disposeAll() + await resetDatabase() +}) + +describe("file HttpApi", () => { + test("serves read endpoints", async () => { + await using tmp = await tmpdir({ git: true }) + await Bun.write(path.join(tmp.path, "hello.txt"), "hello") + + const [list, content, status] = await Promise.all([ + request(FilePaths.list, tmp.path, { path: "." }), + request(FilePaths.content, tmp.path, { path: "hello.txt" }), + request(FilePaths.status, tmp.path), + ]) + + expect(list.status).toBe(200) + expect(await list.json()).toContainEqual( + expect.objectContaining({ name: "hello.txt", path: "hello.txt", type: "file" }), + ) + + expect(content.status).toBe(200) + expect(await content.json()).toMatchObject({ type: "text", content: "hello" }) + + expect(status.status).toBe(200) + expect(await status.json()).toContainEqual({ path: "hello.txt", added: 1, removed: 0, status: "added" }) + }) +}) From a8c8d2dd79cdb98b673a92da738e584e9964b4eb Mon Sep 17 00:00:00 2001 From: opencode Date: Fri, 24 Apr 2026 13:17:13 +0000 Subject: [PATCH 68/92] sync release versions for v1.14.23 --- bun.lock | 32 +++++++++++++------------- packages/app/package.json | 2 +- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop-electron/package.json | 2 +- packages/desktop/package.json | 2 +- packages/enterprise/package.json | 2 +- packages/extensions/zed/extension.toml | 12 +++++----- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/shared/package.json | 2 +- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 19 files changed, 39 insertions(+), 39 deletions(-) diff --git a/bun.lock b/bun.lock index 06a5cfdb4c..16ada2be04 100644 --- a/bun.lock +++ b/bun.lock @@ -29,7 +29,7 @@ }, "packages/app": { "name": "@opencode-ai/app", - "version": "1.14.22", + "version": "1.14.23", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -83,7 +83,7 @@ }, "packages/console/app": { "name": "@opencode-ai/console-app", - "version": "1.14.22", + "version": "1.14.23", "dependencies": { "@cloudflare/vite-plugin": "1.15.2", "@ibm/plex": "6.4.1", @@ -117,7 +117,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.14.22", + "version": "1.14.23", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -144,7 +144,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.14.22", + "version": "1.14.23", "dependencies": { "@ai-sdk/anthropic": "3.0.64", "@ai-sdk/openai": "3.0.48", @@ -168,7 +168,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.14.22", + "version": "1.14.23", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -192,7 +192,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.14.22", + "version": "1.14.23", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -225,7 +225,7 @@ }, "packages/desktop-electron": { "name": "@opencode-ai/desktop-electron", - "version": "1.14.22", + "version": "1.14.23", "dependencies": { "drizzle-orm": "catalog:", "effect": "catalog:", @@ -269,7 +269,7 @@ }, "packages/enterprise": { "name": "@opencode-ai/enterprise", - "version": "1.14.22", + "version": "1.14.23", "dependencies": { "@opencode-ai/shared": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -298,7 +298,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.14.22", + "version": "1.14.23", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "catalog:", @@ -314,7 +314,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.14.22", + "version": "1.14.23", "bin": { "opencode": "./bin/opencode", }, @@ -459,7 +459,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.14.22", + "version": "1.14.23", "dependencies": { "@opencode-ai/sdk": "workspace:*", "effect": "catalog:", @@ -494,7 +494,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.14.22", + "version": "1.14.23", "dependencies": { "cross-spawn": "catalog:", }, @@ -509,7 +509,7 @@ }, "packages/shared": { "name": "@opencode-ai/shared", - "version": "1.14.22", + "version": "1.14.23", "bin": { "opencode": "./bin/opencode", }, @@ -533,7 +533,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.14.22", + "version": "1.14.23", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -568,7 +568,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.14.22", + "version": "1.14.23", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -617,7 +617,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.14.22", + "version": "1.14.23", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/app/package.json b/packages/app/package.json index 0ab5e304a2..b01b9b9d1a 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "1.14.22", + "version": "1.14.23", "description": "", "type": "module", "exports": { diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 3d37527508..acd7024a6d 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-app", - "version": "1.14.22", + "version": "1.14.23", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 70d44b3820..a8ba8c5398 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.14.22", + "version": "1.14.23", "private": true, "type": "module", "license": "MIT", diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 55791a3072..b917ee2b59 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.14.22", + "version": "1.14.23", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 4966bf3e63..17fd13d0f3 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.14.22", + "version": "1.14.23", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop-electron/package.json b/packages/desktop-electron/package.json index a528a9a3ac..bd286786bb 100644 --- a/packages/desktop-electron/package.json +++ b/packages/desktop-electron/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop-electron", "private": true, - "version": "1.14.22", + "version": "1.14.23", "type": "module", "license": "MIT", "homepage": "https://opencode.ai", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 32b63fff13..561a974700 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop", "private": true, - "version": "1.14.22", + "version": "1.14.23", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/enterprise/package.json b/packages/enterprise/package.json index e4428f0cb2..11a6ea7ef6 100644 --- a/packages/enterprise/package.json +++ b/packages/enterprise/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/enterprise", - "version": "1.14.22", + "version": "1.14.23", "private": true, "type": "module", "license": "MIT", diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 6449b8df65..2943614d38 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The open source coding agent." -version = "1.14.22" +version = "1.14.23" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/anomalyco/opencode" @@ -11,26 +11,26 @@ name = "OpenCode" icon = "./icons/opencode.svg" [agent_servers.opencode.targets.darwin-aarch64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.22/opencode-darwin-arm64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.23/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.22/opencode-darwin-x64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.23/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.22/opencode-linux-arm64.tar.gz" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.23/opencode-linux-arm64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.22/opencode-linux-x64.tar.gz" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.23/opencode-linux-x64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.22/opencode-windows-x64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.23/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index 5b06d03685..1501f3df40 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.14.22", + "version": "1.14.23", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index ea8724ceb8..5225ff54cc 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.14.22", + "version": "1.14.23", "name": "opencode", "type": "module", "license": "MIT", diff --git a/packages/plugin/package.json b/packages/plugin/package.json index ee8210ec14..16c5e236b8 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.14.22", + "version": "1.14.23", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 62a50b7434..9f9658eb15 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.14.22", + "version": "1.14.23", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/shared/package.json b/packages/shared/package.json index 48ae0fb78d..08bb009297 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.14.22", + "version": "1.14.23", "name": "@opencode-ai/shared", "type": "module", "license": "MIT", diff --git a/packages/slack/package.json b/packages/slack/package.json index a3516932ab..5149dbffe9 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.14.22", + "version": "1.14.23", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/ui/package.json b/packages/ui/package.json index ba0fb01494..f4d90f1460 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.14.22", + "version": "1.14.23", "type": "module", "license": "MIT", "exports": { diff --git a/packages/web/package.json b/packages/web/package.json index 818cdf721e..386078d171 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -2,7 +2,7 @@ "name": "@opencode-ai/web", "type": "module", "license": "MIT", - "version": "1.14.22", + "version": "1.14.23", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index e238b36702..035a45eb7a 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.14.22", + "version": "1.14.23", "publisher": "sst-dev", "repository": { "type": "git", From 011c23761bd7ebe9df0b772b409a353051d9489c Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Fri, 24 Apr 2026 09:18:57 -0400 Subject: [PATCH 69/92] feat(httpapi): bridge mcp status endpoint (#24100) --- packages/opencode/specs/effect/http-api.md | 6 +- packages/opencode/src/mcp/index.ts | 73 ++++++++----------- .../src/server/routes/instance/httpapi/mcp.ts | 48 ++++++++++++ .../server/routes/instance/httpapi/server.ts | 3 + .../src/server/routes/instance/index.ts | 2 + .../src/server/routes/instance/mcp.ts | 8 +- .../opencode/test/server/httpapi-mcp.test.ts | 48 ++++++++++++ 7 files changed, 138 insertions(+), 50 deletions(-) create mode 100644 packages/opencode/src/server/routes/instance/httpapi/mcp.ts create mode 100644 packages/opencode/test/server/httpapi-mcp.test.ts diff --git a/packages/opencode/specs/effect/http-api.md b/packages/opencode/specs/effect/http-api.md index 771c8b987d..f83b7c0555 100644 --- a/packages/opencode/specs/effect/http-api.md +++ b/packages/opencode/specs/effect/http-api.md @@ -415,8 +415,9 @@ Current instance route inventory: - `file` - `bridged` (partial) bridged endpoints: `GET /file`, `GET /file/content`, `GET /file/status` defer search endpoints first -- `mcp` - `later` - has JSON-only endpoints, but interactive OAuth/auth flows make it a worse early fit +- `mcp` - `bridged` (partial) + bridged endpoints: `GET /mcp` + defer interactive OAuth/auth flows first - `session` - `defer` large, stateful, mixes CRUD with prompt/shell/command/share/revert flows and a streaming route - `event` - `defer` @@ -451,6 +452,7 @@ Recommended near-term sequence: - [x] port `GET /config` full read endpoint - [x] port `workspace` read endpoints - [x] port `file` JSON read endpoints +- [x] port `mcp` status read endpoint - [ ] decide when to remove the flag and make Effect routes the default ## Rule of thumb diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts index 385d7782a6..3c6816c5b7 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -30,6 +30,8 @@ import { EffectBridge } from "@/effect" import { InstanceState } from "@/effect" import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner" +import { zod as effectZod } from "@/util/effect-zod" +import { withStatics } from "@/util/schema" const log = Log.create({ service: "mcp" }) const DEFAULT_TIMEOUT = 30_000 @@ -69,50 +71,33 @@ export const Failed = NamedError.create( type MCPClient = Client -export const Status = z - .discriminatedUnion("status", [ - z - .object({ - status: z.literal("connected"), - }) - .meta({ - ref: "MCPStatusConnected", - }), - z - .object({ - status: z.literal("disabled"), - }) - .meta({ - ref: "MCPStatusDisabled", - }), - z - .object({ - status: z.literal("failed"), - error: z.string(), - }) - .meta({ - ref: "MCPStatusFailed", - }), - z - .object({ - status: z.literal("needs_auth"), - }) - .meta({ - ref: "MCPStatusNeedsAuth", - }), - z - .object({ - status: z.literal("needs_client_registration"), - error: z.string(), - }) - .meta({ - ref: "MCPStatusNeedsClientRegistration", - }), - ]) - .meta({ - ref: "MCPStatus", - }) -export type Status = z.infer +const StatusConnected = Schema.Struct({ status: Schema.Literal("connected") }).annotate({ + identifier: "MCPStatusConnected", +}) +const StatusDisabled = Schema.Struct({ status: Schema.Literal("disabled") }).annotate({ + identifier: "MCPStatusDisabled", +}) +const StatusFailed = Schema.Struct({ status: Schema.Literal("failed"), error: Schema.String }).annotate({ + identifier: "MCPStatusFailed", +}) +const StatusNeedsAuth = Schema.Struct({ status: Schema.Literal("needs_auth") }).annotate({ + identifier: "MCPStatusNeedsAuth", +}) +const StatusNeedsClientRegistration = Schema.Struct({ + status: Schema.Literal("needs_client_registration"), + error: Schema.String, +}).annotate({ identifier: "MCPStatusNeedsClientRegistration" }) + +export const Status = Schema.Union([ + StatusConnected, + StatusDisabled, + StatusFailed, + StatusNeedsAuth, + StatusNeedsClientRegistration, +]) + .annotate({ identifier: "MCPStatus", discriminator: "status" }) + .pipe(withStatics((s) => ({ zod: effectZod(s) }))) +export type Status = Schema.Schema.Type // Store transports for OAuth servers to allow finishing auth type TransportWithAuth = StreamableHTTPClientTransport | SSEClientTransport diff --git a/packages/opencode/src/server/routes/instance/httpapi/mcp.ts b/packages/opencode/src/server/routes/instance/httpapi/mcp.ts new file mode 100644 index 0000000000..91467b1e90 --- /dev/null +++ b/packages/opencode/src/server/routes/instance/httpapi/mcp.ts @@ -0,0 +1,48 @@ +import { MCP } from "@/mcp" +import { Effect, Layer, Schema } from "effect" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" + +export const McpPaths = { + status: "/mcp", +} as const + +export const McpApi = HttpApi.make("mcp") + .add( + HttpApiGroup.make("mcp") + .add( + HttpApiEndpoint.get("status", McpPaths.status, { + success: Schema.Record(Schema.String, MCP.Status), + }).annotateMerge( + OpenApi.annotations({ + identifier: "mcp.status", + summary: "Get MCP status", + description: "Get the status of all Model Context Protocol (MCP) servers.", + }), + ), + ) + .annotateMerge( + OpenApi.annotations({ + title: "mcp", + description: "Experimental HttpApi MCP routes.", + }), + ), + ) + .annotateMerge( + OpenApi.annotations({ + title: "opencode experimental HttpApi", + version: "0.0.1", + description: "Experimental HttpApi surface for selected instance routes.", + }), + ) + +export const mcpHandlers = Layer.unwrap( + Effect.gen(function* () { + const mcp = yield* MCP.Service + + const status = Effect.fn("McpHttpApi.status")(function* () { + return yield* mcp.status() + }) + + return HttpApiBuilder.group(McpApi, "mcp", (handlers) => handlers.handle("status", status)) + }), +).pipe(Layer.provide(MCP.defaultLayer)) diff --git a/packages/opencode/src/server/routes/instance/httpapi/server.ts b/packages/opencode/src/server/routes/instance/httpapi/server.ts index c57320c103..b45ad942b7 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/server.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/server.ts @@ -11,6 +11,7 @@ import { lazy } from "@/util/lazy" import { Filesystem } from "@/util" import { ConfigApi, configHandlers } from "./config" import { FileApi, fileHandlers } from "./file" +import { McpApi, mcpHandlers } from "./mcp" import { PermissionApi, permissionHandlers } from "./permission" import { ProjectApi, projectHandlers } from "./project" import { ProviderApi, providerHandlers } from "./provider" @@ -116,10 +117,12 @@ const ProviderSecured = ProviderApi.middleware(Authorization) const ConfigSecured = ConfigApi.middleware(Authorization) const WorkspaceSecured = WorkspaceApi.middleware(Authorization) const FileSecured = FileApi.middleware(Authorization) +const McpSecured = McpApi.middleware(Authorization) export const routes = Layer.mergeAll( HttpApiBuilder.layer(ConfigSecured).pipe(Layer.provide(configHandlers)), HttpApiBuilder.layer(FileSecured).pipe(Layer.provide(fileHandlers)), + HttpApiBuilder.layer(McpSecured).pipe(Layer.provide(mcpHandlers)), HttpApiBuilder.layer(ProjectSecured).pipe(Layer.provide(projectHandlers)), HttpApiBuilder.layer(QuestionSecured).pipe(Layer.provide(questionHandlers)), HttpApiBuilder.layer(PermissionSecured).pipe(Layer.provide(permissionHandlers)), diff --git a/packages/opencode/src/server/routes/instance/index.ts b/packages/opencode/src/server/routes/instance/index.ts index fba150116c..b899eb1082 100644 --- a/packages/opencode/src/server/routes/instance/index.ts +++ b/packages/opencode/src/server/routes/instance/index.ts @@ -17,6 +17,7 @@ import { PermissionRoutes } from "./permission" import { Flag } from "@/flag/flag" import { ExperimentalHttpApiServer } from "./httpapi/server" import { FilePaths } from "./httpapi/file" +import { McpPaths } from "./httpapi/mcp" import { ProjectRoutes } from "./project" import { SessionRoutes } from "./session" import { PtyRoutes } from "./pty" @@ -52,6 +53,7 @@ export const InstanceRoutes = (upgrade: UpgradeWebSocket): Hono => { app.get(FilePaths.list, (c) => handler(c.req.raw, context)) app.get(FilePaths.content, (c) => handler(c.req.raw, context)) app.get(FilePaths.status, (c) => handler(c.req.raw, context)) + app.get(McpPaths.status, (c) => handler(c.req.raw, context)) } return app diff --git a/packages/opencode/src/server/routes/instance/mcp.ts b/packages/opencode/src/server/routes/instance/mcp.ts index ce4722933b..2de8a7125c 100644 --- a/packages/opencode/src/server/routes/instance/mcp.ts +++ b/packages/opencode/src/server/routes/instance/mcp.ts @@ -21,7 +21,7 @@ export const McpRoutes = lazy(() => description: "MCP server status", content: { "application/json": { - schema: resolver(z.record(z.string(), MCP.Status)), + schema: resolver(z.record(z.string(), MCP.Status.zod)), }, }, }, @@ -44,7 +44,7 @@ export const McpRoutes = lazy(() => description: "MCP server added successfully", content: { "application/json": { - schema: resolver(z.record(z.string(), MCP.Status)), + schema: resolver(z.record(z.string(), MCP.Status.zod)), }, }, }, @@ -121,7 +121,7 @@ export const McpRoutes = lazy(() => description: "OAuth authentication completed", content: { "application/json": { - schema: resolver(MCP.Status), + schema: resolver(MCP.Status.zod), }, }, }, @@ -153,7 +153,7 @@ export const McpRoutes = lazy(() => description: "OAuth authentication completed", content: { "application/json": { - schema: resolver(MCP.Status), + schema: resolver(MCP.Status.zod), }, }, }, diff --git a/packages/opencode/test/server/httpapi-mcp.test.ts b/packages/opencode/test/server/httpapi-mcp.test.ts new file mode 100644 index 0000000000..3da1dc9333 --- /dev/null +++ b/packages/opencode/test/server/httpapi-mcp.test.ts @@ -0,0 +1,48 @@ +import { afterEach, describe, expect, test } from "bun:test" +import { Context } from "effect" +import { ExperimentalHttpApiServer } from "../../src/server/routes/instance/httpapi/server" +import { McpPaths } from "../../src/server/routes/instance/httpapi/mcp" +import { Instance } from "../../src/project/instance" +import { Log } from "../../src/util" +import { resetDatabase } from "../fixture/db" +import { tmpdir } from "../fixture/fixture" + +void Log.init({ print: false }) + +const context = Context.empty() as Context.Context + +function request(route: string, directory: string) { + return ExperimentalHttpApiServer.webHandler().handler( + new Request(`http://localhost${route}`, { + headers: { + "x-opencode-directory": directory, + }, + }), + context, + ) +} + +afterEach(async () => { + await Instance.disposeAll() + await resetDatabase() +}) + +describe("mcp HttpApi", () => { + test("serves status endpoint", async () => { + await using tmp = await tmpdir({ + config: { + mcp: { + demo: { + type: "local", + command: ["echo", "demo"], + enabled: false, + }, + }, + }, + }) + + const response = await request(McpPaths.status, tmp.path) + expect(response.status).toBe(200) + expect(await response.json()).toEqual({ demo: { status: "disabled" } }) + }) +}) From d89bfc32ac0c7d2546f3d6c8096171b32279623b Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Fri, 24 Apr 2026 13:20:23 +0000 Subject: [PATCH 70/92] chore: generate --- packages/opencode/src/server/routes/instance/mcp.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/server/routes/instance/mcp.ts b/packages/opencode/src/server/routes/instance/mcp.ts index 2de8a7125c..b47a6d29a9 100644 --- a/packages/opencode/src/server/routes/instance/mcp.ts +++ b/packages/opencode/src/server/routes/instance/mcp.ts @@ -121,7 +121,7 @@ export const McpRoutes = lazy(() => description: "OAuth authentication completed", content: { "application/json": { - schema: resolver(MCP.Status.zod), + schema: resolver(MCP.Status.zod), }, }, }, @@ -153,7 +153,7 @@ export const McpRoutes = lazy(() => description: "OAuth authentication completed", content: { "application/json": { - schema: resolver(MCP.Status.zod), + schema: resolver(MCP.Status.zod), }, }, }, From 3062d3e0705a3959ff1108c8aa699358c8ea05a7 Mon Sep 17 00:00:00 2001 From: 07akioni <07akioni2@gmail.com> Date: Fri, 24 Apr 2026 22:41:41 +0800 Subject: [PATCH 71/92] fix: use existingModel as fallback for interleaved field (#24172) --- packages/opencode/src/provider/provider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index d826f6b350..0fe53e6e47 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -1177,7 +1177,7 @@ const layer: Layer.Layer< model.modalities?.output?.includes("video") ?? existingModel?.capabilities.output.video ?? false, pdf: model.modalities?.output?.includes("pdf") ?? existingModel?.capabilities.output.pdf ?? false, }, - interleaved: model.interleaved ?? false, + interleaved: model.interleaved ?? existingModel?.capabilities.interleaved ?? false, }, cost: { input: model?.cost?.input ?? existingModel?.cost?.input ?? 0, From 86715fecc469e7bf12e526d386e4927afc95fa3e Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Fri, 24 Apr 2026 11:10:47 -0400 Subject: [PATCH 72/92] fix: ensure assistant messages always have reasoning on them for deepseek (#24180) --- packages/opencode/src/provider/transform.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index 7fcfcd2501..50529c4dd7 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -175,6 +175,24 @@ function normalizeMessages( return result } + // Deepseek requires all assistant messages to have reasoning on them + if (model.api.id.includes("deepseek")) { + msgs = msgs.map((msg) => { + if (msg.role !== "assistant") return msg + if (Array.isArray(msg.content)) { + if (msg.content.some((part) => part.type === "reasoning")) return msg + return { ...msg, content: [...msg.content, { type: "reasoning", text: "" }] } + } + return { + ...msg, + content: [ + ...(msg.content ? [{ type: "text" as const, text: msg.content }] : []), + { type: "reasoning" as const, text: "" }, + ], + } + }) + } + if (typeof model.capabilities.interleaved === "object" && model.capabilities.interleaved.field) { const field = model.capabilities.interleaved.field return msgs.map((msg) => { From 3a5507de95b36da811fc5d3521769a946b883174 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 24 Apr 2026 17:28:07 +0200 Subject: [PATCH 73/92] Use OpenTUI theme detection for initial TUI mode, again (#23846) --- bun.lock | 28 ++++++------- packages/opencode/package.json | 4 +- packages/opencode/src/cli/cmd/tui/app.tsx | 8 +--- .../src/cli/cmd/tui/context/theme.tsx | 2 +- .../opencode/src/cli/cmd/tui/util/terminal.ts | 39 ------------------- packages/plugin/package.json | 8 ++-- 6 files changed, 22 insertions(+), 67 deletions(-) diff --git a/bun.lock b/bun.lock index 16ada2be04..359709a464 100644 --- a/bun.lock +++ b/bun.lock @@ -367,8 +367,8 @@ "@opentelemetry/exporter-trace-otlp-http": "0.214.0", "@opentelemetry/sdk-trace-base": "2.6.1", "@opentelemetry/sdk-trace-node": "2.6.1", - "@opentui/core": "0.1.99", - "@opentui/solid": "0.1.99", + "@opentui/core": "0.1.103", + "@opentui/solid": "0.1.103", "@parcel/watcher": "2.5.1", "@pierre/diffs": "catalog:", "@solid-primitives/event-bus": "1.1.2", @@ -466,16 +466,16 @@ "zod": "catalog:", }, "devDependencies": { - "@opentui/core": "0.1.99", - "@opentui/solid": "0.1.99", + "@opentui/core": "0.1.103", + "@opentui/solid": "0.1.103", "@tsconfig/node22": "catalog:", "@types/node": "catalog:", "@typescript/native-preview": "catalog:", "typescript": "catalog:", }, "peerDependencies": { - "@opentui/core": ">=0.1.99", - "@opentui/solid": ">=0.1.99", + "@opentui/core": ">=0.1.103", + "@opentui/solid": ">=0.1.103", }, "optionalPeers": [ "@opentui/core", @@ -1604,21 +1604,21 @@ "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="], - "@opentui/core": ["@opentui/core@0.1.99", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.99", "@opentui/core-darwin-x64": "0.1.99", "@opentui/core-linux-arm64": "0.1.99", "@opentui/core-linux-x64": "0.1.99", "@opentui/core-win32-arm64": "0.1.99", "@opentui/core-win32-x64": "0.1.99", "bun-webgpu": "0.1.5", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-I3+AEgGzqNWIpWX9g2WOscSPwtQDNOm4KlBjxBWCZjLxkF07u77heWXF7OiAdhKLtNUW6TFiyt6yznqAZPdG3A=="], + "@opentui/core": ["@opentui/core@0.1.103", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.103", "@opentui/core-darwin-x64": "0.1.103", "@opentui/core-linux-arm64": "0.1.103", "@opentui/core-linux-x64": "0.1.103", "@opentui/core-win32-arm64": "0.1.103", "@opentui/core-win32-x64": "0.1.103", "bun-webgpu": "0.1.5", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-PWVv/bDmlk1i6X1f0zXs+jSaTrQ/ByX8wFbP2WinOObTGf//UbcRP4dbWxPXvOyka9QlmRBG/7GbloQSIStyVw=="], - "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.99", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bzVrqeX2vb5iWrc/ftOUOqeUY8XO+qSgoTwj5TXHuwagavgwD3Hpeyjx8+icnTTeM4pao0som1WR9xfye6/X5Q=="], + "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.103", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lxCyedDkcen12IgBtXjkJ7iY66xa7VC4nxRNKCUeLY2ZP9hUE1AsDtbyQzqY+BQadsI/ZME9STzaHDCUFg0TpA=="], - "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.99", "", { "os": "darwin", "cpu": "x64" }, "sha512-VE4FrXBYpkxnvkqcCV1a8aN9jyyMJMihVW+V2NLCtp+4yQsj0AapG5TiUSN76XnmSZRptxDy5rBmEempeoIZbg=="], + "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.103", "", { "os": "darwin", "cpu": "x64" }, "sha512-QMYD+zUDGQliJ6m5nuNvA72jtluFeyVMoHkuA5m/Xmed/u8eLfahAKmDj3kY66ntUroPHWevcpbpvd7NCFEoFQ=="], - "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.99", "", { "os": "linux", "cpu": "arm64" }, "sha512-viXQsbpS7yHjYkl7+am32JdvG96QU9lvHh1UiZtpOxcNUUqiYmA2ZwZFPD2Bi54jNyj5l2hjH6YkD3DzE2FEWA=="], + "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.103", "", { "os": "linux", "cpu": "arm64" }, "sha512-GzOvNr9dN6JaQ9qs7m8E75wLAHwT5CyxqkE6rEr1BO23/d2Ix7e3GYw/JRY5VnTge+eXrfDVbqNtPcQamUNiEA=="], - "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.99", "", { "os": "linux", "cpu": "x64" }, "sha512-WLoEFINOSp0tZSR9y4LUuGc7n4Y7H1wcpjUPzQ9vChkYDXrfZltEanzoDWbDcQ4kZQW5tHVC7LrZHpAsRLwFZg=="], + "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.103", "", { "os": "linux", "cpu": "x64" }, "sha512-odywllco5zUKNc60uD3JKaCybK64u6BfmpScs4a8Qn89yH/yk23bzWXDRWaGgQdY65L2/VCbcGs1ezA1S/2YTw=="], - "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.99", "", { "os": "win32", "cpu": "arm64" }, "sha512-yWMOLWCEO8HdrctU1dMkgZC8qGkiO4Dwr4/e11tTvVpRmYhDsP/IR89ZjEEtOwnKwFOFuB/MxvflqaEWVQ2g5Q=="], + "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.103", "", { "os": "win32", "cpu": "arm64" }, "sha512-tZL5w3Y0JnO7RkIvfuNDAzJn0j6+JIYl6M8DgPM5p8AQt+162S8LmbumzmqQLZl4cEev2eN7/tw72WIk6b+/CQ=="], - "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.99", "", { "os": "win32", "cpu": "x64" }, "sha512-aYRlsL2w8YRL6vPd7/hrqlNVkXU3QowWb01TOvAcHS8UAsXaGFUr47kSDyjxDi1wg1MzmVduCfsC7T3NoThV1w=="], + "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.103", "", { "os": "win32", "cpu": "x64" }, "sha512-wqnibt/OE5ldSzVPxEbriA0TjI2B11CJl4uJoLxTZ47KDx7tAFIMdhBf9IRAGNCSbcDuZ8ZGEFhV+SLaftkrlw=="], - "@opentui/solid": ["@opentui/solid@0.1.99", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.99", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.10", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.11" } }, "sha512-DrqqO4h2V88FmeIP2cErYkMU0ZK5MrUsZw3w6IzZpoXyyiL4/9qpWzUq+CXx+r16VP2iGxDJwGKUmtFAzUch2Q=="], + "@opentui/solid": ["@opentui/solid@0.1.103", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.103", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.10", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.11" } }, "sha512-L28WFBs17Z5JXkJhPagLy8tUamkttDaaQDdb2KEO01IQ9r81yLBRpYqD/lHp6UoSISXgwQVDQ9yNtxwR1BQZvQ=="], "@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="], diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 5225ff54cc..f1d72c640f 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -123,8 +123,8 @@ "@opentelemetry/exporter-trace-otlp-http": "0.214.0", "@opentelemetry/sdk-trace-base": "2.6.1", "@opentelemetry/sdk-trace-node": "2.6.1", - "@opentui/core": "0.1.99", - "@opentui/solid": "0.1.99", + "@opentui/core": "0.1.103", + "@opentui/solid": "0.1.103", "@parcel/watcher": "2.5.1", "@pierre/diffs": "catalog:", "@solid-primitives/event-bus": "1.1.2", diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index eb5cb44e8d..30a597b91e 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -1,7 +1,6 @@ import { render, TimeToFirstDraw, useKeyboard, useRenderer, useTerminalDimensions } from "@opentui/solid" import * as Clipboard from "@tui/util/clipboard" import * as Selection from "@tui/util/selection" -import * as Terminal from "@tui/util/terminal" import { createCliRenderer, MouseButton, type CliRendererConfig } from "@opentui/core" import { RouteProvider, useRoute } from "@tui/context/route" import { @@ -121,12 +120,6 @@ export function tui(input: { const unguard = win32InstallCtrlCGuard() win32DisableProcessedInput() - const mode = await Terminal.getTerminalBackgroundColor() - - // Re-clear after getTerminalBackgroundColor() because setRawMode(false) - // restores the original console mode, including processed input on Windows. - win32DisableProcessedInput() - const onExit = async () => { unguard?.() resolve() @@ -137,6 +130,7 @@ export function tui(input: { } const renderer = await createCliRenderer(rendererConfig(input.config)) + const mode = (await renderer.waitForThemeMode(1000)) ?? "dark" await render(() => { return ( diff --git a/packages/opencode/src/cli/cmd/tui/context/theme.tsx b/packages/opencode/src/cli/cmd/tui/context/theme.tsx index af9582cfb0..3ae1eb869e 100644 --- a/packages/opencode/src/cli/cmd/tui/context/theme.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/theme.tsx @@ -314,7 +314,7 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ setStore( produce((draft) => { const lock = pick(kv.get("theme_mode_lock")) - const mode = lock ?? props.mode + const mode = lock ?? pick(renderer.themeMode) ?? props.mode if (!lock && pick(kv.get("theme_mode")) !== undefined) { kv.set("theme_mode", undefined) } diff --git a/packages/opencode/src/cli/cmd/tui/util/terminal.ts b/packages/opencode/src/cli/cmd/tui/util/terminal.ts index a61390f2cf..c026b7381c 100644 --- a/packages/opencode/src/cli/cmd/tui/util/terminal.ts +++ b/packages/opencode/src/cli/cmd/tui/util/terminal.ts @@ -17,12 +17,6 @@ function parse(color: string): RGBA | null { return null } -function mode(background: RGBA | null): "dark" | "light" { - if (!background) return "dark" - const luminance = (0.299 * background.r + 0.587 * background.g + 0.114 * background.b) / 255 - return luminance > 0.5 ? "light" : "dark" -} - /** * Query terminal colors including background, foreground, and palette (0-15). * Uses OSC escape sequences to retrieve actual terminal color values. @@ -100,36 +94,3 @@ export async function colors(): Promise<{ }, 1000) }) } - -// Keep startup mode detection separate from `colors()`: the TUI boot path only -// needs OSC 11 and should resolve on the first background response instead of -// waiting on the full palette query used by system theme generation. -export async function getTerminalBackgroundColor(): Promise<"dark" | "light"> { - if (!process.stdin.isTTY) return "dark" - - return new Promise((resolve) => { - let timeout: NodeJS.Timeout - - const cleanup = () => { - process.stdin.setRawMode(false) - process.stdin.removeListener("data", handler) - clearTimeout(timeout) - } - - const handler = (data: Buffer) => { - const match = data.toString().match(/\x1b]11;([^\x07\x1b]+)/) - if (!match) return - cleanup() - resolve(mode(parse(match[1]))) - } - - process.stdin.setRawMode(true) - process.stdin.on("data", handler) - process.stdout.write("\x1b]11;?\x07") - - timeout = setTimeout(() => { - cleanup() - resolve("dark") - }, 1000) - }) -} diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 16c5e236b8..45926f05ba 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -22,8 +22,8 @@ "zod": "catalog:" }, "peerDependencies": { - "@opentui/core": ">=0.1.99", - "@opentui/solid": ">=0.1.99" + "@opentui/core": ">=0.1.103", + "@opentui/solid": ">=0.1.103" }, "peerDependenciesMeta": { "@opentui/core": { @@ -34,8 +34,8 @@ } }, "devDependencies": { - "@opentui/core": "0.1.99", - "@opentui/solid": "0.1.99", + "@opentui/core": "0.1.103", + "@opentui/solid": "0.1.103", "@tsconfig/node22": "catalog:", "@types/node": "catalog:", "typescript": "catalog:", From 66936b0fffef0c996b4c6e3aa902662c8c6005f4 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Fri, 24 Apr 2026 15:45:10 +0000 Subject: [PATCH 74/92] chore: update nix node_modules hashes --- nix/hashes.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nix/hashes.json b/nix/hashes.json index c096046106..07d53e889a 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-AgHhYsiygxbsBo3JN4HqHXKAwh8n1qeuSCe2qqxlxW4=", - "aarch64-linux": "sha256-h2lpWRQ5EDYnjpqZXtUAp1mxKLQxJ4m8MspgSY8Ev78=", - "aarch64-darwin": "sha256-xnd91+WyeAqn06run2ajsekxJvTMiLsnqNPe/rR8VTM=", - "x86_64-darwin": "sha256-rXpz45IOjGEk73xhP9VY86eOj2CZBg2l1vzwzTIOOOQ=" + "x86_64-linux": "sha256-+G3/s18NZO1Dpc5TsZyix2Npodzei25Svw3nTjfzXW8=", + "aarch64-linux": "sha256-39HPencmRYRbyCk/cZIdPFk6ocY1AMlyuN9j25zAKzI=", + "aarch64-darwin": "sha256-043korPEjSHKiZ3P+EfWyOfKpgOC7CBpviccviaDa0o=", + "x86_64-darwin": "sha256-vsZ7e//rL9e7Cl5kl/Xplvi1fqayljxTLwRSbxvCxeM=" } } From 28f7d31e72f2556b09442dbddcd0816c1a88b1f1 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 24 Apr 2026 11:45:56 -0400 Subject: [PATCH 75/92] zen: deepseek v4 pro --- packages/console/app/src/i18n/ar.ts | 8 +-- packages/console/app/src/i18n/br.ts | 8 +-- packages/console/app/src/i18n/da.ts | 8 +-- packages/console/app/src/i18n/de.ts | 8 +-- packages/console/app/src/i18n/en.ts | 8 +-- packages/console/app/src/i18n/es.ts | 8 +-- packages/console/app/src/i18n/fr.ts | 8 +-- packages/console/app/src/i18n/it.ts | 8 +-- packages/console/app/src/i18n/ja.ts | 8 +-- packages/console/app/src/i18n/ko.ts | 8 +-- packages/console/app/src/i18n/no.ts | 8 +-- packages/console/app/src/i18n/pl.ts | 8 +-- packages/console/app/src/i18n/ru.ts | 8 +-- packages/console/app/src/i18n/th.ts | 8 +-- packages/console/app/src/i18n/tr.ts | 8 +-- packages/console/app/src/i18n/zh.ts | 8 +-- packages/console/app/src/i18n/zht.ts | 8 +-- packages/console/app/src/routes/go/index.tsx | 12 ++-- .../routes/workspace/[id]/go/lite-section.tsx | 2 + packages/web/src/content/docs/ar/go.mdx | 63 ++++++++++--------- packages/web/src/content/docs/bs/go.mdx | 63 ++++++++++--------- packages/web/src/content/docs/da/go.mdx | 63 ++++++++++--------- packages/web/src/content/docs/de/go.mdx | 63 ++++++++++--------- packages/web/src/content/docs/es/go.mdx | 63 ++++++++++--------- packages/web/src/content/docs/fr/go.mdx | 63 ++++++++++--------- packages/web/src/content/docs/go.mdx | 63 ++++++++++--------- packages/web/src/content/docs/it/go.mdx | 63 ++++++++++--------- packages/web/src/content/docs/ja/go.mdx | 63 ++++++++++--------- packages/web/src/content/docs/ko/go.mdx | 63 ++++++++++--------- packages/web/src/content/docs/nb/go.mdx | 63 ++++++++++--------- packages/web/src/content/docs/pl/go.mdx | 63 ++++++++++--------- packages/web/src/content/docs/pt-br/go.mdx | 63 ++++++++++--------- packages/web/src/content/docs/ru/go.mdx | 63 ++++++++++--------- packages/web/src/content/docs/th/go.mdx | 63 ++++++++++--------- packages/web/src/content/docs/tr/go.mdx | 63 ++++++++++--------- packages/web/src/content/docs/zh-cn/go.mdx | 63 ++++++++++--------- packages/web/src/content/docs/zh-tw/go.mdx | 63 ++++++++++--------- 37 files changed, 708 insertions(+), 576 deletions(-) diff --git a/packages/console/app/src/i18n/ar.ts b/packages/console/app/src/i18n/ar.ts index a7883cfe4c..5c0919e8e2 100644 --- a/packages/console/app/src/i18n/ar.ts +++ b/packages/console/app/src/i18n/ar.ts @@ -249,7 +249,7 @@ export const dict = { "go.title": "OpenCode Go | نماذج برمجة منخفضة التكلفة للجميع", "go.meta.description": - "يبدأ Go من $5 للشهر الأول، ثم $10/شهر، مع حدود طلب سخية لمدة 5 ساعات لـ GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7.", + "يبدأ Go من $5 للشهر الأول، ثم $10/شهر، مع حدود طلب سخية لمدة 5 ساعات لـ GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7 وDeepSeek V4 Pro وDeepSeek V4 Flash.", "go.hero.title": "نماذج برمجة منخفضة التكلفة للجميع", "go.hero.body": "يجلب Go البرمجة الوكيلة للمبرمجين حول العالم. يوفر حدودًا سخية ووصولًا موثوقًا إلى أقوى النماذج مفتوحة المصدر، حتى تتمكن من البناء باستخدام وكلاء أقوياء دون القلق بشأن التكلفة أو التوفر.", @@ -300,7 +300,7 @@ export const dict = { "go.problem.item2": "حدود سخية ووصول موثوق", "go.problem.item3": "مصمم لأكبر عدد ممكن من المبرمجين", "go.problem.item4": - "يتضمن GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7", + "يتضمن GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7 وDeepSeek V4 Pro وDeepSeek V4 Flash", "go.how.title": "كيف يعمل Go", "go.how.body": "يبدأ Go من $5 للشهر الأول، ثم $10/شهر. يمكنك استخدامه مع OpenCode أو أي وكيل.", "go.how.step1.title": "أنشئ حسابًا", @@ -324,7 +324,7 @@ export const dict = { "go.faq.a2": "يتضمن Go النماذج المدرجة أدناه، مع حدود سخية وإتاحة موثوقة.", "go.faq.q3": "هل Go هو نفسه Zen؟", "go.faq.a3": - "لا. Zen هو الدفع حسب الاستخدام، بينما يبدأ Go من $5 للشهر الأول، ثم $10/شهر، مع حدود سخية ووصول موثوق إلى نماذج المصدر المفتوح GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7.", + "لا. Zen هو الدفع حسب الاستخدام، بينما يبدأ Go من $5 للشهر الأول، ثم $10/شهر، مع حدود سخية ووصول موثوق إلى نماذج المصدر المفتوح GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7 وDeepSeek V4 Pro وDeepSeek V4 Flash.", "go.faq.q4": "كم تكلفة Go؟", "go.faq.a4.p1.beforePricing": "تكلفة Go", "go.faq.a4.p1.pricingLink": "$5 للشهر الأول", @@ -347,7 +347,7 @@ export const dict = { "go.faq.q9": "ما الفرق بين النماذج المجانية وGo؟", "go.faq.a9": - "تشمل النماذج المجانية Big Pickle بالإضافة إلى النماذج الترويجية المتاحة في ذلك الوقت، مع حصة 200 طلب/يوم. يتضمن Go نماذج GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7 مع حصص طلبات أعلى مطبقة عبر نوافذ متجددة (5 ساعات، أسبوعيًا، وشهريًا)، تعادل تقريبًا 12 دولارًا كل 5 ساعات، و30 دولارًا في الأسبوع، و60 دولارًا في الشهر (تختلف أعداد الطلبات الفعلية حسب النموذج والاستخدام).", + "تشمل النماذج المجانية Big Pickle بالإضافة إلى النماذج الترويجية المتاحة في ذلك الوقت، مع حصة 200 طلب/يوم. يتضمن Go نماذج GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7 وDeepSeek V4 Pro وDeepSeek V4 Flash مع حصص طلبات أعلى مطبقة عبر نوافذ متجددة (5 ساعات، أسبوعيًا، وشهريًا)، تعادل تقريبًا 12 دولارًا كل 5 ساعات، و30 دولارًا في الأسبوع، و60 دولارًا في الشهر (تختلف أعداد الطلبات الفعلية حسب النموذج والاستخدام).", "zen.api.error.rateLimitExceeded": "تم تجاوز حد الطلبات. يرجى المحاولة مرة أخرى لاحقًا.", "zen.api.error.modelNotSupported": "النموذج {{model}} غير مدعوم", diff --git a/packages/console/app/src/i18n/br.ts b/packages/console/app/src/i18n/br.ts index cf7b68d259..76e6987d3e 100644 --- a/packages/console/app/src/i18n/br.ts +++ b/packages/console/app/src/i18n/br.ts @@ -253,7 +253,7 @@ export const dict = { "go.title": "OpenCode Go | Modelos de codificação de baixo custo para todos", "go.meta.description": - "O Go começa em $5 no primeiro mês, depois $10/mês, com limites generosos de solicitação de 5 horas para GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7.", + "O Go começa em $5 no primeiro mês, depois $10/mês, com limites generosos de solicitação de 5 horas para GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro e DeepSeek V4 Flash.", "go.hero.title": "Modelos de codificação de baixo custo para todos", "go.hero.body": "O Go traz a codificação com agentes para programadores em todo o mundo. Oferecendo limites generosos e acesso confiável aos modelos de código aberto mais capazes, para que você possa construir com agentes poderosos sem se preocupar com custos ou disponibilidade.", @@ -305,7 +305,7 @@ export const dict = { "go.problem.item2": "Limites generosos e acesso confiável", "go.problem.item3": "Feito para o maior número possível de programadores", "go.problem.item4": - "Inclui GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7", + "Inclui GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro e DeepSeek V4 Flash", "go.how.title": "Como o Go funciona", "go.how.body": "O Go começa em $5 no primeiro mês, depois $10/mês. Você pode usá-lo com o OpenCode ou qualquer agente.", @@ -331,7 +331,7 @@ export const dict = { "go.faq.a2": "O Go inclui os modelos listados abaixo, com limites generosos e acesso confiável.", "go.faq.q3": "O Go é o mesmo que o Zen?", "go.faq.a3": - "Não. Zen é pay-as-you-go, enquanto o Go começa em $5 no primeiro mês, depois $10/mês, com limites generosos e acesso confiável aos modelos open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7.", + "Não. Zen é pay-as-you-go, enquanto o Go começa em $5 no primeiro mês, depois $10/mês, com limites generosos e acesso confiável aos modelos open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro e DeepSeek V4 Flash.", "go.faq.q4": "Quanto custa o Go?", "go.faq.a4.p1.beforePricing": "O Go custa", "go.faq.a4.p1.pricingLink": "$5 no primeiro mês", @@ -355,7 +355,7 @@ export const dict = { "go.faq.q9": "Qual a diferença entre os modelos gratuitos e o Go?", "go.faq.a9": - "Os modelos gratuitos incluem Big Pickle e modelos promocionais disponíveis no momento, com uma cota de 200 requisições/dia. O Go inclui GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7 com cotas de requisição mais altas aplicadas em janelas móveis (5 horas, semanal e mensal), aproximadamente equivalentes a $12 por 5 horas, $30 por semana e $60 por mês (as contagens reais de requisições variam de acordo com o modelo e o uso).", + "Os modelos gratuitos incluem Big Pickle e modelos promocionais disponíveis no momento, com uma cota de 200 requisições/dia. O Go inclui GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro e DeepSeek V4 Flash com cotas de requisição mais altas aplicadas em janelas móveis (5 horas, semanal e mensal), aproximadamente equivalentes a $12 por 5 horas, $30 por semana e $60 por mês (as contagens reais de requisições variam de acordo com o modelo e o uso).", "zen.api.error.rateLimitExceeded": "Limite de taxa excedido. Por favor, tente novamente mais tarde.", "zen.api.error.modelNotSupported": "Modelo {{model}} não suportado", diff --git a/packages/console/app/src/i18n/da.ts b/packages/console/app/src/i18n/da.ts index 90eff469a2..b97ee2cc0a 100644 --- a/packages/console/app/src/i18n/da.ts +++ b/packages/console/app/src/i18n/da.ts @@ -251,7 +251,7 @@ export const dict = { "go.title": "OpenCode Go | Kodningsmodeller til lav pris for alle", "go.meta.description": - "Go starter ved $5 for den første måned, derefter $10/måned, med generøse 5-timers anmodningsgrænser for GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7.", + "Go starter ved $5 for den første måned, derefter $10/måned, med generøse 5-timers anmodningsgrænser for GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro og DeepSeek V4 Flash.", "go.hero.title": "Kodningsmodeller til lav pris for alle", "go.hero.body": "Go bringer agentisk kodning til programmører over hele verden. Med generøse grænser og pålidelig adgang til de mest kapable open source-modeller, så du kan bygge med kraftfulde agenter uden at bekymre dig om omkostninger eller tilgængelighed.", @@ -302,7 +302,7 @@ export const dict = { "go.problem.item2": "Generøse grænser og pålidelig adgang", "go.problem.item3": "Bygget til så mange programmører som muligt", "go.problem.item4": - "Inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7", + "Inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro og DeepSeek V4 Flash", "go.how.title": "Hvordan Go virker", "go.how.body": "Go starter ved $5 for den første måned, derefter $10/måned. Du kan bruge det med OpenCode eller enhver agent.", @@ -328,7 +328,7 @@ export const dict = { "go.faq.a2": "Go inkluderer modellerne nedenfor med generøse grænser og pålidelig adgang.", "go.faq.q3": "Er Go det samme som Zen?", "go.faq.a3": - "Nej. Zen er pay-as-you-go, mens Go starter ved $5 for den første måned, derefter $10/måned, med generøse grænser og pålidelig adgang til open source-modellerne GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7.", + "Nej. Zen er pay-as-you-go, mens Go starter ved $5 for den første måned, derefter $10/måned, med generøse grænser og pålidelig adgang til open source-modellerne GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro og DeepSeek V4 Flash.", "go.faq.q4": "Hvad koster Go?", "go.faq.a4.p1.beforePricing": "Go koster", "go.faq.a4.p1.pricingLink": "$5 første måned", @@ -351,7 +351,7 @@ export const dict = { "go.faq.q9": "Hvad er forskellen på gratis modeller og Go?", "go.faq.a9": - "Gratis modeller inkluderer Big Pickle plus salgsfremmende modeller tilgængelige på det tidspunkt, med en kvote på 200 forespørgsler/dag. Go inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7 med højere anmodningskvoter håndhævet over rullende vinduer (5-timers, ugentlig og månedlig), nogenlunde svarende til $12 pr. 5 timer, $30 pr. uge og $60 pr. måned (faktiske anmodningstal varierer efter model og brug).", + "Gratis modeller inkluderer Big Pickle plus salgsfremmende modeller tilgængelige på det tidspunkt, med en kvote på 200 forespørgsler/dag. Go inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro og DeepSeek V4 Flash med højere anmodningskvoter håndhævet over rullende vinduer (5-timers, ugentlig og månedlig), nogenlunde svarende til $12 pr. 5 timer, $30 pr. uge og $60 pr. måned (faktiske anmodningstal varierer efter model og brug).", "zen.api.error.rateLimitExceeded": "Hastighedsgrænse overskredet. Prøv venligst igen senere.", "zen.api.error.modelNotSupported": "Model {{model}} understøttes ikke", diff --git a/packages/console/app/src/i18n/de.ts b/packages/console/app/src/i18n/de.ts index af339802fa..33b6e1b3de 100644 --- a/packages/console/app/src/i18n/de.ts +++ b/packages/console/app/src/i18n/de.ts @@ -253,7 +253,7 @@ export const dict = { "go.title": "OpenCode Go | Kostengünstige Coding-Modelle für alle", "go.meta.description": - "Go beginnt bei $5 für den ersten Monat, danach $10/Monat, mit großzügigen 5-Stunden-Anfragelimits für GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 und MiniMax M2.7.", + "Go beginnt bei $5 für den ersten Monat, danach $10/Monat, mit großzügigen 5-Stunden-Anfragelimits für GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro und DeepSeek V4 Flash.", "go.hero.title": "Kostengünstige Coding-Modelle für alle", "go.hero.body": "Go bringt Agentic Coding zu Programmierern auf der ganzen Welt. Mit großzügigen Limits und zuverlässigem Zugang zu den leistungsfähigsten Open-Source-Modellen, damit du mit leistungsstarken Agenten entwickeln kannst, ohne dir Gedanken über Kosten oder Verfügbarkeit zu machen.", @@ -304,7 +304,7 @@ export const dict = { "go.problem.item2": "Großzügige Limits und zuverlässiger Zugang", "go.problem.item3": "Für so viele Programmierer wie möglich gebaut", "go.problem.item4": - "Beinhaltet GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 und MiniMax M2.7", + "Beinhaltet GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro und DeepSeek V4 Flash", "go.how.title": "Wie Go funktioniert", "go.how.body": "Go beginnt bei $5 für den ersten Monat, danach $10/Monat. Du kannst es mit OpenCode oder jedem Agenten nutzen.", @@ -330,7 +330,7 @@ export const dict = { "go.faq.a2": "Go umfasst die unten aufgeführten Modelle mit großzügigen Limits und zuverlässigem Zugriff.", "go.faq.q3": "Ist Go dasselbe wie Zen?", "go.faq.a3": - "Nein. Zen ist Pay-as-you-go, während Go bei $5 für den ersten Monat beginnt, danach $10/Monat, mit großzügigen Limits und zuverlässigem Zugang zu den Open-Source-Modellen GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 und MiniMax M2.7.", + "Nein. Zen ist Pay-as-you-go, während Go bei $5 für den ersten Monat beginnt, danach $10/Monat, mit großzügigen Limits und zuverlässigem Zugang zu den Open-Source-Modellen GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro und DeepSeek V4 Flash.", "go.faq.q4": "Wie viel kostet Go?", "go.faq.a4.p1.beforePricing": "Go kostet", "go.faq.a4.p1.pricingLink": "$5 im ersten Monat", @@ -354,7 +354,7 @@ export const dict = { "go.faq.q9": "Was ist der Unterschied zwischen kostenlosen Modellen und Go?", "go.faq.a9": - "Kostenlose Modelle beinhalten Big Pickle sowie Werbemodelle, die zum jeweiligen Zeitpunkt verfügbar sind, mit einem Kontingent von 200 Anfragen/Tag. Go beinhaltet GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 und MiniMax M2.7 mit höheren Anfragekontingenten, die über rollierende Zeitfenster (5 Stunden, wöchentlich und monatlich) durchgesetzt werden, grob äquivalent zu $12 pro 5 Stunden, $30 pro Woche und $60 pro Monat (tatsächliche Anfragezahlen variieren je nach Modell und Nutzung).", + "Kostenlose Modelle beinhalten Big Pickle sowie Werbemodelle, die zum jeweiligen Zeitpunkt verfügbar sind, mit einem Kontingent von 200 Anfragen/Tag. Go beinhaltet GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro und DeepSeek V4 Flash mit höheren Anfragekontingenten, die über rollierende Zeitfenster (5 Stunden, wöchentlich und monatlich) durchgesetzt werden, grob äquivalent zu $12 pro 5 Stunden, $30 pro Woche und $60 pro Monat (tatsächliche Anfragezahlen variieren je nach Modell und Nutzung).", "zen.api.error.rateLimitExceeded": "Ratenlimit überschritten. Bitte versuche es später erneut.", "zen.api.error.modelNotSupported": "Modell {{model}} wird nicht unterstützt", diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index f5cc954e5e..b6934b94de 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -248,7 +248,7 @@ export const dict = { "go.title": "OpenCode Go | Low cost coding models for everyone", "go.meta.description": - "Go starts at $5 for your first month, then $10/month, with generous 5-hour request limits for GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, and MiniMax M2.7.", + "Go starts at $5 for your first month, then $10/month, with generous 5-hour request limits for GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, and DeepSeek V4 Flash.", "go.banner.badge": "3x", "go.banner.text": "Kimi K2.6 gets 3× usage limits through April 27", "go.hero.title": "Low cost coding models for everyone", @@ -298,7 +298,7 @@ export const dict = { "go.problem.item2": "Generous limits and reliable access", "go.problem.item3": "Built for as many programmers as possible", "go.problem.item4": - "Includes GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, and MiniMax M2.7", + "Includes GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, and DeepSeek V4 Flash", "go.how.title": "How Go works", "go.how.body": "Go starts at $5 for your first month, then $10/month. You can use it with OpenCode or any agent.", "go.how.step1.title": "Create an account", @@ -323,7 +323,7 @@ export const dict = { "go.faq.a2": "Go includes the models listed below, with generous limits and reliable access.", "go.faq.q3": "Is Go the same as Zen?", "go.faq.a3": - "No. Zen is pay-as-you-go, while Go starts at $5 for your first month, then $10/month, with generous limits and reliable access to open-source models GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, and MiniMax M2.7.", + "No. Zen is pay-as-you-go, while Go starts at $5 for your first month, then $10/month, with generous limits and reliable access to open-source models GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, and DeepSeek V4 Flash.", "go.faq.q4": "How much does Go cost?", "go.faq.a4.p1.beforePricing": "Go costs", "go.faq.a4.p1.pricingLink": "$5 first month", @@ -347,7 +347,7 @@ export const dict = { "go.faq.q9": "What is the difference between free models and Go?", "go.faq.a9": - "Free models include Big Pickle plus promotional models available at the time, with a quota of 200 requests/day. Go includes GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, and MiniMax M2.7 with higher request quotas enforced across rolling windows (5-hour, weekly, and monthly), roughly equivalent to $12 per 5 hours, $30 per week, and $60 per month (actual request counts vary by model and usage).", + "Free models include Big Pickle plus promotional models available at the time, with a quota of 200 requests/day. Go includes GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, and DeepSeek V4 Flash with higher request quotas enforced across rolling windows (5-hour, weekly, and monthly), roughly equivalent to $12 per 5 hours, $30 per week, and $60 per month (actual request counts vary by model and usage).", "zen.api.error.rateLimitExceeded": "Rate limit exceeded. Please try again later.", "zen.api.error.modelNotSupported": "Model {{model}} not supported", diff --git a/packages/console/app/src/i18n/es.ts b/packages/console/app/src/i18n/es.ts index fb718e0541..c5cc71ae1e 100644 --- a/packages/console/app/src/i18n/es.ts +++ b/packages/console/app/src/i18n/es.ts @@ -254,7 +254,7 @@ export const dict = { "go.title": "OpenCode Go | Modelos de programación de bajo coste para todos", "go.meta.description": - "Go comienza en $5 el primer mes, luego 10 $/mes, con generosos límites de solicitudes de 5 horas para GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 y MiniMax M2.7.", + "Go comienza en $5 el primer mes, luego 10 $/mes, con generosos límites de solicitudes de 5 horas para GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro y DeepSeek V4 Flash.", "go.hero.title": "Modelos de programación de bajo coste para todos", "go.hero.body": "Go lleva la programación agéntica a programadores de todo el mundo. Ofrece límites generosos y acceso fiable a los modelos de código abierto más capaces, para que puedas crear con agentes potentes sin preocuparte por el coste o la disponibilidad.", @@ -306,7 +306,7 @@ export const dict = { "go.problem.item2": "Límites generosos y acceso fiable", "go.problem.item3": "Creado para tantos programadores como sea posible", "go.problem.item4": - "Incluye GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 y MiniMax M2.7", + "Incluye GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro y DeepSeek V4 Flash", "go.how.title": "Cómo funciona Go", "go.how.body": "Go comienza en $5 el primer mes, luego 10 $/mes. Puedes usarlo con OpenCode o cualquier agente.", "go.how.step1.title": "Crear una cuenta", @@ -331,7 +331,7 @@ export const dict = { "go.faq.a2": "Go incluye los modelos que se indican abajo, con límites generosos y acceso confiable.", "go.faq.q3": "¿Es Go lo mismo que Zen?", "go.faq.a3": - "No. Zen es pago por uso, mientras que Go comienza en $5 el primer mes, luego 10 $/mes, con límites generosos y acceso fiable a los modelos de código abierto GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 y MiniMax M2.7.", + "No. Zen es pago por uso, mientras que Go comienza en $5 el primer mes, luego 10 $/mes, con límites generosos y acceso fiable a los modelos de código abierto GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro y DeepSeek V4 Flash.", "go.faq.q4": "¿Cuánto cuesta Go?", "go.faq.a4.p1.beforePricing": "Go cuesta", "go.faq.a4.p1.pricingLink": "$5 el primer mes", @@ -355,7 +355,7 @@ export const dict = { "go.faq.q9": "¿Cuál es la diferencia entre los modelos gratuitos y Go?", "go.faq.a9": - "Los modelos gratuitos incluyen Big Pickle más modelos promocionales disponibles en el momento, con una cuota de 200 solicitudes/día. Go incluye GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 y MiniMax M2.7 con cuotas de solicitud más altas aplicadas a través de ventanas móviles (5 horas, semanal y mensual), aproximadamente equivalente a 12 $ por 5 horas, 30 $ por semana y 60 $ por mes (los recuentos reales de solicitudes varían según el modelo y el uso).", + "Los modelos gratuitos incluyen Big Pickle más modelos promocionales disponibles en el momento, con una cuota de 200 solicitudes/día. Go incluye GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro y DeepSeek V4 Flash con cuotas de solicitud más altas aplicadas a través de ventanas móviles (5 horas, semanal y mensual), aproximadamente equivalente a 12 $ por 5 horas, 30 $ por semana y 60 $ por mes (los recuentos reales de solicitudes varían según el modelo y el uso).", "zen.api.error.rateLimitExceeded": "Límite de tasa excedido. Por favor, inténtalo de nuevo más tarde.", "zen.api.error.modelNotSupported": "Modelo {{model}} no soportado", diff --git a/packages/console/app/src/i18n/fr.ts b/packages/console/app/src/i18n/fr.ts index 976d93a29a..04e6e3bc62 100644 --- a/packages/console/app/src/i18n/fr.ts +++ b/packages/console/app/src/i18n/fr.ts @@ -255,7 +255,7 @@ export const dict = { "go.title": "OpenCode Go | Modèles de code à faible coût pour tous", "go.meta.description": - "Go commence à $5 pour le premier mois, puis 10 $/mois, avec des limites de requêtes généreuses sur 5 heures pour GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 et MiniMax M2.7.", + "Go commence à $5 pour le premier mois, puis 10 $/mois, avec des limites de requêtes généreuses sur 5 heures pour GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro et DeepSeek V4 Flash.", "go.hero.title": "Modèles de code à faible coût pour tous", "go.hero.body": "Go apporte le codage agentique aux programmeurs du monde entier. Offrant des limites généreuses et un accès fiable aux modèles open source les plus capables, pour que vous puissiez construire avec des agents puissants sans vous soucier du coût ou de la disponibilité.", @@ -306,7 +306,7 @@ export const dict = { "go.problem.item2": "Limites généreuses et accès fiable", "go.problem.item3": "Conçu pour autant de programmeurs que possible", "go.problem.item4": - "Inclut GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 et MiniMax M2.7", + "Inclut GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro et DeepSeek V4 Flash", "go.how.title": "Comment fonctionne Go", "go.how.body": "Go commence à $5 pour le premier mois, puis 10 $/mois. Vous pouvez l'utiliser avec OpenCode ou n'importe quel agent.", @@ -332,7 +332,7 @@ export const dict = { "go.faq.a2": "Go inclut les modèles ci-dessous, avec des limites généreuses et un accès fiable.", "go.faq.q3": "Est-ce que Go est la même chose que Zen ?", "go.faq.a3": - "Non. Zen est un paiement à l'utilisation, tandis que Go commence à $5 pour le premier mois, puis 10 $/mois, avec des limites généreuses et un accès fiable aux modèles open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 et MiniMax M2.7.", + "Non. Zen est un paiement à l'utilisation, tandis que Go commence à $5 pour le premier mois, puis 10 $/mois, avec des limites généreuses et un accès fiable aux modèles open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro et DeepSeek V4 Flash.", "go.faq.q4": "Combien coûte Go ?", "go.faq.a4.p1.beforePricing": "Go coûte", "go.faq.a4.p1.pricingLink": "$5 le premier mois", @@ -355,7 +355,7 @@ export const dict = { "Oui, vous pouvez utiliser Go avec n'importe quel agent. Suivez les instructions de configuration dans votre agent de code préféré.", "go.faq.q9": "Quelle est la différence entre les modèles gratuits et Go ?", "go.faq.a9": - "Les modèles gratuits incluent Big Pickle ainsi que des modèles promotionnels disponibles à ce moment-là, avec un quota de 200 requêtes/jour. Go inclut GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 et MiniMax M2.7 avec des quotas de requêtes plus élevés appliqués sur des fenêtres glissantes (5 heures, hebdomadaire et mensuelle), à peu près équivalent à 12 $ par 5 heures, 30 $ par semaine et 60 $ par mois (le nombre réel de requêtes varie selon le modèle et l'utilisation).", + "Les modèles gratuits incluent Big Pickle ainsi que des modèles promotionnels disponibles à ce moment-là, avec un quota de 200 requêtes/jour. Go inclut GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro et DeepSeek V4 Flash avec des quotas de requêtes plus élevés appliqués sur des fenêtres glissantes (5 heures, hebdomadaire et mensuelle), à peu près équivalent à 12 $ par 5 heures, 30 $ par semaine et 60 $ par mois (le nombre réel de requêtes varie selon le modèle et l'utilisation).", "zen.api.error.rateLimitExceeded": "Limite de débit dépassée. Veuillez réessayer plus tard.", "zen.api.error.modelNotSupported": "Modèle {{model}} non pris en charge", diff --git a/packages/console/app/src/i18n/it.ts b/packages/console/app/src/i18n/it.ts index 6069ad73ce..13f33bfc39 100644 --- a/packages/console/app/src/i18n/it.ts +++ b/packages/console/app/src/i18n/it.ts @@ -251,7 +251,7 @@ export const dict = { "go.title": "OpenCode Go | Modelli di coding a basso costo per tutti", "go.meta.description": - "Go inizia a $5 per il primo mese, poi $10/mese, con generosi limiti di richiesta di 5 ore per GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7.", + "Go inizia a $5 per il primo mese, poi $10/mese, con generosi limiti di richiesta di 5 ore per GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro e DeepSeek V4 Flash.", "go.hero.title": "Modelli di coding a basso costo per tutti", "go.hero.body": "Go porta il coding agentico ai programmatori di tutto il mondo. Offrendo limiti generosi e un accesso affidabile ai modelli open source più capaci, in modo da poter costruire con agenti potenti senza preoccuparsi dei costi o della disponibilità.", @@ -302,7 +302,7 @@ export const dict = { "go.problem.item2": "Limiti generosi e accesso affidabile", "go.problem.item3": "Costruito per il maggior numero possibile di programmatori", "go.problem.item4": - "Include GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7", + "Include GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro e DeepSeek V4 Flash", "go.how.title": "Come funziona Go", "go.how.body": "Go inizia a $5 per il primo mese, poi $10/mese. Puoi usarlo con OpenCode o qualsiasi agente.", "go.how.step1.title": "Crea un account", @@ -327,7 +327,7 @@ export const dict = { "go.faq.a2": "Go include i modelli elencati di seguito, con limiti generosi e accesso affidabile.", "go.faq.q3": "Go è lo stesso di Zen?", "go.faq.a3": - "No. Zen è a consumo, mentre Go inizia a $5 per il primo mese, poi $10/mese, con limiti generosi e accesso affidabile ai modelli open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7.", + "No. Zen è a consumo, mentre Go inizia a $5 per il primo mese, poi $10/mese, con limiti generosi e accesso affidabile ai modelli open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro e DeepSeek V4 Flash.", "go.faq.q4": "Quanto costa Go?", "go.faq.a4.p1.beforePricing": "Go costa", "go.faq.a4.p1.pricingLink": "$5 il primo mese", @@ -351,7 +351,7 @@ export const dict = { "go.faq.q9": "Qual è la differenza tra i modelli gratuiti e Go?", "go.faq.a9": - "I modelli gratuiti includono Big Pickle più modelli promozionali disponibili al momento, con una quota di 200 richieste/giorno. Go include GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7 con quote di richiesta più elevate applicate su finestre mobili (5 ore, settimanale e mensile), approssimativamente equivalenti a $12 ogni 5 ore, $30 a settimana e $60 al mese (il conteggio effettivo delle richieste varia in base al modello e all'utilizzo).", + "I modelli gratuiti includono Big Pickle più modelli promozionali disponibili al momento, con una quota di 200 richieste/giorno. Go include GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro e DeepSeek V4 Flash con quote di richiesta più elevate applicate su finestre mobili (5 ore, settimanale e mensile), approssimativamente equivalenti a $12 ogni 5 ore, $30 a settimana e $60 al mese (il conteggio effettivo delle richieste varia in base al modello e all'utilizzo).", "zen.api.error.rateLimitExceeded": "Limite di richieste superato. Riprova più tardi.", "zen.api.error.modelNotSupported": "Modello {{model}} non supportato", diff --git a/packages/console/app/src/i18n/ja.ts b/packages/console/app/src/i18n/ja.ts index dcf2f9b52f..845faebf61 100644 --- a/packages/console/app/src/i18n/ja.ts +++ b/packages/console/app/src/i18n/ja.ts @@ -250,7 +250,7 @@ export const dict = { "go.title": "OpenCode Go | すべての人のための低価格なコーディングモデル", "go.meta.description": - "Goは最初の月$5、その後$10/月で、GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7に対して5時間のゆとりあるリクエスト上限があります。", + "Goは最初の月$5、その後$10/月で、GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro、DeepSeek V4 Flashに対して5時間のゆとりあるリクエスト上限があります。", "go.hero.title": "すべての人のための低価格なコーディングモデル", "go.hero.body": "Goは、世界中のプログラマーにエージェント型コーディングをもたらします。最も高性能なオープンソースモデルへの十分な制限と安定したアクセスを提供し、コストや可用性を気にすることなく強力なエージェントで構築できます。", @@ -302,7 +302,7 @@ export const dict = { "go.problem.item2": "十分な制限と安定したアクセス", "go.problem.item3": "できるだけ多くのプログラマーのために構築", "go.problem.item4": - "GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7を含む", + "GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro、DeepSeek V4 Flashを含む", "go.how.title": "Goの仕組み", "go.how.body": "Goは最初の月$5、その後$10/月で始まります。OpenCodeまたは任意のエージェントで使えます。", "go.how.step1.title": "アカウントを作成", @@ -327,7 +327,7 @@ export const dict = { "go.faq.a2": "Go には、十分な利用上限と安定したアクセスを備えた、以下のモデルが含まれます。", "go.faq.q3": "GoはZenと同じですか?", "go.faq.a3": - "いいえ。Zenは従量課金制ですが、Goは最初の月$5、その後$10/月で始まり、GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7のオープンソースモデルに対して、ゆとりある上限と信頼できるアクセスを提供します。", + "いいえ。Zenは従量課金制ですが、Goは最初の月$5、その後$10/月で始まり、GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro、DeepSeek V4 Flashのオープンソースモデルに対して、ゆとりある上限と信頼できるアクセスを提供します。", "go.faq.q4": "Goの料金は?", "go.faq.a4.p1.beforePricing": "Goは", "go.faq.a4.p1.pricingLink": "最初の月$5", @@ -351,7 +351,7 @@ export const dict = { "go.faq.q9": "無料モデルとGoの違いは何ですか?", "go.faq.a9": - "無料モデルにはBig Pickleと、その時点で利用可能なプロモーションモデルが含まれ、1日200リクエストの制限があります。GoにはGLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7が含まれ、ローリングウィンドウ(5時間、週間、月間)全体でより高いリクエスト制限が適用されます。これは概算で5時間あたり$12、週間$30、月間$60相当です(実際のリクエスト数はモデルと使用状況により異なります)。", + "無料モデルにはBig Pickleと、その時点で利用可能なプロモーションモデルが含まれ、1日200リクエストの制限があります。GoにはGLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro、DeepSeek V4 Flashが含まれ、ローリングウィンドウ(5時間、週間、月間)全体でより高いリクエスト制限が適用されます。これは概算で5時間あたり$12、週間$30、月間$60相当です(実際のリクエスト数はモデルと使用状況により異なります)。", "zen.api.error.rateLimitExceeded": "レート制限を超えました。後でもう一度お試しください。", "zen.api.error.modelNotSupported": "モデル {{model}} はサポートされていません", diff --git a/packages/console/app/src/i18n/ko.ts b/packages/console/app/src/i18n/ko.ts index f2a67fbbae..7efe563a07 100644 --- a/packages/console/app/src/i18n/ko.ts +++ b/packages/console/app/src/i18n/ko.ts @@ -247,7 +247,7 @@ export const dict = { "go.title": "OpenCode Go | 모두를 위한 저비용 코딩 모델", "go.meta.description": - "Go는 첫 달 $5, 이후 $10/월로 시작하며, GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7에 대해 넉넉한 5시간 요청 한도를 제공합니다.", + "Go는 첫 달 $5, 이후 $10/월로 시작하며, GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, DeepSeek V4 Flash에 대해 넉넉한 5시간 요청 한도를 제공합니다.", "go.hero.title": "모두를 위한 저비용 코딩 모델", "go.hero.body": "Go는 전 세계 프로그래머들에게 에이전트 코딩을 제공합니다. 가장 유능한 오픈 소스 모델에 대한 넉넉한 한도와 안정적인 액세스를 제공하므로, 비용이나 가용성 걱정 없이 강력한 에이전트로 빌드할 수 있습니다.", @@ -299,7 +299,7 @@ export const dict = { "go.problem.item2": "넉넉한 한도와 안정적인 액세스", "go.problem.item3": "가능한 한 많은 프로그래머를 위해 제작됨", "go.problem.item4": - "GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7 포함", + "GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, DeepSeek V4 Flash 포함", "go.how.title": "Go 작동 방식", "go.how.body": "Go는 첫 달 $5, 이후 $10/월로 시작합니다. OpenCode 또는 어떤 에이전트와도 함께 사용할 수 있습니다.", "go.how.step1.title": "계정 생성", @@ -323,7 +323,7 @@ export const dict = { "go.faq.a2": "Go에는 넉넉한 한도와 안정적인 액세스를 제공하는 아래 모델이 포함됩니다.", "go.faq.q3": "Go는 Zen과 같은가요?", "go.faq.a3": - "아니요. Zen은 종량제인 반면, Go는 첫 달 $5, 이후 $10/월로 시작하며, GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7 오픈 소스 모델에 대한 넉넉한 한도와 안정적인 액세스를 제공합니다.", + "아니요. Zen은 종량제인 반면, Go는 첫 달 $5, 이후 $10/월로 시작하며, GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, DeepSeek V4 Flash 오픈 소스 모델에 대한 넉넉한 한도와 안정적인 액세스를 제공합니다.", "go.faq.q4": "Go 비용은 얼마인가요?", "go.faq.a4.p1.beforePricing": "Go 비용은", "go.faq.a4.p1.pricingLink": "첫 달 $5", @@ -346,7 +346,7 @@ export const dict = { "go.faq.q9": "무료 모델과 Go의 차이점은 무엇인가요?", "go.faq.a9": - "무료 모델에는 Big Pickle과 당시 사용 가능한 프로모션 모델이 포함되며, 하루 200회 요청 할당량이 적용됩니다. Go는 GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7를 포함하며, 롤링 윈도우(5시간, 주간, 월간)에 걸쳐 더 높은 요청 할당량을 적용합니다. 이는 대략 5시간당 $12, 주당 $30, 월 $60에 해당합니다(실제 요청 수는 모델 및 사용량에 따라 다름).", + "무료 모델에는 Big Pickle과 당시 사용 가능한 프로모션 모델이 포함되며, 하루 200회 요청 할당량이 적용됩니다. Go는 GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, DeepSeek V4 Flash를 포함하며, 롤링 윈도우(5시간, 주간, 월간)에 걸쳐 더 높은 요청 할당량을 적용합니다. 이는 대략 5시간당 $12, 주당 $30, 월 $60에 해당합니다(실제 요청 수는 모델 및 사용량에 따라 다름).", "zen.api.error.rateLimitExceeded": "속도 제한을 초과했습니다. 나중에 다시 시도해 주세요.", "zen.api.error.modelNotSupported": "{{model}} 모델은 지원되지 않습니다", diff --git a/packages/console/app/src/i18n/no.ts b/packages/console/app/src/i18n/no.ts index 0207a57760..8948e158b0 100644 --- a/packages/console/app/src/i18n/no.ts +++ b/packages/console/app/src/i18n/no.ts @@ -251,7 +251,7 @@ export const dict = { "go.title": "OpenCode Go | Rimelige kodemodeller for alle", "go.meta.description": - "Go starter på $5 for den første måneden, deretter $10/måned, med sjenerøse 5-timers forespørselsgrenser for GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7.", + "Go starter på $5 for den første måneden, deretter $10/måned, med sjenerøse 5-timers forespørselsgrenser for GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro og DeepSeek V4 Flash.", "go.hero.title": "Rimelige kodemodeller for alle", "go.hero.body": "Go bringer agent-koding til programmerere over hele verden. Med rause grenser og pålitelig tilgang til de mest kapable åpen kildekode-modellene, kan du bygge med kraftige agenter uten å bekymre deg for kostnader eller tilgjengelighet.", @@ -302,7 +302,7 @@ export const dict = { "go.problem.item2": "Rause grenser og pålitelig tilgang", "go.problem.item3": "Bygget for så mange programmerere som mulig", "go.problem.item4": - "Inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7", + "Inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro og DeepSeek V4 Flash", "go.how.title": "Hvordan Go fungerer", "go.how.body": "Go starter på $5 for den første måneden, deretter $10/måned. Du kan bruke det med OpenCode eller hvilken som helst agent.", @@ -328,7 +328,7 @@ export const dict = { "go.faq.a2": "Go inkluderer modellene nedenfor, med høye grenser og pålitelig tilgang.", "go.faq.q3": "Er Go det samme som Zen?", "go.faq.a3": - "Nei. Zen er betaling etter bruk, mens Go starter på $5 for den første måneden, deretter $10/måned, med sjenerøse grenser og pålitelig tilgang til åpen kildekode-modellene GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7.", + "Nei. Zen er betaling etter bruk, mens Go starter på $5 for den første måneden, deretter $10/måned, med sjenerøse grenser og pålitelig tilgang til åpen kildekode-modellene GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro og DeepSeek V4 Flash.", "go.faq.q4": "Hva koster Go?", "go.faq.a4.p1.beforePricing": "Go koster", "go.faq.a4.p1.pricingLink": "$5 første måned", @@ -352,7 +352,7 @@ export const dict = { "go.faq.q9": "Hva er forskjellen mellom gratis modeller og Go?", "go.faq.a9": - "Gratis modeller inkluderer Big Pickle pluss kampanjemodeller tilgjengelig på det tidspunktet, med en kvote på 200 forespørsler/dag. Go inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7 med høyere kvoter håndhevet over rullerende vinduer (5 timer, ukentlig og månedlig), omtrent tilsvarende $12 per 5 timer, $30 per uke og $60 per måned (faktiske forespørselsantall varierer etter modell og bruk).", + "Gratis modeller inkluderer Big Pickle pluss kampanjemodeller tilgjengelig på det tidspunktet, med en kvote på 200 forespørsler/dag. Go inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro og DeepSeek V4 Flash med høyere kvoter håndhevet over rullerende vinduer (5 timer, ukentlig og månedlig), omtrent tilsvarende $12 per 5 timer, $30 per uke og $60 per måned (faktiske forespørselsantall varierer etter modell og bruk).", "zen.api.error.rateLimitExceeded": "Rate limit overskredet. Vennligst prøv igjen senere.", "zen.api.error.modelNotSupported": "Modell {{model}} støttes ikke", diff --git a/packages/console/app/src/i18n/pl.ts b/packages/console/app/src/i18n/pl.ts index 554a2d0aab..f879ed7057 100644 --- a/packages/console/app/src/i18n/pl.ts +++ b/packages/console/app/src/i18n/pl.ts @@ -252,7 +252,7 @@ export const dict = { "go.title": "OpenCode Go | Niskokosztowe modele do kodowania dla każdego", "go.meta.description": - "Go zaczyna się od $5 za pierwszy miesiąc, potem $10/miesiąc, z hojnymi 5-godzinnymi limitami zapytań dla GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 i MiniMax M2.7.", + "Go zaczyna się od $5 za pierwszy miesiąc, potem $10/miesiąc, z hojnymi 5-godzinnymi limitami zapytań dla GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro i DeepSeek V4 Flash.", "go.hero.title": "Niskokosztowe modele do kodowania dla każdego", "go.hero.body": "Go udostępnia programowanie z agentami programistom na całym świecie. Oferuje hojne limity i niezawodny dostęp do najzdolniejszych modeli open source, dzięki czemu możesz budować za pomocą potężnych agentów, nie martwiąc się o koszty czy dostępność.", @@ -303,7 +303,7 @@ export const dict = { "go.problem.item2": "Hojne limity i niezawodny dostęp", "go.problem.item3": "Stworzony dla jak największej liczby programistów", "go.problem.item4": - "Zawiera GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 i MiniMax M2.7", + "Zawiera GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro i DeepSeek V4 Flash", "go.how.title": "Jak działa Go", "go.how.body": "Go zaczyna się od $5 za pierwszy miesiąc, potem $10/miesiąc. Możesz go używać z OpenCode lub dowolnym agentem.", @@ -329,7 +329,7 @@ export const dict = { "go.faq.a2": "Go obejmuje poniższe modele z wysokimi limitami i niezawodnym dostępem.", "go.faq.q3": "Czy Go to to samo co Zen?", "go.faq.a3": - "Nie. Zen to model płatności za użycie, podczas gdy Go zaczyna się od $5 za pierwszy miesiąc, potem $10/miesiąc, z hojnymi limitami i niezawodnym dostępem do modeli open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 i MiniMax M2.7.", + "Nie. Zen to model płatności za użycie, podczas gdy Go zaczyna się od $5 za pierwszy miesiąc, potem $10/miesiąc, z hojnymi limitami i niezawodnym dostępem do modeli open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro i DeepSeek V4 Flash.", "go.faq.q4": "Ile kosztuje Go?", "go.faq.a4.p1.beforePricing": "Go kosztuje", "go.faq.a4.p1.pricingLink": "$5 za pierwszy miesiąc", @@ -353,7 +353,7 @@ export const dict = { "go.faq.q9": "Jaka jest różnica między darmowymi modelami a Go?", "go.faq.a9": - "Darmowe modele obejmują Big Pickle oraz modele promocyjne dostępne w danym momencie, z limitem 200 zapytań/dzień. Go zawiera GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 i MiniMax M2.7 z wyższymi limitami zapytań egzekwowanymi w oknach kroczących (5-godzinnych, tygodniowych i miesięcznych), w przybliżeniu równoważnymi $12 na 5 godzin, $30 tygodniowo i $60 miesięcznie (rzeczywista liczba zapytań zależy od modelu i użycia).", + "Darmowe modele obejmują Big Pickle oraz modele promocyjne dostępne w danym momencie, z limitem 200 zapytań/dzień. Go zawiera GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro i DeepSeek V4 Flash z wyższymi limitami zapytań egzekwowanymi w oknach kroczących (5-godzinnych, tygodniowych i miesięcznych), w przybliżeniu równoważnymi $12 na 5 godzin, $30 tygodniowo i $60 miesięcznie (rzeczywista liczba zapytań zależy od modelu i użycia).", "zen.api.error.rateLimitExceeded": "Przekroczono limit zapytań. Spróbuj ponownie później.", "zen.api.error.modelNotSupported": "Model {{model}} nie jest obsługiwany", diff --git a/packages/console/app/src/i18n/ru.ts b/packages/console/app/src/i18n/ru.ts index 1e50134199..9ba36d2208 100644 --- a/packages/console/app/src/i18n/ru.ts +++ b/packages/console/app/src/i18n/ru.ts @@ -255,7 +255,7 @@ export const dict = { "go.title": "OpenCode Go | Недорогие модели для кодинга для всех", "go.meta.description": - "Go начинается с $5 за первый месяц, затем $10/месяц, с щедрыми лимитами запросов за 5 часов для GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 и MiniMax M2.7.", + "Go начинается с $5 за первый месяц, затем $10/месяц, с щедрыми лимитами запросов за 5 часов для GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro и DeepSeek V4 Flash.", "go.hero.title": "Недорогие модели для кодинга для всех", "go.hero.body": "Go открывает доступ к агентам-программистам разработчикам по всему миру. Предлагая щедрые лимиты и надежный доступ к наиболее способным моделям с открытым исходным кодом, вы можете создавать проекты с мощными агентами, не беспокоясь о затратах или доступности.", @@ -307,7 +307,7 @@ export const dict = { "go.problem.item2": "Щедрые лимиты и надежный доступ", "go.problem.item3": "Создан для максимального числа программистов", "go.problem.item4": - "Включает GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 и MiniMax M2.7", + "Включает GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro и DeepSeek V4 Flash", "go.how.title": "Как работает Go", "go.how.body": "Go начинается с $5 за первый месяц, затем $10/месяц. Вы можете использовать его с OpenCode или любым агентом.", @@ -333,7 +333,7 @@ export const dict = { "go.faq.a2": "Go включает перечисленные ниже модели с щедрыми лимитами и надежным доступом.", "go.faq.q3": "Go — это то же самое, что и Zen?", "go.faq.a3": - "Нет. Zen - это оплата по мере использования, в то время как Go начинается с $5 за первый месяц, затем $10/месяц, с щедрыми лимитами и надежным доступом к моделям с открытым исходным кодом GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 и MiniMax M2.7.", + "Нет. Zen - это оплата по мере использования, в то время как Go начинается с $5 за первый месяц, затем $10/месяц, с щедрыми лимитами и надежным доступом к моделям с открытым исходным кодом GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro и DeepSeek V4 Flash.", "go.faq.q4": "Сколько стоит Go?", "go.faq.a4.p1.beforePricing": "Go стоит", "go.faq.a4.p1.pricingLink": "$5 за первый месяц", @@ -357,7 +357,7 @@ export const dict = { "go.faq.q9": "В чем разница между бесплатными моделями и Go?", "go.faq.a9": - "Бесплатные модели включают Big Pickle плюс промо-модели, доступные на данный момент, с квотой 200 запросов/день. Go включает GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 и MiniMax M2.7 с более высокими квотами запросов, применяемыми в скользящих окнах (5 часов, неделя и месяц), что примерно эквивалентно $12 за 5 часов, $30 в неделю и $60 в месяц (фактическое количество запросов зависит от модели и использования).", + "Бесплатные модели включают Big Pickle плюс промо-модели, доступные на данный момент, с квотой 200 запросов/день. Go включает GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro и DeepSeek V4 Flash с более высокими квотами запросов, применяемыми в скользящих окнах (5 часов, неделя и месяц), что примерно эквивалентно $12 за 5 часов, $30 в неделю и $60 в месяц (фактическое количество запросов зависит от модели и использования).", "zen.api.error.rateLimitExceeded": "Превышен лимит запросов. Пожалуйста, попробуйте позже.", "zen.api.error.modelNotSupported": "Модель {{model}} не поддерживается", diff --git a/packages/console/app/src/i18n/th.ts b/packages/console/app/src/i18n/th.ts index 3a2dc4ba4c..01b2b19c39 100644 --- a/packages/console/app/src/i18n/th.ts +++ b/packages/console/app/src/i18n/th.ts @@ -250,7 +250,7 @@ export const dict = { "go.title": "OpenCode Go | โมเดลเขียนโค้ดราคาประหยัดสำหรับทุกคน", "go.meta.description": - "Go เริ่มต้นที่ $5 สำหรับเดือนแรก จากนั้น $10/เดือน พร้อมขีดจำกัดคำขอ 5 ชั่วโมงที่เอื้อเฟื้อสำหรับ GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 และ MiniMax M2.7", + "Go เริ่มต้นที่ $5 สำหรับเดือนแรก จากนั้น $10/เดือน พร้อมขีดจำกัดคำขอ 5 ชั่วโมงที่เอื้อเฟื้อสำหรับ GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro และ DeepSeek V4 Flash", "go.hero.title": "โมเดลเขียนโค้ดราคาประหยัดสำหรับทุกคน", "go.hero.body": "Go นำการเขียนโค้ดแบบเอเจนต์มาสู่นักเขียนโปรแกรมทั่วโลก เสนอขีดจำกัดที่กว้างขวางและการเข้าถึงโมเดลโอเพนซอร์สที่มีความสามารถสูงสุดได้อย่างน่าเชื่อถือ เพื่อให้คุณสามารถสร้างสรรค์ด้วยเอเจนต์ที่ทรงพลังโดยไม่ต้องกังวลเรื่องค่าใช้จ่ายหรือความพร้อมใช้งาน", @@ -300,7 +300,7 @@ export const dict = { "go.problem.item2": "ขีดจำกัดที่กว้างขวางและการเข้าถึงที่เชื่อถือได้", "go.problem.item3": "สร้างขึ้นเพื่อโปรแกรมเมอร์จำนวนมากที่สุดเท่าที่จะเป็นไปได้", "go.problem.item4": - "รวมถึง GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 และ MiniMax M2.7", + "รวมถึง GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro และ DeepSeek V4 Flash", "go.how.title": "Go ทำงานอย่างไร", "go.how.body": "Go เริ่มต้นที่ $5 สำหรับเดือนแรก จากนั้น $10/เดือน คุณสามารถใช้กับ OpenCode หรือเอเจนต์ใดก็ได้", "go.how.step1.title": "สร้างบัญชี", @@ -325,7 +325,7 @@ export const dict = { "go.faq.a2": "Go รวมโมเดลด้านล่างนี้ พร้อมขีดจำกัดที่มากและการเข้าถึงที่เชื่อถือได้", "go.faq.q3": "Go เหมือนกับ Zen หรือไม่?", "go.faq.a3": - "ไม่ Zen เป็นแบบจ่ายตามการใช้งาน ในขณะที่ Go เริ่มต้นที่ $5 สำหรับเดือนแรก จากนั้น $10/เดือน พร้อมขีดจำกัดที่เอื้อเฟื้อและการเข้าถึงโมเดลโอเพนซอร์ส GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 และ MiniMax M2.7 อย่างเชื่อถือได้", + "ไม่ Zen เป็นแบบจ่ายตามการใช้งาน ในขณะที่ Go เริ่มต้นที่ $5 สำหรับเดือนแรก จากนั้น $10/เดือน พร้อมขีดจำกัดที่เอื้อเฟื้อและการเข้าถึงโมเดลโอเพนซอร์ส GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro และ DeepSeek V4 Flash อย่างเชื่อถือได้", "go.faq.q4": "Go ราคาเท่าไหร่?", "go.faq.a4.p1.beforePricing": "Go ราคา", "go.faq.a4.p1.pricingLink": "$5 เดือนแรก", @@ -348,7 +348,7 @@ export const dict = { "go.faq.q9": "ความแตกต่างระหว่างโมเดลฟรีและ Go คืออะไร?", "go.faq.a9": - "โมเดลฟรีรวมถึง Big Pickle บวกกับโมเดลโปรโมชั่นที่มีให้ในขณะนั้น ด้วยโควต้า 200 คำขอ/วัน Go รวมถึง GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 และ MiniMax M2.7 ที่มีโควต้าคำขอสูงกว่า ซึ่งบังคับใช้ผ่านช่วงเวลาหมุนเวียน (5 ชั่วโมง, รายสัปดาห์ และรายเดือน) เทียบเท่าประมาณ $12 ต่อ 5 ชั่วโมง, $30 ต่อสัปดาห์ และ $60 ต่อเดือน (จำนวนคำขอจริงจะแตกต่างกันไปตามโมเดลและการใช้งาน)", + "โมเดลฟรีรวมถึง Big Pickle บวกกับโมเดลโปรโมชั่นที่มีให้ในขณะนั้น ด้วยโควต้า 200 คำขอ/วัน Go รวมถึง GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro และ DeepSeek V4 Flash ที่มีโควต้าคำขอสูงกว่า ซึ่งบังคับใช้ผ่านช่วงเวลาหมุนเวียน (5 ชั่วโมง, รายสัปดาห์ และรายเดือน) เทียบเท่าประมาณ $12 ต่อ 5 ชั่วโมง, $30 ต่อสัปดาห์ และ $60 ต่อเดือน (จำนวนคำขอจริงจะแตกต่างกันไปตามโมเดลและการใช้งาน)", "zen.api.error.rateLimitExceeded": "เกินขีดจำกัดอัตราการใช้งาน กรุณาลองใหม่ในภายหลัง", "zen.api.error.modelNotSupported": "ไม่รองรับโมเดล {{model}}", diff --git a/packages/console/app/src/i18n/tr.ts b/packages/console/app/src/i18n/tr.ts index e2370f83c2..0345277b87 100644 --- a/packages/console/app/src/i18n/tr.ts +++ b/packages/console/app/src/i18n/tr.ts @@ -253,7 +253,7 @@ export const dict = { "go.title": "OpenCode Go | Herkes için düşük maliyetli kodlama modelleri", "go.meta.description": - "Go ilk ay $5, sonrasında ayda 10$ fiyatıyla başlar; GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 ve MiniMax M2.7 için cömert 5 saatlik istek limitleri sunar.", + "Go ilk ay $5, sonrasında ayda 10$ fiyatıyla başlar; GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro ve DeepSeek V4 Flash için cömert 5 saatlik istek limitleri sunar.", "go.hero.title": "Herkes için düşük maliyetli kodlama modelleri", "go.hero.body": "Go, dünya çapındaki programcılara ajan tabanlı kodlama getiriyor. En yetenekli açık kaynaklı modellere cömert limitler ve güvenilir erişim sunarak, maliyet veya erişilebilirlik konusunda endişelenmeden güçlü ajanlarla geliştirme yapmanızı sağlar.", @@ -305,7 +305,7 @@ export const dict = { "go.problem.item2": "Cömert limitler ve güvenilir erişim", "go.problem.item3": "Mümkün olduğunca çok programcı için geliştirildi", "go.problem.item4": - "GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 ve MiniMax M2.7 içerir", + "GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro ve DeepSeek V4 Flash içerir", "go.how.title": "Go nasıl çalışır?", "go.how.body": "Go ilk ay $5, sonrasında ayda 10$ fiyatıyla başlar. OpenCode veya herhangi bir ajanla kullanabilirsiniz.", @@ -331,7 +331,7 @@ export const dict = { "go.faq.a2": "Go, aşağıda listelenen modelleri cömert limitler ve güvenilir erişimle sunar.", "go.faq.q3": "Go, Zen ile aynı mı?", "go.faq.a3": - "Hayır. Zen kullandıkça öde modelidir, Go ise ilk ay $5, sonrasında ayda 10$ fiyatıyla başlar; GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 ve MiniMax M2.7 açık kaynak modellerine cömert limitler ve güvenilir erişim sunar.", + "Hayır. Zen kullandıkça öde modelidir, Go ise ilk ay $5, sonrasında ayda 10$ fiyatıyla başlar; GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro ve DeepSeek V4 Flash açık kaynak modellerine cömert limitler ve güvenilir erişim sunar.", "go.faq.q4": "Go ne kadar?", "go.faq.a4.p1.beforePricing": "Go'nun maliyeti", "go.faq.a4.p1.pricingLink": "İlk ay $5", @@ -355,7 +355,7 @@ export const dict = { "go.faq.q9": "Ücretsiz modeller ve Go arasındaki fark nedir?", "go.faq.a9": - "Ücretsiz modeller, günlük 200 istek kotası ile Big Pickle ve o sırada mevcut olan promosyonel modelleri içerir. Go ise GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 ve MiniMax M2.7 modellerini; yuvarlanan pencereler (5 saatlik, haftalık ve aylık) üzerinden uygulanan daha yüksek istek kotalarıyla içerir. Bu kotalar kabaca her 5 saatte 12$, haftada 30$ ve ayda 60$ değerine eşdeğerdir (gerçek istek sayıları modele ve kullanıma göre değişir).", + "Ücretsiz modeller, günlük 200 istek kotası ile Big Pickle ve o sırada mevcut olan promosyonel modelleri içerir. Go ise GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro ve DeepSeek V4 Flash modellerini; yuvarlanan pencereler (5 saatlik, haftalık ve aylık) üzerinden uygulanan daha yüksek istek kotalarıyla içerir. Bu kotalar kabaca her 5 saatte 12$, haftada 30$ ve ayda 60$ değerine eşdeğerdir (gerçek istek sayıları modele ve kullanıma göre değişir).", "zen.api.error.rateLimitExceeded": "İstek limiti aşıldı. Lütfen daha sonra tekrar deneyin.", "zen.api.error.modelNotSupported": "{{model}} modeli desteklenmiyor", diff --git a/packages/console/app/src/i18n/zh.ts b/packages/console/app/src/i18n/zh.ts index 649384c23b..b9300cc87e 100644 --- a/packages/console/app/src/i18n/zh.ts +++ b/packages/console/app/src/i18n/zh.ts @@ -241,7 +241,7 @@ export const dict = { "go.title": "OpenCode Go | 人人可用的低成本编程模型", "go.meta.description": - "Go 首月 $5,之后 $10/月,提供对 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 和 MiniMax M2.7 的 5 小时充裕请求额度。", + "Go 首月 $5,之后 $10/月,提供对 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro 和 DeepSeek V4 Flash 的 5 小时充裕请求额度。", "go.hero.title": "人人可用的低成本编程模型", "go.hero.body": "Go 将代理编程带给全世界的程序员。提供充裕的限额和对最强大的开源模型的可靠访问,让您可以利用强大的代理进行构建,而无需担心成本或可用性。", @@ -291,7 +291,7 @@ export const dict = { "go.problem.item2": "充裕的限额和可靠的访问", "go.problem.item3": "为尽可能多的程序员打造", "go.problem.item4": - "包含 GLM-5.1, GLM-5, Kimi K2.5、Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 和 MiniMax M2.7", + "包含 GLM-5.1, GLM-5, Kimi K2.5、Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro 和 DeepSeek V4 Flash", "go.how.title": "Go 如何工作", "go.how.body": "Go 起价为首月 $5,之后 $10/月。您可以将其与 OpenCode 或任何代理搭配使用。", "go.how.step1.title": "创建账户", @@ -313,7 +313,7 @@ export const dict = { "go.faq.a2": "Go 包含下方列出的模型,提供充足的限额和可靠的访问。", "go.faq.q3": "Go 和 Zen 一样吗?", "go.faq.a3": - "不。Zen 是按量付费,而 Go 首月 $5,之后 $10/月,提供充裕的额度,并可可靠地访问 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 和 MiniMax M2.7 等开源模型。", + "不。Zen 是按量付费,而 Go 首月 $5,之后 $10/月,提供充裕的额度,并可可靠地访问 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro 和 DeepSeek V4 Flash 等开源模型。", "go.faq.q4": "Go 多少钱?", "go.faq.a4.p1.beforePricing": "Go 费用为", "go.faq.a4.p1.pricingLink": "首月 $5", @@ -335,7 +335,7 @@ export const dict = { "go.faq.q9": "免费模型和 Go 之间的区别是什么?", "go.faq.a9": - "免费模型包含 Big Pickle 加上当时可用的促销模型,每天有 200 次请求的配额。Go 包含 GLM-5.1, GLM-5, Kimi K2.5、Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 和 MiniMax M2.7,并在滚动窗口(5 小时、每周和每月)内执行更高的请求配额,大致相当于每 5 小时 $12、每周 $30 和每月 $60(实际请求计数因模型和使用情况而异)。", + "免费模型包含 Big Pickle 加上当时可用的促销模型,每天有 200 次请求的配额。Go 包含 GLM-5.1, GLM-5, Kimi K2.5、Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro 和 DeepSeek V4 Flash,并在滚动窗口(5 小时、每周和每月)内执行更高的请求配额,大致相当于每 5 小时 $12、每周 $30 和每月 $60(实际请求计数因模型和使用情况而异)。", "zen.api.error.rateLimitExceeded": "超出速率限制。请稍后重试。", "zen.api.error.modelNotSupported": "不支持模型 {{model}}", diff --git a/packages/console/app/src/i18n/zht.ts b/packages/console/app/src/i18n/zht.ts index 8e93f989e8..f129a99d02 100644 --- a/packages/console/app/src/i18n/zht.ts +++ b/packages/console/app/src/i18n/zht.ts @@ -241,7 +241,7 @@ export const dict = { "go.title": "OpenCode Go | 低成本全民編碼模型", "go.meta.description": - "Go 首月 $5,之後 $10/月,提供對 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 和 MiniMax M2.7 的 5 小時充裕請求額度。", + "Go 首月 $5,之後 $10/月,提供對 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro 和 DeepSeek V4 Flash 的 5 小時充裕請求額度。", "go.hero.title": "低成本全民編碼模型", "go.hero.body": "Go 將代理編碼帶給全世界的程式設計師。提供寬裕的限額以及對最強大開源模型的穩定存取,讓你可以使用強大的代理進行構建,而無需擔心成本或可用性。", @@ -291,7 +291,7 @@ export const dict = { "go.problem.item2": "寬裕的限額與穩定存取", "go.problem.item3": "專為盡可能多的程式設計師打造", "go.problem.item4": - "包含 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 與 MiniMax M2.7", + "包含 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro 與 DeepSeek V4 Flash", "go.how.title": "Go 如何運作", "go.how.body": "Go 起價為首月 $5,之後 $10/月。您可以將其與 OpenCode 或任何代理搭配使用。", "go.how.step1.title": "建立帳號", @@ -313,7 +313,7 @@ export const dict = { "go.faq.a2": "Go 包含下方列出的模型,提供充足的額度與穩定的存取。", "go.faq.q3": "Go 與 Zen 一樣嗎?", "go.faq.a3": - "不。Zen 是按量付費,而 Go 首月 $5,之後 $10/月,提供充裕的額度,並可可靠地存取 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 和 MiniMax M2.7 等開源模型。", + "不。Zen 是按量付費,而 Go 首月 $5,之後 $10/月,提供充裕的額度,並可可靠地存取 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro 和 DeepSeek V4 Flash 等開源模型。", "go.faq.q4": "Go 費用是多少?", "go.faq.a4.p1.beforePricing": "Go 費用為", "go.faq.a4.p1.pricingLink": "首月 $5", @@ -335,7 +335,7 @@ export const dict = { "go.faq.q9": "免費模型與 Go 有什麼區別?", "go.faq.a9": - "免費模型包括 Big Pickle 以及當時可用的促銷模型,配額為 200 次請求/天。Go 包括 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5 與 MiniMax M2.7,並在滾動視窗(5 小時、每週和每月)內執行更高的請求配額,大約相當於每 5 小時 $12、每週 $30 和每月 $60(實際請求數因模型和使用情況而異)。", + "免費模型包括 Big Pickle 以及當時可用的促銷模型,配額為 200 次請求/天。Go 包括 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro 與 DeepSeek V4 Flash,並在滾動視窗(5 小時、每週和每月)內執行更高的請求配額,大約相當於每 5 小時 $12、每週 $30 和每月 $60(實際請求數因模型和使用情況而異)。", "zen.api.error.rateLimitExceeded": "超出頻率限制。請稍後再試。", "zen.api.error.modelNotSupported": "不支援模型 {{model}}", diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index bfaf2969bc..2b169fd500 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -23,8 +23,8 @@ const checkLoggedIn = query(async () => { }, "checkLoggedIn.get") const models = [ - { name: "GLM-5.1", provider: "DeepInfra, Z.ai" }, - { name: "GLM-5", provider: "DeepInfra, Z.ai" }, + { name: "GLM-5.1", provider: "DeepInfra, Fireworks AI, Z.ai" }, + { name: "GLM-5", provider: "DeepInfra, Fireworks AI, Z.ai" }, { name: "Kimi K2.5", provider: "Moonshot AI" }, { name: "Kimi K2.6", provider: "Moonshot AI" }, { name: "MiMo-V2-Pro", provider: "Xiaomi MiMo" }, @@ -35,6 +35,8 @@ const models = [ { name: "Qwen3.6 Plus", provider: "Alibaba Cloud Model Studio" }, { name: "MiniMax M2.7", provider: "MiniMax" }, { name: "MiniMax M2.5", provider: "MiniMax" }, + { name: "DeepSeek V4 Pro", provider: "DeepSeek" }, + { name: "DeepSeek V4 Flash", provider: "DeepSeek" }, ] function LimitsGraph(props: { href: string }) { @@ -63,13 +65,15 @@ function LimitsGraph(props: { href: string }) { { id: "glm-5.1", name: "GLM-5.1", req: 880, d: "100ms" }, { id: "kimi-k2.6", name: "Kimi K2.6 (3x usage)", req: 3450, baseReq: 1150, d: "150ms" }, { id: "mimo-v2.5-pro", name: "MiMo-V2.5-Pro", req: 1290, d: "150ms" }, + { id: "deepseek-v4-pro", name: "DeepSeek V4 Pro", req: 1300, d: "200ms" }, { id: "qwen3.6-plus", name: "Qwen3.6 Plus", req: 3300, d: "280ms" }, { id: "minimax-m2.7", name: "MiniMax M2.7", req: 3400, d: "300ms" }, + { id: "deepseek-v4-flash", name: "DeepSeek V4 Flash", req: 7450, d: "340ms" }, { id: "qwen3.5-plus", name: "Qwen3.5 Plus", req: 10200, d: "360ms" }, ] const w = 720 - const h = 270 + const h = 330 const left = 40 const right = 60 const top = 18 @@ -103,7 +107,7 @@ function LimitsGraph(props: { href: string }) { })() const shown = ticks.filter((t) => labels.has(t)) const bh = 8 - const gap = 16 + const gap = 20 const step = bh + gap const sep = bh + 40 const fy = top + 22 diff --git a/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx b/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx index abd417e06b..0df181ae16 100644 --- a/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx @@ -297,6 +297,8 @@ export function LiteSection() {
  • MiniMax M2.7
  • Qwen3.5 Plus
  • Qwen3.6 Plus
  • +
  • DeepSeek V4 Pro
  • +
  • DeepSeek V4 Flash
  • {i18n.t("workspace.lite.promo.footer")}

    diff --git a/packages/web/src/content/docs/ar/go.mdx b/packages/web/src/content/docs/ar/go.mdx index 785ea35b66..407c915916 100644 --- a/packages/web/src/content/docs/ar/go.mdx +++ b/packages/web/src/content/docs/ar/go.mdx @@ -65,6 +65,8 @@ OpenCode Go حاليًا في المرحلة التجريبية. - **Qwen3.5 Plus** - **Qwen3.6 Plus** - **MiniMax M2.7** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** قد تتغير قائمة النماذج مع استمرارنا في اختبار نماذج جديدة وإضافتها. @@ -82,25 +84,28 @@ OpenCode Go حاليًا في المرحلة التجريبية. يوضح الجدول أدناه عددًا تقديريًا للطلبات بناءً على أنماط استخدام Go المعتادة: -| Model | الطلبات لكل 5 ساعات | الطلبات في الأسبوع | الطلبات في الشهر | -| ------------- | ------------------- | ------------------ | ---------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | الطلبات لكل 5 ساعات | الطلبات في الأسبوع | الطلبات في الشهر | +| --------------- | ------------------- | ------------------ | ---------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | تستند التقديرات إلى متوسطات أنماط الطلبات المرصودة: - GLM-5/5.1 — ‏700 input، و52,000 cached، و150 output tokens لكل طلب - Kimi K2.5/K2.6 — ‏870 input، و55,000 cached، و200 output tokens لكل طلب +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiniMax M2.7/M2.5 — ‏300 input، و55,000 cached، و125 output tokens لكل طلب - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -129,20 +134,22 @@ OpenCode Go حاليًا في المرحلة التجريبية. يمكنك أيضًا الوصول إلى نماذج Go عبر نقاط نهاية API التالية. -| Model | Model ID | Endpoint | AI SDK Package | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Model | Model ID | Endpoint | AI SDK Package | +| --------------- | --------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | يستخدم [model id](/docs/config/#models) في إعدادات OpenCode لديك التنسيق `opencode-go/`. على سبيل المثال، بالنسبة إلى Kimi K2.6، ستستخدم `opencode-go/kimi-k2.6` في إعداداتك. diff --git a/packages/web/src/content/docs/bs/go.mdx b/packages/web/src/content/docs/bs/go.mdx index 523f1ef8ed..a3f71ef14b 100644 --- a/packages/web/src/content/docs/bs/go.mdx +++ b/packages/web/src/content/docs/bs/go.mdx @@ -75,6 +75,8 @@ Trenutna lista modela uključuje: - **Qwen3.5 Plus** - **Qwen3.6 Plus** - **MiniMax M2.7** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** Lista modela se može mijenjati dok testiramo i dodajemo nove. @@ -92,25 +94,28 @@ Ograničenja su definisana u dolarskoj vrijednosti. To znači da vaš stvarni br Tabela ispod pruža procijenjeni broj zahtjeva na osnovu tipičnih obrazaca korištenja Go pretplate: -| Model | zahtjeva na 5 sati | zahtjeva sedmično | zahtjeva mjesečno | -| ------------- | ------------------ | ----------------- | ----------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | zahtjeva na 5 sati | zahtjeva sedmično | zahtjeva mjesečno | +| --------------- | ------------------ | ----------------- | ----------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Procjene se zasnivaju na zapaženim prosječnim obrascima zahtjeva: - GLM-5/5.1 — 700 ulaznih (input), 52,000 keširanih, 150 izlaznih (output) tokena po zahtjevu - Kimi K2.5/K2.6 — 870 ulaznih, 55,000 keširanih, 200 izlaznih tokena po zahtjevu +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiniMax M2.7/M2.5 — 300 ulaznih, 55,000 keširanih, 125 izlaznih tokena po zahtjevu - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -141,20 +146,22 @@ nakon što dostignete ograničenja upotrebe umjesto blokiranja zahtjeva. Također možete pristupiti Go modelima putem sljedećih API endpointa. -| Model | Model ID | Endpoint | AI SDK Paket | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Model | Model ID | Endpoint | AI SDK Paket | +| --------------- | --------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | [Model id](/docs/config/#models) u vašoj OpenCode konfiguraciji koristi format `opencode-go/`. Na primjer, za Kimi K2.6, koristili biste diff --git a/packages/web/src/content/docs/da/go.mdx b/packages/web/src/content/docs/da/go.mdx index 86a834b984..947c613331 100644 --- a/packages/web/src/content/docs/da/go.mdx +++ b/packages/web/src/content/docs/da/go.mdx @@ -75,6 +75,8 @@ Den nuværende liste over modeller inkluderer: - **Qwen3.5 Plus** - **Qwen3.6 Plus** - **MiniMax M2.7** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** Listen over modeller kan ændre sig, efterhånden som vi tester og tilføjer nye. @@ -92,25 +94,28 @@ Grænserne er defineret i dollarværdi. Det betyder, at dit faktiske antal anmod Tabellen nedenfor giver et estimeret antal anmodninger baseret på typiske Go-forbrugsmønstre: -| Model | anmodninger pr. 5 timer | anmodninger pr. uge | anmodninger pr. måned | -| ------------- | ----------------------- | ------------------- | --------------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | anmodninger pr. 5 timer | anmodninger pr. uge | anmodninger pr. måned | +| ----------------- | ----------------------- | ------------------- | --------------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Estimaterne er baseret på observerede gennemsnitlige anmodningsmønstre: - GLM-5/5.1 — 700 input, 52.000 cachelagrede, 150 output-tokens pr. anmodning - Kimi K2.5/K2.6 — 870 input, 55.000 cachelagrede, 200 output-tokens pr. anmodning +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiniMax M2.7/M2.5 — 300 input, 55.000 cachelagrede, 125 output-tokens pr. anmodning - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -141,20 +146,22 @@ når du har nået dine forbrugsgrænser, i stedet for at blokere anmodninger. Du kan også få adgang til Go-modeller gennem følgende API-endpoints. -| Model | Model ID | Endpoint | AI SDK Package | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Model | Model ID | Endpoint | AI SDK Package | +| ----------------- | --------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | Dit [model id](/docs/config/#models) i din OpenCode config bruger formatet `opencode-go/`. For eksempel for Kimi K2.6, vil du diff --git a/packages/web/src/content/docs/de/go.mdx b/packages/web/src/content/docs/de/go.mdx index 49c0efda58..d78df0195f 100644 --- a/packages/web/src/content/docs/de/go.mdx +++ b/packages/web/src/content/docs/de/go.mdx @@ -67,6 +67,8 @@ Die aktuelle Liste der Modelle umfasst: - **Qwen3.5 Plus** - **Qwen3.6 Plus** - **MiniMax M2.7** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** Die Liste der Modelle kann sich ändern, während wir neue testen und hinzufügen. @@ -84,25 +86,28 @@ Limits sind in Dollarwerten definiert. Das bedeutet, dass die tatsächliche Anza Die folgende Tabelle zeigt eine geschätzte Anzahl von Anfragen basierend auf typischen Go-Nutzungsmustern: -| Model | Anfragen pro 5 Stunden | Anfragen pro Woche | Anfragen pro Monat | -| ------------- | ---------------------- | ------------------ | ------------------ | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | Anfragen pro 5 Stunden | Anfragen pro Woche | Anfragen pro Monat | +| --------------- | ---------------------- | ------------------ | ------------------ | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Die Schätzungen basieren auf beobachteten durchschnittlichen Anfragemustern: - GLM-5/5.1 — 700 Input-, 52.000 Cached-, 150 Output-Tokens pro Anfrage - Kimi K2.5/K2.6 — 870 Input-, 55.000 Cached-, 200 Output-Tokens pro Anfrage +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiniMax M2.7/M2.5 — 300 Input-, 55.000 Cached-, 125 Output-Tokens pro Anfrage - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -131,20 +136,22 @@ Wenn du auch Guthaben auf deinem Zen-Konto hast, kannst du in der Console die Op Du kannst auf die Go-Modelle auch über die folgenden API-Endpunkte zugreifen. -| Modell | Modell-ID | Endpunkt | AI SDK Package | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Modell | Modell-ID | Endpunkt | AI SDK Package | +| --------------- | --------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | Die [Modell-ID](/docs/config/#models) in deiner OpenCode Config verwendet das Format `opencode-go/`. Für Kimi K2.6 würdest du beispielsweise `opencode-go/kimi-k2.6` in deiner Config verwenden. diff --git a/packages/web/src/content/docs/es/go.mdx b/packages/web/src/content/docs/es/go.mdx index a541171caf..6d01cfd7fe 100644 --- a/packages/web/src/content/docs/es/go.mdx +++ b/packages/web/src/content/docs/es/go.mdx @@ -75,6 +75,8 @@ La lista actual de modelos incluye: - **Qwen3.5 Plus** - **Qwen3.6 Plus** - **MiniMax M2.7** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** La lista de modelos puede cambiar a medida que probamos y agregamos otros nuevos. @@ -92,25 +94,28 @@ Los límites se definen en valor en dólares. Esto significa que tu cantidad rea La siguiente tabla proporciona una cantidad estimada de peticiones basada en los patrones típicos de uso de Go: -| Model | peticiones por 5 horas | peticiones por semana | peticiones por mes | -| ------------- | ---------------------- | --------------------- | ------------------ | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | peticiones por 5 horas | peticiones por semana | peticiones por mes | +| --------------- | ---------------------- | --------------------- | ------------------ | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Las estimaciones se basan en los patrones de peticiones promedio observados: - GLM-5/5.1 — 700 tokens de entrada, 52,000 en caché, 150 tokens de salida por petición - Kimi K2.5/K2.6 — 870 tokens de entrada, 55,000 en caché, 200 tokens de salida por petición +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiniMax M2.7/M2.5 — 300 tokens de entrada, 55,000 en caché, 125 tokens de salida por petición - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -141,20 +146,22 @@ después de que hayas alcanzado tus límites de uso en lugar de bloquear las pet También puedes acceder a los modelos de Go a través de los siguientes endpoints de la API. -| Modelo | ID del modelo | Endpoint | Paquete de AI SDK | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Modelo | ID del modelo | Endpoint | Paquete de AI SDK | +| --------------- | --------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | El [ID del modelo](/docs/config/#models) en tu configuración de OpenCode usa el formato `opencode-go/`. Por ejemplo, para Kimi K2.6, usarías diff --git a/packages/web/src/content/docs/fr/go.mdx b/packages/web/src/content/docs/fr/go.mdx index 5f55128ed4..c4d70e610b 100644 --- a/packages/web/src/content/docs/fr/go.mdx +++ b/packages/web/src/content/docs/fr/go.mdx @@ -65,6 +65,8 @@ La liste actuelle des modèles comprend : - **Qwen3.5 Plus** - **Qwen3.6 Plus** - **MiniMax M2.7** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** La liste des modèles peut changer au fur et à mesure que nous en testons et en ajoutons de nouveaux. @@ -82,25 +84,28 @@ Les limites sont définies en valeur monétaire (dollars). Cela signifie que vot Le tableau ci-dessous fournit une estimation du nombre de requêtes basée sur des modèles d'utilisation typiques de Go : -| Model | requêtes par 5 heures | requêtes par semaine | requêtes par mois | -| ------------- | --------------------- | -------------------- | ----------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | requêtes par 5 heures | requêtes par semaine | requêtes par mois | +| --------------- | --------------------- | -------------------- | ----------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Les estimations sont basées sur les modèles de requêtes moyens observés : - GLM-5/5.1 — 700 tokens en entrée, 52,000 en cache, 150 tokens en sortie par requête - Kimi K2.5/K2.6 — 870 tokens en entrée, 55,000 en cache, 200 tokens en sortie par requête +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiniMax M2.7/M2.5 — 300 tokens en entrée, 55,000 en cache, 125 tokens en sortie par requête - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -129,20 +134,22 @@ Si vous avez également des crédits sur votre solde Zen, vous pouvez activer l' Vous pouvez également accéder aux modèles Go via les points de terminaison d'API suivants. -| Modèle | ID de modèle | Point de terminaison | Package AI SDK | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Modèle | ID de modèle | Point de terminaison | Package AI SDK | +| --------------- | --------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | L'[ID de modèle](/docs/config/#models) dans votre configuration OpenCode utilise le format `opencode-go/`. Par exemple, pour Kimi K2.6, vous utiliseriez `opencode-go/kimi-k2.6` dans votre configuration. diff --git a/packages/web/src/content/docs/go.mdx b/packages/web/src/content/docs/go.mdx index 946c70de30..9db12a644c 100644 --- a/packages/web/src/content/docs/go.mdx +++ b/packages/web/src/content/docs/go.mdx @@ -75,6 +75,8 @@ The current list of models includes: - **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** The list of models may change as we test and add new ones. @@ -92,25 +94,28 @@ Limits are defined in dollar value. This means your actual request count depends The table below provides an estimated request count based on typical Go usage patterns: -| Model | requests per 5 hour | requests per week | requests per month | -| ------------- | ------------------- | ----------------- | ------------------ | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | requests per 5 hour | requests per week | requests per month | +| ----------------- | ------------------- | ----------------- | ------------------ | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Estimates are based on observed average request patterns: - GLM-5/5.1 — 700 input, 52,000 cached, 150 output tokens per request - Kimi K2.5/K2.6 — 870 input, 55,000 cached, 200 output tokens per request +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiniMax M2.7/M2.5 — 300 input, 55,000 cached, 125 output tokens per request - MiMo-V2-Pro — 350 input, 41,000 cached, 250 output tokens per request - MiMo-V2-Omni — 1000 input, 60,000 cached, 140 output tokens per request @@ -141,20 +146,22 @@ after you've reached your usage limits instead of blocking requests. You can also access Go models through the following API endpoints. -| Model | Model ID | Endpoint | AI SDK Package | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Model | Model ID | Endpoint | AI SDK Package | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | The [model id](/docs/config/#models) in your OpenCode config uses the format `opencode-go/`. For example, for Kimi K2.6, you would diff --git a/packages/web/src/content/docs/it/go.mdx b/packages/web/src/content/docs/it/go.mdx index 341a22c4cb..216362ed4a 100644 --- a/packages/web/src/content/docs/it/go.mdx +++ b/packages/web/src/content/docs/it/go.mdx @@ -73,6 +73,8 @@ L'elenco attuale dei modelli include: - **Qwen3.5 Plus** - **Qwen3.6 Plus** - **MiniMax M2.7** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** L'elenco dei modelli potrebbe cambiare man mano che ne testiamo e aggiungiamo di nuovi. @@ -90,25 +92,28 @@ I limiti sono definiti in valore in dollari. Questo significa che il conteggio e La tabella seguente fornisce una stima del conteggio delle richieste in base a pattern di utilizzo tipici di Go: -| Model | richieste ogni 5 ore | richieste a settimana | richieste al mese | -| ------------- | -------------------- | --------------------- | ----------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | richieste ogni 5 ore | richieste a settimana | richieste al mese | +| --------------- | -------------------- | --------------------- | ----------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Le stime si basano sui pattern medi di richieste osservati: - GLM-5/5.1 — 700 di input, 52.000 in cache, 150 token di output per richiesta - Kimi K2.5/K2.6 — 870 di input, 55.000 in cache, 200 token di output per richiesta +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiniMax M2.7/M2.5 — 300 di input, 55.000 in cache, 125 token di output per richiesta - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -139,20 +144,22 @@ dopo che avrai raggiunto i limiti di utilizzo invece di bloccare le richieste. Puoi anche accedere ai modelli Go tramite i seguenti endpoint API. -| Modello | ID Modello | Endpoint | Pacchetto AI SDK | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Modello | ID Modello | Endpoint | Pacchetto AI SDK | +| --------------- | --------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | Il [model id](/docs/config/#models) nella tua OpenCode config utilizza il formato `opencode-go/`. Ad esempio, per Kimi K2.6, useresti diff --git a/packages/web/src/content/docs/ja/go.mdx b/packages/web/src/content/docs/ja/go.mdx index ddd5a66803..3886a827ae 100644 --- a/packages/web/src/content/docs/ja/go.mdx +++ b/packages/web/src/content/docs/ja/go.mdx @@ -65,6 +65,8 @@ OpenCode Goをサブスクライブできるのは、1つのワークスペー - **Qwen3.5 Plus** - **Qwen3.6 Plus** - **MiniMax M2.7** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** 新しいモデルをテストして追加するにつれて、モデルのリストは変更される場合があります。 @@ -82,25 +84,28 @@ OpenCode Goには以下の制限が含まれています: 以下の表は、一般的なGoの利用パターンに基づいた推定リクエスト数を示しています: -| Model | 5時間あたりのリクエスト数 | 週間リクエスト数 | 月間リクエスト数 | -| ------------- | ------------------------- | ---------------- | ---------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | 5時間あたりのリクエスト数 | 週間リクエスト数 | 月間リクエスト数 | +| --------------- | ------------------------- | ---------------- | ---------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | 推定値は、観測された平均的なリクエストパターンに基づいています: - GLM-5/5.1 — リクエストあたり 入力 700トークン、キャッシュ 52,000トークン、出力 150トークン - Kimi K2.5/K2.6 — リクエストあたり 入力 870トークン、キャッシュ 55,000トークン、出力 200トークン +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiniMax M2.7/M2.5 — リクエストあたり 入力 300トークン、キャッシュ 55,000トークン、出力 125トークン - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -129,20 +134,22 @@ Zen残高にクレジットがある場合は、コンソールで**Use balance* 以下のAPIエンドポイントを通じて、Goモデルにアクセスすることもできます。 -| Model | Model ID | Endpoint | AI SDK Package | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Model | Model ID | Endpoint | AI SDK Package | +| --------------- | --------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | OpenCode設定の[model id](/docs/config/#models)は、`opencode-go/`という形式を使用します。たとえば、Kimi K2.6の場合は、設定で`opencode-go/kimi-k2.6`を使用します。 diff --git a/packages/web/src/content/docs/ko/go.mdx b/packages/web/src/content/docs/ko/go.mdx index da787040fb..c0fbc62bd2 100644 --- a/packages/web/src/content/docs/ko/go.mdx +++ b/packages/web/src/content/docs/ko/go.mdx @@ -65,6 +65,8 @@ workspace당 한 명의 멤버만 OpenCode Go를 구독할 수 있습니다. - **Qwen3.5 Plus** - **Qwen3.6 Plus** - **MiniMax M2.7** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** 새로운 모델을 테스트하고 추가함에 따라 이 목록은 변경될 수 있습니다. @@ -82,25 +84,28 @@ OpenCode Go에는 다음과 같은 한도가 포함됩니다. 아래 표는 일반적인 Go 사용 패턴을 기준으로 한 예상 요청 횟수를 보여줍니다. -| Model | 5시간당 요청 횟수 | 주간 요청 횟수 | 월간 요청 횟수 | -| ------------- | ----------------- | -------------- | -------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | 5시간당 요청 횟수 | 주간 요청 횟수 | 월간 요청 횟수 | +| --------------- | ----------------- | -------------- | -------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | 예상치는 관찰된 평균 요청 패턴을 기준으로 합니다. - GLM-5/5.1 — 요청당 입력 700, 캐시 52,000, 출력 토큰 150 - Kimi K2.5/K2.6 — 요청당 입력 870, 캐시 55,000, 출력 토큰 200 +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiniMax M2.7/M2.5 — 요청당 입력 300, 캐시 55,000, 출력 토큰 125 - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -129,20 +134,22 @@ Zen 잔액에 크레딧도 있다면, console에서 **Use balance** 옵션을 다음 API 엔드포인트를 통해서도 Go 모델에 액세스할 수 있습니다. -| 모델 | 모델 ID | 엔드포인트 | AI SDK 패키지 | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| 모델 | 모델 ID | 엔드포인트 | AI SDK 패키지 | +| --------------- | -------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | OpenCode config의 [model id](/docs/config/#models)는 `opencode-go/` 형식을 사용합니다. 예를 들어 Kimi K2.6의 경우 config에서 `opencode-go/kimi-k2.6`를 사용하면 됩니다. diff --git a/packages/web/src/content/docs/nb/go.mdx b/packages/web/src/content/docs/nb/go.mdx index 95c05417cf..0cae0c57f6 100644 --- a/packages/web/src/content/docs/nb/go.mdx +++ b/packages/web/src/content/docs/nb/go.mdx @@ -75,6 +75,8 @@ Den nåværende listen over modeller inkluderer: - **Qwen3.5 Plus** - **Qwen3.6 Plus** - **MiniMax M2.7** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** Listen over modeller kan endres etter hvert som vi tester og legger til nye. @@ -92,25 +94,28 @@ Grensene er definert i dollarverdi. Dette betyr at ditt faktiske antall forespø Tabellen nedenfor gir et estimert antall forespørsler basert på typiske bruksmønstre for Go: -| Model | forespørsler per 5 timer | forespørsler per uke | forespørsler per måned | -| ------------- | ------------------------ | -------------------- | ---------------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | forespørsler per 5 timer | forespørsler per uke | forespørsler per måned | +| --------------- | ------------------------ | -------------------- | ---------------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Estimatene er basert på observerte gjennomsnittlige forespørselsmønstre: - GLM-5/5.1 — 700 input, 52 000 bufret, 150 output-tokens per forespørsel - Kimi K2.5/K2.6 — 870 input, 55 000 bufret, 200 output-tokens per forespørsel +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiniMax M2.7/M2.5 — 300 input, 55 000 bufret, 125 output-tokens per forespørsel - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -141,20 +146,22 @@ etter at du har nådd bruksgrensene dine, i stedet for å blokkere forespørsler Du kan også få tilgang til Go-modeller gjennom følgende API-endepunkter. -| Modell | Modell-ID | Endepunkt | AI SDK Package | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Modell | Modell-ID | Endepunkt | AI SDK Package | +| --------------- | --------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | [Modell-ID-en](/docs/config/#models) i din OpenCode-konfigurasjon bruker formatet `opencode-go/`. For eksempel, for Kimi K2.6, vil du diff --git a/packages/web/src/content/docs/pl/go.mdx b/packages/web/src/content/docs/pl/go.mdx index 9ae3ea34b8..c64075a3b7 100644 --- a/packages/web/src/content/docs/pl/go.mdx +++ b/packages/web/src/content/docs/pl/go.mdx @@ -69,6 +69,8 @@ Obecna lista modeli obejmuje: - **Qwen3.5 Plus** - **Qwen3.6 Plus** - **MiniMax M2.7** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** Lista modeli może ulec zmianie w miarę testowania i dodawania nowych. @@ -86,25 +88,28 @@ Limity są zdefiniowane w wartości w dolarach. Oznacza to, że rzeczywista licz Poniższa tabela przedstawia szacunkową liczbę żądań na podstawie typowych wzorców korzystania z Go: -| Model | żądania na 5 godzin | żądania na tydzień | żądania na miesiąc | -| ------------- | ------------------- | ------------------ | ------------------ | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | żądania na 5 godzin | żądania na tydzień | żądania na miesiąc | +| --------------- | ------------------- | ------------------ | ------------------ | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Szacunki opierają się na zaobserwowanych średnich wzorcach żądań: - GLM-5/5.1 — 700 tokenów wejściowych, 52 000 w pamięci podręcznej, 150 tokenów wyjściowych na żądanie - Kimi K2.5/K2.6 — 870 tokenów wejściowych, 55 000 w pamięci podręcznej, 200 tokenów wyjściowych na żądanie +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiniMax M2.7/M2.5 — 300 tokenów wejściowych, 55 000 w pamięci podręcznej, 125 tokenów wyjściowych na żądanie - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -133,20 +138,22 @@ Jeśli masz również środki na swoim saldzie Zen, możesz włączyć opcję ** Możesz również uzyskać dostęp do modeli Go za pośrednictwem następujących punktów końcowych API. -| Model | ID modelu | Punkt końcowy | Pakiet AI SDK | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Model | ID modelu | Punkt końcowy | Pakiet AI SDK | +| --------------- | --------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | [ID modelu](/docs/config/#models) w Twojej konfiguracji OpenCode używa formatu `opencode-go/`. Na przykład dla Kimi K2.6 należy użyć diff --git a/packages/web/src/content/docs/pt-br/go.mdx b/packages/web/src/content/docs/pt-br/go.mdx index 7d4d90ed51..4a454c93e7 100644 --- a/packages/web/src/content/docs/pt-br/go.mdx +++ b/packages/web/src/content/docs/pt-br/go.mdx @@ -75,6 +75,8 @@ A lista atual de modelos inclui: - **Qwen3.5 Plus** - **Qwen3.6 Plus** - **MiniMax M2.7** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** A lista de modelos pode mudar conforme testamos e adicionamos novos. @@ -92,25 +94,28 @@ Os limites são definidos em valor em dólares. Isso significa que a sua contage A tabela abaixo fornece uma contagem estimada de requisições com base nos padrões típicos de uso do Go: -| Model | requisições por 5 horas | requisições por semana | requisições por mês | -| ------------- | ----------------------- | ---------------------- | ------------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | requisições por 5 horas | requisições por semana | requisições por mês | +| --------------- | ----------------------- | ---------------------- | ------------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | As estimativas baseiam-se nos padrões médios de requisições observados: - GLM-5/5.1 — 700 tokens de entrada, 52.000 em cache, 150 tokens de saída por requisição - Kimi K2.5/K2.6 — 870 tokens de entrada, 55.000 em cache, 200 tokens de saída por requisição +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiniMax M2.7/M2.5 — 300 tokens de entrada, 55.000 em cache, 125 tokens de saída por requisição - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -141,20 +146,22 @@ após você atingir os seus limites de uso em vez de bloquear as requisições. Você também pode acessar os modelos do Go através dos seguintes endpoints de API. -| Modelo | ID do Modelo | Endpoint | Pacote do AI SDK | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Modelo | ID do Modelo | Endpoint | Pacote do AI SDK | +| --------------- | --------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | O [ID do modelo](/docs/config/#models) na sua configuração do OpenCode usa o formato `opencode-go/`. Por exemplo, para o Kimi K2.6, você usaria diff --git a/packages/web/src/content/docs/ru/go.mdx b/packages/web/src/content/docs/ru/go.mdx index a8d33f296d..2656d3659c 100644 --- a/packages/web/src/content/docs/ru/go.mdx +++ b/packages/web/src/content/docs/ru/go.mdx @@ -75,6 +75,8 @@ OpenCode Go работает так же, как и любой другой пр - **Qwen3.5 Plus** - **Qwen3.6 Plus** - **MiniMax M2.7** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** Список моделей может меняться по мере того, как мы тестируем и добавляем новые. @@ -92,25 +94,28 @@ OpenCode Go включает следующие лимиты: В таблице ниже приведено примерное количество запросов на основе типичных сценариев использования Go: -| Model | запросов за 5 часов | запросов в неделю | запросов в месяц | -| ------------- | ------------------- | ----------------- | ---------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | запросов за 5 часов | запросов в неделю | запросов в месяц | +| --------------- | ------------------- | ----------------- | ---------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Оценки основаны на наблюдаемых средних показателях запросов: - GLM-5/5.1 — 700 входных, 52,000 кешированных, 150 выходных токенов на запрос - Kimi K2.5/K2.6 — 870 входных, 55,000 кешированных, 200 выходных токенов на запрос +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiniMax M2.7/M2.5 — 300 входных, 55,000 кешированных, 125 выходных токенов на запрос - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -141,20 +146,22 @@ OpenCode Go включает следующие лимиты: Вы также можете получить доступ к моделям Go через следующие API-эндпоинты. -| Модель | ID модели | Эндпоинт | Пакет AI SDK | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Модель | ID модели | Эндпоинт | Пакет AI SDK | +| --------------- | --------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | [ID модели](/docs/config/#models) в вашем конфиге OpenCode использует формат `opencode-go/`. Например, для Kimi K2.6 вам нужно diff --git a/packages/web/src/content/docs/th/go.mdx b/packages/web/src/content/docs/th/go.mdx index fb0262c958..04d999159a 100644 --- a/packages/web/src/content/docs/th/go.mdx +++ b/packages/web/src/content/docs/th/go.mdx @@ -65,6 +65,8 @@ OpenCode Go ทำงานเหมือนกับผู้ให้บร - **Qwen3.5 Plus** - **Qwen3.6 Plus** - **MiniMax M2.7** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** รายชื่อโมเดลอาจมีการเปลี่ยนแปลงเมื่อเราทำการทดสอบและเพิ่มโมเดลใหม่ๆ @@ -82,25 +84,28 @@ OpenCode Go มีขีดจำกัดดังต่อไปนี้: ตารางด้านล่างแสดงจำนวน request โดยประมาณตามรูปแบบการใช้งานปกติของ Go: -| Model | requests ต่อ 5 ชั่วโมง | requests ต่อสัปดาห์ | requests ต่อเดือน | -| ------------- | ---------------------- | ------------------- | ----------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | requests ต่อ 5 ชั่วโมง | requests ต่อสัปดาห์ | requests ต่อเดือน | +| ------------------- | ---------------------- | ------------------- | ----------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | การประมาณการอ้างอิงจากรูปแบบการใช้งาน request โดยเฉลี่ยที่สังเกตพบ: - GLM-5/5.1 — 700 input, 52,000 cached, 150 output tokens ต่อ request - Kimi K2.5/K2.6 — 870 input, 55,000 cached, 200 output tokens ต่อ request +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiniMax M2.7/M2.5 — 300 input, 55,000 cached, 125 output tokens ต่อ request - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -129,20 +134,22 @@ OpenCode Go มีขีดจำกัดดังต่อไปนี้: คุณสามารถเข้าถึงโมเดลของ Go ผ่าน API endpoints ต่อไปนี้ได้เช่นกัน -| Model | Model ID | Endpoint | AI SDK Package | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Model | Model ID | Endpoint | AI SDK Package | +| ------------------- | --------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | [model id](/docs/config/#models) ใน OpenCode config ของคุณจะใช้รูปแบบ `opencode-go/` ตัวอย่างเช่น สำหรับ Kimi K2.6 คุณจะใช้ `opencode-go/kimi-k2.6` ใน config ของคุณ diff --git a/packages/web/src/content/docs/tr/go.mdx b/packages/web/src/content/docs/tr/go.mdx index 96a1ca3e2f..66556701a5 100644 --- a/packages/web/src/content/docs/tr/go.mdx +++ b/packages/web/src/content/docs/tr/go.mdx @@ -65,6 +65,8 @@ Mevcut model listesi şunları içerir: - **Qwen3.5 Plus** - **Qwen3.6 Plus** - **MiniMax M2.7** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** Test edip yenilerini ekledikçe model listesi değişebilir. @@ -82,25 +84,28 @@ Limitler dolar değeri üzerinden belirlenmiştir. Bu, gerçek istek sayınızı Aşağıdaki tablo, tipik Go kullanım modellerine dayalı tahmini bir istek sayısı sunmaktadır: -| Model | 5 saatte bir istek | haftalık istek | aylık istek | -| ------------- | ------------------ | -------------- | ----------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | 5 saatte bir istek | haftalık istek | aylık istek | +| --------------- | ------------------ | -------------- | ----------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Tahminler, gözlemlenen ortalama istek modellerine dayanmaktadır: - GLM-5/5.1 — İstek başına 700 girdi, 52.000 önbelleğe alınmış, 150 çıktı token'ı - Kimi K2.5/K2.6 — İstek başına 870 girdi, 55.000 önbelleğe alınmış, 200 çıktı token'ı +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiniMax M2.7/M2.5 — İstek başına 300 girdi, 55.000 önbelleğe alınmış, 125 çıktı token'ı - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -129,20 +134,22 @@ Eğer Zen bakiyenizde kredileriniz varsa, konsoldan **Bakiye kullan (Use balance Go modellerine aşağıdaki API uç noktaları aracılığıyla da erişebilirsiniz. -| Model | Model ID | Uç Nokta | AI SDK Paketi | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Model | Model ID | Uç Nokta | AI SDK Paketi | +| --------------- | --------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | OpenCode yapılandırmanızdaki [model id](/docs/config/#models) formatı `opencode-go/` şeklindedir. Örneğin, Kimi K2.6 için yapılandırmanızda `opencode-go/kimi-k2.6` kullanmalısınız. diff --git a/packages/web/src/content/docs/zh-cn/go.mdx b/packages/web/src/content/docs/zh-cn/go.mdx index f52f5b572e..47caa95588 100644 --- a/packages/web/src/content/docs/zh-cn/go.mdx +++ b/packages/web/src/content/docs/zh-cn/go.mdx @@ -65,6 +65,8 @@ OpenCode Go 的工作方式与 OpenCode 中的其他提供商一样。 - **Qwen3.5 Plus** - **Qwen3.6 Plus** - **MiniMax M2.7** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** 随着我们进行测试和添加新模型,该列表可能会发生变化。 @@ -82,25 +84,28 @@ OpenCode Go 包含以下限制: 下表提供了基于典型 Go 使用模式的预估请求数: -| Model | 每 5 小时请求数 | 每周请求数 | 每月请求数 | -| ------------- | --------------- | ---------- | ---------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | 每 5 小时请求数 | 每周请求数 | 每月请求数 | +| --------------- | --------------- | ---------- | ---------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | 预估值基于观察到的平均请求模式: - GLM-5/5.1 — 每次请求 700 个输入 token,52,000 个缓存 token,150 个输出 token - Kimi K2.5/K2.6 — 每次请求 870 个输入 token,55,000 个缓存 token,200 个输出 token +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiMo-V2-Pro — 每次请求 350 个输入 token,41,000 个缓存 token,250 个输出 token - MiMo-V2-Omni — 每次请求 1000 个输入 token,60,000 个缓存 token,140 个输出 token - MiMo-V2.5-Pro — 每次请求 350 个输入 token,41,000 个缓存 token,250 个输出 token @@ -129,20 +134,22 @@ OpenCode Go 包含以下限制: 你也可以通过以下 API 端点访问 Go 模型。 -| 模型 | 模型 ID | 端点 | AI SDK 包 | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| 模型 | 模型 ID | 端点 | AI SDK 包 | +| --------------- | --------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | 你 OpenCode 配置中的 [模型 ID](/docs/config/#models) 使用 `opencode-go/` 格式。例如,对于 Kimi K2.6,你将在配置中使用 `opencode-go/kimi-k2.6`。 diff --git a/packages/web/src/content/docs/zh-tw/go.mdx b/packages/web/src/content/docs/zh-tw/go.mdx index 481c08cec5..de871f915a 100644 --- a/packages/web/src/content/docs/zh-tw/go.mdx +++ b/packages/web/src/content/docs/zh-tw/go.mdx @@ -65,6 +65,8 @@ OpenCode Go 的運作方式與 OpenCode 中的任何其他供應商相同。 - **Qwen3.5 Plus** - **Qwen3.6 Plus** - **MiniMax M2.7** +- **DeepSeek V4 Pro** +- **DeepSeek V4 Flash** 隨著我們測試並加入新模型,模型清單可能會有所變動。 @@ -82,25 +84,28 @@ OpenCode Go 包含以下限制: 下表提供了基於典型 Go 使用模式的預估請求次數: -| Model | 每 5 小時請求數 | 每週請求數 | 每月請求數 | -| ------------- | --------------- | ---------- | ---------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | 每 5 小時請求數 | 每週請求數 | 每月請求數 | +| --------------- | --------------- | ---------- | ---------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | 預估值是基於觀察到的平均請求模式: - GLM-5/5.1 — 每次請求 700 個輸入 token、52,000 個快取 token、150 個輸出 token - Kimi K2.5/K2.6 — 每次請求 870 個輸入 token、55,000 個快取 token、200 個輸出 token +- DeepSeek V4 Pro/Flash — 700 input, 52,000 cached, 150 output tokens per request - MiniMax M2.7/M2.5 — 每次請求 300 個輸入 token、55,000 個快取 token、125 個輸出 token - Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request @@ -129,20 +134,22 @@ OpenCode Go 包含以下限制: 您也可以透過以下 API 端點存取 Go 模型。 -| 模型 | 模型 ID | 端點 | AI SDK 套件 | -| ------------- | ------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| 模型 | 模型 ID | 端點 | AI SDK 套件 | +| --------------- | --------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | 您的 OpenCode 設定中的 [model id](/docs/config/#models) 使用 `opencode-go/` 格式。例如,Kimi K2.6 在設定中應使用 `opencode-go/kimi-k2.6`。 From 1220f784feeba8421d2b2324feb0d137d341ec86 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Fri, 24 Apr 2026 15:48:08 +0000 Subject: [PATCH 76/92] chore: generate --- packages/web/src/content/docs/ar/go.mdx | 58 ++++++++++---------- packages/web/src/content/docs/bs/go.mdx | 60 ++++++++++---------- packages/web/src/content/docs/da/go.mdx | 28 +++++----- packages/web/src/content/docs/de/go.mdx | 62 ++++++++++----------- packages/web/src/content/docs/es/go.mdx | 62 ++++++++++----------- packages/web/src/content/docs/fr/go.mdx | 36 ++++++------ packages/web/src/content/docs/it/go.mdx | 62 ++++++++++----------- packages/web/src/content/docs/ja/go.mdx | 34 ++++++------ packages/web/src/content/docs/ko/go.mdx | 62 ++++++++++----------- packages/web/src/content/docs/nb/go.mdx | 40 +++++++------- packages/web/src/content/docs/pl/go.mdx | 62 ++++++++++----------- packages/web/src/content/docs/pt-br/go.mdx | 62 ++++++++++----------- packages/web/src/content/docs/ru/go.mdx | 62 ++++++++++----------- packages/web/src/content/docs/th/go.mdx | 64 +++++++++++----------- packages/web/src/content/docs/tr/go.mdx | 62 ++++++++++----------- packages/web/src/content/docs/zh-cn/go.mdx | 62 ++++++++++----------- packages/web/src/content/docs/zh-tw/go.mdx | 62 ++++++++++----------- 17 files changed, 470 insertions(+), 470 deletions(-) diff --git a/packages/web/src/content/docs/ar/go.mdx b/packages/web/src/content/docs/ar/go.mdx index 407c915916..42ba87ffab 100644 --- a/packages/web/src/content/docs/ar/go.mdx +++ b/packages/web/src/content/docs/ar/go.mdx @@ -84,20 +84,20 @@ OpenCode Go حاليًا في المرحلة التجريبية. يوضح الجدول أدناه عددًا تقديريًا للطلبات بناءً على أنماط استخدام Go المعتادة: -| Model | الطلبات لكل 5 ساعات | الطلبات في الأسبوع | الطلبات في الشهر | -| --------------- | ------------------- | ------------------ | ---------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| Model | الطلبات لكل 5 ساعات | الطلبات في الأسبوع | الطلبات في الشهر | +| ----------------- | ------------------- | ------------------ | ---------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | | DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | @@ -134,22 +134,22 @@ OpenCode Go حاليًا في المرحلة التجريبية. يمكنك أيضًا الوصول إلى نماذج Go عبر نقاط نهاية API التالية. -| Model | Model ID | Endpoint | AI SDK Package | -| --------------- | --------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Model | Model ID | Endpoint | AI SDK Package | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | يستخدم [model id](/docs/config/#models) في إعدادات OpenCode لديك التنسيق `opencode-go/`. على سبيل المثال، بالنسبة إلى Kimi K2.6، ستستخدم `opencode-go/kimi-k2.6` في إعداداتك. diff --git a/packages/web/src/content/docs/bs/go.mdx b/packages/web/src/content/docs/bs/go.mdx index a3f71ef14b..0d183ba28e 100644 --- a/packages/web/src/content/docs/bs/go.mdx +++ b/packages/web/src/content/docs/bs/go.mdx @@ -94,22 +94,22 @@ Ograničenja su definisana u dolarskoj vrijednosti. To znači da vaš stvarni br Tabela ispod pruža procijenjeni broj zahtjeva na osnovu tipičnih obrazaca korištenja Go pretplate: -| Model | zahtjeva na 5 sati | zahtjeva sedmično | zahtjeva mjesečno | -| --------------- | ------------------ | ----------------- | ----------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | -| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | -| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | +| Model | zahtjeva na 5 sati | zahtjeva sedmično | zahtjeva mjesečno | +| ----------------- | ------------------ | ----------------- | ----------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Procjene se zasnivaju na zapaženim prosječnim obrascima zahtjeva: @@ -146,22 +146,22 @@ nakon što dostignete ograničenja upotrebe umjesto blokiranja zahtjeva. Također možete pristupiti Go modelima putem sljedećih API endpointa. -| Model | Model ID | Endpoint | AI SDK Paket | -| --------------- | --------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Model | Model ID | Endpoint | AI SDK Paket | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | [Model id](/docs/config/#models) u vašoj OpenCode konfiguraciji koristi format `opencode-go/`. Na primjer, za Kimi K2.6, koristili biste diff --git a/packages/web/src/content/docs/da/go.mdx b/packages/web/src/content/docs/da/go.mdx index 947c613331..fcdbaf5f9b 100644 --- a/packages/web/src/content/docs/da/go.mdx +++ b/packages/web/src/content/docs/da/go.mdx @@ -146,22 +146,22 @@ når du har nået dine forbrugsgrænser, i stedet for at blokere anmodninger. Du kan også få adgang til Go-modeller gennem følgende API-endpoints. -| Model | Model ID | Endpoint | AI SDK Package | -| ----------------- | --------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Model | Model ID | Endpoint | AI SDK Package | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | Dit [model id](/docs/config/#models) i din OpenCode config bruger formatet `opencode-go/`. For eksempel for Kimi K2.6, vil du diff --git a/packages/web/src/content/docs/de/go.mdx b/packages/web/src/content/docs/de/go.mdx index d78df0195f..09341efa4b 100644 --- a/packages/web/src/content/docs/de/go.mdx +++ b/packages/web/src/content/docs/de/go.mdx @@ -86,22 +86,22 @@ Limits sind in Dollarwerten definiert. Das bedeutet, dass die tatsächliche Anza Die folgende Tabelle zeigt eine geschätzte Anzahl von Anfragen basierend auf typischen Go-Nutzungsmustern: -| Model | Anfragen pro 5 Stunden | Anfragen pro Woche | Anfragen pro Monat | -| --------------- | ---------------------- | ------------------ | ------------------ | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | -| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | -| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | +| Model | Anfragen pro 5 Stunden | Anfragen pro Woche | Anfragen pro Monat | +| ----------------- | ---------------------- | ------------------ | ------------------ | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Die Schätzungen basieren auf beobachteten durchschnittlichen Anfragemustern: @@ -136,22 +136,22 @@ Wenn du auch Guthaben auf deinem Zen-Konto hast, kannst du in der Console die Op Du kannst auf die Go-Modelle auch über die folgenden API-Endpunkte zugreifen. -| Modell | Modell-ID | Endpunkt | AI SDK Package | -| --------------- | --------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Modell | Modell-ID | Endpunkt | AI SDK Package | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | Die [Modell-ID](/docs/config/#models) in deiner OpenCode Config verwendet das Format `opencode-go/`. Für Kimi K2.6 würdest du beispielsweise `opencode-go/kimi-k2.6` in deiner Config verwenden. diff --git a/packages/web/src/content/docs/es/go.mdx b/packages/web/src/content/docs/es/go.mdx index 6d01cfd7fe..fd1edcf9ce 100644 --- a/packages/web/src/content/docs/es/go.mdx +++ b/packages/web/src/content/docs/es/go.mdx @@ -94,22 +94,22 @@ Los límites se definen en valor en dólares. Esto significa que tu cantidad rea La siguiente tabla proporciona una cantidad estimada de peticiones basada en los patrones típicos de uso de Go: -| Model | peticiones por 5 horas | peticiones por semana | peticiones por mes | -| --------------- | ---------------------- | --------------------- | ------------------ | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | -| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | -| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | +| Model | peticiones por 5 horas | peticiones por semana | peticiones por mes | +| ----------------- | ---------------------- | --------------------- | ------------------ | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Las estimaciones se basan en los patrones de peticiones promedio observados: @@ -146,22 +146,22 @@ después de que hayas alcanzado tus límites de uso en lugar de bloquear las pet También puedes acceder a los modelos de Go a través de los siguientes endpoints de la API. -| Modelo | ID del modelo | Endpoint | Paquete de AI SDK | -| --------------- | --------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Modelo | ID del modelo | Endpoint | Paquete de AI SDK | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | El [ID del modelo](/docs/config/#models) en tu configuración de OpenCode usa el formato `opencode-go/`. Por ejemplo, para Kimi K2.6, usarías diff --git a/packages/web/src/content/docs/fr/go.mdx b/packages/web/src/content/docs/fr/go.mdx index c4d70e610b..80cd5d2fc2 100644 --- a/packages/web/src/content/docs/fr/go.mdx +++ b/packages/web/src/content/docs/fr/go.mdx @@ -84,11 +84,11 @@ Les limites sont définies en valeur monétaire (dollars). Cela signifie que vot Le tableau ci-dessous fournit une estimation du nombre de requêtes basée sur des modèles d'utilisation typiques de Go : -| Model | requêtes par 5 heures | requêtes par semaine | requêtes par mois | -| --------------- | --------------------- | -------------------- | ----------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Model | requêtes par 5 heures | requêtes par semaine | requêtes par mois | +| ----------------- | --------------------- | -------------------- | ----------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | | MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | | MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | @@ -134,22 +134,22 @@ Si vous avez également des crédits sur votre solde Zen, vous pouvez activer l' Vous pouvez également accéder aux modèles Go via les points de terminaison d'API suivants. -| Modèle | ID de modèle | Point de terminaison | Package AI SDK | -| --------------- | --------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Modèle | ID de modèle | Point de terminaison | Package AI SDK | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | | DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | L'[ID de modèle](/docs/config/#models) dans votre configuration OpenCode utilise le format `opencode-go/`. Par exemple, pour Kimi K2.6, vous utiliseriez `opencode-go/kimi-k2.6` dans votre configuration. diff --git a/packages/web/src/content/docs/it/go.mdx b/packages/web/src/content/docs/it/go.mdx index 216362ed4a..775e567f8e 100644 --- a/packages/web/src/content/docs/it/go.mdx +++ b/packages/web/src/content/docs/it/go.mdx @@ -92,22 +92,22 @@ I limiti sono definiti in valore in dollari. Questo significa che il conteggio e La tabella seguente fornisce una stima del conteggio delle richieste in base a pattern di utilizzo tipici di Go: -| Model | richieste ogni 5 ore | richieste a settimana | richieste al mese | -| --------------- | -------------------- | --------------------- | ----------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | -| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | -| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | +| Model | richieste ogni 5 ore | richieste a settimana | richieste al mese | +| ----------------- | -------------------- | --------------------- | ----------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Le stime si basano sui pattern medi di richieste osservati: @@ -144,22 +144,22 @@ dopo che avrai raggiunto i limiti di utilizzo invece di bloccare le richieste. Puoi anche accedere ai modelli Go tramite i seguenti endpoint API. -| Modello | ID Modello | Endpoint | Pacchetto AI SDK | -| --------------- | --------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Modello | ID Modello | Endpoint | Pacchetto AI SDK | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | Il [model id](/docs/config/#models) nella tua OpenCode config utilizza il formato `opencode-go/`. Ad esempio, per Kimi K2.6, useresti diff --git a/packages/web/src/content/docs/ja/go.mdx b/packages/web/src/content/docs/ja/go.mdx index 3886a827ae..6ab9c3235c 100644 --- a/packages/web/src/content/docs/ja/go.mdx +++ b/packages/web/src/content/docs/ja/go.mdx @@ -84,8 +84,8 @@ OpenCode Goには以下の制限が含まれています: 以下の表は、一般的なGoの利用パターンに基づいた推定リクエスト数を示しています: -| Model | 5時間あたりのリクエスト数 | 週間リクエスト数 | 月間リクエスト数 | -| --------------- | ------------------------- | ---------------- | ---------------- | +| Model | 5時間あたりのリクエスト数 | 週間リクエスト数 | 月間リクエスト数 | +| ----------------- | ------------------------- | ---------------- | ---------------- | | GLM-5.1 | 880 | 2,150 | 4,300 | | GLM-5 | 1,150 | 2,880 | 5,750 | | Kimi K2.5 | 1,850 | 4,630 | 9,250 | @@ -134,22 +134,22 @@ Zen残高にクレジットがある場合は、コンソールで**Use balance* 以下のAPIエンドポイントを通じて、Goモデルにアクセスすることもできます。 -| Model | Model ID | Endpoint | AI SDK Package | -| --------------- | --------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Model | Model ID | Endpoint | AI SDK Package | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | OpenCode設定の[model id](/docs/config/#models)は、`opencode-go/`という形式を使用します。たとえば、Kimi K2.6の場合は、設定で`opencode-go/kimi-k2.6`を使用します。 diff --git a/packages/web/src/content/docs/ko/go.mdx b/packages/web/src/content/docs/ko/go.mdx index c0fbc62bd2..83c7c8e6a6 100644 --- a/packages/web/src/content/docs/ko/go.mdx +++ b/packages/web/src/content/docs/ko/go.mdx @@ -84,22 +84,22 @@ OpenCode Go에는 다음과 같은 한도가 포함됩니다. 아래 표는 일반적인 Go 사용 패턴을 기준으로 한 예상 요청 횟수를 보여줍니다. -| Model | 5시간당 요청 횟수 | 주간 요청 횟수 | 월간 요청 횟수 | -| --------------- | ----------------- | -------------- | -------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | -| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | -| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | +| Model | 5시간당 요청 횟수 | 주간 요청 횟수 | 월간 요청 횟수 | +| ----------------- | ----------------- | -------------- | -------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | 예상치는 관찰된 평균 요청 패턴을 기준으로 합니다. @@ -134,22 +134,22 @@ Zen 잔액에 크레딧도 있다면, console에서 **Use balance** 옵션을 다음 API 엔드포인트를 통해서도 Go 모델에 액세스할 수 있습니다. -| 모델 | 모델 ID | 엔드포인트 | AI SDK 패키지 | -| --------------- | -------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| 모델 | 모델 ID | 엔드포인트 | AI SDK 패키지 | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | OpenCode config의 [model id](/docs/config/#models)는 `opencode-go/` 형식을 사용합니다. 예를 들어 Kimi K2.6의 경우 config에서 `opencode-go/kimi-k2.6`를 사용하면 됩니다. diff --git a/packages/web/src/content/docs/nb/go.mdx b/packages/web/src/content/docs/nb/go.mdx index 0cae0c57f6..53ad74f376 100644 --- a/packages/web/src/content/docs/nb/go.mdx +++ b/packages/web/src/content/docs/nb/go.mdx @@ -94,11 +94,11 @@ Grensene er definert i dollarverdi. Dette betyr at ditt faktiske antall forespø Tabellen nedenfor gir et estimert antall forespørsler basert på typiske bruksmønstre for Go: -| Model | forespørsler per 5 timer | forespørsler per uke | forespørsler per måned | -| --------------- | ------------------------ | -------------------- | ---------------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Model | forespørsler per 5 timer | forespørsler per uke | forespørsler per måned | +| ----------------- | ------------------------ | -------------------- | ---------------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | | Kimi K2.6 | 1,150 | 2,880 | 5,750 | | MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | | MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | @@ -146,22 +146,22 @@ etter at du har nådd bruksgrensene dine, i stedet for å blokkere forespørsler Du kan også få tilgang til Go-modeller gjennom følgende API-endepunkter. -| Modell | Modell-ID | Endepunkt | AI SDK Package | -| --------------- | --------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Modell | Modell-ID | Endepunkt | AI SDK Package | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | [Modell-ID-en](/docs/config/#models) i din OpenCode-konfigurasjon bruker formatet `opencode-go/`. For eksempel, for Kimi K2.6, vil du diff --git a/packages/web/src/content/docs/pl/go.mdx b/packages/web/src/content/docs/pl/go.mdx index c64075a3b7..87fcf1cc35 100644 --- a/packages/web/src/content/docs/pl/go.mdx +++ b/packages/web/src/content/docs/pl/go.mdx @@ -88,22 +88,22 @@ Limity są zdefiniowane w wartości w dolarach. Oznacza to, że rzeczywista licz Poniższa tabela przedstawia szacunkową liczbę żądań na podstawie typowych wzorców korzystania z Go: -| Model | żądania na 5 godzin | żądania na tydzień | żądania na miesiąc | -| --------------- | ------------------- | ------------------ | ------------------ | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | -| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | -| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | +| Model | żądania na 5 godzin | żądania na tydzień | żądania na miesiąc | +| ----------------- | ------------------- | ------------------ | ------------------ | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Szacunki opierają się na zaobserwowanych średnich wzorcach żądań: @@ -138,22 +138,22 @@ Jeśli masz również środki na swoim saldzie Zen, możesz włączyć opcję ** Możesz również uzyskać dostęp do modeli Go za pośrednictwem następujących punktów końcowych API. -| Model | ID modelu | Punkt końcowy | Pakiet AI SDK | -| --------------- | --------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Model | ID modelu | Punkt końcowy | Pakiet AI SDK | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | [ID modelu](/docs/config/#models) w Twojej konfiguracji OpenCode używa formatu `opencode-go/`. Na przykład dla Kimi K2.6 należy użyć diff --git a/packages/web/src/content/docs/pt-br/go.mdx b/packages/web/src/content/docs/pt-br/go.mdx index 4a454c93e7..4a22089339 100644 --- a/packages/web/src/content/docs/pt-br/go.mdx +++ b/packages/web/src/content/docs/pt-br/go.mdx @@ -94,22 +94,22 @@ Os limites são definidos em valor em dólares. Isso significa que a sua contage A tabela abaixo fornece uma contagem estimada de requisições com base nos padrões típicos de uso do Go: -| Model | requisições por 5 horas | requisições por semana | requisições por mês | -| --------------- | ----------------------- | ---------------------- | ------------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | -| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | -| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | +| Model | requisições por 5 horas | requisições por semana | requisições por mês | +| ----------------- | ----------------------- | ---------------------- | ------------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | As estimativas baseiam-se nos padrões médios de requisições observados: @@ -146,22 +146,22 @@ após você atingir os seus limites de uso em vez de bloquear as requisições. Você também pode acessar os modelos do Go através dos seguintes endpoints de API. -| Modelo | ID do Modelo | Endpoint | Pacote do AI SDK | -| --------------- | --------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Modelo | ID do Modelo | Endpoint | Pacote do AI SDK | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | O [ID do modelo](/docs/config/#models) na sua configuração do OpenCode usa o formato `opencode-go/`. Por exemplo, para o Kimi K2.6, você usaria diff --git a/packages/web/src/content/docs/ru/go.mdx b/packages/web/src/content/docs/ru/go.mdx index 2656d3659c..5a07418a73 100644 --- a/packages/web/src/content/docs/ru/go.mdx +++ b/packages/web/src/content/docs/ru/go.mdx @@ -94,22 +94,22 @@ OpenCode Go включает следующие лимиты: В таблице ниже приведено примерное количество запросов на основе типичных сценариев использования Go: -| Model | запросов за 5 часов | запросов в неделю | запросов в месяц | -| --------------- | ------------------- | ----------------- | ---------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | -| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | -| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | +| Model | запросов за 5 часов | запросов в неделю | запросов в месяц | +| ----------------- | ------------------- | ----------------- | ---------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Оценки основаны на наблюдаемых средних показателях запросов: @@ -146,22 +146,22 @@ OpenCode Go включает следующие лимиты: Вы также можете получить доступ к моделям Go через следующие API-эндпоинты. -| Модель | ID модели | Эндпоинт | Пакет AI SDK | -| --------------- | --------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Модель | ID модели | Эндпоинт | Пакет AI SDK | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | [ID модели](/docs/config/#models) в вашем конфиге OpenCode использует формат `opencode-go/`. Например, для Kimi K2.6 вам нужно diff --git a/packages/web/src/content/docs/th/go.mdx b/packages/web/src/content/docs/th/go.mdx index 04d999159a..17cd9feb84 100644 --- a/packages/web/src/content/docs/th/go.mdx +++ b/packages/web/src/content/docs/th/go.mdx @@ -84,22 +84,22 @@ OpenCode Go มีขีดจำกัดดังต่อไปนี้: ตารางด้านล่างแสดงจำนวน request โดยประมาณตามรูปแบบการใช้งานปกติของ Go: -| Model | requests ต่อ 5 ชั่วโมง | requests ต่อสัปดาห์ | requests ต่อเดือน | -| ------------------- | ---------------------- | ------------------- | ----------------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | -| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | -| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | +| Model | requests ต่อ 5 ชั่วโมง | requests ต่อสัปดาห์ | requests ต่อเดือน | +| ----------------- | ---------------------- | ------------------- | ----------------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | การประมาณการอ้างอิงจากรูปแบบการใช้งาน request โดยเฉลี่ยที่สังเกตพบ: @@ -134,22 +134,22 @@ OpenCode Go มีขีดจำกัดดังต่อไปนี้: คุณสามารถเข้าถึงโมเดลของ Go ผ่าน API endpoints ต่อไปนี้ได้เช่นกัน -| Model | Model ID | Endpoint | AI SDK Package | -| ------------------- | --------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Model | Model ID | Endpoint | AI SDK Package | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | [model id](/docs/config/#models) ใน OpenCode config ของคุณจะใช้รูปแบบ `opencode-go/` ตัวอย่างเช่น สำหรับ Kimi K2.6 คุณจะใช้ `opencode-go/kimi-k2.6` ใน config ของคุณ diff --git a/packages/web/src/content/docs/tr/go.mdx b/packages/web/src/content/docs/tr/go.mdx index 66556701a5..884c0e00cf 100644 --- a/packages/web/src/content/docs/tr/go.mdx +++ b/packages/web/src/content/docs/tr/go.mdx @@ -84,22 +84,22 @@ Limitler dolar değeri üzerinden belirlenmiştir. Bu, gerçek istek sayınızı Aşağıdaki tablo, tipik Go kullanım modellerine dayalı tahmini bir istek sayısı sunmaktadır: -| Model | 5 saatte bir istek | haftalık istek | aylık istek | -| --------------- | ------------------ | -------------- | ----------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | -| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | -| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | +| Model | 5 saatte bir istek | haftalık istek | aylık istek | +| ----------------- | ------------------ | -------------- | ----------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | Tahminler, gözlemlenen ortalama istek modellerine dayanmaktadır: @@ -134,22 +134,22 @@ Eğer Zen bakiyenizde kredileriniz varsa, konsoldan **Bakiye kullan (Use balance Go modellerine aşağıdaki API uç noktaları aracılığıyla da erişebilirsiniz. -| Model | Model ID | Uç Nokta | AI SDK Paketi | -| --------------- | --------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Model | Model ID | Uç Nokta | AI SDK Paketi | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | OpenCode yapılandırmanızdaki [model id](/docs/config/#models) formatı `opencode-go/` şeklindedir. Örneğin, Kimi K2.6 için yapılandırmanızda `opencode-go/kimi-k2.6` kullanmalısınız. diff --git a/packages/web/src/content/docs/zh-cn/go.mdx b/packages/web/src/content/docs/zh-cn/go.mdx index 47caa95588..828da590a3 100644 --- a/packages/web/src/content/docs/zh-cn/go.mdx +++ b/packages/web/src/content/docs/zh-cn/go.mdx @@ -84,22 +84,22 @@ OpenCode Go 包含以下限制: 下表提供了基于典型 Go 使用模式的预估请求数: -| Model | 每 5 小时请求数 | 每周请求数 | 每月请求数 | -| --------------- | --------------- | ---------- | ---------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | -| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | -| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | +| Model | 每 5 小时请求数 | 每周请求数 | 每月请求数 | +| ----------------- | --------------- | ---------- | ---------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | 预估值基于观察到的平均请求模式: @@ -134,22 +134,22 @@ OpenCode Go 包含以下限制: 你也可以通过以下 API 端点访问 Go 模型。 -| 模型 | 模型 ID | 端点 | AI SDK 包 | -| --------------- | --------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| 模型 | 模型 ID | 端点 | AI SDK 包 | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | 你 OpenCode 配置中的 [模型 ID](/docs/config/#models) 使用 `opencode-go/` 格式。例如,对于 Kimi K2.6,你将在配置中使用 `opencode-go/kimi-k2.6`。 diff --git a/packages/web/src/content/docs/zh-tw/go.mdx b/packages/web/src/content/docs/zh-tw/go.mdx index de871f915a..1df68a6c4e 100644 --- a/packages/web/src/content/docs/zh-tw/go.mdx +++ b/packages/web/src/content/docs/zh-tw/go.mdx @@ -84,22 +84,22 @@ OpenCode Go 包含以下限制: 下表提供了基於典型 Go 使用模式的預估請求次數: -| Model | 每 5 小時請求數 | 每週請求數 | 每月請求數 | -| --------------- | --------------- | ---------- | ---------- | -| GLM-5.1 | 880 | 2,150 | 4,300 | -| GLM-5 | 1,150 | 2,880 | 5,750 | -| Kimi K2.5 | 1,850 | 4,630 | 9,250 | -| Kimi K2.6 | 1,150 | 2,880 | 5,750 | -| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | -| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | -| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | -| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | -| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | -| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | -| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | -| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | +| Model | 每 5 小時請求數 | 每週請求數 | 每月請求數 | +| ----------------- | --------------- | ---------- | ---------- | +| GLM-5.1 | 880 | 2,150 | 4,300 | +| GLM-5 | 1,150 | 2,880 | 5,750 | +| Kimi K2.5 | 1,850 | 4,630 | 9,250 | +| Kimi K2.6 | 1,150 | 2,880 | 5,750 | +| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 | +| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | +| MiMo-V2.5 | 2,150 | 5,450 | 10,900 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | +| MiniMax M2.7 | 3,400 | 8,500 | 17,000 | +| MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | +| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 | +| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 | 預估值是基於觀察到的平均請求模式: @@ -134,22 +134,22 @@ OpenCode Go 包含以下限制: 您也可以透過以下 API 端點存取 Go 模型。 -| 模型 | 模型 ID | 端點 | AI SDK 套件 | -| --------------- | --------------- | ------------------------------------------------ | --------------------------- | -| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| 模型 | 模型 ID | 端點 | AI SDK 套件 | +| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- | +| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | -| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | -| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | +| Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | +| Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/alibaba` | 您的 OpenCode 設定中的 [model id](/docs/config/#models) 使用 `opencode-go/` 格式。例如,Kimi K2.6 在設定中應使用 `opencode-go/kimi-k2.6`。 From 28025a0f36c710a9db70502e04320b2d18b0d8e2 Mon Sep 17 00:00:00 2001 From: opencode Date: Fri, 24 Apr 2026 15:53:03 +0000 Subject: [PATCH 77/92] sync release versions for v1.14.24 --- bun.lock | 32 +++++++++++++------------- packages/app/package.json | 2 +- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop-electron/package.json | 2 +- packages/desktop/package.json | 2 +- packages/enterprise/package.json | 2 +- packages/extensions/zed/extension.toml | 12 +++++----- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/shared/package.json | 2 +- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 19 files changed, 39 insertions(+), 39 deletions(-) diff --git a/bun.lock b/bun.lock index 359709a464..d42183f938 100644 --- a/bun.lock +++ b/bun.lock @@ -29,7 +29,7 @@ }, "packages/app": { "name": "@opencode-ai/app", - "version": "1.14.23", + "version": "1.14.24", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -83,7 +83,7 @@ }, "packages/console/app": { "name": "@opencode-ai/console-app", - "version": "1.14.23", + "version": "1.14.24", "dependencies": { "@cloudflare/vite-plugin": "1.15.2", "@ibm/plex": "6.4.1", @@ -117,7 +117,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.14.23", + "version": "1.14.24", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -144,7 +144,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.14.23", + "version": "1.14.24", "dependencies": { "@ai-sdk/anthropic": "3.0.64", "@ai-sdk/openai": "3.0.48", @@ -168,7 +168,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.14.23", + "version": "1.14.24", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -192,7 +192,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.14.23", + "version": "1.14.24", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -225,7 +225,7 @@ }, "packages/desktop-electron": { "name": "@opencode-ai/desktop-electron", - "version": "1.14.23", + "version": "1.14.24", "dependencies": { "drizzle-orm": "catalog:", "effect": "catalog:", @@ -269,7 +269,7 @@ }, "packages/enterprise": { "name": "@opencode-ai/enterprise", - "version": "1.14.23", + "version": "1.14.24", "dependencies": { "@opencode-ai/shared": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -298,7 +298,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.14.23", + "version": "1.14.24", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "catalog:", @@ -314,7 +314,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.14.23", + "version": "1.14.24", "bin": { "opencode": "./bin/opencode", }, @@ -459,7 +459,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.14.23", + "version": "1.14.24", "dependencies": { "@opencode-ai/sdk": "workspace:*", "effect": "catalog:", @@ -494,7 +494,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.14.23", + "version": "1.14.24", "dependencies": { "cross-spawn": "catalog:", }, @@ -509,7 +509,7 @@ }, "packages/shared": { "name": "@opencode-ai/shared", - "version": "1.14.23", + "version": "1.14.24", "bin": { "opencode": "./bin/opencode", }, @@ -533,7 +533,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.14.23", + "version": "1.14.24", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -568,7 +568,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.14.23", + "version": "1.14.24", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -617,7 +617,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.14.23", + "version": "1.14.24", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/app/package.json b/packages/app/package.json index b01b9b9d1a..324d8058ca 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "1.14.23", + "version": "1.14.24", "description": "", "type": "module", "exports": { diff --git a/packages/console/app/package.json b/packages/console/app/package.json index acd7024a6d..e553d1d26c 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-app", - "version": "1.14.23", + "version": "1.14.24", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/console/core/package.json b/packages/console/core/package.json index a8ba8c5398..09dad6014c 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.14.23", + "version": "1.14.24", "private": true, "type": "module", "license": "MIT", diff --git a/packages/console/function/package.json b/packages/console/function/package.json index b917ee2b59..2005a941be 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.14.23", + "version": "1.14.24", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 17fd13d0f3..16d99c7c47 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.14.23", + "version": "1.14.24", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop-electron/package.json b/packages/desktop-electron/package.json index bd286786bb..0c9d8b253d 100644 --- a/packages/desktop-electron/package.json +++ b/packages/desktop-electron/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop-electron", "private": true, - "version": "1.14.23", + "version": "1.14.24", "type": "module", "license": "MIT", "homepage": "https://opencode.ai", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 561a974700..34a1375f68 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop", "private": true, - "version": "1.14.23", + "version": "1.14.24", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/enterprise/package.json b/packages/enterprise/package.json index 11a6ea7ef6..13be3723da 100644 --- a/packages/enterprise/package.json +++ b/packages/enterprise/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/enterprise", - "version": "1.14.23", + "version": "1.14.24", "private": true, "type": "module", "license": "MIT", diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 2943614d38..d8c9ecc8c8 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The open source coding agent." -version = "1.14.23" +version = "1.14.24" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/anomalyco/opencode" @@ -11,26 +11,26 @@ name = "OpenCode" icon = "./icons/opencode.svg" [agent_servers.opencode.targets.darwin-aarch64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.23/opencode-darwin-arm64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.24/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.23/opencode-darwin-x64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.24/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.23/opencode-linux-arm64.tar.gz" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.24/opencode-linux-arm64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.23/opencode-linux-x64.tar.gz" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.24/opencode-linux-x64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.23/opencode-windows-x64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.24/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index 1501f3df40..5a1e2beb4e 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.14.23", + "version": "1.14.24", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index f1d72c640f..14ae8b72ec 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.14.23", + "version": "1.14.24", "name": "opencode", "type": "module", "license": "MIT", diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 45926f05ba..e7d9b87edc 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.14.23", + "version": "1.14.24", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 9f9658eb15..d924f1e684 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.14.23", + "version": "1.14.24", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/shared/package.json b/packages/shared/package.json index 08bb009297..151751bdad 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.14.23", + "version": "1.14.24", "name": "@opencode-ai/shared", "type": "module", "license": "MIT", diff --git a/packages/slack/package.json b/packages/slack/package.json index 5149dbffe9..89f54026ab 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.14.23", + "version": "1.14.24", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/ui/package.json b/packages/ui/package.json index f4d90f1460..6339b1f5bc 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.14.23", + "version": "1.14.24", "type": "module", "license": "MIT", "exports": { diff --git a/packages/web/package.json b/packages/web/package.json index 386078d171..a8e9d0e0ee 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -2,7 +2,7 @@ "name": "@opencode-ai/web", "type": "module", "license": "MIT", - "version": "1.14.23", + "version": "1.14.24", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 035a45eb7a..217cb037a3 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.14.23", + "version": "1.14.24", "publisher": "sst-dev", "repository": { "type": "git", From d01ad4c4992f931e334eaeac1baf7001e9d8f4f7 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 24 Apr 2026 14:05:29 -0400 Subject: [PATCH 78/92] zen: gpt-5.5 --- packages/web/src/content/docs/ar/zen.mdx | 4 +++- packages/web/src/content/docs/bs/zen.mdx | 6 ++++-- packages/web/src/content/docs/da/zen.mdx | 6 ++++-- packages/web/src/content/docs/de/zen.mdx | 4 +++- packages/web/src/content/docs/es/zen.mdx | 6 ++++-- packages/web/src/content/docs/fr/zen.mdx | 4 +++- packages/web/src/content/docs/it/zen.mdx | 6 ++++-- packages/web/src/content/docs/ja/zen.mdx | 6 +++++- packages/web/src/content/docs/ko/zen.mdx | 4 +++- packages/web/src/content/docs/nb/zen.mdx | 2 ++ packages/web/src/content/docs/pl/zen.mdx | 2 ++ packages/web/src/content/docs/pt-br/zen.mdx | 2 ++ packages/web/src/content/docs/ru/zen.mdx | 2 ++ packages/web/src/content/docs/th/zen.mdx | 2 ++ packages/web/src/content/docs/tr/zen.mdx | 2 ++ packages/web/src/content/docs/zen.mdx | 8 ++++++-- packages/web/src/content/docs/zh-cn/zen.mdx | 2 ++ packages/web/src/content/docs/zh-tw/zen.mdx | 2 ++ 18 files changed, 55 insertions(+), 15 deletions(-) diff --git a/packages/web/src/content/docs/ar/zen.mdx b/packages/web/src/content/docs/ar/zen.mdx index f85c15ea96..42ab5034c9 100644 --- a/packages/web/src/content/docs/ar/zen.mdx +++ b/packages/web/src/content/docs/ar/zen.mdx @@ -59,6 +59,8 @@ OpenCode Zen هي بوابة AI تتيح لك الوصول إلى هذه الن | النموذج | معرّف النموذج | نقطة النهاية | حزمة AI SDK | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -99,7 +101,7 @@ OpenCode Zen هي بوابة AI تتيح لك الوصول إلى هذه الن | Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -يستخدم [معرّف النموذج](/docs/config/#models) في إعدادات OpenCode الصيغة `opencode/`. على سبيل المثال، بالنسبة إلى GPT 5.4، ستستخدم `opencode/gpt-5.4` في إعداداتك. +يستخدم [معرّف النموذج](/docs/config/#models) في إعدادات OpenCode الصيغة `opencode/`. على سبيل المثال، بالنسبة إلى GPT 5.5، ستستخدم `opencode/gpt-5.5` في إعداداتك. --- diff --git a/packages/web/src/content/docs/bs/zen.mdx b/packages/web/src/content/docs/bs/zen.mdx index 026e145adc..6bc25b4c13 100644 --- a/packages/web/src/content/docs/bs/zen.mdx +++ b/packages/web/src/content/docs/bs/zen.mdx @@ -64,6 +64,8 @@ Našim modelima možete pristupiti i preko sljedećih API endpointa. | Model | Model ID | Endpoint | AI SDK Package | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -105,8 +107,8 @@ Našim modelima možete pristupiti i preko sljedećih API endpointa. | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | [model id](/docs/config/#models) u vašoj OpenCode konfiguraciji koristi format -`opencode/`. Na primjer, za GPT 5.4 u konfiguraciji biste -koristili `opencode/gpt-5.4`. +`opencode/`. Na primjer, za GPT 5.5 u konfiguraciji biste +koristili `opencode/gpt-5.5`. --- diff --git a/packages/web/src/content/docs/da/zen.mdx b/packages/web/src/content/docs/da/zen.mdx index b5c9f469f3..51bae8ef63 100644 --- a/packages/web/src/content/docs/da/zen.mdx +++ b/packages/web/src/content/docs/da/zen.mdx @@ -64,6 +64,8 @@ Du kan også få adgang til vores modeller gennem følgende API-endpoints. | Model | Model ID | Endpoint | AI SDK-pakke | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -105,8 +107,8 @@ Du kan også få adgang til vores modeller gennem følgende API-endpoints. | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | [model id](/docs/config/#models) i din OpenCode-konfiguration -bruger formatet `opencode/`. For eksempel ville du for GPT 5.4 -bruge `opencode/gpt-5.4` i din konfiguration. +bruger formatet `opencode/`. For eksempel ville du for GPT 5.5 +bruge `opencode/gpt-5.5` i din konfiguration. --- diff --git a/packages/web/src/content/docs/de/zen.mdx b/packages/web/src/content/docs/de/zen.mdx index 2fd012dd1b..30a78ddd61 100644 --- a/packages/web/src/content/docs/de/zen.mdx +++ b/packages/web/src/content/docs/de/zen.mdx @@ -55,6 +55,8 @@ Du kannst auch über die folgenden API-Endpunkte auf unsere Modelle zugreifen. | Model | Model ID | Endpoint | AI SDK Package | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -95,7 +97,7 @@ Du kannst auch über die folgenden API-Endpunkte auf unsere Modelle zugreifen. | Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -Die [Model-ID](/docs/config/#models) in deiner OpenCode-Konfiguration verwendet das Format `opencode/`. Für GPT 5.4 würdest du zum Beispiel `opencode/gpt-5.4` in deiner Konfiguration verwenden. +Die [Model-ID](/docs/config/#models) in deiner OpenCode-Konfiguration verwendet das Format `opencode/`. Für GPT 5.5 würdest du zum Beispiel `opencode/gpt-5.5` in deiner Konfiguration verwenden. --- diff --git a/packages/web/src/content/docs/es/zen.mdx b/packages/web/src/content/docs/es/zen.mdx index 82ed07a23b..9534c61de6 100644 --- a/packages/web/src/content/docs/es/zen.mdx +++ b/packages/web/src/content/docs/es/zen.mdx @@ -64,6 +64,8 @@ También puedes acceder a nuestros modelos a través de los siguientes endpoints | Modelo | Model ID | Endpoint | AI SDK Package | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -105,8 +107,8 @@ También puedes acceder a nuestros modelos a través de los siguientes endpoints | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | El [identificador del modelo](/docs/config/#models) en tu configuración de OpenCode -usa el formato `opencode/`. Por ejemplo, para GPT 5.4, usarías -`opencode/gpt-5.4` en tu configuración. +usa el formato `opencode/`. Por ejemplo, para GPT 5.5, usarías +`opencode/gpt-5.5` en tu configuración. --- diff --git a/packages/web/src/content/docs/fr/zen.mdx b/packages/web/src/content/docs/fr/zen.mdx index 0b2bcf94aa..cd2a621f53 100644 --- a/packages/web/src/content/docs/fr/zen.mdx +++ b/packages/web/src/content/docs/fr/zen.mdx @@ -55,6 +55,8 @@ Vous pouvez également accéder à nos modèles via les points de terminaison AP | Modèle | ID du modèle | Point de terminaison | Package AI SDK | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -95,7 +97,7 @@ Vous pouvez également accéder à nos modèles via les points de terminaison AP | Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -Le [model id](/docs/config/#models) dans votre configuration OpenCode utilise le format `opencode/`. Par exemple, pour GPT 5.4, vous utiliseriez `opencode/gpt-5.4` dans votre configuration. +Le [model id](/docs/config/#models) dans votre configuration OpenCode utilise le format `opencode/`. Par exemple, pour GPT 5.5, vous utiliseriez `opencode/gpt-5.5` dans votre configuration. --- diff --git a/packages/web/src/content/docs/it/zen.mdx b/packages/web/src/content/docs/it/zen.mdx index 14ddb891d3..451d407510 100644 --- a/packages/web/src/content/docs/it/zen.mdx +++ b/packages/web/src/content/docs/it/zen.mdx @@ -64,6 +64,8 @@ Puoi anche accedere ai nostri modelli tramite i seguenti endpoint API. | Modello | Model ID | Endpoint | Pacchetto AI SDK | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -105,8 +107,8 @@ Puoi anche accedere ai nostri modelli tramite i seguenti endpoint API. | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | Il [model id](/docs/config/#models) nella config di OpenCode -usa il formato `opencode/`. Per esempio, per GPT 5.4, useresti -`opencode/gpt-5.4` nella tua config. +usa il formato `opencode/`. Per esempio, per GPT 5.5, useresti +`opencode/gpt-5.5` nella tua config. --- diff --git a/packages/web/src/content/docs/ja/zen.mdx b/packages/web/src/content/docs/ja/zen.mdx index ee84dc9172..0d142a73fb 100644 --- a/packages/web/src/content/docs/ja/zen.mdx +++ b/packages/web/src/content/docs/ja/zen.mdx @@ -55,6 +55,8 @@ OpenCode Zen は、OpenCode のほかのプロバイダーと同じように動 | Model | Model ID | Endpoint | AI SDK Package | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -95,7 +97,7 @@ OpenCode Zen は、OpenCode のほかのプロバイダーと同じように動 | Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -OpenCode 設定で使う [model id](/docs/config/#models) は `opencode/` 形式です。たとえば、GPT 5.4 では設定に `opencode/gpt-5.4` を使用します。 +OpenCode 設定で使う [model id](/docs/config/#models) は `opencode/` 形式です。たとえば、GPT 5.5 では設定に `opencode/gpt-5.5` を使用します。 --- @@ -142,6 +144,8 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/ko/zen.mdx b/packages/web/src/content/docs/ko/zen.mdx index 416ec9f20b..1fc661da6d 100644 --- a/packages/web/src/content/docs/ko/zen.mdx +++ b/packages/web/src/content/docs/ko/zen.mdx @@ -55,6 +55,8 @@ OpenCode Zen은 OpenCode의 다른 provider와 똑같이 작동합니다. | 모델 | 모델 ID | 엔드포인트 | AI SDK 패키지 | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -95,7 +97,7 @@ OpenCode Zen은 OpenCode의 다른 provider와 똑같이 작동합니다. | Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -OpenCode config에서 사용하는 [모델 ID](/docs/config/#models)는 `opencode/` 형식입니다. 예를 들어 GPT 5.4를 사용하려면 config에서 `opencode/gpt-5.4`를 사용하면 됩니다. +OpenCode config에서 사용하는 [모델 ID](/docs/config/#models)는 `opencode/` 형식입니다. 예를 들어 GPT 5.5를 사용하려면 config에서 `opencode/gpt-5.5`를 사용하면 됩니다. --- diff --git a/packages/web/src/content/docs/nb/zen.mdx b/packages/web/src/content/docs/nb/zen.mdx index 25689ef8c4..6d98347994 100644 --- a/packages/web/src/content/docs/nb/zen.mdx +++ b/packages/web/src/content/docs/nb/zen.mdx @@ -64,6 +64,8 @@ Du kan også få tilgang til modellene våre gjennom følgende API-endepunkter. | Modell | Modell-ID | Endepunkt | AI SDK-pakke | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | diff --git a/packages/web/src/content/docs/pl/zen.mdx b/packages/web/src/content/docs/pl/zen.mdx index 023f22da29..0e2ee0af7d 100644 --- a/packages/web/src/content/docs/pl/zen.mdx +++ b/packages/web/src/content/docs/pl/zen.mdx @@ -64,6 +64,8 @@ Możesz też uzyskać dostęp do naszych modeli przez poniższe endpointy API. | Model | ID modelu | Endpoint | Pakiet AI SDK | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | diff --git a/packages/web/src/content/docs/pt-br/zen.mdx b/packages/web/src/content/docs/pt-br/zen.mdx index 05fabd40ce..73be927b81 100644 --- a/packages/web/src/content/docs/pt-br/zen.mdx +++ b/packages/web/src/content/docs/pt-br/zen.mdx @@ -55,6 +55,8 @@ Você também pode acessar nossos modelos pelos seguintes endpoints de API. | Modelo | ID do modelo | Endpoint | Pacote AI SDK | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | diff --git a/packages/web/src/content/docs/ru/zen.mdx b/packages/web/src/content/docs/ru/zen.mdx index 13184ecf77..92b08e2382 100644 --- a/packages/web/src/content/docs/ru/zen.mdx +++ b/packages/web/src/content/docs/ru/zen.mdx @@ -64,6 +64,8 @@ OpenCode Zen работает как любой другой провайдер | Модель | Идентификатор модели | Конечная точка | Пакет AI SDK | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | diff --git a/packages/web/src/content/docs/th/zen.mdx b/packages/web/src/content/docs/th/zen.mdx index b75e6d5fd6..b082bff008 100644 --- a/packages/web/src/content/docs/th/zen.mdx +++ b/packages/web/src/content/docs/th/zen.mdx @@ -57,6 +57,8 @@ OpenCode Zen ทำงานเหมือน provider อื่น ๆ ใน | Model | Model ID | Endpoint | AI SDK Package | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | diff --git a/packages/web/src/content/docs/tr/zen.mdx b/packages/web/src/content/docs/tr/zen.mdx index a3a1781f0b..bf3d1ac3f6 100644 --- a/packages/web/src/content/docs/tr/zen.mdx +++ b/packages/web/src/content/docs/tr/zen.mdx @@ -55,6 +55,8 @@ Modellerimize aşağıdaki API uç noktaları aracılığıyla da erişebilirsin | Model | Model ID | Endpoint | AI SDK Package | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | diff --git a/packages/web/src/content/docs/zen.mdx b/packages/web/src/content/docs/zen.mdx index d208d3ae5c..97d16618d4 100644 --- a/packages/web/src/content/docs/zen.mdx +++ b/packages/web/src/content/docs/zen.mdx @@ -64,6 +64,8 @@ You can also access our models through the following API endpoints. | Model | Model ID | Endpoint | AI SDK Package | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -105,8 +107,8 @@ You can also access our models through the following API endpoints. | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | The [model id](/docs/config/#models) in your OpenCode config -uses the format `opencode/`. For example, for GPT 5.4, you would -use `opencode/gpt-5.4` in your config. +uses the format `opencode/`. For example, for GPT 5.5, you would +use `opencode/gpt-5.5` in your config. --- @@ -153,6 +155,8 @@ We support a pay-as-you-go model. Below are the prices **per 1M tokens**. | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/zh-cn/zen.mdx b/packages/web/src/content/docs/zh-cn/zen.mdx index 510b936667..a74386e8b9 100644 --- a/packages/web/src/content/docs/zh-cn/zen.mdx +++ b/packages/web/src/content/docs/zh-cn/zen.mdx @@ -55,6 +55,8 @@ OpenCode Zen 的工作方式与 OpenCode 中的任何其他提供商相同。 | 模型 | 模型 ID | 端点 | AI SDK 包 | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | diff --git a/packages/web/src/content/docs/zh-tw/zen.mdx b/packages/web/src/content/docs/zh-tw/zen.mdx index 3634b6eca5..d02b5c290b 100644 --- a/packages/web/src/content/docs/zh-tw/zen.mdx +++ b/packages/web/src/content/docs/zh-tw/zen.mdx @@ -59,6 +59,8 @@ OpenCode Zen 的運作方式和 OpenCode 中的其他供應商一樣。 | 模型 | Model ID | 端點 | AI SDK Package | | --------------------- | --------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.5 | gpt-5.5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.5 Pro | gpt-5.5-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | From 3776d85e15e829fc623427fac122219dd5ea9951 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 24 Apr 2026 14:39:24 -0400 Subject: [PATCH 79/92] zen: gpt-5.5 --- packages/web/src/content/docs/ar/zen.mdx | 2 ++ packages/web/src/content/docs/bs/zen.mdx | 2 ++ packages/web/src/content/docs/da/zen.mdx | 2 ++ packages/web/src/content/docs/de/zen.mdx | 2 ++ packages/web/src/content/docs/es/zen.mdx | 2 ++ packages/web/src/content/docs/fr/zen.mdx | 2 ++ packages/web/src/content/docs/it/zen.mdx | 2 ++ packages/web/src/content/docs/ko/zen.mdx | 2 ++ packages/web/src/content/docs/nb/zen.mdx | 6 ++++-- packages/web/src/content/docs/pl/zen.mdx | 6 ++++-- packages/web/src/content/docs/pt-br/zen.mdx | 4 +++- packages/web/src/content/docs/ru/zen.mdx | 6 ++++-- packages/web/src/content/docs/th/zen.mdx | 4 +++- packages/web/src/content/docs/tr/zen.mdx | 4 +++- packages/web/src/content/docs/zh-cn/zen.mdx | 4 +++- packages/web/src/content/docs/zh-tw/zen.mdx | 4 +++- 16 files changed, 43 insertions(+), 11 deletions(-) diff --git a/packages/web/src/content/docs/ar/zen.mdx b/packages/web/src/content/docs/ar/zen.mdx index 42ab5034c9..7f439675a5 100644 --- a/packages/web/src/content/docs/ar/zen.mdx +++ b/packages/web/src/content/docs/ar/zen.mdx @@ -148,6 +148,8 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/bs/zen.mdx b/packages/web/src/content/docs/bs/zen.mdx index 6bc25b4c13..4e0c7a77af 100644 --- a/packages/web/src/content/docs/bs/zen.mdx +++ b/packages/web/src/content/docs/bs/zen.mdx @@ -155,6 +155,8 @@ Podržavamo pay-as-you-go model. Ispod su cijene **po 1M tokena**. | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/da/zen.mdx b/packages/web/src/content/docs/da/zen.mdx index 51bae8ef63..0113f8b15d 100644 --- a/packages/web/src/content/docs/da/zen.mdx +++ b/packages/web/src/content/docs/da/zen.mdx @@ -155,6 +155,8 @@ Vi understøtter en pay-as-you-go-model. Nedenfor er priserne **pr. 1M tokens**. | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/de/zen.mdx b/packages/web/src/content/docs/de/zen.mdx index 30a78ddd61..2aaba57fbf 100644 --- a/packages/web/src/content/docs/de/zen.mdx +++ b/packages/web/src/content/docs/de/zen.mdx @@ -144,6 +144,8 @@ Wir unterstützen ein Pay-as-you-go-Modell. Unten findest du die Preise **pro 1M | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/es/zen.mdx b/packages/web/src/content/docs/es/zen.mdx index 9534c61de6..f775a4633d 100644 --- a/packages/web/src/content/docs/es/zen.mdx +++ b/packages/web/src/content/docs/es/zen.mdx @@ -155,6 +155,8 @@ Admitimos un modelo de pago por uso. A continuación se muestran los precios **p | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/fr/zen.mdx b/packages/web/src/content/docs/fr/zen.mdx index cd2a621f53..3791856586 100644 --- a/packages/web/src/content/docs/fr/zen.mdx +++ b/packages/web/src/content/docs/fr/zen.mdx @@ -144,6 +144,8 @@ Nous prenons en charge un modèle de paiement à l'utilisation. Vous trouverez c | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/it/zen.mdx b/packages/web/src/content/docs/it/zen.mdx index 451d407510..19de7dc0a3 100644 --- a/packages/web/src/content/docs/it/zen.mdx +++ b/packages/web/src/content/docs/it/zen.mdx @@ -155,6 +155,8 @@ Supportiamo un modello pay-as-you-go. Qui sotto trovi i prezzi **per 1M token**. | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/ko/zen.mdx b/packages/web/src/content/docs/ko/zen.mdx index 1fc661da6d..31276d18bd 100644 --- a/packages/web/src/content/docs/ko/zen.mdx +++ b/packages/web/src/content/docs/ko/zen.mdx @@ -144,6 +144,8 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/nb/zen.mdx b/packages/web/src/content/docs/nb/zen.mdx index 6d98347994..08e13d4c8d 100644 --- a/packages/web/src/content/docs/nb/zen.mdx +++ b/packages/web/src/content/docs/nb/zen.mdx @@ -107,8 +107,8 @@ Du kan også få tilgang til modellene våre gjennom følgende API-endepunkter. | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | [modell-id](/docs/config/#models) i OpenCode-konfigurasjonen din -bruker formatet `opencode/`. For eksempel, for GPT 5.4, ville du -brukt `opencode/gpt-5.4` i konfigurasjonen din. +bruker formatet `opencode/`. For eksempel, for GPT 5.5, ville du +brukt `opencode/gpt-5.5` i konfigurasjonen din. --- @@ -155,6 +155,8 @@ Vi støtter en pay-as-you-go-modell. Nedenfor er prisene **per 1M tokens**. | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/pl/zen.mdx b/packages/web/src/content/docs/pl/zen.mdx index 0e2ee0af7d..84d4e2d806 100644 --- a/packages/web/src/content/docs/pl/zen.mdx +++ b/packages/web/src/content/docs/pl/zen.mdx @@ -107,8 +107,8 @@ Możesz też uzyskać dostęp do naszych modeli przez poniższe endpointy API. | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | [ID modelu](/docs/config/#models) w Twojej konfiguracji OpenCode używa formatu -`opencode/`. Na przykład dla GPT 5.4 użyjesz w konfiguracji -`opencode/gpt-5.4`. +`opencode/`. Na przykład dla GPT 5.5 użyjesz w konfiguracji +`opencode/gpt-5.5`. --- @@ -155,6 +155,8 @@ Obsługujemy model pay-as-you-go. Poniżej znajdują się ceny **za 1M tokenów* | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/pt-br/zen.mdx b/packages/web/src/content/docs/pt-br/zen.mdx index 73be927b81..d67f065441 100644 --- a/packages/web/src/content/docs/pt-br/zen.mdx +++ b/packages/web/src/content/docs/pt-br/zen.mdx @@ -97,7 +97,7 @@ Você também pode acessar nossos modelos pelos seguintes endpoints de API. | Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -O [model id](/docs/config/#models) na sua configuração do OpenCode usa o formato `opencode/`. Por exemplo, para GPT 5.4, você usaria `opencode/gpt-5.4` na sua configuração. +O [model id](/docs/config/#models) na sua configuração do OpenCode usa o formato `opencode/`. Por exemplo, para GPT 5.5, você usaria `opencode/gpt-5.5` na sua configuração. --- @@ -144,6 +144,8 @@ Oferecemos um modelo pay-as-you-go. Abaixo estão os preços **por 1M tokens**. | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/ru/zen.mdx b/packages/web/src/content/docs/ru/zen.mdx index 92b08e2382..422f14bdf2 100644 --- a/packages/web/src/content/docs/ru/zen.mdx +++ b/packages/web/src/content/docs/ru/zen.mdx @@ -107,8 +107,8 @@ OpenCode Zen работает как любой другой провайдер | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | [идентификатор модели](/docs/config/#models) в вашей конфигурации OpenCode -использует формат `opencode/`. Например, для GPT 5.4 вам нужно -использовать `opencode/gpt-5.4` в своей конфигурации. +использует формат `opencode/`. Например, для GPT 5.5 вам нужно +использовать `opencode/gpt-5.5` в своей конфигурации. --- @@ -155,6 +155,8 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/th/zen.mdx b/packages/web/src/content/docs/th/zen.mdx index b082bff008..0ac427c02f 100644 --- a/packages/web/src/content/docs/th/zen.mdx +++ b/packages/web/src/content/docs/th/zen.mdx @@ -99,7 +99,7 @@ OpenCode Zen ทำงานเหมือน provider อื่น ๆ ใน | Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -[model id](/docs/config/#models) ใน OpenCode config ของคุณใช้รูปแบบ `opencode/` ตัวอย่างเช่น สำหรับ GPT 5.4 คุณจะใช้ `opencode/gpt-5.4` ใน config ของคุณ +[model id](/docs/config/#models) ใน OpenCode config ของคุณใช้รูปแบบ `opencode/` ตัวอย่างเช่น สำหรับ GPT 5.5 คุณจะใช้ `opencode/gpt-5.5` ใน config ของคุณ --- @@ -146,6 +146,8 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/tr/zen.mdx b/packages/web/src/content/docs/tr/zen.mdx index bf3d1ac3f6..eda5cf1b49 100644 --- a/packages/web/src/content/docs/tr/zen.mdx +++ b/packages/web/src/content/docs/tr/zen.mdx @@ -97,7 +97,7 @@ Modellerimize aşağıdaki API uç noktaları aracılığıyla da erişebilirsin | Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -OpenCode yapılandırmanızdaki [model id](/docs/config/#models) `opencode/` biçimini kullanır. Örneğin, GPT 5.4 için yapılandırmanızda `opencode/gpt-5.4` kullanırsınız. +OpenCode yapılandırmanızdaki [model id](/docs/config/#models) `opencode/` biçimini kullanır. Örneğin, GPT 5.5 için yapılandırmanızda `opencode/gpt-5.5` kullanırsınız. --- @@ -144,6 +144,8 @@ Kullandıkça öde modelini destekliyoruz. Aşağıda **1M token başına** fiya | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/zh-cn/zen.mdx b/packages/web/src/content/docs/zh-cn/zen.mdx index a74386e8b9..57f2d1659d 100644 --- a/packages/web/src/content/docs/zh-cn/zen.mdx +++ b/packages/web/src/content/docs/zh-cn/zen.mdx @@ -97,7 +97,7 @@ OpenCode Zen 的工作方式与 OpenCode 中的任何其他提供商相同。 | Hy3 Preview Free | hy3-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -在你的 OpenCode 配置中,[模型 ID](/docs/config/#models) 使用 `opencode/` 格式。例如,对于 GPT 5.4,你需要在配置中使用 `opencode/gpt-5.4`。 +在你的 OpenCode 配置中,[模型 ID](/docs/config/#models) 使用 `opencode/` 格式。例如,对于 GPT 5.5,你需要在配置中使用 `opencode/gpt-5.5`。 --- @@ -144,6 +144,8 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/zh-tw/zen.mdx b/packages/web/src/content/docs/zh-tw/zen.mdx index d02b5c290b..9c63cf4b20 100644 --- a/packages/web/src/content/docs/zh-tw/zen.mdx +++ b/packages/web/src/content/docs/zh-tw/zen.mdx @@ -102,7 +102,7 @@ OpenCode Zen 的運作方式和 OpenCode 中的其他供應商一樣。 | Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | OpenCode 設定中的 [模型 ID](/docs/config/#models) 會使用 `opencode/` -格式。例如,如果是 GPT 5.4,你會在設定中使用 `opencode/gpt-5.4`。 +格式。例如,如果是 GPT 5.5,你會在設定中使用 `opencode/gpt-5.5`。 --- @@ -149,6 +149,8 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | From 4dab2a8555dabdc40109cc79d7528fca452bbdab Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 24 Apr 2026 14:43:04 -0400 Subject: [PATCH 80/92] zen: gpt-5.5 --- packages/web/src/content/docs/ar/zen.mdx | 2 +- packages/web/src/content/docs/bs/zen.mdx | 2 +- packages/web/src/content/docs/da/zen.mdx | 2 +- packages/web/src/content/docs/de/zen.mdx | 2 +- packages/web/src/content/docs/es/zen.mdx | 2 +- packages/web/src/content/docs/fr/zen.mdx | 2 +- packages/web/src/content/docs/it/zen.mdx | 2 +- packages/web/src/content/docs/ja/zen.mdx | 2 +- packages/web/src/content/docs/ko/zen.mdx | 2 +- packages/web/src/content/docs/nb/zen.mdx | 2 +- packages/web/src/content/docs/pl/zen.mdx | 2 +- packages/web/src/content/docs/pt-br/zen.mdx | 2 +- packages/web/src/content/docs/ru/zen.mdx | 2 +- packages/web/src/content/docs/th/zen.mdx | 2 +- packages/web/src/content/docs/tr/zen.mdx | 2 +- packages/web/src/content/docs/zen.mdx | 2 +- packages/web/src/content/docs/zh-cn/zen.mdx | 2 +- packages/web/src/content/docs/zh-tw/zen.mdx | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/web/src/content/docs/ar/zen.mdx b/packages/web/src/content/docs/ar/zen.mdx index 7f439675a5..17fb0020fe 100644 --- a/packages/web/src/content/docs/ar/zen.mdx +++ b/packages/web/src/content/docs/ar/zen.mdx @@ -149,7 +149,7 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/bs/zen.mdx b/packages/web/src/content/docs/bs/zen.mdx index 4e0c7a77af..c57ceb001b 100644 --- a/packages/web/src/content/docs/bs/zen.mdx +++ b/packages/web/src/content/docs/bs/zen.mdx @@ -156,7 +156,7 @@ Podržavamo pay-as-you-go model. Ispod su cijene **po 1M tokena**. | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/da/zen.mdx b/packages/web/src/content/docs/da/zen.mdx index 0113f8b15d..234ea63eef 100644 --- a/packages/web/src/content/docs/da/zen.mdx +++ b/packages/web/src/content/docs/da/zen.mdx @@ -156,7 +156,7 @@ Vi understøtter en pay-as-you-go-model. Nedenfor er priserne **pr. 1M tokens**. | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/de/zen.mdx b/packages/web/src/content/docs/de/zen.mdx index 2aaba57fbf..4fc54e12b4 100644 --- a/packages/web/src/content/docs/de/zen.mdx +++ b/packages/web/src/content/docs/de/zen.mdx @@ -145,7 +145,7 @@ Wir unterstützen ein Pay-as-you-go-Modell. Unten findest du die Preise **pro 1M | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/es/zen.mdx b/packages/web/src/content/docs/es/zen.mdx index f775a4633d..36da8a2819 100644 --- a/packages/web/src/content/docs/es/zen.mdx +++ b/packages/web/src/content/docs/es/zen.mdx @@ -156,7 +156,7 @@ Admitimos un modelo de pago por uso. A continuación se muestran los precios **p | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/fr/zen.mdx b/packages/web/src/content/docs/fr/zen.mdx index 3791856586..1c5b45a085 100644 --- a/packages/web/src/content/docs/fr/zen.mdx +++ b/packages/web/src/content/docs/fr/zen.mdx @@ -145,7 +145,7 @@ Nous prenons en charge un modèle de paiement à l'utilisation. Vous trouverez c | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/it/zen.mdx b/packages/web/src/content/docs/it/zen.mdx index 19de7dc0a3..70c08152ea 100644 --- a/packages/web/src/content/docs/it/zen.mdx +++ b/packages/web/src/content/docs/it/zen.mdx @@ -156,7 +156,7 @@ Supportiamo un modello pay-as-you-go. Qui sotto trovi i prezzi **per 1M token**. | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/ja/zen.mdx b/packages/web/src/content/docs/ja/zen.mdx index 0d142a73fb..f7793544be 100644 --- a/packages/web/src/content/docs/ja/zen.mdx +++ b/packages/web/src/content/docs/ja/zen.mdx @@ -145,7 +145,7 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/ko/zen.mdx b/packages/web/src/content/docs/ko/zen.mdx index 31276d18bd..a49413b871 100644 --- a/packages/web/src/content/docs/ko/zen.mdx +++ b/packages/web/src/content/docs/ko/zen.mdx @@ -145,7 +145,7 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/nb/zen.mdx b/packages/web/src/content/docs/nb/zen.mdx index 08e13d4c8d..400256a453 100644 --- a/packages/web/src/content/docs/nb/zen.mdx +++ b/packages/web/src/content/docs/nb/zen.mdx @@ -156,7 +156,7 @@ Vi støtter en pay-as-you-go-modell. Nedenfor er prisene **per 1M tokens**. | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/pl/zen.mdx b/packages/web/src/content/docs/pl/zen.mdx index 84d4e2d806..200f696316 100644 --- a/packages/web/src/content/docs/pl/zen.mdx +++ b/packages/web/src/content/docs/pl/zen.mdx @@ -156,7 +156,7 @@ Obsługujemy model pay-as-you-go. Poniżej znajdują się ceny **za 1M tokenów* | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/pt-br/zen.mdx b/packages/web/src/content/docs/pt-br/zen.mdx index d67f065441..8b69c7ccbe 100644 --- a/packages/web/src/content/docs/pt-br/zen.mdx +++ b/packages/web/src/content/docs/pt-br/zen.mdx @@ -145,7 +145,7 @@ Oferecemos um modelo pay-as-you-go. Abaixo estão os preços **por 1M tokens**. | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/ru/zen.mdx b/packages/web/src/content/docs/ru/zen.mdx index 422f14bdf2..d2c24ae9a4 100644 --- a/packages/web/src/content/docs/ru/zen.mdx +++ b/packages/web/src/content/docs/ru/zen.mdx @@ -156,7 +156,7 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/th/zen.mdx b/packages/web/src/content/docs/th/zen.mdx index 0ac427c02f..64003550c9 100644 --- a/packages/web/src/content/docs/th/zen.mdx +++ b/packages/web/src/content/docs/th/zen.mdx @@ -147,7 +147,7 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/tr/zen.mdx b/packages/web/src/content/docs/tr/zen.mdx index eda5cf1b49..1f0a7005b4 100644 --- a/packages/web/src/content/docs/tr/zen.mdx +++ b/packages/web/src/content/docs/tr/zen.mdx @@ -145,7 +145,7 @@ Kullandıkça öde modelini destekliyoruz. Aşağıda **1M token başına** fiya | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/zen.mdx b/packages/web/src/content/docs/zen.mdx index 97d16618d4..d377e4a2a4 100644 --- a/packages/web/src/content/docs/zen.mdx +++ b/packages/web/src/content/docs/zen.mdx @@ -156,7 +156,7 @@ We support a pay-as-you-go model. Below are the prices **per 1M tokens**. | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/zh-cn/zen.mdx b/packages/web/src/content/docs/zh-cn/zen.mdx index 57f2d1659d..edd623df5d 100644 --- a/packages/web/src/content/docs/zh-cn/zen.mdx +++ b/packages/web/src/content/docs/zh-cn/zen.mdx @@ -145,7 +145,7 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | diff --git a/packages/web/src/content/docs/zh-tw/zen.mdx b/packages/web/src/content/docs/zh-tw/zen.mdx index 9c63cf4b20..42bff33d99 100644 --- a/packages/web/src/content/docs/zh-tw/zen.mdx +++ b/packages/web/src/content/docs/zh-tw/zen.mdx @@ -150,7 +150,7 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | | GPT 5.5 | $5.00 | $30.00 | $0.50 | - | -| GPT 5.5 Pro | $60.00 | $360.00 | $60.00 | - | +| GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 | $2.50 | $15.00 | $0.25 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | From 0405bc74e9f0251115232bba62d14d152406675a Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 24 Apr 2026 14:57:23 -0400 Subject: [PATCH 81/92] zen: gpt-5.5 --- packages/web/src/content/docs/ar/zen.mdx | 6 ++++-- packages/web/src/content/docs/bs/zen.mdx | 6 ++++-- packages/web/src/content/docs/da/zen.mdx | 6 ++++-- packages/web/src/content/docs/de/zen.mdx | 6 ++++-- packages/web/src/content/docs/es/zen.mdx | 6 ++++-- packages/web/src/content/docs/fr/zen.mdx | 6 ++++-- packages/web/src/content/docs/it/zen.mdx | 6 ++++-- packages/web/src/content/docs/ja/zen.mdx | 6 ++++-- packages/web/src/content/docs/ko/zen.mdx | 6 ++++-- packages/web/src/content/docs/nb/zen.mdx | 6 ++++-- packages/web/src/content/docs/pl/zen.mdx | 6 ++++-- packages/web/src/content/docs/pt-br/zen.mdx | 6 ++++-- packages/web/src/content/docs/ru/zen.mdx | 6 ++++-- packages/web/src/content/docs/th/zen.mdx | 6 ++++-- packages/web/src/content/docs/tr/zen.mdx | 6 ++++-- packages/web/src/content/docs/zen.mdx | 6 ++++-- packages/web/src/content/docs/zh-cn/zen.mdx | 6 ++++-- packages/web/src/content/docs/zh-tw/zen.mdx | 6 ++++-- 18 files changed, 72 insertions(+), 36 deletions(-) diff --git a/packages/web/src/content/docs/ar/zen.mdx b/packages/web/src/content/docs/ar/zen.mdx index 17fb0020fe..9f7ed302ed 100644 --- a/packages/web/src/content/docs/ar/zen.mdx +++ b/packages/web/src/content/docs/ar/zen.mdx @@ -148,9 +148,11 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | diff --git a/packages/web/src/content/docs/bs/zen.mdx b/packages/web/src/content/docs/bs/zen.mdx index c57ceb001b..d10e4f87f6 100644 --- a/packages/web/src/content/docs/bs/zen.mdx +++ b/packages/web/src/content/docs/bs/zen.mdx @@ -155,9 +155,11 @@ Podržavamo pay-as-you-go model. Ispod su cijene **po 1M tokena**. | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | diff --git a/packages/web/src/content/docs/da/zen.mdx b/packages/web/src/content/docs/da/zen.mdx index 234ea63eef..44df1602ab 100644 --- a/packages/web/src/content/docs/da/zen.mdx +++ b/packages/web/src/content/docs/da/zen.mdx @@ -155,9 +155,11 @@ Vi understøtter en pay-as-you-go-model. Nedenfor er priserne **pr. 1M tokens**. | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | diff --git a/packages/web/src/content/docs/de/zen.mdx b/packages/web/src/content/docs/de/zen.mdx index 4fc54e12b4..61a03e7c24 100644 --- a/packages/web/src/content/docs/de/zen.mdx +++ b/packages/web/src/content/docs/de/zen.mdx @@ -144,9 +144,11 @@ Wir unterstützen ein Pay-as-you-go-Modell. Unten findest du die Preise **pro 1M | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | diff --git a/packages/web/src/content/docs/es/zen.mdx b/packages/web/src/content/docs/es/zen.mdx index 36da8a2819..f0df78118c 100644 --- a/packages/web/src/content/docs/es/zen.mdx +++ b/packages/web/src/content/docs/es/zen.mdx @@ -155,9 +155,11 @@ Admitimos un modelo de pago por uso. A continuación se muestran los precios **p | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | diff --git a/packages/web/src/content/docs/fr/zen.mdx b/packages/web/src/content/docs/fr/zen.mdx index 1c5b45a085..09fa4699a8 100644 --- a/packages/web/src/content/docs/fr/zen.mdx +++ b/packages/web/src/content/docs/fr/zen.mdx @@ -144,9 +144,11 @@ Nous prenons en charge un modèle de paiement à l'utilisation. Vous trouverez c | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | diff --git a/packages/web/src/content/docs/it/zen.mdx b/packages/web/src/content/docs/it/zen.mdx index 70c08152ea..36c4fd3e84 100644 --- a/packages/web/src/content/docs/it/zen.mdx +++ b/packages/web/src/content/docs/it/zen.mdx @@ -155,9 +155,11 @@ Supportiamo un modello pay-as-you-go. Qui sotto trovi i prezzi **per 1M token**. | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | diff --git a/packages/web/src/content/docs/ja/zen.mdx b/packages/web/src/content/docs/ja/zen.mdx index f7793544be..504f1fd786 100644 --- a/packages/web/src/content/docs/ja/zen.mdx +++ b/packages/web/src/content/docs/ja/zen.mdx @@ -144,9 +144,11 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | diff --git a/packages/web/src/content/docs/ko/zen.mdx b/packages/web/src/content/docs/ko/zen.mdx index a49413b871..222f494bcf 100644 --- a/packages/web/src/content/docs/ko/zen.mdx +++ b/packages/web/src/content/docs/ko/zen.mdx @@ -144,9 +144,11 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | diff --git a/packages/web/src/content/docs/nb/zen.mdx b/packages/web/src/content/docs/nb/zen.mdx index 400256a453..c86c282e7d 100644 --- a/packages/web/src/content/docs/nb/zen.mdx +++ b/packages/web/src/content/docs/nb/zen.mdx @@ -155,9 +155,11 @@ Vi støtter en pay-as-you-go-modell. Nedenfor er prisene **per 1M tokens**. | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | diff --git a/packages/web/src/content/docs/pl/zen.mdx b/packages/web/src/content/docs/pl/zen.mdx index 200f696316..0788889656 100644 --- a/packages/web/src/content/docs/pl/zen.mdx +++ b/packages/web/src/content/docs/pl/zen.mdx @@ -155,9 +155,11 @@ Obsługujemy model pay-as-you-go. Poniżej znajdują się ceny **za 1M tokenów* | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | diff --git a/packages/web/src/content/docs/pt-br/zen.mdx b/packages/web/src/content/docs/pt-br/zen.mdx index 8b69c7ccbe..a72a9a90bf 100644 --- a/packages/web/src/content/docs/pt-br/zen.mdx +++ b/packages/web/src/content/docs/pt-br/zen.mdx @@ -144,9 +144,11 @@ Oferecemos um modelo pay-as-you-go. Abaixo estão os preços **por 1M tokens**. | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | diff --git a/packages/web/src/content/docs/ru/zen.mdx b/packages/web/src/content/docs/ru/zen.mdx index d2c24ae9a4..84fedeb107 100644 --- a/packages/web/src/content/docs/ru/zen.mdx +++ b/packages/web/src/content/docs/ru/zen.mdx @@ -155,9 +155,11 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | diff --git a/packages/web/src/content/docs/th/zen.mdx b/packages/web/src/content/docs/th/zen.mdx index 64003550c9..efb896601c 100644 --- a/packages/web/src/content/docs/th/zen.mdx +++ b/packages/web/src/content/docs/th/zen.mdx @@ -146,9 +146,11 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | diff --git a/packages/web/src/content/docs/tr/zen.mdx b/packages/web/src/content/docs/tr/zen.mdx index 1f0a7005b4..c505662cbe 100644 --- a/packages/web/src/content/docs/tr/zen.mdx +++ b/packages/web/src/content/docs/tr/zen.mdx @@ -144,9 +144,11 @@ Kullandıkça öde modelini destekliyoruz. Aşağıda **1M token başına** fiya | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | diff --git a/packages/web/src/content/docs/zen.mdx b/packages/web/src/content/docs/zen.mdx index d377e4a2a4..6ebf78336a 100644 --- a/packages/web/src/content/docs/zen.mdx +++ b/packages/web/src/content/docs/zen.mdx @@ -155,9 +155,11 @@ We support a pay-as-you-go model. Below are the prices **per 1M tokens**. | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | diff --git a/packages/web/src/content/docs/zh-cn/zen.mdx b/packages/web/src/content/docs/zh-cn/zen.mdx index edd623df5d..9248ff174c 100644 --- a/packages/web/src/content/docs/zh-cn/zen.mdx +++ b/packages/web/src/content/docs/zh-cn/zen.mdx @@ -144,9 +144,11 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | diff --git a/packages/web/src/content/docs/zh-tw/zen.mdx b/packages/web/src/content/docs/zh-tw/zen.mdx index 42bff33d99..3be6a3da00 100644 --- a/packages/web/src/content/docs/zh-tw/zen.mdx +++ b/packages/web/src/content/docs/zh-tw/zen.mdx @@ -149,9 +149,11 @@ https://opencode.ai/zen/v1/models | Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.5 | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (≤ 272K tokens) | $5.00 | $30.00 | $0.50 | - | +| GPT 5.5 (> 272K tokens) | $10.00 | $45.00 | $1.00 | - | | GPT 5.5 Pro | $30.00 | $180.00 | $30.00 | - | -| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | - | +| GPT 5.4 (> 272K tokens) | $5.00 | $22.50 | $0.50 | - | | GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | | GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - | | GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - | From 435becbea01183ab3dd5581067c64f885b93c2d8 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Fri, 24 Apr 2026 17:11:07 -0400 Subject: [PATCH 82/92] Refactor HttpApi auth middleware wiring (#24168) --- .../server/routes/instance/httpapi/auth.ts | 66 +++++++++++++++ .../server/routes/instance/httpapi/config.ts | 4 +- .../server/routes/instance/httpapi/file.ts | 4 +- .../src/server/routes/instance/httpapi/mcp.ts | 4 +- .../routes/instance/httpapi/permission.ts | 4 +- .../server/routes/instance/httpapi/project.ts | 4 +- .../routes/instance/httpapi/provider.ts | 4 +- .../routes/instance/httpapi/question.ts | 4 +- .../server/routes/instance/httpapi/server.ts | 84 +++---------------- .../routes/instance/httpapi/workspace.ts | 4 +- 10 files changed, 102 insertions(+), 80 deletions(-) create mode 100644 packages/opencode/src/server/routes/instance/httpapi/auth.ts diff --git a/packages/opencode/src/server/routes/instance/httpapi/auth.ts b/packages/opencode/src/server/routes/instance/httpapi/auth.ts new file mode 100644 index 0000000000..adddcc4bed --- /dev/null +++ b/packages/opencode/src/server/routes/instance/httpapi/auth.ts @@ -0,0 +1,66 @@ +import { Effect, Encoding, Layer, Redacted, Schema } from "effect" +import { HttpApiMiddleware, HttpApiSecurity } from "effect/unstable/httpapi" +import { Flag } from "@/flag/flag" + +class Unauthorized extends Schema.TaggedErrorClass()( + "Unauthorized", + { message: Schema.String }, + { httpApiStatus: 401 }, +) {} + +export class Authorization extends HttpApiMiddleware.Service()("@opencode/ExperimentalHttpApiAuthorization", { + error: Unauthorized, + security: { + basic: HttpApiSecurity.basic, + authToken: HttpApiSecurity.apiKey({ in: "query", key: "auth_token" }), + }, +}) {} + +const emptyCredential = { + username: "", + password: Redacted.make(""), +} + +function validateCredential( + effect: Effect.Effect, + credential: { readonly username: string; readonly password: typeof emptyCredential.password }, +) { + return Effect.gen(function* () { + if (!Flag.OPENCODE_SERVER_PASSWORD) return yield* effect + + if (credential.username !== (Flag.OPENCODE_SERVER_USERNAME ?? "opencode")) { + return yield* new Unauthorized({ message: "Unauthorized" }) + } + if (Redacted.value(credential.password) !== Flag.OPENCODE_SERVER_PASSWORD) { + return yield* new Unauthorized({ message: "Unauthorized" }) + } + return yield* effect + }) +} + +function decodeCredential(input: string) { + return Encoding.decodeBase64String(input).asEffect().pipe( + Effect.match({ + onFailure: () => emptyCredential, + onSuccess: (header) => { + const parts = header.split(":") + if (parts.length !== 2) return emptyCredential + return { + username: parts[0], + password: Redacted.make(parts[1]), + } + }, + }), + ) +} + +export const authorizationLayer = Layer.succeed( + Authorization, + Authorization.of({ + basic: (effect, { credential }) => validateCredential(effect, credential), + authToken: (effect, { credential }) => + Effect.gen(function* () { + return yield* validateCredential(effect, yield* decodeCredential(Redacted.value(credential))) + }), + }), +) diff --git a/packages/opencode/src/server/routes/instance/httpapi/config.ts b/packages/opencode/src/server/routes/instance/httpapi/config.ts index 2dfdec172a..fcdf6d1a33 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/config.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/config.ts @@ -2,6 +2,7 @@ import { Config } from "@/config" import { Provider } from "@/provider" import { Effect, Layer } from "effect" import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { Authorization } from "./auth" const root = "/config" @@ -33,7 +34,8 @@ export const ConfigApi = HttpApi.make("config") title: "config", description: "Experimental HttpApi config routes.", }), - ), + ) + .middleware(Authorization), ) .annotateMerge( OpenApi.annotations({ diff --git a/packages/opencode/src/server/routes/instance/httpapi/file.ts b/packages/opencode/src/server/routes/instance/httpapi/file.ts index eaf43862ad..c55d0c2e71 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/file.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/file.ts @@ -1,6 +1,7 @@ import { File } from "@/file" import { Effect, Layer, Schema } from "effect" import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { Authorization } from "./auth" const FileQuery = Schema.Struct({ path: Schema.String, @@ -51,7 +52,8 @@ export const FileApi = HttpApi.make("file") title: "file", description: "Experimental HttpApi file routes.", }), - ), + ) + .middleware(Authorization), ) .annotateMerge( OpenApi.annotations({ diff --git a/packages/opencode/src/server/routes/instance/httpapi/mcp.ts b/packages/opencode/src/server/routes/instance/httpapi/mcp.ts index 91467b1e90..34d4e09e2d 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/mcp.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/mcp.ts @@ -1,6 +1,7 @@ import { MCP } from "@/mcp" import { Effect, Layer, Schema } from "effect" import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { Authorization } from "./auth" export const McpPaths = { status: "/mcp", @@ -25,7 +26,8 @@ export const McpApi = HttpApi.make("mcp") title: "mcp", description: "Experimental HttpApi MCP routes.", }), - ), + ) + .middleware(Authorization), ) .annotateMerge( OpenApi.annotations({ diff --git a/packages/opencode/src/server/routes/instance/httpapi/permission.ts b/packages/opencode/src/server/routes/instance/httpapi/permission.ts index ed8cb4e277..85dbecd116 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/permission.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/permission.ts @@ -2,6 +2,7 @@ import { Permission } from "@/permission" import { PermissionID } from "@/permission/schema" import { Effect, Layer, Schema } from "effect" import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { Authorization } from "./auth" const root = "/permission" @@ -35,7 +36,8 @@ export const PermissionApi = HttpApi.make("permission") title: "permission", description: "Experimental HttpApi permission routes.", }), - ), + ) + .middleware(Authorization), ) .annotateMerge( OpenApi.annotations({ diff --git a/packages/opencode/src/server/routes/instance/httpapi/project.ts b/packages/opencode/src/server/routes/instance/httpapi/project.ts index 7d2d8462f0..10cf25118f 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/project.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/project.ts @@ -2,6 +2,7 @@ import { Instance } from "@/project/instance" import { Project } from "@/project" import { Effect, Layer, Schema } from "effect" import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { Authorization } from "./auth" const root = "/project" @@ -33,7 +34,8 @@ export const ProjectApi = HttpApi.make("project") title: "project", description: "Experimental HttpApi project routes.", }), - ), + ) + .middleware(Authorization), ) .annotateMerge( OpenApi.annotations({ diff --git a/packages/opencode/src/server/routes/instance/httpapi/provider.ts b/packages/opencode/src/server/routes/instance/httpapi/provider.ts index 67831a1faf..dd1a21d2b0 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/provider.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/provider.ts @@ -6,6 +6,7 @@ import { ProviderID } from "@/provider/schema" import { mapValues } from "remeda" import { Effect, Layer, Schema } from "effect" import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiError, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { Authorization } from "./auth" const root = "/provider" @@ -59,7 +60,8 @@ export const ProviderApi = HttpApi.make("provider") title: "provider", description: "Experimental HttpApi provider routes.", }), - ), + ) + .middleware(Authorization), ) .annotateMerge( OpenApi.annotations({ diff --git a/packages/opencode/src/server/routes/instance/httpapi/question.ts b/packages/opencode/src/server/routes/instance/httpapi/question.ts index 3192b530e9..526a78ee0a 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/question.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/question.ts @@ -2,6 +2,7 @@ import { Question } from "@/question" import { QuestionID } from "@/question/schema" import { Effect, Layer, Schema } from "effect" import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { Authorization } from "./auth" const root = "/question" @@ -45,7 +46,8 @@ export const QuestionApi = HttpApi.make("question") title: "question", description: "Question routes.", }), - ), + ) + .middleware(Authorization), ) .annotateMerge( OpenApi.annotations({ diff --git a/packages/opencode/src/server/routes/instance/httpapi/server.ts b/packages/opencode/src/server/routes/instance/httpapi/server.ts index b45ad942b7..14c2550ed2 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/server.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/server.ts @@ -1,14 +1,14 @@ -import { Effect, Layer, Redacted, Schema } from "effect" -import { HttpApiBuilder, HttpApiMiddleware, HttpApiSecurity } from "effect/unstable/httpapi" +import { Effect, Layer, Schema } from "effect" +import { HttpApiBuilder } from "effect/unstable/httpapi" import { HttpRouter, HttpServer, HttpServerRequest } from "effect/unstable/http" import { AppRuntime } from "@/effect/app-runtime" import { InstanceRef, WorkspaceRef } from "@/effect/instance-ref" import { Observability } from "@/effect" -import { Flag } from "@/flag/flag" import { InstanceBootstrap } from "@/project/bootstrap" import { Instance } from "@/project/instance" import { lazy } from "@/util/lazy" import { Filesystem } from "@/util" +import { authorizationLayer } from "./auth" import { ConfigApi, configHandlers } from "./config" import { FileApi, fileHandlers } from "./file" import { McpApi, mcpHandlers } from "./mcp" @@ -38,56 +38,6 @@ function decode(input: string) { } } -class Unauthorized extends Schema.TaggedErrorClass()( - "Unauthorized", - { message: Schema.String }, - { httpApiStatus: 401 }, -) {} - -class Authorization extends HttpApiMiddleware.Service()("@opencode/ExperimentalHttpApiAuthorization", { - error: Unauthorized, - security: { - basic: HttpApiSecurity.basic, - }, -}) {} - -const normalize = HttpRouter.middleware()( - Effect.gen(function* () { - return (effect) => - Effect.gen(function* () { - const query = yield* HttpServerRequest.schemaSearchParams(Query) - if (!query.auth_token) return yield* effect - const req = yield* HttpServerRequest.HttpServerRequest - const next = req.modify({ - headers: { - ...req.headers, - authorization: `Basic ${query.auth_token}`, - }, - }) - return yield* effect.pipe(Effect.provideService(HttpServerRequest.HttpServerRequest, next)) - }) - }), -).layer - -const auth = Layer.succeed( - Authorization, - Authorization.of({ - basic: (effect, { credential }) => - Effect.gen(function* () { - if (!Flag.OPENCODE_SERVER_PASSWORD) return yield* effect - - const user = Flag.OPENCODE_SERVER_USERNAME ?? "opencode" - if (credential.username !== user) { - return yield* new Unauthorized({ message: "Unauthorized" }) - } - if (Redacted.value(credential.password) !== Flag.OPENCODE_SERVER_PASSWORD) { - return yield* new Unauthorized({ message: "Unauthorized" }) - } - return yield* effect - }), - }), -) - const instance = HttpRouter.middleware()( Effect.gen(function* () { return (effect) => @@ -110,27 +60,17 @@ const instance = HttpRouter.middleware()( }), ).layer -const QuestionSecured = QuestionApi.middleware(Authorization) -const PermissionSecured = PermissionApi.middleware(Authorization) -const ProjectSecured = ProjectApi.middleware(Authorization) -const ProviderSecured = ProviderApi.middleware(Authorization) -const ConfigSecured = ConfigApi.middleware(Authorization) -const WorkspaceSecured = WorkspaceApi.middleware(Authorization) -const FileSecured = FileApi.middleware(Authorization) -const McpSecured = McpApi.middleware(Authorization) - export const routes = Layer.mergeAll( - HttpApiBuilder.layer(ConfigSecured).pipe(Layer.provide(configHandlers)), - HttpApiBuilder.layer(FileSecured).pipe(Layer.provide(fileHandlers)), - HttpApiBuilder.layer(McpSecured).pipe(Layer.provide(mcpHandlers)), - HttpApiBuilder.layer(ProjectSecured).pipe(Layer.provide(projectHandlers)), - HttpApiBuilder.layer(QuestionSecured).pipe(Layer.provide(questionHandlers)), - HttpApiBuilder.layer(PermissionSecured).pipe(Layer.provide(permissionHandlers)), - HttpApiBuilder.layer(ProviderSecured).pipe(Layer.provide(providerHandlers)), - HttpApiBuilder.layer(WorkspaceSecured).pipe(Layer.provide(workspaceHandlers)), + HttpApiBuilder.layer(ConfigApi).pipe(Layer.provide(configHandlers)), + HttpApiBuilder.layer(FileApi).pipe(Layer.provide(fileHandlers)), + HttpApiBuilder.layer(McpApi).pipe(Layer.provide(mcpHandlers)), + HttpApiBuilder.layer(ProjectApi).pipe(Layer.provide(projectHandlers)), + HttpApiBuilder.layer(QuestionApi).pipe(Layer.provide(questionHandlers)), + HttpApiBuilder.layer(PermissionApi).pipe(Layer.provide(permissionHandlers)), + HttpApiBuilder.layer(ProviderApi).pipe(Layer.provide(providerHandlers)), + HttpApiBuilder.layer(WorkspaceApi).pipe(Layer.provide(workspaceHandlers)), ).pipe( - Layer.provide(auth), - Layer.provide(normalize), + Layer.provide(authorizationLayer), Layer.provide(instance), Layer.provide(HttpServer.layerServices), Layer.provideMerge(Observability.layer), diff --git a/packages/opencode/src/server/routes/instance/httpapi/workspace.ts b/packages/opencode/src/server/routes/instance/httpapi/workspace.ts index 596545073e..2ab6b03d24 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/workspace.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/workspace.ts @@ -4,6 +4,7 @@ import { WorkspaceAdaptorEntry } from "@/control-plane/types" import * as InstanceState from "@/effect/instance-state" import { Effect, Layer, Schema } from "effect" import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { Authorization } from "./auth" const root = "/experimental/workspace" export const WorkspacePaths = { @@ -49,7 +50,8 @@ export const WorkspaceApi = HttpApi.make("workspace") title: "workspace", description: "Experimental HttpApi workspace routes.", }), - ), + ) + .middleware(Authorization), ) .annotateMerge( OpenApi.annotations({ From cf45a8d80752fd4f29a57c6b696c40c3b332c3e9 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Fri, 24 Apr 2026 17:11:52 -0400 Subject: [PATCH 83/92] refactor(schema): decode effect schemas directly (#24169) --- packages/opencode/src/acp/agent.ts | 19 ++++++++++--------- packages/opencode/src/cli/cmd/import.ts | 7 +++++-- .../src/control-plane/adaptors/worktree.ts | 11 +++++------ .../src/server/routes/instance/pty.ts | 6 ++++-- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts index 672b93f6ce..24bcb9c2d6 100644 --- a/packages/opencode/src/acp/agent.ts +++ b/packages/opencode/src/acp/agent.ts @@ -46,7 +46,7 @@ import { MessageV2 } from "@/session/message-v2" import { Config } from "@/config" import { ConfigMCP } from "@/config/mcp" import { Todo } from "@/session/todo" -import { z } from "zod" +import { Result, Schema } from "effect" import { LoadAPIKeyError } from "ai" import type { AssistantMessage, Event, OpencodeClient, SessionMessageResponse, ToolPart } from "@opencode-ai/sdk/v2" import { applyPatch } from "diff" @@ -54,6 +54,7 @@ import { InstallationVersion } from "@/installation/version" type ModeOption = { id: string; name: string; description?: string } type ModelOption = { modelId: string; name: string } +const decodeTodos = Schema.decodeUnknownResult(Schema.fromJsonString(Schema.Array(Todo.Info))) const DEFAULT_VARIANT_VALUE = "default" @@ -372,14 +373,14 @@ export class Agent implements ACPAgent { } if (part.tool === "todowrite") { - const parsedTodos = z.array(Todo.Info.zod).safeParse(JSON.parse(part.state.output)) - if (parsedTodos.success) { + const parsedTodos = decodeTodos(part.state.output) + if (Result.isSuccess(parsedTodos)) { await this.connection .sessionUpdate({ sessionId, update: { sessionUpdate: "plan", - entries: parsedTodos.data.map((todo) => { + entries: parsedTodos.success.map((todo) => { const status: PlanEntry["status"] = todo.status === "cancelled" ? "completed" : (todo.status as PlanEntry["status"]) return { @@ -394,7 +395,7 @@ export class Agent implements ACPAgent { log.error("failed to send session update for todo", { error }) }) } else { - log.error("failed to parse todo output", { error: parsedTodos.error }) + log.error("failed to parse todo output", { error: parsedTodos.failure }) } } @@ -901,14 +902,14 @@ export class Agent implements ACPAgent { } if (part.tool === "todowrite") { - const parsedTodos = z.array(Todo.Info.zod).safeParse(JSON.parse(part.state.output)) - if (parsedTodos.success) { + const parsedTodos = decodeTodos(part.state.output) + if (Result.isSuccess(parsedTodos)) { await this.connection .sessionUpdate({ sessionId, update: { sessionUpdate: "plan", - entries: parsedTodos.data.map((todo) => { + entries: parsedTodos.success.map((todo) => { const status: PlanEntry["status"] = todo.status === "cancelled" ? "completed" : (todo.status as PlanEntry["status"]) return { @@ -923,7 +924,7 @@ export class Agent implements ACPAgent { log.error("failed to send session update for todo", { error: err }) }) } else { - log.error("failed to parse todo output", { error: parsedTodos.error }) + log.error("failed to parse todo output", { error: parsedTodos.failure }) } } diff --git a/packages/opencode/src/cli/cmd/import.ts b/packages/opencode/src/cli/cmd/import.ts index e52120f1af..26256a770f 100644 --- a/packages/opencode/src/cli/cmd/import.ts +++ b/packages/opencode/src/cli/cmd/import.ts @@ -13,6 +13,9 @@ import { Filesystem } from "../../util" import { AppRuntime } from "@/effect/app-runtime" import { Schema } from "effect" +const decodeMessageInfo = Schema.decodeUnknownSync(MessageV2.Info) +const decodePart = Schema.decodeUnknownSync(MessageV2.Part) + /** Discriminated union returned by the ShareNext API (GET /api/shares/:id/data) */ export type ShareData = | { type: "session"; data: SDKSession } @@ -169,7 +172,7 @@ export const ImportCommand = cmd({ ) for (const msg of exportData.messages) { - const msgInfo = MessageV2.Info.zod.parse(msg.info) + const msgInfo = decodeMessageInfo(msg.info) as MessageV2.Info const { id, sessionID: _, ...msgData } = msgInfo Database.use((db) => db @@ -185,7 +188,7 @@ export const ImportCommand = cmd({ ) for (const part of msg.parts) { - const partInfo = MessageV2.Part.zod.parse(part) + const partInfo = decodePart(part) as MessageV2.Part const { id: partId, sessionID: _s, messageID, ...partData } = partInfo Database.use((db) => db diff --git a/packages/opencode/src/control-plane/adaptors/worktree.ts b/packages/opencode/src/control-plane/adaptors/worktree.ts index 8d421b9a33..9c080daa38 100644 --- a/packages/opencode/src/control-plane/adaptors/worktree.ts +++ b/packages/opencode/src/control-plane/adaptors/worktree.ts @@ -2,14 +2,13 @@ import { Schema } from "effect" import { AppRuntime } from "@/effect/app-runtime" import { Worktree } from "@/worktree" import { type WorkspaceAdaptor, WorkspaceInfo } from "../types" -import { zod } from "@/util/effect-zod" -import { withStatics } from "@/util/schema" const WorktreeConfig = Schema.Struct({ name: WorkspaceInfo.fields.name, branch: Schema.String, directory: Schema.String, -}).pipe(withStatics((s) => ({ zod: zod(s) }))) +}) +const decodeWorktreeConfig = Schema.decodeUnknownSync(WorktreeConfig) export const WorktreeAdaptor: WorkspaceAdaptor = { name: "Worktree", @@ -24,7 +23,7 @@ export const WorktreeAdaptor: WorkspaceAdaptor = { } }, async create(info) { - const config = WorktreeConfig.zod.parse(info) + const config = decodeWorktreeConfig(info) await AppRuntime.runPromise( Worktree.Service.use((svc) => svc.createFromInfo({ @@ -36,11 +35,11 @@ export const WorktreeAdaptor: WorkspaceAdaptor = { ) }, async remove(info) { - const config = WorktreeConfig.zod.parse(info) + const config = decodeWorktreeConfig(info) await AppRuntime.runPromise(Worktree.Service.use((svc) => svc.remove({ directory: config.directory }))) }, target(info) { - const config = WorktreeConfig.zod.parse(info) + const config = decodeWorktreeConfig(info) return { type: "local", directory: config.directory, diff --git a/packages/opencode/src/server/routes/instance/pty.ts b/packages/opencode/src/server/routes/instance/pty.ts index 51c4699241..5815372219 100644 --- a/packages/opencode/src/server/routes/instance/pty.ts +++ b/packages/opencode/src/server/routes/instance/pty.ts @@ -1,7 +1,7 @@ import { Hono } from "hono" import { describeRoute, validator, resolver } from "hono-openapi" import type { UpgradeWebSocket } from "hono/ws" -import { Effect } from "effect" +import { Effect, Schema } from "effect" import z from "zod" import { AppRuntime } from "@/effect/app-runtime" import { Pty } from "@/pty" @@ -10,6 +10,8 @@ import { NotFoundError } from "@/storage" import { errors } from "../../error" import { jsonRequest, runRequest } from "./trace" +const decodePtyID = Schema.decodeUnknownSync(PtyID) + export function PtyRoutes(upgradeWebSocket: UpgradeWebSocket) { return new Hono() .get( @@ -171,7 +173,7 @@ export function PtyRoutes(upgradeWebSocket: UpgradeWebSocket) { onClose: () => void } - const id = PtyID.zod.parse(c.req.param("ptyID")) + const id = decodePtyID(c.req.param("ptyID")) const cursor = (() => { const value = c.req.query("cursor") if (!value) return From 7a02eee0f4002687a5167574744cd00cb06624c4 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Fri, 24 Apr 2026 21:13:00 +0000 Subject: [PATCH 84/92] chore: generate --- .../server/routes/instance/httpapi/auth.ts | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/packages/opencode/src/server/routes/instance/httpapi/auth.ts b/packages/opencode/src/server/routes/instance/httpapi/auth.ts index adddcc4bed..fe72b78223 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/auth.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/auth.ts @@ -8,13 +8,16 @@ class Unauthorized extends Schema.TaggedErrorClass()( { httpApiStatus: 401 }, ) {} -export class Authorization extends HttpApiMiddleware.Service()("@opencode/ExperimentalHttpApiAuthorization", { - error: Unauthorized, - security: { - basic: HttpApiSecurity.basic, - authToken: HttpApiSecurity.apiKey({ in: "query", key: "auth_token" }), +export class Authorization extends HttpApiMiddleware.Service()( + "@opencode/ExperimentalHttpApiAuthorization", + { + error: Unauthorized, + security: { + basic: HttpApiSecurity.basic, + authToken: HttpApiSecurity.apiKey({ in: "query", key: "auth_token" }), + }, }, -}) {} +) {} const emptyCredential = { username: "", @@ -39,19 +42,21 @@ function validateCredential( } function decodeCredential(input: string) { - return Encoding.decodeBase64String(input).asEffect().pipe( - Effect.match({ - onFailure: () => emptyCredential, - onSuccess: (header) => { - const parts = header.split(":") - if (parts.length !== 2) return emptyCredential - return { - username: parts[0], - password: Redacted.make(parts[1]), - } - }, - }), - ) + return Encoding.decodeBase64String(input) + .asEffect() + .pipe( + Effect.match({ + onFailure: () => emptyCredential, + onSuccess: (header) => { + const parts = header.split(":") + if (parts.length !== 2) return emptyCredential + return { + username: parts[0], + password: Redacted.make(parts[1]), + } + }, + }), + ) } export const authorizationLayer = Layer.succeed( From 361d7001d00bdf6da9f3dd89f9d653f70d5056eb Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Fri, 24 Apr 2026 17:36:49 -0400 Subject: [PATCH 85/92] Clarify HttpApi migration plan (#24211) --- packages/opencode/specs/effect/http-api.md | 540 +++++---------------- 1 file changed, 126 insertions(+), 414 deletions(-) diff --git a/packages/opencode/specs/effect/http-api.md b/packages/opencode/specs/effect/http-api.md index f83b7c0555..6d4791af8f 100644 --- a/packages/opencode/specs/effect/http-api.md +++ b/packages/opencode/specs/effect/http-api.md @@ -1,462 +1,174 @@ # HttpApi migration -Practical notes for an eventual migration of `packages/opencode` server routes from the current Hono handlers to Effect `HttpApi`, either as a full replacement or as a parallel surface. +Plan for replacing instance Hono route implementations with Effect `HttpApi` while preserving behavior, OpenAPI, and SDK output during the transition. -## Goal +## End State -Use Effect `HttpApi` where it gives us a better typed contract for: +- JSON route contracts and handlers live in `src/server/routes/instance/httpapi/*`. +- Route modules own their `HttpApiGroup`, schemas, handlers, and route-level middleware. +- `httpapi/server.ts` only composes groups, instance lookup, observability, and the web handler bridge. +- Hono route implementations are deleted once their `HttpApi` replacements are default, tested, and represented in the SDK/OpenAPI pipeline. +- Streaming, SSE, and websocket routes move later through Effect HTTP primitives or another explicit replacement plan; they do not need to fit `HttpApi` if `HttpApi` is the wrong abstraction. -- route definition -- request decoding and validation -- typed success and error responses -- OpenAPI generation -- handler composition inside Effect +## Current State -This should be treated as a later-stage HTTP boundary migration, not a prerequisite for ongoing service, route-handler, or schema work. +- `OPENCODE_EXPERIMENTAL_HTTPAPI` gates the bridge. Default behavior still uses Hono. +- The bridge mounts selected paths in `server/routes/instance/index.ts` before legacy Hono routes. +- Legacy Hono routes remain for default behavior and for `hono-openapi` SDK generation. +- `HttpApi` auth is independent of Hono auth. +- `Authorization` is attached in each route module, not centrally wrapped in `server.ts`. +- Auth supports Basic auth and the legacy `auth_token` query parameter through `HttpApiSecurity.apiKey`. +- Instance context is provided by `httpapi/server.ts` using `directory`, `workspace`, and `x-opencode-directory`. +- `Observability.layer` is provided in the Effect route layer and deduplicated through the shared `memoMap`. -## Core model +## Migration Rules -`HttpApi` is definition-first. +- Preserve runtime behavior first. Semantic changes, new error behavior, or route shape changes need separate PRs. +- Migrate one route group, or one coherent subset of a route group, at a time. +- Reuse existing services. Do not re-architect service logic during HTTP boundary migration. +- Effect Schema owns route DTOs. Keep `.zod` only as compatibility for remaining Hono/OpenAPI surfaces. +- Regenerate the SDK after schema or OpenAPI-affecting changes and verify the diff is expected. +- Do not delete a Hono route until the SDK/OpenAPI pipeline no longer depends on its Hono `describeRoute` entry. -- `HttpApi` is the root API -- `HttpApiGroup` groups related endpoints -- `HttpApiEndpoint` defines a single route and its request / response schemas -- handlers are implemented separately from the contract +## Schema Notes -This is a better fit once route inputs and outputs are already moving toward Effect Schema-first models. +- Use `Schema.Struct(...).annotate({ identifier })` for named OpenAPI refs when handlers return plain objects. +- Use `Schema.Class` only when the handler returns real class instances or the constructor requirement is intentional. +- Keep nested anonymous shapes as `Schema.Struct` unless a named SDK type is useful. +- Avoid parallel hand-written Zod and Effect definitions for the same route boundary. -## Why it is relevant here +## Phases -The current route-effectification work is already pushing handlers toward: +### 1. Stabilize The Bridge -- one `AppRuntime.runPromise(Effect.gen(...))` body -- yielding services from context -- using typed Effect errors instead of Promise wrappers +Before porting more routes, cover the bridge behavior that every route depends on. -That work is a good prerequisite for `HttpApi`. Once the handler body is already a composed Effect, the remaining migration is mostly about replacing the Hono route declaration and validator layer. +- Add tests that hit the Hono-mounted `HttpApi` bridge, not just `HttpApiBuilder.layer` directly. +- Cover auth disabled, Basic auth success, `auth_token` success, missing credentials, and bad credentials. +- Cover `directory` and `x-opencode-directory` instance selection. +- Verify generated SDK output remains unchanged for non-SDK work. +- Fix or remove any implemented-but-unmounted `HttpApi` groups. -## What HttpApi gives us +### 2. Complete The Inventory -### Contracts +Create a route inventory from the actual Hono registrations and classify each route. -Request params, query, payload, success payloads, and typed error payloads are declared in one place using Effect Schema. +Statuses: -### Validation and decoding +- `bridged`: served through the `HttpApi` bridge when the flag is on. +- `implemented`: `HttpApi` group exists but is not mounted through Hono. +- `next`: good JSON candidate for near-term porting. +- `later`: portable, but needs schema/service cleanup first. +- `special`: SSE, websocket, streaming, or UI bridge behavior that likely needs raw Effect HTTP rather than `HttpApi`. -Incoming data is decoded through Effect Schema instead of hand-maintained Zod validators per route. +### 3. Finish JSON Route Parity -### OpenAPI +Port remaining JSON routes in small batches. -`HttpApi` can derive OpenAPI from the API definition, which overlaps with the current `describeRoute(...)` and `resolver(...)` pattern. +Good near-term candidates: -### Typed errors +- top-level reads: `GET /path`, `GET /vcs`, `GET /vcs/diff`, `GET /command`, `GET /agent`, `GET /skill`, `GET /lsp`, `GET /formatter` +- simple mutations: `POST /instance/dispose` +- experimental JSON reads: console, tool, worktree list, resource list +- deferred JSON mutations: `PATCH /config`, project git init, workspace/worktree create/remove/reset, file search, MCP auth flows -`Schema.TaggedErrorClass` maps naturally to endpoint error contracts. +Keep large or stateful groups for later: -## Likely fit for opencode +- `session` +- `sync` +- process-level experimental routes -Best fit first: +### 4. Move OpenAPI And SDK Generation -- JSON request / response endpoints -- route groups that already mostly delegate into services -- endpoints whose request and response models can be defined with Effect Schema +Hono routes cannot be deleted while `hono-openapi` is the source of SDK generation. -Harder / later fit: +Required before route deletion: -- SSE endpoints -- websocket endpoints -- streaming handlers -- routes with heavy Hono-specific middleware assumptions +- Generate the public OpenAPI surface from Effect `HttpApi` for ported routes. +- Keep operation IDs, schemas, status codes, and SDK type names stable unless the change is intentional. +- Compare generated SDK output against `dev` for every route group deletion. +- Remove Hono OpenAPI stubs only after Effect OpenAPI is the SDK source for those paths. -## Current blockers and gaps +### 5. Make HttpApi Default For JSON Routes -### Schema split +After JSON parity and SDK generation are covered: -Many route boundaries still use Zod-first validators. That does not block all experimentation, but full `HttpApi` adoption is easier after the domain and boundary types are more consistently Schema-first with `.zod` compatibility only where needed. +- Flip the bridge default for ported JSON routes. +- Keep a short-lived fallback flag for the old Hono implementation. +- Run the same tests against both the default and fallback path during rollout. +- Stop adding new Hono handlers for JSON routes once the default flips. -### Mixed handler styles +### 6. Delete Hono Route Implementations -Many current `server/routes/instance/*.ts` handlers still mix composed Effect code with smaller Promise- or ALS-backed seams. Migrating those to consistent `Effect.gen(...)` handlers is the low-risk step to do first. +Delete Hono routes group-by-group after each group meets the deletion criteria. -### Non-JSON routes +Deletion criteria: -The server currently includes SSE, websocket, and streaming-style endpoints. Those should not be the first `HttpApi` targets. +- `HttpApi` route is mounted by default. +- Behavior is covered by bridge-level tests. +- OpenAPI/SDK generation comes from Effect for that path. +- SDK diff is zero or explicitly accepted. +- Legacy Hono route is no longer needed as a fallback. -### Existing Hono integration +After deleting a group: -The current server composition, middleware, and docs flow are Hono-centered today. That suggests a parallel or incremental adoption plan is safer than a flag day rewrite. +- Remove its Hono route file or dead endpoints. +- Remove its `.route(...)` registration from `instance/index.ts`. +- Remove duplicate Zod-only route DTOs if Effect Schema now owns the type. +- Regenerate SDK and verify output. -## Recommended strategy +### 7. Replace Special Routes -### 1. Finish the prerequisites first +Special routes need explicit designs before Hono can disappear completely. -- continue route-handler effectification in `server/routes/instance/*.ts` -- continue schema migration toward Effect Schema-first DTOs and errors -- keep removing service facades +- `event`: SSE +- `pty`: websocket +- `tui`: UI/control bridge behavior +- streaming `session` endpoints -### 2. Start with one parallel group +Use raw Effect HTTP routes where `HttpApi` does not fit. The goal is deleting Hono implementations, not forcing every transport shape through `HttpApi`. -Introduce one small `HttpApi` group for plain JSON endpoints only. Good initial candidates are the least stateful endpoints in: +## Current Route Status -- `server/routes/instance/question.ts` -- `server/routes/instance/provider.ts` -- `server/routes/instance/permission.ts` +| Area | Status | Notes | +| --- | --- | --- | +| `question` | `bridged` | `GET /question`, reply, reject | +| `permission` | `bridged` | list and reply | +| `provider` | `bridged` | list, auth, OAuth authorize/callback | +| `config` | `bridged` partial | reads only; mutation remains Hono | +| `project` | `bridged` partial | reads only; git-init remains Hono | +| `file` | `bridged` partial | list/content/status only | +| `mcp` | `bridged` partial | status only | +| `workspace` | `implemented` | `HttpApi` group exists, but bridge mounting needs verification | +| top-level instance reads | `next` | path, vcs, command, agent, skill, lsp, formatter | +| experimental JSON routes | `next/later` | console, tool, worktree, resource, global session list | +| `session` | `later/special` | large stateful surface plus streaming | +| `sync` | `later` | process/control side effects | +| `event` | `special` | SSE | +| `pty` | `special` | websocket | +| `tui` | `special` | UI bridge | -Avoid `session.ts`, SSE, websocket, and TUI-facing routes first. +## Next PRs -Recommended first slice: - -- start with `question` -- start with `GET /question` -- start with `POST /question/:requestID/reply` - -Why `question` first: - -- already JSON-only -- already delegates into an Effect service -- proves list + mutation + params + payload + OpenAPI in one small slice -- avoids the harder streaming and middleware cases - -### 3. Reuse existing services - -Do not re-architect business logic during the HTTP migration. `HttpApi` handlers should call the same Effect services already used by the Hono handlers. - -### 4. Bridge into Hono behind a feature flag - -The `HttpApi` routes are bridged into the Hono server via `HttpRouter.toWebHandler` with a shared `memoMap`. This means: - -- one process, one port — no separate server -- the Effect handler shares layer instances with `AppRuntime` (same `Question.Service`, etc.) -- Effect middleware handles auth and instance lookup independently from Hono middleware -- Hono's `.all()` catch-all intercepts matching paths before the Hono route handlers - -The bridge is gated behind `OPENCODE_EXPERIMENTAL_HTTPAPI` (or `OPENCODE_EXPERIMENTAL`). When the flag is off (default), all requests go through the original Hono handlers unchanged. - -```ts -// in instance/index.ts -if (Flag.OPENCODE_EXPERIMENTAL_HTTPAPI) { - const handler = ExperimentalHttpApiServer.webHandler().handler - app.all("/question", (c) => handler(c.req.raw)).all("/question/*", (c) => handler(c.req.raw)) -} -``` - -The Hono route handlers are always registered (after the bridge) so `hono-openapi` generates the OpenAPI spec entries that feed SDK codegen. When the flag is on, these handlers are dead code — the `.all()` bridge matches first. - -### 5. Observability - -The `webHandler` provides `Observability.layer` via `Layer.provideMerge`. Since the `memoMap` is shared with `AppRuntime`, the tracing provider is deduplicated — no extra initialization cost. - -This gives: - -- **spans**: `Effect.fn("QuestionHttpApi.list")` etc. appear in traces alongside service-layer spans -- **HTTP logs**: `HttpMiddleware.logger` emits structured `Effect.log` entries with `http.method`, `http.url`, `http.status` annotations, flowing to motel via `OtlpLogger` - -### 6. Migrate JSON route groups gradually - -As each route group is ported to `HttpApi`: - -1. add `.get(...)` / `.post(...)` bridge entries to the flag block in `server/routes/instance/index.ts` -2. for partial ports (e.g. only `GET /provider/auth`), bridge only the specific path -3. keep the legacy Hono route registered behind it for OpenAPI / SDK generation until the spec pipeline changes -4. verify SDK output is unchanged - -Leave streaming-style endpoints on Hono until there is a clear reason to move them. - -## Schema rule for HttpApi work - -Every `HttpApi` slice should follow `specs/effect/schema.md` and the Schema -> Zod interop rule in `specs/effect/migration.md`. - -Default rule: - -- Effect Schema owns the type -- `.zod` exists only as a compatibility surface -- do not introduce a new hand-written Zod schema for a type that is already migrating to Effect Schema - -Practical implication for `HttpApi` migration: - -- if a route boundary already depends on a shared DTO, ID, input, output, or tagged error, migrate that model to Effect Schema first or in the same change -- if an existing Hono route or tool still needs Zod, derive it with `@/util/effect-zod` -- avoid maintaining parallel Zod and Effect definitions for the same request or response type - -Ordering for a route-group migration: - -1. move implicated shared `schema.ts` leaf types to Effect Schema first -2. move exported `Info` / `Input` / `Output` route DTOs to Effect Schema -3. move tagged route-facing errors to `Schema.TaggedErrorClass` where needed -4. switch existing Zod boundary validators to derived `.zod` -5. define the `HttpApi` contract from the canonical Effect schemas -6. regenerate the SDK (`./packages/sdk/js/script/build.ts`) and verify zero diff against `dev` - -SDK shape rule: - -- every schema migration must preserve the generated SDK output byte-for-byte **unless the new ref is intentional** (see Schema.Class vs Schema.Struct below) -- if an unintended diff appears in `packages/sdk/js/src/v2/gen/types.gen.ts`, the migration introduced an unintended API surface change — fix it before merging - -### Schema.Class vs Schema.Struct - -The pattern choice determines whether a schema becomes a **named** export in the SDK or stays **anonymous inline**. - -**Schema.Class** emits a named `$ref` in OpenAPI via its identifier → produces a named `export type Foo = ...` in `types.gen.ts`: - -```ts -export class Info extends Schema.Class("FooConfig")({ ... }) { - static readonly zod = zod(this) -} -``` - -**Schema.Struct** stays anonymous and is inlined everywhere it is referenced: - -```ts -export const Info = Schema.Struct({ ... }).pipe( - withStatics((s) => ({ zod: zod(s) })), -) -export type Info = Schema.Schema.Type -``` - -When to use each: - -- Use **Schema.Class** when: - - the original Zod had `.meta({ ref: ... })` (preserve the existing named SDK type byte-for-byte) - - the schema is a top-level endpoint request or response (SDK consumers benefit from a stable importable name) -- Use **Schema.Struct** when: - - the type is only used as a nested field inside another named schema - - the original Zod was anonymous and promoting it would bloat SDK types with no import value - -Promoting a previously-anonymous schema to Schema.Class is acceptable when it is top-level or endpoint-facing, but call it out in the PR — it is an additive SDK change (`export type Foo = ...` newly appears) even if it preserves the JSON shape. - -Schemas that are **not** pure objects (enums, unions, records, tuples) cannot use Schema.Class. For those — and for pure-object schemas where handlers populate plain objects rather than class instances — add `.annotate({ identifier: "FooName" })` to get the same named-ref behavior without the `instanceof` requirement: - -```ts -export const Action = Schema.Literals(["ask", "allow", "deny"]).annotate({ identifier: "PermissionActionConfig" }) -``` - -Temporary exception: - -- it is acceptable to keep a route-local Zod schema for the first spike only when the type is boundary-local and migrating it would create unrelated churn -- if that happens, leave a short note so the type does not become a permanent second source of truth - -## First vertical slice - -The first `HttpApi` spike should be intentionally small and repeatable. - -Chosen slice: - -- group: `question` -- endpoints: `GET /question` and `POST /question/:requestID/reply` - -Non-goals: - -- no `session` routes -- no SSE or websocket routes -- no auth redesign -- no broad service refactor - -Behavior rule: - -- preserve current runtime behavior first -- treat semantic changes such as introducing new `404` behavior as a separate follow-up unless they are required to make the contract honest - -Add `POST /question/:requestID/reject` only after the first two endpoints work cleanly. - -## Repeatable slice template - -Use the same sequence for each route group. - -1. Pick one JSON-only route group that already mostly delegates into services. -2. Identify the shared DTOs, IDs, and errors implicated by that slice. -3. Apply the schema migration ordering above so those types are Effect Schema-first. -4. Define the `HttpApi` contract separately from the handlers. -5. Implement handlers by yielding the existing service from context. -6. Mount the new surface in parallel behind the `OPENCODE_EXPERIMENTAL_HTTPAPI` bridge. -7. Regenerate the SDK and verify zero diff against `dev` (see SDK shape rule above). -8. Add one end-to-end test and one OpenAPI-focused test. -9. Compare ergonomics before migrating the next endpoint. - -Rule of thumb: - -- migrate one route group at a time -- migrate one or two endpoints first, not the whole file -- keep business logic in the existing service -- keep the first spike easy to delete if the experiment is not worth continuing - -## Example structure - -Placement rule: - -- keep `HttpApi` code under `src/server`, not `src/effect` -- `src/effect` should stay focused on runtimes, layers, instance state, and shared Effect plumbing -- place each `HttpApi` slice next to the HTTP boundary it serves -- for instance-scoped routes, prefer `src/server/routes/instance/httpapi/*` -- if control-plane routes ever migrate, prefer `src/server/routes/control/httpapi/*` - -Suggested file layout for a repeatable spike: - -- `src/server/routes/instance/httpapi/question.ts` — contract and handler layer for one route group -- `src/server/routes/instance/httpapi/server.ts` — bridged Effect HTTP layer that composes all groups -- route or OpenAPI verification should live alongside the existing server tests; there is no dedicated `question-httpapi` test file on this branch - -Suggested responsibilities: - -- `question.ts` defines the `HttpApi` contract and `HttpApiBuilder.group(...)` handlers -- `server.ts` composes all route groups into one `HttpRouter.toWebHandler(...)` bridge with shared middleware (auth, instance lookup) -- tests should verify the bridged routes through the normal server surface - -## Example migration shape - -Each route-group spike should follow the same shape. - -### 1. Contract - -- define an experimental `HttpApi` -- define one `HttpApiGroup` -- define endpoint params, payload, success, and error schemas from canonical Effect schemas -- annotate summary, description, and operation ids explicitly so generated docs are stable - -### 2. Handler layer - -- implement with `HttpApiBuilder.group(api, groupName, ...)` -- yield the existing Effect service from context -- keep handler bodies thin -- keep transport mapping at the HTTP boundary only - -### 3. Bridged server - -- the Effect HTTP layer is composed in `httpapi/server.ts` -- it is mounted into the Hono app via `HttpRouter.toWebHandler(...)` -- routes keep their normal instance paths and are gated by the `OPENCODE_EXPERIMENTAL_HTTPAPI` flag -- the legacy Hono handlers stay registered after the bridge so current OpenAPI / SDK generation still works - -### 4. Verification - -- seed real state through the existing service -- call the bridged endpoints with the flag enabled -- assert that the service behavior is unchanged -- assert that the generated OpenAPI contains the migrated paths and schemas - -## Boundary composition - -The Effect `HttpApi` layer owns its own auth and instance middleware, but it is currently mounted inside the existing Hono server. - -### Auth - -- the bridged `HttpApi` layer implements auth as an `HttpApiMiddleware.Service` using `HttpApiSecurity.basic` -- each route group's `HttpApi` is wrapped with `.middleware(Authorization)` before being served -- this is independent of the Hono auth layer; the current bridge keeps the responsibility local to the `HttpApi` slice - -### Instance and workspace lookup - -- the bridged `HttpApi` layer resolves instance context via an `HttpRouter.middleware` that reads `x-opencode-directory` headers and `directory` query params -- this is the Effect equivalent of the Hono `WorkspaceRouterMiddleware` -- `HttpApi` handlers yield services from context and assume the correct instance has already been provided - -### Error mapping - -- keep domain and service errors typed in the service layer -- declare typed transport errors on the endpoint only when the route can actually return them intentionally -- request decoding failures are transport-level `400`s handled by Effect `HttpApi` automatically -- storage or lookup failures that are part of the route contract should be declared as typed endpoint errors - -## Exit criteria for the spike - -The first slice is successful if: - -- the bridged endpoints serve correctly through the existing Hono host when the flag is enabled -- the handlers reuse the existing Effect service -- request decoding and response shapes are schema-defined from canonical Effect schemas -- any remaining Zod boundary usage is derived from `.zod` or clearly temporary -- OpenAPI is generated from the `HttpApi` contract -- the tests are straightforward enough that the next slice feels mechanical - -## Learnings - -### Schema - -- `Schema.Class` works well for route DTOs such as `Question.Request`, `Question.Info`, and `Question.Reply`. -- scalar or collection schemas such as `Question.Answer` should stay as schemas and use helpers like `withStatics(...)` instead of being forced into classes. -- if an `HttpApi` success schema uses `Schema.Class`, the handler or underlying service needs to return real schema instances rather than plain objects. `Schema.Class`'s Declaration AST enforces `input instanceof self || input.[ClassTypeId]` during encode (see effect-smol `Schema.ts:10479-10484`). Plain objects from zod parse fail with `Expected Foo, got {...}`. This surfaced on `GET /config` where the service returns zod-parsed plain objects and `Config.InfoSchema` referenced `ConfigProvider.Info` (class). The fix was to convert pure-object classes to `Schema.Struct(...).annotate({ identifier: "..." })` — same named SDK `$ref`, no instance requirement. Verified byte-identical `types.gen.ts` vs `dev`. -- internal event payloads can stay anonymous when we want to avoid adding extra named OpenAPI component churn for non-route shapes. -- `Schema.Class` emits named `$ref` in OpenAPI — only use it for types that already had `.meta({ ref })` in the old Zod schema **and** when the handler/service returns real instances. For schemas that need a named `$ref` but are populated from plain objects, use `Schema.Struct(...).annotate({ identifier: "..." })` instead. Inner/nested types should stay as `Schema.Struct` to avoid SDK shape changes. - -### Integration - -- `HttpRouter.toWebHandler` with the shared `memoMap` from `run-service.ts` cleanly bridges Effect routes into Hono — one process, one port, shared layer instances. -- `Observability.layer` must be explicitly provided via `Layer.provideMerge` in the routes layer for OTEL spans and HTTP logs to flow. The `memoMap` deduplicates it with `AppRuntime` — no extra cost. -- `HttpMiddleware.logger` (enabled by default when `disableLogger` is not set) emits structured `Effect.log` entries with `http.method`, `http.url`, `http.status` — these flow through `OtlpLogger` to motel. -- Hono OpenAPI stubs must remain registered for SDK codegen until the SDK pipeline reads from the Effect OpenAPI spec instead. -- the `OPENCODE_EXPERIMENTAL_HTTPAPI` flag gates the bridge at the Hono router level — default off, no behavior change unless opted in. - -## Route inventory - -Status legend: - -- `bridged` - Effect HttpApi slice exists and is bridged into Hono behind the flag -- `done` - Effect HttpApi slice exists but not yet bridged -- `next` - good near-term candidate -- `later` - possible, but not first wave -- `defer` - not a good early `HttpApi` target - -Current instance route inventory: - -- `question` - `bridged` - endpoints: `GET /question`, `POST /question/:requestID/reply`, `POST /question/:requestID/reject` -- `permission` - `bridged` - endpoints: `GET /permission`, `POST /permission/:requestID/reply` -- `provider` - `bridged` - endpoints: `GET /provider`, `GET /provider/auth`, `POST /provider/:providerID/oauth/authorize`, `POST /provider/:providerID/oauth/callback` -- `config` - `bridged` (partial) - bridged endpoints: `GET /config`, `GET /config/providers` - defer `PATCH /config` for now -- `project` - `bridged` (partial) - bridged endpoints: `GET /project`, `GET /project/current` - defer git-init mutation first -- `workspace` - `bridged` - best small reads: `GET /experimental/workspace/adaptor`, `GET /experimental/workspace`, `GET /experimental/workspace/status` - defer create/remove mutations first -- `file` - `bridged` (partial) - bridged endpoints: `GET /file`, `GET /file/content`, `GET /file/status` - defer search endpoints first -- `mcp` - `bridged` (partial) - bridged endpoints: `GET /mcp` - defer interactive OAuth/auth flows first -- `session` - `defer` - large, stateful, mixes CRUD with prompt/shell/command/share/revert flows and a streaming route -- `event` - `defer` - SSE only -- `global` - `defer` - mixed bag with SSE and process-level side effects -- `pty` - `defer` - websocket-heavy route surface -- `tui` - `defer` - queue-style UI bridge, weak early `HttpApi` fit - -Recommended near-term sequence: - -1. `workspace` read endpoints (`GET /experimental/workspace/adaptor`, `GET /experimental/workspace`, `GET /experimental/workspace/status`) -2. `file` JSON read endpoints -3. `mcp` JSON read endpoints +1. Add bridge-level auth and instance-context tests for the current `HttpApi` bridge. +2. Produce a generated route inventory from Hono registrations and update `Current Route Status` with exact paths. +3. Fix the `workspace` status: mount it if it should be reachable, or remove it from the composed `HttpApi` layer. +4. Port the top-level JSON reads. +5. Start the Effect OpenAPI/SDK generation path for already-bridged routes. ## Checklist -- [x] add one small spike that defines an `HttpApi` group for a simple JSON route set -- [x] use Effect Schema request / response types for that slice -- [x] keep the underlying service calls identical to the current handlers -- [x] compare generated OpenAPI against the current Hono/OpenAPI setup -- [x] document how auth, instance lookup, and error mapping would compose in the new stack -- [x] bridge Effect routes into Hono via `toWebHandler` with shared `memoMap` -- [x] gate behind `OPENCODE_EXPERIMENTAL_HTTPAPI` flag -- [x] verify OTEL spans and HTTP logs flow to motel -- [x] bridge question, permission, and provider auth routes -- [x] port remaining provider endpoints (`GET /provider`, OAuth mutations) -- [x] port `config` providers read endpoint -- [x] port `project` read endpoints (`GET /project`, `GET /project/current`) -- [x] port `GET /config` full read endpoint -- [x] port `workspace` read endpoints -- [x] port `file` JSON read endpoints -- [x] port `mcp` status read endpoint -- [ ] decide when to remove the flag and make Effect routes the default - -## Rule of thumb - -Do not start with the hardest route file. - -If `HttpApi` is adopted here, it should arrive after the handler body is already Effect-native and after the relevant request / response models have moved to Effect Schema. +- [x] Add first `HttpApi` JSON route slices. +- [x] Bridge selected `HttpApi` routes into Hono behind `OPENCODE_EXPERIMENTAL_HTTPAPI`. +- [x] Reuse existing Effect services in handlers. +- [x] Provide auth, instance lookup, and observability in the Effect route layer. +- [x] Attach auth middleware in route modules. +- [x] Support `auth_token` as a query security scheme. +- [ ] Add bridge-level auth and instance tests. +- [ ] Complete exact Hono route inventory. +- [ ] Resolve implemented-but-unmounted route groups. +- [ ] Port remaining JSON routes. +- [ ] Generate SDK/OpenAPI from Effect routes. +- [ ] Flip ported JSON routes to default-on with fallback. +- [ ] Delete replaced Hono route implementations. +- [ ] Replace SSE/websocket/streaming Hono routes with non-Hono implementations. From 872cdff2ab1997f071bc29c17910d3a995bb2540 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Fri, 24 Apr 2026 17:37:28 -0400 Subject: [PATCH 86/92] ignore: denounce ai spammer --- .github/VOUCHED.td | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/VOUCHED.td b/.github/VOUCHED.td index 65bda9804a..589002d084 100644 --- a/.github/VOUCHED.td +++ b/.github/VOUCHED.td @@ -33,3 +33,4 @@ simonklee -spider-yamet clawdbot/llm psychosis, spam pinging the team thdxr -toastythebot +-davidbernat looks to be a clawdbot that spams team and sends super weird emails, doesnt appear to be a real person From c4e33d31680f4b0804045e5b9f0ed78596d33ea4 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Fri, 24 Apr 2026 21:38:31 +0000 Subject: [PATCH 87/92] chore: generate --- packages/opencode/specs/effect/http-api.md | 34 +++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/opencode/specs/effect/http-api.md b/packages/opencode/specs/effect/http-api.md index 6d4791af8f..ad9fcb2ba5 100644 --- a/packages/opencode/specs/effect/http-api.md +++ b/packages/opencode/specs/effect/http-api.md @@ -130,23 +130,23 @@ Use raw Effect HTTP routes where `HttpApi` does not fit. The goal is deleting Ho ## Current Route Status -| Area | Status | Notes | -| --- | --- | --- | -| `question` | `bridged` | `GET /question`, reply, reject | -| `permission` | `bridged` | list and reply | -| `provider` | `bridged` | list, auth, OAuth authorize/callback | -| `config` | `bridged` partial | reads only; mutation remains Hono | -| `project` | `bridged` partial | reads only; git-init remains Hono | -| `file` | `bridged` partial | list/content/status only | -| `mcp` | `bridged` partial | status only | -| `workspace` | `implemented` | `HttpApi` group exists, but bridge mounting needs verification | -| top-level instance reads | `next` | path, vcs, command, agent, skill, lsp, formatter | -| experimental JSON routes | `next/later` | console, tool, worktree, resource, global session list | -| `session` | `later/special` | large stateful surface plus streaming | -| `sync` | `later` | process/control side effects | -| `event` | `special` | SSE | -| `pty` | `special` | websocket | -| `tui` | `special` | UI bridge | +| Area | Status | Notes | +| ------------------------ | ----------------- | -------------------------------------------------------------- | +| `question` | `bridged` | `GET /question`, reply, reject | +| `permission` | `bridged` | list and reply | +| `provider` | `bridged` | list, auth, OAuth authorize/callback | +| `config` | `bridged` partial | reads only; mutation remains Hono | +| `project` | `bridged` partial | reads only; git-init remains Hono | +| `file` | `bridged` partial | list/content/status only | +| `mcp` | `bridged` partial | status only | +| `workspace` | `implemented` | `HttpApi` group exists, but bridge mounting needs verification | +| top-level instance reads | `next` | path, vcs, command, agent, skill, lsp, formatter | +| experimental JSON routes | `next/later` | console, tool, worktree, resource, global session list | +| `session` | `later/special` | large stateful surface plus streaming | +| `sync` | `later` | process/control side effects | +| `event` | `special` | SSE | +| `pty` | `special` | websocket | +| `tui` | `special` | UI bridge | ## Next PRs From 4a67905266633f1867aaf89d863b4a8d149d5237 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Fri, 24 Apr 2026 17:39:06 -0400 Subject: [PATCH 88/92] fix: ensure gpt-5.5 compacts at correct context size when using openai oauth (#24212) --- packages/opencode/src/plugin/codex.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/opencode/src/plugin/codex.ts b/packages/opencode/src/plugin/codex.ts index e05111fc6a..60d2d5b47c 100644 --- a/packages/opencode/src/plugin/codex.ts +++ b/packages/opencode/src/plugin/codex.ts @@ -390,6 +390,16 @@ export async function CodexAuthPlugin(input: PluginInput): Promise { output: 0, cache: { read: 0, write: 0 }, } + + // gpt-5.5 models temporarily have restricted context window size for codex plans + if (model.id.includes("gpt-5.5")) { + model.limit = { + context: 400_000, + //@ts-expect-error incorrect type for v1 sdk but works + input: 272_000, + output: 128_000, + } + } } return { From bb3509b5ff445912e2b6d5f594866e92b42eb463 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Fri, 24 Apr 2026 17:42:10 -0400 Subject: [PATCH 89/92] fix(opencode): clarify git amend condition to require verifying commit landed (#19937) Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com> Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Co-authored-by: opencode-agent[bot] Co-authored-by: Shoubhit Dash --- packages/opencode/src/tool/bash.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencode/src/tool/bash.txt b/packages/opencode/src/tool/bash.txt index 668cea307c..c2fe873791 100644 --- a/packages/opencode/src/tool/bash.txt +++ b/packages/opencode/src/tool/bash.txt @@ -58,7 +58,7 @@ Git Safety Protocol: - NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it - NEVER run force push to main/master, warn the user if they request it - Avoid git commit --amend. ONLY use --amend when ALL conditions are met: - (1) User explicitly requested amend, OR commit SUCCEEDED but pre-commit hook auto-modified files that need including + (1) User explicitly requested amend, OR the commit succeeded and pre-commit hooks auto-modified files that need including — verify by checking `git log` that HEAD is the new commit before amending (2) HEAD commit was created by you in this conversation (verify: git log -1 --format='%an %ae') (3) Commit has NOT been pushed to remote (verify: git status shows "Your branch is ahead") - CRITICAL: If commit FAILED or was REJECTED by hook, NEVER amend - fix the issue and create a NEW commit From 5a04de231ee455bb112afc7b19af5c8e4144c6a2 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Fri, 24 Apr 2026 17:42:52 -0400 Subject: [PATCH 90/92] refactor(ripgrep): migrate result schemas to effect (#24213) --- packages/opencode/src/file/ripgrep.ts | 127 +++++++++--------- .../src/server/routes/instance/file.ts | 2 +- 2 files changed, 63 insertions(+), 66 deletions(-) diff --git a/packages/opencode/src/file/ripgrep.ts b/packages/opencode/src/file/ripgrep.ts index d6fd61f1d0..64a2e3d8e4 100644 --- a/packages/opencode/src/file/ripgrep.ts +++ b/packages/opencode/src/file/ripgrep.ts @@ -1,7 +1,6 @@ import path from "path" -import z from "zod" import { AppFileSystem } from "@opencode-ai/shared/filesystem" -import { Cause, Context, Effect, Fiber, Layer, Queue, Stream } from "effect" +import { Cause, Context, Effect, Fiber, Layer, Queue, Schema, Stream } from "effect" import type { PlatformError } from "effect/PlatformError" import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/unstable/http" import { ChildProcess } from "effect/unstable/process" @@ -12,6 +11,8 @@ import { Global } from "@/global" import { Log } from "@/util" import { sanitizedProcessEnv } from "@/util/opencode-process" import { which } from "@/util/which" +import { zod } from "@/util/effect-zod" +import { withStatics } from "@/util/schema" const log = Log.create({ service: "ripgrep" }) const VERSION = "15.1.0" @@ -25,83 +26,82 @@ const PLATFORM = { "x64-win32": { platform: "x86_64-pc-windows-msvc", extension: "zip" }, } as const -const Stats = z.object({ - elapsed: z.object({ - secs: z.number(), - nanos: z.number(), - human: z.string(), - }), - searches: z.number(), - searches_with_match: z.number(), - bytes_searched: z.number(), - bytes_printed: z.number(), - matched_lines: z.number(), - matches: z.number(), +const TimeStats = Schema.Struct({ + secs: Schema.Number, + nanos: Schema.Number, + human: Schema.String, }) -const Begin = z.object({ - type: z.literal("begin"), - data: z.object({ - path: z.object({ - text: z.string(), - }), +const Stats = Schema.Struct({ + elapsed: TimeStats, + searches: Schema.Number, + searches_with_match: Schema.Number, + bytes_searched: Schema.Number, + bytes_printed: Schema.Number, + matched_lines: Schema.Number, + matches: Schema.Number, +}) + +const PathText = Schema.Struct({ + text: Schema.String, +}) + +const Begin = Schema.Struct({ + type: Schema.Literal("begin"), + data: Schema.Struct({ + path: PathText, }), }) -export const Match = z.object({ - type: z.literal("match"), - data: z.object({ - path: z.object({ - text: z.string(), - }), - lines: z.object({ - text: z.string(), - }), - line_number: z.number(), - absolute_offset: z.number(), - submatches: z.array( - z.object({ - match: z.object({ - text: z.string(), - }), - start: z.number(), - end: z.number(), +export const SearchMatch = Schema.Struct({ + path: PathText, + lines: Schema.Struct({ + text: Schema.String, + }), + line_number: Schema.Number, + absolute_offset: Schema.Number, + submatches: Schema.Array( + Schema.Struct({ + match: Schema.Struct({ + text: Schema.String, }), - ), - }), + start: Schema.Number, + end: Schema.Number, + }), + ), +}).pipe(withStatics((s) => ({ zod: zod(s) }))) + +export const Match = Schema.Struct({ + type: Schema.Literal("match"), + data: SearchMatch, }) -const End = z.object({ - type: z.literal("end"), - data: z.object({ - path: z.object({ - text: z.string(), - }), - binary_offset: z.number().nullable(), +const End = Schema.Struct({ + type: Schema.Literal("end"), + data: Schema.Struct({ + path: PathText, + binary_offset: Schema.NullOr(Schema.Number), stats: Stats, }), }) -const Summary = z.object({ - type: z.literal("summary"), - data: z.object({ - elapsed_total: z.object({ - human: z.string(), - nanos: z.number(), - secs: z.number(), - }), +const Summary = Schema.Struct({ + type: Schema.Literal("summary"), + data: Schema.Struct({ + elapsed_total: TimeStats, stats: Stats, }), }) -const Result = z.union([Begin, Match, End, Summary]) +const Result = Schema.Union([Begin, Match, End, Summary]) +const decodeResult = Schema.decodeUnknownEffect(Schema.fromJsonString(Result)) -export type Result = z.infer -export type Match = z.infer +export type Result = Schema.Schema.Type +export type Match = Schema.Schema.Type export type Item = Match["data"] -export type Begin = z.infer -export type End = z.infer -export type Summary = z.infer +export type Begin = Schema.Schema.Type +export type End = Schema.Schema.Type +export type Summary = Schema.Schema.Type export type Row = Match["data"] export interface SearchResult { @@ -187,10 +187,7 @@ function row(data: Row): Row { } function parse(line: string) { - return Effect.try({ - try: () => Result.parse(JSON.parse(line)), - catch: (cause) => new Error("invalid ripgrep output", { cause }), - }) + return decodeResult(line).pipe(Effect.mapError((cause) => new Error("invalid ripgrep output", { cause }))) } function fail(queue: Queue.Queue, err: PlatformError | Error) { diff --git a/packages/opencode/src/server/routes/instance/file.ts b/packages/opencode/src/server/routes/instance/file.ts index 661322127e..65b3cbad33 100644 --- a/packages/opencode/src/server/routes/instance/file.ts +++ b/packages/opencode/src/server/routes/instance/file.ts @@ -21,7 +21,7 @@ export const FileRoutes = lazy(() => description: "Matches", content: { "application/json": { - schema: resolver(Ripgrep.Match.shape.data.array()), + schema: resolver(Ripgrep.SearchMatch.zod.array()), }, }, }, From 97eb9fdee839020e18a1cf80bf4c5873e8138633 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Fri, 24 Apr 2026 18:03:51 -0400 Subject: [PATCH 91/92] test(httpapi): cover hono bridge middleware (#24216) --- .../server/routes/instance/httpapi/project.ts | 4 +- .../test/server/httpapi-bridge.test.ts | 131 ++++++++++++++++++ 2 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 packages/opencode/test/server/httpapi-bridge.test.ts diff --git a/packages/opencode/src/server/routes/instance/httpapi/project.ts b/packages/opencode/src/server/routes/instance/httpapi/project.ts index 10cf25118f..6d3143df86 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/project.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/project.ts @@ -1,4 +1,4 @@ -import { Instance } from "@/project/instance" +import * as InstanceState from "@/effect/instance-state" import { Project } from "@/project" import { Effect, Layer, Schema } from "effect" import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" @@ -54,7 +54,7 @@ export const projectHandlers = Layer.unwrap( }) const current = Effect.fn("ProjectHttpApi.current")(function* () { - return Instance.project + return (yield* InstanceState.context).project }) return HttpApiBuilder.group(ProjectApi, "project", (handlers) => diff --git a/packages/opencode/test/server/httpapi-bridge.test.ts b/packages/opencode/test/server/httpapi-bridge.test.ts new file mode 100644 index 0000000000..29f85b8810 --- /dev/null +++ b/packages/opencode/test/server/httpapi-bridge.test.ts @@ -0,0 +1,131 @@ +import { afterEach, describe, expect, test } from "bun:test" +import type { UpgradeWebSocket } from "hono/ws" +import { Flag } from "../../src/flag/flag" +import { Instance } from "../../src/project/instance" +import { InstanceRoutes } from "../../src/server/routes/instance" +import { FilePaths } from "../../src/server/routes/instance/httpapi/file" +import { Log } from "../../src/util" +import { resetDatabase } from "../fixture/db" +import { tmpdir } from "../fixture/fixture" + +void Log.init({ print: false }) + +const original = { + OPENCODE_EXPERIMENTAL_HTTPAPI: Flag.OPENCODE_EXPERIMENTAL_HTTPAPI, + OPENCODE_SERVER_PASSWORD: Flag.OPENCODE_SERVER_PASSWORD, + OPENCODE_SERVER_USERNAME: Flag.OPENCODE_SERVER_USERNAME, +} + +const websocket = (() => () => new Response(null, { status: 501 })) as unknown as UpgradeWebSocket + +function app(input?: { password?: string; username?: string }) { + Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = true + Flag.OPENCODE_SERVER_PASSWORD = input?.password + Flag.OPENCODE_SERVER_USERNAME = input?.username + return InstanceRoutes(websocket) +} + +function authorization(username: string, password: string) { + return `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}` +} + +function fileUrl(input?: { directory?: string; token?: string }) { + const url = new URL(`http://localhost${FilePaths.content}`) + url.searchParams.set("path", "hello.txt") + if (input?.directory) url.searchParams.set("directory", input.directory) + if (input?.token) url.searchParams.set("auth_token", input.token) + return url +} + +afterEach(async () => { + Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original.OPENCODE_EXPERIMENTAL_HTTPAPI + Flag.OPENCODE_SERVER_PASSWORD = original.OPENCODE_SERVER_PASSWORD + Flag.OPENCODE_SERVER_USERNAME = original.OPENCODE_SERVER_USERNAME + await Instance.disposeAll() + await resetDatabase() +}) + +describe("HttpApi Hono bridge", () => { + test("allows requests when auth is disabled", async () => { + await using tmp = await tmpdir({ git: true }) + await Bun.write(`${tmp.path}/hello.txt`, "hello") + + const response = await app().request(fileUrl(), { + headers: { + "x-opencode-directory": tmp.path, + }, + }) + + expect(response.status).toBe(200) + expect(await response.json()).toMatchObject({ content: "hello" }) + }) + + test("provides instance context to bridged handlers", async () => { + await using tmp = await tmpdir({ git: true }) + + const response = await app().request("/project/current", { + headers: { + "x-opencode-directory": tmp.path, + }, + }) + + expect(response.status).toBe(200) + expect(await response.json()).toMatchObject({ worktree: tmp.path }) + }) + + test("requires credentials when auth is enabled", async () => { + await using tmp = await tmpdir({ git: true }) + await Bun.write(`${tmp.path}/hello.txt`, "hello") + + const [missing, bad, good] = await Promise.all([ + app({ password: "secret" }).request(fileUrl(), { + headers: { "x-opencode-directory": tmp.path }, + }), + app({ password: "secret" }).request(fileUrl(), { + headers: { + authorization: authorization("opencode", "wrong"), + "x-opencode-directory": tmp.path, + }, + }), + app({ password: "secret" }).request(fileUrl(), { + headers: { + authorization: authorization("opencode", "secret"), + "x-opencode-directory": tmp.path, + }, + }), + ]) + + expect(missing.status).toBe(401) + expect(bad.status).toBe(401) + expect(good.status).toBe(200) + }) + + test("accepts auth_token query credentials", async () => { + await using tmp = await tmpdir({ git: true }) + await Bun.write(`${tmp.path}/hello.txt`, "hello") + + const response = await app({ password: "secret" }).request(fileUrl({ token: Buffer.from("opencode:secret").toString("base64") }), { + headers: { + "x-opencode-directory": tmp.path, + }, + }) + + expect(response.status).toBe(200) + }) + + test("selects instance from query before directory header", async () => { + await using header = await tmpdir({ git: true }) + await using query = await tmpdir({ git: true }) + await Bun.write(`${header.path}/hello.txt`, "header") + await Bun.write(`${query.path}/hello.txt`, "query") + + const response = await app().request(fileUrl({ directory: query.path }), { + headers: { + "x-opencode-directory": header.path, + }, + }) + + expect(response.status).toBe(200) + expect(await response.json()).toMatchObject({ content: "query" }) + }) +}) From 5cd178ba7008969c9fc711c78603d7e3144b4ce8 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Fri, 24 Apr 2026 22:05:23 +0000 Subject: [PATCH 92/92] chore: generate --- packages/opencode/test/server/httpapi-bridge.test.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/opencode/test/server/httpapi-bridge.test.ts b/packages/opencode/test/server/httpapi-bridge.test.ts index 29f85b8810..3f0de26a1d 100644 --- a/packages/opencode/test/server/httpapi-bridge.test.ts +++ b/packages/opencode/test/server/httpapi-bridge.test.ts @@ -104,11 +104,14 @@ describe("HttpApi Hono bridge", () => { await using tmp = await tmpdir({ git: true }) await Bun.write(`${tmp.path}/hello.txt`, "hello") - const response = await app({ password: "secret" }).request(fileUrl({ token: Buffer.from("opencode:secret").toString("base64") }), { - headers: { - "x-opencode-directory": tmp.path, + const response = await app({ password: "secret" }).request( + fileUrl({ token: Buffer.from("opencode:secret").toString("base64") }), + { + headers: { + "x-opencode-directory": tmp.path, + }, }, - }) + ) expect(response.status).toBe(200) })