From 87e9e700cd115db59f6fbd7c927967cbb731cedf Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Mon, 25 May 2026 23:42:33 -0500 Subject: [PATCH 01/40] fix(opencode): revert google sdk tool call id change (#29310) --- bun.lock | 16 +++++----------- packages/core/package.json | 2 +- packages/opencode/package.json | 2 +- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/bun.lock b/bun.lock index c899ce9c48..bf44bd581d 100644 --- a/bun.lock +++ b/bun.lock @@ -207,7 +207,7 @@ "@ai-sdk/cohere": "3.0.27", "@ai-sdk/deepinfra": "2.0.41", "@ai-sdk/gateway": "3.0.104", - "@ai-sdk/google": "3.0.75", + "@ai-sdk/google": "3.0.63", "@ai-sdk/google-vertex": "4.0.131", "@ai-sdk/groq": "3.0.31", "@ai-sdk/mistral": "3.0.27", @@ -417,7 +417,7 @@ "@ai-sdk/cohere": "3.0.27", "@ai-sdk/deepinfra": "2.0.41", "@ai-sdk/gateway": "3.0.104", - "@ai-sdk/google": "3.0.75", + "@ai-sdk/google": "3.0.63", "@ai-sdk/google-vertex": "4.0.131", "@ai-sdk/groq": "3.0.31", "@ai-sdk/mistral": "3.0.27", @@ -895,7 +895,7 @@ "@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.104", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@vercel/oidc": "3.2.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZKX5n74io8VIRlhIMSLWVlvT3sXC8Z7cZ9GHuWBWZDVi96+62AIsWuLGvMfcBA1STYuSoDrp6rIziZmvrTq0TA=="], - "@ai-sdk/google": ["@ai-sdk/google@3.0.75", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-XAm31ftiOrzlb8NjDzT7kw0xw+4lmgFdGFn1QKM73nXFFKyN1kWLESBV75UGNfjXP8X1YJ0YydnMVqO0jaPghw=="], + "@ai-sdk/google": ["@ai-sdk/google@3.0.63", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-RfOZWVMYSPu2sPRfGajrauWAZ9BSaRopSn+AszkKWQ1MFj8nhaXvCqRHB5pBQUaHTfZKagvOmMpNfa/s3gPLgQ=="], "@ai-sdk/google-vertex": ["@ai-sdk/google-vertex@4.0.131", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.78", "@ai-sdk/google": "3.0.75", "@ai-sdk/openai-compatible": "2.0.47", "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27", "google-auth-library": "^10.5.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Oj1X8p0rVgvEoR5OOSxWi6XgzJ3QDlE/n30MZVtpKkCiToYYDyvlvVDGXz3IqhMyUev2JhlcuUk1brScKT01kA=="], @@ -5207,12 +5207,10 @@ "@ai-sdk/fireworks/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="], - "@ai-sdk/google/@ai-sdk/provider": ["@ai-sdk/provider@3.0.10", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-Q3BZ27qfpYqnCYGvE3vt+Qi6LGOF9R5Nmzn+9JoM1lCRsD9mYaIhfJLkSunN48nfGXJ6n+XNV0J/XVpqGQl7Dw=="], - - "@ai-sdk/google/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw=="], - "@ai-sdk/google-vertex/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.78", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-0OY12G20cUt6iU6htpEA1491Oz++NVxZxlmWGX4B7rSbeZ5pnDmOu6YtW9BKzdZlNx5Gn23i6WMxyZFoMKNcgA=="], + "@ai-sdk/google-vertex/@ai-sdk/google": ["@ai-sdk/google@3.0.75", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-XAm31ftiOrzlb8NjDzT7kw0xw+4lmgFdGFn1QKM73nXFFKyN1kWLESBV75UGNfjXP8X1YJ0YydnMVqO0jaPghw=="], + "@ai-sdk/google-vertex/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.47", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Enm5UlL0zUCrW3792opk5h7hRWxZOZzDe6eQYVFqX9LUOGGCe1h8MZWAGim765nwzgnjlpeYOsuzZmLtRsTPlg=="], "@ai-sdk/google-vertex/@ai-sdk/provider": ["@ai-sdk/provider@3.0.10", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-Q3BZ27qfpYqnCYGvE3vt+Qi6LGOF9R5Nmzn+9JoM1lCRsD9mYaIhfJLkSunN48nfGXJ6n+XNV0J/XVpqGQl7Dw=="], @@ -6151,10 +6149,6 @@ "@ai-sdk/google-vertex/@ai-sdk/provider-utils/eventsource-parser": ["eventsource-parser@3.0.8", "", {}, "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ=="], - "@ai-sdk/google/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], - - "@ai-sdk/google/@ai-sdk/provider-utils/eventsource-parser": ["eventsource-parser@3.0.8", "", {}, "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ=="], - "@ai-sdk/groq/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], "@ai-sdk/mistral/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], diff --git a/packages/core/package.json b/packages/core/package.json index 738e4d80bf..d49a717c05 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -34,7 +34,7 @@ "@ai-sdk/cohere": "3.0.27", "@ai-sdk/deepinfra": "2.0.41", "@ai-sdk/gateway": "3.0.104", - "@ai-sdk/google": "3.0.75", + "@ai-sdk/google": "3.0.63", "@ai-sdk/google-vertex": "4.0.131", "@ai-sdk/groq": "3.0.31", "@ai-sdk/mistral": "3.0.27", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 559924ca9e..1e3db56823 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -81,7 +81,7 @@ "@ai-sdk/cohere": "3.0.27", "@ai-sdk/deepinfra": "2.0.41", "@ai-sdk/gateway": "3.0.104", - "@ai-sdk/google": "3.0.75", + "@ai-sdk/google": "3.0.63", "@ai-sdk/google-vertex": "4.0.131", "@ai-sdk/groq": "3.0.31", "@ai-sdk/mistral": "3.0.27", From dbb787232605f5293945edc5b1ac14856e5d43e3 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Tue, 26 May 2026 05:01:16 +0000 Subject: [PATCH 02/40] 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 a4353299a4..c0148e83d8 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-6s5msV+dYMHHt9Gc/CqvCrUj8K7ELjxoAe6ejHSJo4I=", - "aarch64-linux": "sha256-SP94UPy5LePd7ZdC3eENIXiozc67blpg1SN9Ug5yiv8=", - "aarch64-darwin": "sha256-jv3lffiAQ5kxDAbXNavsHD+tjjdgT0dT0JxN0bWMYTE=", - "x86_64-darwin": "sha256-aYNtcarg516ZmqaO62mnUZYiSyWt8rJjUHQslhrhGHM=" + "x86_64-linux": "sha256-gqXxbi1OwLoDSDtlmYWcTTPT/fqhVGb53JXS/9a1vWw=", + "aarch64-linux": "sha256-+ARbWtOUDx0J5k55mmre/2kPekUsQtWWS0QZnyX6NTo=", + "aarch64-darwin": "sha256-Q6ioI6lFUhNKogbvbtGWsZcXJfbRgUAWS5X2X4mKdg4=", + "x86_64-darwin": "sha256-8K/hmcvXi9FGqprNbTKzMB80h5zZhO2TjOQbtve3ltQ=" } } From 49707c211773aaabf0721a95c67b569861c8ab94 Mon Sep 17 00:00:00 2001 From: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Date: Tue, 26 May 2026 13:41:13 +0800 Subject: [PATCH 03/40] fix(app): deduplicate and merge server connections in resolveServerList (#29313) --- packages/app/src/context/server.tsx | 30 +++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/packages/app/src/context/server.tsx b/packages/app/src/context/server.tsx index 2758fbed73..8532c8249e 100644 --- a/packages/app/src/context/server.tsx +++ b/packages/app/src/context/server.tsx @@ -36,24 +36,30 @@ export function resolveServerList(input: { props?: Array stored: StoredServer[] }): Array { - const servers = [ - ...(input.props ?? []), - ...input.stored.map((value) => + const deduped = new Map( + input.props?.map((v) => [ServerConnection.key(v), v]) ?? [], + ) + + for (const value of input.stored) { + const conn: ServerConnection.Http = typeof value === "string" ? { type: "http" as const, http: { url: value }, } - : value, - ), - ] - - const deduped = new Map() - for (const value of servers) { - const conn: ServerConnection.Any = "type" in value ? value : { type: "http", http: value } + : "http" in value + ? value + : { type: "http", http: value } const key = ServerConnection.key(conn) - if (deduped.has(key) && conn.type === "http" && !conn.authToken) continue - deduped.set(key, conn) + + const existing = deduped.get(key) + if (existing) + deduped.set(key, { + ...existing, + ...conn, + http: { ...existing.http, ...conn.http }, + }) + else deduped.set(key, conn) } return [...deduped.values()] From 15c5ec6d248c2d146ec7b6b9ce94b3aa66329ed3 Mon Sep 17 00:00:00 2001 From: Shoubhit Dash Date: Tue, 26 May 2026 11:45:24 +0530 Subject: [PATCH 04/40] feat(acp): add acp-next session lifecycle (#29320) --- packages/opencode/src/acp-next/agent.ts | 20 +++ packages/opencode/src/acp-next/service.ts | 154 ++++++++++++++++++ .../test/acp-next/service-session.test.ts | 154 +++++++++++++++++- .../cli/acp-next/acp-next-process.test.ts | 56 ++++++- 4 files changed, 378 insertions(+), 6 deletions(-) diff --git a/packages/opencode/src/acp-next/agent.ts b/packages/opencode/src/acp-next/agent.ts index a4ae006956..040c1947e2 100644 --- a/packages/opencode/src/acp-next/agent.ts +++ b/packages/opencode/src/acp-next/agent.ts @@ -4,10 +4,14 @@ import { type AgentSideConnection, type AuthenticateRequest, type CancelNotification, + type CloseSessionRequest, + type ForkSessionRequest, type InitializeRequest, + type ListSessionsRequest, type LoadSessionRequest, type NewSessionRequest, type PromptRequest, + type ResumeSessionRequest, type SetSessionConfigOptionRequest, type SetSessionModelRequest, type SetSessionModeRequest, @@ -44,6 +48,22 @@ export class Agent implements ACPAgent { return run(this.service.loadSession(params)) } + listSessions(params: ListSessionsRequest) { + return run(this.service.listSessions(params)) + } + + resumeSession(params: ResumeSessionRequest) { + return run(this.service.resumeSession(params)) + } + + closeSession(params: CloseSessionRequest) { + return run(this.service.closeSession(params)) + } + + unstable_forkSession(params: ForkSessionRequest) { + return run(this.service.forkSession(params)) + } + setSessionConfigOption(params: SetSessionConfigOptionRequest) { return run(this.service.setSessionConfigOption(params)) } diff --git a/packages/opencode/src/acp-next/service.ts b/packages/opencode/src/acp-next/service.ts index ce1ea18085..36352634c4 100644 --- a/packages/opencode/src/acp-next/service.ts +++ b/packages/opencode/src/acp-next/service.ts @@ -4,8 +4,14 @@ import { type AuthenticateResponse, type AuthMethod, type CancelNotification, + type CloseSessionRequest, + type CloseSessionResponse, + type ForkSessionRequest, + type ForkSessionResponse, type InitializeRequest, type InitializeResponse, + type ListSessionsRequest, + type ListSessionsResponse, type LoadSessionRequest, type LoadSessionResponse, type McpServer, @@ -13,6 +19,9 @@ import { type NewSessionResponse, type PromptRequest, type PromptResponse, + type ResumeSessionRequest, + type ResumeSessionResponse, + type SessionInfo, type SetSessionConfigOptionRequest, type SetSessionConfigOptionResponse, type SetSessionModelRequest, @@ -21,6 +30,7 @@ import { type SetSessionModeResponse, } from "@agentclientprotocol/sdk" import { InstallationVersion } from "@opencode-ai/core/installation/version" +import * as Log from "@opencode-ai/core/util/log" import type { OpencodeClient } from "@opencode-ai/sdk/v2" import { Context, Effect, Layer, ManagedRuntime } from "effect" import * as ACPNextError from "./error" @@ -32,6 +42,7 @@ import { Provider } from "@/provider/provider" import type { Command } from "@/command" export const AuthMethodID = "opencode-login" +const log = Log.create({ service: "acp-next-service" }) export type Error = ACPNextError.Error @@ -40,6 +51,10 @@ export type Interface = { readonly authenticate: (input: AuthenticateRequest) => Effect.Effect readonly newSession: (input: NewSessionRequest) => Effect.Effect readonly loadSession: (input: LoadSessionRequest) => Effect.Effect + readonly listSessions: (input: ListSessionsRequest) => Effect.Effect + readonly resumeSession: (input: ResumeSessionRequest) => Effect.Effect + readonly closeSession: (input: CloseSessionRequest) => Effect.Effect + readonly forkSession: (input: ForkSessionRequest) => Effect.Effect readonly setSessionConfigOption: ( input: SetSessionConfigOptionRequest, ) => Effect.Effect @@ -90,6 +105,12 @@ export function make(input: { embeddedContext: true, image: true, }, + sessionCapabilities: { + close: {}, + fork: {}, + list: {}, + resume: {}, + }, }, authMethods: [authMethod], agentInfo: { @@ -181,6 +202,135 @@ export function make(input: { yield* registerMcpServers(input.sdk, registeredMcp, params.cwd, state.id, params.mcpServers) yield* sendAvailableCommands(input.connection, state.id, snapshot) + return { + configOptions: configOptions(snapshot, { + model: state.model ?? model, + variant: state.variant, + modeId: state.modeId, + }), + } + }) + + const listSessions = Effect.fn("ACPNext.listSessions")(function* (params: ListSessionsRequest) { + const cursor = params.cursor ? Number(params.cursor) : undefined + const limit = 100 + const sessions = yield* request( + () => + input.sdk.session.list( + { + ...(params.cwd ? { directory: params.cwd } : {}), + roots: true, + }, + { throwOnError: true }, + ), + "session", + ) + const sorted = sessions.toSorted((a, b) => b.time.updated - a.time.updated) + const filtered = + cursor === undefined || !Number.isFinite(cursor) ? sorted : sorted.filter((item) => item.time.updated < cursor) + const page = filtered.slice(0, limit) + const last = page.at(-1) + return { + sessions: page.map((item): SessionInfo => ({ + sessionId: item.id, + cwd: item.directory, + title: item.title, + updatedAt: new Date(item.time.updated).toISOString(), + })), + ...(filtered.length > limit && last ? { nextCursor: String(last.time.updated) } : {}), + } + }) + + const resumeSession = Effect.fn("ACPNext.resumeSession")(function* (params: ResumeSessionRequest) { + const snapshot = yield* directorySnapshot(params.cwd) + yield* request( + () => input.sdk.session.get({ directory: params.cwd, sessionID: params.sessionId }, { throwOnError: true }), + "session", + ) + const messages = yield* request( + () => + input.sdk.session.messages( + { directory: params.cwd, sessionID: params.sessionId, limit: 20 }, + { throwOnError: true }, + ), + "session", + ) + const restored = restoreFromMessages(messages.map((item) => item.info)) + const model = restored.model ?? selectDefaultModel(snapshot) + const state = yield* session.load({ + id: params.sessionId, + cwd: params.cwd, + mcpServers: params.mcpServers ?? [], + model, + variant: restored.variant ?? selectVariant(snapshot, model), + modeId: restored.modeId ?? (snapshot.availableModes.length > 0 ? snapshot.defaultModeID : undefined), + }) + + yield* registerMcpServers(input.sdk, registeredMcp, params.cwd, state.id, params.mcpServers ?? []) + yield* sendAvailableCommands(input.connection, state.id, snapshot) + + return { + configOptions: configOptions(snapshot, { + model: state.model ?? model, + variant: state.variant, + modeId: state.modeId, + }), + } + }) + + const closeSession = Effect.fn("ACPNext.closeSession")(function* (params: CloseSessionRequest) { + const removed = yield* session.remove(params.sessionId) + registeredMcp.delete(params.sessionId) + if (!removed) return {} + + yield* request( + () => input.sdk.session.abort({ directory: removed.cwd, sessionID: params.sessionId }, { throwOnError: true }), + "session", + ).pipe( + Effect.catch((error) => + Effect.sync(() => { + log.error("failed to abort session while closing ACP session", { error, sessionID: params.sessionId }) + }), + ), + ) + return {} + }) + + const forkSession = Effect.fn("ACPNext.forkSession")(function* (params: ForkSessionRequest) { + const snapshot = yield* directorySnapshot(params.cwd) + const forked = yield* request( + () => + input.sdk.session.fork( + { + directory: params.cwd, + sessionID: params.sessionId, + }, + { throwOnError: true }, + ), + "session", + ) + const messages = yield* request( + () => + input.sdk.session.messages( + { directory: params.cwd, sessionID: forked.id, limit: 20 }, + { throwOnError: true }, + ), + "session", + ) + const restored = restoreFromMessages(messages.map((item) => item.info)) + const model = restored.model ?? selectDefaultModel(snapshot) + const state = yield* session.load({ + id: forked.id, + cwd: params.cwd, + mcpServers: params.mcpServers ?? [], + model, + variant: restored.variant ?? selectVariant(snapshot, model), + modeId: restored.modeId ?? (snapshot.availableModes.length > 0 ? snapshot.defaultModeID : undefined), + }) + + yield* registerMcpServers(input.sdk, registeredMcp, params.cwd, state.id, params.mcpServers ?? []) + yield* sendAvailableCommands(input.connection, state.id, snapshot) + return { sessionId: state.id, configOptions: configOptions(snapshot, { @@ -278,6 +428,10 @@ export function make(input: { authenticate, newSession, loadSession, + listSessions, + resumeSession, + closeSession, + forkSession, setSessionConfigOption, setSessionMode, setSessionModel, diff --git a/packages/opencode/test/acp-next/service-session.test.ts b/packages/opencode/test/acp-next/service-session.test.ts index a024758aaf..96d4066f7e 100644 --- a/packages/opencode/test/acp-next/service-session.test.ts +++ b/packages/opencode/test/acp-next/service-session.test.ts @@ -1,16 +1,19 @@ import { describe, expect, it } from "bun:test" import type { AgentSideConnection, + ForkSessionResponse, LoadSessionResponse, NewSessionResponse, + ResumeSessionResponse, SessionConfigOption, SessionConfigSelectOption, SetSessionConfigOptionResponse, } from "@agentclientprotocol/sdk" import type { OpencodeClient } from "@opencode-ai/sdk/v2" -import { Effect } from "effect" +import { Effect, ManagedRuntime } from "effect" import * as ACPNextService from "@/acp-next/service" import * as ACPNextError from "@/acp-next/error" +import { ACPNextSession } from "@/acp-next/session" import { ModelID, ProviderID } from "@/provider/schema" import type { Provider } from "@/provider/provider" @@ -140,6 +143,14 @@ describe("ACP next service sessions", () => { const makeService = (messages: readonly { info: unknown; parts: readonly unknown[] }[] = []) => { const updates: unknown[] = [] const mcpAdds: string[] = [] + const aborts: string[] = [] + const forks: string[] = [] + const sessions = Array.from({ length: 102 }, (_, index) => ({ + id: `ses_${index + 1}`, + directory: index % 2 === 0 ? "/workspace" : "/other", + title: `Session ${index + 1}`, + time: { created: index + 1, updated: index + 1 }, + })) const sdk = { config: { providers: () => Promise.resolve({ data: { providers: [provider], default: { test: modelID } } }), @@ -168,8 +179,19 @@ describe("ACP next service sessions", () => { session: { create: () => Promise.resolve({ data: { id: "ses_new" } }), get: () => Promise.resolve({ data: { id: "ses_loaded" } }), - list: () => Promise.resolve({ data: [] }), + list: (input: { directory?: string }) => + Promise.resolve({ + data: input.directory ? sessions.filter((session) => session.directory === input.directory) : sessions, + }), messages: () => Promise.resolve({ data: messages }), + abort: (input: { sessionID: string }) => { + aborts.push(input.sessionID) + return Promise.resolve({ data: true }) + }, + fork: (input: { sessionID: string }) => { + forks.push(input.sessionID) + return Promise.resolve({ data: { id: `fork_${input.sessionID}` } }) + }, }, mcp: { add: (input: { name?: string }) => { @@ -185,7 +207,7 @@ describe("ACP next service sessions", () => { }, } as Pick - return { service: ACPNextService.make({ sdk, connection }), updates, mcpAdds } + return { service: ACPNextService.make({ sdk, connection }), updates, mcpAdds, aborts, forks } } it("creates a backed session with config options and command update", async () => { @@ -233,6 +255,125 @@ describe("ACP next service sessions", () => { expect(result.configOptions?.find((option) => option.id === "mode")?.currentValue).toBe("plan") }) + it("lists sessions sorted by updated time with cursor support", async () => { + const { service } = makeService() + const first = await Effect.runPromise(service.listSessions({ cwd: "/workspace" })) + const second = await Effect.runPromise(service.listSessions({ cwd: "/workspace", cursor: first.nextCursor })) + + expect(first.sessions).toHaveLength(51) + expect(first.sessions[0]?.sessionId).toBe("ses_101") + expect(first.sessions.at(-1)?.sessionId).toBe("ses_1") + expect(first.nextCursor).toBeUndefined() + expect(second.sessions).toEqual(first.sessions) + }) + + it("lists all sessions with next cursor when the first page is full", async () => { + const { service } = makeService() + const first = await Effect.runPromise(service.listSessions({})) + const second = await Effect.runPromise(service.listSessions({ cursor: first.nextCursor })) + + expect(first.sessions).toHaveLength(100) + expect(first.sessions[0]?.sessionId).toBe("ses_102") + expect(first.sessions.at(-1)?.sessionId).toBe("ses_3") + expect(first.nextCursor).toBe("3") + expect(second.sessions.map((session) => session.sessionId)).toEqual(["ses_2", "ses_1"]) + }) + + it("resumes a session and stores restored state", async () => { + const { service } = makeService([ + { + info: { + role: "user", + model: { providerID: "test", modelID: "test-model", variant: "high" }, + agent: "plan", + }, + parts: [], + }, + ]) + const resumed = await Effect.runPromise( + service.resumeSession({ cwd: "/workspace", sessionId: "ses_resume", mcpServers: [] }), + ) + const updated = await Effect.runPromise( + service.setSessionConfigOption({ sessionId: "ses_resume", configId: "effort", value: "default" }), + ) + + expect(select(resumed, "effort")?.currentValue).toBe("high") + expect(select(updated, "effort")?.currentValue).toBe("default") + }) + + it("closes local ACP state and aborts the backing session best-effort", async () => { + const { service, aborts } = makeService() + const created = await Effect.runPromise(service.newSession({ cwd: "/workspace", mcpServers: [] })) + + expect(await Effect.runPromise(service.closeSession({ sessionId: created.sessionId }))).toEqual({}) + const missing = await Effect.runPromise( + service + .setSessionConfigOption({ sessionId: created.sessionId, configId: "effort", value: "high" }) + .pipe(Effect.mapError(ACPNextError.toRequestError), Effect.flip), + ) + expect(missing.code).toBe(-32602) + expect(aborts).toEqual([created.sessionId]) + expect(await Effect.runPromise(service.closeSession({ sessionId: "missing" }))).toEqual({}) + }) + + it("does not fail close when backing abort fails", async () => { + const sessionService = ManagedRuntime.make(ACPNextSession.defaultLayer).runSync( + ACPNextSession.Service.use((service) => Effect.succeed(service)), + ) + const { service } = makeService() + const sdk = { + config: { + providers: () => Promise.resolve({ data: { providers: [provider], default: { test: modelID } } }), + get: () => Promise.resolve({ data: {} }), + }, + app: { + agents: () => Promise.resolve({ data: [{ name: "build", mode: "primary", permission: [], options: {} }] }), + skills: () => Promise.resolve({ data: [] }), + }, + command: { + list: () => Promise.resolve({ data: [] }), + }, + session: { + abort: () => Promise.reject(new Error("nope")), + }, + mcp: { + add: () => Promise.resolve({ data: {} }), + }, + } as unknown as OpencodeClient + const closing = ACPNextService.make({ sdk, session: sessionService }) + await Effect.runPromise(sessionService.create({ id: "ses_close", cwd: "/workspace" })) + + expect(await Effect.runPromise(closing.closeSession({ sessionId: "ses_close" }))).toEqual({}) + expect(await Effect.runPromise(service.closeSession({ sessionId: "missing" }))).toEqual({}) + }) + + it("forks a session, loads fork state, and returns config options", async () => { + const { service, forks } = makeService([ + { + info: { + role: "assistant", + providerID: "test", + modelID: "second-model", + variant: "medium", + mode: "plan", + }, + parts: [], + }, + ]) + const forked = await Effect.runPromise( + service.forkSession({ cwd: "/workspace", sessionId: "ses_parent", mcpServers: [] }), + ) + const updated = await Effect.runPromise( + service.setSessionConfigOption({ sessionId: forked.sessionId, configId: "effort", value: "low" }), + ) + + expect(forked.sessionId).toBe("fork_ses_parent") + expect(select(forked, "model")?.currentValue).toBe("test/second-model") + expect(select(forked, "effort")?.currentValue).toBe("medium") + expect(select(updated, "effort")?.currentValue).toBe("low") + expect(forks).toEqual(["ses_parent"]) + }) + it("restores model variant and mode from the latest user message", async () => { const { service } = makeService([ { @@ -522,8 +663,11 @@ function categories(result: NewSessionResponse | LoadSessionResponse) { return result.configOptions?.map((option) => option.category) ?? [] } -function select(result: SetSessionConfigOptionResponse, id: string) { - return result.configOptions.find( +function select( + result: SetSessionConfigOptionResponse | ResumeSessionResponse | NewSessionResponse | ForkSessionResponse, + id: string, +) { + return result.configOptions?.find( (option): option is Extract => option.id === id && option.type === "select", ) diff --git a/packages/opencode/test/cli/acp-next/acp-next-process.test.ts b/packages/opencode/test/cli/acp-next/acp-next-process.test.ts index c4e88fb74e..95b905543b 100644 --- a/packages/opencode/test/cli/acp-next/acp-next-process.test.ts +++ b/packages/opencode/test/cli/acp-next/acp-next-process.test.ts @@ -1,9 +1,11 @@ import { describe, expect } from "bun:test" import type { AuthenticateResponse, + CloseSessionResponse, InitializeResponse, LoadSessionResponse, NewSessionResponse, + ResumeSessionResponse, SessionNotification, SetSessionConfigOptionResponse, } from "@agentclientprotocol/sdk" @@ -31,7 +33,10 @@ describe("opencode acp-next (subprocess)", () => { expect(initialized.agentCapabilities?.mcpCapabilities?.http).toBe(true) expect(initialized.agentCapabilities?.mcpCapabilities?.sse).toBe(true) expect(initialized.agentCapabilities?.loadSession).toBe(true) - expect(initialized.agentCapabilities?.sessionCapabilities).toBeUndefined() + expect(initialized.agentCapabilities?.sessionCapabilities?.close).toEqual({}) + expect(initialized.agentCapabilities?.sessionCapabilities?.fork).toEqual({}) + expect(initialized.agentCapabilities?.sessionCapabilities?.list).toEqual({}) + expect(initialized.agentCapabilities?.sessionCapabilities?.resume).toEqual({}) expect(initialized.agentInfo?.name).toBe("OpenCode") expect(initialized.authMethods?.[0]?.id).toBe("opencode-login") expect(initialized.authMethods?.[0]?._meta?.["terminal-auth"]).toBeDefined() @@ -159,6 +164,55 @@ describe("opencode acp-next (subprocess)", () => { 60_000, ) + cliIt.live( + "advertises and supports close behind OPENCODE_ACP_NEXT", + ({ home, llm, opencode }) => + Effect.gen(function* () { + const acp = createAcpClient( + yield* opencode.acp({ + env: { + OPENCODE_ACP_NEXT: "1", + OPENCODE_CONFIG_CONTENT: JSON.stringify(verifierConfig(llm.url)), + }, + }), + ) + const initialized = expectOk(yield* acp.request("initialize", { protocolVersion: 1 })) + expect(initialized.agentCapabilities?.sessionCapabilities?.close).toEqual({}) + const session = expectOk(yield* acp.request("session/new", { cwd: home, mcpServers: [] })) + + expectOk(yield* acp.request("session/close", { sessionId: session.sessionId })) + }), + 60_000, + ) + + cliIt.live( + "advertises and supports resume behind OPENCODE_ACP_NEXT", + ({ home, llm, opencode }) => + Effect.gen(function* () { + const acp = createAcpClient( + yield* opencode.acp({ + env: { + OPENCODE_ACP_NEXT: "1", + OPENCODE_CONFIG_CONTENT: JSON.stringify(verifierConfig(llm.url)), + }, + }), + ) + const initialized = expectOk(yield* acp.request("initialize", { protocolVersion: 1 })) + expect(initialized.agentCapabilities?.sessionCapabilities?.resume).toEqual({}) + const session = expectOk(yield* acp.request("session/new", { cwd: home, mcpServers: [] })) + const resumed = expectOk( + yield* acp.request("session/resume", { + cwd: home, + sessionId: session.sessionId, + mcpServers: [], + }), + ) + + expect(selectConfigOption(resumed.configOptions, "model")?.category).toBe("model") + }), + 60_000, + ) + cliIt.live( "exits cleanly when flagged stdin is closed", ({ opencode }) => From 245f00a4b3c83f78a3ba668443556441e7a2d129 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Tue, 26 May 2026 06:17:48 +0000 Subject: [PATCH 05/40] chore: generate --- packages/opencode/src/acp-next/service.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/opencode/src/acp-next/service.ts b/packages/opencode/src/acp-next/service.ts index 36352634c4..5ec9fd48b8 100644 --- a/packages/opencode/src/acp-next/service.ts +++ b/packages/opencode/src/acp-next/service.ts @@ -231,12 +231,14 @@ export function make(input: { const page = filtered.slice(0, limit) const last = page.at(-1) return { - sessions: page.map((item): SessionInfo => ({ - sessionId: item.id, - cwd: item.directory, - title: item.title, - updatedAt: new Date(item.time.updated).toISOString(), - })), + sessions: page.map( + (item): SessionInfo => ({ + sessionId: item.id, + cwd: item.directory, + title: item.title, + updatedAt: new Date(item.time.updated).toISOString(), + }), + ), ...(filtered.length > limit && last ? { nextCursor: String(last.time.updated) } : {}), } }) @@ -311,10 +313,7 @@ export function make(input: { ) const messages = yield* request( () => - input.sdk.session.messages( - { directory: params.cwd, sessionID: forked.id, limit: 20 }, - { throwOnError: true }, - ), + input.sdk.session.messages({ directory: params.cwd, sessionID: forked.id, limit: 20 }, { throwOnError: true }), "session", ) const restored = restoreFromMessages(messages.map((item) => item.info)) From 7e5305c7651b3aa950118aaef924f2f1d8e57a58 Mon Sep 17 00:00:00 2001 From: Shoubhit Dash Date: Tue, 26 May 2026 12:17:20 +0530 Subject: [PATCH 06/40] feat(acp-next): add event routing (#29327) --- packages/opencode/src/acp-next/event.ts | 190 ++++++++++ packages/opencode/src/acp-next/service.ts | 26 +- packages/opencode/src/acp-next/session.ts | 10 + packages/opencode/src/acp-next/usage.ts | 24 +- packages/opencode/test/acp-next/event.test.ts | 332 ++++++++++++++++++ 5 files changed, 552 insertions(+), 30 deletions(-) create mode 100644 packages/opencode/src/acp-next/event.ts create mode 100644 packages/opencode/test/acp-next/event.test.ts diff --git a/packages/opencode/src/acp-next/event.ts b/packages/opencode/src/acp-next/event.ts new file mode 100644 index 0000000000..cffdccf14a --- /dev/null +++ b/packages/opencode/src/acp-next/event.ts @@ -0,0 +1,190 @@ +import type { AgentSideConnection } from "@agentclientprotocol/sdk" +import * as Log from "@opencode-ai/core/util/log" +import type { + Event, + EventMessagePartDelta, + EventMessagePartUpdated, + OpencodeClient, + Part, + SessionMessageResponse, +} from "@opencode-ai/sdk/v2" +import { Effect } from "effect" +import { ACPNextSession } from "./session" + +const log = Log.create({ service: "acp-next-event" }) + +type Connection = Pick +type GlobalEventEnvelope = { + payload?: Event +} +type GlobalEventStream = { + stream: AsyncIterable +} + +export function start(input: { + sdk: OpencodeClient + connection: Connection + session: ACPNextSession.Interface +}) { + const subscription = new Subscription(input) + subscription.start() + return subscription +} + +export class Subscription { + private readonly abort = new AbortController() + private started = false + + constructor( + private readonly input: { + sdk: OpencodeClient + connection: Connection + session: ACPNextSession.Interface + }, + ) {} + + start() { + if (this.started) return + this.started = true + this.run().catch((error: unknown) => { + if (this.abort.signal.aborted) return + log.error("event subscription failed", { error }) + }) + } + + stop() { + this.abort.abort() + } + + async handle(event: Event) { + switch (event.type) { + case "message.part.updated": + return this.handlePartUpdated(event) + case "message.part.delta": + return this.handlePartDelta(event) + } + } + + private async run() { + while (!this.abort.signal.aborted) { + const events = (await this.input.sdk.global.event({ + signal: this.abort.signal, + })) as GlobalEventStream + + for await (const event of events.stream) { + if (this.abort.signal.aborted) return + if (!event.payload) continue + await this.handle(event.payload).catch((error: unknown) => { + log.error("failed to handle event", { error, type: event.payload?.type }) + }) + } + if (!this.abort.signal.aborted) await new Promise((resolve) => setTimeout(resolve, 1000)) + } + } + + private async handlePartUpdated(event: EventMessagePartUpdated) { + const part = event.properties.part + const sessionId = part.sessionID || event.properties.sessionID + const session = await Effect.runPromise(this.input.session.tryGet(sessionId)) + if (!session) return + + await Effect.runPromise( + this.input.session.recordPartMetadata({ + sessionId: session.id, + messageId: part.messageID, + partId: part.id, + partType: part.type, + role: part.type === "reasoning" ? "assistant" : undefined, + ignored: part.type === "text" ? part.ignored : undefined, + toolCallId: part.type === "tool" ? part.callID : undefined, + metadata: "metadata" in part ? part.metadata : undefined, + }), + ) + } + + private async handlePartDelta(event: EventMessagePartDelta) { + const props = event.properties + const session = await Effect.runPromise(this.input.session.tryGet(props.sessionID)) + if (!session) return + + const known = await Effect.runPromise( + this.input.session.tryGetPartMetadata({ + sessionId: session.id, + messageId: props.messageID, + partId: props.partID, + }), + ) + const metadata = + known?.role && known.partType + ? known + : await this.fetchPartMetadata(session.id, session.cwd, props.messageID, props.partID) + if (metadata?.role !== "assistant") return + if (metadata.partType === "text" && props.field === "text" && metadata.ignored !== true) { + await this.input.connection.sessionUpdate({ + sessionId: session.id, + update: { + sessionUpdate: "agent_message_chunk", + messageId: props.messageID, + content: { + type: "text", + text: props.delta, + }, + }, + }) + return + } + + if (metadata.partType === "reasoning" && props.field === "text") { + await this.input.connection.sessionUpdate({ + sessionId: session.id, + update: { + sessionUpdate: "agent_thought_chunk", + messageId: props.messageID, + content: { + type: "text", + text: props.delta, + }, + }, + }) + } + } + + private async fetchPartMetadata(sessionId: string, cwd: string, messageId: string, partId: string) { + const message = await this.input.sdk.session + .message( + { + sessionID: sessionId, + messageID: messageId, + directory: cwd, + }, + { throwOnError: true }, + ) + .then((response) => response.data) + .catch((error: unknown) => { + log.error("unexpected error when fetching message for delta metadata", { error, messageId, partId }) + return undefined + }) + if (!message) return + + const part = message.parts.find((item) => item.id === partId) + if (!part) return + return await this.recordFetchedPart(sessionId, message, part) + } + + private async recordFetchedPart(sessionId: string, message: SessionMessageResponse, part: Part) { + return await Effect.runPromise( + this.input.session.recordPartMetadata({ + sessionId, + messageId: part.messageID, + partId: part.id, + partType: part.type, + role: message.info.role, + ignored: part.type === "text" ? part.ignored : undefined, + toolCallId: part.type === "tool" ? part.callID : undefined, + metadata: "metadata" in part ? part.metadata : undefined, + }), + ) + } +} + +export * as ACPNextEvent from "./event" diff --git a/packages/opencode/src/acp-next/service.ts b/packages/opencode/src/acp-next/service.ts index 5ec9fd48b8..a465264d45 100644 --- a/packages/opencode/src/acp-next/service.ts +++ b/packages/opencode/src/acp-next/service.ts @@ -31,11 +31,12 @@ import { } from "@agentclientprotocol/sdk" import { InstallationVersion } from "@opencode-ai/core/installation/version" import * as Log from "@opencode-ai/core/util/log" -import type { OpencodeClient } from "@opencode-ai/sdk/v2" +import type { Message, OpencodeClient } from "@opencode-ai/sdk/v2" import { Context, Effect, Layer, ManagedRuntime } from "effect" import * as ACPNextError from "./error" import { buildConfigOptions, parseModelSelection } from "./config-option" import { Directory } from "./directory" +import { ACPNextEvent } from "./event" import { ACPNextSession } from "./session" import { ModelID, ProviderID } from "@/provider/schema" import { Provider } from "@/provider/provider" @@ -71,10 +72,15 @@ export function make(input: { connection?: Pick directory?: Directory.Interface session?: ACPNextSession.Interface + eventSubscription?: (subscription: ACPNextEvent.Subscription) => void }): Interface { const session = input.session ?? makeSessionService() const directoryService = input.directory ?? makeDirectoryService(input.sdk) const registeredMcp = new Map>() + if (input.connection) { + const subscription = ACPNextEvent.start({ sdk: input.sdk, connection: input.connection, session }) + input.eventSubscription?.(subscription) + } const initialize = Effect.fn("ACPNext.initialize")(function* (params: InitializeRequest) { const authMethod: AuthMethod = { @@ -476,17 +482,13 @@ type SdkResponse = { } type MessageInfo = { - readonly role?: string - readonly model?: { - readonly providerID?: string - readonly modelID?: string - readonly variant?: string - } - readonly providerID?: string - readonly modelID?: string - readonly variant?: string - readonly mode?: string - readonly agent?: string + readonly role?: Message["role"] + readonly model?: Extract["model"] + readonly providerID?: Extract["providerID"] + readonly modelID?: Extract["modelID"] + readonly variant?: Extract["variant"] + readonly mode?: Extract["mode"] + readonly agent?: Message["agent"] } function request(fn: () => Promise>, service?: string) { diff --git a/packages/opencode/src/acp-next/session.ts b/packages/opencode/src/acp-next/session.ts index 7a969c867f..6ab61f5f0a 100644 --- a/packages/opencode/src/acp-next/session.ts +++ b/packages/opencode/src/acp-next/session.ts @@ -1,4 +1,5 @@ import type { McpServer } from "@agentclientprotocol/sdk" +import type { Message, Part } from "@opencode-ai/sdk/v2" import { Context, Effect, Layer, Ref } from "effect" import type { ModelID, ProviderID } from "../provider/schema" import * as ACPNextError from "./error" @@ -11,6 +12,9 @@ export type SelectedModel = { export type KnownMessagePartMetadata = { messageId: string partId: string + partType?: Part["type"] + role?: Message["role"] + ignored?: boolean toolCallId?: string metadata?: unknown } @@ -40,6 +44,9 @@ export type RecordPartMetadataInput = { sessionId: string messageId: string partId: string + partType?: Part["type"] + role?: Message["role"] + ignored?: boolean toolCallId?: string metadata?: unknown } @@ -146,6 +153,9 @@ export const layer = Layer.effect( const metadata = { messageId: input.messageId, partId: input.partId, + partType: input.partType, + role: input.role, + ignored: input.ignored, toolCallId: input.toolCallId, metadata: input.metadata, } diff --git a/packages/opencode/src/acp-next/usage.ts b/packages/opencode/src/acp-next/usage.ts index a37f370c68..eabbb02af2 100644 --- a/packages/opencode/src/acp-next/usage.ts +++ b/packages/opencode/src/acp-next/usage.ts @@ -1,5 +1,6 @@ import type { AgentSideConnection, Usage } from "@agentclientprotocol/sdk" import * as Log from "@opencode-ai/core/util/log" +import type { AssistantMessage as OpenCodeAssistantMessage, Message } from "@opencode-ai/sdk/v2" import { InstanceRef } from "@/effect/instance-ref" import { InstanceStore } from "@/project/instance-store" import { ModelID, ProviderID } from "@/provider/schema" @@ -8,27 +9,14 @@ import { Context, Effect, Layer, SynchronizedRef } from "effect" const log = Log.create({ service: "acp-next-usage" }) -export type AssistantTokenCost = { - readonly cost: number - readonly tokens: { - readonly input: number - readonly output: number - readonly reasoning: number - readonly cache: { - readonly read: number - readonly write: number - } - } -} +export type AssistantTokenCost = Pick -export type AssistantMessage = AssistantTokenCost & { - readonly role: "assistant" - readonly providerID?: string - readonly modelID?: string -} +export type AssistantMessage = AssistantTokenCost & + Pick & + Partial> export type SessionMessage = { - readonly info: { readonly role: string } | AssistantMessage + readonly info: { readonly role: Message["role"] } | AssistantMessage } export type MessagesInput = { diff --git a/packages/opencode/test/acp-next/event.test.ts b/packages/opencode/test/acp-next/event.test.ts new file mode 100644 index 0000000000..8a4c88f234 --- /dev/null +++ b/packages/opencode/test/acp-next/event.test.ts @@ -0,0 +1,332 @@ +import { describe, expect, it } from "bun:test" +import type { AgentSideConnection } from "@agentclientprotocol/sdk" +import type { Event, Message, OpencodeClient, Part, SessionMessageResponse } from "@opencode-ai/sdk/v2" +import { Effect, ManagedRuntime } from "effect" +import { ACPNextEvent } from "@/acp-next/event" +import * as ACPNextService from "@/acp-next/service" +import { Directory } from "@/acp-next/directory" +import { ACPNextSession } from "@/acp-next/session" + +type SessionUpdateParams = Parameters[0] +type GlobalEventEnvelope = { + payload?: Event +} +type DeltaPartType = Extract["type"] + +const pollUntil = async ( + check: () => boolean | Promise, + message: string, + opts?: { timeoutMs?: number; intervalMs?: number }, +) => { + const started = Date.now() + while (true) { + if (await check()) return + if (Date.now() - started > (opts?.timeoutMs ?? 2000)) throw new Error(message) + await new Promise((resolve) => setTimeout(resolve, opts?.intervalMs ?? 5)) + } +} + +function makeSessionService() { + return ManagedRuntime.make(ACPNextSession.defaultLayer).runSync( + ACPNextSession.Service.use((service) => Effect.succeed(service)), + ) +} + +function createEventStream() { + const queue: GlobalEventEnvelope[] = [] + const waiters: Array<(value: GlobalEventEnvelope | undefined) => void> = [] + const state = { closed: false } + + const push = (event: GlobalEventEnvelope) => { + const waiter = waiters.shift() + if (waiter) { + waiter(event) + return + } + queue.push(event) + } + + const close = () => { + state.closed = true + for (const waiter of waiters.splice(0)) { + waiter(undefined) + } + } + + const stream = async function* (signal?: AbortSignal) { + while (true) { + if (signal?.aborted) return + const next = queue.shift() + if (next) { + yield next + continue + } + if (state.closed) return + const value = await new Promise((resolve) => { + waiters.push(resolve) + signal?.addEventListener("abort", () => resolve(undefined), { once: true }) + }) + if (!value) return + yield value + } + } + + return { push, close, stream } +} + +function createHarness(messages: Record = {}) { + const updates: SessionUpdateParams[] = [] + const calls = { + eventSubscribe: 0, + message: 0, + } + const events = createEventStream() + const sdk = { + global: { + event: (options?: { signal?: AbortSignal }) => { + calls.eventSubscribe++ + return Promise.resolve({ stream: events.stream(options?.signal) }) + }, + }, + session: { + message: (input: { messageID: string }) => { + calls.message++ + return Promise.resolve({ data: messages[input.messageID] }) + }, + get: () => Promise.resolve({ data: { id: "ses_loaded" } }), + messages: () => Promise.resolve({ data: [] }), + }, + } as unknown as OpencodeClient + const connection = { + sessionUpdate: (params: SessionUpdateParams) => { + updates.push(params) + return Promise.resolve() + }, + } satisfies Pick + const session = makeSessionService() + const subscription = new ACPNextEvent.Subscription({ sdk, connection, session }) + + return { calls, connection, events, sdk, session, subscription, updates } +} + +function textDelta(sessionID: string, messageID: string, partID: string, delta: string): Event { + return { + id: `evt_${sessionID}_${messageID}_${partID}_${delta}`, + type: "message.part.delta", + properties: { + sessionID, + messageID, + partID, + field: "text", + delta, + }, + } +} + +function partUpdated(sessionID: string, messageID: string, partID: string, type: DeltaPartType): Event { + return { + id: `evt_${sessionID}_${messageID}_${partID}`, + type: "message.part.updated", + properties: { + sessionID, + time: Date.now(), + part: + type === "text" + ? { + id: partID, + sessionID, + messageID, + type: "text", + text: "", + } + : { + id: partID, + sessionID, + messageID, + type: "reasoning", + text: "", + time: { start: Date.now() }, + }, + }, + } +} + +function assistantMessage(sessionID: string, messageID: string, partID: string, type: DeltaPartType) { + return { + info: { + id: messageID, + sessionID, + role: "assistant", + time: { created: Date.now() }, + parentID: "msg_parent", + modelID: "model", + providerID: "provider", + mode: "build", + agent: "build", + path: { cwd: "/workspace", root: "/workspace" }, + cost: 0, + tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, + }, + parts: [ + type === "text" + ? { + id: partID, + sessionID, + messageID, + type: "text", + text: "", + } + : { + id: partID, + sessionID, + messageID, + type: "reasoning", + text: "", + time: { start: Date.now() }, + }, + ], + } satisfies SessionMessageResponse +} + +async function createKnownSession( + session: ACPNextSession.Interface, + sessionId: string, + part: { messageId: string; partId: string; partType: Part["type"]; role?: Message["role"] }, +) { + await Effect.runPromise(session.create({ id: sessionId, cwd: "/workspace" })) + await Effect.runPromise( + session.recordPartMetadata({ + sessionId, + messageId: part.messageId, + partId: part.partId, + partType: part.partType, + role: part.role ?? "assistant", + }), + ) +} + +describe("acp-next event routing", () => { + it("routes message.part.delta by sessionID without cross-session pollution", async () => { + const harness = createHarness() + await createKnownSession(harness.session, "ses_a", { messageId: "msg_a", partId: "part_a", partType: "text" }) + await createKnownSession(harness.session, "ses_b", { messageId: "msg_b", partId: "part_b", partType: "text" }) + + await harness.subscription.handle(textDelta("ses_b", "msg_b", "part_b", "hello")) + + expect(harness.updates.map((update) => update.sessionId)).toEqual(["ses_b"]) + expect(harness.updates[0]?.update.sessionUpdate).toBe("agent_message_chunk") + }) + + it("keeps interleaved sessions isolated for text and reasoning deltas", async () => { + const harness = createHarness() + await createKnownSession(harness.session, "ses_a", { messageId: "msg_a", partId: "part_a", partType: "text" }) + await createKnownSession(harness.session, "ses_b", { + messageId: "msg_b", + partId: "part_b", + partType: "reasoning", + }) + + await harness.subscription.handle(textDelta("ses_a", "msg_a", "part_a", "A1")) + await harness.subscription.handle(textDelta("ses_b", "msg_b", "part_b", "B1")) + await harness.subscription.handle(textDelta("ses_a", "msg_a", "part_a", "A2")) + await harness.subscription.handle(textDelta("ses_b", "msg_b", "part_b", "B2")) + + expect( + harness.updates + .filter((update) => update.sessionId === "ses_a") + .map((update) => update.update.sessionUpdate), + ).toEqual(["agent_message_chunk", "agent_message_chunk"]) + expect( + harness.updates + .filter((update) => update.sessionId === "ses_b") + .map((update) => update.update.sessionUpdate), + ).toEqual(["agent_thought_chunk", "agent_thought_chunk"]) + }) + + it("does not create extra subscriptions on repeated loadSession", async () => { + const harness = createHarness() + let subscription: ACPNextEvent.Subscription | undefined + const service = ACPNextService.make({ + sdk: harness.sdk, + connection: harness.connection, + directory: { + get: () => + Effect.succeed( + Directory.build({ + directory: "/workspace", + providers: {}, + modes: [], + defaultModeID: "build", + commands: [], + }), + ), + refresh: () => + Effect.succeed( + Directory.build({ + directory: "/workspace", + providers: {}, + modes: [], + defaultModeID: "build", + commands: [], + }), + ), + variants: Directory.variants, + }, + session: harness.session, + eventSubscription: (started) => { + subscription = started + }, + }) + + await pollUntil(() => harness.calls.eventSubscribe === 1, "event subscription did not start") + await Effect.runPromise(service.loadSession({ cwd: "/workspace", sessionId: "ses_loaded", mcpServers: [] })) + await Effect.runPromise(service.loadSession({ cwd: "/workspace", sessionId: "ses_loaded", mcpServers: [] })) + await Effect.runPromise(service.loadSession({ cwd: "/workspace", sessionId: "ses_loaded", mcpServers: [] })) + + expect(harness.calls.eventSubscribe).toBe(1) + subscription?.stop() + harness.events.close() + }) + + it("does not call sdk.session.message repeatedly when metadata is known", async () => { + const harness = createHarness() + await createKnownSession(harness.session, "ses_a", { messageId: "msg_a", partId: "part_a", partType: "text" }) + + for (const delta of ["a", "b", "c", "d", "e"]) { + await harness.subscription.handle(textDelta("ses_a", "msg_a", "part_a", delta)) + } + + expect(harness.calls.message).toBe(0) + expect(harness.updates).toHaveLength(5) + }) + + it("fetches unknown part metadata once and reuses it for later deltas", async () => { + const harness = createHarness({ + msg_a: assistantMessage("ses_a", "msg_a", "part_a", "text"), + }) + await Effect.runPromise(harness.session.create({ id: "ses_a", cwd: "/workspace" })) + + await harness.subscription.handle(partUpdated("ses_a", "msg_a", "part_a", "text")) + await harness.subscription.handle(textDelta("ses_a", "msg_a", "part_a", "a")) + await harness.subscription.handle(textDelta("ses_a", "msg_a", "part_a", "b")) + + expect(harness.calls.message).toBe(1) + expect(harness.updates).toHaveLength(2) + }) + + it("ignores unknown sessions and live user parts without user_message_chunk duplication", async () => { + const harness = createHarness() + await createKnownSession(harness.session, "ses_user", { + messageId: "msg_user", + partId: "part_user", + partType: "text", + role: "user", + }) + + await harness.subscription.handle(textDelta("ses_missing", "msg_missing", "part_missing", "ignored")) + await harness.subscription.handle(partUpdated("ses_user", "msg_user", "part_live", "text")) + await harness.subscription.handle(textDelta("ses_user", "msg_user", "part_user", "hello")) + + expect(harness.updates).toHaveLength(0) + }) +}) From 8845a43e9eb4af3392cc719c97186fb0d5c2ccdc Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Tue, 26 May 2026 06:48:48 +0000 Subject: [PATCH 07/40] chore: generate --- packages/opencode/src/acp-next/event.ts | 6 +----- packages/opencode/test/acp-next/event.test.ts | 8 ++------ 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/opencode/src/acp-next/event.ts b/packages/opencode/src/acp-next/event.ts index cffdccf14a..86c902d46e 100644 --- a/packages/opencode/src/acp-next/event.ts +++ b/packages/opencode/src/acp-next/event.ts @@ -21,11 +21,7 @@ type GlobalEventStream = { stream: AsyncIterable } -export function start(input: { - sdk: OpencodeClient - connection: Connection - session: ACPNextSession.Interface -}) { +export function start(input: { sdk: OpencodeClient; connection: Connection; session: ACPNextSession.Interface }) { const subscription = new Subscription(input) subscription.start() return subscription diff --git a/packages/opencode/test/acp-next/event.test.ts b/packages/opencode/test/acp-next/event.test.ts index 8a4c88f234..a101d2f347 100644 --- a/packages/opencode/test/acp-next/event.test.ts +++ b/packages/opencode/test/acp-next/event.test.ts @@ -232,14 +232,10 @@ describe("acp-next event routing", () => { await harness.subscription.handle(textDelta("ses_b", "msg_b", "part_b", "B2")) expect( - harness.updates - .filter((update) => update.sessionId === "ses_a") - .map((update) => update.update.sessionUpdate), + harness.updates.filter((update) => update.sessionId === "ses_a").map((update) => update.update.sessionUpdate), ).toEqual(["agent_message_chunk", "agent_message_chunk"]) expect( - harness.updates - .filter((update) => update.sessionId === "ses_b") - .map((update) => update.update.sessionUpdate), + harness.updates.filter((update) => update.sessionId === "ses_b").map((update) => update.update.sessionUpdate), ).toEqual(["agent_thought_chunk", "agent_thought_chunk"]) }) From b5632ea7003fcc0053fc30c8e12348ce4ff99ea7 Mon Sep 17 00:00:00 2001 From: Shoubhit Dash Date: Tue, 26 May 2026 12:42:12 +0530 Subject: [PATCH 08/40] fix(config): fallback when user info unavailable (#29332) --- packages/opencode/src/config/config.ts | 9 ++++++++- packages/opencode/src/config/managed.ts | 9 ++++++++- packages/opencode/test/config/config.test.ts | 17 ++++++++++++++++- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 307b02ca4d..456d6c3ee3 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -762,7 +762,14 @@ export const layer = Layer.effect( result.permission = mergeDeep(perms, result.permission ?? {}) } - if (!result.username) result.username = os.userInfo().username + if (!result.username) { + try { + result.username = os.userInfo().username || "user" + } catch (err) { + log.warn("failed to read system username, using fallback", { err }) + result.username = "user" + } + } if (result.autoshare === true && !result.share) { result.share = "auto" diff --git a/packages/opencode/src/config/managed.ts b/packages/opencode/src/config/managed.ts index 5b04884208..c5348afaf7 100644 --- a/packages/opencode/src/config/managed.ts +++ b/packages/opencode/src/config/managed.ts @@ -46,7 +46,14 @@ export function parseManagedPlist(json: string): string { export async function readManagedPreferences() { if (process.platform !== "darwin") return - const user = os.userInfo().username + const user = (() => { + try { + return os.userInfo().username || "user" + } catch (err) { + log.warn("failed to read system username, using fallback", { err }) + return "user" + } + })() const paths = [ path.join("/Library/Managed Preferences", user, `${MANAGED_PLIST_DOMAIN}.plist`), path.join("/Library/Managed Preferences", `${MANAGED_PLIST_DOMAIN}.plist`), diff --git a/packages/opencode/test/config/config.test.ts b/packages/opencode/test/config/config.test.ts index 6ce0acdb2a..4d5aaf6fe1 100644 --- a/packages/opencode/test/config/config.test.ts +++ b/packages/opencode/test/config/config.test.ts @@ -1,4 +1,4 @@ -import { test, expect, describe, afterEach, beforeEach } from "bun:test" +import { test, expect, describe, afterEach, beforeEach, spyOn } from "bun:test" import { Effect, Exit, Layer, Option } from "effect" import { FetchHttpClient, HttpClient, HttpClientResponse } from "effect/unstable/http" import { NodeFileSystem, NodePath } from "@effect/platform-node" @@ -28,6 +28,7 @@ import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import { testEffect } from "../lib/effect" import path from "path" import fs from "fs/promises" +import os from "os" import { pathToFileURL } from "url" import { Global } from "@opencode-ai/core/global" import { ProjectID } from "../../src/project/schema" @@ -291,6 +292,20 @@ it.instance("loads config with defaults when no files exist", () => }), ) +it.instance("falls back to generic username when system user info is unavailable", () => + Effect.gen(function* () { + const userInfo = spyOn(os, "userInfo").mockImplementation(() => { + throw Object.assign(new Error("missing passwd entry"), { code: "ENOENT" }) + }) + try { + const config = yield* Config.use.get() + expect(config.username).toBe("user") + } finally { + userInfo.mockRestore() + } + }), +) + it.effect("creates global jsonc config with schema when no global configs exist", () => withGlobalConfig({}, ({ dir }) => Effect.gen(function* () { From 717e74f3e51ccf64851433b256f9fec7a124bd87 Mon Sep 17 00:00:00 2001 From: Shoubhit Dash Date: Tue, 26 May 2026 12:48:31 +0530 Subject: [PATCH 09/40] feat(acp): stream acp-next tool updates (#29333) --- packages/opencode/src/acp-next/event.ts | 125 +++++++ packages/opencode/src/acp-next/service.ts | 24 +- packages/opencode/src/acp-next/tool.ts | 118 ++++++- packages/opencode/test/acp-next/event.test.ts | 331 +++++++++++++++++- 4 files changed, 591 insertions(+), 7 deletions(-) diff --git a/packages/opencode/src/acp-next/event.ts b/packages/opencode/src/acp-next/event.ts index 86c902d46e..25aa5c08ef 100644 --- a/packages/opencode/src/acp-next/event.ts +++ b/packages/opencode/src/acp-next/event.ts @@ -7,9 +7,18 @@ import type { OpencodeClient, Part, SessionMessageResponse, + ToolPart, } from "@opencode-ai/sdk/v2" import { Effect } from "effect" import { ACPNextSession } from "./session" +import { + duplicateRunningToolUpdate, + errorToolUpdate, + pendingToolCall, + runningToolUpdate, + shellOutputSnapshot, + completedToolUpdate, +} from "./tool" const log = Log.create({ service: "acp-next-event" }) @@ -29,6 +38,8 @@ export function start(input: { sdk: OpencodeClient; connection: Connection; sess export class Subscription { private readonly abort = new AbortController() + private readonly shellSnapshots = new Map() + private readonly toolStarts = new Set() private started = false constructor( @@ -61,6 +72,17 @@ export class Subscription { } } + async replayMessage(message: SessionMessageResponse) { + if (message.info.role !== "assistant" && message.info.role !== "user") return + + for (const part of message.parts) { + await this.recordFetchedPart(message.info.sessionID, message, part) + if (part.type === "tool") { + await this.handleToolPart(message.info.sessionID, part) + } + } + } + private async run() { while (!this.abort.signal.aborted) { const events = (await this.input.sdk.global.event({ @@ -96,6 +118,9 @@ export class Subscription { metadata: "metadata" in part ? part.metadata : undefined, }), ) + if (part.type === "tool") { + await this.handleToolPart(session.id, part) + } } private async handlePartDelta(event: EventMessagePartDelta) { @@ -181,6 +206,106 @@ export class Subscription { }), ) } + + private async handleToolPart(sessionId: string, part: ToolPart) { + await this.toolStart(sessionId, part) + + switch (part.state.status) { + case "pending": + this.shellSnapshots.delete(part.callID) + return + + case "running": + await this.runningTool(sessionId, part) + return + + case "completed": + this.clearTool(part.callID) + await this.input.connection.sessionUpdate({ + sessionId, + update: { + sessionUpdate: "tool_call_update", + ...completedToolUpdate({ + toolCallId: part.callID, + toolName: part.tool, + state: part.state, + }), + }, + }) + return + + case "error": + this.clearTool(part.callID) + await this.input.connection.sessionUpdate({ + sessionId, + update: { + sessionUpdate: "tool_call_update", + ...errorToolUpdate({ + toolCallId: part.callID, + toolName: part.tool, + state: part.state, + }), + }, + }) + return + } + } + + private async runningTool(sessionId: string, part: ToolPart) { + if (part.state.status !== "running") return + + const output = part.tool === "bash" ? shellOutputSnapshot(part.state) : undefined + if (output !== undefined) { + if (this.shellSnapshots.get(part.callID) === output) { + await this.input.connection.sessionUpdate({ + sessionId, + update: { + sessionUpdate: "tool_call_update", + ...duplicateRunningToolUpdate({ + toolCallId: part.callID, + toolName: part.tool, + state: part.state, + }), + }, + }) + return + } + this.shellSnapshots.set(part.callID, output) + } + + await this.input.connection.sessionUpdate({ + sessionId, + update: { + sessionUpdate: "tool_call_update", + ...runningToolUpdate({ + toolCallId: part.callID, + toolName: part.tool, + state: part.state, + output, + }), + }, + }) + } + + private async toolStart(sessionId: string, part: ToolPart) { + if (this.toolStarts.has(part.callID)) return + this.toolStarts.add(part.callID) + await this.input.connection.sessionUpdate({ + sessionId, + update: { + sessionUpdate: "tool_call", + ...pendingToolCall({ + toolCallId: part.callID, + toolName: part.tool, + }), + }, + }) + } + + private clearTool(toolCallId: string) { + this.toolStarts.delete(toolCallId) + this.shellSnapshots.delete(toolCallId) + } } export * as ACPNextEvent from "./event" diff --git a/packages/opencode/src/acp-next/service.ts b/packages/opencode/src/acp-next/service.ts index a465264d45..be368da623 100644 --- a/packages/opencode/src/acp-next/service.ts +++ b/packages/opencode/src/acp-next/service.ts @@ -31,7 +31,7 @@ import { } from "@agentclientprotocol/sdk" import { InstallationVersion } from "@opencode-ai/core/installation/version" import * as Log from "@opencode-ai/core/util/log" -import type { Message, OpencodeClient } from "@opencode-ai/sdk/v2" +import type { Message, OpencodeClient, SessionMessageResponse } from "@opencode-ai/sdk/v2" import { Context, Effect, Layer, ManagedRuntime } from "effect" import * as ACPNextError from "./error" import { buildConfigOptions, parseModelSelection } from "./config-option" @@ -77,10 +77,10 @@ export function make(input: { const session = input.session ?? makeSessionService() const directoryService = input.directory ?? makeDirectoryService(input.sdk) const registeredMcp = new Map>() - if (input.connection) { - const subscription = ACPNextEvent.start({ sdk: input.sdk, connection: input.connection, session }) - input.eventSubscription?.(subscription) - } + const events = input.connection + ? ACPNextEvent.start({ sdk: input.sdk, connection: input.connection, session }) + : undefined + if (events) input.eventSubscription?.(events) const initialize = Effect.fn("ACPNext.initialize")(function* (params: InitializeRequest) { const authMethod: AuthMethod = { @@ -207,6 +207,7 @@ export function make(input: { yield* registerMcpServers(input.sdk, registeredMcp, params.cwd, state.id, params.mcpServers) yield* sendAvailableCommands(input.connection, state.id, snapshot) + yield* replayMessages(events, messages) return { configOptions: configOptions(snapshot, { @@ -276,6 +277,7 @@ export function make(input: { yield* registerMcpServers(input.sdk, registeredMcp, params.cwd, state.id, params.mcpServers ?? []) yield* sendAvailableCommands(input.connection, state.id, snapshot) + yield* replayMessages(events, messages) return { configOptions: configOptions(snapshot, { @@ -335,6 +337,7 @@ export function make(input: { yield* registerMcpServers(input.sdk, registeredMcp, params.cwd, state.id, params.mcpServers ?? []) yield* sendAvailableCommands(input.connection, state.id, snapshot) + yield* replayMessages(events, messages) return { sessionId: state.id, @@ -470,6 +473,17 @@ function makeDirectoryService(sdk: OpencodeClient) { ).runSync(Directory.Service.use((service) => Effect.succeed(service))) } +function replayMessages(subscription: ACPNextEvent.Subscription | undefined, messages: SessionMessageResponse[]) { + if (!subscription) return Effect.void + return Effect.promise(async () => { + for (const message of messages) { + await subscription.replayMessage(message).catch((error: unknown) => { + log.error("failed to replay ACP message", { error, messageID: message.info.id }) + }) + } + }) +} + type ConfigState = { readonly model: Directory.DefaultModel readonly variant?: string diff --git a/packages/opencode/src/acp-next/tool.ts b/packages/opencode/src/acp-next/tool.ts index 128c4c9c85..288d24e31e 100644 --- a/packages/opencode/src/acp-next/tool.ts +++ b/packages/opencode/src/acp-next/tool.ts @@ -1,4 +1,4 @@ -import type { ToolCallContent, ToolCallLocation, ToolKind } from "@agentclientprotocol/sdk" +import type { ToolCall, ToolCallContent, ToolCallLocation, ToolCallUpdate, ToolKind } from "@agentclientprotocol/sdk" export type ToolInput = Record @@ -16,6 +16,19 @@ export type CompletedToolState = { readonly attachments?: ReadonlyArray } +export type RunningToolState = { + readonly status: "running" + readonly input: ToolInput + readonly title?: string +} + +export type ErrorToolState = { + readonly status: "error" + readonly input: ToolInput + readonly error: string + readonly metadata?: unknown +} + export type ImageAttachment = { readonly mimeType: string readonly data: string @@ -100,6 +113,104 @@ export function completedToolContent(toolName: string, state: CompletedToolState return content } +export function pendingToolCall(input: { readonly toolCallId: string; readonly toolName: string }): ToolCall { + return { + toolCallId: input.toolCallId, + title: input.toolName, + kind: toToolKind(input.toolName), + status: "pending", + locations: [], + rawInput: {}, + } +} + +export function runningToolUpdate(input: { + readonly toolCallId: string + readonly toolName: string + readonly state: RunningToolState + readonly output?: string +}): ToolCallUpdate { + const content = input.output + ? [ + { + type: "content" as const, + content: { + type: "text" as const, + text: input.output, + }, + }, + ] + : undefined + + return { + toolCallId: input.toolCallId, + status: "in_progress", + kind: toToolKind(input.toolName), + title: input.state.title ?? input.toolName, + locations: toLocations(input.toolName, input.state.input), + rawInput: input.state.input, + ...(content ? { content } : {}), + } +} + +export function duplicateRunningToolUpdate(input: { + readonly toolCallId: string + readonly toolName: string + readonly state: RunningToolState +}): ToolCallUpdate { + return { + toolCallId: input.toolCallId, + status: "in_progress", + kind: toToolKind(input.toolName), + title: input.state.title ?? input.toolName, + locations: toLocations(input.toolName, input.state.input), + rawInput: input.state.input, + } +} + +export function completedToolUpdate(input: { + readonly toolCallId: string + readonly toolName: string + readonly state: CompletedToolState & { readonly title: string } +}): ToolCallUpdate { + return { + toolCallId: input.toolCallId, + status: "completed", + kind: toToolKind(input.toolName), + title: input.state.title, + content: completedToolContent(input.toolName, input.state), + rawInput: input.state.input, + rawOutput: completedToolRawOutput(input.state), + } +} + +export function errorToolUpdate(input: { + readonly toolCallId: string + readonly toolName: string + readonly state: ErrorToolState +}): ToolCallUpdate { + return { + toolCallId: input.toolCallId, + status: "failed", + kind: toToolKind(input.toolName), + title: input.toolName, + rawInput: input.state.input, + content: [ + { + type: "content", + content: { + type: "text", + text: input.state.error, + }, + }, + ], + rawOutput: { + error: input.state.error, + metadata: input.state.metadata, + }, + } +} + export function completedToolRawOutput(state: CompletedToolState) { return { output: state.output, @@ -138,6 +249,11 @@ export const extractLocations = toLocations export const buildCompletedToolContent = completedToolContent export const buildCompletedRawOutput = completedToolRawOutput export const extractShellOutputSnapshot = shellOutputSnapshot +export const buildPendingToolCall = pendingToolCall +export const buildRunningToolUpdate = runningToolUpdate +export const buildDuplicateRunningToolUpdate = duplicateRunningToolUpdate +export const buildCompletedToolUpdate = completedToolUpdate +export const buildErrorToolUpdate = errorToolUpdate function locationFrom(value: unknown): ToolCallLocation[] { const path = stringValue(value) diff --git a/packages/opencode/test/acp-next/event.test.ts b/packages/opencode/test/acp-next/event.test.ts index a101d2f347..92b65b8881 100644 --- a/packages/opencode/test/acp-next/event.test.ts +++ b/packages/opencode/test/acp-next/event.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "bun:test" import type { AgentSideConnection } from "@agentclientprotocol/sdk" -import type { Event, Message, OpencodeClient, Part, SessionMessageResponse } from "@opencode-ai/sdk/v2" +import type { Event, Message, OpencodeClient, Part, SessionMessageResponse, ToolPart } from "@opencode-ai/sdk/v2" import { Effect, ManagedRuntime } from "effect" import { ACPNextEvent } from "@/acp-next/event" import * as ACPNextService from "@/acp-next/service" @@ -8,6 +8,9 @@ import { Directory } from "@/acp-next/directory" import { ACPNextSession } from "@/acp-next/session" type SessionUpdateParams = Parameters[0] +type ToolSessionUpdateParams = SessionUpdateParams & { + update: Extract +} type GlobalEventEnvelope = { payload?: Event } @@ -151,6 +154,18 @@ function partUpdated(sessionID: string, messageID: string, partID: string, type: } } +function toolUpdated(part: ToolPart): Event { + return { + id: `evt_${part.sessionID}_${part.messageID}_${part.id}_${part.state.status}`, + type: "message.part.updated", + properties: { + sessionID: part.sessionID, + time: Date.now(), + part, + }, + } +} + function assistantMessage(sessionID: string, messageID: string, partID: string, type: DeltaPartType) { return { info: { @@ -188,6 +203,98 @@ function assistantMessage(sessionID: string, messageID: string, partID: string, } satisfies SessionMessageResponse } +function assistantToolMessage(part: ToolPart) { + return { + info: { + id: part.messageID, + sessionID: part.sessionID, + role: "assistant", + time: { created: Date.now() }, + parentID: "msg_parent", + modelID: "model", + providerID: "provider", + mode: "build", + agent: "build", + path: { cwd: "/workspace", root: "/workspace" }, + cost: 0, + tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, + }, + parts: [part], + } satisfies SessionMessageResponse +} + +function runningTool( + sessionID: string, + callID: string, + output?: string, + input: Record = { cmd: "printf hello" }, +) { + return { + id: `part_${callID}`, + sessionID, + messageID: `msg_${callID}`, + type: "tool", + callID, + tool: "bash", + state: { + status: "running", + input, + title: "bash", + ...(output !== undefined ? { metadata: { output } } : {}), + time: { start: Date.now() }, + }, + } satisfies ToolPart +} + +function completedTool( + sessionID: string, + callID: string, + output = "done", + attachments: Extract["attachments"] = [], +) { + return { + id: `part_${callID}`, + sessionID, + messageID: `msg_${callID}`, + type: "tool", + callID, + tool: "bash", + state: { + status: "completed", + input: { cmd: "printf done" }, + output, + title: "bash", + metadata: { exit: 0 }, + time: { start: Date.now() - 1, end: Date.now() }, + ...(attachments.length ? { attachments } : {}), + }, + } satisfies ToolPart +} + +function errorTool(sessionID: string, callID: string) { + return { + id: `part_${callID}`, + sessionID, + messageID: `msg_${callID}`, + type: "tool", + callID, + tool: "bash", + state: { + status: "error", + input: { cmd: "exit 1" }, + error: "failed hard", + metadata: { exit: 1 }, + time: { start: Date.now() - 1, end: Date.now() }, + }, + } satisfies ToolPart +} + +function toolUpdates(updates: SessionUpdateParams[]) { + return updates.filter((item): item is ToolSessionUpdateParams => { + return item.update.sessionUpdate === "tool_call" || item.update.sessionUpdate === "tool_call_update" + }) +} + async function createKnownSession( session: ACPNextSession.Interface, sessionId: string, @@ -310,6 +417,85 @@ describe("acp-next event routing", () => { expect(harness.updates).toHaveLength(2) }) + it("replays loaded session messages sequentially and continues after update failures", async () => { + const events = createEventStream() + const updates: SessionUpdateParams[] = [] + const connection = { + sessionUpdate: (params: SessionUpdateParams) => { + if (params.update.sessionUpdate === "tool_call" && params.update.toolCallId === "call_slow") { + return new Promise((resolve) => { + setTimeout(() => { + updates.push(params) + resolve() + }, 20) + }) + } + + if (params.update.sessionUpdate === "tool_call_update" && params.update.toolCallId === "call_slow") { + return Promise.reject(new Error("replay send failed")) + } + + updates.push(params) + return Promise.resolve() + }, + } satisfies Pick + let subscription: ACPNextEvent.Subscription | undefined + const service = ACPNextService.make({ + sdk: { + global: { + event: (options?: { signal?: AbortSignal }) => Promise.resolve({ stream: events.stream(options?.signal) }), + }, + session: { + get: () => Promise.resolve({ data: { id: "ses_loaded" } }), + messages: () => + Promise.resolve({ + data: [ + assistantToolMessage(completedTool("ses_loaded", "call_slow", "slow")), + assistantToolMessage(completedTool("ses_loaded", "call_after", "after")), + ], + }), + }, + } as unknown as OpencodeClient, + connection, + directory: { + get: () => + Effect.succeed( + Directory.build({ + directory: "/workspace", + providers: {}, + modes: [], + defaultModeID: "build", + commands: [], + }), + ), + refresh: () => + Effect.succeed( + Directory.build({ + directory: "/workspace", + providers: {}, + modes: [], + defaultModeID: "build", + commands: [], + }), + ), + variants: Directory.variants, + }, + eventSubscription: (started) => { + subscription = started + }, + }) + + await Effect.runPromise(service.loadSession({ cwd: "/workspace", sessionId: "ses_loaded", mcpServers: [] })) + + expect(toolUpdates(updates).map((item) => item.update.toolCallId)).toEqual([ + "call_slow", + "call_after", + "call_after", + ]) + subscription?.stop() + events.close() + }) + it("ignores unknown sessions and live user parts without user_message_chunk duplication", async () => { const harness = createHarness() await createKnownSession(harness.session, "ses_user", { @@ -325,4 +511,147 @@ describe("acp-next event routing", () => { expect(harness.updates).toHaveLength(0) }) + + it("emits synthetic pending before the first running tool update", async () => { + const harness = createHarness() + await Effect.runPromise(harness.session.create({ id: "ses_tool", cwd: "/workspace" })) + + await harness.subscription.handle(toolUpdated(runningTool("ses_tool", "call_1", "hello"))) + + expect(toolUpdates(harness.updates).map((item) => item.update.sessionUpdate)).toEqual([ + "tool_call", + "tool_call_update", + ]) + expect(harness.updates[0]?.update).toMatchObject({ status: "pending", toolCallId: "call_1" }) + expect(harness.updates[1]?.update).toMatchObject({ status: "in_progress", toolCallId: "call_1" }) + }) + + it("does not emit duplicate synthetic pending after a replayed running tool", async () => { + const harness = createHarness() + await Effect.runPromise(harness.session.create({ id: "ses_replay", cwd: "/workspace" })) + + await harness.subscription.replayMessage(assistantToolMessage(runningTool("ses_replay", "call_replay", "first"))) + await harness.subscription.handle(toolUpdated(runningTool("ses_replay", "call_replay", "second"))) + + expect(toolUpdates(harness.updates).filter((item) => item.update.sessionUpdate === "tool_call")).toHaveLength(1) + expect(toolUpdates(harness.updates).map((item) => item.update.sessionUpdate)).toEqual([ + "tool_call", + "tool_call_update", + "tool_call_update", + ]) + }) + + it("dedupes shell output snapshots while still sending status-only running updates", async () => { + const harness = createHarness() + await Effect.runPromise(harness.session.create({ id: "ses_shell", cwd: "/workspace" })) + + await harness.subscription.handle(toolUpdated(runningTool("ses_shell", "call_shell", "same"))) + await harness.subscription.handle(toolUpdated(runningTool("ses_shell", "call_shell", "same"))) + + const updates = toolUpdates(harness.updates) + expect(updates).toHaveLength(3) + expect(updates[1]?.update).toMatchObject({ + sessionUpdate: "tool_call_update", + content: [{ type: "content", content: { type: "text", text: "same" } }], + }) + expect(updates[2]?.update).toMatchObject({ sessionUpdate: "tool_call_update", status: "in_progress" }) + expect("content" in updates[2]!.update).toBe(false) + }) + + it("clears shell snapshot marker when a tool returns to pending", async () => { + const harness = createHarness() + await Effect.runPromise(harness.session.create({ id: "ses_pending", cwd: "/workspace" })) + + await harness.subscription.handle(toolUpdated(runningTool("ses_pending", "call_pending", "repeat"))) + await harness.subscription.handle( + toolUpdated({ + id: "part_call_pending", + sessionID: "ses_pending", + messageID: "msg_call_pending", + type: "tool", + callID: "call_pending", + tool: "bash", + state: { + status: "pending", + input: { cmd: "printf repeat" }, + raw: '{"cmd":"printf repeat"}', + }, + }), + ) + await harness.subscription.handle(toolUpdated(runningTool("ses_pending", "call_pending", "repeat"))) + + expect( + toolUpdates(harness.updates) + .filter((item) => item.update.sessionUpdate === "tool_call_update") + .map((item) => ("content" in item.update ? item.update.content : undefined)), + ).toEqual([ + [{ type: "content", content: { type: "text", text: "repeat" } }], + [{ type: "content", content: { type: "text", text: "repeat" } }], + ]) + }) + + it("emits completed tool output and rawOutput", async () => { + const harness = createHarness() + await Effect.runPromise(harness.session.create({ id: "ses_done", cwd: "/workspace" })) + + await harness.subscription.handle(toolUpdated(completedTool("ses_done", "call_done", "finished"))) + + expect(harness.updates.at(-1)?.update).toMatchObject({ + sessionUpdate: "tool_call_update", + toolCallId: "call_done", + status: "completed", + content: [{ type: "content", content: { type: "text", text: "finished" } }], + rawOutput: { output: "finished", metadata: { exit: 0 } }, + }) + }) + + it("emits error tool output", async () => { + const harness = createHarness() + await Effect.runPromise(harness.session.create({ id: "ses_error", cwd: "/workspace" })) + + await harness.subscription.handle(toolUpdated(errorTool("ses_error", "call_error"))) + + expect(harness.updates.at(-1)?.update).toMatchObject({ + sessionUpdate: "tool_call_update", + toolCallId: "call_error", + status: "failed", + content: [{ type: "content", content: { type: "text", text: "failed hard" } }], + rawOutput: { error: "failed hard", metadata: { exit: 1 } }, + }) + }) + + it("emits image attachments as ACP image content for live and replayed completed tool updates", async () => { + const harness = createHarness() + const image = Buffer.from("image-data").toString("base64") + const attachment = { + id: "file_image", + sessionID: "ses_image", + messageID: "msg_image", + type: "file", + mime: "image/png", + filename: "image.png", + url: `data:image/png;base64,${image}`, + } as const + await Effect.runPromise(harness.session.create({ id: "ses_image", cwd: "/workspace" })) + + await harness.subscription.handle(toolUpdated(completedTool("ses_image", "call_live", "live", [attachment]))) + await harness.subscription.replayMessage( + assistantToolMessage(completedTool("ses_image", "call_replayed", "replayed", [attachment])), + ) + + expect( + toolUpdates(harness.updates) + .filter((item) => item.update.sessionUpdate === "tool_call_update" && item.update.status === "completed") + .map((item) => ("content" in item.update ? item.update.content : [])), + ).toEqual([ + [ + { type: "content", content: { type: "text", text: "live" } }, + { type: "content", content: { type: "image", mimeType: "image/png", data: image } }, + ], + [ + { type: "content", content: { type: "text", text: "replayed" } }, + { type: "content", content: { type: "image", mimeType: "image/png", data: image } }, + ], + ]) + }) }) From c71fe789700ee039842ceebaa8a0d0e214103213 Mon Sep 17 00:00:00 2001 From: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Date: Tue, 26 May 2026 15:26:59 +0800 Subject: [PATCH 10/40] fix(app): disable health check for web deployments (#29319) --- packages/app/src/entry.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/app/src/entry.tsx b/packages/app/src/entry.tsx index 50fd5e18f6..5115f0348a 100644 --- a/packages/app/src/entry.tsx +++ b/packages/app/src/entry.tsx @@ -168,7 +168,11 @@ if (root instanceof HTMLElement) { () => ( - + ), From 1f66db0e4e174675373d72a17cb47b6e6f4f3e42 Mon Sep 17 00:00:00 2001 From: Luke Parker <10430890+Hona@users.noreply.github.com> Date: Tue, 26 May 2026 17:36:46 +1000 Subject: [PATCH 11/40] test(app): restore timeline e2e server health mock (#29336) --- .../session-timeline-collapse-state.spec.ts | 61 +++---------------- .../session-timeline-context-resize.spec.ts | 49 +++------------ packages/app/e2e/utils/mock-server.ts | 12 +++- 3 files changed, 26 insertions(+), 96 deletions(-) diff --git a/packages/app/e2e/regression/session-timeline-collapse-state.spec.ts b/packages/app/e2e/regression/session-timeline-collapse-state.spec.ts index db191d2575..88b140a61d 100644 --- a/packages/app/e2e/regression/session-timeline-collapse-state.spec.ts +++ b/packages/app/e2e/regression/session-timeline-collapse-state.spec.ts @@ -1,4 +1,5 @@ -import { expect, test, type Locator, type Page, type Route } from "@playwright/test" +import { expect, test, type Locator, type Page } from "@playwright/test" +import { mockOpenCodeServer } from "../utils/mock-server" const directory = "C:/OpenCode/TimelineStateRegression" const projectID = "proj_timeline_state_regression" @@ -299,39 +300,13 @@ function readExpanded(element: Element) { } async function mockServer(page: Page, events: EventPayload[]) { - await page.route("**/*", async (route) => { - const url = new URL(route.request().url()) - const targetPort = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096" - if (url.port !== targetPort) return route.fallback() - - const path = url.pathname - if (path === "/global/event") return sse(route, events.splice(0)) - if ( - path === "/global/config" || - path === "/config" || - path === "/provider/auth" || - path === "/mcp" || - path === "/session/status" - ) - return json(route, {}) - if ( - ["/skill", "/command", "/lsp", "/formatter", "/permission", "/question", "/vcs/status", "/vcs/diff"].includes( - path, - ) - ) - return json(route, []) - if (path === "/provider") return json(route, provider()) - if (path === "/path") - return json(route, { state: directory, config: directory, worktree: directory, directory, home: "C:/OpenCode" }) - if (path === "/project") return json(route, [project()]) - if (path === "/project/current") return json(route, project()) - if (path === "/agent") return json(route, [{ name: "build", mode: "primary" }]) - if (path === "/vcs") return json(route, { branch: "main", default_branch: "main" }) - if (path === "/session") return json(route, [session()]) - if (path === `/session/${sessionID}`) return json(route, session()) - if (/^\/session\/[^/]+\/(children|todo|diff)$/.test(path)) return json(route, []) - if (path === `/session/${sessionID}/message`) return json(route, [userMessage, assistantMessage]) - return json(route, {}) + await mockOpenCodeServer(page, { + directory, + project: project(), + provider: provider(), + sessions: [session()], + pageMessages: () => ({ items: [userMessage, assistantMessage] }), + events: () => events.splice(0), }) } @@ -372,24 +347,6 @@ function provider() { } } -function json(route: Route, body: unknown, headers?: Record) { - return route.fulfill({ - status: 200, - contentType: "application/json", - headers: { "access-control-allow-origin": "*", "access-control-expose-headers": "x-next-cursor", ...headers }, - body: JSON.stringify(body ?? null), - }) -} - -function sse(route: Route, events: EventPayload[]) { - return route.fulfill({ - status: 200, - contentType: "text/event-stream", - headers: { "access-control-allow-origin": "*" }, - body: events.map((event) => `data: ${JSON.stringify(event)}\n\n`).join(""), - }) -} - function base64Encode(value: string) { return Buffer.from(value, "utf8").toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "") } diff --git a/packages/app/e2e/regression/session-timeline-context-resize.spec.ts b/packages/app/e2e/regression/session-timeline-context-resize.spec.ts index 98f34b2b9c..dc72e24f0d 100644 --- a/packages/app/e2e/regression/session-timeline-context-resize.spec.ts +++ b/packages/app/e2e/regression/session-timeline-context-resize.spec.ts @@ -1,4 +1,5 @@ -import { expect, test, type Page, type Route } from "@playwright/test" +import { expect, test, type Page } from "@playwright/test" +import { mockOpenCodeServer } from "../utils/mock-server" const directory = "C:/OpenCode/ContextResizeRegression" const projectID = "proj_context_resize_regression" @@ -207,33 +208,12 @@ function contextTool(partID: string, messageID: string, tool: string, input: Rec } async function mockServer(page: Page) { - await page.route("**/*", async (route) => { - const url = new URL(route.request().url()) - const targetPort = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096" - if (url.port !== targetPort) return route.fallback() - - const path = url.pathname - if (path === "/global/event" || path === "/event") return sse(route) - if (["/global/config", "/config", "/provider/auth", "/mcp", "/session/status"].includes(path)) - return json(route, {}) - if ( - ["/skill", "/command", "/lsp", "/formatter", "/permission", "/question", "/vcs/status", "/vcs/diff"].includes( - path, - ) - ) - return json(route, []) - if (path === "/provider") return json(route, provider()) - if (path === "/path") - return json(route, { state: directory, config: directory, worktree: directory, directory, home: "C:/OpenCode" }) - if (path === "/project") return json(route, [project()]) - if (path === "/project/current") return json(route, project()) - if (path === "/agent") return json(route, [{ name: "build", mode: "primary" }]) - if (path === "/vcs") return json(route, { branch: "main", default_branch: "main" }) - if (path === "/session") return json(route, [session()]) - if (path === `/session/${sessionID}`) return json(route, session()) - if (/^\/session\/[^/]+\/(children|todo|diff)$/.test(path)) return json(route, []) - if (path === `/session/${sessionID}/message`) return json(route, messages) - return json(route, {}) + await mockOpenCodeServer(page, { + directory, + project: project(), + provider: provider(), + sessions: [session()], + pageMessages: () => ({ items: messages }), }) } @@ -282,19 +262,6 @@ function provider() { } } -function json(route: Route, body: unknown, headers?: Record) { - return route.fulfill({ - status: 200, - contentType: "application/json", - headers: { "access-control-allow-origin": "*", "access-control-expose-headers": "x-next-cursor", ...headers }, - body: JSON.stringify(body ?? null), - }) -} - -function sse(route: Route) { - return route.fulfill({ status: 200, contentType: "text/event-stream", body: ": ok\n\n" }) -} - function base64Encode(value: string) { return Buffer.from(value, "utf8").toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "") } diff --git a/packages/app/e2e/utils/mock-server.ts b/packages/app/e2e/utils/mock-server.ts index b89f46deea..9a03a9d5ad 100644 --- a/packages/app/e2e/utils/mock-server.ts +++ b/packages/app/e2e/utils/mock-server.ts @@ -18,6 +18,7 @@ export interface MockServerConfig { project: unknown sessions: ({ id: string } & Record)[] pageMessages: (sessionId: string, limit: number, before?: string) => { items: unknown[]; cursor?: string } + events?: () => unknown[] } export async function mockOpenCodeServer(page: Page, config: MockServerConfig) { @@ -43,7 +44,8 @@ export async function mockOpenCodeServer(page: Page, config: MockServerConfig) { if (url.port !== targetPort) return route.fallback() const path = url.pathname - if (path === "/global/event" || path === "/event") return sse(route) + if (path === "/global/event" || path === "/event") return sse(route, config.events?.()) + if (path === "/global/health") return json(route, { healthy: true }) if (emptyObject.has(path)) return json(route, {}) if (emptyList.has(path)) return json(route, []) if (path in staticRoutes) return json(route, staticRoutes[path]) @@ -81,6 +83,10 @@ function json(route: Route, body: unknown, headers?: Record) { }) } -function sse(route: Route) { - return route.fulfill({ status: 200, contentType: "text/event-stream", body: ": ok\n\n" }) +function sse(route: Route, events?: unknown[]) { + return route.fulfill({ + status: 200, + contentType: "text/event-stream", + body: events?.map((event) => `data: ${JSON.stringify(event)}\n\n`).join("") || ": ok\n\n", + }) } From 13c9d097a020e5c1ece8693f6507d809cc039ade Mon Sep 17 00:00:00 2001 From: Luke Parker <10430890+Hona@users.noreply.github.com> Date: Tue, 26 May 2026 17:50:07 +1000 Subject: [PATCH 12/40] feat(app): refine desktop v2 home and session controls (#28788) --- packages/app/src/components/prompt-input.tsx | 498 +++++++++++++----- .../src/components/session/session-header.tsx | 422 ++++++++------- .../session/session-new-design-view.tsx | 63 +-- .../app/src/components/settings-general.tsx | 27 +- .../src/components/status-popover-body.tsx | 153 ++++++ .../app/src/components/status-popover.tsx | 133 ++++- packages/app/src/components/titlebar.tsx | 96 ++-- packages/app/src/context/settings.tsx | 6 + packages/app/src/i18n/en.ts | 9 +- packages/app/src/i18n/uk.ts | 2 +- packages/app/src/pages/home.tsx | 293 +++++++++-- packages/app/src/pages/session.tsx | 3 +- .../composer/session-composer-region.tsx | 2 - .../src/pages/session/session-side-panel.tsx | 10 +- .../pages/session/use-session-commands.tsx | 8 +- packages/ui/src/v2/components/icon.tsx | 12 + 16 files changed, 1252 insertions(+), 485 deletions(-) diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index a087c366e7..3dd3b4ad59 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -4,6 +4,8 @@ import { createEffect, on, Component, + splitProps, + For, Show, onCleanup, createMemo, @@ -11,7 +13,10 @@ import { createResource, Switch, Match, + type ComponentProps, + type JSX, } from "solid-js" +import { Popover as KobaltePopover } from "@kobalte/core/popover" import { createStore } from "solid-js/store" import { useLocal } from "@/context/local" import { selectionFromLines, type SelectedLineRange, useFile } from "@/context/file" @@ -26,12 +31,14 @@ import { FileAttachmentPart, } from "@/context/prompt" import { useLayout } from "@/context/layout" +import { useNavigate } from "@solidjs/router" import { useSDK } from "@/context/sdk" +import { useServer } from "@/context/server" import { useSync } from "@/context/sync" import { useComments } from "@/context/comments" import { Button } from "@opencode-ai/ui/button" import { DockShellForm, DockTray } from "@opencode-ai/ui/dock-surface" -import { Icon } from "@opencode-ai/ui/icon" +import { Icon, type IconProps } from "@opencode-ai/ui/icon" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" import { IconButton } from "@opencode-ai/ui/icon-button" @@ -44,6 +51,7 @@ import { Persist, persisted } from "@/utils/persist" import { usePermission } from "@/context/permission" import { useLanguage } from "@/context/language" import { usePlatform } from "@/context/platform" +import { useSettings } from "@/context/settings" import { useSessionLayout } from "@/pages/session/session-layout" import { createSessionTabs } from "@/pages/session/helpers" import { createTextFragment, getCursorPosition, setCursorPosition, setRangeEdge } from "./prompt-input/editor-dom" @@ -68,14 +76,16 @@ import { ImagePreview } from "@opencode-ai/ui/image-preview" import { useQueries } from "@tanstack/solid-query" import { useQueryOptions } from "@/context/server-sync" import { pathKey } from "@/utils/path-key" -import { getFilename } from "@opencode-ai/core/util/path" +import { base64Encode } from "@opencode-ai/core/util/encode" +import { displayName } from "@/pages/layout/helpers" + +const USE_V2_INPUT = import.meta.env.VITE_OPENCODE_CHANNEL !== "prod" interface PromptInputProps { class?: string variant?: "dock" | "new-session" ref?: (el: HTMLDivElement) => void newSessionWorktree?: string - onNewSessionWorktreeChange?: (worktree: string) => void onNewSessionWorktreeReset?: () => void edit?: { id: string; prompt: Prompt; context: FollowupDraft["context"] } onEditLoaded?: () => void @@ -113,11 +123,9 @@ const EXAMPLES = [ "prompt.example.25", ] as const -const MAIN_WORKTREE = "main" -const CREATE_WORKTREE = "create" - export const PromptInput: Component = (props) => { const sdk = useSDK() + const navigate = useNavigate() const queryOptions = useQueryOptions() const sync = useSync() @@ -125,6 +133,7 @@ export const PromptInput: Component = (props) => { const files = useFile() const prompt = usePrompt() const layout = useLayout() + const server = useServer() const comments = useComments() const dialog = useDialog() const providers = useProviders() @@ -132,11 +141,13 @@ export const PromptInput: Component = (props) => { const permission = usePermission() const language = useLanguage() const platform = usePlatform() + const settings = useSettings() const { params, tabs, view } = useSessionLayout() let editorRef!: HTMLDivElement let fileInputRef: HTMLInputElement | undefined let scrollRef!: HTMLDivElement let slashPopoverRef!: HTMLDivElement + let projectSearchRef: HTMLInputElement | undefined const mirror = { input: false } const inset = 56 @@ -277,6 +288,10 @@ export const PromptInput: Component = (props) => { mode: "normal", applyingHistory: false, }) + const [picker, setPicker] = createStore({ + projectOpen: false, + projectSearch: "", + }) const buttonsSpring = useSpring(() => (store.mode === "normal" ? 1 : 0), { visualDuration: 0.2, bounce: 0 }) const motion = (value: number) => ({ @@ -1303,91 +1318,122 @@ export const PromptInput: Component = (props) => { return "Ask anything, / for commands, @ for context..." } - const modelControl = () => ( - - 0} - fallback={ - - - - } - > - - - - - - {local.model.current()?.name ?? language.t("dialog.model.select.title")} - - - - - - ) + const modelControlState = createMemo(() => ({ + loading: providersLoading(), + paid: providers.paid().length > 0, + title: language.t("command.model.choose"), + keybind: command.keybind("model.choose"), + model: local.model, + providerID: local.model.current()?.provider?.id, + modelName: local.model.current()?.name ?? language.t("dialog.model.select.title"), + style: control(), + onClose: restoreFocus, + onUnpaidClick: () => { + void import("@/components/dialog-select-model-unpaid").then((x) => { + dialog.show(() => ) + }) + }, + })) const newSession = () => props.variant === "new-session" - const worktrees = createMemo(() => [MAIN_WORKTREE, ...(sync.project?.sandboxes ?? []), CREATE_WORKTREE]) - const currentWorktree = createMemo(() => { - if (worktrees().includes(props.newSessionWorktree ?? MAIN_WORKTREE)) - return props.newSessionWorktree ?? MAIN_WORKTREE - return MAIN_WORKTREE + const projects = createMemo(() => layout.projects.list()) + const projectForDirectory = (directory: string | undefined) => { + if (!directory) return + const key = pathKey(directory) + return projects().find( + (project) => + pathKey(project.worktree) === key || project.sandboxes?.some((sandbox) => pathKey(sandbox) === key), + ) + } + const selectedProject = createMemo(() => projectForDirectory(sdk.directory)) + const projectResults = createMemo(() => { + const search = picker.projectSearch.trim().toLowerCase() + if (!search) return projects() + return projects().filter((project) => displayName(project).toLowerCase().includes(search)) }) - const worktreeLabel = (value: string) => { - if (value === MAIN_WORKTREE) return MAIN_WORKTREE - if (value === CREATE_WORKTREE) return language.t("session.new.worktree.create") - return getFilename(value) + const showAgentControl = createMemo(() => settings.general.showCustomAgents() && agentNames().length > 0) + const selectProject = (worktree: string) => { + setPicker({ + projectOpen: false, + projectSearch: "", + }) + if (pathKey(worktree) === pathKey(selectedProject()?.worktree ?? "")) { + restoreFocus() + return + } + layout.projects.open(worktree) + server.projects.touch(worktree) + navigate(`/${base64Encode(worktree)}/session`) + } + const addProject = async () => { + const select = (result: string | string[] | null) => { + const directory = Array.isArray(result) ? result[0] : result + if (!directory) return + selectProject(directory) + } + if (platform.openDirectoryPickerDialog && server.isLocal()) { + select(await platform.openDirectoryPickerDialog({ title: language.t("command.project.open") })) + return + } + void import("@/components/dialog-select-directory").then((x) => { + dialog.show(() => , () => select(null)) + }) } - const USE_V2_INPUT = import.meta.env.VITE_OPENCODE_CHANNEL !== "prod" + const projectPickerState = createMemo(() => ({ + open: picker.projectOpen, + trigger: { + action: "prompt-project", + icon: "folder", + label: selectedProject() ? displayName(selectedProject()!) : language.t("session.new.project.new"), + class: "max-w-[203px]", + style: control(), + onPress: () => setPicker("projectOpen", true), + }, + search: picker.projectSearch, + searchPlaceholder: language.t("session.new.project.search"), + clearLabel: language.t("common.clear"), + items: projectResults().map((project) => ({ + icon: "folder", + label: displayName(project), + selected: selectedProject()?.worktree === project.worktree, + onSelect: () => selectProject(project.worktree), + })), + action: { + icon: "plus", + label: language.t("session.new.project.add"), + onSelect: () => { + setPicker("projectOpen", false) + void addProject() + }, + }, + onOpenChange: (open) => { + setPicker("projectOpen", open) + if (open) requestAnimationFrame(() => projectSearchRef?.focus()) + }, + onSearchInput: (value) => setPicker("projectSearch", value), + onSearchClear: () => setPicker("projectSearch", ""), + searchRef: (el) => (projectSearchRef = el), + })) + const agentControlState = createMemo(() => ({ + title: language.t("command.agent.cycle"), + keybind: command.keybind("agent.cycle"), + options: agentNames(), + current: local.agent.current()?.name ?? "", + style: control(), + onSelect: (value) => { + local.agent.set(value) + restoreFocus() + }, + })) + const newProjectTriggerState = createMemo(() => ({ + action: "prompt-project", + icon: "folder-add-left", + label: language.t("session.new.project.new"), + class: "max-w-[160px]", + style: control(), + onPress: () => void addProject(), + })) return (
@@ -1409,15 +1455,16 @@ export const PromptInput: Component = (props) => { /> - +
+ = (props) => { onMouseDown={(e) => { const target = e.target if (!(target instanceof HTMLElement)) return - if (target.closest('[data-action="prompt-attach"], [data-action="prompt-submit"]')) return + if (target.closest('[data-action^="prompt-"]')) return editorRef?.focus() }} > @@ -1515,29 +1562,13 @@ export const PromptInput: Component = (props) => { aria-label={language.t("prompt.action.attachFile")} /> - -
-
- -
- props.state.onSearchInput(event.currentTarget.value)} + /> + + + +
+ {(item) => } +
+
+
+ +
+ + + + ) +} + +function ComposerAgentControl(props: { state: ComposerAgentControlState }) { + return ( +
+
+ +
+ + -
-
- -
- + + + + ) +} diff --git a/packages/console/support/src/routes/lookup.tsx b/packages/console/support/src/routes/lookup.tsx new file mode 100644 index 0000000000..7e977b7f95 --- /dev/null +++ b/packages/console/support/src/routes/lookup.tsx @@ -0,0 +1,39 @@ +import { Title } from "@solidjs/meta" +import { createAsync, query, useSearchParams, type RouteDefinition } from "@solidjs/router" +import { Show } from "solid-js" +import { ErrorBoundary } from "solid-js" +import { Result } from "~/component/result" +import { lookup } from "~/lib/lookup" + +const getLookup = query(async (identifier: string) => { + "use server" + return lookup(identifier) +}, "support.lookup") + +export const route: RouteDefinition = { + preload: ({ location }) => { + const identifier = new URLSearchParams(location.search).get("identifier")?.trim() + if (identifier) void getLookup(identifier) + }, +} + +export default function LookupPage() { + const [params] = useSearchParams() + const identifier = () => String(params.identifier ?? "").trim() + const data = createAsync(() => (identifier() ? getLookup(identifier()) : Promise.resolve(undefined))) + + return ( +
+ opencode support — {identifier() || "lookup"} +

Lookup: {identifier() || "(no identifier)"}

+ + Provide an `identifier` query parameter.
}> +
{(err as Error).message}
}> + Loading...
}> + {(result) => } + + + + + ) +} diff --git a/packages/console/support/sst-env.d.ts b/packages/console/support/sst-env.d.ts new file mode 100644 index 0000000000..301538ccb2 --- /dev/null +++ b/packages/console/support/sst-env.d.ts @@ -0,0 +1,10 @@ +/* This file is auto-generated by SST. Do not edit. */ +/* tslint:disable */ +/* eslint-disable */ +/* deno-fmt-ignore-file */ +/* biome-ignore-all lint: auto-generated */ + +/// + +import "sst" +export {} \ No newline at end of file diff --git a/packages/console/support/tsconfig.json b/packages/console/support/tsconfig.json new file mode 100644 index 0000000000..0f96f182ce --- /dev/null +++ b/packages/console/support/tsconfig.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + "allowJs": true, + "strict": true, + "noEmit": true, + "types": ["vite/client", "bun"], + "isolatedModules": true, + "paths": { + "~/*": ["./src/*"] + } + } +} diff --git a/packages/console/support/vite.config.ts b/packages/console/support/vite.config.ts new file mode 100644 index 0000000000..3b013e9901 --- /dev/null +++ b/packages/console/support/vite.config.ts @@ -0,0 +1,25 @@ +import { defineConfig, PluginOption } from "vite" +import { solidStart } from "@solidjs/start/config" +import { nitro } from "nitro/vite" + +export default defineConfig({ + plugins: [ + solidStart() as PluginOption, + nitro({ + compatibilityDate: "2024-09-19", + preset: "cloudflare_module", + cloudflare: { + nodeCompat: true, + }, + }), + ], + server: { + allowedHosts: true, + }, + build: { + rollupOptions: { + external: ["cloudflare:workers"], + }, + minify: false, + }, +}) From 249dc0e01e9ea0be108ee33d9ae09e5bf4a2e6c1 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Tue, 26 May 2026 14:03:28 +0000 Subject: [PATCH 17/40] chore: generate --- packages/console/support/src/lib/lookup.ts | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/console/support/src/lib/lookup.ts b/packages/console/support/src/lib/lookup.ts index 14c3978bf1..5bf2b06f6b 100644 --- a/packages/console/support/src/lib/lookup.ts +++ b/packages/console/support/src/lib/lookup.ts @@ -73,15 +73,11 @@ export async function lookup(identifier: string): Promise { } // Treat as email - const authData = await Database.use((tx) => - tx.select().from(AuthTable).where(eq(AuthTable.subject, identifier)), - ) + const authData = await Database.use((tx) => tx.select().from(AuthTable).where(eq(AuthTable.subject, identifier))) if (authData.length === 0) throw new Error("Email not found") const accountID = authData[0].accountID - const auth = await Database.use((tx) => - tx.select().from(AuthTable).where(eq(AuthTable.accountID, accountID)), - ) + const auth = await Database.use((tx) => tx.select().from(AuthTable).where(eq(AuthTable.accountID, accountID))) const accountWorkspaces = await Database.use((tx) => tx @@ -313,8 +309,13 @@ async function loadWorkspace(workspaceID: string): Promise { freeRequests: sql`SUM(CASE WHEN ${UsageTable.cost} = 0 THEN 1 ELSE 0 END)`.as("free_requests"), goRequests: sql`SUM(CASE WHEN ${planExpr} = 'lite' THEN 1 ELSE 0 END)`.as("go_requests"), goCost: sql`SUM(CASE WHEN ${planExpr} = 'lite' THEN ${UsageTable.cost} ELSE 0 END)`.as("go_cost"), - apiRequests: sql`SUM(CASE WHEN ${planExpr} IS NULL AND ${UsageTable.cost} > 0 THEN 1 ELSE 0 END)`.as("api_requests"), - apiCost: sql`SUM(CASE WHEN ${planExpr} IS NULL AND ${UsageTable.cost} > 0 THEN ${UsageTable.cost} ELSE 0 END)`.as("api_cost"), + apiRequests: sql`SUM(CASE WHEN ${planExpr} IS NULL AND ${UsageTable.cost} > 0 THEN 1 ELSE 0 END)`.as( + "api_requests", + ), + apiCost: + sql`SUM(CASE WHEN ${planExpr} IS NULL AND ${UsageTable.cost} > 0 THEN ${UsageTable.cost} ELSE 0 END)`.as( + "api_cost", + ), }) .from(UsageTable) .where( @@ -466,9 +467,7 @@ function getSubscriptionStatus(row: { const retryIn = isWeeklyLimited ? formatRetryTime(Math.ceil((week.end.getTime() - now.getTime()) / 1000)) : isRollingLimited && row.timeRollingUpdated - ? formatRetryTime( - Math.ceil((row.timeRollingUpdated.getTime() + rollingWindowMs - now.getTime()) / 1000), - ) + ? formatRetryTime(Math.ceil((row.timeRollingUpdated.getTime() + rollingWindowMs - now.getTime()) / 1000)) : null return { From 26b1d14c162b77333197cf74f3148eeffe85d6e6 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 26 May 2026 10:11:41 -0400 Subject: [PATCH 18/40] ci: fix --- sst.config.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sst.config.ts b/sst.config.ts index 526fefabd4..0097201108 100644 --- a/sst.config.ts +++ b/sst.config.ts @@ -4,7 +4,9 @@ export default $config({ app(input) { // Dev owns the shared AWS lake/stats infra for all non-production stages. const awsStage = input.stage === "production" ? "production" : "dev" - const deployAws = input.stage === awsStage + // TODO temporarily disable AWS infra deployment + const deployAws = false + //const deployAws = input.stage === awsStage return { name: "opencode", removal: input?.stage === "production" ? "retain" : "remove", @@ -38,8 +40,8 @@ export default $config({ const stage = await import("./infra/stage.js") await import("./infra/app.js") if (stage.deployAws) { - await import("./infra/lake.js") - await import("./infra/stats.js") + //await import("./infra/lake.js") + //await import("./infra/stats.js") } const { stat } = await import("./infra/console.js") await import("./infra/enterprise.js") From 5ee18f9b75f8fbac0fd1c26364659b0ec4058c70 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 26 May 2026 10:18:37 -0400 Subject: [PATCH 19/40] ci: fix --- infra/stage.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/infra/stage.ts b/infra/stage.ts index 5dc17fc85a..e7b7aa0244 100644 --- a/infra/stage.ts +++ b/infra/stage.ts @@ -7,7 +7,9 @@ export const domain = (() => { export const zoneID = "430ba34c138cfb5360826c4909f99be8" // Dev owns the shared AWS lake/stats infra for all non-production stages. export const awsStage = $app.stage === "production" ? "production" : "dev" -export const deployAws = $app.stage === awsStage +// TODO temporarily disable AWS infra deployment +export const deployAws = false +//export const deployAws = $app.stage === awsStage new cloudflare.RegionalHostname("RegionalHostname", { hostname: domain, From 1bf2b298e93781511b59e9f6ad9be2b690d6bc60 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Tue, 26 May 2026 14:23:57 +0000 Subject: [PATCH 20/40] 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 c0148e83d8..ce02618335 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-gqXxbi1OwLoDSDtlmYWcTTPT/fqhVGb53JXS/9a1vWw=", - "aarch64-linux": "sha256-+ARbWtOUDx0J5k55mmre/2kPekUsQtWWS0QZnyX6NTo=", - "aarch64-darwin": "sha256-Q6ioI6lFUhNKogbvbtGWsZcXJfbRgUAWS5X2X4mKdg4=", - "x86_64-darwin": "sha256-8K/hmcvXi9FGqprNbTKzMB80h5zZhO2TjOQbtve3ltQ=" + "x86_64-linux": "sha256-p8EPw6YDdAaToGibLAljdtLuuSIqQ3mVJecYOwUWqY0=", + "aarch64-linux": "sha256-G/xOunyVzqJucokje713GkysXgixJmce6jlevRht7Sc=", + "aarch64-darwin": "sha256-zMeGIyWXUb0ofrUGxTluAytZMkTtlyEydIhbu62O2VM=", + "x86_64-darwin": "sha256-ef7+QlnKmtB2fGOw3EFjlyZcgj+Q8XLbNVdPQiNNvh8=" } } From 541a25c2a1cf065b44e948507a056d8d06014cea Mon Sep 17 00:00:00 2001 From: vimtor Date: Tue, 26 May 2026 17:48:27 +0200 Subject: [PATCH 21/40] fix: stuck sst deployment --- infra/lake-destroy-prep.ts | 27 +++++++++++++++++++++++++++ infra/stage.ts | 4 ++-- sst-env.d.ts | 2 +- sst.config.ts | 31 ++++++++++++------------------- 4 files changed, 42 insertions(+), 22 deletions(-) create mode 100644 infra/lake-destroy-prep.ts diff --git a/infra/lake-destroy-prep.ts b/infra/lake-destroy-prep.ts new file mode 100644 index 0000000000..842776a157 --- /dev/null +++ b/infra/lake-destroy-prep.ts @@ -0,0 +1,27 @@ +// Temporary destroy prep: keep only non-empty resources declared so SST updates forceDestroy before omission. +new aws.s3tables.TableBucket("LakeTableBucket", { + name: `opencode-${$app.stage}-lake`, + forceDestroy: true, +}) + +const athenaResultsBucket = new aws.s3.Bucket("LakeAthenaResults", { + bucket: `opencode-${$app.stage}-lake-athena-results`, + forceDestroy: true, +}) + +new aws.s3.Bucket("LakeFirehoseErrors", { + bucket: `opencode-${$app.stage}-lake-firehose-errors`, + forceDestroy: true, +}) + +new aws.athena.Workgroup("LakeAthenaWorkgroup", { + name: `opencode-${$app.stage}-lake-workgroup`, + forceDestroy: true, + configuration: { + enforceWorkgroupConfiguration: true, + publishCloudwatchMetricsEnabled: true, + resultConfiguration: { + outputLocation: $interpolate`s3://${athenaResultsBucket.bucket}/`, + }, + }, +}) diff --git a/infra/stage.ts b/infra/stage.ts index e7b7aa0244..18a9d6222a 100644 --- a/infra/stage.ts +++ b/infra/stage.ts @@ -7,9 +7,9 @@ export const domain = (() => { export const zoneID = "430ba34c138cfb5360826c4909f99be8" // Dev owns the shared AWS lake/stats infra for all non-production stages. export const awsStage = $app.stage === "production" ? "production" : "dev" -// TODO temporarily disable AWS infra deployment +export const prepareAwsDestroy = $app.stage === "production" || $app.stage === "dev" +// Temporarily omit AWS infra so SST removes the lake/stats resources. export const deployAws = false -//export const deployAws = $app.stage === awsStage new cloudflare.RegionalHostname("RegionalHostname", { hostname: domain, diff --git a/sst-env.d.ts b/sst-env.d.ts index c8acbde01f..02ba732efd 100644 --- a/sst-env.d.ts +++ b/sst-env.d.ts @@ -344,4 +344,4 @@ declare module "sst" { } import "sst" -export {} \ No newline at end of file +export {} diff --git a/sst.config.ts b/sst.config.ts index 0097201108..86cedb3321 100644 --- a/sst.config.ts +++ b/sst.config.ts @@ -2,30 +2,20 @@ export default $config({ app(input) { - // Dev owns the shared AWS lake/stats infra for all non-production stages. - const awsStage = input.stage === "production" ? "production" : "dev" - // TODO temporarily disable AWS infra deployment + const prepareAwsDestroy = input.stage === "production" || input.stage === "dev" + // Temporarily omit AWS infra so SST removes the lake/stats resources. const deployAws = false - //const deployAws = input.stage === awsStage return { name: "opencode", removal: input?.stage === "production" ? "retain" : "remove", protect: ["production"].includes(input?.stage), home: "cloudflare", providers: { - ...(deployAws - ? { - aws: { - version: "7.30.0", - region: "us-east-1", - profile: process.env.GITHUB_ACTIONS - ? undefined - : input.stage === "production" - ? "opencode-production" - : "opencode-dev", - }, - } - : {}), + aws: { + version: "7.30.0", + region: "us-east-1", + profile: process.env.GITHUB_ACTIONS ? undefined : input.stage === "production" ? "opencode-production" : "opencode-dev", + }, stripe: { version: "0.0.28", apiKey: process.env.STRIPE_SECRET_KEY!, @@ -39,9 +29,12 @@ export default $config({ async run() { const stage = await import("./infra/stage.js") await import("./infra/app.js") + if (stage.prepareAwsDestroy) { + await import("./infra/lake-destroy-prep.js") + } if (stage.deployAws) { - //await import("./infra/lake.js") - //await import("./infra/stats.js") + await import("./infra/lake.js") + await import("./infra/stats.js") } const { stat } = await import("./infra/console.js") await import("./infra/enterprise.js") From 922903e4104dd60d47972aab6d54ea976edf39fa Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Tue, 26 May 2026 15:52:47 +0000 Subject: [PATCH 22/40] chore: generate --- sst.config.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sst.config.ts b/sst.config.ts index 86cedb3321..0976d933b7 100644 --- a/sst.config.ts +++ b/sst.config.ts @@ -14,7 +14,11 @@ export default $config({ aws: { version: "7.30.0", region: "us-east-1", - profile: process.env.GITHUB_ACTIONS ? undefined : input.stage === "production" ? "opencode-production" : "opencode-dev", + profile: process.env.GITHUB_ACTIONS + ? undefined + : input.stage === "production" + ? "opencode-production" + : "opencode-dev", }, stripe: { version: "0.0.28", From 715589fea447f759581b3cc21acf5c5db7a094ac Mon Sep 17 00:00:00 2001 From: vimtor Date: Tue, 26 May 2026 18:07:50 +0200 Subject: [PATCH 23/40] fix: stuck sst deployment --- infra/lake-destroy-prep.ts | 27 --------------------------- infra/stage.ts | 1 - sst.config.ts | 6 ------ 3 files changed, 34 deletions(-) delete mode 100644 infra/lake-destroy-prep.ts diff --git a/infra/lake-destroy-prep.ts b/infra/lake-destroy-prep.ts deleted file mode 100644 index 842776a157..0000000000 --- a/infra/lake-destroy-prep.ts +++ /dev/null @@ -1,27 +0,0 @@ -// Temporary destroy prep: keep only non-empty resources declared so SST updates forceDestroy before omission. -new aws.s3tables.TableBucket("LakeTableBucket", { - name: `opencode-${$app.stage}-lake`, - forceDestroy: true, -}) - -const athenaResultsBucket = new aws.s3.Bucket("LakeAthenaResults", { - bucket: `opencode-${$app.stage}-lake-athena-results`, - forceDestroy: true, -}) - -new aws.s3.Bucket("LakeFirehoseErrors", { - bucket: `opencode-${$app.stage}-lake-firehose-errors`, - forceDestroy: true, -}) - -new aws.athena.Workgroup("LakeAthenaWorkgroup", { - name: `opencode-${$app.stage}-lake-workgroup`, - forceDestroy: true, - configuration: { - enforceWorkgroupConfiguration: true, - publishCloudwatchMetricsEnabled: true, - resultConfiguration: { - outputLocation: $interpolate`s3://${athenaResultsBucket.bucket}/`, - }, - }, -}) diff --git a/infra/stage.ts b/infra/stage.ts index 18a9d6222a..beb3f5925b 100644 --- a/infra/stage.ts +++ b/infra/stage.ts @@ -7,7 +7,6 @@ export const domain = (() => { export const zoneID = "430ba34c138cfb5360826c4909f99be8" // Dev owns the shared AWS lake/stats infra for all non-production stages. export const awsStage = $app.stage === "production" ? "production" : "dev" -export const prepareAwsDestroy = $app.stage === "production" || $app.stage === "dev" // Temporarily omit AWS infra so SST removes the lake/stats resources. export const deployAws = false diff --git a/sst.config.ts b/sst.config.ts index 0976d933b7..550f91c6f3 100644 --- a/sst.config.ts +++ b/sst.config.ts @@ -2,9 +2,6 @@ export default $config({ app(input) { - const prepareAwsDestroy = input.stage === "production" || input.stage === "dev" - // Temporarily omit AWS infra so SST removes the lake/stats resources. - const deployAws = false return { name: "opencode", removal: input?.stage === "production" ? "retain" : "remove", @@ -33,9 +30,6 @@ export default $config({ async run() { const stage = await import("./infra/stage.js") await import("./infra/app.js") - if (stage.prepareAwsDestroy) { - await import("./infra/lake-destroy-prep.js") - } if (stage.deployAws) { await import("./infra/lake.js") await import("./infra/stats.js") From 28dbd4ab4a51824bb67b1a8e1e642bfebd64b9e3 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Tue, 26 May 2026 11:34:54 -0500 Subject: [PATCH 24/40] chore(opencode): pin google providers before tool id regression (#29423) --- bun.lock | 22 ++++++++++++++-------- packages/core/package.json | 4 ++-- packages/opencode/package.json | 4 ++-- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/bun.lock b/bun.lock index a9e11c0450..2140bccf23 100644 --- a/bun.lock +++ b/bun.lock @@ -227,8 +227,8 @@ "@ai-sdk/cohere": "3.0.27", "@ai-sdk/deepinfra": "2.0.41", "@ai-sdk/gateway": "3.0.104", - "@ai-sdk/google": "3.0.63", - "@ai-sdk/google-vertex": "4.0.131", + "@ai-sdk/google": "3.0.73", + "@ai-sdk/google-vertex": "4.0.128", "@ai-sdk/groq": "3.0.31", "@ai-sdk/mistral": "3.0.27", "@ai-sdk/openai": "3.0.53", @@ -437,8 +437,8 @@ "@ai-sdk/cohere": "3.0.27", "@ai-sdk/deepinfra": "2.0.41", "@ai-sdk/gateway": "3.0.104", - "@ai-sdk/google": "3.0.63", - "@ai-sdk/google-vertex": "4.0.131", + "@ai-sdk/google": "3.0.73", + "@ai-sdk/google-vertex": "4.0.128", "@ai-sdk/groq": "3.0.31", "@ai-sdk/mistral": "3.0.27", "@ai-sdk/openai": "3.0.53", @@ -915,9 +915,9 @@ "@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.104", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@vercel/oidc": "3.2.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZKX5n74io8VIRlhIMSLWVlvT3sXC8Z7cZ9GHuWBWZDVi96+62AIsWuLGvMfcBA1STYuSoDrp6rIziZmvrTq0TA=="], - "@ai-sdk/google": ["@ai-sdk/google@3.0.63", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-RfOZWVMYSPu2sPRfGajrauWAZ9BSaRopSn+AszkKWQ1MFj8nhaXvCqRHB5pBQUaHTfZKagvOmMpNfa/s3gPLgQ=="], + "@ai-sdk/google": ["@ai-sdk/google@3.0.73", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-o2MuIeyvZrFIeIbnbA8Thrr63irdyUBh0uWBZ2lY6yFeXuE/tcwyXF74bDKS4KvTu84uFpQfpbS/LXHGKKXz+g=="], - "@ai-sdk/google-vertex": ["@ai-sdk/google-vertex@4.0.131", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.78", "@ai-sdk/google": "3.0.75", "@ai-sdk/openai-compatible": "2.0.47", "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27", "google-auth-library": "^10.5.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Oj1X8p0rVgvEoR5OOSxWi6XgzJ3QDlE/n30MZVtpKkCiToYYDyvlvVDGXz3IqhMyUev2JhlcuUk1brScKT01kA=="], + "@ai-sdk/google-vertex": ["@ai-sdk/google-vertex@4.0.128", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.77", "@ai-sdk/google": "3.0.73", "@ai-sdk/openai-compatible": "2.0.47", "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27", "google-auth-library": "^10.5.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-jK8fixb4km2yfgvb9DUFQRpV/jiDB0v9gyxHoHfPydaQvz+CpAz8DTt1quyaM+Wg9G2R8Zo68CYmHbIkUqW2AA=="], "@ai-sdk/groq": ["@ai-sdk/groq@3.0.31", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-XbbugpnFmXGu2TlXiq8KUJskP6/VVbuFcnFIGDzDIB/Chg6XHsNnqrTF80Zxkh0Pd3+NvbM+2Uqrtsndk6bDAg=="], @@ -5229,9 +5229,11 @@ "@ai-sdk/fireworks/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="], - "@ai-sdk/google-vertex/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.78", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-0OY12G20cUt6iU6htpEA1491Oz++NVxZxlmWGX4B7rSbeZ5pnDmOu6YtW9BKzdZlNx5Gn23i6WMxyZFoMKNcgA=="], + "@ai-sdk/google/@ai-sdk/provider": ["@ai-sdk/provider@3.0.10", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-Q3BZ27qfpYqnCYGvE3vt+Qi6LGOF9R5Nmzn+9JoM1lCRsD9mYaIhfJLkSunN48nfGXJ6n+XNV0J/XVpqGQl7Dw=="], - "@ai-sdk/google-vertex/@ai-sdk/google": ["@ai-sdk/google@3.0.75", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-XAm31ftiOrzlb8NjDzT7kw0xw+4lmgFdGFn1QKM73nXFFKyN1kWLESBV75UGNfjXP8X1YJ0YydnMVqO0jaPghw=="], + "@ai-sdk/google/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw=="], + + "@ai-sdk/google-vertex/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.77", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ML8C2M1YvPA1ulEx4TiyF0k1xvC2ikEiPBIC1PPQ0a5xELUGrO2lAaEzsTEoJ+eCeDd8PSBuFJjs+r+9yIwQXA=="], "@ai-sdk/google-vertex/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.47", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Enm5UlL0zUCrW3792opk5h7hRWxZOZzDe6eQYVFqX9LUOGGCe1h8MZWAGim765nwzgnjlpeYOsuzZmLtRsTPlg=="], @@ -6171,6 +6173,10 @@ "@ai-sdk/google-vertex/@ai-sdk/provider-utils/eventsource-parser": ["eventsource-parser@3.0.8", "", {}, "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ=="], + "@ai-sdk/google/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + + "@ai-sdk/google/@ai-sdk/provider-utils/eventsource-parser": ["eventsource-parser@3.0.8", "", {}, "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ=="], + "@ai-sdk/groq/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], "@ai-sdk/mistral/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], diff --git a/packages/core/package.json b/packages/core/package.json index d49a717c05..0f299613e7 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -34,8 +34,8 @@ "@ai-sdk/cohere": "3.0.27", "@ai-sdk/deepinfra": "2.0.41", "@ai-sdk/gateway": "3.0.104", - "@ai-sdk/google": "3.0.63", - "@ai-sdk/google-vertex": "4.0.131", + "@ai-sdk/google": "3.0.73", + "@ai-sdk/google-vertex": "4.0.128", "@ai-sdk/groq": "3.0.31", "@ai-sdk/mistral": "3.0.27", "@ai-sdk/openai": "3.0.53", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 1e3db56823..b8546b815b 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -81,8 +81,8 @@ "@ai-sdk/cohere": "3.0.27", "@ai-sdk/deepinfra": "2.0.41", "@ai-sdk/gateway": "3.0.104", - "@ai-sdk/google": "3.0.63", - "@ai-sdk/google-vertex": "4.0.131", + "@ai-sdk/google": "3.0.73", + "@ai-sdk/google-vertex": "4.0.128", "@ai-sdk/groq": "3.0.31", "@ai-sdk/mistral": "3.0.27", "@ai-sdk/openai": "3.0.53", From 1c4196c358d354f70241fe8bc0f8bbb524f31f84 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Tue, 26 May 2026 11:46:45 -0500 Subject: [PATCH 25/40] docs: remove ambiguous agent automation guidance (#29427) --- AGENTS.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 8e7ff342b5..fa39b00a40 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,8 +1,6 @@ - To regenerate the JavaScript SDK, run `./packages/sdk/js/script/build.ts`. -- ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE. - The default branch in this repo is `dev`. - Local `main` ref may not exist; use `dev` or `origin/dev` for diffs. -- Prefer automation: execute requested actions without confirmation unless blocked by missing info or safety/irreversibility. ## Commits and PR Titles From 034298cb1f9ee92b10d94d59532ccc91fca3c2e6 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Tue, 26 May 2026 16:55:51 +0000 Subject: [PATCH 26/40] 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 ce02618335..b34f76d8b1 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-p8EPw6YDdAaToGibLAljdtLuuSIqQ3mVJecYOwUWqY0=", - "aarch64-linux": "sha256-G/xOunyVzqJucokje713GkysXgixJmce6jlevRht7Sc=", - "aarch64-darwin": "sha256-zMeGIyWXUb0ofrUGxTluAytZMkTtlyEydIhbu62O2VM=", - "x86_64-darwin": "sha256-ef7+QlnKmtB2fGOw3EFjlyZcgj+Q8XLbNVdPQiNNvh8=" + "x86_64-linux": "sha256-TOKVB2fGz/8QobMjrlAizTytCupwIRxfD4Ww1FgdC/g=", + "aarch64-linux": "sha256-FkAEvniN1Qy7scRHrc6LJLsvRkdvlGVCDS7cGn8m4fI=", + "aarch64-darwin": "sha256-fG6Ihrxnxk+FOv4yrYMZ3HfuzvjKlQVKZ00vLhCYoz8=", + "x86_64-darwin": "sha256-Sn8nWN4B0JStMnmlrt9sR7ji4RystwWdkiNgfspPxA0=" } } From 797359fbf0c06bdfdb36060678f709824dad2fc7 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Tue, 26 May 2026 12:18:09 -0500 Subject: [PATCH 27/40] fix(opencode): patch gcp metadata warning leak (#29431) --- bun.lock | 3 ++- package.json | 3 ++- patches/gcp-metadata@8.1.2.patch | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 patches/gcp-metadata@8.1.2.patch diff --git a/bun.lock b/bun.lock index 2140bccf23..c6cf5247a3 100644 --- a/bun.lock +++ b/bun.lock @@ -799,8 +799,9 @@ ], "patchedDependencies": { "solid-js@1.9.10": "patches/solid-js@1.9.10.patch", - "@ai-sdk/xai@3.0.82": "patches/@ai-sdk%2Fxai@3.0.82.patch", "virtua@0.49.1": "patches/virtua@0.49.1.patch", + "gcp-metadata@8.1.2": "patches/gcp-metadata@8.1.2.patch", + "@ai-sdk/xai@3.0.82": "patches/@ai-sdk%2Fxai@3.0.82.patch", "@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch", "@npmcli/agent@4.0.0": "patches/@npmcli%2Fagent@4.0.0.patch", "@silvia-odwyer/photon-node@0.3.4": "patches/@silvia-odwyer%2Fphoton-node@0.3.4.patch", diff --git a/package.json b/package.json index fcf3873d37..bc24db85d8 100644 --- a/package.json +++ b/package.json @@ -144,6 +144,7 @@ "@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch", "solid-js@1.9.10": "patches/solid-js@1.9.10.patch", "virtua@0.49.1": "patches/virtua@0.49.1.patch", - "@ai-sdk/xai@3.0.82": "patches/@ai-sdk%2Fxai@3.0.82.patch" + "@ai-sdk/xai@3.0.82": "patches/@ai-sdk%2Fxai@3.0.82.patch", + "gcp-metadata@8.1.2": "patches/gcp-metadata@8.1.2.patch" } } diff --git a/patches/gcp-metadata@8.1.2.patch b/patches/gcp-metadata@8.1.2.patch new file mode 100644 index 0000000000..8b7667e29a --- /dev/null +++ b/patches/gcp-metadata@8.1.2.patch @@ -0,0 +1,14 @@ +diff --git a/build/src/index.js b/build/src/index.js +--- a/build/src/index.js ++++ b/build/src/index.js +@@ -323,6 +323,10 @@ async function isAvailable() { + if (process.env.DEBUG_AUTH) { + console.info(err); + } ++ // Promise.any() rejects with AggregateError when neither metadata host ++ // is available. This is expected outside GCP, not a warning condition. ++ if (err instanceof AggregateError) ++ return false; + if (err.type === 'request-timeout') { + // If running in a GCP environment, metadata endpoint should return + // within ms. From 1554a5a82e32c30d2665ed6b59ebd33f79f9b9e3 Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 27 May 2026 01:26:57 +0800 Subject: [PATCH 28/40] docs(go): add Qwen3.7 Max (#29389) --- 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/uk.ts | 6 +++--- packages/console/app/src/i18n/zh.ts | 8 ++++---- packages/console/app/src/i18n/zht.ts | 8 ++++---- packages/console/app/src/routes/go/index.tsx | 6 ++++-- .../app/src/routes/workspace/[id]/go/lite-section.tsx | 1 + packages/web/src/content/docs/ar/go.mdx | 10 +++++++--- packages/web/src/content/docs/ar/zen.mdx | 4 +++- packages/web/src/content/docs/bs/go.mdx | 8 ++++++-- packages/web/src/content/docs/bs/zen.mdx | 4 +++- packages/web/src/content/docs/da/go.mdx | 8 ++++++-- packages/web/src/content/docs/da/zen.mdx | 4 +++- packages/web/src/content/docs/de/go.mdx | 8 ++++++-- packages/web/src/content/docs/de/zen.mdx | 4 +++- packages/web/src/content/docs/es/go.mdx | 8 ++++++-- packages/web/src/content/docs/es/zen.mdx | 4 +++- packages/web/src/content/docs/fr/go.mdx | 8 ++++++-- packages/web/src/content/docs/fr/zen.mdx | 4 +++- packages/web/src/content/docs/go.mdx | 6 +++++- packages/web/src/content/docs/it/go.mdx | 8 ++++++-- packages/web/src/content/docs/it/zen.mdx | 4 +++- packages/web/src/content/docs/ja/go.mdx | 8 ++++++-- packages/web/src/content/docs/ja/zen.mdx | 4 +++- packages/web/src/content/docs/ko/go.mdx | 8 ++++++-- packages/web/src/content/docs/ko/zen.mdx | 4 +++- packages/web/src/content/docs/nb/go.mdx | 8 ++++++-- packages/web/src/content/docs/nb/zen.mdx | 4 +++- packages/web/src/content/docs/pl/go.mdx | 8 ++++++-- packages/web/src/content/docs/pl/zen.mdx | 2 ++ packages/web/src/content/docs/pt-br/go.mdx | 8 ++++++-- packages/web/src/content/docs/pt-br/zen.mdx | 2 ++ packages/web/src/content/docs/ru/go.mdx | 8 ++++++-- packages/web/src/content/docs/ru/zen.mdx | 2 ++ packages/web/src/content/docs/th/go.mdx | 8 ++++++-- packages/web/src/content/docs/th/zen.mdx | 4 +++- packages/web/src/content/docs/tr/go.mdx | 8 ++++++-- packages/web/src/content/docs/tr/zen.mdx | 4 +++- packages/web/src/content/docs/zen.mdx | 2 ++ packages/web/src/content/docs/zh-cn/go.mdx | 10 +++++++--- packages/web/src/content/docs/zh-cn/zen.mdx | 2 ++ packages/web/src/content/docs/zh-tw/go.mdx | 10 +++++++--- packages/web/src/content/docs/zh-tw/zen.mdx | 2 ++ 56 files changed, 234 insertions(+), 123 deletions(-) diff --git a/packages/console/app/src/i18n/ar.ts b/packages/console/app/src/i18n/ar.ts index bf624e0455..550d8207e6 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.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7 وDeepSeek V4 Pro وDeepSeek V4 Flash.", + "يبدأ Go من $5 للشهر الأول، ثم $10/شهر، مع حدود طلب سخية لمدة 5 ساعات لـ GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.7 Max وQwen3.6 Plus وQwen3.5 Plus وMiniMax M2.5 وMiniMax M2.7 وDeepSeek V4 Pro وDeepSeek V4 Flash.", "go.hero.title": "نماذج برمجة منخفضة التكلفة للجميع", "go.hero.body": "يجلب Go البرمجة الوكيلة للمبرمجين حول العالم. يوفر حدودًا سخية ووصولًا موثوقًا إلى أقوى النماذج مفتوحة المصدر، حتى تتمكن من البناء باستخدام وكلاء أقوياء دون القلق بشأن التكلفة أو التوفر.", @@ -298,7 +298,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.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7 وDeepSeek V4 Pro وDeepSeek V4 Flash", + "يتضمن GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.7 Max وQwen3.6 Plus وQwen3.5 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": "أنشئ حسابًا", @@ -322,7 +322,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.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7 وDeepSeek V4 Pro وDeepSeek V4 Flash.", + "لا. Zen هو الدفع حسب الاستخدام، بينما يبدأ Go من $5 للشهر الأول، ثم $10/شهر، مع حدود سخية ووصول موثوق إلى نماذج المصدر المفتوح GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.7 Max وQwen3.6 Plus وQwen3.5 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 للشهر الأول", @@ -345,7 +345,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.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 دولارًا في الشهر (تختلف أعداد الطلبات الفعلية حسب النموذج والاستخدام).", + "تشمل النماذج المجانية Big Pickle بالإضافة إلى النماذج الترويجية المتاحة في ذلك الوقت، مع حصة 200 طلب/يوم. يتضمن Go نماذج GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.7 Max وQwen3.6 Plus وQwen3.5 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 8f902cb63f..b6f1a4d622 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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro e DeepSeek V4 Flash.", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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.", @@ -303,7 +303,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro e DeepSeek V4 Flash", + "Inclui GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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.", @@ -329,7 +329,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro e DeepSeek V4 Flash.", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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", @@ -353,7 +353,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.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).", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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 ae3940fa70..b8a315e7e5 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.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 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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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.", @@ -300,7 +300,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro og DeepSeek V4 Flash", + "Inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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.", @@ -326,7 +326,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro og DeepSeek V4 Flash.", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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", @@ -349,7 +349,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.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).", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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 8cbbbe3ef7..42bca9c7ce 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.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 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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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.", @@ -302,7 +302,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro und DeepSeek V4 Flash", + "Beinhaltet GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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.", @@ -328,7 +328,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro und DeepSeek V4 Flash.", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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", @@ -352,7 +352,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.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).", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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 5701f76da5..bbd269d52a 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.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 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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, and DeepSeek V4 Flash.", "go.hero.title": "Low cost coding models for everyone", "go.hero.body": "Go brings agentic coding to programmers around the world. Offering generous limits and reliable access to the most capable open-source models, so you can build with powerful agents without worrying about cost or availability.", @@ -296,7 +296,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, and DeepSeek V4 Flash", + "Includes GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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", @@ -321,7 +321,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, and DeepSeek V4 Flash.", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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", @@ -345,7 +345,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.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).", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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}} is not supported", diff --git a/packages/console/app/src/i18n/es.ts b/packages/console/app/src/i18n/es.ts index 0e9561b220..813bffd497 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.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 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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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.", @@ -304,7 +304,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro y DeepSeek V4 Flash", + "Incluye GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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", @@ -329,7 +329,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro y DeepSeek V4 Flash.", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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", @@ -353,7 +353,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.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).", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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 9aed850eb3..f788e9d686 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.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 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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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é.", @@ -304,7 +304,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro et DeepSeek V4 Flash", + "Inclut GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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.", @@ -330,7 +330,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro et DeepSeek V4 Flash.", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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", @@ -353,7 +353,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.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).", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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 d1b0c390b3..1195f8182c 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.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 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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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à.", @@ -300,7 +300,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro e DeepSeek V4 Flash", + "Include GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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", @@ -325,7 +325,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro e DeepSeek V4 Flash.", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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", @@ -349,7 +349,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.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).", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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 18cf077a2d..d33df6a4da 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.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は最初の月$5、その後$10/月で、GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.7 Max、Qwen3.6 Plus、Qwen3.5 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro、DeepSeek V4 Flashに対して5時間のゆとりあるリクエスト上限があります。", "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.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro、DeepSeek V4 Flashを含む", + "GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.7 Max、Qwen3.6 Plus、Qwen3.5 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.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro、DeepSeek V4 Flashのオープンソースモデルに対して、ゆとりある上限と信頼できるアクセスを提供します。", + "いいえ。Zenは従量課金制ですが、Goは最初の月$5、その後$10/月で始まり、GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.7 Max、Qwen3.6 Plus、Qwen3.5 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", @@ -349,7 +349,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.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相当です(実際のリクエスト数はモデルと使用状況により異なります)。", + "無料モデルにはBig Pickleと、その時点で利用可能なプロモーションモデルが含まれ、1日200リクエストの制限があります。GoにはGLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.7 Max、Qwen3.6 Plus、Qwen3.5 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 3572d605cf..3c06a5d356 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.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는 첫 달 $5, 이후 $10/월로 시작하며, GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, DeepSeek V4 Flash에 대해 넉넉한 5시간 요청 한도를 제공합니다.", "go.hero.title": "모두를 위한 저비용 코딩 모델", "go.hero.body": "Go는 전 세계 프로그래머들에게 에이전트 코딩을 제공합니다. 가장 유능한 오픈 소스 모델에 대한 넉넉한 한도와 안정적인 액세스를 제공하므로, 비용이나 가용성 걱정 없이 강력한 에이전트로 빌드할 수 있습니다.", @@ -297,7 +297,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, DeepSeek V4 Flash 포함", + "GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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": "계정 생성", @@ -321,7 +321,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, DeepSeek V4 Flash 오픈 소스 모델에 대한 넉넉한 한도와 안정적인 액세스를 제공합니다.", + "아니요. Zen은 종량제인 반면, Go는 첫 달 $5, 이후 $10/월로 시작하며, GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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", @@ -344,7 +344,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.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에 해당합니다(실제 요청 수는 모델 및 사용량에 따라 다름).", + "무료 모델에는 Big Pickle과 당시 사용 가능한 프로모션 모델이 포함되며, 하루 200회 요청 할당량이 적용됩니다. Go는 GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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 ea25f98eac..7f76e4eff5 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.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 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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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.", @@ -300,7 +300,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro og DeepSeek V4 Flash", + "Inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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.", @@ -326,7 +326,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro og DeepSeek V4 Flash.", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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", @@ -350,7 +350,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.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).", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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 4a222b13b1..8186cf3593 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.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 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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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ść.", @@ -301,7 +301,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro i DeepSeek V4 Flash", + "Zawiera GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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.", @@ -327,7 +327,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro i DeepSeek V4 Flash.", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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", @@ -351,7 +351,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.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).", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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 d2e2849359..2031e61287 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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro и DeepSeek V4 Flash.", + "Go начинается с $5 за первый месяц, затем $10/месяц, с щедрыми лимитами запросов за 5 часов для GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro и DeepSeek V4 Flash.", "go.hero.title": "Недорогие модели для кодинга для всех", "go.hero.body": "Go открывает доступ к агентам-программистам разработчикам по всему миру. Предлагая щедрые лимиты и надежный доступ к наиболее способным моделям с открытым исходным кодом, вы можете создавать проекты с мощными агентами, не беспокоясь о затратах или доступности.", @@ -305,7 +305,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro и DeepSeek V4 Flash", + "Включает GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro и DeepSeek V4 Flash", "go.how.title": "Как работает Go", "go.how.body": "Go начинается с $5 за первый месяц, затем $10/месяц. Вы можете использовать его с OpenCode или любым агентом.", @@ -331,7 +331,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro и DeepSeek V4 Flash.", + "Нет. Zen - это оплата по мере использования, в то время как Go начинается с $5 за первый месяц, затем $10/месяц, с щедрыми лимитами и надежным доступом к моделям с открытым исходным кодом GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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 за первый месяц", @@ -355,7 +355,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.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 в месяц (фактическое количество запросов зависит от модели и использования).", + "Бесплатные модели включают Big Pickle плюс промо-модели, доступные на данный момент, с квотой 200 запросов/день. Go включает GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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 bae5c860d5..ac9de47b66 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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro และ DeepSeek V4 Flash", + "Go เริ่มต้นที่ $5 สำหรับเดือนแรก จากนั้น $10/เดือน พร้อมขีดจำกัดคำขอ 5 ชั่วโมงที่เอื้อเฟื้อสำหรับ GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro และ DeepSeek V4 Flash", "go.hero.title": "โมเดลเขียนโค้ดราคาประหยัดสำหรับทุกคน", "go.hero.body": "Go นำการเขียนโค้ดแบบเอเจนต์มาสู่นักเขียนโปรแกรมทั่วโลก เสนอขีดจำกัดที่กว้างขวางและการเข้าถึงโมเดลโอเพนซอร์สที่มีความสามารถสูงสุดได้อย่างน่าเชื่อถือ เพื่อให้คุณสามารถสร้างสรรค์ด้วยเอเจนต์ที่ทรงพลังโดยไม่ต้องกังวลเรื่องค่าใช้จ่ายหรือความพร้อมใช้งาน", @@ -298,7 +298,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro และ DeepSeek V4 Flash", + "รวมถึง GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro และ DeepSeek V4 Flash อย่างเชื่อถือได้", + "ไม่ Zen เป็นแบบจ่ายตามการใช้งาน ในขณะที่ Go เริ่มต้นที่ $5 สำหรับเดือนแรก จากนั้น $10/เดือน พร้อมขีดจำกัดที่เอื้อเฟื้อและการเข้าถึงโมเดลโอเพนซอร์ส GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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.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 ต่อเดือน (จำนวนคำขอจริงจะแตกต่างกันไปตามโมเดลและการใช้งาน)", + "โมเดลฟรีรวมถึง Big Pickle บวกกับโมเดลโปรโมชั่นที่มีให้ในขณะนั้น ด้วยโควต้า 200 คำขอ/วัน Go รวมถึง GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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 bf3144c73b..e9f83a9356 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.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 ilk ay $5, sonrasında ayda 10$ fiyatıyla başlar; GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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.", @@ -303,7 +303,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.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", + "GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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.", @@ -329,7 +329,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.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.", + "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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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", @@ -353,7 +353,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.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).", + "Ü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.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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/uk.ts b/packages/console/app/src/i18n/uk.ts index 4c0b0d645e..57542edfe1 100644 --- a/packages/console/app/src/i18n/uk.ts +++ b/packages/console/app/src/i18n/uk.ts @@ -252,7 +252,7 @@ export const dict = { "go.title": "OpenCode Go | Недорогі моделі кодування для всіх", "go.meta.description": - "Go починається від $5 за перший місяць, потім $10/місяць, з generous 5-годинними лімітами запитів для GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, 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 починається від $5 за перший місяць, потім $10/місяць, з generous 5-годинними лімітами запитів для GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro та DeepSeek V4 Flash.", "go.hero.title": "Недорогі моделі кодування для всіх", "go.hero.body": "Go надає агентне програмування програмістам у всьому світі, пропонуючи щедрі ліміти та надійний доступ до найкращих моделей з відкритим кодом.", @@ -301,7 +301,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro та DeepSeek V4 Flash", + "Включає GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro та DeepSeek V4 Flash", "go.how.title": "Як працює Go", "go.how.body": "Go починається від $5 за перший місяць, потім $10/місяць. Використовуйте з OpenCode або будь-яким агентом.", @@ -350,7 +350,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro та DeepSeek V4 Flash із вищими лімітами.", + "Безкоштовні моделі включають Big Pickle та акційні моделі з лімітом 200 запитів/день. Go включає GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro та DeepSeek V4 Flash із вищими лімітами.", "zen.api.error.rateLimitExceeded": "Перевищено ліміт запитів. Спробуйте пізніше.", "zen.api.error.modelNotSupported": "Модель {{model}} не підтримується", diff --git a/packages/console/app/src/i18n/zh.ts b/packages/console/app/src/i18n/zh.ts index ec134ccae1..3e5a35ec76 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.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 首月 $5,之后 $10/月,提供对 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.7 Max、Qwen3.6 Plus、Qwen3.5 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro 和 DeepSeek V4 Flash 的 5 小时充裕请求额度。", "go.hero.title": "人人可用的低成本编程模型", "go.hero.body": "Go 将代理编程带给全世界的程序员。提供充裕的限额和对最强大的开源模型的可靠访问,让您可以利用强大的代理进行构建,而无需担心成本或可用性。", @@ -289,7 +289,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.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro 和 DeepSeek V4 Flash", + "包含 GLM-5.1, GLM-5, Kimi K2.5、Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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": "创建账户", @@ -311,7 +311,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.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro 和 DeepSeek V4 Flash 等开源模型。", + "不。Zen 是按量付费,而 Go 首月 $5,之后 $10/月,提供充裕的额度,并可可靠地访问 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.7 Max、Qwen3.6 Plus、Qwen3.5 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", @@ -333,7 +333,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.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(实际请求计数因模型和使用情况而异)。", + "免费模型包含 Big Pickle 加上当时可用的促销模型,每天有 200 次请求的配额。Go 包含 GLM-5.1, GLM-5, Kimi K2.5、Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.6 Plus, Qwen3.5 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 cfb57d359f..72686ada80 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.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 首月 $5,之後 $10/月,提供對 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.7 Max、Qwen3.6 Plus、Qwen3.5 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro 和 DeepSeek V4 Flash 的 5 小時充裕請求額度。", "go.hero.title": "低成本全民編碼模型", "go.hero.body": "Go 將代理編碼帶給全世界的程式設計師。提供寬裕的限額以及對最強大開源模型的穩定存取,讓你可以使用強大的代理進行構建,而無需擔心成本或可用性。", @@ -289,7 +289,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.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro 與 DeepSeek V4 Flash", + "包含 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.7 Max、Qwen3.6 Plus、Qwen3.5 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": "建立帳號", @@ -311,7 +311,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.5-Pro、MiMo-V2.5、Qwen3.5 Plus、Qwen3.6 Plus、MiniMax M2.5、MiniMax M2.7、DeepSeek V4 Pro 和 DeepSeek V4 Flash 等開源模型。", + "不。Zen 是按量付費,而 Go 首月 $5,之後 $10/月,提供充裕的額度,並可可靠地存取 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.7 Max、Qwen3.6 Plus、Qwen3.5 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", @@ -333,7 +333,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.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(實際請求數因模型和使用情況而異)。", + "免費模型包括 Big Pickle 以及當時可用的促銷模型,配額為 200 次請求/天。Go 包括 GLM-5.1、GLM-5、Kimi K2.5、Kimi K2.6、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.7 Max、Qwen3.6 Plus、Qwen3.5 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 71102c7227..c6cc5c24e6 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -29,8 +29,9 @@ const models = [ { name: "Kimi K2.6", provider: "Moonshot AI" }, { 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.7 Max", provider: "Alibaba Cloud Model Studio" }, { name: "Qwen3.6 Plus", provider: "Alibaba Cloud Model Studio" }, + { name: "Qwen3.5 Plus", provider: "Alibaba Cloud Model Studio" }, { name: "MiniMax M2.7", provider: "MiniMax" }, { name: "MiniMax M2.5", provider: "MiniMax" }, { name: "DeepSeek V4 Pro", provider: "DeepSeek" }, @@ -61,6 +62,7 @@ function LimitsGraph(props: { href: string }) { const free = 200 const graph = [ { id: "glm-5.1", name: "GLM-5.1", req: 880, d: "100ms" }, + { id: "qwen3.7-max", name: "Qwen3.7 Max", req: 950, d: "280ms" }, { id: "kimi-k2.6", name: "Kimi K2.6", req: 1150, 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" }, @@ -71,7 +73,6 @@ function LimitsGraph(props: { href: string }) { ] const w = 720 - const h = 330 const left = 40 const right = 60 const top = 18 @@ -107,6 +108,7 @@ function LimitsGraph(props: { href: string }) { const bh = 8 const gap = 20 const step = bh + gap + const h = 330 + Math.max(0, graph.length - 8) * step const sep = bh + 40 const fy = top + 22 const gy = (i: number) => fy + sep + step * i 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 2e065e9388..37295402d7 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 @@ -268,6 +268,7 @@ export function LiteSection(props: { lite: LiteSubscription | undefined }) {
  • MiniMax M2.7
  • Qwen3.5 Plus
  • Qwen3.6 Plus
  • +
  • Qwen3.7 Max
  • DeepSeek V4 Pro
  • DeepSeek V4 Flash
  • diff --git a/packages/web/src/content/docs/ar/go.mdx b/packages/web/src/content/docs/ar/go.mdx index f644643a18..da18988dd3 100644 --- a/packages/web/src/content/docs/ar/go.mdx +++ b/packages/web/src/content/docs/ar/go.mdx @@ -56,9 +56,10 @@ OpenCode Go هو اشتراك منخفض التكلفة — **$5 للشهر ال - **MiMo-V2.5** - **MiMo-V2.5-Pro** - **MiniMax M2.5** +- **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** -- **MiniMax M2.7** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -86,9 +87,10 @@ OpenCode Go هو اشتراك منخفض التكلفة — **$5 للشهر ال | Kimi K2.6 | 1,150 | 2,880 | 5,750 | | MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 | | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| 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.7 Max | 950 | 2,390 | 4,770 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | | DeepSeek V4 Flash | 31,650 | 79,050 | 158,150 | @@ -100,8 +102,9 @@ OpenCode Go هو اشتراك منخفض التكلفة — **$5 للشهر ال - DeepSeek V4 Pro — ‏750 input، و82,000 cached، و290 output tokens لكل طلب - DeepSeek V4 Flash — ‏790 input، و68,000 cached، و280 output tokens لكل طلب - MiniMax M2.7/M2.5 — ‏300 input، و55,000 cached، و125 output tokens لكل طلب -- Qwen3.5 Plus — ‏410 input، و47,000 cached، و140 output tokens لكل طلب +- Qwen3.7 Max — ‏420 input، و66,000 cached، و200 output tokens لكل طلب - Qwen3.6 Plus — ‏500 input، و57,000 cached، و190 output tokens لكل طلب +- Qwen3.5 Plus — ‏410 input، و47,000 cached، و140 output tokens لكل طلب - MiMo-V2.5 — ‏1000 input، و60,000 cached، و140 output tokens لكل طلب - MiMo-V2.5-Pro — ‏350 input، و41,000 cached، و250 output tokens لكل طلب @@ -137,6 +140,7 @@ OpenCode Go هو اشتراك منخفض التكلفة — **$5 للشهر ال | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/ar/zen.mdx b/packages/web/src/content/docs/ar/zen.mdx index 0dd23e06b4..e57102a374 100644 --- a/packages/web/src/content/docs/ar/zen.mdx +++ b/packages/web/src/content/docs/ar/zen.mdx @@ -84,10 +84,11 @@ OpenCode Zen هي بوابة AI تتيح لك الوصول إلى هذه الن | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `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` | | GLM 5.1 | glm-5.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -126,6 +127,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/bs/go.mdx b/packages/web/src/content/docs/bs/go.mdx index a17d89cbb1..4b1a2d3e5c 100644 --- a/packages/web/src/content/docs/bs/go.mdx +++ b/packages/web/src/content/docs/bs/go.mdx @@ -66,9 +66,10 @@ Trenutna lista modela uključuje: - **MiMo-V2.5** - **MiMo-V2.5-Pro** - **MiniMax M2.5** +- **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** -- **MiniMax M2.7** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -98,6 +99,7 @@ Tabela ispod pruža procijenjeni broj zahtjeva na osnovu tipičnih obrazaca kori | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.7 Max | 950 | 2,390 | 4,770 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | @@ -110,8 +112,9 @@ Procjene se zasnivaju na zapaženim prosječnim obrascima zahtjeva: - DeepSeek V4 Pro — 750 ulaznih, 82,000 keširanih, 290 izlaznih tokena po zahtjevu - DeepSeek V4 Flash — 790 ulaznih, 68,000 keširanih, 280 izlaznih tokena po zahtjevu - MiniMax M2.7/M2.5 — 300 ulaznih, 55,000 keširanih, 125 izlaznih tokena po zahtjevu -- Qwen3.5 Plus — 410 ulaznih, 47,000 keširanih, 140 izlaznih tokena po zahtjevu +- Qwen3.7 Max — 420 ulaznih, 66,000 keširanih, 200 izlaznih tokena po zahtjevu - Qwen3.6 Plus — 500 ulaznih, 57,000 keširanih, 190 izlaznih tokena po zahtjevu +- Qwen3.5 Plus — 410 ulaznih, 47,000 keširanih, 140 izlaznih tokena po zahtjevu - MiMo-V2.5 — 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 @@ -149,6 +152,7 @@ Također možete pristupiti Go modelima putem sljedećih API endpointa. | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/bs/zen.mdx b/packages/web/src/content/docs/bs/zen.mdx index 91c08d1e11..5ac0308b21 100644 --- a/packages/web/src/content/docs/bs/zen.mdx +++ b/packages/web/src/content/docs/bs/zen.mdx @@ -89,10 +89,11 @@ Našim modelima možete pristupiti i preko sljedećih API endpointa. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `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` | | GLM 5.1 | glm-5.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -133,6 +134,7 @@ Podržavamo pay-as-you-go model. Ispod su cijene **po 1M tokena**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/da/go.mdx b/packages/web/src/content/docs/da/go.mdx index 912ae22e02..01368470ee 100644 --- a/packages/web/src/content/docs/da/go.mdx +++ b/packages/web/src/content/docs/da/go.mdx @@ -66,9 +66,10 @@ Den nuværende liste over modeller inkluderer: - **MiMo-V2.5** - **MiMo-V2.5-Pro** - **MiniMax M2.5** +- **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** -- **MiniMax M2.7** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -98,6 +99,7 @@ Tabellen nedenfor giver et estimeret antal anmodninger baseret på typiske Go-fo | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.7 Max | 950 | 2,390 | 4,770 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | @@ -110,8 +112,9 @@ Estimaterne er baseret på observerede gennemsnitlige anmodningsmønstre: - DeepSeek V4 Pro — 750 input, 82.000 cachelagrede, 290 output-tokens pr. anmodning - DeepSeek V4 Flash — 790 input, 68.000 cachelagrede, 280 output-tokens pr. anmodning - MiniMax M2.7/M2.5 — 300 input, 55.000 cachelagrede, 125 output-tokens pr. anmodning -- Qwen3.5 Plus — 410 input, 47.000 cachelagrede, 140 output-tokens pr. anmodning +- Qwen3.7 Max — 420 input, 66.000 cachelagrede, 200 output-tokens pr. anmodning - Qwen3.6 Plus — 500 input, 57.000 cachelagrede, 190 output-tokens pr. anmodning +- Qwen3.5 Plus — 410 input, 47.000 cachelagrede, 140 output-tokens pr. anmodning - MiMo-V2.5 — 1000 input, 60.000 cachelagrede, 140 output-tokens pr. anmodning - MiMo-V2.5-Pro — 350 input, 41.000 cachelagrede, 250 output-tokens pr. anmodning @@ -149,6 +152,7 @@ Du kan også få adgang til Go-modeller gennem følgende API-endpoints. | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/da/zen.mdx b/packages/web/src/content/docs/da/zen.mdx index 54c09cbbd0..3c7e7a516c 100644 --- a/packages/web/src/content/docs/da/zen.mdx +++ b/packages/web/src/content/docs/da/zen.mdx @@ -89,10 +89,11 @@ Du kan også få adgang til vores modeller gennem følgende API-endpoints. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `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` | | GLM 5.1 | glm-5.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -133,6 +134,7 @@ Vi understøtter en pay-as-you-go-model. Nedenfor er priserne **pr. 1M tokens**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/de/go.mdx b/packages/web/src/content/docs/de/go.mdx index 093ef91da8..746945d85d 100644 --- a/packages/web/src/content/docs/de/go.mdx +++ b/packages/web/src/content/docs/de/go.mdx @@ -58,9 +58,10 @@ Die aktuelle Liste der Modelle umfasst: - **MiMo-V2.5** - **MiMo-V2.5-Pro** - **MiniMax M2.5** +- **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** -- **MiniMax M2.7** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -90,6 +91,7 @@ Die folgende Tabelle zeigt eine geschätzte Anzahl von Anfragen basierend auf ty | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.7 Max | 950 | 2,390 | 4,770 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | @@ -102,8 +104,9 @@ Die Schätzungen basieren auf beobachteten durchschnittlichen Anfragemustern: - DeepSeek V4 Pro — 750 Input-, 82.000 Cached-, 290 Output-Tokens pro Anfrage - DeepSeek V4 Flash — 790 Input-, 68.000 Cached-, 280 Output-Tokens pro Anfrage - 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 pro Anfrage +- Qwen3.7 Max — 420 Input-, 66.000 Cached-, 200 Output-Tokens pro Anfrage - Qwen3.6 Plus — 500 Input-, 57.000 Cached-, 190 Output-Tokens pro Anfrage +- Qwen3.5 Plus — 410 Input-, 47.000 Cached-, 140 Output-Tokens pro Anfrage - MiMo-V2.5 — 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 @@ -139,6 +142,7 @@ Du kannst auf die Go-Modelle auch über die folgenden API-Endpunkte zugreifen. | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/de/zen.mdx b/packages/web/src/content/docs/de/zen.mdx index 22129e56f4..ffc58cc031 100644 --- a/packages/web/src/content/docs/de/zen.mdx +++ b/packages/web/src/content/docs/de/zen.mdx @@ -80,10 +80,11 @@ Du kannst auch über die folgenden API-Endpunkte auf unsere Modelle zugreifen. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `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` | | GLM 5.1 | glm-5.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -122,6 +123,7 @@ Wir unterstützen ein Pay-as-you-go-Modell. Unten findest du die Preise **pro 1M | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/es/go.mdx b/packages/web/src/content/docs/es/go.mdx index 37697b2cad..2106c905e5 100644 --- a/packages/web/src/content/docs/es/go.mdx +++ b/packages/web/src/content/docs/es/go.mdx @@ -66,9 +66,10 @@ La lista actual de modelos incluye: - **MiMo-V2.5** - **MiMo-V2.5-Pro** - **MiniMax M2.5** +- **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** -- **MiniMax M2.7** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -98,6 +99,7 @@ La siguiente tabla proporciona una cantidad estimada de peticiones basada en los | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.7 Max | 950 | 2,390 | 4,770 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | @@ -110,8 +112,9 @@ Las estimaciones se basan en los patrones de peticiones promedio observados: - DeepSeek V4 Pro — 750 tokens de entrada, 82,000 en caché, 290 tokens de salida por petición - DeepSeek V4 Flash — 790 tokens de entrada, 68,000 en caché, 280 tokens de salida por petición - MiniMax M2.7/M2.5 — 300 tokens de entrada, 55,000 en caché, 125 tokens de salida por petición -- Qwen3.5 Plus — 410 tokens de entrada, 47,000 en caché, 140 tokens de salida por petición +- Qwen3.7 Max — 420 tokens de entrada, 66,000 en caché, 200 tokens de salida por petición - Qwen3.6 Plus — 500 tokens de entrada, 57,000 en caché, 190 tokens de salida por petición +- Qwen3.5 Plus — 410 tokens de entrada, 47,000 en caché, 140 tokens de salida por petición - MiMo-V2.5 — 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 @@ -149,6 +152,7 @@ También puedes acceder a los modelos de Go a través de los siguientes endpoint | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/es/zen.mdx b/packages/web/src/content/docs/es/zen.mdx index 96c294366b..58adc6d1a2 100644 --- a/packages/web/src/content/docs/es/zen.mdx +++ b/packages/web/src/content/docs/es/zen.mdx @@ -89,10 +89,11 @@ También puedes acceder a nuestros modelos a través de los siguientes endpoints | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `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` | | GLM 5.1 | glm-5.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -133,6 +134,7 @@ Admitimos un modelo de pago por uso. A continuación se muestran los precios **p | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/fr/go.mdx b/packages/web/src/content/docs/fr/go.mdx index a2faec91f4..35f7bdeb06 100644 --- a/packages/web/src/content/docs/fr/go.mdx +++ b/packages/web/src/content/docs/fr/go.mdx @@ -56,9 +56,10 @@ La liste actuelle des modèles comprend : - **MiMo-V2.5** - **MiMo-V2.5-Pro** - **MiniMax M2.5** +- **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** -- **MiniMax M2.7** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -88,6 +89,7 @@ Le tableau ci-dessous fournit une estimation du nombre de requêtes basée sur d | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.7 Max | 950 | 2,390 | 4,770 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | @@ -100,8 +102,9 @@ Les estimations sont basées sur les modèles de requêtes moyens observés : - DeepSeek V4 Pro — 750 tokens en entrée, 82,000 en cache, 290 tokens en sortie par requête - DeepSeek V4 Flash — 790 tokens en entrée, 68,000 en cache, 280 tokens en sortie par requête - 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 tokens en entrée, 47,000 en cache, 140 tokens en sortie par requête +- Qwen3.7 Max — 420 tokens en entrée, 66,000 en cache, 200 tokens en sortie par requête - Qwen3.6 Plus — 500 tokens en entrée, 57,000 en cache, 190 tokens en sortie par requête +- Qwen3.5 Plus — 410 tokens en entrée, 47,000 en cache, 140 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 - MiMo-V2.5-Pro — 350 tokens en entrée, 41,000 en cache, 250 tokens en sortie par requête @@ -137,6 +140,7 @@ Vous pouvez également accéder aux modèles Go via les points de terminaison d' | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/fr/zen.mdx b/packages/web/src/content/docs/fr/zen.mdx index 5650c42625..243f31ca89 100644 --- a/packages/web/src/content/docs/fr/zen.mdx +++ b/packages/web/src/content/docs/fr/zen.mdx @@ -80,10 +80,11 @@ Vous pouvez également accéder à nos modèles via les points de terminaison AP | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `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` | | GLM 5.1 | glm-5.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -122,6 +123,7 @@ Nous prenons en charge un modèle de paiement à l'utilisation. Vous trouverez c | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/go.mdx b/packages/web/src/content/docs/go.mdx index 3d8e4f6987..5f993bb7c8 100644 --- a/packages/web/src/content/docs/go.mdx +++ b/packages/web/src/content/docs/go.mdx @@ -69,6 +69,7 @@ The current list of models includes: - **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -98,6 +99,7 @@ The table below provides an estimated request count based on typical Go usage pa | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.7 Max | 950 | 2,390 | 4,770 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | @@ -112,8 +114,9 @@ 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.5 — 1000 input, 60,000 cached, 140 output tokens per request - MiMo-V2.5-Pro — 350 input, 41,000 cached, 250 output tokens per request -- Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request +- Qwen3.7 Max — 420 input, 66,000 cached, 200 output tokens per request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens per request +- Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens per request You can track your current usage in the **console**. @@ -149,6 +152,7 @@ You can also access Go models through the following API endpoints. | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/it/go.mdx b/packages/web/src/content/docs/it/go.mdx index 1a189803ae..4d17972059 100644 --- a/packages/web/src/content/docs/it/go.mdx +++ b/packages/web/src/content/docs/it/go.mdx @@ -64,9 +64,10 @@ L'elenco attuale dei modelli include: - **MiMo-V2.5** - **MiMo-V2.5-Pro** - **MiniMax M2.5** +- **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** -- **MiniMax M2.7** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -96,6 +97,7 @@ La tabella seguente fornisce una stima del conteggio delle richieste in base a p | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.7 Max | 950 | 2,390 | 4,770 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | @@ -108,8 +110,9 @@ Le stime si basano sui pattern medi di richieste osservati: - DeepSeek V4 Pro — 750 di input, 82.000 in cache, 290 token di output per richiesta - DeepSeek V4 Flash — 790 di input, 68.000 in cache, 280 token di output per richiesta - MiniMax M2.7/M2.5 — 300 di input, 55.000 in cache, 125 token di output per richiesta -- Qwen3.5 Plus — 410 di input, 47.000 in cache, 140 token di output per richiesta +- Qwen3.7 Max — 420 di input, 66.000 in cache, 200 token di output per richiesta - Qwen3.6 Plus — 500 di input, 57.000 in cache, 190 token di output per richiesta +- Qwen3.5 Plus — 410 di input, 47.000 in cache, 140 token di output per richiesta - MiMo-V2.5 — 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 @@ -147,6 +150,7 @@ Puoi anche accedere ai modelli Go tramite i seguenti endpoint API. | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/it/zen.mdx b/packages/web/src/content/docs/it/zen.mdx index fc34016d31..b13b383114 100644 --- a/packages/web/src/content/docs/it/zen.mdx +++ b/packages/web/src/content/docs/it/zen.mdx @@ -89,10 +89,11 @@ Puoi anche accedere ai nostri modelli tramite i seguenti endpoint API. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `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` | | GLM 5.1 | glm-5.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -133,6 +134,7 @@ Supportiamo un modello pay-as-you-go. Qui sotto trovi i prezzi **per 1M token**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/ja/go.mdx b/packages/web/src/content/docs/ja/go.mdx index c2d50f5aa0..2c4c6e05a2 100644 --- a/packages/web/src/content/docs/ja/go.mdx +++ b/packages/web/src/content/docs/ja/go.mdx @@ -56,9 +56,10 @@ OpenCode Goをサブスクライブできるのは、1つのワークスペー - **MiMo-V2.5** - **MiMo-V2.5-Pro** - **MiniMax M2.5** +- **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** -- **MiniMax M2.7** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -88,6 +89,7 @@ OpenCode Goには以下の制限が含まれています: | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.7 Max | 950 | 2,390 | 4,770 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | @@ -100,8 +102,9 @@ OpenCode Goには以下の制限が含まれています: - DeepSeek V4 Pro — リクエストあたり 入力 750トークン、キャッシュ 82,000トークン、出力 290トークン - DeepSeek V4 Flash — リクエストあたり 入力 790トークン、キャッシュ 68,000トークン、出力 280トークン - MiniMax M2.7/M2.5 — リクエストあたり 入力 300トークン、キャッシュ 55,000トークン、出力 125トークン -- Qwen3.5 Plus — リクエストあたり 入力 410トークン、キャッシュ 47,000トークン、出力 140トークン +- Qwen3.7 Max — リクエストあたり 入力 420トークン、キャッシュ 66,000トークン、出力 200トークン - Qwen3.6 Plus — リクエストあたり 入力 500トークン、キャッシュ 57,000トークン、出力 190トークン +- Qwen3.5 Plus — リクエストあたり 入力 410トークン、キャッシュ 47,000トークン、出力 140トークン - MiMo-V2.5 — リクエストあたり 入力 1000トークン、キャッシュ 60,000トークン、出力 140トークン - MiMo-V2.5-Pro — リクエストあたり 入力 350トークン、キャッシュ 41,000トークン、出力 250トークン @@ -137,6 +140,7 @@ Zen残高にクレジットがある場合は、コンソールで**Use balance* | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/ja/zen.mdx b/packages/web/src/content/docs/ja/zen.mdx index 0ce99ab57d..12307d4bac 100644 --- a/packages/web/src/content/docs/ja/zen.mdx +++ b/packages/web/src/content/docs/ja/zen.mdx @@ -80,10 +80,11 @@ OpenCode Zen は、OpenCode のほかのプロバイダーと同じように動 | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `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` | | GLM 5.1 | glm-5.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -122,6 +123,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/ko/go.mdx b/packages/web/src/content/docs/ko/go.mdx index ca0bee3c1a..def8ec2430 100644 --- a/packages/web/src/content/docs/ko/go.mdx +++ b/packages/web/src/content/docs/ko/go.mdx @@ -56,9 +56,10 @@ workspace당 한 명의 멤버만 OpenCode Go를 구독할 수 있습니다. - **MiMo-V2.5** - **MiMo-V2.5-Pro** - **MiniMax M2.5** +- **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** -- **MiniMax M2.7** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -88,6 +89,7 @@ OpenCode Go에는 다음과 같은 한도가 포함됩니다. | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.7 Max | 950 | 2,390 | 4,770 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | @@ -100,8 +102,9 @@ OpenCode Go에는 다음과 같은 한도가 포함됩니다. - DeepSeek V4 Pro — 요청당 입력 750, 캐시 82,000, 출력 토큰 290 - DeepSeek V4 Flash — 요청당 입력 790, 캐시 68,000, 출력 토큰 280 - MiniMax M2.7/M2.5 — 요청당 입력 300, 캐시 55,000, 출력 토큰 125 -- Qwen3.5 Plus — 요청당 입력 410, 캐시 47,000, 출력 토큰 140 +- Qwen3.7 Max — 요청당 입력 420, 캐시 66,000, 출력 토큰 200 - Qwen3.6 Plus — 요청당 입력 500, 캐시 57,000, 출력 토큰 190 +- Qwen3.5 Plus — 요청당 입력 410, 캐시 47,000, 출력 토큰 140 - MiMo-V2.5 — 요청당 입력 1000, 캐시 60,000, 출력 토큰 140 - MiMo-V2.5-Pro — 요청당 입력 350, 캐시 41,000, 출력 토큰 250 @@ -137,6 +140,7 @@ Zen 잔액에 크레딧도 있다면, console에서 **Use balance** 옵션을 | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/ko/zen.mdx b/packages/web/src/content/docs/ko/zen.mdx index 8579032277..a7576b76b5 100644 --- a/packages/web/src/content/docs/ko/zen.mdx +++ b/packages/web/src/content/docs/ko/zen.mdx @@ -80,10 +80,11 @@ OpenCode Zen은 OpenCode의 다른 provider와 똑같이 작동합니다. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `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` | | GLM 5.1 | glm-5.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -122,6 +123,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/nb/go.mdx b/packages/web/src/content/docs/nb/go.mdx index 022e2b86ba..f68c12c6e7 100644 --- a/packages/web/src/content/docs/nb/go.mdx +++ b/packages/web/src/content/docs/nb/go.mdx @@ -66,9 +66,10 @@ Den nåværende listen over modeller inkluderer: - **MiMo-V2.5** - **MiMo-V2.5-Pro** - **MiniMax M2.5** +- **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** -- **MiniMax M2.7** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -98,6 +99,7 @@ Tabellen nedenfor gir et estimert antall forespørsler basert på typiske bruksm | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.7 Max | 950 | 2,390 | 4,770 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | @@ -110,8 +112,9 @@ Estimatene er basert på observerte gjennomsnittlige forespørselsmønstre: - DeepSeek V4 Pro — 750 input, 82 000 bufret, 290 output-tokens per forespørsel - DeepSeek V4 Flash — 790 input, 68 000 bufret, 280 output-tokens per forespørsel - MiniMax M2.7/M2.5 — 300 input, 55 000 bufret, 125 output-tokens per forespørsel -- Qwen3.5 Plus — 410 input, 47 000 bufret, 140 output-tokens per forespørsel +- Qwen3.7 Max — 420 input, 66 000 bufret, 200 output-tokens per forespørsel - Qwen3.6 Plus — 500 input, 57 000 bufret, 190 output-tokens per forespørsel +- Qwen3.5 Plus — 410 input, 47 000 bufret, 140 output-tokens per forespørsel - MiMo-V2.5 — 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 @@ -149,6 +152,7 @@ Du kan også få tilgang til Go-modeller gjennom følgende API-endepunkter. | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/nb/zen.mdx b/packages/web/src/content/docs/nb/zen.mdx index c9aa4514fd..bd4b3950e2 100644 --- a/packages/web/src/content/docs/nb/zen.mdx +++ b/packages/web/src/content/docs/nb/zen.mdx @@ -89,10 +89,11 @@ Du kan også få tilgang til modellene våre gjennom følgende API-endepunkter. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `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` | | GLM 5.1 | glm-5.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -133,6 +134,7 @@ Vi støtter en pay-as-you-go-modell. Nedenfor er prisene **per 1M tokens**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/pl/go.mdx b/packages/web/src/content/docs/pl/go.mdx index 84d0ca036e..68fa33ebeb 100644 --- a/packages/web/src/content/docs/pl/go.mdx +++ b/packages/web/src/content/docs/pl/go.mdx @@ -60,9 +60,10 @@ Obecna lista modeli obejmuje: - **MiMo-V2.5** - **MiMo-V2.5-Pro** - **MiniMax M2.5** +- **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** -- **MiniMax M2.7** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -92,6 +93,7 @@ Poniższa tabela przedstawia szacunkową liczbę żądań na podstawie typowych | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.7 Max | 950 | 2,390 | 4,770 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | @@ -104,8 +106,9 @@ Szacunki opierają się na zaobserwowanych średnich wzorcach żądań: - DeepSeek V4 Pro — 750 tokenów wejściowych, 82 000 w pamięci podręcznej, 290 tokenów wyjściowych na żądanie - DeepSeek V4 Flash — 790 tokenów wejściowych, 68 000 w pamięci podręcznej, 280 tokenów wyjściowych na żądanie - 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 tokenów wejściowych, 47 000 w pamięci podręcznej, 140 tokenów wyjściowych na żądanie +- Qwen3.7 Max — 420 tokenów wejściowych, 66 000 w pamięci podręcznej, 200 tokenów wyjściowych na żądanie - Qwen3.6 Plus — 500 tokenów wejściowych, 57 000 w pamięci podręcznej, 190 tokenów wyjściowych na żądanie +- Qwen3.5 Plus — 410 tokenów wejściowych, 47 000 w pamięci podręcznej, 140 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 - MiMo-V2.5-Pro — 350 tokenów wejściowych, 41 000 w pamięci podręcznej, 250 tokenów wyjściowych na żądanie @@ -141,6 +144,7 @@ Możesz również uzyskać dostęp do modeli Go za pośrednictwem następującyc | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/pl/zen.mdx b/packages/web/src/content/docs/pl/zen.mdx index 99743b8489..19388b556e 100644 --- a/packages/web/src/content/docs/pl/zen.mdx +++ b/packages/web/src/content/docs/pl/zen.mdx @@ -89,6 +89,7 @@ Możesz też uzyskać dostęp do naszych modeli przez poniższe endpointy API. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -133,6 +134,7 @@ Obsługujemy model pay-as-you-go. Poniżej znajdują się ceny **za 1M tokenów* | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/pt-br/go.mdx b/packages/web/src/content/docs/pt-br/go.mdx index d261395d46..fa3527d035 100644 --- a/packages/web/src/content/docs/pt-br/go.mdx +++ b/packages/web/src/content/docs/pt-br/go.mdx @@ -66,9 +66,10 @@ A lista atual de modelos inclui: - **MiMo-V2.5** - **MiMo-V2.5-Pro** - **MiniMax M2.5** +- **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** -- **MiniMax M2.7** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -98,6 +99,7 @@ A tabela abaixo fornece uma contagem estimada de requisições com base nos padr | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.7 Max | 950 | 2,390 | 4,770 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | @@ -110,8 +112,9 @@ As estimativas baseiam-se nos padrões médios de requisições observados: - DeepSeek V4 Pro — 750 tokens de entrada, 82.000 em cache, 290 tokens de saída por requisição - DeepSeek V4 Flash — 790 tokens de entrada, 68.000 em cache, 280 tokens de saída por requisição - 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 tokens de entrada, 47.000 em cache, 140 tokens de saída por requisição +- Qwen3.7 Max — 420 tokens de entrada, 66.000 em cache, 200 tokens de saída por requisição - Qwen3.6 Plus — 500 tokens de entrada, 57.000 em cache, 190 tokens de saída por requisição +- Qwen3.5 Plus — 410 tokens de entrada, 47.000 em cache, 140 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 - MiMo-V2.5-Pro — 350 tokens de entrada, 41.000 em cache, 250 tokens de saída por requisição @@ -149,6 +152,7 @@ Você também pode acessar os modelos do Go através dos seguintes endpoints de | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/pt-br/zen.mdx b/packages/web/src/content/docs/pt-br/zen.mdx index 054e1e19ec..d5bd468e94 100644 --- a/packages/web/src/content/docs/pt-br/zen.mdx +++ b/packages/web/src/content/docs/pt-br/zen.mdx @@ -80,6 +80,7 @@ Você também pode acessar nossos modelos pelos seguintes endpoints de API. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -122,6 +123,7 @@ Oferecemos um modelo pay-as-you-go. Abaixo estão os preços **por 1M tokens**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/ru/go.mdx b/packages/web/src/content/docs/ru/go.mdx index 88cadfe291..6b42057aeb 100644 --- a/packages/web/src/content/docs/ru/go.mdx +++ b/packages/web/src/content/docs/ru/go.mdx @@ -66,9 +66,10 @@ OpenCode Go работает так же, как и любой другой пр - **MiMo-V2.5** - **MiMo-V2.5-Pro** - **MiniMax M2.5** +- **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** -- **MiniMax M2.7** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -98,6 +99,7 @@ OpenCode Go включает следующие лимиты: | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.7 Max | 950 | 2,390 | 4,770 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | @@ -110,8 +112,9 @@ OpenCode Go включает следующие лимиты: - DeepSeek V4 Pro — 750 входных, 82,000 кешированных, 290 выходных токенов на запрос - DeepSeek V4 Flash — 790 входных, 68,000 кешированных, 280 выходных токенов на запрос - MiniMax M2.7/M2.5 — 300 входных, 55,000 кешированных, 125 выходных токенов на запрос -- Qwen3.5 Plus — 410 входных, 47,000 кешированных, 140 выходных токенов на запрос +- Qwen3.7 Max — 420 входных, 66,000 кешированных, 200 выходных токенов на запрос - Qwen3.6 Plus — 500 входных, 57,000 кешированных, 190 выходных токенов на запрос +- Qwen3.5 Plus — 410 входных, 47,000 кешированных, 140 выходных токенов на запрос - MiMo-V2.5 — 1000 входных, 60,000 кешированных, 140 выходных токенов на запрос - MiMo-V2.5-Pro — 350 входных, 41,000 кешированных, 250 выходных токенов на запрос @@ -149,6 +152,7 @@ OpenCode Go включает следующие лимиты: | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/ru/zen.mdx b/packages/web/src/content/docs/ru/zen.mdx index 54491d14e1..a9bd1f9500 100644 --- a/packages/web/src/content/docs/ru/zen.mdx +++ b/packages/web/src/content/docs/ru/zen.mdx @@ -89,6 +89,7 @@ OpenCode Zen работает как любой другой провайдер | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -133,6 +134,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/th/go.mdx b/packages/web/src/content/docs/th/go.mdx index 2059ad2c06..03e45e4731 100644 --- a/packages/web/src/content/docs/th/go.mdx +++ b/packages/web/src/content/docs/th/go.mdx @@ -56,9 +56,10 @@ OpenCode Go ทำงานเหมือนกับผู้ให้บร - **MiMo-V2.5** - **MiMo-V2.5-Pro** - **MiniMax M2.5** +- **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** -- **MiniMax M2.7** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -88,6 +89,7 @@ OpenCode Go มีขีดจำกัดดังต่อไปนี้: | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.7 Max | 950 | 2,390 | 4,770 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | @@ -100,8 +102,9 @@ OpenCode Go มีขีดจำกัดดังต่อไปนี้: - DeepSeek V4 Pro — 750 input, 82,000 cached, 290 output tokens ต่อ request - DeepSeek V4 Flash — 790 input, 68,000 cached, 280 output tokens ต่อ 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 ต่อ request +- Qwen3.7 Max — 420 input, 66,000 cached, 200 output tokens ต่อ request - Qwen3.6 Plus — 500 input, 57,000 cached, 190 output tokens ต่อ request +- Qwen3.5 Plus — 410 input, 47,000 cached, 140 output tokens ต่อ request - MiMo-V2.5 — 1000 input, 60,000 cached, 140 output tokens ต่อ request - MiMo-V2.5-Pro — 350 input, 41,000 cached, 250 output tokens ต่อ request @@ -137,6 +140,7 @@ OpenCode Go มีขีดจำกัดดังต่อไปนี้: | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/th/zen.mdx b/packages/web/src/content/docs/th/zen.mdx index 9c233d46ca..0a6201cf25 100644 --- a/packages/web/src/content/docs/th/zen.mdx +++ b/packages/web/src/content/docs/th/zen.mdx @@ -82,10 +82,11 @@ OpenCode Zen ทำงานเหมือน provider อื่น ๆ ใน | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `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` | | GLM 5.1 | glm-5.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -124,6 +125,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/tr/go.mdx b/packages/web/src/content/docs/tr/go.mdx index 49d7ebecc0..1defec2be7 100644 --- a/packages/web/src/content/docs/tr/go.mdx +++ b/packages/web/src/content/docs/tr/go.mdx @@ -56,9 +56,10 @@ Mevcut model listesi şunları içerir: - **MiMo-V2.5** - **MiMo-V2.5-Pro** - **MiniMax M2.5** +- **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** -- **MiniMax M2.7** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -88,6 +89,7 @@ Aşağıdaki tablo, tipik Go kullanım modellerine dayalı tahmini bir istek say | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | | MiniMax M2.7 | 3,400 | 8,500 | 17,000 | | MiniMax M2.5 | 6,300 | 15,900 | 31,800 | +| Qwen3.7 Max | 950 | 2,390 | 4,770 | | Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | @@ -100,8 +102,9 @@ Tahminler, gözlemlenen ortalama istek modellerine dayanmaktadır: - DeepSeek V4 Pro — İstek başına 750 girdi, 82.000 önbelleğe alınmış, 290 çıktı token'ı - DeepSeek V4 Flash — İstek başına 790 girdi, 68.000 önbelleğe alınmış, 280 çıktı token'ı - MiniMax M2.7/M2.5 — İstek başına 300 girdi, 55.000 önbelleğe alınmış, 125 çıktı token'ı -- Qwen3.5 Plus — İstek başına 410 girdi, 47.000 önbelleğe alınmış, 140 çıktı token'ı +- Qwen3.7 Max — İstek başına 420 girdi, 66.000 önbelleğe alınmış, 200 çıktı token'ı - Qwen3.6 Plus — İstek başına 500 girdi, 57.000 önbelleğe alınmış, 190 çıktı token'ı +- Qwen3.5 Plus — İstek başına 410 girdi, 47.000 önbelleğe alınmış, 140 çıktı token'ı - MiMo-V2.5 — İ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'ı @@ -137,6 +140,7 @@ Go modellerine aşağıdaki API uç noktaları aracılığıyla da erişebilirsi | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/tr/zen.mdx b/packages/web/src/content/docs/tr/zen.mdx index 8357d107a8..732783a529 100644 --- a/packages/web/src/content/docs/tr/zen.mdx +++ b/packages/web/src/content/docs/tr/zen.mdx @@ -80,10 +80,11 @@ Modellerimize aşağıdaki API uç noktaları aracılığıyla da erişebilirsin | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| MiniMax M2.5 | minimax-m2.5 | `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` | | GLM 5.1 | glm-5.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -122,6 +123,7 @@ Kullandıkça öde modelini destekliyoruz. Aşağıda **1M token başına** fiya | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/zen.mdx b/packages/web/src/content/docs/zen.mdx index 173b34f548..6147552b86 100644 --- a/packages/web/src/content/docs/zen.mdx +++ b/packages/web/src/content/docs/zen.mdx @@ -89,6 +89,7 @@ You can also access our models through the following API endpoints. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -133,6 +134,7 @@ We support a pay-as-you-go model. Below are the prices **per 1M tokens**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/zh-cn/go.mdx b/packages/web/src/content/docs/zh-cn/go.mdx index 2e2c792089..959ad01df1 100644 --- a/packages/web/src/content/docs/zh-cn/go.mdx +++ b/packages/web/src/content/docs/zh-cn/go.mdx @@ -56,9 +56,10 @@ OpenCode Go 的工作方式与 OpenCode 中的其他提供商一样。 - **MiMo-V2.5** - **MiMo-V2.5-Pro** - **MiniMax M2.5** +- **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** -- **MiniMax M2.7** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -86,9 +87,10 @@ OpenCode Go 包含以下限制: | Kimi K2.5 | 1,850 | 4,630 | 9,250 | | MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 | | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| 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.7 Max | 950 | 2,390 | 4,770 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | | DeepSeek V4 Flash | 31,650 | 79,050 | 158,150 | @@ -102,8 +104,9 @@ OpenCode Go 包含以下限制: - MiMo-V2.5 — 每次请求 1000 个输入 token,60,000 个缓存 token,140 个输出 token - MiMo-V2.5-Pro — 每次请求 350 个输入 token,41,000 个缓存 token,250 个输出 token - MiniMax M2.7/M2.5 — 每次请求 300 个输入 token,55,000 个缓存 token,125 个输出 token -- Qwen3.5 Plus — 每次请求 410 个输入 token,47,000 个缓存 token,140 个输出 token +- Qwen3.7 Max — 每次请求 420 个输入 token,66,000 个缓存 token,200 个输出 token - Qwen3.6 Plus — 每次请求 500 个输入 token,57,000 个缓存 token,190 个输出 token +- Qwen3.5 Plus — 每次请求 410 个输入 token,47,000 个缓存 token,140 个输出 token 你可以在 **控制台** 中跟踪你当前的使用情况。 @@ -137,6 +140,7 @@ OpenCode Go 包含以下限制: | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/zh-cn/zen.mdx b/packages/web/src/content/docs/zh-cn/zen.mdx index 65e009f9bc..52730c3031 100644 --- a/packages/web/src/content/docs/zh-cn/zen.mdx +++ b/packages/web/src/content/docs/zh-cn/zen.mdx @@ -80,6 +80,7 @@ OpenCode Zen 的工作方式与 OpenCode 中的任何其他提供商相同。 | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -122,6 +123,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/zh-tw/go.mdx b/packages/web/src/content/docs/zh-tw/go.mdx index 763a113078..666febe0e0 100644 --- a/packages/web/src/content/docs/zh-tw/go.mdx +++ b/packages/web/src/content/docs/zh-tw/go.mdx @@ -56,9 +56,10 @@ OpenCode Go 的運作方式與 OpenCode 中的任何其他供應商相同。 - **MiMo-V2.5** - **MiMo-V2.5-Pro** - **MiniMax M2.5** +- **MiniMax M2.7** - **Qwen3.5 Plus** - **Qwen3.6 Plus** -- **MiniMax M2.7** +- **Qwen3.7 Max** - **DeepSeek V4 Pro** - **DeepSeek V4 Flash** @@ -86,9 +87,10 @@ OpenCode Go 包含以下限制: | Kimi K2.6 | 1,150 | 2,880 | 5,750 | | MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 | | MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 | -| 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.7 Max | 950 | 2,390 | 4,770 | +| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 | | Qwen3.5 Plus | 10,200 | 25,200 | 50,500 | | DeepSeek V4 Pro | 3,450 | 8,550 | 17,150 | | DeepSeek V4 Flash | 31,650 | 79,050 | 158,150 | @@ -100,8 +102,9 @@ OpenCode Go 包含以下限制: - DeepSeek V4 Pro — 每次請求 750 個輸入 token、82,000 個快取 token、290 個輸出 token - DeepSeek V4 Flash — 每次請求 790 個輸入 token、68,000 個快取 token、280 個輸出 token - MiniMax M2.7/M2.5 — 每次請求 300 個輸入 token、55,000 個快取 token、125 個輸出 token -- Qwen3.5 Plus — 每次請求 410 個輸入 token、47,000 個快取 token、140 個輸出 token +- Qwen3.7 Max — 每次請求 420 個輸入 token、66,000 個快取 token、200 個輸出 token - Qwen3.6 Plus — 每次請求 500 個輸入 token、57,000 個快取 token、190 個輸出 token +- Qwen3.5 Plus — 每次請求 410 個輸入 token、47,000 個快取 token、140 個輸出 token - MiMo-V2.5 — 每次請求 1000 個輸入 token、60,000 個快取 token、140 個輸出 token - MiMo-V2.5-Pro — 每次請求 350 個輸入 token、41,000 個快取 token、250 個輸出 token @@ -137,6 +140,7 @@ OpenCode Go 包含以下限制: | MiMo-V2.5-Pro | mimo-v2.5-pro | `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.7 Max | qwen3.7-max | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | diff --git a/packages/web/src/content/docs/zh-tw/zen.mdx b/packages/web/src/content/docs/zh-tw/zen.mdx index 0cb5a45754..ae62add0f1 100644 --- a/packages/web/src/content/docs/zh-tw/zen.mdx +++ b/packages/web/src/content/docs/zh-tw/zen.mdx @@ -84,6 +84,7 @@ OpenCode Zen 的運作方式和 OpenCode 中的其他供應商一樣。 | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -127,6 +128,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | From cf8b03ec109f59890fba0dfe88b6c7c053f1e407 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Tue, 26 May 2026 17:29:38 +0000 Subject: [PATCH 29/40] chore: generate --- 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 e57102a374..a0d118cfb7 100644 --- a/packages/web/src/content/docs/ar/zen.mdx +++ b/packages/web/src/content/docs/ar/zen.mdx @@ -127,7 +127,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/bs/zen.mdx b/packages/web/src/content/docs/bs/zen.mdx index 5ac0308b21..24bb7b0867 100644 --- a/packages/web/src/content/docs/bs/zen.mdx +++ b/packages/web/src/content/docs/bs/zen.mdx @@ -134,7 +134,7 @@ Podržavamo pay-as-you-go model. Ispod su cijene **po 1M tokena**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/da/zen.mdx b/packages/web/src/content/docs/da/zen.mdx index 3c7e7a516c..22f9c0b6f5 100644 --- a/packages/web/src/content/docs/da/zen.mdx +++ b/packages/web/src/content/docs/da/zen.mdx @@ -134,7 +134,7 @@ Vi understøtter en pay-as-you-go-model. Nedenfor er priserne **pr. 1M tokens**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/de/zen.mdx b/packages/web/src/content/docs/de/zen.mdx index ffc58cc031..fb81083361 100644 --- a/packages/web/src/content/docs/de/zen.mdx +++ b/packages/web/src/content/docs/de/zen.mdx @@ -123,7 +123,7 @@ Wir unterstützen ein Pay-as-you-go-Modell. Unten findest du die Preise **pro 1M | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/es/zen.mdx b/packages/web/src/content/docs/es/zen.mdx index 58adc6d1a2..2d51ccbef9 100644 --- a/packages/web/src/content/docs/es/zen.mdx +++ b/packages/web/src/content/docs/es/zen.mdx @@ -134,7 +134,7 @@ Admitimos un modelo de pago por uso. A continuación se muestran los precios **p | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/fr/zen.mdx b/packages/web/src/content/docs/fr/zen.mdx index 243f31ca89..19f6b08a15 100644 --- a/packages/web/src/content/docs/fr/zen.mdx +++ b/packages/web/src/content/docs/fr/zen.mdx @@ -123,7 +123,7 @@ Nous prenons en charge un modèle de paiement à l'utilisation. Vous trouverez c | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/it/zen.mdx b/packages/web/src/content/docs/it/zen.mdx index b13b383114..6d1aab9b85 100644 --- a/packages/web/src/content/docs/it/zen.mdx +++ b/packages/web/src/content/docs/it/zen.mdx @@ -134,7 +134,7 @@ Supportiamo un modello pay-as-you-go. Qui sotto trovi i prezzi **per 1M token**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/ja/zen.mdx b/packages/web/src/content/docs/ja/zen.mdx index 12307d4bac..56d32f32d7 100644 --- a/packages/web/src/content/docs/ja/zen.mdx +++ b/packages/web/src/content/docs/ja/zen.mdx @@ -123,7 +123,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/ko/zen.mdx b/packages/web/src/content/docs/ko/zen.mdx index a7576b76b5..16e5a5c1d5 100644 --- a/packages/web/src/content/docs/ko/zen.mdx +++ b/packages/web/src/content/docs/ko/zen.mdx @@ -123,7 +123,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/nb/zen.mdx b/packages/web/src/content/docs/nb/zen.mdx index bd4b3950e2..52973bff10 100644 --- a/packages/web/src/content/docs/nb/zen.mdx +++ b/packages/web/src/content/docs/nb/zen.mdx @@ -134,7 +134,7 @@ Vi støtter en pay-as-you-go-modell. Nedenfor er prisene **per 1M tokens**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/pl/zen.mdx b/packages/web/src/content/docs/pl/zen.mdx index 19388b556e..278c9aa500 100644 --- a/packages/web/src/content/docs/pl/zen.mdx +++ b/packages/web/src/content/docs/pl/zen.mdx @@ -134,7 +134,7 @@ Obsługujemy model pay-as-you-go. Poniżej znajdują się ceny **za 1M tokenów* | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/pt-br/zen.mdx b/packages/web/src/content/docs/pt-br/zen.mdx index d5bd468e94..c5c205b4d4 100644 --- a/packages/web/src/content/docs/pt-br/zen.mdx +++ b/packages/web/src/content/docs/pt-br/zen.mdx @@ -123,7 +123,7 @@ Oferecemos um modelo pay-as-you-go. Abaixo estão os preços **por 1M tokens**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/ru/zen.mdx b/packages/web/src/content/docs/ru/zen.mdx index a9bd1f9500..d3ac8cee21 100644 --- a/packages/web/src/content/docs/ru/zen.mdx +++ b/packages/web/src/content/docs/ru/zen.mdx @@ -134,7 +134,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/th/zen.mdx b/packages/web/src/content/docs/th/zen.mdx index 0a6201cf25..761553ff78 100644 --- a/packages/web/src/content/docs/th/zen.mdx +++ b/packages/web/src/content/docs/th/zen.mdx @@ -125,7 +125,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/tr/zen.mdx b/packages/web/src/content/docs/tr/zen.mdx index 732783a529..f823599afc 100644 --- a/packages/web/src/content/docs/tr/zen.mdx +++ b/packages/web/src/content/docs/tr/zen.mdx @@ -123,7 +123,7 @@ Kullandıkça öde modelini destekliyoruz. Aşağıda **1M token başına** fiya | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/zen.mdx b/packages/web/src/content/docs/zen.mdx index 6147552b86..e3a435c2dd 100644 --- a/packages/web/src/content/docs/zen.mdx +++ b/packages/web/src/content/docs/zen.mdx @@ -134,7 +134,7 @@ We support a pay-as-you-go model. Below are the prices **per 1M tokens**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/zh-cn/zen.mdx b/packages/web/src/content/docs/zh-cn/zen.mdx index 52730c3031..43bfd808f8 100644 --- a/packages/web/src/content/docs/zh-cn/zen.mdx +++ b/packages/web/src/content/docs/zh-cn/zen.mdx @@ -123,7 +123,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/zh-tw/zen.mdx b/packages/web/src/content/docs/zh-tw/zen.mdx index ae62add0f1..068a723143 100644 --- a/packages/web/src/content/docs/zh-tw/zen.mdx +++ b/packages/web/src/content/docs/zh-tw/zen.mdx @@ -128,7 +128,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | From 50b869a5080d2f7e561b8b703dccaa5f4314d569 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Tue, 26 May 2026 17:40:59 +0000 Subject: [PATCH 30/40] 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 b34f76d8b1..163c77be6a 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-TOKVB2fGz/8QobMjrlAizTytCupwIRxfD4Ww1FgdC/g=", - "aarch64-linux": "sha256-FkAEvniN1Qy7scRHrc6LJLsvRkdvlGVCDS7cGn8m4fI=", - "aarch64-darwin": "sha256-fG6Ihrxnxk+FOv4yrYMZ3HfuzvjKlQVKZ00vLhCYoz8=", - "x86_64-darwin": "sha256-Sn8nWN4B0JStMnmlrt9sR7ji4RystwWdkiNgfspPxA0=" + "x86_64-linux": "sha256-FT8N4SBP7OmVu73OwNyPJvBoxFd2+IXzNnFubB8y6J0=", + "aarch64-linux": "sha256-rGst01voY1/qr/fIMEgfL2zep/+W2RhjJh5pKs+/P3s=", + "aarch64-darwin": "sha256-+oTdR3CuR88Ra3QQsDn7ixNwJf0YjOxySTSiRsPPUOg=", + "x86_64-darwin": "sha256-3ZkB83KWtp6N7u9xhzmCouv27UuisXYvr2SBap4k++E=" } } From afdae3950af4e685c5d83d6dcdbc3e4efb9dc43c Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 26 May 2026 13:41:31 -0400 Subject: [PATCH 31/40] sync --- packages/web/src/content/docs/ar/zen.mdx | 3 +-- packages/web/src/content/docs/bs/zen.mdx | 3 +-- packages/web/src/content/docs/da/zen.mdx | 3 +-- packages/web/src/content/docs/de/zen.mdx | 3 +-- packages/web/src/content/docs/es/zen.mdx | 3 +-- packages/web/src/content/docs/fr/zen.mdx | 3 +-- packages/web/src/content/docs/it/zen.mdx | 3 +-- packages/web/src/content/docs/ja/zen.mdx | 3 +-- packages/web/src/content/docs/ko/zen.mdx | 3 +-- packages/web/src/content/docs/nb/zen.mdx | 3 +-- packages/web/src/content/docs/pl/zen.mdx | 3 +-- packages/web/src/content/docs/pt-br/zen.mdx | 3 +-- packages/web/src/content/docs/ru/zen.mdx | 3 +-- packages/web/src/content/docs/th/zen.mdx | 3 +-- packages/web/src/content/docs/tr/zen.mdx | 3 +-- packages/web/src/content/docs/zen.mdx | 3 +-- packages/web/src/content/docs/zh-cn/zen.mdx | 3 +-- packages/web/src/content/docs/zh-tw/zen.mdx | 3 +-- 18 files changed, 18 insertions(+), 36 deletions(-) diff --git a/packages/web/src/content/docs/ar/zen.mdx b/packages/web/src/content/docs/ar/zen.mdx index a0d118cfb7..85d318ed4e 100644 --- a/packages/web/src/content/docs/ar/zen.mdx +++ b/packages/web/src/content/docs/ar/zen.mdx @@ -84,7 +84,6 @@ OpenCode Zen هي بوابة AI تتيح لك الوصول إلى هذه الن | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -127,7 +126,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/bs/zen.mdx b/packages/web/src/content/docs/bs/zen.mdx index 24bb7b0867..cd20ae4d8e 100644 --- a/packages/web/src/content/docs/bs/zen.mdx +++ b/packages/web/src/content/docs/bs/zen.mdx @@ -89,7 +89,6 @@ Našim modelima možete pristupiti i preko sljedećih API endpointa. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -134,7 +133,7 @@ Podržavamo pay-as-you-go model. Ispod su cijene **po 1M tokena**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/da/zen.mdx b/packages/web/src/content/docs/da/zen.mdx index 22f9c0b6f5..1d209714bf 100644 --- a/packages/web/src/content/docs/da/zen.mdx +++ b/packages/web/src/content/docs/da/zen.mdx @@ -89,7 +89,6 @@ Du kan også få adgang til vores modeller gennem følgende API-endpoints. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -134,7 +133,7 @@ Vi understøtter en pay-as-you-go-model. Nedenfor er priserne **pr. 1M tokens**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/de/zen.mdx b/packages/web/src/content/docs/de/zen.mdx index fb81083361..a0148a96f2 100644 --- a/packages/web/src/content/docs/de/zen.mdx +++ b/packages/web/src/content/docs/de/zen.mdx @@ -80,7 +80,6 @@ Du kannst auch über die folgenden API-Endpunkte auf unsere Modelle zugreifen. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -123,7 +122,7 @@ Wir unterstützen ein Pay-as-you-go-Modell. Unten findest du die Preise **pro 1M | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/es/zen.mdx b/packages/web/src/content/docs/es/zen.mdx index 2d51ccbef9..cab2bf197d 100644 --- a/packages/web/src/content/docs/es/zen.mdx +++ b/packages/web/src/content/docs/es/zen.mdx @@ -89,7 +89,6 @@ También puedes acceder a nuestros modelos a través de los siguientes endpoints | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -134,7 +133,7 @@ Admitimos un modelo de pago por uso. A continuación se muestran los precios **p | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/fr/zen.mdx b/packages/web/src/content/docs/fr/zen.mdx index 19f6b08a15..43339f7dc3 100644 --- a/packages/web/src/content/docs/fr/zen.mdx +++ b/packages/web/src/content/docs/fr/zen.mdx @@ -80,7 +80,6 @@ Vous pouvez également accéder à nos modèles via les points de terminaison AP | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -123,7 +122,7 @@ Nous prenons en charge un modèle de paiement à l'utilisation. Vous trouverez c | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/it/zen.mdx b/packages/web/src/content/docs/it/zen.mdx index 6d1aab9b85..3e20209a68 100644 --- a/packages/web/src/content/docs/it/zen.mdx +++ b/packages/web/src/content/docs/it/zen.mdx @@ -89,7 +89,6 @@ Puoi anche accedere ai nostri modelli tramite i seguenti endpoint API. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -134,7 +133,7 @@ Supportiamo un modello pay-as-you-go. Qui sotto trovi i prezzi **per 1M token**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/ja/zen.mdx b/packages/web/src/content/docs/ja/zen.mdx index 56d32f32d7..5cec8da7ef 100644 --- a/packages/web/src/content/docs/ja/zen.mdx +++ b/packages/web/src/content/docs/ja/zen.mdx @@ -80,7 +80,6 @@ OpenCode Zen は、OpenCode のほかのプロバイダーと同じように動 | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -123,7 +122,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/ko/zen.mdx b/packages/web/src/content/docs/ko/zen.mdx index 16e5a5c1d5..d3b86db62f 100644 --- a/packages/web/src/content/docs/ko/zen.mdx +++ b/packages/web/src/content/docs/ko/zen.mdx @@ -80,7 +80,6 @@ OpenCode Zen은 OpenCode의 다른 provider와 똑같이 작동합니다. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -123,7 +122,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/nb/zen.mdx b/packages/web/src/content/docs/nb/zen.mdx index 52973bff10..c18611b89b 100644 --- a/packages/web/src/content/docs/nb/zen.mdx +++ b/packages/web/src/content/docs/nb/zen.mdx @@ -89,7 +89,6 @@ Du kan også få tilgang til modellene våre gjennom følgende API-endepunkter. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -134,7 +133,7 @@ Vi støtter en pay-as-you-go-modell. Nedenfor er prisene **per 1M tokens**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/pl/zen.mdx b/packages/web/src/content/docs/pl/zen.mdx index 278c9aa500..df183dbc2b 100644 --- a/packages/web/src/content/docs/pl/zen.mdx +++ b/packages/web/src/content/docs/pl/zen.mdx @@ -89,7 +89,6 @@ Możesz też uzyskać dostęp do naszych modeli przez poniższe endpointy API. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -134,7 +133,7 @@ Obsługujemy model pay-as-you-go. Poniżej znajdują się ceny **za 1M tokenów* | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/pt-br/zen.mdx b/packages/web/src/content/docs/pt-br/zen.mdx index c5c205b4d4..b2c8db3161 100644 --- a/packages/web/src/content/docs/pt-br/zen.mdx +++ b/packages/web/src/content/docs/pt-br/zen.mdx @@ -80,7 +80,6 @@ Você também pode acessar nossos modelos pelos seguintes endpoints de API. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -123,7 +122,7 @@ Oferecemos um modelo pay-as-you-go. Abaixo estão os preços **por 1M tokens**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/ru/zen.mdx b/packages/web/src/content/docs/ru/zen.mdx index d3ac8cee21..9bdeaa7cd8 100644 --- a/packages/web/src/content/docs/ru/zen.mdx +++ b/packages/web/src/content/docs/ru/zen.mdx @@ -89,7 +89,6 @@ OpenCode Zen работает как любой другой провайдер | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -134,7 +133,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/th/zen.mdx b/packages/web/src/content/docs/th/zen.mdx index 761553ff78..c7921c58a3 100644 --- a/packages/web/src/content/docs/th/zen.mdx +++ b/packages/web/src/content/docs/th/zen.mdx @@ -82,7 +82,6 @@ OpenCode Zen ทำงานเหมือน provider อื่น ๆ ใน | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -125,7 +124,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/tr/zen.mdx b/packages/web/src/content/docs/tr/zen.mdx index f823599afc..b6737fdc75 100644 --- a/packages/web/src/content/docs/tr/zen.mdx +++ b/packages/web/src/content/docs/tr/zen.mdx @@ -80,7 +80,6 @@ Modellerimize aşağıdaki API uç noktaları aracılığıyla da erişebilirsin | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -123,7 +122,7 @@ Kullandıkça öde modelini destekliyoruz. Aşağıda **1M token başına** fiya | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/zen.mdx b/packages/web/src/content/docs/zen.mdx index e3a435c2dd..1f7df7e603 100644 --- a/packages/web/src/content/docs/zen.mdx +++ b/packages/web/src/content/docs/zen.mdx @@ -89,7 +89,6 @@ You can also access our models through the following API endpoints. | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -134,7 +133,7 @@ We support a pay-as-you-go model. Below are the prices **per 1M tokens**. | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/zh-cn/zen.mdx b/packages/web/src/content/docs/zh-cn/zen.mdx index 43bfd808f8..28db9f3be8 100644 --- a/packages/web/src/content/docs/zh-cn/zen.mdx +++ b/packages/web/src/content/docs/zh-cn/zen.mdx @@ -80,7 +80,6 @@ OpenCode Zen 的工作方式与 OpenCode 中的任何其他提供商相同。 | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -123,7 +122,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | diff --git a/packages/web/src/content/docs/zh-tw/zen.mdx b/packages/web/src/content/docs/zh-tw/zen.mdx index 068a723143..546126c17f 100644 --- a/packages/web/src/content/docs/zh-tw/zen.mdx +++ b/packages/web/src/content/docs/zh-tw/zen.mdx @@ -84,7 +84,6 @@ OpenCode Zen 的運作方式和 OpenCode 中的其他供應商一樣。 | Gemini 3.5 Flash | gemini-3.5-flash | `https://opencode.ai/zen/v1/models/gemini-3.5-flash` | `@ai-sdk/google` | | 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.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.6 Plus | qwen3.6-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Qwen3.5 Plus | qwen3.5-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -128,7 +127,7 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2.6 | $0.95 | $4.00 | $0.16 | - | -| Qwen3.7 Max | $1.65 | $4.951 | $0.165 | $2.063 | +| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 | | Qwen3.6 Plus | $0.50 | $3.00 | $0.05 | $0.625 | | Qwen3.5 Plus | $0.20 | $1.20 | $0.02 | $0.25 | | Grok Build 0.1 | 1.00 | $2.00 | $0.20 | - | From 5f31d2ca88916011636fbcc5039a682390a5e792 Mon Sep 17 00:00:00 2001 From: Dustin Deus Date: Tue, 26 May 2026 19:59:51 +0200 Subject: [PATCH 32/40] docs(web): update LSP docs wording (#29435) Co-authored-by: starptech --- packages/web/src/content/docs/ar/lsp.mdx | 29 +++++++++++++++++---- packages/web/src/content/docs/bs/lsp.mdx | 29 +++++++++++++++++---- packages/web/src/content/docs/da/lsp.mdx | 29 +++++++++++++++++---- packages/web/src/content/docs/de/lsp.mdx | 29 +++++++++++++++++---- packages/web/src/content/docs/es/lsp.mdx | 29 +++++++++++++++++---- packages/web/src/content/docs/fr/lsp.mdx | 29 +++++++++++++++++---- packages/web/src/content/docs/it/lsp.mdx | 29 +++++++++++++++++---- packages/web/src/content/docs/ja/lsp.mdx | 29 +++++++++++++++++---- packages/web/src/content/docs/ko/lsp.mdx | 29 +++++++++++++++++---- packages/web/src/content/docs/lsp.mdx | 12 +++++++-- packages/web/src/content/docs/nb/lsp.mdx | 29 +++++++++++++++++---- packages/web/src/content/docs/pl/lsp.mdx | 29 +++++++++++++++++---- packages/web/src/content/docs/pt-br/lsp.mdx | 29 +++++++++++++++++---- packages/web/src/content/docs/ru/lsp.mdx | 29 +++++++++++++++++---- packages/web/src/content/docs/th/lsp.mdx | 29 +++++++++++++++++---- packages/web/src/content/docs/tr/lsp.mdx | 29 +++++++++++++++++---- packages/web/src/content/docs/zh-cn/lsp.mdx | 29 +++++++++++++++++---- packages/web/src/content/docs/zh-tw/lsp.mdx | 29 +++++++++++++++++---- 18 files changed, 418 insertions(+), 87 deletions(-) diff --git a/packages/web/src/content/docs/ar/lsp.mdx b/packages/web/src/content/docs/ar/lsp.mdx index fd1b455340..a33a457c8b 100644 --- a/packages/web/src/content/docs/ar/lsp.mdx +++ b/packages/web/src/content/docs/ar/lsp.mdx @@ -3,7 +3,7 @@ title: خوادم LSP description: يتكامل OpenCode مع خوادم LSP لديك. --- -يتكامل OpenCode مع بروتوكول خادم اللغة (LSP) لمساعدة LLM على التفاعل مع قاعدة الشيفرة لديك. ويستخدم التشخيصات لتزويد LLM بتغذية راجعة. +يمكن أن يتكامل OpenCode مع خوادم Language Server Protocol (LSP) لاستخدام التشخيصات كملاحظات للوكيل. --- @@ -46,7 +46,7 @@ description: يتكامل OpenCode مع خوادم LSP لديك. | yaml-ls | .yaml, .yml | يثبت `yaml-language-server` من Red Hat تلقائيا | | zls | .zig, .zon | توفر أمر `zig` | -تُفعَّل خوادم LSP تلقائيا عند اكتشاف أحد امتدادات الملفات المذكورة أعلاه واستيفاء المتطلبات. +تكون ميزة LSP معطلة افتراضيا. عند تفعيلها، تبدأ الخوادم عند اكتشاف أحد امتدادات الملفات المذكورة أعلاه واستيفاء المتطلبات. :::note يمكنك تعطيل تنزيلات خوادم LSP التلقائية عبر ضبط متغير البيئة `OPENCODE_DISABLE_LSP_DOWNLOAD` على `true`. @@ -56,16 +56,35 @@ description: يتكامل OpenCode مع خوادم LSP لديك. ## كيف يعمل -عندما يفتح opencode ملفا، فإنه: +عند تفعيل LSP وفتح opencode لملف، فإنه: 1. يفحص امتداد الملف مقابل جميع خوادم LSP المفعّلة. 2. يشغّل خادم LSP المناسب إذا لم يكن قيد التشغيل بالفعل. --- +## أفضل الممارسات + +يمكن أن تساعد LSP الوكيل على العثور على المشاكل وإصلاحها عبر توفير التشخيصات من خوادم اللغة. هذا مفيد في بعض المشاريع، لكنه ليس دائما مكسبا صافيا. + +قد تخرج خوادم اللغة عن المزامنة، وتستهلك ذاكرة كبيرة، وتختلف حسب الإصدار أو المشروع، وتبطئ سير عمل الوكيل. في كثير من المشاريع، يكون من الأفضل أن يشغّل الوكيل lint أو typecheck أو أدوات CLI التشخيصية الأخرى مباشرة، بحيث تعود الأخطاء إلى حلقة الوكيل دون هذه المفاضلات. فعّل LSP عندما يستفيد مشروعك من ملاحظات إضافية من خادم اللغة. + +--- + ## الإعداد -يمكنك تخصيص خوادم LSP عبر قسم `lsp` في إعدادات opencode. +يمكنك تفعيل خوادم LSP وتخصيصها عبر قسم `lsp` في إعدادات opencode. + +لتفعيل جميع خوادم LSP المدمجة، اضبط `lsp` على `true`. + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +استخدم كائنا لإبقاء الخوادم المدمجة مفعلة أثناء إعداد التجاوزات أو الخوادم المخصصة. ```json title="opencode.json" { @@ -134,7 +153,7 @@ description: يتكامل OpenCode مع خوادم LSP لديك. ### تعطيل خوادم LSP -لتعطيل **جميع** خوادم LSP على مستوى التطبيق، اضبط `lsp` على `false`: +إذا تم حذف `lsp`، فستكون جميع خوادم LSP معطلة. لتعطيل جميع خوادم LSP بعد أن فعّلها إعداد آخر، اضبط `lsp` على `false`: ```json title="opencode.json" {3} { diff --git a/packages/web/src/content/docs/bs/lsp.mdx b/packages/web/src/content/docs/bs/lsp.mdx index 8f52f3bf61..fb8d06b24a 100644 --- a/packages/web/src/content/docs/bs/lsp.mdx +++ b/packages/web/src/content/docs/bs/lsp.mdx @@ -3,7 +3,7 @@ title: LSP serveri description: OpenCode se integriše sa vašim LSP serverima. --- -OpenCode se integriše sa vašim Language Server Protocol (LSP) serverima kako bi pomogao LLM-u u interakciji s kodnom bazom. Koristi dijagnostiku za slanje povratnih informacija modelu. +OpenCode se može integrisati sa Language Server Protocol (LSP) serverima kako bi koristio dijagnostiku kao feedback za agenta. ## Ugrađeni @@ -45,7 +45,7 @@ OpenCode dolazi sa nekoliko ugrađenih LSP servera za popularne jezike: | yaml-ls | .yaml, .yml | Automatski instalira Red Hat yaml-language-server | | zls | .zig, .zon | `zig` komanda dostupna | -LSP serveri su automatski omogućeni kada se otkrije jedna od gore navedenih ekstenzija datoteke i zahtjevi su ispunjeni. +LSP je podrazumijevano isključen. Kada je omogućen, serveri se pokreću kada se otkrije jedna od gore navedenih ekstenzija datoteke i zahtjevi su ispunjeni. :::note Možete onemogućiti automatska preuzimanja LSP servera tako što ćete postaviti varijablu okruženja `OPENCODE_DISABLE_LSP_DOWNLOAD` na `true`. ::: @@ -54,16 +54,35 @@ Možete onemogućiti automatska preuzimanja LSP servera tako što ćete postavit ## Kako radi -Kada opencode otvori fajl, on: +Kada je LSP omogućen i opencode otvori fajl, on: 1. Provjerava ekstenziju datoteke u odnosu na sve omogućene LSP servere. 2. Pokreće odgovarajući LSP server ako već nije pokrenut. --- +## Najbolje prakse + +LSP može pomoći agentu da pronađe i popravi probleme pružanjem dijagnostike iz jezičkih servera. Ovo je korisno u nekim projektima, ali nije uvijek neto pozitivno. + +Jezički serveri mogu ispasti iz sinhronizacije, koristiti mnogo memorije, razlikovati se po verziji ili projektu i usporiti agent workflow. U mnogim projektima je bolje da agent direktno pokreće lint, typecheck ili druge dijagnostičke CLI alate, tako da se greške vraćaju u agent loop bez tih kompromisa. Uključite LSP kada vaš projekt ima koristi od dodatnog feedbacka jezičkog servera. + +--- + ## Konfiguracija -Možete prilagoditi LSP servere kroz `lsp` odjeljak u vašoj opencode konfiguraciji. +Možete omogućiti i prilagoditi LSP servere kroz `lsp` odjeljak u vašoj opencode konfiguraciji. + +Da biste omogućili sve ugrađene LSP servere, postavite `lsp` na `true`. + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +Koristite objekt da zadržite ugrađene servere omogućene dok konfigurirate izmjene ili prilagođene servere. ```json title="opencode.json" { @@ -132,7 +151,7 @@ Opcije inicijalizacije razlikuju se od LSP servera. Provjerite dokumentaciju va ### Onemogućavanje LSP servera -Da biste onemogućili **sve** LSP servere globalno, postavite `lsp` na `false`: +Ako je `lsp` izostavljen, svi LSP serveri su onemogućeni. Da biste onemogućili sve LSP servere nakon što ih je druga konfiguracija omogućila, postavite `lsp` na `false`: ```json title="opencode.json" {3} { diff --git a/packages/web/src/content/docs/da/lsp.mdx b/packages/web/src/content/docs/da/lsp.mdx index 27d43b192b..3ba3eeb5ef 100644 --- a/packages/web/src/content/docs/da/lsp.mdx +++ b/packages/web/src/content/docs/da/lsp.mdx @@ -3,7 +3,7 @@ title: LSP-servere description: OpenCode integreres med dine LSP-servere. --- -OpenCode integreres med Language Server Protocol (LSP) for at hjælpe LLM med at interagere med din kodebase. Den bruger diagnostik til at give feedback til LLM. +OpenCode kan integreres med Language Server Protocol (LSP)-servere for at bruge diagnostik som feedback til agenten. --- @@ -47,7 +47,7 @@ OpenCode leveres med flere indbyggede LSP-servere til populære sprog: | yaml-ls | .yaml,.yml | Autoinstallerer Red Hat yaml-language-server | | zls | .zig,.zon | `zig` kommando tilgængelig | -LSP-servere aktiveres automatisk, når en af ​​ovenstående filtypenavne opdages, og kravene er opfyldt. +LSP er deaktiveret som standard. Når det er aktiveret, starter servere, når en af ovenstående filtypenavne opdages, og kravene er opfyldt. :::note Du kan deaktivere automatisk LSP-serverdownloads ved at indstille miljøvariablen `OPENCODE_DISABLE_LSP_DOWNLOAD` til `true`. @@ -57,16 +57,35 @@ Du kan deaktivere automatisk LSP-serverdownloads ved at indstille miljøvariable ## Sådan fungerer det -Når opencode åbner en fil, vil den: +Når LSP er aktiveret, og opencode åbner en fil, vil den: 1. Kontrollerer filtypenavnet mod alle aktiverede LSP-servere. 2. Starter den relevante LSP-server, hvis den ikke allerede kører. --- +## Bedste praksis + +LSP kan hjælpe agenten med at finde og rette problemer ved at levere diagnostik fra sprogservere. Det er nyttigt i nogle projekter, men er ikke altid en klar fordel. + +Sprogservere kan komme ud af sync, bruge meget hukommelse, variere efter version eller projekt og gøre agentarbejdsgange langsommere. I mange projekter er det bedre, at agenten kører lint, typecheck eller andre diagnostiske CLI-værktøjer direkte, så fejl føres tilbage i agentens loop uden disse afvejninger. Aktivér LSP, når dit projekt har gavn af ekstra sprogserverfeedback. + +--- + ## Konfiguration -Du kan tilpasse LSP-servere gennem sektionen `lsp` i din opencode-konfiguration. +Du kan aktivere og tilpasse LSP-servere gennem sektionen `lsp` i din opencode-konfiguration. + +For at aktivere alle indbyggede LSP-servere skal du indstille `lsp` til `true`. + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +Brug et objekt til at holde indbyggede servere aktiveret, mens du konfigurerer tilsidesættelser eller brugerdefinerede servere. ```json title="opencode.json" { @@ -135,7 +154,7 @@ Initialiseringsmuligheder forskellige afhængige af LSP-serveren. Se din LSP-ser ### Deaktivering af LSP-servere -For at deaktivere **alle** LSP-servere globalt, skal du indstille `lsp` til `false`: +Hvis `lsp` udelades, er alle LSP-servere deaktiveret. For at deaktivere alle LSP-servere efter at en anden konfiguration har aktiveret dem, skal du indstille `lsp` til `false`: ```json title="opencode.json" {3} { diff --git a/packages/web/src/content/docs/de/lsp.mdx b/packages/web/src/content/docs/de/lsp.mdx index 60f8316c6b..154aeaa060 100644 --- a/packages/web/src/content/docs/de/lsp.mdx +++ b/packages/web/src/content/docs/de/lsp.mdx @@ -3,7 +3,7 @@ title: LSP Server description: OpenCode lässt sich in Ihren LSP-Server integrieren. --- -OpenCode lässt sich in Ihr Language Server Protocol (LSP) integrieren, um die Interaktion von LLM mit Ihrer Codebasis zu unterstützen. Es verwendet Diagnosefunktionen, um dem LLM Feedback zu geben. +OpenCode kann sich in Language Server Protocol (LSP)-Server integrieren, um Diagnosen als Feedback für den Agenten zu verwenden. --- @@ -46,7 +46,7 @@ OpenCode verfügt über mehrere integrierte LSP-Server für gängige Sprachen: | yaml-ls | .yaml, .yml | Installiert den Red Hat yaml-language-server automatisch | | zls | .zig, .zon | `zig`-Befehl verfügbar | -LSP-Server werden automatisch aktiviert, wenn eine der oben genannten Dateierweiterungen erkannt wird und die Anforderungen erfüllt sind. +LSP ist standardmäßig deaktiviert. Wenn es aktiviert ist, starten Server, sobald eine der oben genannten Dateierweiterungen erkannt wird und die Anforderungen erfüllt sind. :::note Sie können LSP-Server-Downloads automatisch deaktivieren, indem Sie die Umgebungsvariable `OPENCODE_DISABLE_LSP_DOWNLOAD` auf `true` setzen. @@ -56,16 +56,35 @@ Sie können LSP-Server-Downloads automatisch deaktivieren, indem Sie die Umgebun ## Funktionsweise -Wenn OpenCode eine Datei öffnet, geschieht Folgendes: +Wenn LSP aktiviert ist und OpenCode eine Datei öffnet, geschieht Folgendes: 1. Überprüft die Dateierweiterung anhand aller aktivierten LSP-Server. 2. Startet den entsprechenden LSP-Server, falls er noch nicht ausgeführt wird. --- +## Bewährte Praktiken + +LSP kann dem Agenten helfen, Probleme zu finden und zu beheben, indem es Diagnosen von Sprachservern bereitstellt. Das ist in einigen Projekten nützlich, aber nicht immer ein klarer Vorteil. + +Sprachserver können aus dem Sync geraten, viel Speicher verwenden, je nach Version oder Projekt unterschiedlich arbeiten und Agent-Workflows verlangsamen. In vielen Projekten ist es besser, wenn der Agent lint, typecheck oder andere diagnostische CLI-Tools direkt ausführt, damit Fehler in die Agent-Schleife zurückfließen, ohne diese Kompromisse einzugehen. Aktivieren Sie LSP, wenn Ihr Projekt von zusätzlichem Sprachserver-Feedback profitiert. + +--- + ## Konfiguration -Sie können LSP-Server über den Abschnitt `lsp` in Ihrer OpenCode-Konfiguration anpassen. +Sie können LSP-Server über den Abschnitt `lsp` in Ihrer OpenCode-Konfiguration aktivieren und anpassen. + +Um alle integrierten LSP-Server zu aktivieren, setzen Sie `lsp` auf `true`. + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +Verwenden Sie ein Objekt, um integrierte Server aktiviert zu lassen und gleichzeitig Überschreibungen oder benutzerdefinierte Server zu konfigurieren. ```json title="opencode.json" { @@ -134,7 +153,7 @@ Die Initialisierungsoptionen variieren je nach LSP-Server. Überprüfen Sie die ### Deaktivieren von LSP-Servern -Um **alle** LSP-Server global zu deaktivieren, setzen Sie `lsp` auf `false`: +Wenn `lsp` ausgelassen wird, sind alle LSP-Server deaktiviert. Um alle LSP-Server zu deaktivieren, nachdem sie durch eine andere Konfiguration aktiviert wurden, setzen Sie `lsp` auf `false`: ```json title="opencode.json" {3} { diff --git a/packages/web/src/content/docs/es/lsp.mdx b/packages/web/src/content/docs/es/lsp.mdx index 27eab4cadf..a1ede5a085 100644 --- a/packages/web/src/content/docs/es/lsp.mdx +++ b/packages/web/src/content/docs/es/lsp.mdx @@ -3,7 +3,7 @@ title: Servidores LSP description: OpenCode se integra con sus servidores LSP. --- -OpenCode se integra con su protocolo de servidor de idiomas (LSP) para ayudar a LLM a interactuar con su código base. Utiliza diagnósticos para proporcionar retroalimentación al LLM. +OpenCode puede integrarse con servidores Language Server Protocol (LSP) para usar diagnósticos como feedback para el agente. --- @@ -47,7 +47,7 @@ OpenCode viene con varios servidores LSP integrados para idiomas populares: | yaml-ls | .yaml, .yml | Autoinstala Red Hat yaml-language-server | | zls | .zig, .zon | Comando `zig` disponible | -Los servidores LSP se habilitan automáticamente cuando se detecta una de las extensiones de archivo anteriores y se cumplen los requisitos. +LSP está deshabilitado por defecto. Cuando está habilitado, los servidores se inician cuando se detecta una de las extensiones de archivo anteriores y se cumplen los requisitos. :::note Puede deshabilitar las descargas automáticas del servidor LSP configurando la variable de entorno `OPENCODE_DISABLE_LSP_DOWNLOAD` en `true`. @@ -57,16 +57,35 @@ Puede deshabilitar las descargas automáticas del servidor LSP configurando la v ## Cómo funciona -Cuando opencode abre un archivo: +Cuando LSP está habilitado y opencode abre un archivo: 1. Comprueba la extensión del archivo con todos los servidores LSP habilitados. 2. Inicia el servidor LSP apropiado si aún no se está ejecutando. --- +## Buenas prácticas + +LSP puede ayudar al agente a encontrar y corregir problemas proporcionando diagnósticos de los servidores de lenguaje. Esto es útil en algunos proyectos, pero no siempre es una mejora neta. + +Los servidores de lenguaje pueden desincronizarse, usar bastante memoria, variar según la versión o el proyecto y ralentizar los flujos de trabajo del agente. En muchos proyectos es mejor hacer que el agente ejecute lint, typecheck u otras herramientas CLI de diagnóstico directamente, para que los errores vuelvan al ciclo del agente sin esas compensaciones. Habilita LSP cuando tu proyecto se beneficie de feedback adicional del servidor de lenguaje. + +--- + ## Configuración -Puede personalizar los servidores LSP a través de la sección `lsp` en su configuración opencode. +Puede habilitar y personalizar los servidores LSP a través de la sección `lsp` en su configuración opencode. + +Para habilitar todos los servidores LSP integrados, configure `lsp` como `true`. + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +Use un objeto para mantener habilitados los servidores integrados mientras configura anulaciones o servidores personalizados. ```json title="opencode.json" { @@ -135,7 +154,7 @@ Las opciones de inicialización varían según el servidor LSP. Consulte la docu ### Deshabilitar servidores LSP -Para deshabilitar **todos** los servidores LSP globalmente, configure `lsp` en `false`: +Si se omite `lsp`, todos los servidores LSP están deshabilitados. Para deshabilitar todos los servidores LSP después de que otra configuración los haya habilitado, configure `lsp` en `false`: ```json title="opencode.json" {3} { diff --git a/packages/web/src/content/docs/fr/lsp.mdx b/packages/web/src/content/docs/fr/lsp.mdx index 8a83370da0..1401f0ab7d 100644 --- a/packages/web/src/content/docs/fr/lsp.mdx +++ b/packages/web/src/content/docs/fr/lsp.mdx @@ -3,7 +3,7 @@ title: Serveurs LSP description: OpenCode s'intègre à vos serveurs LSP. --- -OpenCode s'intègre via le protocole LSP (Language Server Protocol) pour aider le LLM à interagir avec votre base de code. Il utilise des diagnostics pour fournir des commentaires au LLM. +OpenCode peut s'intégrer aux serveurs Language Server Protocol (LSP) pour utiliser les diagnostics comme retour pour l'agent. --- @@ -47,7 +47,7 @@ OpenCode est livré avec plusieurs serveurs LSP intégrés pour les langages pop | yaml-ls | .yaml, .yml | Installe automatiquement le serveur yaml-language-server de Red Hat | | zls | .zig, .zon | Commande `zig` disponible | -Les serveurs LSP sont automatiquement activés lorsque l'une des extensions de fichier ci-dessus est détectée et que les exigences sont remplies. +LSP est désactivé par défaut. Lorsqu'il est activé, les serveurs démarrent lorsqu'une des extensions de fichier ci-dessus est détectée et que les exigences sont remplies. :::note Vous pouvez désactiver les téléchargements automatiques du serveur LSP en définissant la variable d'environnement `OPENCODE_DISABLE_LSP_DOWNLOAD` sur `true`. @@ -57,16 +57,35 @@ Vous pouvez désactiver les téléchargements automatiques du serveur LSP en dé ## Comment ça marche -Lorsque opencode ouvre un fichier, il : +Lorsque LSP est activé et qu'opencode ouvre un fichier, il : 1. Vérifie l'extension du fichier par rapport à tous les serveurs LSP activés. 2. Démarre le serveur LSP approprié s'il n'est pas déjà en cours d'exécution. --- +## Bonnes pratiques + +LSP peut aider l'agent à trouver et corriger des problèmes en fournissant les diagnostics des serveurs de langage. C'est utile dans certains projets, mais ce n'est pas toujours un gain net. + +Les serveurs de langage peuvent se désynchroniser, consommer beaucoup de mémoire, varier selon la version ou le projet, et ralentir les flux de travail de l'agent. Dans de nombreux projets, il est préférable de faire exécuter directement par l'agent le lint, le typecheck ou d'autres outils CLI de diagnostic, afin que les erreurs reviennent dans la boucle de l'agent sans ces compromis. Activez LSP lorsque votre projet bénéficie d'un retour supplémentaire des serveurs de langage. + +--- + ## Configuration -Vous pouvez personnaliser les serveurs LSP via la section `lsp` de votre configuration opencode. +Vous pouvez activer et personnaliser les serveurs LSP via la section `lsp` de votre configuration opencode. + +Pour activer tous les serveurs LSP intégrés, définissez `lsp` sur `true`. + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +Utilisez un objet pour conserver les serveurs intégrés activés tout en configurant des remplacements ou des serveurs personnalisés. ```json title="opencode.json" { @@ -135,7 +154,7 @@ Les options d'initialisation varient selon le serveur LSP. Consultez la document ### Désactivation des serveurs LSP -Pour désactiver **tous** les serveurs LSP globalement, définissez `lsp` sur `false` : +Si `lsp` est omis, tous les serveurs LSP sont désactivés. Pour désactiver tous les serveurs LSP après qu'une autre configuration les a activés, définissez `lsp` sur `false` : ```json title="opencode.json" {3} { diff --git a/packages/web/src/content/docs/it/lsp.mdx b/packages/web/src/content/docs/it/lsp.mdx index a21133b141..705410aae2 100644 --- a/packages/web/src/content/docs/it/lsp.mdx +++ b/packages/web/src/content/docs/it/lsp.mdx @@ -3,7 +3,7 @@ title: Server LSP description: OpenCode si integra con i tuoi server LSP. --- -OpenCode si integra con il tuo Language Server Protocol (LSP) per aiutare l'LLM a interagire con la tua codebase. Usa le diagnostiche per fornire feedback all'LLM. +OpenCode può integrarsi con server Language Server Protocol (LSP) per usare la diagnostica come feedback per l'agente. --- @@ -47,7 +47,7 @@ OpenCode include diversi server LSP integrati per linguaggi popolari: | yaml-ls | .yaml, .yml | Installazione automatica di Red Hat yaml-language-server | | zls | .zig, .zon | comando `zig` disponibile | -I server LSP vengono abilitati automaticamente quando viene rilevata una delle estensioni qui sopra e i requisiti sono soddisfatti. +LSP è disabilitato per impostazione predefinita. Quando è abilitato, i server si avviano quando viene rilevata una delle estensioni qui sopra e i requisiti sono soddisfatti. :::note Puoi disabilitare il download automatico dei server LSP impostando la variabile d'ambiente `OPENCODE_DISABLE_LSP_DOWNLOAD` a `true`. @@ -57,16 +57,35 @@ Puoi disabilitare il download automatico dei server LSP impostando la variabile ## Come funziona -Quando opencode apre un file: +Quando LSP è abilitato e opencode apre un file: 1. Controlla l'estensione del file rispetto a tutti i server LSP abilitati. 2. Avvia il server LSP appropriato se non e gia in esecuzione. --- +## Buone pratiche + +LSP può aiutare l'agente a trovare e correggere problemi fornendo diagnostica dai server di linguaggio. Questo è utile in alcuni progetti, ma non è sempre un vantaggio netto. + +I server di linguaggio possono andare fuori sincronizzazione, usare molta memoria, variare in base alla versione o al progetto e rallentare i workflow dell'agente. In molti progetti è meglio far eseguire direttamente all'agente lint, typecheck o altri strumenti CLI diagnostici, così gli errori rientrano nel ciclo dell'agente senza questi compromessi. Abilita LSP quando il tuo progetto trae beneficio da feedback aggiuntivo del server di linguaggio. + +--- + ## Configura -Puoi personalizzare i server LSP tramite la sezione `lsp` nella configurazione di opencode. +Puoi abilitare e personalizzare i server LSP tramite la sezione `lsp` nella configurazione di opencode. + +Per abilitare tutti i server LSP integrati, imposta `lsp` a `true`. + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +Usa un oggetto per mantenere abilitati i server integrati mentre configuri override o server personalizzati. ```json title="opencode.json" { @@ -135,7 +154,7 @@ Le opzioni di inizializzazione variano da server a server. Consulta la documenta ### Disabilitare i server LSP -Per disabilitare **tutti** i server LSP globalmente, imposta `lsp` a `false`: +Se `lsp` è omesso, tutti i server LSP sono disabilitati. Per disabilitare tutti i server LSP dopo che un'altra configurazione li ha abilitati, imposta `lsp` a `false`: ```json title="opencode.json" {3} { diff --git a/packages/web/src/content/docs/ja/lsp.mdx b/packages/web/src/content/docs/ja/lsp.mdx index 948e743503..82ec96e18e 100644 --- a/packages/web/src/content/docs/ja/lsp.mdx +++ b/packages/web/src/content/docs/ja/lsp.mdx @@ -3,7 +3,7 @@ title: LSPサーバー description: OpenCode は LSP サーバーと統合します。 --- -OpenCode は言語サーバープロトコル (LSP) と統合して、LLM がコードベースと対話できるようにします。診断を使用して LLM にフィードバックを提供します。 +OpenCode は Language Server Protocol (LSP) サーバーと統合し、診断を agent へのフィードバックとして使用できます。 --- @@ -47,7 +47,7 @@ OpenCode には、一般的な言語用のいくつかの組み込み LSP サー | yaml-ls | .yaml, .yml | Auto-installs Red Hat yaml-language-server | | zls | .zig, .zon | `zig` command available | -上記のファイル拡張子のいずれかが検出され、要件が満たされると、LSP サーバーは自動的に有効になります。 +LSP はデフォルトで無効です。有効にすると、上記のファイル拡張子のいずれかが検出され、要件が満たされた場合にサーバーが起動します。 :::note `OPENCODE_DISABLE_LSP_DOWNLOAD` 環境変数を `true` に設定すると、LSP サーバーの自動ダウンロードを無効にできます。 @@ -57,16 +57,35 @@ OpenCode には、一般的な言語用のいくつかの組み込み LSP サー ## 仕組み -OpenCode がファイルを開くと、次のようになります。 +LSP が有効で OpenCode がファイルを開くと、次のようになります。 1. 有効なすべての LSP サーバーに対してファイル拡張子をチェックします。 2. 適切な LSP サーバーがまだ実行されていない場合は開始します。 --- +## ベストプラクティス + +LSP は、言語サーバーの診断を提供することで、agent が問題を見つけて修正する助けになります。これは一部のプロジェクトで有用ですが、常に明確な利点になるとは限りません。 + +言語サーバーは同期が外れたり、多くのメモリを使用したり、バージョンやプロジェクトによって挙動が変わったり、agent のワークフローを遅くすることがあります。多くのプロジェクトでは、agent に lint、typecheck、その他の診断用 CLI ツールを直接実行させる方が適しています。これにより、これらのトレードオフを避けながら、エラーを agent のループに戻せます。追加の言語サーバーフィードバックが有効な場合に LSP を有効にしてください。 + +--- + ## 設定 -OpenCode 設定の `lsp` セクションを通じて LSP サーバーをカスタマイズできます。 +OpenCode 設定の `lsp` セクションを通じて LSP サーバーを有効化し、カスタマイズできます。 + +すべての組み込み LSP サーバーを有効にするには、`lsp` を `true` に設定します。 + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +オブジェクトを使用すると、組み込みサーバーを有効にしたまま、上書き設定やカスタムサーバーを設定できます。 ```json title="opencode.json" { @@ -135,7 +154,7 @@ LSP サーバーの起動時に `env` プロパティを使用して環境変数 ### LSPサーバーの無効化 -**すべて** LSP サーバーをグローバルに無効にするには、`lsp` を `false` に設定します。 +`lsp` を省略すると、すべての LSP サーバーは無効になります。別の設定で有効化されたすべての LSP サーバーを無効にするには、`lsp` を `false` に設定します。 ```json title="opencode.json" {3} { diff --git a/packages/web/src/content/docs/ko/lsp.mdx b/packages/web/src/content/docs/ko/lsp.mdx index c1786f6aef..d6053238b4 100644 --- a/packages/web/src/content/docs/ko/lsp.mdx +++ b/packages/web/src/content/docs/ko/lsp.mdx @@ -3,7 +3,7 @@ title: LSP 서버 description: OpenCode는 LSP 서버와 통합됩니다. --- -OpenCode는 Language Server Protocol(LSP)과 통합되어 LLM이 코드베이스와 상호작용하도록 돕습니다. 진단 정보를 활용해 LLM에 피드백을 제공합니다. +OpenCode는 Language Server Protocol(LSP) 서버와 통합해 진단 정보를 agent의 피드백으로 사용할 수 있습니다. --- @@ -47,7 +47,7 @@ OpenCode는 널리 사용되는 언어를 위해 여러 built-in LSP 서버를 | yaml-ls | .yaml, .yml | Red Hat `yaml-language-server` 자동 설치 | | zls | .zig, .zon | `zig` 명령 사용 가능 | -위 확장자 중 하나가 감지되고 요구 사항이 충족되면 LSP 서버가 자동으로 활성화됩니다. +LSP는 기본적으로 비활성화되어 있습니다. 활성화하면 위 확장자 중 하나가 감지되고 요구 사항이 충족될 때 서버가 시작됩니다. :::note `OPENCODE_DISABLE_LSP_DOWNLOAD` 환경 변수를 `true`로 설정하면 LSP 서버 자동 다운로드를 비활성화할 수 있습니다. @@ -57,16 +57,35 @@ OpenCode는 널리 사용되는 언어를 위해 여러 built-in LSP 서버를 ## 작동 방식 -OpenCode가 파일을 열면 다음과 같이 동작합니다. +LSP가 활성화되어 있고 OpenCode가 파일을 열면 다음과 같이 동작합니다. 1. 활성화된 모든 LSP 서버에 대해 파일 확장자를 확인합니다. 2. 적절한 LSP 서버가 아직 실행 중이지 않다면 시작합니다. --- +## 모범 사례 + +LSP는 언어 서버의 진단을 제공해 agent가 문제를 찾고 수정하는 데 도움을 줄 수 있습니다. 일부 프로젝트에서는 유용하지만 항상 순이익이 되는 것은 아닙니다. + +언어 서버는 동기화가 어긋나거나 많은 메모리를 사용하거나 버전 또는 프로젝트에 따라 다르게 동작하고 agent 워크플로를 느리게 만들 수 있습니다. 많은 프로젝트에서는 agent가 lint, typecheck 또는 다른 진단용 CLI 도구를 직접 실행하게 하는 편이 더 좋습니다. 이렇게 하면 이러한 트레이드오프 없이 오류가 agent 루프로 다시 전달됩니다. 프로젝트가 추가 언어 서버 피드백의 이점을 얻을 때 LSP를 활성화하세요. + +--- + ## 구성 -OpenCode config의 `lsp` 섹션에서 LSP 서버를 사용자 정의할 수 있습니다. +OpenCode config의 `lsp` 섹션에서 LSP 서버를 활성화하고 사용자 정의할 수 있습니다. + +모든 내장 LSP 서버를 활성화하려면 `lsp`를 `true`로 설정하세요. + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +객체를 사용하면 내장 서버를 활성화한 상태로 유지하면서 오버라이드나 사용자 정의 서버를 구성할 수 있습니다. ```json title="opencode.json" { @@ -135,7 +154,7 @@ OpenCode config의 `lsp` 섹션에서 LSP 서버를 사용자 정의할 수 있 ### LSP 서버 비활성화 -전역에서 **모든** LSP 서버를 비활성화하려면 `lsp`를 `false`로 설정하세요. +`lsp`를 생략하면 모든 LSP 서버가 비활성화됩니다. 다른 config에서 활성화한 모든 LSP 서버를 비활성화하려면 `lsp`를 `false`로 설정하세요. ```json title="opencode.json" {3} { diff --git a/packages/web/src/content/docs/lsp.mdx b/packages/web/src/content/docs/lsp.mdx index 5854fe1f1a..25f88170f5 100644 --- a/packages/web/src/content/docs/lsp.mdx +++ b/packages/web/src/content/docs/lsp.mdx @@ -3,7 +3,7 @@ title: LSP Servers description: OpenCode integrates with your LSP servers. --- -OpenCode can integrate with your Language Server Protocol (LSP) to help the LLM interact with your codebase. It uses diagnostics to provide feedback to the LLM. +OpenCode can integrate with Language Server Protocol (LSP) servers to use diagnostics as feedback for the agent. --- @@ -48,7 +48,7 @@ OpenCode comes with several built-in LSP servers for popular languages: | yaml-ls | .yaml, .yml | Auto-installs Red Hat yaml-language-server | | zls | .zig, .zon | `zig` command available | -When LSP is enabled, servers start when one of the above file extensions is detected and the requirements are met. +LSP is disabled by default. When enabled, servers start when one of the above file extensions is detected and the requirements are met. :::note You can disable automatic LSP server downloads by setting the `OPENCODE_DISABLE_LSP_DOWNLOAD` environment variable to `true`. @@ -65,6 +65,14 @@ When LSP is enabled and opencode opens a file, it: --- +## Best Practices + +LSP can help the agent find and fix issues by providing diagnostics from language servers. This is useful in some projects, but it is not always a net positive. + +Language servers can get out of sync, use significant memory, vary by version or project, and slow down agent workflows. In many projects it is better to have the agent run lint, typecheck, or other diagnostic CLI tools directly, so errors are fed back into the agent loop without those tradeoffs. Enable LSP when your project benefits from additional language-server feedback. + +--- + ## Configure You can enable and customize LSP servers through the `lsp` section in your opencode config. diff --git a/packages/web/src/content/docs/nb/lsp.mdx b/packages/web/src/content/docs/nb/lsp.mdx index 924b0dad1a..b7c72950c6 100644 --- a/packages/web/src/content/docs/nb/lsp.mdx +++ b/packages/web/src/content/docs/nb/lsp.mdx @@ -3,7 +3,7 @@ title: LSP-servere description: opencode integreres med LSP-serverne dine. --- -OpenCode integreres med din Language Server Protocol (LSP) for å hjelpe LLM med å samhandle med kodebasen din. Den bruker diagnostikk for å gi tilbakemelding til LLM. +OpenCode kan integreres med Language Server Protocol (LSP)-servere for å bruke diagnostikk som tilbakemelding til agenten. --- @@ -47,7 +47,7 @@ OpenCode kommer med flere innebygde LSP-servere for populære språk: | yaml-ls | .yaml, .yml | Installerer Red Hat yaml-language-server automatisk | | zls | .zig, .zon | `zig` kommando tilgjengelig | -LSP-servere aktiveres automatisk når en av filtypene ovenfor oppdages og kravene oppfylles. +LSP er deaktivert som standard. Når det er aktivert, starter servere når en av filtypene ovenfor oppdages og kravene oppfylles. :::note Du kan deaktivere automatiske LSP-servernedlastinger ved å sette miljøvariabelen `OPENCODE_DISABLE_LSP_DOWNLOAD` til `true`. @@ -57,16 +57,35 @@ Du kan deaktivere automatiske LSP-servernedlastinger ved å sette miljøvariabel ## Slik fungerer det -Når opencode åpner en fil, gjør den: +Når LSP er aktivert og opencode åpner en fil, gjør den: 1. Kontrollerer filtypen mot alle aktiverte LSP-servere. 2. Starter den riktige LSP-serveren hvis den ikke allerede kjører. --- +## Beste praksis + +LSP kan hjelpe agenten med å finne og fikse problemer ved å gi diagnostikk fra språkservere. Dette er nyttig i noen prosjekter, men er ikke alltid en klar gevinst. + +Språkservere kan komme ut av synk, bruke mye minne, variere etter versjon eller prosjekt og redusere agentarbeidsflyter. I mange prosjekter er det bedre at agenten kjører lint, typecheck eller andre diagnostiske CLI-verktøy direkte, slik at feil mates tilbake i agentløkken uten disse avveiningene. Aktiver LSP når prosjektet ditt har nytte av ekstra språkservertilbakemelding. + +--- + ## Konfigurasjon -Du kan tilpasse LSP-servere gjennom `lsp`-delen i OpenCode-konfigurasjonen. +Du kan aktivere og tilpasse LSP-servere gjennom `lsp`-delen i OpenCode-konfigurasjonen. + +For å aktivere alle innebygde LSP-servere, sett `lsp` til `true`. + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +Bruk et objekt for å beholde innebygde servere aktivert mens du konfigurerer overstyringer eller egendefinerte servere. ```json title="opencode.json" { @@ -135,7 +154,7 @@ Initialiseringsalternativer varierer etter LSP-server. Sjekk dokumentasjonen til ### Deaktivering av LSP-servere -For å deaktivere **alle** LSP-servere globalt, sett `lsp` til `false`: +Hvis `lsp` utelates, er alle LSP-servere deaktivert. For å deaktivere alle LSP-servere etter at en annen konfigurasjon har aktivert dem, sett `lsp` til `false`: ```json title="opencode.json" {3} { diff --git a/packages/web/src/content/docs/pl/lsp.mdx b/packages/web/src/content/docs/pl/lsp.mdx index ec2edec430..3ee58aef10 100644 --- a/packages/web/src/content/docs/pl/lsp.mdx +++ b/packages/web/src/content/docs/pl/lsp.mdx @@ -3,7 +3,7 @@ title: Serwery LSP description: OpenCode integruje się z serwerami LSP. --- -OpenCode integruje się z protokołem Language Server Protocol (LSP), aby zapewnić modelom LLM kontekst bazy kodu. Wykorzystuje diagnostykę, aby przekazywać informacje zwrotne do LLM. +OpenCode może integrować się z serwerami Language Server Protocol (LSP), aby używać diagnostyki jako informacji zwrotnej dla agenta. --- @@ -47,7 +47,7 @@ OpenCode posiada kilka wbudowanych serwerów LSP dla następujących języków: | yaml-ls | .yaml, .yml | Automatycznie instaluje serwer języka yaml Red Hat | | zls | .zig, .zon | Dostępne polecenie `zig` | -Serwery LSP są automatycznie włączane po wykryciu jednego z obsługiwanych plików i spełnieniu wymagań. +LSP jest domyślnie wyłączone. Gdy jest włączone, serwery uruchamiają się po wykryciu jednego z obsługiwanych rozszerzeń plików i spełnieniu wymagań. :::note Możesz wyłączyć automatyczne pobieranie serwerów LSP, ustawiając zmienną środowiskową `OPENCODE_DISABLE_LSP_DOWNLOAD` na `true`. @@ -57,16 +57,35 @@ Możesz wyłączyć automatyczne pobieranie serwerów LSP, ustawiając zmienną ## Jak to działa -Gdy OpenCode otwiera plik: +Gdy LSP jest włączony i OpenCode otwiera plik: 1. Sprawdza plik pod kątem wszystkich dostępnych serwerów LSP. 2. Uruchamia odpowiedni serwer LSP, jeśli jeszcze nie działa. --- +## Dobre praktyki + +LSP może pomóc agentowi znajdować i naprawiać problemy, dostarczając diagnostykę z serwerów językowych. Jest to przydatne w niektórych projektach, ale nie zawsze jest jednoznaczną korzyścią. + +Serwery językowe mogą wypaść z synchronizacji, zużywać dużo pamięci, różnić się między wersjami lub projektami i spowalniać workflow agenta. W wielu projektach lepiej, aby agent uruchamiał lint, typecheck lub inne diagnostyczne narzędzia CLI bezpośrednio; wtedy błędy wracają do pętli agenta bez tych kompromisów. Włącz LSP, gdy Twój projekt korzysta z dodatkowej informacji zwrotnej z serwera językowego. + +--- + ## Konfiguracja -Możesz dostosować serwery LSP poprzez sekcję `lsp` w konfiguracji OpenCode. +Możesz włączać i dostosowywać serwery LSP poprzez sekcję `lsp` w konfiguracji OpenCode. + +Aby włączyć wszystkie wbudowane serwery LSP, ustaw `lsp` na `true`. + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +Użyj obiektu, aby pozostawić wbudowane serwery włączone i jednocześnie skonfigurować nadpisania lub serwery niestandardowe. ```json title="opencode.json" { @@ -135,7 +154,7 @@ Opcje inicjalizacji różnią się w zależności od serwera LSP. Sprawdź dokum ### Wyłączanie serwerów LSP -Aby wyłączyć **wszystkie** serwery LSP globalnie, ustaw `lsp` na `false`: +Jeśli `lsp` zostanie pominięte, wszystkie serwery LSP są wyłączone. Aby wyłączyć wszystkie serwery LSP po tym, jak inna konfiguracja je włączyła, ustaw `lsp` na `false`: ```json title="opencode.json" {3} { diff --git a/packages/web/src/content/docs/pt-br/lsp.mdx b/packages/web/src/content/docs/pt-br/lsp.mdx index cd8937b244..aff101cc6c 100644 --- a/packages/web/src/content/docs/pt-br/lsp.mdx +++ b/packages/web/src/content/docs/pt-br/lsp.mdx @@ -3,7 +3,7 @@ title: Servidores LSP description: O opencode integra-se aos seus servidores LSP. --- -O opencode integra-se ao seu Protocolo de Servidor de Linguagem (LSP) para ajudar o LLM a interagir com sua base de código. Ele usa diagnósticos para fornecer feedback ao LLM. +O opencode pode se integrar a servidores Language Server Protocol (LSP) para usar diagnósticos como feedback para o agente. --- @@ -47,7 +47,7 @@ O opencode vem com vários servidores LSP integrados para linguagens populares: | yaml-ls | .yaml, .yml | Instala automaticamente o servidor yaml-language-server da Red Hat | | zls | .zig, .zon | Comando `zig` disponível | -Os servidores LSP são habilitados automaticamente quando uma das extensões de arquivo acima é detectada e os requisitos são atendidos. +O LSP fica desabilitado por padrão. Quando habilitado, os servidores iniciam quando uma das extensões de arquivo acima é detectada e os requisitos são atendidos. :::note Você pode desabilitar os downloads automáticos do servidor LSP definindo a variável de ambiente `OPENCODE_DISABLE_LSP_DOWNLOAD` como `true`. @@ -57,16 +57,35 @@ Você pode desabilitar os downloads automáticos do servidor LSP definindo a var ## Como Funciona -Quando o opencode abre um arquivo, ele: +Quando o LSP está habilitado e o opencode abre um arquivo, ele: 1. Verifica a extensão do arquivo em relação a todos os servidores LSP habilitados. 2. Inicia o servidor LSP apropriado se não estiver em execução. --- +## Boas práticas + +O LSP pode ajudar o agente a encontrar e corrigir problemas fornecendo diagnósticos dos servidores de linguagem. Isso é útil em alguns projetos, mas nem sempre é um ganho líquido. + +Servidores de linguagem podem ficar fora de sincronia, usar bastante memória, variar por versão ou projeto e desacelerar fluxos de trabalho do agente. Em muitos projetos, é melhor fazer o agente executar lint, typecheck ou outras ferramentas CLI de diagnóstico diretamente, para que os erros voltem ao ciclo do agente sem essas compensações. Habilite o LSP quando seu projeto se beneficiar de feedback adicional do servidor de linguagem. + +--- + ## Configuração -Você pode personalizar os servidores LSP através da seção `lsp` na sua configuração do opencode. +Você pode habilitar e personalizar os servidores LSP através da seção `lsp` na sua configuração do opencode. + +Para habilitar todos os servidores LSP integrados, defina `lsp` como `true`. + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +Use um objeto para manter os servidores integrados habilitados enquanto configura substituições ou servidores personalizados. ```json title="opencode.json" { @@ -135,7 +154,7 @@ As opções de inicialização variam de acordo com o servidor LSP. Verifique a ### Desabilitando servidores LSP -Para desabilitar **todos** os servidores LSP globalmente, defina `lsp` como `false`: +Se `lsp` for omitido, todos os servidores LSP ficam desabilitados. Para desabilitar todos os servidores LSP depois que outra configuração os habilitou, defina `lsp` como `false`: ```json title="opencode.json" {3} { diff --git a/packages/web/src/content/docs/ru/lsp.mdx b/packages/web/src/content/docs/ru/lsp.mdx index 0b63c9ea3b..738e18d967 100644 --- a/packages/web/src/content/docs/ru/lsp.mdx +++ b/packages/web/src/content/docs/ru/lsp.mdx @@ -3,7 +3,7 @@ title: LSP-серверы description: opencode интегрируется с вашими серверами LSP. --- -opencode интегрируется с вашим протоколом языкового сервера (LSP), чтобы помочь LLM взаимодействовать с вашей кодовой базой. Он использует диагностику для предоставления обратной связи LLM. +opencode может интегрироваться с серверами Language Server Protocol (LSP), чтобы использовать диагностику как обратную связь для агента. --- @@ -46,7 +46,7 @@ opencode поставляется с несколькими встроенным | yaml-ls | .yaml, .yml | Автоматически устанавливает Red Hat yaml-language-server | | zls | .zig, .zon | `zig` команда доступна | -Серверы LSP автоматически включаются при обнаружении одного из указанных выше расширений файлов и выполнении требований. +LSP отключен по умолчанию. Когда он включен, серверы запускаются при обнаружении одного из указанных выше расширений файлов и выполнении требований. :::note Вы можете отключить автоматическую загрузку LSP-сервера, установив для переменной среды `OPENCODE_DISABLE_LSP_DOWNLOAD` значение `true`. @@ -56,16 +56,35 @@ opencode поставляется с несколькими встроенным ## Как это работает -Когда opencode открывает файл, он: +Когда LSP включен и opencode открывает файл, он: 1. Проверяет расширение файла на всех включенных серверах LSP. 2. Запускает соответствующий сервер LSP, если он еще не запущен. --- +## Рекомендации + +LSP может помочь агенту находить и исправлять проблемы, предоставляя диагностику от языковых серверов. Это полезно в некоторых проектах, но не всегда является однозначным преимуществом. + +Языковые серверы могут рассинхронизироваться, потреблять много памяти, отличаться по поведению между версиями или проектами и замедлять рабочие процессы агента. Во многих проектах лучше, чтобы агент напрямую запускал lint, typecheck или другие диагностические CLI-инструменты; так ошибки возвращаются в цикл агента без этих компромиссов. Включайте LSP, когда проект получает пользу от дополнительной обратной связи языкового сервера. + +--- + ## Настройка -Вы можете настроить серверы LSP через раздел `lsp` в конфигурации opencode. +Вы можете включить и настроить серверы LSP через раздел `lsp` в конфигурации opencode. + +Чтобы включить все встроенные LSP-серверы, установите `lsp` в `true`. + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +Используйте объект, чтобы оставить встроенные серверы включенными и при этом настроить переопределения или пользовательские серверы. ```json title="opencode.json" { @@ -134,7 +153,7 @@ opencode поставляется с несколькими встроенным ### Отключение LSP-серверов -Чтобы отключить **все** LSP-серверы глобально, установите для `lsp` значение `false`: +Если `lsp` не указан, все LSP-серверы отключены. Чтобы отключить все LSP-серверы после того, как другая конфигурация их включила, установите для `lsp` значение `false`: ```json title="opencode.json" {3} { diff --git a/packages/web/src/content/docs/th/lsp.mdx b/packages/web/src/content/docs/th/lsp.mdx index 91d3f479fb..1ab0d970a6 100644 --- a/packages/web/src/content/docs/th/lsp.mdx +++ b/packages/web/src/content/docs/th/lsp.mdx @@ -3,7 +3,7 @@ title: LSP เซิร์ฟเวอร์ description: OpenCode ทำงานร่วมกับเซิร์ฟเวอร์ LSP ของคุณ --- -OpenCode ทำงานร่วมกับ Language Server Protocol (LSP) เพื่อช่วยให้ LLM โต้ตอบกับโค้ดเบสของคุณ ใช้การวินิจฉัยเพื่อให้ข้อเสนอแนะไปยัง LLM +OpenCode สามารถทำงานร่วมกับเซิร์ฟเวอร์ Language Server Protocol (LSP) เพื่อใช้ diagnostics เป็น feedback สำหรับ agent --- @@ -47,7 +47,7 @@ OpenCode มาพร้อมกับเซิร์ฟเวอร์ LSP ใ | yaml-ls | .yaml, .yml | ติดตั้งเซิร์ฟเวอร์ภาษา Red Hat yaml โดยอัตโนมัติ | | zls | .zig, .zon | `zig` คำสั่งใช้ได้ | -เซิร์ฟเวอร์ LSP จะถูกเปิดใช้งานโดยอัตโนมัติเมื่อตรวจพบนามสกุลไฟล์ใดนามสกุลหนึ่งข้างต้นและเป็นไปตามข้อกำหนด +LSP ปิดใช้งานเป็นค่าเริ่มต้น เมื่อเปิดใช้งาน เซิร์ฟเวอร์จะเริ่มทำงานเมื่อตรวจพบนามสกุลไฟล์ข้างต้นและเป็นไปตามข้อกำหนด :::note คุณสามารถปิดใช้งานการดาวน์โหลดเซิร์ฟเวอร์ LSP อัตโนมัติได้โดยตั้งค่าตัวแปรสภาพแวดล้อม `OPENCODE_DISABLE_LSP_DOWNLOAD` เป็น `true` @@ -57,16 +57,35 @@ OpenCode มาพร้อมกับเซิร์ฟเวอร์ LSP ใ ## มันทำงานอย่างไร -เมื่อ opencode เปิดไฟล์ มันจะ: +เมื่อเปิดใช้งาน LSP และ opencode เปิดไฟล์ มันจะ: 1. ตรวจสอบนามสกุลไฟล์กับเซิร์ฟเวอร์ LSP ที่เปิดใช้งานทั้งหมด 2. เริ่มเซิร์ฟเวอร์ LSP ที่เหมาะสมหากยังไม่ได้ทำงาน --- +## แนวทางปฏิบัติที่แนะนำ + +LSP สามารถช่วยให้ agent ค้นหาและแก้ไขปัญหาโดยให้ diagnostics จากเซิร์ฟเวอร์ภาษา สิ่งนี้มีประโยชน์ในบางโปรเจ็กต์ แต่ไม่ได้เป็นผลบวกเสมอไป + +เซิร์ฟเวอร์ภาษาอาจไม่ตรงกับสถานะโปรเจ็กต์ ใช้หน่วยความจำมาก แตกต่างกันตามเวอร์ชันหรือโปรเจ็กต์ และทำให้เวิร์กโฟลว์ของ agent ช้าลง ในหลายโปรเจ็กต์ การให้ agent รัน lint, typecheck หรือเครื่องมือ CLI สำหรับ diagnostics อื่นโดยตรงจะดีกว่า เพราะข้อผิดพลาดจะถูกส่งกลับเข้า loop ของ agent โดยไม่มีข้อแลกเปลี่ยนเหล่านี้ เปิดใช้งาน LSP เมื่อโปรเจ็กต์ของคุณได้ประโยชน์จาก feedback เพิ่มเติมของเซิร์ฟเวอร์ภาษา + +--- + ## กำหนดค่า -You can customize LSP servers through the `lsp` section in your opencode config. +คุณสามารถเปิดใช้งานและปรับแต่งเซิร์ฟเวอร์ LSP ผ่านส่วน `lsp` ในการกำหนดค่า opencode + +หากต้องการเปิดใช้งานเซิร์ฟเวอร์ LSP ในตัวทั้งหมด ให้ตั้งค่า `lsp` เป็น `true` + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +ใช้อ็อบเจ็กต์เพื่อให้เซิร์ฟเวอร์ในตัวยังคงเปิดใช้งานอยู่ พร้อมกำหนดค่าการแทนที่หรือเซิร์ฟเวอร์แบบกำหนดเอง ```json title="opencode.json" { @@ -135,7 +154,7 @@ You can customize LSP servers through the `lsp` section in your opencode config. ### ปิดการใช้งานเซิร์ฟเวอร์ LSP -หากต้องการปิดการใช้งานเซิร์ฟเวอร์ **ทั้งหมด** LSP ทั่วโลก ให้ตั้งค่า `lsp` เป็น `false`: +หากละเว้น `lsp` เซิร์ฟเวอร์ LSP ทั้งหมดจะถูกปิดใช้งาน หากการกำหนดค่าอื่นเปิดใช้งาน LSP ไว้ ให้ตั้งค่า `lsp` เป็น `false` เพื่อปิดใช้งานเซิร์ฟเวอร์ LSP ทั้งหมด: ```json title="opencode.json" {3} { diff --git a/packages/web/src/content/docs/tr/lsp.mdx b/packages/web/src/content/docs/tr/lsp.mdx index 52a95d1c3c..18da488442 100644 --- a/packages/web/src/content/docs/tr/lsp.mdx +++ b/packages/web/src/content/docs/tr/lsp.mdx @@ -3,7 +3,7 @@ title: LSP Sunucuları description: OpenCode, LSP sunucularınızla bütünleşir. --- -OpenCode, LLM'in kod tabanınızla etkileşime girmesine yardımcı olmak için Dil Sunucusu Protokolünüzle (LSP) bütünleşir. LLM'ye geri bildirim sağlamak için tanılamayı kullanır. +OpenCode, tanılamayı agent için geri bildirim olarak kullanmak üzere Language Server Protocol (LSP) sunucularıyla bütünleşebilir. --- @@ -47,7 +47,7 @@ OpenCode, popüler diller için çeşitli yerleşik LSP sunucularıyla birlikte | yaml-ls | .yaml, .yml | Red Hat yaml-language-server'ı otomatik olarak yükler | | zls | .zig, .zon | `zig` komutu mevcut | -Yukarıdaki dosya uzantılarından biri tespit edildiğinde ve gereksinimler karşılandığında LSP sunucuları otomatik olarak etkinleştirilir. +LSP varsayılan olarak devre dışıdır. Etkinleştirildiğinde, yukarıdaki dosya uzantılarından biri tespit edilir ve gereksinimler karşılanırsa sunucular başlatılır. :::note `OPENCODE_DISABLE_LSP_DOWNLOAD` ortam değişkenini `true` olarak ayarlayarak otomatik LSP sunucu indirmelerini devre dışı bırakabilirsiniz. @@ -57,16 +57,35 @@ Yukarıdaki dosya uzantılarından biri tespit edildiğinde ve gereksinimler kar ## Nasıl Çalışır? -opencode bir dosyayı açtığında: +LSP etkinleştirildiğinde ve opencode bir dosyayı açtığında: 1. Dosya uzantısını tüm etkin LSP sunucularına göre kontrol eder. 2. Henüz çalışmıyorsa uygun LSP sunucusunu başlatır. --- +## En İyi Uygulamalar + +LSP, dil sunucularından tanılama sağlayarak agent'ın sorunları bulup düzeltmesine yardımcı olabilir. Bu bazı projelerde yararlıdır, ancak her zaman net bir kazanç değildir. + +Dil sunucuları senkronizasyonu kaybedebilir, önemli miktarda bellek kullanabilir, sürüme veya projeye göre değişebilir ve agent iş akışlarını yavaşlatabilir. Birçok projede agent'ın lint, typecheck veya diğer tanılama CLI araçlarını doğrudan çalıştırması daha iyidir; böylece hatalar bu ödünleşimler olmadan agent döngüsüne geri beslenir. Projeniz ek dil sunucusu geri bildiriminden yararlanıyorsa LSP'yi etkinleştirin. + +--- + ## Yapılandırma -LSP sunucularını, opencode yapılandırmanızdaki `lsp` bölümü aracılığıyla özelleştirebilirsiniz. +LSP sunucularını, opencode yapılandırmanızdaki `lsp` bölümü aracılığıyla etkinleştirebilir ve özelleştirebilirsiniz. + +Tüm yerleşik LSP sunucularını etkinleştirmek için `lsp` değerini `true` olarak ayarlayın. + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +Yerleşik sunucuları etkin tutarken geçersiz kılmaları veya özel sunucuları yapılandırmak için bir nesne kullanın. ```json title="opencode.json" { @@ -135,7 +154,7 @@ Başlatma seçenekleri LSP sunucusuna göre değişir. Mevcut seçenekler için ### LSP sunucularını devre dışı bırakma -**tüm** LSP sunucularını genel olarak devre dışı bırakmak için `lsp`'yi `false` olarak ayarlayın: +`lsp` atlanırsa tüm LSP sunucuları devre dışı kalır. Başka bir yapılandırma etkinleştirdikten sonra tüm LSP sunucularını devre dışı bırakmak için `lsp` değerini `false` olarak ayarlayın: ```json title="opencode.json" {3} { diff --git a/packages/web/src/content/docs/zh-cn/lsp.mdx b/packages/web/src/content/docs/zh-cn/lsp.mdx index 59dd7082a1..63b5abaf48 100644 --- a/packages/web/src/content/docs/zh-cn/lsp.mdx +++ b/packages/web/src/content/docs/zh-cn/lsp.mdx @@ -3,7 +3,7 @@ title: LSP 服务器 description: OpenCode 与你的 LSP 服务器集成。 --- -OpenCode 与你的语言服务器协议(LSP)集成,帮助 LLM 与你的代码库进行交互。它利用诊断信息向 LLM 提供反馈。 +OpenCode 可以与语言服务器协议(LSP)服务器集成,将诊断信息作为 agent 的反馈。 --- @@ -47,7 +47,7 @@ OpenCode 内置了多种适用于主流语言的 LSP 服务器: | yaml-ls | .yaml, .yml | 自动安装 Red Hat yaml-language-server | | zls | .zig, .zon | 需要 `zig` 命令可用 | -当检测到上述文件扩展名且满足相应要求时,LSP 服务器会自动启用。 +LSP 默认关闭。启用后,当检测到上述文件扩展名且满足相应要求时,服务器会启动。 :::note 你可以将 `OPENCODE_DISABLE_LSP_DOWNLOAD` 环境变量设置为 `true` 来禁用 LSP 服务器的自动下载。 @@ -57,16 +57,35 @@ OpenCode 内置了多种适用于主流语言的 LSP 服务器: ## 工作原理 -当 opencode 打开一个文件时,它会: +启用 LSP 且 opencode 打开文件时,它会: 1. 将文件扩展名与所有已启用的 LSP 服务器进行匹配。 2. 如果对应的 LSP 服务器尚未运行,则自动启动它。 --- +## 最佳实践 + +LSP 可以通过语言服务器诊断帮助 agent 发现并修复问题。这对某些项目很有用,但并不总是带来净收益。 + +语言服务器可能与项目不同步、占用较多内存、随版本或项目表现不同,并拖慢 agent 工作流。在许多项目中,更好的做法是让 agent 直接运行 lint、typecheck 或其他诊断类 CLI 工具,这样错误会进入 agent 循环,同时避免这些权衡。当你的项目能从额外的语言服务器反馈中受益时再启用 LSP。 + +--- + ## 配置 -你可以通过 opencode 配置文件中的 `lsp` 部分来自定义 LSP 服务器。 +你可以通过 opencode 配置文件中的 `lsp` 部分来启用并自定义 LSP 服务器。 + +要启用所有内置 LSP 服务器,请将 `lsp` 设置为 `true`。 + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +使用对象可以在保持内置服务器启用的同时配置覆盖项或自定义服务器。 ```json title="opencode.json" { @@ -135,7 +154,7 @@ OpenCode 内置了多种适用于主流语言的 LSP 服务器: ### 禁用 LSP 服务器 -要全局禁用**所有** LSP 服务器,将 `lsp` 设置为 `false`: +如果省略 `lsp`,所有 LSP 服务器都会被禁用。如果另一个配置启用了 LSP,可将 `lsp` 设置为 `false` 来禁用所有 LSP 服务器: ```json title="opencode.json" {3} { diff --git a/packages/web/src/content/docs/zh-tw/lsp.mdx b/packages/web/src/content/docs/zh-tw/lsp.mdx index aa3af32881..fbc5296129 100644 --- a/packages/web/src/content/docs/zh-tw/lsp.mdx +++ b/packages/web/src/content/docs/zh-tw/lsp.mdx @@ -3,7 +3,7 @@ title: LSP 伺服器 description: OpenCode 與您的 LSP 伺服器整合。 --- -OpenCode 與您的語言伺服器協定(LSP)整合,協助 LLM 與您的程式碼庫進行互動。它利用診斷資訊向 LLM 提供回饋。 +OpenCode 可以與語言伺服器協定(LSP)伺服器整合,將診斷資訊作為 agent 的回饋。 --- @@ -47,7 +47,7 @@ OpenCode 內建了多種適用於主流語言的 LSP 伺服器: | yaml-ls | .yaml, .yml | 自動安裝 Red Hat yaml-language-server | | zls | .zig, .zon | 需要 `zig` 指令可用 | -當偵測到上述檔案副檔名且滿足相應要求時,LSP 伺服器會自動啟用。 +LSP 預設關閉。啟用後,當偵測到上述檔案副檔名且滿足相應要求時,伺服器會啟動。 :::note 您可以將 `OPENCODE_DISABLE_LSP_DOWNLOAD` 環境變數設定為 `true` 來停用 LSP 伺服器的自動下載。 @@ -57,16 +57,35 @@ OpenCode 內建了多種適用於主流語言的 LSP 伺服器: ## 工作原理 -當 OpenCode 開啟一個檔案時,它會: +啟用 LSP 且 OpenCode 開啟檔案時,它會: 1. 將檔案副檔名與所有已啟用的 LSP 伺服器進行比對。 2. 如果對應的 LSP 伺服器尚未執行,則自動啟動它。 --- +## 最佳實踐 + +LSP 可以透過語言伺服器診斷幫助 agent 發現並修復問題。這對某些專案很有用,但不一定總是帶來淨收益。 + +語言伺服器可能與專案不同步、佔用較多記憶體、隨版本或專案表現不同,並拖慢 agent 工作流程。在許多專案中,更好的做法是讓 agent 直接執行 lint、typecheck 或其他診斷類 CLI 工具,這樣錯誤會回到 agent 循環,同時避免這些取捨。當您的專案能從額外的語言伺服器回饋中受益時再啟用 LSP。 + +--- + ## 設定 -您可以透過 OpenCode 設定檔中的 `lsp` 部分來自訂 LSP 伺服器。 +您可以透過 OpenCode 設定檔中的 `lsp` 部分來啟用並自訂 LSP 伺服器。 + +要啟用所有內建 LSP 伺服器,請將 `lsp` 設定為 `true`。 + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +使用物件可以在保持內建伺服器啟用的同時設定覆寫項或自訂伺服器。 ```json title="opencode.json" { @@ -135,7 +154,7 @@ OpenCode 內建了多種適用於主流語言的 LSP 伺服器: ### 停用 LSP 伺服器 -要全域停用**所有** LSP 伺服器,將 `lsp` 設定為 `false`: +如果省略 `lsp`,所有 LSP 伺服器都會被停用。如果另一個設定啟用了 LSP,可將 `lsp` 設定為 `false` 來停用所有 LSP 伺服器: ```json title="opencode.json" {3} { From fdfd0afed7fddbe852ea53b5a75ce1ea8ad725a2 Mon Sep 17 00:00:00 2001 From: Dustin Deus Date: Tue, 26 May 2026 20:59:05 +0200 Subject: [PATCH 33/40] docs: add tip to lsp section (#29444) Co-authored-by: starptech --- packages/web/src/content/docs/ar/lsp.mdx | 2 +- packages/web/src/content/docs/bs/lsp.mdx | 2 +- packages/web/src/content/docs/da/lsp.mdx | 2 +- packages/web/src/content/docs/de/lsp.mdx | 2 +- packages/web/src/content/docs/es/lsp.mdx | 2 +- packages/web/src/content/docs/fr/lsp.mdx | 2 +- packages/web/src/content/docs/it/lsp.mdx | 2 +- packages/web/src/content/docs/ja/lsp.mdx | 2 +- packages/web/src/content/docs/ko/lsp.mdx | 2 +- packages/web/src/content/docs/lsp.mdx | 2 +- packages/web/src/content/docs/nb/lsp.mdx | 2 +- packages/web/src/content/docs/pl/lsp.mdx | 2 +- packages/web/src/content/docs/pt-br/lsp.mdx | 2 +- packages/web/src/content/docs/ru/lsp.mdx | 2 +- packages/web/src/content/docs/th/lsp.mdx | 2 +- packages/web/src/content/docs/tr/lsp.mdx | 2 +- packages/web/src/content/docs/zh-cn/lsp.mdx | 2 +- packages/web/src/content/docs/zh-tw/lsp.mdx | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/web/src/content/docs/ar/lsp.mdx b/packages/web/src/content/docs/ar/lsp.mdx index a33a457c8b..8b2c721df2 100644 --- a/packages/web/src/content/docs/ar/lsp.mdx +++ b/packages/web/src/content/docs/ar/lsp.mdx @@ -67,7 +67,7 @@ description: يتكامل OpenCode مع خوادم LSP لديك. يمكن أن تساعد LSP الوكيل على العثور على المشاكل وإصلاحها عبر توفير التشخيصات من خوادم اللغة. هذا مفيد في بعض المشاريع، لكنه ليس دائما مكسبا صافيا. -قد تخرج خوادم اللغة عن المزامنة، وتستهلك ذاكرة كبيرة، وتختلف حسب الإصدار أو المشروع، وتبطئ سير عمل الوكيل. في كثير من المشاريع، يكون من الأفضل أن يشغّل الوكيل lint أو typecheck أو أدوات CLI التشخيصية الأخرى مباشرة، بحيث تعود الأخطاء إلى حلقة الوكيل دون هذه المفاضلات. فعّل LSP عندما يستفيد مشروعك من ملاحظات إضافية من خادم اللغة. +قد تخرج خوادم اللغة عن المزامنة، وتستهلك ذاكرة كبيرة، وتختلف حسب الإصدار أو المشروع، وتبطئ سير عمل الوكيل. في كثير من المشاريع، يكون من الأفضل أن يشغّل الوكيل lint أو typecheck أو أدوات CLI التشخيصية الأخرى مباشرة، بحيث تعود الأخطاء إلى حلقة الوكيل دون هذه المفاضلات. وثّق هذه الأوامر في ملفات التعليمات مثل `AGENTS.md` أو المهارات حتى يعرف الوكيل ما يجب تشغيله. فعّل LSP عندما يستفيد مشروعك من ملاحظات إضافية من خادم اللغة. --- diff --git a/packages/web/src/content/docs/bs/lsp.mdx b/packages/web/src/content/docs/bs/lsp.mdx index fb8d06b24a..a30d589f9a 100644 --- a/packages/web/src/content/docs/bs/lsp.mdx +++ b/packages/web/src/content/docs/bs/lsp.mdx @@ -65,7 +65,7 @@ Kada je LSP omogućen i opencode otvori fajl, on: LSP može pomoći agentu da pronađe i popravi probleme pružanjem dijagnostike iz jezičkih servera. Ovo je korisno u nekim projektima, ali nije uvijek neto pozitivno. -Jezički serveri mogu ispasti iz sinhronizacije, koristiti mnogo memorije, razlikovati se po verziji ili projektu i usporiti agent workflow. U mnogim projektima je bolje da agent direktno pokreće lint, typecheck ili druge dijagnostičke CLI alate, tako da se greške vraćaju u agent loop bez tih kompromisa. Uključite LSP kada vaš projekt ima koristi od dodatnog feedbacka jezičkog servera. +Jezički serveri mogu ispasti iz sinhronizacije, koristiti mnogo memorije, razlikovati se po verziji ili projektu i usporiti agent workflow. U mnogim projektima je bolje da agent direktno pokreće lint, typecheck ili druge dijagnostičke CLI alate, tako da se greške vraćaju u agent loop bez tih kompromisa. Dokumentujte te komande u instrukcijskim fajlovima kao što su `AGENTS.md` ili skills, kako bi agent znao šta treba pokrenuti. Uključite LSP kada vaš projekt ima koristi od dodatnog feedbacka jezičkog servera. --- diff --git a/packages/web/src/content/docs/da/lsp.mdx b/packages/web/src/content/docs/da/lsp.mdx index 3ba3eeb5ef..0b6ea0fee8 100644 --- a/packages/web/src/content/docs/da/lsp.mdx +++ b/packages/web/src/content/docs/da/lsp.mdx @@ -68,7 +68,7 @@ Når LSP er aktiveret, og opencode åbner en fil, vil den: LSP kan hjælpe agenten med at finde og rette problemer ved at levere diagnostik fra sprogservere. Det er nyttigt i nogle projekter, men er ikke altid en klar fordel. -Sprogservere kan komme ud af sync, bruge meget hukommelse, variere efter version eller projekt og gøre agentarbejdsgange langsommere. I mange projekter er det bedre, at agenten kører lint, typecheck eller andre diagnostiske CLI-værktøjer direkte, så fejl føres tilbage i agentens loop uden disse afvejninger. Aktivér LSP, når dit projekt har gavn af ekstra sprogserverfeedback. +Sprogservere kan komme ud af sync, bruge meget hukommelse, variere efter version eller projekt og gøre agentarbejdsgange langsommere. I mange projekter er det bedre, at agenten kører lint, typecheck eller andre diagnostiske CLI-værktøjer direkte, så fejl føres tilbage i agentens loop uden disse afvejninger. Dokumentér disse kommandoer i instruktionsfiler som `AGENTS.md` eller skills, så agenten ved, hvad den skal køre. Aktivér LSP, når dit projekt har gavn af ekstra sprogserverfeedback. --- diff --git a/packages/web/src/content/docs/de/lsp.mdx b/packages/web/src/content/docs/de/lsp.mdx index 154aeaa060..7ecd16d90f 100644 --- a/packages/web/src/content/docs/de/lsp.mdx +++ b/packages/web/src/content/docs/de/lsp.mdx @@ -67,7 +67,7 @@ Wenn LSP aktiviert ist und OpenCode eine Datei öffnet, geschieht Folgendes: LSP kann dem Agenten helfen, Probleme zu finden und zu beheben, indem es Diagnosen von Sprachservern bereitstellt. Das ist in einigen Projekten nützlich, aber nicht immer ein klarer Vorteil. -Sprachserver können aus dem Sync geraten, viel Speicher verwenden, je nach Version oder Projekt unterschiedlich arbeiten und Agent-Workflows verlangsamen. In vielen Projekten ist es besser, wenn der Agent lint, typecheck oder andere diagnostische CLI-Tools direkt ausführt, damit Fehler in die Agent-Schleife zurückfließen, ohne diese Kompromisse einzugehen. Aktivieren Sie LSP, wenn Ihr Projekt von zusätzlichem Sprachserver-Feedback profitiert. +Sprachserver können aus dem Sync geraten, viel Speicher verwenden, je nach Version oder Projekt unterschiedlich arbeiten und Agent-Workflows verlangsamen. In vielen Projekten ist es besser, wenn der Agent lint, typecheck oder andere diagnostische CLI-Tools direkt ausführt, damit Fehler in die Agent-Schleife zurückfließen, ohne diese Kompromisse einzugehen. Dokumentieren Sie diese Befehle in Instruktionsdateien wie `AGENTS.md` oder Skills, damit der Agent weiß, was er ausführen soll. Aktivieren Sie LSP, wenn Ihr Projekt von zusätzlichem Sprachserver-Feedback profitiert. --- diff --git a/packages/web/src/content/docs/es/lsp.mdx b/packages/web/src/content/docs/es/lsp.mdx index a1ede5a085..726d720581 100644 --- a/packages/web/src/content/docs/es/lsp.mdx +++ b/packages/web/src/content/docs/es/lsp.mdx @@ -68,7 +68,7 @@ Cuando LSP está habilitado y opencode abre un archivo: LSP puede ayudar al agente a encontrar y corregir problemas proporcionando diagnósticos de los servidores de lenguaje. Esto es útil en algunos proyectos, pero no siempre es una mejora neta. -Los servidores de lenguaje pueden desincronizarse, usar bastante memoria, variar según la versión o el proyecto y ralentizar los flujos de trabajo del agente. En muchos proyectos es mejor hacer que el agente ejecute lint, typecheck u otras herramientas CLI de diagnóstico directamente, para que los errores vuelvan al ciclo del agente sin esas compensaciones. Habilita LSP cuando tu proyecto se beneficie de feedback adicional del servidor de lenguaje. +Los servidores de lenguaje pueden desincronizarse, usar bastante memoria, variar según la versión o el proyecto y ralentizar los flujos de trabajo del agente. En muchos proyectos es mejor hacer que el agente ejecute lint, typecheck u otras herramientas CLI de diagnóstico directamente, para que los errores vuelvan al ciclo del agente sin esas compensaciones. Documenta esos comandos en archivos de instrucciones como `AGENTS.md` o skills para que el agente sepa qué ejecutar. Habilita LSP cuando tu proyecto se beneficie de feedback adicional del servidor de lenguaje. --- diff --git a/packages/web/src/content/docs/fr/lsp.mdx b/packages/web/src/content/docs/fr/lsp.mdx index 1401f0ab7d..143361d9a9 100644 --- a/packages/web/src/content/docs/fr/lsp.mdx +++ b/packages/web/src/content/docs/fr/lsp.mdx @@ -68,7 +68,7 @@ Lorsque LSP est activé et qu'opencode ouvre un fichier, il : LSP peut aider l'agent à trouver et corriger des problèmes en fournissant les diagnostics des serveurs de langage. C'est utile dans certains projets, mais ce n'est pas toujours un gain net. -Les serveurs de langage peuvent se désynchroniser, consommer beaucoup de mémoire, varier selon la version ou le projet, et ralentir les flux de travail de l'agent. Dans de nombreux projets, il est préférable de faire exécuter directement par l'agent le lint, le typecheck ou d'autres outils CLI de diagnostic, afin que les erreurs reviennent dans la boucle de l'agent sans ces compromis. Activez LSP lorsque votre projet bénéficie d'un retour supplémentaire des serveurs de langage. +Les serveurs de langage peuvent se désynchroniser, consommer beaucoup de mémoire, varier selon la version ou le projet, et ralentir les flux de travail de l'agent. Dans de nombreux projets, il est préférable de faire exécuter directement par l'agent le lint, le typecheck ou d'autres outils CLI de diagnostic, afin que les erreurs reviennent dans la boucle de l'agent sans ces compromis. Documentez ces commandes dans des fichiers d'instructions comme `AGENTS.md` ou des skills afin que l'agent sache quoi exécuter. Activez LSP lorsque votre projet bénéficie d'un retour supplémentaire des serveurs de langage. --- diff --git a/packages/web/src/content/docs/it/lsp.mdx b/packages/web/src/content/docs/it/lsp.mdx index 705410aae2..7e645b6038 100644 --- a/packages/web/src/content/docs/it/lsp.mdx +++ b/packages/web/src/content/docs/it/lsp.mdx @@ -68,7 +68,7 @@ Quando LSP è abilitato e opencode apre un file: LSP può aiutare l'agente a trovare e correggere problemi fornendo diagnostica dai server di linguaggio. Questo è utile in alcuni progetti, ma non è sempre un vantaggio netto. -I server di linguaggio possono andare fuori sincronizzazione, usare molta memoria, variare in base alla versione o al progetto e rallentare i workflow dell'agente. In molti progetti è meglio far eseguire direttamente all'agente lint, typecheck o altri strumenti CLI diagnostici, così gli errori rientrano nel ciclo dell'agente senza questi compromessi. Abilita LSP quando il tuo progetto trae beneficio da feedback aggiuntivo del server di linguaggio. +I server di linguaggio possono andare fuori sincronizzazione, usare molta memoria, variare in base alla versione o al progetto e rallentare i workflow dell'agente. In molti progetti è meglio far eseguire direttamente all'agente lint, typecheck o altri strumenti CLI diagnostici, così gli errori rientrano nel ciclo dell'agente senza questi compromessi. Documenta questi comandi nei file di istruzioni come `AGENTS.md` o nelle skills, così l'agente sa cosa eseguire. Abilita LSP quando il tuo progetto trae beneficio da feedback aggiuntivo del server di linguaggio. --- diff --git a/packages/web/src/content/docs/ja/lsp.mdx b/packages/web/src/content/docs/ja/lsp.mdx index 82ec96e18e..dfcda179bf 100644 --- a/packages/web/src/content/docs/ja/lsp.mdx +++ b/packages/web/src/content/docs/ja/lsp.mdx @@ -68,7 +68,7 @@ LSP が有効で OpenCode がファイルを開くと、次のようになりま LSP は、言語サーバーの診断を提供することで、agent が問題を見つけて修正する助けになります。これは一部のプロジェクトで有用ですが、常に明確な利点になるとは限りません。 -言語サーバーは同期が外れたり、多くのメモリを使用したり、バージョンやプロジェクトによって挙動が変わったり、agent のワークフローを遅くすることがあります。多くのプロジェクトでは、agent に lint、typecheck、その他の診断用 CLI ツールを直接実行させる方が適しています。これにより、これらのトレードオフを避けながら、エラーを agent のループに戻せます。追加の言語サーバーフィードバックが有効な場合に LSP を有効にしてください。 +言語サーバーは同期が外れたり、多くのメモリを使用したり、バージョンやプロジェクトによって挙動が変わったり、agent のワークフローを遅くすることがあります。多くのプロジェクトでは、agent に lint、typecheck、その他の診断用 CLI ツールを直接実行させる方が適しています。これにより、これらのトレードオフを避けながら、エラーを agent のループに戻せます。これらのコマンドを `AGENTS.md` や skills などの instruction files に記載し、agent が何を実行すべきか分かるようにしてください。追加の言語サーバーフィードバックが有効な場合に LSP を有効にしてください。 --- diff --git a/packages/web/src/content/docs/ko/lsp.mdx b/packages/web/src/content/docs/ko/lsp.mdx index d6053238b4..0bbd6c8e17 100644 --- a/packages/web/src/content/docs/ko/lsp.mdx +++ b/packages/web/src/content/docs/ko/lsp.mdx @@ -68,7 +68,7 @@ LSP가 활성화되어 있고 OpenCode가 파일을 열면 다음과 같이 동 LSP는 언어 서버의 진단을 제공해 agent가 문제를 찾고 수정하는 데 도움을 줄 수 있습니다. 일부 프로젝트에서는 유용하지만 항상 순이익이 되는 것은 아닙니다. -언어 서버는 동기화가 어긋나거나 많은 메모리를 사용하거나 버전 또는 프로젝트에 따라 다르게 동작하고 agent 워크플로를 느리게 만들 수 있습니다. 많은 프로젝트에서는 agent가 lint, typecheck 또는 다른 진단용 CLI 도구를 직접 실행하게 하는 편이 더 좋습니다. 이렇게 하면 이러한 트레이드오프 없이 오류가 agent 루프로 다시 전달됩니다. 프로젝트가 추가 언어 서버 피드백의 이점을 얻을 때 LSP를 활성화하세요. +언어 서버는 동기화가 어긋나거나 많은 메모리를 사용하거나 버전 또는 프로젝트에 따라 다르게 동작하고 agent 워크플로를 느리게 만들 수 있습니다. 많은 프로젝트에서는 agent가 lint, typecheck 또는 다른 진단용 CLI 도구를 직접 실행하게 하는 편이 더 좋습니다. 이렇게 하면 이러한 트레이드오프 없이 오류가 agent 루프로 다시 전달됩니다. agent가 무엇을 실행해야 하는지 알 수 있도록 해당 명령을 `AGENTS.md` 또는 skills 같은 instruction files에 문서화하세요. 프로젝트가 추가 언어 서버 피드백의 이점을 얻을 때 LSP를 활성화하세요. --- diff --git a/packages/web/src/content/docs/lsp.mdx b/packages/web/src/content/docs/lsp.mdx index 25f88170f5..b9428e5b2d 100644 --- a/packages/web/src/content/docs/lsp.mdx +++ b/packages/web/src/content/docs/lsp.mdx @@ -69,7 +69,7 @@ When LSP is enabled and opencode opens a file, it: LSP can help the agent find and fix issues by providing diagnostics from language servers. This is useful in some projects, but it is not always a net positive. -Language servers can get out of sync, use significant memory, vary by version or project, and slow down agent workflows. In many projects it is better to have the agent run lint, typecheck, or other diagnostic CLI tools directly, so errors are fed back into the agent loop without those tradeoffs. Enable LSP when your project benefits from additional language-server feedback. +Language servers can get out of sync, use significant memory, vary by version or project, and slow down agent workflows. In many projects it is better to have the agent run lint, typecheck, or other diagnostic CLI tools directly, so errors are fed back into the agent loop without those tradeoffs. Document those commands in instruction files such as `AGENTS.md` or skills so the agent knows what to run. Enable LSP when your project benefits from additional language-server feedback. --- diff --git a/packages/web/src/content/docs/nb/lsp.mdx b/packages/web/src/content/docs/nb/lsp.mdx index b7c72950c6..7c9ceeaf88 100644 --- a/packages/web/src/content/docs/nb/lsp.mdx +++ b/packages/web/src/content/docs/nb/lsp.mdx @@ -68,7 +68,7 @@ Når LSP er aktivert og opencode åpner en fil, gjør den: LSP kan hjelpe agenten med å finne og fikse problemer ved å gi diagnostikk fra språkservere. Dette er nyttig i noen prosjekter, men er ikke alltid en klar gevinst. -Språkservere kan komme ut av synk, bruke mye minne, variere etter versjon eller prosjekt og redusere agentarbeidsflyter. I mange prosjekter er det bedre at agenten kjører lint, typecheck eller andre diagnostiske CLI-verktøy direkte, slik at feil mates tilbake i agentløkken uten disse avveiningene. Aktiver LSP når prosjektet ditt har nytte av ekstra språkservertilbakemelding. +Språkservere kan komme ut av synk, bruke mye minne, variere etter versjon eller prosjekt og redusere agentarbeidsflyter. I mange prosjekter er det bedre at agenten kjører lint, typecheck eller andre diagnostiske CLI-verktøy direkte, slik at feil mates tilbake i agentløkken uten disse avveiningene. Dokumenter disse kommandoene i instruksjonsfiler som `AGENTS.md` eller skills, slik at agenten vet hva den skal kjøre. Aktiver LSP når prosjektet ditt har nytte av ekstra språkservertilbakemelding. --- diff --git a/packages/web/src/content/docs/pl/lsp.mdx b/packages/web/src/content/docs/pl/lsp.mdx index 3ee58aef10..5d7048f270 100644 --- a/packages/web/src/content/docs/pl/lsp.mdx +++ b/packages/web/src/content/docs/pl/lsp.mdx @@ -68,7 +68,7 @@ Gdy LSP jest włączony i OpenCode otwiera plik: LSP może pomóc agentowi znajdować i naprawiać problemy, dostarczając diagnostykę z serwerów językowych. Jest to przydatne w niektórych projektach, ale nie zawsze jest jednoznaczną korzyścią. -Serwery językowe mogą wypaść z synchronizacji, zużywać dużo pamięci, różnić się między wersjami lub projektami i spowalniać workflow agenta. W wielu projektach lepiej, aby agent uruchamiał lint, typecheck lub inne diagnostyczne narzędzia CLI bezpośrednio; wtedy błędy wracają do pętli agenta bez tych kompromisów. Włącz LSP, gdy Twój projekt korzysta z dodatkowej informacji zwrotnej z serwera językowego. +Serwery językowe mogą wypaść z synchronizacji, zużywać dużo pamięci, różnić się między wersjami lub projektami i spowalniać workflow agenta. W wielu projektach lepiej, aby agent uruchamiał lint, typecheck lub inne diagnostyczne narzędzia CLI bezpośrednio; wtedy błędy wracają do pętli agenta bez tych kompromisów. Udokumentuj te komendy w plikach instrukcji, takich jak `AGENTS.md` lub skills, aby agent wiedział, co uruchomić. Włącz LSP, gdy Twój projekt korzysta z dodatkowej informacji zwrotnej z serwera językowego. --- diff --git a/packages/web/src/content/docs/pt-br/lsp.mdx b/packages/web/src/content/docs/pt-br/lsp.mdx index aff101cc6c..f89a5d3530 100644 --- a/packages/web/src/content/docs/pt-br/lsp.mdx +++ b/packages/web/src/content/docs/pt-br/lsp.mdx @@ -68,7 +68,7 @@ Quando o LSP está habilitado e o opencode abre um arquivo, ele: O LSP pode ajudar o agente a encontrar e corrigir problemas fornecendo diagnósticos dos servidores de linguagem. Isso é útil em alguns projetos, mas nem sempre é um ganho líquido. -Servidores de linguagem podem ficar fora de sincronia, usar bastante memória, variar por versão ou projeto e desacelerar fluxos de trabalho do agente. Em muitos projetos, é melhor fazer o agente executar lint, typecheck ou outras ferramentas CLI de diagnóstico diretamente, para que os erros voltem ao ciclo do agente sem essas compensações. Habilite o LSP quando seu projeto se beneficiar de feedback adicional do servidor de linguagem. +Servidores de linguagem podem ficar fora de sincronia, usar bastante memória, variar por versão ou projeto e desacelerar fluxos de trabalho do agente. Em muitos projetos, é melhor fazer o agente executar lint, typecheck ou outras ferramentas CLI de diagnóstico diretamente, para que os erros voltem ao ciclo do agente sem essas compensações. Documente esses comandos em arquivos de instruções como `AGENTS.md` ou skills, para que o agente saiba o que executar. Habilite o LSP quando seu projeto se beneficiar de feedback adicional do servidor de linguagem. --- diff --git a/packages/web/src/content/docs/ru/lsp.mdx b/packages/web/src/content/docs/ru/lsp.mdx index 738e18d967..95d7a8774a 100644 --- a/packages/web/src/content/docs/ru/lsp.mdx +++ b/packages/web/src/content/docs/ru/lsp.mdx @@ -67,7 +67,7 @@ LSP отключен по умолчанию. Когда он включен, с LSP может помочь агенту находить и исправлять проблемы, предоставляя диагностику от языковых серверов. Это полезно в некоторых проектах, но не всегда является однозначным преимуществом. -Языковые серверы могут рассинхронизироваться, потреблять много памяти, отличаться по поведению между версиями или проектами и замедлять рабочие процессы агента. Во многих проектах лучше, чтобы агент напрямую запускал lint, typecheck или другие диагностические CLI-инструменты; так ошибки возвращаются в цикл агента без этих компромиссов. Включайте LSP, когда проект получает пользу от дополнительной обратной связи языкового сервера. +Языковые серверы могут рассинхронизироваться, потреблять много памяти, отличаться по поведению между версиями или проектами и замедлять рабочие процессы агента. Во многих проектах лучше, чтобы агент напрямую запускал lint, typecheck или другие диагностические CLI-инструменты; так ошибки возвращаются в цикл агента без этих компромиссов. Задокументируйте эти команды в файлах инструкций, например `AGENTS.md` или skills, чтобы агент знал, что запускать. Включайте LSP, когда проект получает пользу от дополнительной обратной связи языкового сервера. --- diff --git a/packages/web/src/content/docs/th/lsp.mdx b/packages/web/src/content/docs/th/lsp.mdx index 1ab0d970a6..52d7980365 100644 --- a/packages/web/src/content/docs/th/lsp.mdx +++ b/packages/web/src/content/docs/th/lsp.mdx @@ -68,7 +68,7 @@ LSP ปิดใช้งานเป็นค่าเริ่มต้น เ LSP สามารถช่วยให้ agent ค้นหาและแก้ไขปัญหาโดยให้ diagnostics จากเซิร์ฟเวอร์ภาษา สิ่งนี้มีประโยชน์ในบางโปรเจ็กต์ แต่ไม่ได้เป็นผลบวกเสมอไป -เซิร์ฟเวอร์ภาษาอาจไม่ตรงกับสถานะโปรเจ็กต์ ใช้หน่วยความจำมาก แตกต่างกันตามเวอร์ชันหรือโปรเจ็กต์ และทำให้เวิร์กโฟลว์ของ agent ช้าลง ในหลายโปรเจ็กต์ การให้ agent รัน lint, typecheck หรือเครื่องมือ CLI สำหรับ diagnostics อื่นโดยตรงจะดีกว่า เพราะข้อผิดพลาดจะถูกส่งกลับเข้า loop ของ agent โดยไม่มีข้อแลกเปลี่ยนเหล่านี้ เปิดใช้งาน LSP เมื่อโปรเจ็กต์ของคุณได้ประโยชน์จาก feedback เพิ่มเติมของเซิร์ฟเวอร์ภาษา +เซิร์ฟเวอร์ภาษาอาจไม่ตรงกับสถานะโปรเจ็กต์ ใช้หน่วยความจำมาก แตกต่างกันตามเวอร์ชันหรือโปรเจ็กต์ และทำให้เวิร์กโฟลว์ของ agent ช้าลง ในหลายโปรเจ็กต์ การให้ agent รัน lint, typecheck หรือเครื่องมือ CLI สำหรับ diagnostics อื่นโดยตรงจะดีกว่า เพราะข้อผิดพลาดจะถูกส่งกลับเข้า loop ของ agent โดยไม่มีข้อแลกเปลี่ยนเหล่านี้ ระบุคำสั่งเหล่านี้ไว้ในไฟล์คำแนะนำ เช่น `AGENTS.md` หรือ skills เพื่อให้ agent รู้ว่าต้องรันอะไร เปิดใช้งาน LSP เมื่อโปรเจ็กต์ของคุณได้ประโยชน์จาก feedback เพิ่มเติมของเซิร์ฟเวอร์ภาษา --- diff --git a/packages/web/src/content/docs/tr/lsp.mdx b/packages/web/src/content/docs/tr/lsp.mdx index 18da488442..78af6cc5f1 100644 --- a/packages/web/src/content/docs/tr/lsp.mdx +++ b/packages/web/src/content/docs/tr/lsp.mdx @@ -68,7 +68,7 @@ LSP etkinleştirildiğinde ve opencode bir dosyayı açtığında: LSP, dil sunucularından tanılama sağlayarak agent'ın sorunları bulup düzeltmesine yardımcı olabilir. Bu bazı projelerde yararlıdır, ancak her zaman net bir kazanç değildir. -Dil sunucuları senkronizasyonu kaybedebilir, önemli miktarda bellek kullanabilir, sürüme veya projeye göre değişebilir ve agent iş akışlarını yavaşlatabilir. Birçok projede agent'ın lint, typecheck veya diğer tanılama CLI araçlarını doğrudan çalıştırması daha iyidir; böylece hatalar bu ödünleşimler olmadan agent döngüsüne geri beslenir. Projeniz ek dil sunucusu geri bildiriminden yararlanıyorsa LSP'yi etkinleştirin. +Dil sunucuları senkronizasyonu kaybedebilir, önemli miktarda bellek kullanabilir, sürüme veya projeye göre değişebilir ve agent iş akışlarını yavaşlatabilir. Birçok projede agent'ın lint, typecheck veya diğer tanılama CLI araçlarını doğrudan çalıştırması daha iyidir; böylece hatalar bu ödünleşimler olmadan agent döngüsüne geri beslenir. Agent'ın ne çalıştıracağını bilmesi için bu komutları `AGENTS.md` veya skills gibi talimat dosyalarında belgeleyin. Projeniz ek dil sunucusu geri bildiriminden yararlanıyorsa LSP'yi etkinleştirin. --- diff --git a/packages/web/src/content/docs/zh-cn/lsp.mdx b/packages/web/src/content/docs/zh-cn/lsp.mdx index 63b5abaf48..07466c384e 100644 --- a/packages/web/src/content/docs/zh-cn/lsp.mdx +++ b/packages/web/src/content/docs/zh-cn/lsp.mdx @@ -68,7 +68,7 @@ LSP 默认关闭。启用后,当检测到上述文件扩展名且满足相应 LSP 可以通过语言服务器诊断帮助 agent 发现并修复问题。这对某些项目很有用,但并不总是带来净收益。 -语言服务器可能与项目不同步、占用较多内存、随版本或项目表现不同,并拖慢 agent 工作流。在许多项目中,更好的做法是让 agent 直接运行 lint、typecheck 或其他诊断类 CLI 工具,这样错误会进入 agent 循环,同时避免这些权衡。当你的项目能从额外的语言服务器反馈中受益时再启用 LSP。 +语言服务器可能与项目不同步、占用较多内存、随版本或项目表现不同,并拖慢 agent 工作流。在许多项目中,更好的做法是让 agent 直接运行 lint、typecheck 或其他诊断类 CLI 工具,这样错误会进入 agent 循环,同时避免这些权衡。将这些命令记录在 `AGENTS.md` 或 skills 等指令文件中,让 agent 知道该运行什么。当你的项目能从额外的语言服务器反馈中受益时再启用 LSP。 --- diff --git a/packages/web/src/content/docs/zh-tw/lsp.mdx b/packages/web/src/content/docs/zh-tw/lsp.mdx index fbc5296129..32e1f05079 100644 --- a/packages/web/src/content/docs/zh-tw/lsp.mdx +++ b/packages/web/src/content/docs/zh-tw/lsp.mdx @@ -68,7 +68,7 @@ LSP 預設關閉。啟用後,當偵測到上述檔案副檔名且滿足相應 LSP 可以透過語言伺服器診斷幫助 agent 發現並修復問題。這對某些專案很有用,但不一定總是帶來淨收益。 -語言伺服器可能與專案不同步、佔用較多記憶體、隨版本或專案表現不同,並拖慢 agent 工作流程。在許多專案中,更好的做法是讓 agent 直接執行 lint、typecheck 或其他診斷類 CLI 工具,這樣錯誤會回到 agent 循環,同時避免這些取捨。當您的專案能從額外的語言伺服器回饋中受益時再啟用 LSP。 +語言伺服器可能與專案不同步、佔用較多記憶體、隨版本或專案表現不同,並拖慢 agent 工作流程。在許多專案中,更好的做法是讓 agent 直接執行 lint、typecheck 或其他診斷類 CLI 工具,這樣錯誤會回到 agent 循環,同時避免這些取捨。將這些指令記錄在 `AGENTS.md` 或 skills 等指示檔中,讓 agent 知道該執行什麼。當您的專案能從額外的語言伺服器回饋中受益時再啟用 LSP。 --- From 848d763d08f9cdede9604ae11e29528241b8b0fe Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 26 May 2026 21:02:02 +0200 Subject: [PATCH 34/40] Prepare TUI lifecycle for scenario tests (#28258) --- packages/opencode/src/cli/cmd/tui/app.tsx | 296 ++++++++++++------ packages/opencode/src/cli/cmd/tui/attach.ts | 7 +- .../cli/cmd/tui/component/error-component.tsx | 19 +- .../opencode/src/cli/cmd/tui/context/exit.tsx | 80 ++--- packages/opencode/src/cli/cmd/tui/thread.ts | 7 +- .../test/cli/cmd/tui/sync-fixture.tsx | 89 +----- .../test/cli/tui/app-lifecycle.test.ts | 261 +++++++++++++++ .../opencode/test/cli/tui/use-event.test.tsx | 35 +-- packages/opencode/test/fixture/tui-sdk.ts | 82 +++++ 9 files changed, 596 insertions(+), 280 deletions(-) create mode 100644 packages/opencode/test/cli/tui/app-lifecycle.test.ts create mode 100644 packages/opencode/test/fixture/tui-sdk.ts diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 530ba3ff23..b61ee80446 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -3,7 +3,7 @@ import { createDefaultOpenTuiKeymap } from "@opentui/keymap/opentui" import * as Clipboard from "@tui/util/clipboard" import * as Selection from "@tui/util/selection" import * as TuiAudio from "@tui/util/audio" -import { createCliRenderer, MouseButton, type CliRendererConfig } from "@opentui/core" +import { createCliRenderer, MouseButton, type CliRenderer, type CliRendererConfig } from "@opentui/core" import { RouteProvider, useRoute } from "@tui/context/route" import { Switch, @@ -18,7 +18,7 @@ import { Show, on, } from "solid-js" -import { win32DisableProcessedInput, win32InstallCtrlCGuard } from "./win32" +import { win32DisableProcessedInput, win32FlushInputBuffer, win32InstallCtrlCGuard } from "./win32" import { Flag } from "@opencode-ai/core/flag/flag" import semver from "semver" import { DialogProvider, useDialog } from "@tui/ui/dialog" @@ -51,7 +51,7 @@ import { PromptStashProvider } from "./component/prompt/stash" import { DialogAlert } from "./ui/dialog-alert" import { DialogConfirm } from "./ui/dialog-confirm" import { ToastProvider, useToast } from "./ui/toast" -import { ExitProvider, useExit } from "./context/exit" +import { createExit, ExitProvider, useExit, type Exit } from "./context/exit" import { Session as SessionApi } from "@/session/session" import { TuiEvent } from "./event" import { KVProvider, useKV } from "./context/kv" @@ -123,7 +123,7 @@ const appBindingCommands = [ "app.toggle.session_directory_filter", ] as const -function rendererConfig(_config: TuiConfig.Resolved): CliRendererConfig { +export function tuiRendererConfig(_config: TuiConfig.Resolved): CliRendererConfig { const mouseEnabled = !Flag.OPENCODE_DISABLE_MOUSE && (_config.mouse ?? true) return { @@ -146,6 +146,34 @@ function rendererConfig(_config: TuiConfig.Resolved): CliRendererConfig { } } +export function createTuiRenderer(config: TuiConfig.Resolved) { + return createCliRenderer(tuiRendererConfig(config)) +} + +export type TuiHandle = { + ready: Promise + done: Promise + exit: Exit +} + +type TuiInput = { + url: string + args: Args + config: TuiConfig.Resolved + renderer: CliRenderer + onSnapshot?: () => Promise + directory?: string + fetch?: typeof fetch + headers?: RequestInit["headers"] + events?: EventSource +} + +type TuiLifecycle = { + exit: Exit + exited: Promise + fail(error: unknown): Promise +} + function errorMessage(error: unknown) { const formatted = FormatError(error) if (formatted !== undefined) return formatted @@ -163,105 +191,175 @@ function errorMessage(error: unknown) { return FormatUnknownError(error) } -export function tui(input: { - url: string - args: Args - config: TuiConfig.Resolved - onSnapshot?: () => Promise - directory?: string - fetch?: typeof fetch - headers?: RequestInit["headers"] - events?: EventSource -}) { - // promise to prevent immediate exit - // oxlint-disable-next-line no-async-promise-executor -- intentional: async executor used for sequential setup before resolve - return new Promise(async (resolve) => { - const unguard = win32InstallCtrlCGuard() - win32DisableProcessedInput() +export function tui(input: TuiInput): TuiHandle { + const unguard = win32InstallCtrlCGuard() + win32DisableProcessedInput() - const onExit = async () => { - unguard?.() - resolve() - } - const onBeforeExit = async () => { - offKeymap() + const renderer = input.renderer + const keymap = createDefaultOpenTuiKeymap(renderer) + const unregisterKeymap = registerOpencodeKeymap(keymap, renderer, input.config) + const lifecycle = createTuiLifecycle({ + renderer, + unguard, + cleanup: async () => { + unregisterKeymap() await TuiPluginRuntime.dispose() TuiAudio.dispose() - } - - const renderer = await createCliRenderer(rendererConfig(input.config)) - // Prewarm palette before ThemeProvider mounts so `system` theme avoids a first-paint fallback flash. - void renderer.getPalette({ size: 16 }).catch(() => undefined) - const mode = (await renderer.waitForThemeMode(1000)) ?? "dark" - - const keymap = createDefaultOpenTuiKeymap(renderer) - const offKeymap = registerOpencodeKeymap(keymap, renderer, input.config) - - await render(() => { - return ( - ( - - )} - > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ) - }, renderer) + }, }) + const ready = mountTui({ ...input, keymap, exit: lifecycle.exit }).catch((error) => lifecycle.fail(error)) + const done = waitUntilDone(ready, lifecycle.exited) + + return { ready, done, exit: lifecycle.exit } +} + +async function mountTui(input: TuiInput & { keymap: ReturnType; exit: Exit }) { + const renderer = input.renderer + // Prewarm palette before ThemeProvider mounts so `system` theme avoids a first-paint fallback flash. + void renderer.getPalette({ size: 16 }).catch(() => undefined) + const mode = (await renderer.waitForThemeMode(1000)) ?? "dark" + if (renderer.isDestroyed) return + + await render(() => { + return ( + } + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) + }, renderer) +} + +function createTuiLifecycle(input: { + renderer: CliRenderer + unguard?: () => void + cleanup: () => Promise +}): TuiLifecycle { + let resolveExited!: () => void + const exited = new Promise((resolve) => { + resolveExited = resolve + }) + let exitCompleted = false + let exiting = false + let cleanupTask: Promise | undefined + + const completeExit = () => { + if (exitCompleted) return + exitCompleted = true + resolveExited() + } + + const cleanup = () => { + cleanupTask ??= (async () => { + process.off("SIGHUP", onSighup) + try { + await input.cleanup() + } finally { + input.unguard?.() + } + })() + return cleanupTask + } + + const exit = createExit(async (reason, message) => { + exiting = true + await cleanup() + if (!input.renderer.isDestroyed) { + input.renderer.setTerminalTitle("") + input.renderer.destroy() + } + win32FlushInputBuffer() + if (reason) { + const formatted = FormatError(reason) ?? FormatUnknownError(reason) + if (formatted) process.stderr.write(formatted + "\n") + } + const text = message() + if (text) process.stdout.write(text + "\n") + completeExit() + }) + const onSighup = () => { + void exit() + } + + input.renderer.once("destroy", () => { + if (exiting) return + void cleanup().finally(() => { + win32FlushInputBuffer() + completeExit() + }) + }) + process.on("SIGHUP", onSighup) + + return { + exit, + exited, + async fail(error) { + exiting = true + await cleanup().catch(() => {}) + if (!input.renderer.isDestroyed) input.renderer.destroy() + completeExit() + throw error + }, + } +} + +async function waitUntilDone(ready: Promise, exited: Promise) { + await ready + await exited } function App(props: { onSnapshot?: () => Promise }) { diff --git a/packages/opencode/src/cli/cmd/tui/attach.ts b/packages/opencode/src/cli/cmd/tui/attach.ts index 2897a41caf..b908887c39 100644 --- a/packages/opencode/src/cli/cmd/tui/attach.ts +++ b/packages/opencode/src/cli/cmd/tui/attach.ts @@ -67,7 +67,6 @@ export const AttachCommand = cmd({ })() const headers = ServerAuth.headers({ password: args.password, username: args.username }) const config = await TuiConfig.get() - const { tui } = await import("./app") try { await validateSession({ @@ -82,9 +81,12 @@ export const AttachCommand = cmd({ return } - await tui({ + const { createTuiRenderer, tui } = await import("./app") + const renderer = await createTuiRenderer(config) + const handle = tui({ url: args.url, config, + renderer, args: { continue: args.continue, sessionID: args.session, @@ -93,6 +95,7 @@ export const AttachCommand = cmd({ directory, headers, }) + await handle.done } finally { unguard?.() } diff --git a/packages/opencode/src/cli/cmd/tui/component/error-component.tsx b/packages/opencode/src/cli/cmd/tui/component/error-component.tsx index fcbd27ca9b..e67dc249c8 100644 --- a/packages/opencode/src/cli/cmd/tui/component/error-component.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/error-component.tsx @@ -1,32 +1,21 @@ import { TextAttributes } from "@opentui/core" -import { useKeyboard, useRenderer, useTerminalDimensions } from "@opentui/solid" +import { useKeyboard, useTerminalDimensions } from "@opentui/solid" import * as Clipboard from "@tui/util/clipboard" import { createSignal } from "solid-js" import { InstallationVersion } from "@opencode-ai/core/installation/version" -import { win32FlushInputBuffer } from "../win32" import { getScrollAcceleration } from "../util/scroll" export function ErrorComponent(props: { error: Error reset: () => void - onBeforeExit?: () => Promise - onExit: () => Promise + exit: () => Promise mode?: "dark" | "light" }) { const term = useTerminalDimensions() - const renderer = useRenderer() - - const handleExit = async () => { - await props.onBeforeExit?.() - renderer.setTerminalTitle("") - renderer.destroy() - win32FlushInputBuffer() - await props.onExit() - } useKeyboard((evt) => { if (evt.ctrl && evt.name === "c") { - void handleExit() + void props.exit() } }) const [copied, setCopied] = createSignal(false) @@ -79,7 +68,7 @@ export function ErrorComponent(props: { Reset TUI - + void props.exit()} backgroundColor={colors.primary} padding={1}> Exit diff --git a/packages/opencode/src/cli/cmd/tui/context/exit.tsx b/packages/opencode/src/cli/cmd/tui/context/exit.tsx index 205025f867..5b25a60039 100644 --- a/packages/opencode/src/cli/cmd/tui/context/exit.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/exit.tsx @@ -1,8 +1,6 @@ -import { useRenderer } from "@opentui/solid" import { createSimpleContext } from "./helper" -import { FormatError, FormatUnknownError } from "@/cli/error" -import { win32FlushInputBuffer } from "../win32" -type Exit = ((reason?: unknown) => Promise) & { + +export type Exit = ((reason?: unknown) => Promise) & { message: { set: (value?: string) => () => void clear: () => void @@ -10,51 +8,35 @@ type Exit = ((reason?: unknown) => Promise) & { } } +export function createExit(run: (reason: unknown | undefined, message: () => string | undefined) => Promise) { + let message: string | undefined + let task: Promise | undefined + const store = { + set: (value?: string) => { + const prev = message + message = value + return () => { + message = prev + } + }, + clear: () => { + message = undefined + }, + get: () => message, + } + + return Object.assign( + (reason?: unknown) => { + task ??= run(reason, store.get) + return task + }, + { + message: store, + }, + ) satisfies Exit +} + export const { use: useExit, provider: ExitProvider } = createSimpleContext({ name: "Exit", - init: (input: { onBeforeExit?: () => Promise; onExit?: () => Promise }) => { - const renderer = useRenderer() - let message: string | undefined - let task: Promise | undefined - const store = { - set: (value?: string) => { - const prev = message - message = value - return () => { - message = prev - } - }, - clear: () => { - message = undefined - }, - get: () => message, - } - const exit: Exit = Object.assign( - (reason?: unknown) => { - if (task) return task - task = (async () => { - await input.onBeforeExit?.() - // Reset window title before destroying renderer - renderer.setTerminalTitle("") - renderer.destroy() - win32FlushInputBuffer() - if (reason) { - const formatted = FormatError(reason) ?? FormatUnknownError(reason) - if (formatted) { - process.stderr.write(formatted + "\n") - } - } - const text = store.get() - if (text) process.stdout.write(text + "\n") - await input.onExit?.() - })() - return task - }, - { - message: store, - }, - ) - process.on("SIGHUP", () => exit()) - return exit - }, + init: (input: { exit: Exit }) => input.exit, }) diff --git a/packages/opencode/src/cli/cmd/tui/thread.ts b/packages/opencode/src/cli/cmd/tui/thread.ts index 7230dae16a..382147d918 100644 --- a/packages/opencode/src/cli/cmd/tui/thread.ts +++ b/packages/opencode/src/cli/cmd/tui/thread.ts @@ -228,9 +228,11 @@ export const TuiThreadCommand = cmd({ }, 1000).unref?.() try { - const { tui } = await import("./app") - await tui({ + const { createTuiRenderer, tui } = await import("./app") + const renderer = await createTuiRenderer(config) + const handle = tui({ url: transport.url, + renderer, async onSnapshot() { const tui = writeHeapSnapshot("tui.heapsnapshot") const server = await client.call("snapshot", undefined) @@ -249,6 +251,7 @@ export const TuiThreadCommand = cmd({ fork: args.fork, }, }) + await handle.done } finally { await stop() } diff --git a/packages/opencode/test/cli/cmd/tui/sync-fixture.tsx b/packages/opencode/test/cli/cmd/tui/sync-fixture.tsx index 5f51374c16..4b3c6037ea 100644 --- a/packages/opencode/test/cli/cmd/tui/sync-fixture.tsx +++ b/packages/opencode/test/cli/cmd/tui/sync-fixture.tsx @@ -2,15 +2,13 @@ import { testRender } from "@opentui/solid" import { onMount } from "solid-js" import { ArgsProvider } from "../../../../src/cli/cmd/tui/context/args" -import { ExitProvider } from "../../../../src/cli/cmd/tui/context/exit" +import { createExit, ExitProvider } from "../../../../src/cli/cmd/tui/context/exit" import { KVProvider, useKV } from "../../../../src/cli/cmd/tui/context/kv" import { ProjectProvider, useProject } from "../../../../src/cli/cmd/tui/context/project" -import { SDKProvider, type EventSource } from "../../../../src/cli/cmd/tui/context/sdk" +import { SDKProvider } from "../../../../src/cli/cmd/tui/context/sdk" import { SyncProvider, useSync } from "../../../../src/cli/cmd/tui/context/sync" -import type { GlobalEvent } from "@opencode-ai/sdk/v2" - -export const worktree = "/tmp/opencode" -export const directory = `${worktree}/packages/opencode` +import { createEventSource, createFetch, type FetchHandler, directory } from "../../../fixture/tui-sdk" +export { createEventSource, createFetch, directory, eventSource, json, worktree } from "../../../fixture/tui-sdk" export async function wait(fn: () => boolean, timeout = 2000) { const start = Date.now() @@ -20,83 +18,6 @@ export async function wait(fn: () => boolean, timeout = 2000) { } } -export function json(data: unknown, init?: ResponseInit) { - return new Response(JSON.stringify(data), { - ...init, - headers: { "content-type": "application/json", ...(init?.headers ?? {}) }, - }) -} - -export function eventSource(): EventSource { - return { subscribe: async () => () => {} } -} - -export function createEventSource() { - let fn: ((event: GlobalEvent) => void) | undefined - - return { - source: { - subscribe: async (handler: (event: GlobalEvent) => void) => { - fn = handler - return () => { - if (fn === handler) fn = undefined - } - }, - } satisfies EventSource, - emit(event: GlobalEvent) { - if (!fn) throw new Error("event source not ready") - fn(event) - }, - } -} - -type FetchHandler = (url: URL) => Response | Promise | undefined - -export function createFetch(override?: FetchHandler) { - const session = [] as URL[] - const fetch = (async (input: RequestInfo | URL) => { - const url = new URL(input instanceof Request ? input.url : String(input)) - if (url.pathname === "/session") session.push(url) - - const overridden = await override?.(url) - if (overridden) return overridden - - switch (url.pathname) { - case "/agent": - case "/command": - case "/experimental/workspace": - case "/experimental/workspace/status": - case "/formatter": - case "/lsp": - return json([]) - case "/config": - case "/experimental/resource": - case "/mcp": - case "/provider/auth": - case "/session/status": - return json({}) - case "/config/providers": - return json({ providers: {}, default: {} }) - case "/experimental/console": - return json({ consoleManagedProviders: [], switchableOrgCount: 0 }) - case "/path": - return json({ home: "", state: "", config: "", worktree, directory }) - case "/project/current": - return json({ id: "proj_test" }) - case "/provider": - return json({ all: [], default: {}, connected: [] }) - case "/session": - return json([]) - case "/vcs": - return json({ branch: "main" }) - } - - throw new Error(`unexpected request: ${url.pathname}`) - }) as typeof globalThis.fetch - - return { fetch, session } -} - type Ctx = { kv: ReturnType; project: ReturnType; sync: ReturnType } export async function mount(override?: FetchHandler) { @@ -123,7 +44,7 @@ export async function mount(override?: FetchHandler) { const app = await testRender(() => ( - + {})}> diff --git a/packages/opencode/test/cli/tui/app-lifecycle.test.ts b/packages/opencode/test/cli/tui/app-lifecycle.test.ts new file mode 100644 index 0000000000..8f5cb52346 --- /dev/null +++ b/packages/opencode/test/cli/tui/app-lifecycle.test.ts @@ -0,0 +1,261 @@ +import { afterEach, expect, spyOn, test } from "bun:test" +import { createTestRenderer } from "@opentui/core/testing" +import { mkdir } from "node:fs/promises" +import path from "node:path" +import { tmpdir } from "../../fixture/fixture" +import { createTuiResolvedConfig } from "../../fixture/tui-runtime" +import { TuiPluginRuntime } from "../../../src/cli/cmd/tui/plugin/runtime" +import { tui, type TuiHandle } from "../../../src/cli/cmd/tui/app" +import { Global } from "@opencode-ai/core/global" +import { createEventSource, createFetch, directory } from "../../fixture/tui-sdk" +import * as TuiAudio from "../../../src/cli/cmd/tui/util/audio" +import * as TuiKeymap from "../../../src/cli/cmd/tui/keymap" + +type TestRendererSetup = Awaited> +type TmpDir = Awaited> + +const disabledInternalPlugins = { + "internal:home-footer": false, + "internal:home-tips": false, + "internal:sidebar-context": false, + "internal:sidebar-mcp": false, + "internal:sidebar-lsp": false, + "internal:sidebar-todo": false, + "internal:sidebar-files": false, + "internal:sidebar-footer": false, + "internal:plugin-manager": false, + "internal:session-v2-debug": false, + "which-key": false, +} +let active: { handle?: TuiHandle; setup?: TestRendererSetup; restore?: () => void; tmp?: TmpDir } | undefined + +afterEach(async () => { + const current = active + active = undefined + await current?.handle?.exit().catch(() => {}) + await current?.handle?.done.catch(() => {}) + await current?.handle?.ready.catch(() => {}) + if (current?.setup && !current.setup.renderer.isDestroyed) current.setup.renderer.destroy() + current?.restore?.() + await Bun.sleep(20) + await current?.tmp?.[Symbol.asyncDispose]() + await TuiPluginRuntime.dispose().catch(() => {}) +}) + +test("returns a handle immediately and resolves ready after async mount setup", async () => { + const app = await startTui() + + expect(await promiseState(app.handle.ready)).toBe("pending") + + app.theme.resolve("dark") + await app.handle.ready + + expect(app.setup.renderer.isDestroyed).toBe(false) + expect(await promiseState(app.handle.done)).toBe("pending") +}) + +test("production can await done only and still receives mount failures", async () => { + const app = await startTui({ rejectTheme: new Error("theme failed") }) + + await expect(app.handle.done).rejects.toThrow("theme failed") + expect(app.setup.renderer.isDestroyed).toBe(true) +}) + +test("exit destroys the renderer, resolves done, and runs cleanup once", async () => { + const beforeSighup = process.listenerCount("SIGHUP") + const app = await startTui() + + app.theme.resolve("dark") + await app.handle.ready + expect(process.listenerCount("SIGHUP")).toBeGreaterThan(beforeSighup) + + await Promise.all([app.handle.exit(), app.handle.exit()]) + await app.handle.done + + expect(app.setup.renderer.isDestroyed).toBe(true) + expect(process.listenerCount("SIGHUP")).toBe(beforeSighup) +}) + +test("exit preserves reason formatting and exit messages", async () => { + const stdout: string[] = [] + const stderr: string[] = [] + const stdoutWrite = spyOn(process.stdout, "write").mockImplementation((chunk: string | Uint8Array) => { + stdout.push(String(chunk)) + return true + }) + const stderrWrite = spyOn(process.stderr, "write").mockImplementation((chunk: string | Uint8Array) => { + stderr.push(String(chunk)) + return true + }) + + try { + const app = await startTui() + app.theme.resolve("dark") + await app.handle.ready + + app.handle.exit.message.set("goodbye") + await app.handle.exit(new Error("boom")) + await app.handle.done + + expect(stderr.join("")).toContain("boom") + expect(stdout.join("")).toBe("goodbye\n") + } finally { + stdoutWrite.mockRestore() + stderrWrite.mockRestore() + } +}) + +test("exit before ready cancels mount and resolves done", async () => { + const app = await startTui() + + await app.handle.exit() + await app.handle.done + + expect(app.setup.renderer.isDestroyed).toBe(true) + await expect(app.handle.ready).resolves.toBeUndefined() +}) + +test("direct renderer destruction still cleans up and resolves done", async () => { + const beforeSighup = process.listenerCount("SIGHUP") + const app = await startTui() + + app.theme.resolve("dark") + await app.handle.ready + app.setup.renderer.destroy() + await app.handle.done + + expect(process.listenerCount("SIGHUP")).toBe(beforeSighup) +}) + +test("SIGHUP exits before ready and removes its listener", async () => { + const beforeSighup = process.listenerCount("SIGHUP") + const app = await startTui() + + process.emit("SIGHUP") + await app.handle.done + + expect(app.setup.renderer.isDestroyed).toBe(true) + expect(process.listenerCount("SIGHUP")).toBe(beforeSighup) +}) + +test("SIGHUP exits after ready and removes its listener", async () => { + const beforeSighup = process.listenerCount("SIGHUP") + const app = await startTui() + + app.theme.resolve("dark") + await app.handle.ready + process.emit("SIGHUP") + await app.handle.done + + expect(app.setup.renderer.isDestroyed).toBe(true) + expect(process.listenerCount("SIGHUP")).toBe(beforeSighup) +}) + +test("plugin, audio, and keymap cleanup run exactly once", async () => { + const originalRegister = TuiKeymap.registerOpencodeKeymap + let unregisterKeymapCalls = 0 + const registerKeymap = spyOn(TuiKeymap, "registerOpencodeKeymap").mockImplementation((...args) => { + const unregister = originalRegister(...args) + return () => { + unregisterKeymapCalls++ + unregister() + } + }) + const disposePlugins = spyOn(TuiPluginRuntime, "dispose") + const disposeAudio = spyOn(TuiAudio, "dispose") + + try { + const app = await startTui() + app.theme.resolve("dark") + await app.handle.ready + + app.setup.renderer.destroy() + await Promise.all([app.handle.exit(), app.handle.exit()]) + await app.handle.done + + expect(registerKeymap).toHaveBeenCalledTimes(1) + expect(unregisterKeymapCalls).toBe(1) + expect(disposePlugins).toHaveBeenCalledTimes(1) + expect(disposeAudio).toHaveBeenCalledTimes(1) + } finally { + registerKeymap.mockRestore() + disposePlugins.mockRestore() + disposeAudio.mockRestore() + } +}) + +async function startTui(options: { rejectTheme?: Error } = {}) { + const tmp = await tmpdir() + const restore = await isolateGlobalPaths(tmp.path) + const setup = await createTestRenderer({ width: 80, height: 24, useThread: false, maxFps: Number.POSITIVE_INFINITY }) + const theme = deferred<"dark" | "light" | null>() + const waitForThemeMode = spyOn(setup.renderer, "waitForThemeMode").mockImplementation(() => { + if (options.rejectTheme) return Promise.reject(options.rejectTheme) + return theme.promise + }) + setup.renderer.once("destroy", () => theme.resolve(null)) + + const calls = createFetch() + const events = createEventSource() + const handle = tui({ + url: "http://test", + renderer: setup.renderer, + config: createTuiResolvedConfig({ plugin_enabled: disabledInternalPlugins }), + directory, + fetch: calls.fetch, + events: events.source, + args: {}, + }) + active = { + handle, + setup, + tmp, + restore: () => { + waitForThemeMode.mockRestore() + restore() + }, + } + + return { handle, setup, theme } +} + +async function isolateGlobalPaths(root: string) { + const previous = { + config: Global.Path.config, + state: Global.Path.state, + } + Global.Path.config = path.join(root, "config") + Global.Path.state = path.join(root, "state") + await mkdir(Global.Path.config, { recursive: true }) + await mkdir(Global.Path.state, { recursive: true }) + await Bun.write(path.join(Global.Path.state, "kv.json"), JSON.stringify({ animations_enabled: false })) + + return () => { + Global.Path.config = previous.config + Global.Path.state = previous.state + } +} + +async function promiseState(promise: Promise) { + let state: "pending" | "resolved" | "rejected" = "pending" + promise.then( + () => { + state = "resolved" + }, + () => { + state = "rejected" + }, + ) + await Promise.resolve() + return state +} + +function deferred() { + let resolve!: (value: T | PromiseLike) => void + let reject!: (error: unknown) => void + const promise = new Promise((done, fail) => { + resolve = done + reject = fail + }) + return { promise, resolve, reject } +} diff --git a/packages/opencode/test/cli/tui/use-event.test.tsx b/packages/opencode/test/cli/tui/use-event.test.tsx index d690cfd6ce..2aa3e97812 100644 --- a/packages/opencode/test/cli/tui/use-event.test.tsx +++ b/packages/opencode/test/cli/tui/use-event.test.tsx @@ -6,6 +6,7 @@ import { onMount } from "solid-js" import { ProjectProvider, useProject } from "../../../src/cli/cmd/tui/context/project" import { SDKProvider } from "../../../src/cli/cmd/tui/context/sdk" import { useEvent } from "../../../src/cli/cmd/tui/context/event" +import { createEventSource, createFetch, directory } from "../../fixture/tui-sdk" const projectID = "proj_test" @@ -46,35 +47,11 @@ function update(version: string): Event { } } -function createSource() { - let fn: ((event: GlobalEvent) => void) | undefined - - return { - source: { - subscribe: async (handler: (event: GlobalEvent) => void) => { - fn = handler - return () => { - if (fn === handler) fn = undefined - } - }, - }, - emit(evt: GlobalEvent) { - if (!fn) throw new Error("event source not ready") - fn(evt) - }, - } -} - async function mount() { - const source = createSource() + const events = createEventSource() + const calls = createFetch() const seen: Event[] = [] const workspaces: Array = [] - const fetch = (async (input: RequestInfo | URL) => { - const url = new URL(input instanceof Request ? input.url : String(input)) - if (url.pathname === "/path") return Response.json({ home: "", state: "", config: "", directory: "/tmp/root" }) - if (url.pathname === "/project/current") return Response.json({ id: projectID }) - throw new Error(`unexpected request: ${url.pathname}`) - }) as typeof globalThis.fetch let project!: ReturnType let done!: () => void const ready = new Promise((resolve) => { @@ -82,7 +59,7 @@ async function mount() { }) const app = await testRender(() => ( - + { @@ -98,7 +75,7 @@ async function mount() { )) await ready - return { app, emit: source.emit, project, seen, workspaces } + return { app, emit: events.emit, project, seen, workspaces } } function Probe(props: { @@ -140,7 +117,7 @@ describe("useEvent", () => { const { app, emit, seen } = await mount() try { - emit(event(vcs("other"), { directory: "/tmp/root", project: "proj_other" })) + emit(event(vcs("other"), { directory, project: "proj_other" })) await Bun.sleep(30) expect(seen).toHaveLength(0) diff --git a/packages/opencode/test/fixture/tui-sdk.ts b/packages/opencode/test/fixture/tui-sdk.ts new file mode 100644 index 0000000000..cf59222a15 --- /dev/null +++ b/packages/opencode/test/fixture/tui-sdk.ts @@ -0,0 +1,82 @@ +import type { GlobalEvent } from "@opencode-ai/sdk/v2" +import type { EventSource } from "../../src/cli/cmd/tui/context/sdk" + +export const worktree = "/tmp/opencode" +export const directory = `${worktree}/packages/opencode` + +export function json(data: unknown, init?: ResponseInit) { + return new Response(JSON.stringify(data), { + ...init, + headers: { "content-type": "application/json", ...(init?.headers ?? {}) }, + }) +} + +export function eventSource(): EventSource { + return { subscribe: async () => () => {} } +} + +export function createEventSource() { + let fn: ((event: GlobalEvent) => void) | undefined + + return { + source: { + subscribe: async (handler: (event: GlobalEvent) => void) => { + fn = handler + return () => { + if (fn === handler) fn = undefined + } + }, + } satisfies EventSource, + emit(event: GlobalEvent) { + if (!fn) throw new Error("event source not ready") + fn(event) + }, + } +} + +export type FetchHandler = (url: URL) => Response | Promise | undefined + +export function createFetch(override?: FetchHandler) { + const session = [] as URL[] + const fetch = (async (input: RequestInfo | URL) => { + const url = new URL(input instanceof Request ? input.url : String(input)) + if (url.pathname === "/session") session.push(url) + + const overridden = await override?.(url) + if (overridden) return overridden + + switch (url.pathname) { + case "/agent": + case "/command": + case "/experimental/workspace": + case "/experimental/workspace/status": + case "/formatter": + case "/lsp": + return json([]) + case "/config": + case "/experimental/resource": + case "/mcp": + case "/provider/auth": + case "/session/status": + return json({}) + case "/config/providers": + return json({ providers: {}, default: {} }) + case "/experimental/console": + return json({ consoleManagedProviders: [], switchableOrgCount: 0 }) + case "/path": + return json({ home: "", state: "", config: "", worktree, directory }) + case "/project/current": + return json({ id: "proj_test" }) + case "/provider": + return json({ all: [], default: {}, connected: [] }) + case "/session": + return json([]) + case "/vcs": + return json({ branch: "main" }) + } + + throw new Error(`unexpected request: ${url.pathname}`) + }) as typeof globalThis.fetch + + return { fetch, session } +} From 0448a3082132cd05dd91e80ff2a93b465ef4c872 Mon Sep 17 00:00:00 2001 From: Musa Date: Tue, 26 May 2026 12:20:25 -0700 Subject: [PATCH 35/40] fix(digitalocean): use OAuth token directly for inference instead of creating MAK (#28897) Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Co-authored-by: Aiden Cline Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../cli/cmd/tui/component/dialog-provider.tsx | 7 +++ packages/opencode/src/plugin/digitalocean.ts | 54 ++++++------------- packages/web/src/content/docs/providers.mdx | 8 ++- 3 files changed, 30 insertions(+), 39 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx index 2caa67b559..874afa05b4 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx @@ -262,6 +262,13 @@ function AutoMethod(props: AutoMethodProps) { method: props.index, }) if (result.error) { + toast.show({ + variant: "error", + message: + "name" in result.error && result.error.name === "ProviderAuthOauthCallbackFailed" + ? "OAuth authorization failed. Try /connect again." + : JSON.stringify(result.error), + }) dialog.clear() return } diff --git a/packages/opencode/src/plugin/digitalocean.ts b/packages/opencode/src/plugin/digitalocean.ts index 19d1364875..d04437a4ea 100644 --- a/packages/opencode/src/plugin/digitalocean.ts +++ b/packages/opencode/src/plugin/digitalocean.ts @@ -3,18 +3,20 @@ import type { Model } from "@opencode-ai/sdk/v2" import * as Log from "@opencode-ai/core/util/log" import { InstallationVersion } from "@opencode-ai/core/installation/version" import { createServer } from "http" +import open from "open" const log = Log.create({ service: "plugin.digitalocean" }) const DO_OAUTH_CLIENT_ID = "b1a6c5158156caac821fd1b30253ca8acb52454a48fa744420e41889cb589f82" const DO_AUTHORIZE_URL = "https://cloud.digitalocean.com/v1/oauth/authorize" const DO_API_BASE = "https://api.digitalocean.com" +const DO_GENAI_API = `${DO_API_BASE}/v2/gen-ai` const DO_INFERENCE_BASE = "https://inference.do-ai.run/v1" const OAUTH_PORT = 1456 const OAUTH_REDIRECT_PATH = "/auth/callback" const OAUTH_TOKEN_PATH = "/auth/token" const ROUTER_REFRESH_INTERVAL_MS = 5 * 60 * 1000 -const MAK_NAME_PREFIX = "opencode-oauth" +const OAUTH_SCOPES = "genai:read inference:query" interface ImplicitTokenPayload { access_token: string @@ -28,12 +30,6 @@ interface PendingOAuth { reject: (error: Error) => void } -interface ApiKeyInfo { - uuid: string - name: string - secret_key: string -} - interface RouterEntry { name: string uuid?: string @@ -59,7 +55,7 @@ function buildAuthorizeUrl(state: string): string { response_type: "token", client_id: DO_OAUTH_CLIENT_ID, redirect_uri: redirectUri(), - scope: "genai:create genai:read", + scope: OAUTH_SCOPES, state, }) return `${DO_AUTHORIZE_URL}?${params.toString()}` @@ -91,15 +87,20 @@ const HTML_CALLBACK = ` const errorDescription = params.get("error_description") || search.get("error_description") const titleEl = document.getElementById("title") const msgEl = document.getElementById("msg") + const tokenUrl = new URL(${JSON.stringify(OAUTH_TOKEN_PATH)}, window.location.origin).href try { const body = error ? { error, error_description: errorDescription || "" } : { access_token: params.get("access_token") || "", expires_in: params.get("expires_in") || "0", state: params.get("state") || "" } - await fetch(${JSON.stringify(OAUTH_TOKEN_PATH)}, { + const res = await fetch(tokenUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }) + if (!res.ok) { + const detail = await res.text().catch(function () { return "" }) + throw new Error(detail || ("callback failed (" + res.status + ")")) + } if (error) { titleEl.textContent = "Authorization Failed" msgEl.textContent = errorDescription || error @@ -225,31 +226,10 @@ function waitForOAuthCallback(state: string): Promise { }) } -async function createModelAccessKey(bearer: string): Promise { - // Suffix-on-collision strategy keeps re-`/connect` non-destructive. - const name = `${MAK_NAME_PREFIX}-${Math.floor(Date.now() / 1000)}` - const res = await fetch(`${DO_API_BASE}/v2/gen-ai/models/api_keys`, { - method: "POST", - headers: { - Authorization: `Bearer ${bearer}`, - "Content-Type": "application/json", - "User-Agent": `opencode/${InstallationVersion}`, - }, - body: JSON.stringify({ name }), - }) - if (!res.ok) { - const body = await res.text().catch(() => "") - throw new Error(`Failed to create Model Access Key (${res.status}): ${body}`) - } - const data = (await res.json()) as { api_key_info?: ApiKeyInfo } - if (!data.api_key_info?.secret_key) throw new Error("Model Access Key response missing secret_key") - return data.api_key_info -} - async function listRouters( bearer: string, ): Promise<{ ok: true; routers: RouterEntry[] } | { ok: false; status: number }> { - const res = await fetch(`${DO_API_BASE}/v2/gen-ai/models/routers`, { + const res = await fetch(`${DO_GENAI_API}/models/routers`, { headers: { Authorization: `Bearer ${bearer}`, Accept: "application/json", @@ -362,15 +342,16 @@ export async function DigitalOceanAuthPlugin(input: PluginInput): Promise await startOAuthServer() const state = generateState() const callbackPromise = waitForOAuthCallback(state) + const url = buildAuthorizeUrl(state) + await open(url).catch(() => undefined) return { - url: buildAuthorizeUrl(state), + url, instructions: - "Sign in to DigitalOcean in your browser. OpenCode will create a Model Access Key named opencode-oauth-* and load your Inference Routers. Re-run /connect to refresh routers later.", + "Sign in to DigitalOcean in your browser. OpenCode will use your DigitalOcean API token directly for inference and load your Inference Routers. Re-run /connect to refresh routers later.", method: "auto" as const, async callback() { try { const tokens = await callbackPromise - const apiKeyInfo = await createModelAccessKey(tokens.access_token) const routerResult = await listRouters(tokens.access_token) const routers = routerResult.ok ? routerResult.routers : [] if (!routerResult.ok) { @@ -379,12 +360,11 @@ export async function DigitalOceanAuthPlugin(input: PluginInput): Promise return { type: "success" as const, provider: "digitalocean", - key: apiKeyInfo.secret_key, + key: tokens.access_token, metadata: { - mak_uuid: apiKeyInfo.uuid, - mak_name: apiKeyInfo.name, oauth_access: tokens.access_token, oauth_expires: String(Date.now() + tokens.expires_in * 1000), + oauth_scopes: OAUTH_SCOPES, routers: JSON.stringify( routers.map((r) => ({ name: r.name, uuid: r.uuid, description: r.description })), ), diff --git a/packages/web/src/content/docs/providers.mdx b/packages/web/src/content/docs/providers.mdx index fd25227712..f5c2160daa 100644 --- a/packages/web/src/content/docs/providers.mdx +++ b/packages/web/src/content/docs/providers.mdx @@ -727,7 +727,7 @@ DigitalOcean's [Inference Engine](https://docs.digitalocean.com/products/inferen OpenCode supports two authentication methods: -- **OAuth (Recommended)** — Sign in to your DigitalOcean account; OpenCode auto-creates a Model Access Key and discovers your available Models & Inference Routers. +- **OAuth (Recommended)** — Sign in to your DigitalOcean account; OpenCode uses your DigitalOcean API token directly for inference and discovers your Inference Routers. - **Model Access Key** — Paste an existing key from the DigitalOcean console. #### OAuth (Recommended) @@ -751,7 +751,11 @@ OpenCode supports two authentication methods: 3. Your browser opens to authorize OpenCode. Sign in and approve. :::note - OpenCode creates a Model Access Key named `opencode-oauth-` in your DigitalOcean account. You can rotate or revoke it from the **Model Access Keys** page in the "Manage" section of the DigitalOcean console under Inference. + OpenCode requests `genai:read` and `inference:query` OAuth scopes. Your DigitalOcean API token is used directly for inference — no separate Model Access Key is created. + ::: + + :::note + Inference Routers only appear in the model picker after OAuth. Pasting a Model Access Key manually does not discover routers. ::: 4. Run the `/models` command. Your Inference Routers appear as the format `router:` in the model selection. From 0ba1081cf1a1cadaedb56f9e2731941c65288b07 Mon Sep 17 00:00:00 2001 From: James Long Date: Tue, 26 May 2026 16:53:13 -0400 Subject: [PATCH 36/40] fix(tui): accelerate diff viewer scrolling (#29453) --- .../src/cli/cmd/tui/feature-plugins/system/diff-viewer.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer.tsx b/packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer.tsx index 924bbd7eb3..614408bcec 100644 --- a/packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer.tsx +++ b/packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer.tsx @@ -11,6 +11,7 @@ import { createEffect, createMemo, createResource, createSignal, For, Match, onC import { DiffViewerFileTree } from "./diff-viewer-file-tree" import { Panel, PanelGroup, Separator } from "./diff-viewer-ui" import { DialogSelect } from "@tui/ui/dialog-select" +import { getScrollAcceleration } from "@tui/util/scroll" import { allExpandedFileTreeDirectories, buildFileTree, @@ -133,6 +134,7 @@ function DiffViewer(props: { api: TuiPluginApi }) { const [activePatchFileIndex, setActivePatchFileIndex] = createSignal() const [selectedFileIndex, setSelectedFileIndex] = createSignal() const [reviewedFileNames, setReviewedFileNames] = createSignal>(new Set()) + const patchScrollAcceleration = createMemo(() => getScrollAcceleration(props.api.tuiConfig)) const fileRows = createMemo(() => flattenFileTree(fileTree(), expandedFileNodes())) const patchFileIndexes = createMemo(() => orderedPatchFileIndexes(flattenFileTree(fileTree()))) const focusRunner = (input: Record void>) => () => input[focus()]() @@ -713,6 +715,7 @@ function DiffViewer(props: { api: TuiPluginApi }) { ref={(element: ScrollBoxRenderable) => (scroll = element)} flexGrow={1} minHeight={0} + scrollAcceleration={patchScrollAcceleration()} verticalScrollbarOptions={{ visible: false }} horizontalScrollbarOptions={{ visible: false }} > From 00a6f228f2f9537e0efa6c4f1f47e4dcf4c3cab0 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 26 May 2026 17:48:19 -0400 Subject: [PATCH 37/40] fix(project): preserve cached project identity --- packages/core/src/project.ts | 2 +- packages/core/test/project.test.ts | 40 ++------- .../opencode/test/project/project.test.ts | 86 ++----------------- 3 files changed, 12 insertions(+), 116 deletions(-) diff --git a/packages/core/src/project.ts b/packages/core/src/project.ts index 9c265d75be..e25dd16122 100644 --- a/packages/core/src/project.ts +++ b/packages/core/src/project.ts @@ -108,7 +108,7 @@ export const layer = Layer.effect( if (!repo) return { id: ID.global, directory: input, vcs: undefined } const previous = yield* cached(repo.store) - const id = (yield* remote(repo)) ?? previous ?? (yield* root(repo)) + const id = previous ?? (yield* root(repo)) return { previous, diff --git a/packages/core/test/project.test.ts b/packages/core/test/project.test.ts index c5b96b6389..a6d192bb1d 100644 --- a/packages/core/test/project.test.ts +++ b/packages/core/test/project.test.ts @@ -5,16 +5,11 @@ import path from "path" import { Effect } from "effect" import { Project } from "@opencode-ai/core/project" import { AbsolutePath } from "@opencode-ai/core/schema" -import { Hash } from "@opencode-ai/core/util/hash" import { tmpdir } from "./fixture/tmpdir" import { testEffect } from "./lib/effect" const it = testEffect(Project.defaultLayer) -function remoteID(remote: string) { - return Project.ID.make(Hash.fast(`git-remote:${remote}`)) -} - function abs(value: string) { return AbsolutePath.make(value) } @@ -91,7 +86,7 @@ describe("ProjectV2.resolve", () => { }), ) - it.live("prefers normalized origin over root commit", () => + it.live("uses root commit when origin exists", () => Effect.gen(function* () { const tmp = yield* Effect.acquireRelease( Effect.promise(() => tmpdir()), @@ -102,36 +97,13 @@ describe("ProjectV2.resolve", () => { const result = yield* project.resolve(abs(tmp.path)) - expect(result.id).toBe(remoteID("github.com/Acme/App")) - expect(result.id).not.toBe(Project.ID.make(yield* Effect.promise(() => rootCommit(tmp.path)))) + expect(result.id).toBe(Project.ID.make(yield* Effect.promise(() => rootCommit(tmp.path)))) expect(result.directory).toBe(yield* real(tmp.path)) expect(result.vcs?.type).toBe("git") }), ) - it.live("normalizes ssh and https remotes to the same id", () => - Effect.gen(function* () { - const ssh = yield* Effect.acquireRelease( - Effect.promise(() => tmpdir()), - (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()), - ) - const https = yield* Effect.acquireRelease( - Effect.promise(() => tmpdir()), - (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()), - ) - yield* Effect.promise(() => initRepo(ssh.path, { commit: true, remote: "git@github.com:owner/repo.git" })) - yield* Effect.promise(() => initRepo(https.path, { commit: true, remote: "https://github.com/owner/repo.git" })) - const project = yield* Project.Service - - const a = yield* project.resolve(abs(ssh.path)) - const b = yield* project.resolve(abs(https.path)) - - expect(a.id).toBe(remoteID("github.com/owner/repo")) - expect(b.id).toBe(a.id) - }), - ) - - it.live("ignores file remotes and falls back to root commit", () => + it.live("uses root commit when local remote exists", () => Effect.gen(function* () { const tmp = yield* Effect.acquireRelease( Effect.promise(() => tmpdir()), @@ -146,7 +118,7 @@ describe("ProjectV2.resolve", () => { }), ) - it.live("returns previous cached id from common dir", () => + it.live("prefers previous cached id over origin", () => Effect.gen(function* () { const tmp = yield* Effect.acquireRelease( Effect.promise(() => tmpdir()), @@ -159,7 +131,7 @@ describe("ProjectV2.resolve", () => { const result = yield* project.resolve(abs(tmp.path)) expect(result.previous).toBe(Project.ID.make("old-id")) - expect(result.id).toBe(remoteID("github.com/owner/repo")) + expect(result.id).toBe(Project.ID.make("old-id")) }), ) @@ -213,7 +185,7 @@ describe("ProjectV2.resolve", () => { expect(result.directory).toBe(yield* real(worktree)) expect(result.previous).toBe(Project.ID.make("old-id")) - expect(result.id).toBe(remoteID("github.com/owner/repo")) + expect(result.id).toBe(Project.ID.make("old-id")) expect(result.vcs?.type).toBe("git") }), ) diff --git a/packages/opencode/test/project/project.test.ts b/packages/opencode/test/project/project.test.ts index 869326d87a..e636fef90e 100644 --- a/packages/opencode/test/project/project.test.ts +++ b/packages/opencode/test/project/project.test.ts @@ -7,15 +7,6 @@ import path from "path" import { tmpdirScoped } from "../fixture/fixture" import { GlobalBus } from "../../src/bus/global" import { ProjectID } from "../../src/project/schema" -import { Database } from "@/storage/db" -import { ProjectTable } from "@/project/project.sql" -import { SessionTable } from "@/session/session.sql" -import { PermissionTable } from "@/session/session.sql" -import { WorkspaceTable } from "@/control-plane/workspace.sql" -import { eq } from "drizzle-orm" -import { Hash } from "@opencode-ai/core/util/hash" -import { SessionID } from "@/session/schema" -import { WorkspaceID } from "@/control-plane/schema" import { Cause, Effect, Exit, Layer, Stream } from "effect" import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" import { NodePath } from "@effect/platform-node" @@ -40,10 +31,6 @@ function run(fn: (svc: Project.Interface) => Effect.Effect) { }) } -function remoteProjectID(remote: string) { - return ProjectID.make(Hash.fast(`git-remote:${remote}`)) -} - /** * Creates a mock ChildProcessSpawner layer that intercepts git subcommands * matching `failArg` and returns exit code 128, while delegating everything @@ -167,91 +154,28 @@ describe("Project.fromDirectory", () => { }), ) - it.live("prefers normalized origin remote over root commit", () => + it.live("keeps root commit identity when origin exists", () => Effect.gen(function* () { const tmp = yield* tmpdirScoped({ git: true }) yield* Effect.promise(() => $`git remote add origin git@github.com:Test-Org/Test-Repo.git`.cwd(tmp).quiet()) const { project } = yield* run((svc) => svc.fromDirectory(tmp)) + const root = (yield* Effect.promise(() => $`git rev-list --max-parents=0 HEAD`.cwd(tmp).text())).trim() - expect(project.id).toBe(remoteProjectID("github.com/Test-Org/Test-Repo")) + expect(project.id).toBe(ProjectID.make(root)) }), ) - it.live("normalizes equivalent origin URL forms to the same project ID", () => - Effect.gen(function* () { - const ssh = yield* tmpdirScoped({ git: true }) - const https = yield* tmpdirScoped({ git: true }) - yield* Effect.promise(() => $`git remote add origin git@github.com:owner/repo.git`.cwd(ssh).quiet()) - yield* Effect.promise(() => $`git remote add origin https://github.com/owner/repo.git`.cwd(https).quiet()) - - const { project: a } = yield* run((svc) => svc.fromDirectory(ssh)) - const { project: b } = yield* run((svc) => svc.fromDirectory(https)) - - expect(a.id).toBe(remoteProjectID("github.com/owner/repo")) - expect(b.id).toBe(a.id) - }), - ) - - it.live("migrates cached root project data when origin becomes available", () => + it.live("keeps cached project identity when origin becomes available", () => Effect.gen(function* () { const tmp = yield* tmpdirScoped({ git: true }) const projects = yield* Project.Service const { project: rootProject } = yield* projects.fromDirectory(tmp) - const remoteID = remoteProjectID("github.com/acme/app") - const sessionID = crypto.randomUUID() as SessionID - const workspaceID = WorkspaceID.ascending() - - yield* Effect.sync(() => { - Database.use((db) => { - db.insert(SessionTable) - .values({ - id: sessionID, - project_id: rootProject.id, - slug: sessionID, - directory: tmp, - title: "test", - version: "0.0.0-test", - time_created: Date.now(), - time_updated: Date.now(), - }) - .run() - db.insert(PermissionTable) - .values({ - project_id: rootProject.id, - data: [{ permission: "edit", pattern: "*", action: "allow" }], - time_created: Date.now(), - time_updated: Date.now(), - }) - .run() - db.insert(WorkspaceTable) - .values({ - id: workspaceID, - type: "local", - name: "test", - project_id: rootProject.id, - }) - .run() - }) - }) yield* Effect.promise(() => $`git remote add origin git@github.com:acme/app.git`.cwd(tmp).quiet()) const { project } = yield* projects.fromDirectory(tmp) - expect(project.id).toBe(remoteID) - expect( - Database.use((db) => db.select().from(ProjectTable).where(eq(ProjectTable.id, rootProject.id)).get()), - ).toBeUndefined() - expect( - Database.use((db) => db.select().from(SessionTable).where(eq(SessionTable.id, sessionID)).get())?.project_id, - ).toBe(remoteID) - expect( - Database.use((db) => db.select().from(PermissionTable).where(eq(PermissionTable.project_id, remoteID)).get()), - ).toBeDefined() - expect( - Database.use((db) => db.select().from(WorkspaceTable).where(eq(WorkspaceTable.id, workspaceID)).get()) - ?.project_id, - ).toBe(remoteID) + expect(project.id).toBe(rootProject.id) }), ) }) From 0e669bbd18fd1a9beffb8d1cf7436bbec20d3a7d Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 26 May 2026 18:49:10 -0400 Subject: [PATCH 38/40] zen: disable models --- packages/console/app/src/routes/zen/util/handler.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/console/app/src/routes/zen/util/handler.ts b/packages/console/app/src/routes/zen/util/handler.ts index 0434f9100b..dac287551f 100644 --- a/packages/console/app/src/routes/zen/util/handler.ts +++ b/packages/console/app/src/routes/zen/util/handler.ts @@ -483,27 +483,29 @@ export async function handler( modelTpsLimits: Record | undefined, ) { const modelProvider = (() => { + const allProviders = modelInfo.providers.filter((provider) => !provider.disabled) + // Byok is top priority b/c if user set their own API key, we should use it // instead of using the sticky provider for the same session if (authInfo?.provider?.credentials) { - return modelInfo.providers.find((provider) => provider.id === modelInfo.byokProvider) + return allProviders.find((provider) => provider.id === modelInfo.byokProvider) } // Always use the same provider for the same session if (stickyProvider) { - const provider = modelInfo.providers.find((provider) => provider.id === stickyProvider) + const provider = allProviders.find((provider) => provider.id === stickyProvider) if (provider) return provider } if (trialProviders) { const trialProvider = trialProviders[Math.floor(Math.random() * trialProviders.length)] - const provider = modelInfo.providers.find((provider) => provider.id === trialProvider) + const provider = allProviders.find((provider) => provider.id === trialProvider) if (provider) return provider } if (retry.retryCount !== MAX_FAILOVER_RETRIES) { let topPriority = Infinity - const providers = modelInfo.providers + const providers = allProviders .filter((provider) => !provider.disabled) .filter((provider) => provider.weight !== 0) .filter((provider) => !retry.excludeProviders.includes(provider.id)) @@ -536,7 +538,7 @@ export async function handler( } // fallback provider - return modelInfo.providers.find((provider) => provider.id === modelInfo.fallbackProvider) + return allProviders.find((provider) => provider.id === modelInfo.fallbackProvider) })() if (!modelProvider) throw new ModelError(t("zen.api.error.noProviderAvailable")) From c0bc020ad6af6b6f4af97095d8f4106f09f54e37 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Tue, 26 May 2026 18:28:03 -0500 Subject: [PATCH 39/40] fix(opencode): disconnect dynamically added mcp servers (#29452) --- packages/opencode/src/mcp/index.ts | 14 ++++++++++++-- packages/opencode/test/server/httpapi-mcp.test.ts | 4 ++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts index efd72c0c1f..c95394f338 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -234,6 +234,7 @@ interface AuthResult { // --- Effect Service --- interface State { + config: Record status: Record clients: Record defs: Record @@ -525,6 +526,7 @@ export const layer = Layer.effect( const bridge = yield* EffectBridge.make() const config = cfg.mcp ?? {} const s: State = { + config: {}, status: {}, clients: {}, defs: {}, @@ -619,6 +621,10 @@ export const layer = Layer.effect( result[key] = s.status[key] ?? { status: "disabled" } } + for (const key of Object.keys(s.config)) { + result[key] = s.status[key] ?? { status: "disabled" } + } + return result }) @@ -642,8 +648,9 @@ export const layer = Layer.effect( }) const add = Effect.fn("MCP.add")(function* (name: string, mcp: ConfigMCP.Info) { - yield* createAndStore(name, mcp) const s = yield* InstanceState.get(state) + s.config[name] = mcp + yield* createAndStore(name, mcp) return { status: s.status } }) @@ -677,7 +684,7 @@ export const layer = Layer.effect( ([clientName, client]) => Effect.gen(function* () { const mcpConfig = config[clientName] - const entry = mcpConfig && isMcpConfigured(mcpConfig) ? mcpConfig : undefined + const entry = mcpConfig && isMcpConfigured(mcpConfig) ? mcpConfig : s.config[clientName] const listed = s.defs[clientName] if (!listed) { @@ -756,6 +763,9 @@ export const layer = Layer.effect( }) const getMcpConfig = Effect.fnUntraced(function* (mcpName: string) { + const s = yield* InstanceState.get(state) + if (s.config[mcpName]) return s.config[mcpName] + const cfg = yield* cfgSvc.get() const mcpConfig = cfg.mcp?.[mcpName] if (!mcpConfig || !isMcpConfigured(mcpConfig)) return undefined diff --git a/packages/opencode/test/server/httpapi-mcp.test.ts b/packages/opencode/test/server/httpapi-mcp.test.ts index 9985ced9f6..2cd5d2abba 100644 --- a/packages/opencode/test/server/httpapi-mcp.test.ts +++ b/packages/opencode/test/server/httpapi-mcp.test.ts @@ -109,6 +109,10 @@ describe("mcp HttpApi", () => { expect(added.status).toBe(200) expect(yield* json(added)).toMatchObject({ added: { status: "disabled" } }) + const addedDisconnected = yield* request(handler, "/mcp/added/disconnect", tmp.directory, { method: "POST" }) + expect(addedDisconnected.status).toBe(200) + expect(yield* json(addedDisconnected)).toBe(true) + const connected = yield* request(handler, "/mcp/demo/connect", tmp.directory, { method: "POST" }) expect(connected.status).toBe(200) expect(yield* json(connected)).toBe(true) From a78605f8ea1a6e56cab516c20d9b3311cd0ce0b1 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Tue, 26 May 2026 19:16:07 -0500 Subject: [PATCH 40/40] fix(plugin): use codex session-id header (#29471) --- packages/opencode/src/plugin/codex.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencode/src/plugin/codex.ts b/packages/opencode/src/plugin/codex.ts index df4b4d0d5c..bbd65e0f00 100644 --- a/packages/opencode/src/plugin/codex.ts +++ b/packages/opencode/src/plugin/codex.ts @@ -638,7 +638,7 @@ export async function CodexAuthPlugin(input: PluginInput, options: CodexAuthPlug if (input.model.providerID !== "openai") return output.headers.originator = "opencode" output.headers["User-Agent"] = `opencode/${InstallationVersion} (${os.platform()} ${os.release()}; ${os.arch()})` - output.headers.session_id = input.sessionID + output.headers["session-id"] = input.sessionID }, "chat.params": async (input, output) => { if (input.model.providerID !== "openai") return