mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-03 16:56:33 -04:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4c893a77a0 | |||
| ddfcdee425 | |||
| ff58d21b22 |
@@ -129,8 +129,8 @@ export const loadProjectsQuery = (scope: ServerScope, api: ProjectApi) =>
|
||||
api.list().then((projects) => {
|
||||
return projects
|
||||
.filter((p) => !!p?.id)
|
||||
.map(normalizeProjectInfo)
|
||||
.filter((p) => !!p.worktree && !p.worktree.includes("opencode-test"))
|
||||
.map(normalizeProjectInfo)
|
||||
.slice()
|
||||
.sort((a, b) => cmp(a.id, b.id))
|
||||
}),
|
||||
|
||||
@@ -168,7 +168,6 @@ export function sanitizeProject(project: Project) {
|
||||
export function normalizeProjectInfo(project: Project | CurrentProject): Project {
|
||||
return {
|
||||
...project,
|
||||
worktree: "canonical" in project ? project.canonical : project.worktree,
|
||||
vcs: project.vcs === "git" ? "git" : undefined,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ function createV1Api(input: CompatibleInput): CompatibleApi {
|
||||
const located = <T>(data: T, value?: { directory?: string }) => ({
|
||||
location: {
|
||||
directory: directory(value) ?? "",
|
||||
project: { id: "", directory: directory(value) ?? "", canonical: directory(value) ?? "" },
|
||||
project: { id: "", directory: directory(value) ?? "" },
|
||||
},
|
||||
data,
|
||||
})
|
||||
@@ -298,19 +298,12 @@ function createV1Api(input: CompatibleInput): CompatibleApi {
|
||||
project: {
|
||||
...input.current.project,
|
||||
async list() {
|
||||
return ((await legacy().project.list()).data ?? []).map((project) => ({
|
||||
...project,
|
||||
canonical: project.worktree,
|
||||
}))
|
||||
return ((await legacy().project.list()).data ?? []) as Project[]
|
||||
},
|
||||
async current(value?: Parameters<ServerApi["project"]["current"]>[0]) {
|
||||
const result = await legacy(value?.location).project.current()
|
||||
if (!result.data) throw new Error("Project not found")
|
||||
return {
|
||||
id: result.data.id,
|
||||
directory: result.data.worktree,
|
||||
canonical: result.data.worktree,
|
||||
} satisfies ProjectCurrent
|
||||
return { id: result.data.id, directory: result.data.worktree } satisfies ProjectCurrent
|
||||
},
|
||||
// async update(value: Parameters<ServerApi["project"]["update"]>[0]) {
|
||||
// const project = (await legacy().project.list()).data?.find((item) => item.id === value.projectID)
|
||||
|
||||
@@ -3,7 +3,7 @@ import { OpenCode, type LocationGetOutput, type ModelRef, type SessionInfo } fro
|
||||
import { resolveSessionTarget, SessionTargetMutationError } from "../src/session-target"
|
||||
|
||||
function location(directory: string, workspaceID?: string): LocationGetOutput {
|
||||
return { directory, workspaceID, project: { id: "project", directory, canonical: directory } }
|
||||
return { directory, workspaceID, project: { id: "project", directory } }
|
||||
}
|
||||
|
||||
function session(id: string, directory: string, workspaceID?: string, model?: ModelRef): SessionInfo {
|
||||
|
||||
@@ -279,7 +279,7 @@ export type ProjectCommands = { start?: string }
|
||||
|
||||
export type ProjectTime = { created: number; updated: number; initialized?: number }
|
||||
|
||||
export type ProjectCurrent = { id: string; directory: string; canonical: string }
|
||||
export type ProjectCurrent = { id: string; directory: string }
|
||||
|
||||
export type ProjectDirectory = { directory: string; strategy?: string }
|
||||
|
||||
@@ -1430,7 +1430,7 @@ export type McpResourceCatalog = { resources: Array<McpResource>; templates: Arr
|
||||
|
||||
export type Project = {
|
||||
id: string
|
||||
canonical: string
|
||||
worktree: string
|
||||
vcs?: ProjectVcs
|
||||
name?: string
|
||||
icon?: ProjectIcon
|
||||
@@ -2515,11 +2515,7 @@ export type LocationGetInput = {
|
||||
}["location"]
|
||||
}
|
||||
|
||||
export type LocationGetOutput = {
|
||||
directory: string
|
||||
workspaceID?: string
|
||||
project: { id: string; directory: string; canonical: string }
|
||||
}
|
||||
export type LocationGetOutput = { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
|
||||
export type AgentListInput = {
|
||||
readonly location?: {
|
||||
@@ -2528,7 +2524,7 @@ export type AgentListInput = {
|
||||
}
|
||||
|
||||
export type AgentListOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<AgentInfo>
|
||||
}
|
||||
|
||||
@@ -2540,7 +2536,7 @@ export type AgentGetInput = {
|
||||
}
|
||||
|
||||
export type AgentGetOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: AgentInfo
|
||||
}
|
||||
|
||||
@@ -2551,7 +2547,7 @@ export type PluginListInput = {
|
||||
}
|
||||
|
||||
export type PluginListOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<PluginInfo>
|
||||
}
|
||||
|
||||
@@ -3235,7 +3231,7 @@ export type ModelListInput = {
|
||||
}
|
||||
|
||||
export type ModelListOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<ModelInfo>
|
||||
}
|
||||
|
||||
@@ -3246,7 +3242,7 @@ export type ModelDefaultInput = {
|
||||
}
|
||||
|
||||
export type ModelDefaultOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: ModelInfo | null
|
||||
}
|
||||
|
||||
@@ -3273,7 +3269,7 @@ export type ProviderListInput = {
|
||||
}
|
||||
|
||||
export type ProviderListOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<ProviderInfo>
|
||||
}
|
||||
|
||||
@@ -3285,7 +3281,7 @@ export type ProviderGetInput = {
|
||||
}
|
||||
|
||||
export type ProviderGetOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: ProviderInfo
|
||||
}
|
||||
|
||||
@@ -3296,7 +3292,7 @@ export type IntegrationListInput = {
|
||||
}
|
||||
|
||||
export type IntegrationListOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<IntegrationInfo>
|
||||
}
|
||||
|
||||
@@ -3308,7 +3304,7 @@ export type IntegrationGetInput = {
|
||||
}
|
||||
|
||||
export type IntegrationGetOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: IntegrationInfo | null
|
||||
}
|
||||
|
||||
@@ -3355,7 +3351,7 @@ export type IntegrationOauthConnectInput = {
|
||||
}
|
||||
|
||||
export type IntegrationOauthConnectOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: {
|
||||
attemptID: string
|
||||
url: string
|
||||
@@ -3374,7 +3370,7 @@ export type IntegrationOauthStatusInput = {
|
||||
}
|
||||
|
||||
export type IntegrationOauthStatusOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: IntegrationAttemptStatus
|
||||
}
|
||||
|
||||
@@ -3409,7 +3405,7 @@ export type IntegrationCommandConnectInput = {
|
||||
}
|
||||
|
||||
export type IntegrationCommandConnectOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: IntegrationCommandAttempt
|
||||
}
|
||||
|
||||
@@ -3422,7 +3418,7 @@ export type IntegrationCommandStatusInput = {
|
||||
}
|
||||
|
||||
export type IntegrationCommandStatusOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: IntegrationCommandAttemptStatus
|
||||
}
|
||||
|
||||
@@ -3443,7 +3439,7 @@ export type McpListInput = {
|
||||
}
|
||||
|
||||
export type McpListOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<McpServer>
|
||||
}
|
||||
|
||||
@@ -3532,7 +3528,7 @@ export type McpResourceCatalogInput = {
|
||||
}
|
||||
|
||||
export type McpResourceCatalogOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: McpResourceCatalog
|
||||
}
|
||||
|
||||
@@ -3581,7 +3577,7 @@ export type FormRequestListInput = {
|
||||
}
|
||||
|
||||
export type FormRequestListOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<FormInfo>
|
||||
}
|
||||
|
||||
@@ -4437,7 +4433,7 @@ export type PermissionRequestListInput = {
|
||||
}
|
||||
|
||||
export type PermissionRequestListOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<PermissionRequest>
|
||||
}
|
||||
|
||||
@@ -4559,7 +4555,7 @@ export type FileListInput = {
|
||||
}
|
||||
|
||||
export type FileListOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<FileSystemEntry>
|
||||
}
|
||||
|
||||
@@ -4591,7 +4587,7 @@ export type FileFindInput = {
|
||||
}
|
||||
|
||||
export type FileFindOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<FileSystemEntry>
|
||||
}
|
||||
|
||||
@@ -4602,7 +4598,7 @@ export type CommandListInput = {
|
||||
}
|
||||
|
||||
export type CommandListOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<CommandInfo>
|
||||
}
|
||||
|
||||
@@ -4613,7 +4609,7 @@ export type SkillListInput = {
|
||||
}
|
||||
|
||||
export type SkillListOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<SkillInfo>
|
||||
}
|
||||
|
||||
@@ -4626,7 +4622,7 @@ export type PtyListInput = {
|
||||
}
|
||||
|
||||
export type PtyListOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<Pty>
|
||||
}
|
||||
|
||||
@@ -4672,7 +4668,7 @@ export type PtyCreateInput = {
|
||||
}
|
||||
|
||||
export type PtyCreateOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Pty
|
||||
}
|
||||
|
||||
@@ -4684,7 +4680,7 @@ export type PtyGetInput = {
|
||||
}
|
||||
|
||||
export type PtyGetOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Pty
|
||||
}
|
||||
|
||||
@@ -4701,7 +4697,7 @@ export type PtyUpdateInput = {
|
||||
}
|
||||
|
||||
export type PtyUpdateOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Pty
|
||||
}
|
||||
|
||||
@@ -4721,7 +4717,7 @@ export type ShellListInput = {
|
||||
}
|
||||
|
||||
export type ShellListOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<ShellInfo1>
|
||||
}
|
||||
|
||||
@@ -4756,7 +4752,7 @@ export type ShellCreateInput = {
|
||||
}
|
||||
|
||||
export type ShellCreateOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: ShellInfo1
|
||||
}
|
||||
|
||||
@@ -4768,7 +4764,7 @@ export type ShellGetInput = {
|
||||
}
|
||||
|
||||
export type ShellGetOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: ShellInfo1
|
||||
}
|
||||
|
||||
@@ -4781,7 +4777,7 @@ export type ShellTimeoutInput = {
|
||||
}
|
||||
|
||||
export type ShellTimeoutOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: ShellInfo1
|
||||
}
|
||||
|
||||
@@ -4805,7 +4801,7 @@ export type ShellOutputInput = {
|
||||
}
|
||||
|
||||
export type ShellOutputOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: { output: string; cursor: number; size: number; truncated: boolean }
|
||||
}
|
||||
|
||||
@@ -4825,7 +4821,7 @@ export type QuestionRequestListInput = {
|
||||
}
|
||||
|
||||
export type QuestionRequestListOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<QuestionRequest>
|
||||
}
|
||||
|
||||
@@ -4855,7 +4851,7 @@ export type ReferenceListInput = {
|
||||
}
|
||||
|
||||
export type ReferenceListOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<ReferenceInfo>
|
||||
}
|
||||
|
||||
@@ -4898,7 +4894,7 @@ export type VcsStatusInput = {
|
||||
}
|
||||
|
||||
export type VcsStatusOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<VcsFileStatus>
|
||||
}
|
||||
|
||||
@@ -4921,7 +4917,7 @@ export type VcsDiffInput = {
|
||||
}
|
||||
|
||||
export type VcsDiffOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<FileDiffInfo>
|
||||
}
|
||||
|
||||
@@ -4942,7 +4938,7 @@ export type WebsearchProvidersInput = {
|
||||
}
|
||||
|
||||
export type WebsearchProvidersOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: Array<WebSearchProvider>
|
||||
}
|
||||
|
||||
@@ -4955,6 +4951,6 @@ export type WebsearchQueryInput = {
|
||||
}
|
||||
|
||||
export type WebsearchQueryOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
|
||||
data: { providerID: string; results: Array<WebSearchResult> }
|
||||
}
|
||||
|
||||
@@ -264,7 +264,8 @@ export const dict = {
|
||||
"go.cta.text": "اشترك في Go",
|
||||
"go.cta.price": "$10/شهر",
|
||||
"go.cta.promo": "$5 للشهر الأول",
|
||||
"go.pricing.body": "يبدأ Go من $5 للشهر الأول، ثم $10/شهر.",
|
||||
"go.pricing.body":
|
||||
"استخدمه مع أي وكيل. $5 للشهر الأول، ثم $10/شهر. قم بزيادة الرصيد إذا لزم الأمر. الإلغاء في أي وقت.",
|
||||
"go.graph.free": "مجاني",
|
||||
"go.graph.freePill": "Big Pickle ونماذج مجانية",
|
||||
"go.graph.go": "Go",
|
||||
@@ -303,15 +304,15 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"يتضمن Grok 4.5 وGLM-5.2 وGLM-5.1 وKimi K3 وKimi K2.7 Code وKimi K2.6 وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.7 Max وQwen3.7 Plus وQwen3.6 Plus وMiniMax M2.7 وMiniMax M3 وDeepSeek V4 Pro وDeepSeek V4 Flash وHy3",
|
||||
"go.how.title": "كيف يعمل Go",
|
||||
"go.how.body": "يبدأ Go من $5 للشهر الأول، ثم $10/شهر.",
|
||||
"go.how.step1.title": "اشترك في Go",
|
||||
"go.how.step1.beforeLink": "في",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "ربط OpenCode",
|
||||
"go.how.step2.link": "opencode2 console login",
|
||||
"go.how.step2.afterLink": "ووافق على الجهاز في متصفحك",
|
||||
"go.how.body": "يبدأ Go من $5 للشهر الأول، ثم $10/شهر. يمكنك استخدامه مع OpenCode أو أي وكيل.",
|
||||
"go.how.step1.title": "أنشئ حسابًا",
|
||||
"go.how.step1.beforeLink": "اتبع",
|
||||
"go.how.step1.link": "تعليمات الإعداد",
|
||||
"go.how.step2.title": "اشترك في Go",
|
||||
"go.how.step2.link": "$5 للشهر الأول",
|
||||
"go.how.step2.afterLink": "ثم $10/شهر مع حدود سخية",
|
||||
"go.how.step3.title": "ابدأ البرمجة",
|
||||
"go.how.step3.body": "مع مزود opencode",
|
||||
"go.how.step3.body": "مع وصول موثوق لنماذج مفتوحة المصدر",
|
||||
"go.privacy.title": "خصوصيتك مهمة بالنسبة لنا",
|
||||
"go.privacy.body":
|
||||
"تم تصميم الخطة بشكل أساسي للمستخدمين الدوليين، مع استضافة النماذج في الولايات المتحدة والاتحاد الأوروبي وسنغافورة للحصول على وصول عالمي مستقر.",
|
||||
@@ -343,8 +344,8 @@ export const dict = {
|
||||
"go.faq.a6": "إذا كنت بحاجة إلى مزيد من الاستخدام، يمكنك شحن رصيد في حسابك.",
|
||||
"go.faq.q7": "هل يمكنني الإلغاء؟",
|
||||
"go.faq.a7": "نعم، يمكنك الإلغاء في أي وقت.",
|
||||
"go.faq.q8": "ما الوصول المؤجل؟",
|
||||
"go.faq.a8": "دعم الوكلاء الخارجيين وحسابات الخدمة مؤجل.",
|
||||
"go.faq.q8": "هل يمكنني استخدام Go مع وكلاء برمجة آخرين؟",
|
||||
"go.faq.a8": "نعم، يمكنك استخدام Go مع أي وكيل. اتبع تعليمات الإعداد في وكيل البرمجة المفضل لديك.",
|
||||
|
||||
"go.faq.q9": "ما الفرق بين النماذج المجانية وGo؟",
|
||||
"go.faq.a9":
|
||||
@@ -649,7 +650,8 @@ export const dict = {
|
||||
"workspace.lite.subscription.monthlyUsage": "الاستخدام الشهري",
|
||||
"workspace.lite.subscription.resetsIn": "إعادة تعيين في",
|
||||
"workspace.lite.subscription.useBalance": "استخدم رصيدك المتوفر بعد الوصول إلى حدود الاستخدام",
|
||||
"workspace.lite.subscription.selectProvider": "اختر مزود opencode لاستخدام نماذج Go.",
|
||||
"workspace.lite.subscription.selectProvider":
|
||||
'اختر "OpenCode Go" كمزود في إعدادات opencode الخاصة بك لاستخدام نماذج Go.',
|
||||
"workspace.lite.providers.title": "المزودون",
|
||||
"workspace.lite.providers.description": "تحكم في المزودين المستخدمين للتوجيه.",
|
||||
"workspace.lite.providers.useChina": "تفعيل النماذج المستضافة في الصين",
|
||||
|
||||
@@ -268,7 +268,8 @@ export const dict = {
|
||||
"go.cta.text": "Assinar o Go",
|
||||
"go.cta.price": "$10/mês",
|
||||
"go.cta.promo": "$5 no primeiro mês",
|
||||
"go.pricing.body": "O Go começa em $5 no primeiro mês, depois $10/mês.",
|
||||
"go.pricing.body":
|
||||
"Use com qualquer agente. $5 no primeiro mês, depois $10/mês. Recarregue o crédito se necessário. Cancele a qualquer momento.",
|
||||
"go.graph.free": "Grátis",
|
||||
"go.graph.freePill": "Big Pickle e modelos gratuitos",
|
||||
"go.graph.go": "Go",
|
||||
@@ -308,15 +309,16 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"Inclui Grok 4.5, GLM-5.2, GLM-5.1, Kimi K3, Kimi K2.7 Code, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.7 Plus, Qwen3.6 Plus, MiniMax M2.7, MiniMax M3, DeepSeek V4 Pro, DeepSeek V4 Flash e Hy3",
|
||||
"go.how.title": "Como o Go funciona",
|
||||
"go.how.body": "O Go começa em $5 no primeiro mês, depois $10/mês.",
|
||||
"go.how.step1.title": "Assinar o Go",
|
||||
"go.how.step1.beforeLink": "no",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "Conectar o OpenCode",
|
||||
"go.how.step2.link": "opencode2 console login",
|
||||
"go.how.step2.afterLink": "e aprove o dispositivo no navegador",
|
||||
"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.",
|
||||
"go.how.step1.title": "Crie uma conta",
|
||||
"go.how.step1.beforeLink": "siga as",
|
||||
"go.how.step1.link": "instruções de configuração",
|
||||
"go.how.step2.title": "Assinar o Go",
|
||||
"go.how.step2.link": "$5 no primeiro mês",
|
||||
"go.how.step2.afterLink": "depois $10/mês com limites generosos",
|
||||
"go.how.step3.title": "Comece a codificar",
|
||||
"go.how.step3.body": "com o provedor opencode",
|
||||
"go.how.step3.body": "com acesso confiável a modelos de código aberto",
|
||||
"go.privacy.title": "Sua privacidade é importante para nós",
|
||||
"go.privacy.body":
|
||||
"O plano é projetado principalmente para usuários internacionais, com modelos hospedados nos EUA, UE e Singapura para acesso global estável.",
|
||||
@@ -349,8 +351,9 @@ export const dict = {
|
||||
"go.faq.a6": "Se você precisar de mais uso, pode recarregar crédito em sua conta.",
|
||||
"go.faq.q7": "Posso cancelar?",
|
||||
"go.faq.a7": "Sim, você pode cancelar a qualquer momento.",
|
||||
"go.faq.q8": "Qual acesso foi adiado?",
|
||||
"go.faq.a8": "O suporte a agentes externos e contas de serviço foi adiado.",
|
||||
"go.faq.q8": "Posso usar o Go com outros agentes de codificação?",
|
||||
"go.faq.a8":
|
||||
"Sim, você pode usar o Go com qualquer agente. Siga as instruções de configuração no seu agente de codificação preferido.",
|
||||
|
||||
"go.faq.q9": "Qual a diferença entre os modelos gratuitos e o Go?",
|
||||
"go.faq.a9":
|
||||
@@ -657,7 +660,8 @@ export const dict = {
|
||||
"workspace.lite.subscription.monthlyUsage": "Uso Mensal",
|
||||
"workspace.lite.subscription.resetsIn": "Reinicia em",
|
||||
"workspace.lite.subscription.useBalance": "Use seu saldo disponível após atingir os limites de uso",
|
||||
"workspace.lite.subscription.selectProvider": "Selecione o provedor opencode para usar os modelos Go.",
|
||||
"workspace.lite.subscription.selectProvider":
|
||||
'Selecione "OpenCode Go" como provedor na sua configuração do opencode para usar os modelos Go.',
|
||||
"workspace.lite.providers.title": "Provedores",
|
||||
"workspace.lite.providers.description": "Controle quais provedores são usados para roteamento.",
|
||||
"workspace.lite.providers.useChina": "Ativar modelos hospedados na China",
|
||||
|
||||
@@ -266,7 +266,8 @@ export const dict = {
|
||||
"go.cta.text": "Abonner på Go",
|
||||
"go.cta.price": "$10/måned",
|
||||
"go.cta.promo": "$5 første måned",
|
||||
"go.pricing.body": "Go starter ved $5 for den første måned, derefter $10/måned.",
|
||||
"go.pricing.body":
|
||||
"Brug med enhver agent. $5 første måned, derefter $10/måned. Tank op med kredit efter behov. Afmeld når som helst.",
|
||||
"go.graph.free": "Gratis",
|
||||
"go.graph.freePill": "Big Pickle og gratis modeller",
|
||||
"go.graph.go": "Go",
|
||||
@@ -305,15 +306,16 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"Inkluderer Grok 4.5, GLM-5.2, GLM-5.1, Kimi K3, Kimi K2.7 Code, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.7 Plus, Qwen3.6 Plus, MiniMax M2.7, MiniMax M3, DeepSeek V4 Pro, DeepSeek V4 Flash og Hy3",
|
||||
"go.how.title": "Hvordan Go virker",
|
||||
"go.how.body": "Go starter ved $5 for den første måned, derefter $10/måned.",
|
||||
"go.how.step1.title": "Abonner på Go",
|
||||
"go.how.step1.beforeLink": "i",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "Forbind OpenCode",
|
||||
"go.how.step2.link": "opencode2 console login",
|
||||
"go.how.step2.afterLink": "og godkend enheden i din browser",
|
||||
"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.",
|
||||
"go.how.step1.title": "Opret en konto",
|
||||
"go.how.step1.beforeLink": "følg",
|
||||
"go.how.step1.link": "opsætningsinstruktionerne",
|
||||
"go.how.step2.title": "Abonner på Go",
|
||||
"go.how.step2.link": "$5 første måned",
|
||||
"go.how.step2.afterLink": "derefter $10/måned med generøse grænser",
|
||||
"go.how.step3.title": "Start kodning",
|
||||
"go.how.step3.body": "med opencode-udbyderen",
|
||||
"go.how.step3.body": "med pålidelig adgang til open source-modeller",
|
||||
"go.privacy.title": "Dit privatliv er vigtigt for os",
|
||||
"go.privacy.body":
|
||||
"Planen er primært designet til internationale brugere, med modeller hostet i USA, EU og Singapore for stabil global adgang.",
|
||||
@@ -346,8 +348,8 @@ export const dict = {
|
||||
"go.faq.a6": "Hvis du har brug for mere forbrug, kan du tanke kredit op på din konto.",
|
||||
"go.faq.q7": "Kan jeg annullere?",
|
||||
"go.faq.a7": "Ja, du kan annullere til enhver tid.",
|
||||
"go.faq.q8": "Hvilken adgang er udskudt?",
|
||||
"go.faq.a8": "Understøttelse af eksterne agenter og tjenestekonti er udskudt.",
|
||||
"go.faq.q8": "Kan jeg bruge Go med andre kodningsagenter?",
|
||||
"go.faq.a8": "Ja, du kan bruge Go med enhver agent. Følg opsætningsinstruktionerne i din foretrukne kodningsagent.",
|
||||
|
||||
"go.faq.q9": "Hvad er forskellen på gratis modeller og Go?",
|
||||
"go.faq.a9":
|
||||
@@ -654,7 +656,8 @@ export const dict = {
|
||||
"workspace.lite.subscription.monthlyUsage": "Månedligt forbrug",
|
||||
"workspace.lite.subscription.resetsIn": "Nulstiller i",
|
||||
"workspace.lite.subscription.useBalance": "Brug din tilgængelige saldo, når du har nået forbrugsgrænserne",
|
||||
"workspace.lite.subscription.selectProvider": "Vælg opencode-udbyderen for at bruge Go-modeller.",
|
||||
"workspace.lite.subscription.selectProvider":
|
||||
'Vælg "OpenCode Go" som udbyder i din opencode-konfiguration for at bruge Go-modeller.',
|
||||
"workspace.lite.providers.title": "Udbydere",
|
||||
"workspace.lite.providers.description": "Styr, hvilke udbydere der bruges til routing.",
|
||||
"workspace.lite.providers.useChina": "Aktivér modeller hostet i Kina",
|
||||
|
||||
@@ -268,7 +268,8 @@ export const dict = {
|
||||
"go.cta.text": "Go abonnieren",
|
||||
"go.cta.price": "$10/Monat",
|
||||
"go.cta.promo": "$5 im ersten Monat",
|
||||
"go.pricing.body": "Go beginnt bei $5 für den ersten Monat, danach $10/Monat.",
|
||||
"go.pricing.body":
|
||||
"Mit jedem Agenten nutzbar. $5 im ersten Monat, danach $10/Monat. Guthaben bei Bedarf aufladen. Jederzeit kündbar.",
|
||||
"go.graph.free": "Kostenlos",
|
||||
"go.graph.freePill": "Big Pickle und kostenlose Modelle",
|
||||
"go.graph.go": "Go",
|
||||
@@ -307,15 +308,16 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"Beinhaltet Grok 4.5, GLM-5.2, GLM-5.1, Kimi K3, Kimi K2.7 Code, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.7 Plus, Qwen3.6 Plus, MiniMax M2.7, MiniMax M3, DeepSeek V4 Pro, DeepSeek V4 Flash und Hy3",
|
||||
"go.how.title": "Wie Go funktioniert",
|
||||
"go.how.body": "Go beginnt bei $5 für den ersten Monat, danach $10/Monat.",
|
||||
"go.how.step1.title": "Go abonnieren",
|
||||
"go.how.step1.beforeLink": "in",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "OpenCode verbinden",
|
||||
"go.how.step2.link": "opencode2 console login",
|
||||
"go.how.step2.afterLink": "und autorisiere das Gerät in deinem Browser",
|
||||
"go.how.body":
|
||||
"Go beginnt bei $5 für den ersten Monat, danach $10/Monat. Du kannst es mit OpenCode oder jedem Agenten nutzen.",
|
||||
"go.how.step1.title": "Konto erstellen",
|
||||
"go.how.step1.beforeLink": "folge den",
|
||||
"go.how.step1.link": "Einrichtungsanweisungen",
|
||||
"go.how.step2.title": "Go abonnieren",
|
||||
"go.how.step2.link": "$5 im ersten Monat",
|
||||
"go.how.step2.afterLink": "danach $10/Monat mit großzügigen Limits",
|
||||
"go.how.step3.title": "Loslegen mit Coding",
|
||||
"go.how.step3.body": "mit dem opencode-Anbieter",
|
||||
"go.how.step3.body": "mit zuverlässigem Zugang zu Open-Source-Modellen",
|
||||
"go.privacy.title": "Deine Privatsphäre ist uns wichtig",
|
||||
"go.privacy.body":
|
||||
"Der Plan ist primär für internationale Nutzer konzipiert, mit Modellen gehostet in den USA, der EU und Singapur für stabilen globalen Zugang.",
|
||||
@@ -348,8 +350,9 @@ export const dict = {
|
||||
"go.faq.a6": "Wenn du mehr Nutzung benötigst, kannst du Guthaben in deinem Konto aufladen.",
|
||||
"go.faq.q7": "Kann ich kündigen?",
|
||||
"go.faq.a7": "Ja, du kannst jederzeit kündigen.",
|
||||
"go.faq.q8": "Welcher Zugriff ist zurückgestellt?",
|
||||
"go.faq.a8": "Unterstützung für externe Agenten und Dienstkonten ist zurückgestellt.",
|
||||
"go.faq.q8": "Kann ich Go mit anderen Coding-Agenten nutzen?",
|
||||
"go.faq.a8":
|
||||
"Ja, du kannst Go mit jedem Agenten nutzen. Folge den Einrichtungsanweisungen in deinem bevorzugten Coding-Agenten.",
|
||||
|
||||
"go.faq.q9": "Was ist der Unterschied zwischen kostenlosen Modellen und Go?",
|
||||
"go.faq.a9":
|
||||
@@ -656,7 +659,8 @@ export const dict = {
|
||||
"workspace.lite.subscription.monthlyUsage": "Monatliche Nutzung",
|
||||
"workspace.lite.subscription.resetsIn": "Setzt zurück in",
|
||||
"workspace.lite.subscription.useBalance": "Nutze dein verfügbares Guthaben, nachdem die Nutzungslimits erreicht sind",
|
||||
"workspace.lite.subscription.selectProvider": "Wähle den opencode-Anbieter, um Go-Modelle zu verwenden.",
|
||||
"workspace.lite.subscription.selectProvider":
|
||||
'Wähle "OpenCode Go" als Anbieter in deiner opencode-Konfiguration, um Go-Modelle zu verwenden.',
|
||||
"workspace.lite.providers.title": "Anbieter",
|
||||
"workspace.lite.providers.description": "Steuere, welche Anbieter für das Routing verwendet werden.",
|
||||
"workspace.lite.providers.useChina": "In China gehostete Modelle aktivieren",
|
||||
|
||||
@@ -265,8 +265,7 @@ export const dict = {
|
||||
"go.cta.text": "Subscribe to Go",
|
||||
"go.cta.price": "$10/month",
|
||||
"go.cta.promo": "$5 first month",
|
||||
"go.pricing.body":
|
||||
"For a named OpenCode subscriber. $5 first month, then $10/month. Service accounts are not eligible. Cancel any time.",
|
||||
"go.pricing.body": "Use with any agent. $5 first month, then $10/month. Top up credit if needed. Cancel any time.",
|
||||
"go.graph.free": "Free",
|
||||
"go.graph.freePill": "Big Pickle and free models",
|
||||
"go.graph.go": "Go",
|
||||
@@ -305,15 +304,15 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"Includes Grok 4.5, GLM-5.2, GLM-5.1, Kimi K3, Kimi K2.7 Code, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.7 Plus, Qwen3.6 Plus, MiniMax M2.7, MiniMax M3, DeepSeek V4 Pro, DeepSeek V4 Flash, and Hy3",
|
||||
"go.how.title": "How Go works",
|
||||
"go.how.body": "Go is available to a named subscriber using OpenCode. No API key needs to be copied.",
|
||||
"go.how.step1.title": "Subscribe to Go",
|
||||
"go.how.step1.beforeLink": "in",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "Connect OpenCode",
|
||||
"go.how.step2.link": "run opencode2 console login",
|
||||
"go.how.step2.afterLink": "and authorize the device in your browser",
|
||||
"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",
|
||||
"go.how.step1.beforeLink": "follow the",
|
||||
"go.how.step1.link": "setup instructions",
|
||||
"go.how.step2.title": "Subscribe to Go",
|
||||
"go.how.step2.link": "$5 first month",
|
||||
"go.how.step2.afterLink": "then $10/month with generous limits",
|
||||
"go.how.step3.title": "Start coding",
|
||||
"go.how.step3.body": "with the opencode provider",
|
||||
"go.how.step3.body": "with reliable access to open-source models",
|
||||
"go.privacy.title": "Your privacy is important to us",
|
||||
"go.privacy.body":
|
||||
"The plan is designed primarily for international users, with models hosted in the US, EU, and Singapore for stable global access.",
|
||||
@@ -347,9 +346,8 @@ export const dict = {
|
||||
"go.faq.a6": "If you need more usage, you can top up credit in your account.",
|
||||
"go.faq.q7": "Can I cancel?",
|
||||
"go.faq.a7": "Yes, you can cancel any time.",
|
||||
"go.faq.q8": "Who can use Go?",
|
||||
"go.faq.a8":
|
||||
"Go is available to the named subscriber through OpenCode. Other coding agents and service accounts are not eligible.",
|
||||
"go.faq.q8": "Can I use Go with other coding agents?",
|
||||
"go.faq.a8": "Yes, you can use Go with any agent. Follow the setup instructions in your preferred coding agent.",
|
||||
|
||||
"go.faq.q9": "What is the difference between free models and Go?",
|
||||
"go.faq.a9":
|
||||
@@ -656,7 +654,8 @@ export const dict = {
|
||||
"workspace.lite.subscription.monthlyUsage": "Monthly Usage",
|
||||
"workspace.lite.subscription.resetsIn": "Resets in",
|
||||
"workspace.lite.subscription.useBalance": "Use your available balance after reaching the usage limits",
|
||||
"workspace.lite.subscription.selectProvider": 'Select the "opencode" provider to use Go models.',
|
||||
"workspace.lite.subscription.selectProvider":
|
||||
'Select "OpenCode Go" as the provider in your opencode configuration to use Go models.',
|
||||
"workspace.lite.providers.title": "Providers",
|
||||
"workspace.lite.providers.description": "Control which providers are used for routing.",
|
||||
"workspace.lite.providers.useChina": "Enable models hosted in China",
|
||||
|
||||
@@ -269,7 +269,8 @@ export const dict = {
|
||||
"go.cta.text": "Suscribirse a Go",
|
||||
"go.cta.price": "10 $/mes",
|
||||
"go.cta.promo": "$5 el primer mes",
|
||||
"go.pricing.body": "Go comienza en $5 el primer mes, luego 10 $/mes.",
|
||||
"go.pricing.body":
|
||||
"Úsalo con cualquier agente. $5 el primer mes, luego 10 $/mes. Recarga crédito si es necesario. Cancela en cualquier momento.",
|
||||
"go.graph.free": "Gratis",
|
||||
"go.graph.freePill": "Big Pickle y modelos gratuitos",
|
||||
"go.graph.go": "Go",
|
||||
@@ -309,15 +310,15 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"Incluye Grok 4.5, GLM-5.2, GLM-5.1, Kimi K3, Kimi K2.7 Code, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.7 Plus, Qwen3.6 Plus, MiniMax M2.7, MiniMax M3, DeepSeek V4 Pro, DeepSeek V4 Flash y Hy3",
|
||||
"go.how.title": "Cómo funciona Go",
|
||||
"go.how.body": "Go comienza en $5 el primer mes, luego 10 $/mes.",
|
||||
"go.how.step1.title": "Suscribirse a Go",
|
||||
"go.how.step1.beforeLink": "en",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "Conectar OpenCode",
|
||||
"go.how.step2.link": "opencode2 console login",
|
||||
"go.how.step2.afterLink": "y autoriza el dispositivo en tu navegador",
|
||||
"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",
|
||||
"go.how.step1.beforeLink": "sigue las",
|
||||
"go.how.step1.link": "instrucciones de configuración",
|
||||
"go.how.step2.title": "Suscribirse a Go",
|
||||
"go.how.step2.link": "$5 el primer mes",
|
||||
"go.how.step2.afterLink": "luego 10 $/mes con límites generosos",
|
||||
"go.how.step3.title": "Empezar a programar",
|
||||
"go.how.step3.body": "con el proveedor opencode",
|
||||
"go.how.step3.body": "con acceso fiable a modelos de código abierto",
|
||||
"go.privacy.title": "Tu privacidad es importante para nosotros",
|
||||
"go.privacy.body":
|
||||
"El plan está diseñado principalmente para usuarios internacionales, con modelos alojados en EE. UU., UE y Singapur para un acceso global estable.",
|
||||
@@ -350,8 +351,9 @@ export const dict = {
|
||||
"go.faq.a6": "Si necesitas más uso, puedes recargar crédito en tu cuenta.",
|
||||
"go.faq.q7": "¿Puedo cancelar?",
|
||||
"go.faq.a7": "Sí, puedes cancelar en cualquier momento.",
|
||||
"go.faq.q8": "¿Qué acceso está aplazado?",
|
||||
"go.faq.a8": "La compatibilidad con agentes externos y cuentas de servicio está aplazada.",
|
||||
"go.faq.q8": "¿Puedo usar Go con otros agentes de programación?",
|
||||
"go.faq.a8":
|
||||
"Sí, puedes usar Go con cualquier agente. Sigue las instrucciones de configuración en tu agente de programación preferido.",
|
||||
|
||||
"go.faq.q9": "¿Cuál es la diferencia entre los modelos gratuitos y Go?",
|
||||
"go.faq.a9":
|
||||
@@ -658,7 +660,8 @@ export const dict = {
|
||||
"workspace.lite.subscription.monthlyUsage": "Uso Mensual",
|
||||
"workspace.lite.subscription.resetsIn": "Se reinicia en",
|
||||
"workspace.lite.subscription.useBalance": "Usa tu saldo disponible después de alcanzar los límites de uso",
|
||||
"workspace.lite.subscription.selectProvider": "Selecciona el proveedor opencode para usar los modelos de Go.",
|
||||
"workspace.lite.subscription.selectProvider":
|
||||
'Selecciona "OpenCode Go" como proveedor en tu configuración de opencode para usar los modelos Go.',
|
||||
"workspace.lite.providers.title": "Proveedores",
|
||||
"workspace.lite.providers.description": "Controla qué proveedores se usan para el enrutamiento.",
|
||||
"workspace.lite.providers.useChina": "Activar modelos alojados en China",
|
||||
|
||||
@@ -270,7 +270,8 @@ export const dict = {
|
||||
"go.cta.text": "S'abonner à Go",
|
||||
"go.cta.price": "10 $/mois",
|
||||
"go.cta.promo": "$5 le premier mois",
|
||||
"go.pricing.body": "Go commence à $5 pour le premier mois, puis 10 $/mois.",
|
||||
"go.pricing.body":
|
||||
"Utilisez-le avec n'importe quel agent. $5 le premier mois, puis 10 $/mois. Rechargez du crédit si nécessaire. Annulez à tout moment.",
|
||||
"go.graph.free": "Gratuit",
|
||||
"go.graph.freePill": "Big Pickle et modèles gratuits",
|
||||
"go.graph.go": "Go",
|
||||
@@ -309,15 +310,16 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"Inclut Grok 4.5, GLM-5.2, GLM-5.1, Kimi K3, Kimi K2.7 Code, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.7 Plus, Qwen3.6 Plus, MiniMax M2.7, MiniMax M3, DeepSeek V4 Pro, DeepSeek V4 Flash et Hy3",
|
||||
"go.how.title": "Comment fonctionne Go",
|
||||
"go.how.body": "Go commence à $5 pour le premier mois, puis 10 $/mois.",
|
||||
"go.how.step1.title": "Abonnez-vous à Go",
|
||||
"go.how.step1.beforeLink": "dans",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "Connecter OpenCode",
|
||||
"go.how.step2.link": "opencode2 console login",
|
||||
"go.how.step2.afterLink": "et autorisez l’appareil dans votre navigateur",
|
||||
"go.how.body":
|
||||
"Go commence à $5 pour le premier mois, puis 10 $/mois. Vous pouvez l'utiliser avec OpenCode ou n'importe quel agent.",
|
||||
"go.how.step1.title": "Créez un compte",
|
||||
"go.how.step1.beforeLink": "suivez les",
|
||||
"go.how.step1.link": "instructions de configuration",
|
||||
"go.how.step2.title": "Abonnez-vous à Go",
|
||||
"go.how.step2.link": "$5 le premier mois",
|
||||
"go.how.step2.afterLink": "puis 10 $/mois avec des limites généreuses",
|
||||
"go.how.step3.title": "Commencez à coder",
|
||||
"go.how.step3.body": "avec le fournisseur opencode",
|
||||
"go.how.step3.body": "avec un accès fiable aux modèles open source",
|
||||
"go.privacy.title": "Votre vie privée est importante pour nous",
|
||||
"go.privacy.body":
|
||||
"Le plan est conçu principalement pour les utilisateurs internationaux, avec des modèles hébergés aux États-Unis, dans l'UE et à Singapour pour un accès mondial stable.",
|
||||
@@ -350,8 +352,9 @@ export const dict = {
|
||||
"go.faq.a6": "Si vous avez besoin de plus d'utilisation, vous pouvez recharger du crédit dans votre compte.",
|
||||
"go.faq.q7": "Puis-je annuler ?",
|
||||
"go.faq.a7": "Oui, vous pouvez annuler à tout moment.",
|
||||
"go.faq.q8": "Quel accès est reporté ?",
|
||||
"go.faq.a8": "La prise en charge des agents externes et des comptes de service est reportée.",
|
||||
"go.faq.q8": "Puis-je utiliser Go avec d'autres agents de code ?",
|
||||
"go.faq.a8":
|
||||
"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 Grok 4.5, GLM-5.2, GLM-5.1, Kimi K3, Kimi K2.7 Code, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.7 Plus, Qwen3.6 Plus, MiniMax M2.7, MiniMax M3, DeepSeek V4 Pro, DeepSeek V4 Flash et Hy3 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).",
|
||||
@@ -663,7 +666,8 @@ export const dict = {
|
||||
"workspace.lite.subscription.resetsIn": "Réinitialisation dans",
|
||||
"workspace.lite.subscription.useBalance":
|
||||
"Utilisez votre solde disponible après avoir atteint les limites d'utilisation",
|
||||
"workspace.lite.subscription.selectProvider": "Sélectionnez le fournisseur opencode pour utiliser les modèles Go.",
|
||||
"workspace.lite.subscription.selectProvider":
|
||||
'Sélectionnez "OpenCode Go" comme fournisseur dans votre configuration opencode pour utiliser les modèles Go.',
|
||||
"workspace.lite.providers.title": "Fournisseurs",
|
||||
"workspace.lite.providers.description": "Contrôlez les fournisseurs utilisés pour le routage.",
|
||||
"workspace.lite.providers.useChina": "Activer les modèles hébergés en Chine",
|
||||
|
||||
@@ -266,7 +266,8 @@ export const dict = {
|
||||
"go.cta.text": "Abbonati a Go",
|
||||
"go.cta.price": "$10/mese",
|
||||
"go.cta.promo": "$5 il primo mese",
|
||||
"go.pricing.body": "Go inizia a $5 per il primo mese, poi $10/mese.",
|
||||
"go.pricing.body":
|
||||
"Usalo con qualsiasi agente. $5 il primo mese, poi $10/mese. Ricarica il credito se necessario. Annulla in qualsiasi momento.",
|
||||
"go.graph.free": "Gratis",
|
||||
"go.graph.freePill": "Big Pickle e modelli gratuiti",
|
||||
"go.graph.go": "Go",
|
||||
@@ -305,15 +306,15 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"Include Grok 4.5, GLM-5.2, GLM-5.1, Kimi K3, Kimi K2.7 Code, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.7 Plus, Qwen3.6 Plus, MiniMax M2.7, MiniMax M3, DeepSeek V4 Pro, DeepSeek V4 Flash e Hy3",
|
||||
"go.how.title": "Come funziona Go",
|
||||
"go.how.body": "Go inizia a $5 per il primo mese, poi $10/mese.",
|
||||
"go.how.step1.title": "Abbonati a Go",
|
||||
"go.how.step1.beforeLink": "in",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "Connetti OpenCode",
|
||||
"go.how.step2.link": "opencode2 console login",
|
||||
"go.how.step2.afterLink": "e autorizza il dispositivo nel browser",
|
||||
"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",
|
||||
"go.how.step1.beforeLink": "segui le",
|
||||
"go.how.step1.link": "istruzioni di configurazione",
|
||||
"go.how.step2.title": "Abbonati a Go",
|
||||
"go.how.step2.link": "$5 il primo mese",
|
||||
"go.how.step2.afterLink": "poi $10/mese con limiti generosi",
|
||||
"go.how.step3.title": "Inizia a programmare",
|
||||
"go.how.step3.body": "con il provider opencode",
|
||||
"go.how.step3.body": "con accesso affidabile ai modelli open source",
|
||||
"go.privacy.title": "La tua privacy è importante per noi",
|
||||
"go.privacy.body":
|
||||
"Il piano è progettato principalmente per gli utenti internazionali, con modelli ospitati negli Stati Uniti, UE e Singapore per un accesso globale stabile.",
|
||||
@@ -346,8 +347,9 @@ export const dict = {
|
||||
"go.faq.a6": "Se hai bisogno di più utilizzo, puoi ricaricare il credito nel tuo account.",
|
||||
"go.faq.q7": "Posso annullare?",
|
||||
"go.faq.a7": "Sì, puoi annullare in qualsiasi momento.",
|
||||
"go.faq.q8": "Quale accesso è rinviato?",
|
||||
"go.faq.a8": "Il supporto per agenti esterni e account di servizio è rinviato.",
|
||||
"go.faq.q8": "Posso usare Go con altri agenti di coding?",
|
||||
"go.faq.a8":
|
||||
"Sì, puoi usare Go con qualsiasi agente. Segui le istruzioni di configurazione nel tuo agente di coding preferito.",
|
||||
|
||||
"go.faq.q9": "Qual è la differenza tra i modelli gratuiti e Go?",
|
||||
"go.faq.a9":
|
||||
@@ -656,7 +658,8 @@ export const dict = {
|
||||
"workspace.lite.subscription.monthlyUsage": "Utilizzo Mensile",
|
||||
"workspace.lite.subscription.resetsIn": "Si resetta tra",
|
||||
"workspace.lite.subscription.useBalance": "Usa il tuo saldo disponibile dopo aver raggiunto i limiti di utilizzo",
|
||||
"workspace.lite.subscription.selectProvider": "Seleziona il provider opencode per usare i modelli Go.",
|
||||
"workspace.lite.subscription.selectProvider":
|
||||
'Seleziona "OpenCode Go" come provider nella tua configurazione opencode per utilizzare i modelli Go.',
|
||||
"workspace.lite.providers.title": "Provider",
|
||||
"workspace.lite.providers.description": "Controlla quali provider vengono usati per il routing.",
|
||||
"workspace.lite.providers.useChina": "Abilita modelli ospitati in Cina",
|
||||
|
||||
@@ -265,7 +265,8 @@ export const dict = {
|
||||
"go.cta.text": "Goを購読する",
|
||||
"go.cta.price": "$10/月",
|
||||
"go.cta.promo": "初月 $5",
|
||||
"go.pricing.body": "Goは最初の月$5、その後$10/月で始まります。",
|
||||
"go.pricing.body":
|
||||
"どのエージェントでも使えます。最初の月$5、その後$10/月。必要に応じてクレジットを追加。いつでもキャンセルできます。",
|
||||
"go.graph.free": "無料",
|
||||
"go.graph.freePill": "Big Pickleと無料モデル",
|
||||
"go.graph.go": "Go",
|
||||
@@ -305,15 +306,15 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"Grok 4.5、GLM-5.2、GLM-5.1、Kimi K3、Kimi K2.7 Code、Kimi K2.6、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.7 Max、Qwen3.7 Plus、Qwen3.6 Plus、MiniMax M2.7、MiniMax M3、DeepSeek V4 Pro、DeepSeek V4 Flash、Hy3を含む",
|
||||
"go.how.title": "Goの仕組み",
|
||||
"go.how.body": "Goは最初の月$5、その後$10/月で始まります。",
|
||||
"go.how.step1.title": "Goを購読する",
|
||||
"go.how.step1.beforeLink": "で",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "OpenCodeを接続",
|
||||
"go.how.step2.link": "opencode2 console login",
|
||||
"go.how.step2.afterLink": "ブラウザでデバイスを承認します",
|
||||
"go.how.body": "Goは最初の月$5、その後$10/月で始まります。OpenCodeまたは任意のエージェントで使えます。",
|
||||
"go.how.step1.title": "アカウントを作成",
|
||||
"go.how.step1.beforeLink": "",
|
||||
"go.how.step1.link": "セットアップ手順はこちら",
|
||||
"go.how.step2.title": "Goを購読する",
|
||||
"go.how.step2.link": "最初の月$5",
|
||||
"go.how.step2.afterLink": "その後$10/月、ゆとりある上限付き",
|
||||
"go.how.step3.title": "コーディングを開始",
|
||||
"go.how.step3.body": "opencodeプロバイダーで",
|
||||
"go.how.step3.body": "オープンソースモデルへの安定したアクセスで",
|
||||
"go.privacy.title": "あなたのプライバシーは私たちにとって重要です",
|
||||
"go.privacy.body":
|
||||
"このプランは主に海外ユーザー向けに設計されており、米国、EU、シンガポールでホストされたモデルにより安定したグローバルアクセスを提供します。",
|
||||
@@ -346,8 +347,9 @@ export const dict = {
|
||||
"go.faq.a6": "利用枠を追加したい場合は、アカウントでクレジットをチャージできます。",
|
||||
"go.faq.q7": "キャンセルできますか?",
|
||||
"go.faq.a7": "はい、いつでもキャンセル可能です。",
|
||||
"go.faq.q8": "どのアクセスが延期されていますか?",
|
||||
"go.faq.a8": "外部エージェントとサービスアカウントのサポートは延期されています。",
|
||||
"go.faq.q8": "他のコーディングエージェントでGoを使えますか?",
|
||||
"go.faq.a8":
|
||||
"はい、Goは任意のエージェントで使用できます。お使いのコーディングエージェントのセットアップ手順に従ってください。",
|
||||
|
||||
"go.faq.q9": "無料モデルとGoの違いは何ですか?",
|
||||
"go.faq.a9":
|
||||
@@ -656,7 +658,8 @@ export const dict = {
|
||||
"workspace.lite.subscription.monthlyUsage": "月間利用量",
|
||||
"workspace.lite.subscription.resetsIn": "リセットまで",
|
||||
"workspace.lite.subscription.useBalance": "利用限度額に達したら利用可能な残高を使用する",
|
||||
"workspace.lite.subscription.selectProvider": "Goモデルを使用するにはopencodeプロバイダーを選択してください。",
|
||||
"workspace.lite.subscription.selectProvider":
|
||||
"Go モデルを使用するには、opencode の設定で「OpenCode Go」をプロバイダーとして選択してください。",
|
||||
"workspace.lite.providers.title": "プロバイダー",
|
||||
"workspace.lite.providers.description": "ルーティングに使用するプロバイダーを管理します。",
|
||||
"workspace.lite.providers.useChina": "中国でホストされているモデルを有効にする",
|
||||
|
||||
@@ -262,7 +262,8 @@ export const dict = {
|
||||
"go.cta.text": "Go 구독하기",
|
||||
"go.cta.price": "$10/월",
|
||||
"go.cta.promo": "첫 달 $5",
|
||||
"go.pricing.body": "Go는 첫 달 $5, 이후 $10/월로 시작합니다.",
|
||||
"go.pricing.body":
|
||||
"어떤 에이전트와도 사용할 수 있습니다. 첫 달 $5, 이후 $10/월. 필요하면 크레딧을 충전하세요. 언제든지 취소할 수 있습니다.",
|
||||
"go.graph.free": "무료",
|
||||
"go.graph.freePill": "Big Pickle 및 무료 모델",
|
||||
"go.graph.go": "Go",
|
||||
@@ -302,15 +303,15 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"Grok 4.5, GLM-5.2, GLM-5.1, Kimi K3, Kimi K2.7 Code, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.7 Plus, Qwen3.6 Plus, MiniMax M2.7, MiniMax M3, DeepSeek V4 Pro, DeepSeek V4 Flash, Hy3 포함",
|
||||
"go.how.title": "Go 작동 방식",
|
||||
"go.how.body": "Go는 첫 달 $5, 이후 $10/월로 시작합니다.",
|
||||
"go.how.step1.title": "Go 구독",
|
||||
"go.how.step1.beforeLink": "에서",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "OpenCode 연결",
|
||||
"go.how.step2.link": "opencode2 console login",
|
||||
"go.how.step2.afterLink": "브라우저에서 기기를 승인하세요",
|
||||
"go.how.body": "Go는 첫 달 $5, 이후 $10/월로 시작합니다. OpenCode 또는 어떤 에이전트와도 함께 사용할 수 있습니다.",
|
||||
"go.how.step1.title": "계정 생성",
|
||||
"go.how.step1.beforeLink": "",
|
||||
"go.how.step1.link": "설정 지침을 따르세요",
|
||||
"go.how.step2.title": "Go 구독",
|
||||
"go.how.step2.link": "첫 달 $5",
|
||||
"go.how.step2.afterLink": "이후 $10/월, 넉넉한 한도 포함",
|
||||
"go.how.step3.title": "코딩 시작",
|
||||
"go.how.step3.body": "opencode 공급자로",
|
||||
"go.how.step3.body": "오픈 소스 모델에 대한 안정적인 액세스와 함께",
|
||||
"go.privacy.title": "귀하의 프라이버시는 우리에게 중요합니다",
|
||||
"go.privacy.body":
|
||||
"이 플랜은 주로 글로벌 사용자를 위해 설계되었으며, 안정적인 글로벌 액세스를 위해 미국, EU, 싱가포르에 모델이 호스팅되어 있습니다.",
|
||||
@@ -342,8 +343,8 @@ export const dict = {
|
||||
"go.faq.a6": "사용량이 더 필요한 경우 계정에서 크레딧을 충전할 수 있습니다.",
|
||||
"go.faq.q7": "취소할 수 있나요?",
|
||||
"go.faq.a7": "네, 언제든지 취소할 수 있습니다.",
|
||||
"go.faq.q8": "어떤 액세스가 연기되었나요?",
|
||||
"go.faq.a8": "외부 에이전트와 서비스 계정 지원은 연기되었습니다.",
|
||||
"go.faq.q8": "다른 코딩 에이전트와 Go를 사용할 수 있나요?",
|
||||
"go.faq.a8": "네, Go는 어떤 에이전트와도 사용할 수 있습니다. 선호하는 코딩 에이전트의 설정 지침을 따르세요.",
|
||||
|
||||
"go.faq.q9": "무료 모델과 Go의 차이점은 무엇인가요?",
|
||||
"go.faq.a9":
|
||||
@@ -649,7 +650,8 @@ export const dict = {
|
||||
"workspace.lite.subscription.monthlyUsage": "월간 사용량",
|
||||
"workspace.lite.subscription.resetsIn": "초기화까지 남은 시간:",
|
||||
"workspace.lite.subscription.useBalance": "사용 한도 도달 후에는 보유 잔액 사용",
|
||||
"workspace.lite.subscription.selectProvider": "Go 모델을 사용하려면 opencode 공급자를 선택하세요.",
|
||||
"workspace.lite.subscription.selectProvider":
|
||||
'Go 모델을 사용하려면 opencode 설정에서 "OpenCode Go"를 공급자로 선택하세요.',
|
||||
"workspace.lite.providers.title": "공급자",
|
||||
"workspace.lite.providers.description": "라우팅에 사용할 공급자를 제어합니다.",
|
||||
"workspace.lite.providers.useChina": "중국에서 호스팅되는 모델 활성화",
|
||||
|
||||
@@ -266,7 +266,8 @@ export const dict = {
|
||||
"go.cta.text": "Abonner på Go",
|
||||
"go.cta.price": "$10/måned",
|
||||
"go.cta.promo": "$5 første måned",
|
||||
"go.pricing.body": "Go starter på $5 for den første måneden, deretter $10/måned.",
|
||||
"go.pricing.body":
|
||||
"Bruk med hvilken som helst agent. $5 første måned, deretter $10/måned. Fyll på kreditt ved behov. Avslutt når som helst.",
|
||||
"go.graph.free": "Gratis",
|
||||
"go.graph.freePill": "Big Pickle og gratis modeller",
|
||||
"go.graph.go": "Go",
|
||||
@@ -305,15 +306,16 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"Inkluderer Grok 4.5, GLM-5.2, GLM-5.1, Kimi K3, Kimi K2.7 Code, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.7 Plus, Qwen3.6 Plus, MiniMax M2.7, MiniMax M3, DeepSeek V4 Pro, DeepSeek V4 Flash og Hy3",
|
||||
"go.how.title": "Hvordan Go fungerer",
|
||||
"go.how.body": "Go starter på $5 for den første måneden, deretter $10/måned.",
|
||||
"go.how.step1.title": "Abonner på Go",
|
||||
"go.how.step1.beforeLink": "i",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "Koble til OpenCode",
|
||||
"go.how.step2.link": "opencode2 console login",
|
||||
"go.how.step2.afterLink": "og godkjenn enheten i nettleseren",
|
||||
"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.",
|
||||
"go.how.step1.title": "Opprett en konto",
|
||||
"go.how.step1.beforeLink": "følg",
|
||||
"go.how.step1.link": "oppsettsinstruksjonene",
|
||||
"go.how.step2.title": "Abonner på Go",
|
||||
"go.how.step2.link": "$5 første måned",
|
||||
"go.how.step2.afterLink": "deretter $10/måned med sjenerøse grenser",
|
||||
"go.how.step3.title": "Begynn å kode",
|
||||
"go.how.step3.body": "med opencode-leverandøren",
|
||||
"go.how.step3.body": "med pålitelig tilgang til åpen kildekode-modeller",
|
||||
"go.privacy.title": "Personvernet ditt er viktig for oss",
|
||||
"go.privacy.body":
|
||||
"Planen er primært designet for internasjonale brukere, med modeller driftet i USA, EU og Singapore for stabil global tilgang.",
|
||||
@@ -346,8 +348,9 @@ export const dict = {
|
||||
"go.faq.a6": "Hvis du trenger mer bruk, kan du fylle på kreditt i kontoen din.",
|
||||
"go.faq.q7": "Kan jeg avslutte?",
|
||||
"go.faq.a7": "Ja, du kan avslutte når som helst.",
|
||||
"go.faq.q8": "Hvilken tilgang er utsatt?",
|
||||
"go.faq.a8": "Støtte for eksterne agenter og tjenestekontoer er utsatt.",
|
||||
"go.faq.q8": "Kan jeg bruke Go med andre kodeagenter?",
|
||||
"go.faq.a8":
|
||||
"Ja, du kan bruke Go med hvilken som helst agent. Følg oppsettinstruksjonene i din foretrukne kodeagent.",
|
||||
|
||||
"go.faq.q9": "Hva er forskjellen mellom gratis modeller og Go?",
|
||||
"go.faq.a9":
|
||||
@@ -654,7 +657,8 @@ export const dict = {
|
||||
"workspace.lite.subscription.monthlyUsage": "Månedlig bruk",
|
||||
"workspace.lite.subscription.resetsIn": "Nullstilles om",
|
||||
"workspace.lite.subscription.useBalance": "Bruk din tilgjengelige saldo etter å ha nådd bruksgrensene",
|
||||
"workspace.lite.subscription.selectProvider": "Velg opencode-leverandøren for å bruke Go-modeller.",
|
||||
"workspace.lite.subscription.selectProvider":
|
||||
'Velg "OpenCode Go" som leverandør i opencode-konfigurasjonen din for å bruke Go-modeller.',
|
||||
"workspace.lite.providers.title": "Leverandører",
|
||||
"workspace.lite.providers.description": "Kontroller hvilke leverandører som brukes til ruting.",
|
||||
"workspace.lite.providers.useChina": "Aktiver modeller hostet i Kina",
|
||||
|
||||
@@ -267,7 +267,8 @@ export const dict = {
|
||||
"go.cta.text": "Zasubskrybuj Go",
|
||||
"go.cta.price": "$10/miesiąc",
|
||||
"go.cta.promo": "$5 pierwszy miesiąc",
|
||||
"go.pricing.body": "Go zaczyna się od $5 za pierwszy miesiąc, potem $10/miesiąc.",
|
||||
"go.pricing.body":
|
||||
"Używaj z dowolnym agentem. $5 za pierwszy miesiąc, potem $10/miesiąc. Doładuj konto w razie potrzeby. Anuluj w dowolnym momencie.",
|
||||
"go.graph.free": "Darmowe",
|
||||
"go.graph.freePill": "Big Pickle i darmowe modele",
|
||||
"go.graph.go": "Go",
|
||||
@@ -306,15 +307,16 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"Zawiera Grok 4.5, GLM-5.2, GLM-5.1, Kimi K3, Kimi K2.7 Code, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.7 Plus, Qwen3.6 Plus, MiniMax M2.7, MiniMax M3, DeepSeek V4 Pro, DeepSeek V4 Flash i Hy3",
|
||||
"go.how.title": "Jak działa Go",
|
||||
"go.how.body": "Go zaczyna się od $5 za pierwszy miesiąc, potem $10/miesiąc.",
|
||||
"go.how.step1.title": "Zasubskrybuj Go",
|
||||
"go.how.step1.beforeLink": "w",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "Połącz OpenCode",
|
||||
"go.how.step2.link": "opencode2 console login",
|
||||
"go.how.step2.afterLink": "i zatwierdź urządzenie w przeglądarce",
|
||||
"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.",
|
||||
"go.how.step1.title": "Załóż konto",
|
||||
"go.how.step1.beforeLink": "postępuj zgodnie z",
|
||||
"go.how.step1.link": "instrukcją konfiguracji",
|
||||
"go.how.step2.title": "Zasubskrybuj Go",
|
||||
"go.how.step2.link": "$5 za pierwszy miesiąc",
|
||||
"go.how.step2.afterLink": "potem $10/miesiąc z hojnymi limitami",
|
||||
"go.how.step3.title": "Zacznij kodować",
|
||||
"go.how.step3.body": "z dostawcą opencode",
|
||||
"go.how.step3.body": "z niezawodnym dostępem do modeli open source",
|
||||
"go.privacy.title": "Twoja prywatność jest dla nas ważna",
|
||||
"go.privacy.body":
|
||||
"Plan został zaprojektowany głównie dla użytkowników międzynarodowych, z modelami hostowanymi w USA, UE i Singapurze, aby zapewnić stabilny globalny dostęp.",
|
||||
@@ -347,8 +349,9 @@ export const dict = {
|
||||
"go.faq.a6": "Jeśli potrzebujesz większego użycia, możesz doładować środki na swoim koncie.",
|
||||
"go.faq.q7": "Czy mogę anulować?",
|
||||
"go.faq.a7": "Tak, możesz anulować w dowolnym momencie.",
|
||||
"go.faq.q8": "Jaki dostęp jest odroczony?",
|
||||
"go.faq.a8": "Obsługa zewnętrznych agentów i kont usług jest odroczona.",
|
||||
"go.faq.q8": "Czy mogę używać Go z innymi agentami kodującymi?",
|
||||
"go.faq.a8":
|
||||
"Tak, możesz używać Go z dowolnym agentem. Postępuj zgodnie z instrukcjami konfiguracji w swoim preferowanym agencie.",
|
||||
|
||||
"go.faq.q9": "Jaka jest różnica między darmowymi modelami a Go?",
|
||||
"go.faq.a9":
|
||||
@@ -655,7 +658,8 @@ export const dict = {
|
||||
"workspace.lite.subscription.monthlyUsage": "Użycie miesięczne",
|
||||
"workspace.lite.subscription.resetsIn": "Resetuje się za",
|
||||
"workspace.lite.subscription.useBalance": "Użyj dostępnego salda po osiągnięciu limitów użycia",
|
||||
"workspace.lite.subscription.selectProvider": "Wybierz dostawcę opencode, aby używać modeli Go.",
|
||||
"workspace.lite.subscription.selectProvider":
|
||||
'Wybierz "OpenCode Go" jako dostawcę w konfiguracji opencode, aby używać modeli Go.',
|
||||
"workspace.lite.providers.title": "Dostawcy",
|
||||
"workspace.lite.providers.description": "Kontroluj, którzy dostawcy są używani do routingu.",
|
||||
"workspace.lite.providers.useChina": "Włącz modele hostowane w Chinach",
|
||||
|
||||
@@ -270,7 +270,8 @@ export const dict = {
|
||||
"go.cta.text": "Подписаться на Go",
|
||||
"go.cta.price": "$10/месяц",
|
||||
"go.cta.promo": "$5 первый месяц",
|
||||
"go.pricing.body": "Go начинается с $5 за первый месяц, затем $10/месяц.",
|
||||
"go.pricing.body":
|
||||
"Используйте с любым агентом. $5 за первый месяц, затем $10/месяц. Пополняйте баланс при необходимости. Отменить можно в любое время.",
|
||||
"go.graph.free": "Бесплатно",
|
||||
"go.graph.freePill": "Big Pickle и бесплатные модели",
|
||||
"go.graph.go": "Go",
|
||||
@@ -310,15 +311,16 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"Включает Grok 4.5, GLM-5.2, GLM-5.1, Kimi K3, Kimi K2.7 Code, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.7 Plus, Qwen3.6 Plus, MiniMax M2.7, MiniMax M3, DeepSeek V4 Pro, DeepSeek V4 Flash и Hy3",
|
||||
"go.how.title": "Как работает Go",
|
||||
"go.how.body": "Go начинается с $5 за первый месяц, затем $10/месяц.",
|
||||
"go.how.step1.title": "Подпишитесь на Go",
|
||||
"go.how.step1.beforeLink": "в",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "Подключить OpenCode",
|
||||
"go.how.step2.link": "opencode2 console login",
|
||||
"go.how.step2.afterLink": "и подтвердите устройство в браузере",
|
||||
"go.how.body":
|
||||
"Go начинается с $5 за первый месяц, затем $10/месяц. Вы можете использовать его с OpenCode или любым агентом.",
|
||||
"go.how.step1.title": "Создайте аккаунт",
|
||||
"go.how.step1.beforeLink": "следуйте",
|
||||
"go.how.step1.link": "инструкциям по настройке",
|
||||
"go.how.step2.title": "Подпишитесь на Go",
|
||||
"go.how.step2.link": "$5 за первый месяц",
|
||||
"go.how.step2.afterLink": "затем $10/месяц с щедрыми лимитами",
|
||||
"go.how.step3.title": "Начните кодить",
|
||||
"go.how.step3.body": "с провайдером opencode",
|
||||
"go.how.step3.body": "с надежным доступом к open-source моделям",
|
||||
"go.privacy.title": "Ваша приватность важна для нас",
|
||||
"go.privacy.body":
|
||||
"План разработан в первую очередь для международных пользователей, с моделями, размещенными в США, ЕС и Сингапуре для стабильного глобального доступа.",
|
||||
@@ -351,8 +353,9 @@ export const dict = {
|
||||
"go.faq.a6": "Если вам нужно больше использования, вы можете пополнить баланс в своем аккаунте.",
|
||||
"go.faq.q7": "Могу ли я отменить подписку?",
|
||||
"go.faq.a7": "Да, вы можете отменить подписку в любое время.",
|
||||
"go.faq.q8": "Какая поддержка отложена?",
|
||||
"go.faq.a8": "Поддержка внешних агентов и сервисных аккаунтов отложена.",
|
||||
"go.faq.q8": "Могу ли я использовать Go с другими кодинг-агентами?",
|
||||
"go.faq.a8":
|
||||
"Да, вы можете использовать Go с любым агентом. Следуйте инструкциям по настройке в вашем предпочитаемом агенте.",
|
||||
|
||||
"go.faq.q9": "В чем разница между бесплатными моделями и Go?",
|
||||
"go.faq.a9":
|
||||
@@ -661,7 +664,8 @@ export const dict = {
|
||||
"workspace.lite.subscription.monthlyUsage": "Ежемесячное использование",
|
||||
"workspace.lite.subscription.resetsIn": "Сброс через",
|
||||
"workspace.lite.subscription.useBalance": "Использовать доступный баланс после достижения лимитов",
|
||||
"workspace.lite.subscription.selectProvider": "Выберите провайдер opencode для использования моделей Go.",
|
||||
"workspace.lite.subscription.selectProvider":
|
||||
'Выберите "OpenCode Go" в качестве провайдера в настройках opencode для использования моделей Go.',
|
||||
"workspace.lite.providers.title": "Провайдеры",
|
||||
"workspace.lite.providers.description": "Управляйте провайдерами, используемыми для маршрутизации.",
|
||||
"workspace.lite.providers.useChina": "Включить модели, размещенные в Китае",
|
||||
|
||||
@@ -265,7 +265,7 @@ export const dict = {
|
||||
"go.cta.text": "สมัครสมาชิก Go",
|
||||
"go.cta.price": "$10/เดือน",
|
||||
"go.cta.promo": "$5 เดือนแรก",
|
||||
"go.pricing.body": "Go เริ่มต้นที่ $5 สำหรับเดือนแรก จากนั้น $10/เดือน",
|
||||
"go.pricing.body": "ใช้กับเอเจนต์ใดก็ได้ $5 ในเดือนแรก จากนั้น $10/เดือน เติมเครดิตหากจำเป็น ยกเลิกได้ตลอดเวลา",
|
||||
"go.graph.free": "ฟรี",
|
||||
"go.graph.freePill": "Big Pickle และโมเดลฟรี",
|
||||
"go.graph.go": "Go",
|
||||
@@ -304,15 +304,15 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"รวมถึง Grok 4.5, GLM-5.2, GLM-5.1, Kimi K3, Kimi K2.7 Code, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.7 Plus, Qwen3.6 Plus, MiniMax M2.7, MiniMax M3, DeepSeek V4 Pro, DeepSeek V4 Flash และ Hy3",
|
||||
"go.how.title": "Go ทำงานอย่างไร",
|
||||
"go.how.body": "Go เริ่มต้นที่ $5 สำหรับเดือนแรก จากนั้น $10/เดือน",
|
||||
"go.how.step1.title": "สมัครสมาชิก Go",
|
||||
"go.how.step1.beforeLink": "ใน",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "เชื่อมต่อ OpenCode",
|
||||
"go.how.step2.link": "opencode2 console login",
|
||||
"go.how.step2.afterLink": "และอนุมัติอุปกรณ์ในเบราว์เซอร์",
|
||||
"go.how.body": "Go เริ่มต้นที่ $5 สำหรับเดือนแรก จากนั้น $10/เดือน คุณสามารถใช้กับ OpenCode หรือเอเจนต์ใดก็ได้",
|
||||
"go.how.step1.title": "สร้างบัญชี",
|
||||
"go.how.step1.beforeLink": "ทำตาม",
|
||||
"go.how.step1.link": "คำแนะนำการตั้งค่า",
|
||||
"go.how.step2.title": "สมัครสมาชิก Go",
|
||||
"go.how.step2.link": "$5 เดือนแรก",
|
||||
"go.how.step2.afterLink": "จากนั้น $10/เดือน พร้อมขีดจำกัดที่เอื้อเฟื้อ",
|
||||
"go.how.step3.title": "เริ่มเขียนโค้ด",
|
||||
"go.how.step3.body": "ด้วยผู้ให้บริการ opencode",
|
||||
"go.how.step3.body": "ด้วยการเข้าถึงโมเดลโอเพนซอร์สที่เชื่อถือได้",
|
||||
"go.privacy.title": "ความเป็นส่วนตัวของคุณสำคัญสำหรับเรา",
|
||||
"go.privacy.body":
|
||||
"แผนนี้ออกแบบมาเพื่อผู้ใช้งานระหว่างประเทศเป็นหลัก โดยมีโมเดลโฮสต์ในสหรัฐอเมริกา สหภาพยุโรป และสิงคโปร์ เพื่อการเข้าถึงทั่วโลกที่เสถียร",
|
||||
@@ -345,8 +345,8 @@ export const dict = {
|
||||
"go.faq.a6": "หากคุณต้องการใช้งานเพิ่ม คุณสามารถเติมเครดิตในบัญชีของคุณได้",
|
||||
"go.faq.q7": "ฉันสามารถยกเลิกได้หรือไม่?",
|
||||
"go.faq.a7": "ได้ คุณสามารถยกเลิกได้ตลอดเวลา",
|
||||
"go.faq.q8": "การเข้าถึงใดถูกเลื่อนออกไป?",
|
||||
"go.faq.a8": "การรองรับเอเจนต์ภายนอกและบัญชีบริการถูกเลื่อนออกไป",
|
||||
"go.faq.q8": "ฉันสามารถใช้ Go กับเอเจนต์เขียนโค้ดอื่นได้หรือไม่?",
|
||||
"go.faq.a8": "ได้ คุณสามารถใช้ Go กับเอเจนต์ใดก็ได้ ทำตามคำแนะนำการตั้งค่าในเอเจนต์เขียนโค้ดที่คุณต้องการ",
|
||||
|
||||
"go.faq.q9": "ความแตกต่างระหว่างโมเดลฟรีและ Go คืออะไร?",
|
||||
"go.faq.a9":
|
||||
@@ -653,7 +653,8 @@ export const dict = {
|
||||
"workspace.lite.subscription.monthlyUsage": "การใช้งานรายเดือน",
|
||||
"workspace.lite.subscription.resetsIn": "รีเซ็ตใน",
|
||||
"workspace.lite.subscription.useBalance": "ใช้ยอดคงเหลือของคุณหลังจากถึงขีดจำกัดการใช้งาน",
|
||||
"workspace.lite.subscription.selectProvider": "เลือกผู้ให้บริการ opencode เพื่อใช้โมเดล Go",
|
||||
"workspace.lite.subscription.selectProvider":
|
||||
'เลือก "OpenCode Go" เป็นผู้ให้บริการในการตั้งค่า opencode ของคุณเพื่อใช้โมเดล Go',
|
||||
"workspace.lite.providers.title": "ผู้ให้บริการ",
|
||||
"workspace.lite.providers.description": "ควบคุมผู้ให้บริการที่ใช้สำหรับการกำหนดเส้นทาง",
|
||||
"workspace.lite.providers.useChina": "เปิดใช้โมเดลที่โฮสต์ในจีน",
|
||||
|
||||
@@ -268,7 +268,8 @@ export const dict = {
|
||||
"go.cta.text": "Go'ya abone ol",
|
||||
"go.cta.price": "Ayda 10$",
|
||||
"go.cta.promo": "İlk ay $5",
|
||||
"go.pricing.body": "Go ilk ay $5, sonrasında ayda 10$ fiyatıyla başlar.",
|
||||
"go.pricing.body":
|
||||
"Herhangi bir ajanla kullanın. İlk ay $5, sonrasında ayda 10$. Gerekirse kredi yükleyin. İstediğiniz zaman iptal edin.",
|
||||
"go.graph.free": "Ücretsiz",
|
||||
"go.graph.freePill": "Big Pickle ve ücretsiz modeller",
|
||||
"go.graph.go": "Go",
|
||||
@@ -308,15 +309,16 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"Grok 4.5, GLM-5.2, GLM-5.1, Kimi K3, Kimi K2.7 Code, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.7 Plus, Qwen3.6 Plus, MiniMax M2.7, MiniMax M3, DeepSeek V4 Pro, DeepSeek V4 Flash ve Hy3 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.",
|
||||
"go.how.step1.title": "Go'ya abone olun",
|
||||
"go.how.step1.beforeLink": "içinde",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "OpenCode’u bağlayın",
|
||||
"go.how.step2.link": "opencode2 console login",
|
||||
"go.how.step2.afterLink": "ve cihazı tarayıcınızda onaylayın",
|
||||
"go.how.body":
|
||||
"Go ilk ay $5, sonrasında ayda 10$ fiyatıyla başlar. OpenCode veya herhangi bir ajanla kullanabilirsiniz.",
|
||||
"go.how.step1.title": "Bir hesap oluşturun",
|
||||
"go.how.step1.beforeLink": "takip edin",
|
||||
"go.how.step1.link": "kurulum talimatları",
|
||||
"go.how.step2.title": "Go'ya abone olun",
|
||||
"go.how.step2.link": "İlk ay $5",
|
||||
"go.how.step2.afterLink": "sonrasında cömert limitlerle ayda 10$",
|
||||
"go.how.step3.title": "Kodlamaya başlayın",
|
||||
"go.how.step3.body": "opencode sağlayıcısıyla",
|
||||
"go.how.step3.body": "açık kaynaklı modellere güvenilir erişimle",
|
||||
"go.privacy.title": "Gizliliğiniz bizim için önemlidir",
|
||||
"go.privacy.body":
|
||||
"Bu plan öncelikle uluslararası kullanıcılar için tasarlanmış olup, istikrarlı küresel erişim için modeller ABD, AB ve Singapur'da barındırılmaktadır.",
|
||||
@@ -349,8 +351,9 @@ export const dict = {
|
||||
"go.faq.a6": "Daha fazla kullanıma ihtiyacınız varsa, hesabınıza kredi yükleyebilirsiniz.",
|
||||
"go.faq.q7": "İptal edebilir miyim?",
|
||||
"go.faq.a7": "Evet, istediğiniz zaman iptal edebilirsiniz.",
|
||||
"go.faq.q8": "Hangi erişim ertelendi?",
|
||||
"go.faq.a8": "Harici ajan ve hizmet hesabı desteği ertelendi.",
|
||||
"go.faq.q8": "Go'yu diğer kodlama ajanlarıyla kullanabilir miyim?",
|
||||
"go.faq.a8":
|
||||
"Evet, Go'yu herhangi bir ajanla kullanabilirsiniz. Tercih ettiğiniz kodlama ajanındaki kurulum talimatlarını izleyin.",
|
||||
|
||||
"go.faq.q9": "Ücretsiz modeller ve Go arasındaki fark nedir?",
|
||||
"go.faq.a9":
|
||||
@@ -657,7 +660,8 @@ export const dict = {
|
||||
"workspace.lite.subscription.monthlyUsage": "Aylık Kullanım",
|
||||
"workspace.lite.subscription.resetsIn": "Sıfırlama süresi",
|
||||
"workspace.lite.subscription.useBalance": "Kullanım limitlerine ulaştıktan sonra mevcut bakiyenizi kullanın",
|
||||
"workspace.lite.subscription.selectProvider": "Go modellerini kullanmak için opencode sağlayıcısını seçin.",
|
||||
"workspace.lite.subscription.selectProvider":
|
||||
'Go modellerini kullanmak için opencode yapılandırmanızda "OpenCode Go"\'yu sağlayıcı olarak seçin.',
|
||||
"workspace.lite.providers.title": "Sağlayıcılar",
|
||||
"workspace.lite.providers.description": "Yönlendirme için hangi sağlayıcıların kullanılacağını kontrol edin.",
|
||||
"workspace.lite.providers.useChina": "Çin'de barındırılan modelleri etkinleştir",
|
||||
|
||||
@@ -267,7 +267,8 @@ export const dict = {
|
||||
"go.cta.text": "Підписатися на Go",
|
||||
"go.cta.price": "$10/місяць",
|
||||
"go.cta.promo": "$5 перший місяць",
|
||||
"go.pricing.body": "Go починається від $5 за перший місяць, потім $10/місяць.",
|
||||
"go.pricing.body":
|
||||
"Використовуйте з будь-яким агентом. $5 перший місяць, потім $10/місяць. Поповнюйте за потреби. Скасуйте в будь-який час.",
|
||||
"go.graph.free": "Безкоштовно",
|
||||
"go.graph.freePill": "Big Pickle та безкоштовні моделі",
|
||||
"go.graph.go": "Go",
|
||||
@@ -306,15 +307,16 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"Включає Grok 4.5, GLM-5.2, GLM-5.1, Kimi K3, Kimi K2.7 Code, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.7 Plus, Qwen3.6 Plus, MiniMax M2.7, MiniMax M3, DeepSeek V4 Pro, DeepSeek V4 Flash та Hy3",
|
||||
"go.how.title": "Як працює Go",
|
||||
"go.how.body": "Go починається від $5 за перший місяць, потім $10/місяць.",
|
||||
"go.how.step1.title": "Підпишіться на Go",
|
||||
"go.how.step1.beforeLink": "в",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "Підключити OpenCode",
|
||||
"go.how.step2.link": "opencode2 console login",
|
||||
"go.how.step2.afterLink": "і підтвердьте пристрій у браузері",
|
||||
"go.how.body":
|
||||
"Go починається від $5 за перший місяць, потім $10/місяць. Використовуйте з OpenCode або будь-яким агентом.",
|
||||
"go.how.step1.title": "Створіть обліковий запис",
|
||||
"go.how.step1.beforeLink": "дотримуйтесь",
|
||||
"go.how.step1.link": "інструкцій з налаштування",
|
||||
"go.how.step2.title": "Підпишіться на Go",
|
||||
"go.how.step2.link": "$5 перший місяць",
|
||||
"go.how.step2.afterLink": "потім $10/місяць із щедрими лімітами",
|
||||
"go.how.step3.title": "Почніть кодувати",
|
||||
"go.how.step3.body": "з провайдером opencode",
|
||||
"go.how.step3.body": "з надійним доступом до моделей з відкритим кодом",
|
||||
"go.privacy.title": "Ваша конфіденційність важлива для нас",
|
||||
"go.privacy.body":
|
||||
"План розроблений переважно для міжнародних користувачів, з моделями, розміщеними в США, ЄС та Сінгапурі для стабільного глобального доступу.",
|
||||
@@ -347,8 +349,8 @@ export const dict = {
|
||||
"go.faq.a6": "Якщо вам потрібно більше використання, ви можете поповнити баланс в обліковому записі.",
|
||||
"go.faq.q7": "Чи можна скасувати?",
|
||||
"go.faq.a7": "Так, ви можете скасувати в будь-який час.",
|
||||
"go.faq.q8": "Яку підтримку відкладено?",
|
||||
"go.faq.a8": "Підтримку зовнішніх агентів і сервісних акаунтів відкладено.",
|
||||
"go.faq.q8": "Чи можна використовувати Go з іншими агентами кодування?",
|
||||
"go.faq.a8": "Так, ви можете використовувати Go з будь-яким агентом.",
|
||||
|
||||
"go.faq.q9": "Яка різниця між безкоштовними моделями та Go?",
|
||||
"go.faq.a9":
|
||||
@@ -655,7 +657,7 @@ export const dict = {
|
||||
"workspace.lite.subscription.monthlyUsage": "Місячне використання",
|
||||
"workspace.lite.subscription.resetsIn": "Скидається через",
|
||||
"workspace.lite.subscription.useBalance": "Використовуйте доступний баланс після досягнення лімітів",
|
||||
"workspace.lite.subscription.selectProvider": "Виберіть провайдер opencode, щоб використовувати моделі Go.",
|
||||
"workspace.lite.subscription.selectProvider": 'Виберіть "OpenCode Go" як провайдера в конфігурації opencode.',
|
||||
"workspace.lite.providers.title": "Провайдери",
|
||||
"workspace.lite.providers.description": "Керуйте провайдерами, які використовуються для маршрутизації.",
|
||||
"workspace.lite.providers.useChina": "Увімкнути моделі, розміщені в Китаї",
|
||||
|
||||
@@ -256,7 +256,7 @@ export const dict = {
|
||||
"go.cta.text": "订阅 Go",
|
||||
"go.cta.price": "$10/月",
|
||||
"go.cta.promo": "首月 $5",
|
||||
"go.pricing.body": "Go 起价为首月 $5,之后 $10/月。",
|
||||
"go.pricing.body": "可配合任何代理使用。首月 $5,之后 $10/月。如有需要可充值。随时取消。",
|
||||
"go.graph.free": "免费",
|
||||
"go.graph.freePill": "Big Pickle 和免费模型",
|
||||
"go.graph.go": "Go",
|
||||
@@ -295,15 +295,15 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"包含 Grok 4.5, GLM-5.2, GLM-5.1, Kimi K3, Kimi K2.7 Code、Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.7 Max, Qwen3.7 Plus, Qwen3.6 Plus, MiniMax M2.7、MiniMax M3、DeepSeek V4 Pro、DeepSeek V4 Flash 和 Hy3",
|
||||
"go.how.title": "Go 如何工作",
|
||||
"go.how.body": "Go 起价为首月 $5,之后 $10/月。",
|
||||
"go.how.step1.title": "订阅 Go",
|
||||
"go.how.step1.beforeLink": "在",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "连接 OpenCode",
|
||||
"go.how.step2.link": "opencode2 console login",
|
||||
"go.how.step2.afterLink": "并在浏览器中批准设备",
|
||||
"go.how.body": "Go 起价为首月 $5,之后 $10/月。您可以将其与 OpenCode 或任何代理搭配使用。",
|
||||
"go.how.step1.title": "创建账户",
|
||||
"go.how.step1.beforeLink": "遵循",
|
||||
"go.how.step1.link": "设置说明",
|
||||
"go.how.step2.title": "订阅 Go",
|
||||
"go.how.step2.link": "首月 $5",
|
||||
"go.how.step2.afterLink": "之后 $10/月,额度充裕",
|
||||
"go.how.step3.title": "开始编程",
|
||||
"go.how.step3.body": "使用 opencode 提供商",
|
||||
"go.how.step3.body": "可靠访问开源模型",
|
||||
"go.privacy.title": "您的隐私对我们很重要",
|
||||
"go.privacy.body": "该计划主要面向国际用户设计,模型部署在美国、欧盟和新加坡,以确保稳定的全球访问。",
|
||||
"go.privacy.contactAfter": "如果您有任何问题。",
|
||||
@@ -332,8 +332,8 @@ export const dict = {
|
||||
"go.faq.a6": "如果您需要更多用量,可以在账户中充值余额。",
|
||||
"go.faq.q7": "我可以取消吗?",
|
||||
"go.faq.a7": "可以,您可以随时取消。",
|
||||
"go.faq.q8": "哪些访问支持尚未推出?",
|
||||
"go.faq.a8": "外部代理和服务账户支持尚未推出。",
|
||||
"go.faq.q8": "我可以在其他编程代理中使用 Go 吗?",
|
||||
"go.faq.a8": "可以,您可以在任何代理中使用 Go。请遵循您首选编程代理中的设置说明。",
|
||||
|
||||
"go.faq.q9": "免费模型和 Go 之间的区别是什么?",
|
||||
"go.faq.a9":
|
||||
@@ -634,7 +634,8 @@ export const dict = {
|
||||
"workspace.lite.subscription.monthlyUsage": "每月用量",
|
||||
"workspace.lite.subscription.resetsIn": "重置于",
|
||||
"workspace.lite.subscription.useBalance": "达到使用限额后使用您的可用余额",
|
||||
"workspace.lite.subscription.selectProvider": "选择 opencode 提供商以使用 Go 模型。",
|
||||
"workspace.lite.subscription.selectProvider":
|
||||
"在你的 opencode 配置中选择「OpenCode Go」作为提供商,即可使用 Go 模型。",
|
||||
"workspace.lite.providers.title": "提供商",
|
||||
"workspace.lite.providers.description": "控制用于路由的提供商。",
|
||||
"workspace.lite.providers.useChina": "启用部署在中国的模型",
|
||||
|
||||
@@ -256,7 +256,7 @@ export const dict = {
|
||||
"go.cta.text": "訂閱 Go",
|
||||
"go.cta.price": "$10/月",
|
||||
"go.cta.promo": "首月 $5",
|
||||
"go.pricing.body": "Go 起價為首月 $5,之後 $10/月。",
|
||||
"go.pricing.body": "可搭配任何代理使用。首月 $5,之後 $10/月。如有需要可儲值。隨時取消。",
|
||||
"go.graph.free": "免費",
|
||||
"go.graph.freePill": "Big Pickle 與免費模型",
|
||||
"go.graph.go": "Go",
|
||||
@@ -295,15 +295,15 @@ export const dict = {
|
||||
"go.problem.item4":
|
||||
"包含 Grok 4.5、GLM-5.2、GLM-5.1、Kimi K3、Kimi K2.7 Code、Kimi K2.6、MiMo-V2.5-Pro、MiMo-V2.5、Qwen3.7 Max、Qwen3.7 Plus、Qwen3.6 Plus、MiniMax M2.7、MiniMax M3、DeepSeek V4 Pro、DeepSeek V4 Flash 與 Hy3",
|
||||
"go.how.title": "Go 如何運作",
|
||||
"go.how.body": "Go 起價為首月 $5,之後 $10/月。",
|
||||
"go.how.step1.title": "訂閱 Go",
|
||||
"go.how.step1.beforeLink": "在",
|
||||
"go.how.step1.link": "OpenCode Console",
|
||||
"go.how.step2.title": "連接 OpenCode",
|
||||
"go.how.step2.link": "opencode2 console login",
|
||||
"go.how.step2.afterLink": "並在瀏覽器中核准裝置",
|
||||
"go.how.body": "Go 起價為首月 $5,之後 $10/月。您可以將其與 OpenCode 或任何代理搭配使用。",
|
||||
"go.how.step1.title": "建立帳號",
|
||||
"go.how.step1.beforeLink": "遵循",
|
||||
"go.how.step1.link": "設定說明",
|
||||
"go.how.step2.title": "訂閱 Go",
|
||||
"go.how.step2.link": "首月 $5",
|
||||
"go.how.step2.afterLink": "之後 $10/月,額度充裕",
|
||||
"go.how.step3.title": "開始編碼",
|
||||
"go.how.step3.body": "使用 opencode 提供商",
|
||||
"go.how.step3.body": "穩定存取開源模型",
|
||||
"go.privacy.title": "你的隱私對我們很重要",
|
||||
"go.privacy.body": "該方案主要面向國際用戶設計,模型託管在美國、歐盟和新加坡,以確保全球穩定存取。",
|
||||
"go.privacy.contactAfter": "如果你有任何問題。",
|
||||
@@ -332,8 +332,8 @@ export const dict = {
|
||||
"go.faq.a6": "如果你需要更多使用量,可以在帳戶中儲值額度。",
|
||||
"go.faq.q7": "我可以取消嗎?",
|
||||
"go.faq.a7": "可以,你可以隨時取消。",
|
||||
"go.faq.q8": "哪些存取支援尚未推出?",
|
||||
"go.faq.a8": "外部代理和服務帳戶支援尚未推出。",
|
||||
"go.faq.q8": "我可以在其他編碼代理中使用 Go 嗎?",
|
||||
"go.faq.a8": "可以,你可以將 Go 與任何代理一起使用。請在你偏好的編碼代理中按照設定說明進行配置。",
|
||||
|
||||
"go.faq.q9": "免費模型與 Go 有什麼區別?",
|
||||
"go.faq.a9":
|
||||
@@ -634,7 +634,8 @@ export const dict = {
|
||||
"workspace.lite.subscription.monthlyUsage": "每月使用量",
|
||||
"workspace.lite.subscription.resetsIn": "重置時間:",
|
||||
"workspace.lite.subscription.useBalance": "達到使用限制後使用您的可用餘額",
|
||||
"workspace.lite.subscription.selectProvider": "選擇 opencode 提供商以使用 Go 模型。",
|
||||
"workspace.lite.subscription.selectProvider":
|
||||
"在您的 opencode 設定中選擇「OpenCode Go」作為提供商,即可使用 Go 模型。",
|
||||
"workspace.lite.providers.title": "提供商",
|
||||
"workspace.lite.providers.description": "控制用於路由的提供商。",
|
||||
"workspace.lite.providers.useChina": "啟用部署在中國的模型",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import "./index.css"
|
||||
import { createAsync, query } from "@solidjs/router"
|
||||
import { Title, Meta } from "@solidjs/meta"
|
||||
import { For, createSignal, onCleanup, onMount } from "solid-js"
|
||||
import { For, createMemo, createSignal, onCleanup, onMount } from "solid-js"
|
||||
//import { HttpHeader } from "@solidjs/start"
|
||||
import goLogoLight from "../../asset/go-ornate-light.svg"
|
||||
import goLogoDark from "../../asset/go-ornate-dark.svg"
|
||||
@@ -10,11 +11,17 @@ import { Legal } from "~/component/legal"
|
||||
import { Footer } from "~/component/footer"
|
||||
import { Header } from "~/component/header"
|
||||
import { config } from "~/config"
|
||||
import { getLastSeenWorkspaceID } from "../workspace/common"
|
||||
import { IconMiniMax, IconMiMo, IconZai, IconAlibaba, IconDeepSeek } from "~/component/icon"
|
||||
import { useI18n } from "~/context/i18n"
|
||||
import { useLanguage } from "~/context/language"
|
||||
import { LocaleLinks } from "~/component/locale-links"
|
||||
|
||||
const checkLoggedIn = query(async () => {
|
||||
"use server"
|
||||
return await getLastSeenWorkspaceID().catch(() => undefined)
|
||||
}, "checkLoggedIn.get")
|
||||
|
||||
const models = [
|
||||
"Grok 4.5",
|
||||
"GLM-5.2",
|
||||
@@ -181,7 +188,8 @@ function LimitsGraph(props: { href: string }) {
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const subscribeUrl = "/console/go"
|
||||
const workspaceID = createAsync(() => checkLoggedIn())
|
||||
const subscribeUrl = createMemo(() => (workspaceID() ? `/workspace/${workspaceID()}/go` : "/auth"))
|
||||
const i18n = useI18n()
|
||||
const language = useLanguage()
|
||||
return (
|
||||
@@ -199,6 +207,8 @@ export default function Home() {
|
||||
<Meta name="twitter:title" content={i18n.t("go.title")} />
|
||||
<Meta name="twitter:description" content={i18n.t("go.meta.description")} />
|
||||
<Meta name="twitter:image" content="/social-share-black.png" />
|
||||
<Meta name="opencode:auth" content={workspaceID() ? "true" : "false"} />
|
||||
|
||||
<div data-component="container">
|
||||
<Header go hideGetStarted />
|
||||
|
||||
@@ -299,7 +309,7 @@ export default function Home() {
|
||||
</div>
|
||||
*/}
|
||||
</div>
|
||||
<a href={subscribeUrl}>
|
||||
<a href={subscribeUrl()}>
|
||||
<span>
|
||||
<For
|
||||
each={i18n
|
||||
@@ -372,7 +382,7 @@ export default function Home() {
|
||||
<span>[1]</span>
|
||||
<div>
|
||||
<strong>{i18n.t("go.how.step1.title")}</strong> - {i18n.t("go.how.step1.beforeLink")}{" "}
|
||||
<a href="/console/go" title={i18n.t("go.how.step1.link")}>
|
||||
<a href={language.route("/docs/go/#how-it-works")} title={i18n.t("go.how.step1.link")}>
|
||||
{i18n.t("go.how.step1.link")}
|
||||
</a>
|
||||
</div>
|
||||
@@ -381,7 +391,8 @@ export default function Home() {
|
||||
<span>[2]</span>
|
||||
<div>
|
||||
<strong>{i18n.t("go.how.step2.title")}</strong> -{" "}
|
||||
<a href="/v2/docs/go">{i18n.t("go.how.step2.link")}</a> {i18n.t("go.how.step2.afterLink")}
|
||||
<a href={language.route("/docs/go/#pricing")}>{i18n.t("go.how.step2.link")}</a>{" "}
|
||||
{i18n.t("go.how.step2.afterLink")}
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
@@ -418,7 +429,7 @@ export default function Home() {
|
||||
{i18n.t("go.faq.a4.p1.beforePricing")}{" "}
|
||||
<a href={language.route("/docs/go/#pricing")}>{i18n.t("go.faq.a4.p1.pricingLink")}</a>{" "}
|
||||
{i18n.t("go.faq.a4.p1.afterPricing")} {i18n.t("go.faq.a4.p2.beforeAccount")}{" "}
|
||||
<a href={subscribeUrl}>{i18n.t("go.faq.a4.p2.accountLink")}</a>. {i18n.t("go.faq.a4.p3")}
|
||||
<a href={subscribeUrl()}>{i18n.t("go.faq.a4.p2.accountLink")}</a>. {i18n.t("go.faq.a4.p3")}
|
||||
</Faq>
|
||||
</li>
|
||||
<li>
|
||||
|
||||
@@ -404,7 +404,6 @@ const layer = Layer.effect(
|
||||
.get()
|
||||
.integrations.get(attempt.integrationID)
|
||||
?.implementations.get(attempt.methodID)
|
||||
const previous = (yield* credentials.list(attempt.integrationID)).at(-1)
|
||||
const persistence = yield* Effect.sync(() => attempt.label ?? implementation?.label?.(exit.value)).pipe(
|
||||
Effect.flatMap((label) =>
|
||||
credentials.create({
|
||||
@@ -413,26 +412,11 @@ const layer = Layer.effect(
|
||||
value: exit.value,
|
||||
}),
|
||||
),
|
||||
Effect.asVoid,
|
||||
Effect.exit,
|
||||
)
|
||||
const settled = Exit.isSuccess(persistence)
|
||||
? yield* Effect.gen(function* () {
|
||||
yield* bus.publish(Integration.Event.ConnectionUpdated, { integrationID: attempt.integrationID })
|
||||
yield* bus.publish(Integration.Event.Updated, {})
|
||||
}).pipe(Effect.exit)
|
||||
: persistence
|
||||
if (Exit.isFailure(settled) && Exit.isSuccess(persistence)) {
|
||||
yield* credentials.remove(persistence.value.id)
|
||||
if (previous) {
|
||||
yield* credentials.create({
|
||||
integrationID: previous.integrationID,
|
||||
label: previous.label,
|
||||
value: previous.value,
|
||||
})
|
||||
}
|
||||
}
|
||||
const settledAt = yield* Clock.currentTimeMillis
|
||||
const terminal: TerminalAttempt = Exit.isSuccess(settled)
|
||||
const terminal: TerminalAttempt = Exit.isSuccess(persistence)
|
||||
? {
|
||||
status: "complete",
|
||||
integrationID: attempt.integrationID,
|
||||
@@ -442,13 +426,15 @@ const layer = Layer.effect(
|
||||
: {
|
||||
status: "failed",
|
||||
integrationID: attempt.integrationID,
|
||||
message: message(settled.cause),
|
||||
message: message(persistence.cause),
|
||||
time: attempt.time,
|
||||
removeAt: settledAt + terminalRetention,
|
||||
}
|
||||
// Persisting attempts cannot be cancelled, expired, or claimed again.
|
||||
yield* SynchronizedRef.update(attempts, (current) => new Map(current).set(attemptID, terminal))
|
||||
if (Exit.isFailure(settled)) yield* Effect.failCause(settled.cause)
|
||||
if (Exit.isFailure(persistence)) yield* Effect.failCause(persistence.cause)
|
||||
yield* bus.publish(Integration.Event.ConnectionUpdated, { integrationID: attempt.integrationID })
|
||||
yield* bus.publish(Integration.Event.Updated, {})
|
||||
}).pipe(Effect.ensuring(close(attempt.scope)))
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -25,7 +25,7 @@ const layer = (ref: Ref) =>
|
||||
return Service.of({
|
||||
directory: ref.directory,
|
||||
workspaceID: ref.workspaceID,
|
||||
project: { id: resolved.id, directory: resolved.directory, canonical: resolved.canonical },
|
||||
project: { id: resolved.id, directory: resolved.directory },
|
||||
vcs: resolved.vcs,
|
||||
})
|
||||
}),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Duration, Effect, Option, Schema, Semaphore } from "effect"
|
||||
import { Duration, Effect, Schema, Semaphore, Stream } from "effect"
|
||||
import type { Scope } from "effect"
|
||||
import type { IntegrationOAuthMethodRegistration } from "@opencode-ai/plugin/effect/integration"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
@@ -14,7 +14,7 @@ import { Money } from "@opencode-ai/schema/money"
|
||||
import { ConfigProviderOptionsV1 } from "../../v1/config/provider-options"
|
||||
import { ConfigV1 } from "../../v1/config/config"
|
||||
|
||||
const defaultServer = "https://opencode.ai/console"
|
||||
const defaultServer = "https://console.opencode.ai"
|
||||
const clientID = "opencode-cli"
|
||||
const methodID = Integration.MethodID.make("device")
|
||||
const RemoteResponse = Schema.Struct({ config: ConfigV1.Info })
|
||||
@@ -47,13 +47,15 @@ function oauth(http: HttpClient.HttpClient) {
|
||||
Effect.gen(function* () {
|
||||
const server = yield* normalizeServer(inputs.server ?? defaultServer)
|
||||
const device = yield* post(http, `${server}/auth/device/code`, { client_id: clientID }, Device)
|
||||
const verification = new URL(device.verification_uri_complete, new URL(server).origin)
|
||||
if (verification.protocol !== "http:" && verification.protocol !== "https:") {
|
||||
const verification = URL.canParse(device.verification_uri_complete)
|
||||
? new URL(device.verification_uri_complete)
|
||||
: undefined
|
||||
if (verification && verification.protocol !== "http:" && verification.protocol !== "https:") {
|
||||
return yield* Effect.fail(new Error("Invalid device verification URL: expected HTTP(S)"))
|
||||
}
|
||||
return {
|
||||
mode: "auto" as const,
|
||||
url: verification.href,
|
||||
url: verification?.href ?? `${server}/${device.verification_uri_complete.replace(/^\/+/, "")}`,
|
||||
instructions: `Enter code: ${device.user_code}`,
|
||||
callback: poll(http, server, device.device_code, Duration.seconds(device.interval)),
|
||||
}
|
||||
@@ -95,14 +97,13 @@ export const OpencodePlugin = define<HttpClient.HttpClient | Bus.Service | Scope
|
||||
? yield* ctx.integration.connection.resolve(connection).pipe(Effect.catch(() => Effect.succeed(undefined)))
|
||||
: undefined
|
||||
connected = connection !== undefined
|
||||
const managed = credential && typeof credential.metadata?.server === "string"
|
||||
const loaded = managed ? yield* fetchProviders(http, credential) : undefined
|
||||
if (managed && !loaded) {
|
||||
return yield* Effect.fail(
|
||||
new Error("OpenCode Console did not return provider config for the selected organization"),
|
||||
)
|
||||
}
|
||||
providers = loaded
|
||||
providers = credential
|
||||
? yield* fetchProviders(http, credential).pipe(
|
||||
Effect.catch((cause) =>
|
||||
Effect.logWarning("failed to load OpenCode provider config", { cause }).pipe(Effect.as(undefined)),
|
||||
),
|
||||
)
|
||||
: undefined
|
||||
})
|
||||
|
||||
yield* ctx.integration.transform((draft) => {
|
||||
@@ -110,13 +111,10 @@ export const OpencodePlugin = define<HttpClient.HttpClient | Bus.Service | Scope
|
||||
integration.name = "OpenCode"
|
||||
})
|
||||
draft.method.update(oauth(http))
|
||||
draft.method.update({
|
||||
integrationID: "opencode",
|
||||
method: { type: "key", label: "API key (managed inference service account; not Go)" },
|
||||
})
|
||||
draft.method.update({ integrationID: "opencode", method: { type: "key", label: "API key (service account)" } })
|
||||
})
|
||||
|
||||
yield* load().pipe(Effect.orDie)
|
||||
yield* load()
|
||||
yield* ctx.catalog.transform((catalog) => {
|
||||
for (const [providerID, item] of Object.entries(providers ?? {})) {
|
||||
catalog.provider.update(providerID, (provider) => {
|
||||
@@ -191,19 +189,12 @@ export const OpencodePlugin = define<HttpClient.HttpClient | Bus.Service | Scope
|
||||
}
|
||||
})
|
||||
|
||||
const unsubscribe = yield* bus.listen((event) => {
|
||||
if (event.type !== Integration.Event.ConnectionUpdated.type) return Effect.void
|
||||
const data = Schema.decodeUnknownOption(Integration.Event.ConnectionUpdated.data)(event.data)
|
||||
if (Option.isNone(data) || data.value.integrationID !== Integration.ID.make("opencode")) return Effect.void
|
||||
return loading.withPermit(load().pipe(Effect.andThen(ctx.catalog.reload()))).pipe(
|
||||
Effect.timeoutOrElse({
|
||||
duration: "30 seconds",
|
||||
orElse: () => Effect.fail(new Error("Timed out loading OpenCode Console provider config")),
|
||||
}),
|
||||
Effect.orDie,
|
||||
)
|
||||
})
|
||||
yield* Effect.addFinalizer(() => unsubscribe)
|
||||
const refresh = () => loading.withPermit(load().pipe(Effect.andThen(ctx.catalog.reload())))
|
||||
yield* bus.subscribe(Integration.Event.ConnectionUpdated).pipe(
|
||||
Stream.filter((event) => event.data.integrationID === Integration.ID.make("opencode")),
|
||||
Stream.runForEach(refresh),
|
||||
Effect.forkScoped({ startImmediately: true }),
|
||||
)
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -223,12 +214,6 @@ function fetchProviders(http: HttpClient.HttpClient, value: CredentialValue) {
|
||||
.pipe(
|
||||
Effect.flatMap((response) => {
|
||||
if (response.status === 404) return Effect.succeed(undefined)
|
||||
if (response.status === 403) {
|
||||
return Effect.fail(new Error("OpenCode Console access is forbidden for the selected organization"))
|
||||
}
|
||||
if (response.status < 200 || response.status >= 300) {
|
||||
return Effect.fail(new Error(`OpenCode Console provider config failed with HTTP ${response.status}`))
|
||||
}
|
||||
return HttpClientResponse.filterStatusOk(response).pipe(
|
||||
Effect.flatMap(HttpClientResponse.schemaBodyJson(RemoteResponse)),
|
||||
Effect.map((remote) => remote.config.provider),
|
||||
@@ -311,22 +296,8 @@ function credential(http: HttpClient.HttpClient, server: string, token: typeof T
|
||||
],
|
||||
{ concurrency: 2 },
|
||||
)
|
||||
if (orgs.length === 0) {
|
||||
return yield* Effect.fail(
|
||||
new Error(
|
||||
"Your OpenCode Console account does not belong to an organization. Create or join one at https://opencode.ai/console, then try again.",
|
||||
),
|
||||
)
|
||||
}
|
||||
if (orgs.length > 1) {
|
||||
return yield* Effect.fail(
|
||||
new Error(
|
||||
"Your OpenCode Console account belongs to multiple organizations. Organization selection is not supported yet; use an account with one organization, then try again.",
|
||||
),
|
||||
)
|
||||
}
|
||||
const org = orgs[0]
|
||||
const value = Credential.OAuth.make({
|
||||
const org = orgs.toSorted((a, b) => a.name.localeCompare(b.name) || a.id.localeCompare(b.id))[0]
|
||||
return Credential.OAuth.make({
|
||||
type: "oauth" as const,
|
||||
methodID,
|
||||
access: token.access_token,
|
||||
@@ -336,11 +307,10 @@ function credential(http: HttpClient.HttpClient, server: string, token: typeof T
|
||||
server,
|
||||
accountID: user.id,
|
||||
email: user.email,
|
||||
orgID: org.id,
|
||||
orgName: org.name,
|
||||
orgID: org?.id,
|
||||
orgName: org?.name,
|
||||
},
|
||||
})
|
||||
return value
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ export * as Project from "./project"
|
||||
|
||||
import { Context, Effect, Layer, Schema } from "effect"
|
||||
import { ChildProcess } from "effect/unstable/process"
|
||||
import { asc, desc, isNotNull, isNull, ne, or } from "drizzle-orm"
|
||||
import { asc, desc } from "drizzle-orm"
|
||||
import path from "path"
|
||||
import { AbsolutePath } from "./schema"
|
||||
import { Database } from "./database/database"
|
||||
@@ -40,7 +40,6 @@ export interface Resolved {
|
||||
readonly previous?: ID
|
||||
readonly id: ID
|
||||
readonly directory: AbsolutePath
|
||||
readonly canonical: AbsolutePath
|
||||
readonly vcs?: Vcs
|
||||
}
|
||||
|
||||
@@ -84,7 +83,7 @@ function fromRow(row: typeof ProjectTable.$inferSelect): Info {
|
||||
: undefined
|
||||
return {
|
||||
id: row.id,
|
||||
canonical: row.worktree,
|
||||
worktree: row.worktree,
|
||||
vcs: row.vcs ?? undefined,
|
||||
name: row.name ?? undefined,
|
||||
icon,
|
||||
@@ -107,40 +106,6 @@ const layer = Layer.effect(
|
||||
const db = (yield* Database.Service).db
|
||||
const projectDirectories = yield* ProjectDirectories.Service
|
||||
|
||||
const persist = Effect.fnUntraced(function* (project: Resolved) {
|
||||
yield* db
|
||||
.transaction((tx) =>
|
||||
Effect.gen(function* () {
|
||||
const vcs = project.vcs?.type
|
||||
yield* tx
|
||||
.insert(ProjectTable)
|
||||
.values({ id: project.id, worktree: project.canonical, vcs, sandboxes: [] })
|
||||
.onConflictDoUpdate({
|
||||
target: ProjectTable.id,
|
||||
set: { worktree: project.canonical, vcs: vcs ?? null },
|
||||
setWhere: or(
|
||||
ne(ProjectTable.worktree, project.canonical),
|
||||
vcs ? or(isNull(ProjectTable.vcs), ne(ProjectTable.vcs, vcs)) : isNotNull(ProjectTable.vcs),
|
||||
),
|
||||
})
|
||||
.run()
|
||||
if (!project.vcs) return
|
||||
yield* projectDirectories.create({ projectID: project.id, directory: project.canonical }, tx)
|
||||
if (project.directory === project.canonical) return
|
||||
yield* projectDirectories.create(
|
||||
{
|
||||
projectID: project.id,
|
||||
directory: project.directory,
|
||||
strategy: project.vcs.type === "git" ? "git_worktree" : undefined,
|
||||
},
|
||||
tx,
|
||||
)
|
||||
}),
|
||||
)
|
||||
.pipe(Effect.orDie)
|
||||
return project
|
||||
})
|
||||
|
||||
const list = Effect.fn("Project.list")(function* () {
|
||||
const rows = yield* db
|
||||
.select()
|
||||
@@ -246,25 +211,17 @@ const layer = Layer.effect(
|
||||
if (repo) {
|
||||
const previous = yield* cached(repo.commonDirectory)
|
||||
const id = (yield* remote(repo)) ?? previous ?? (yield* root(repo))
|
||||
const canonical = yield* git.worktree
|
||||
.list(repo)
|
||||
.pipe(
|
||||
Effect.map((items) => items.find((item) => item.kind === "main")?.directory ?? repo.worktree),
|
||||
Effect.catch(() => Effect.succeed(repo.worktree)),
|
||||
)
|
||||
return yield* persist({
|
||||
return {
|
||||
previous,
|
||||
id: id ?? ID.global,
|
||||
directory: repo.worktree,
|
||||
canonical,
|
||||
vcs: { type: "git" as const, store: repo.commonDirectory },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const hg = yield* hgDiscover(input)
|
||||
if (hg) return yield* persist({ ...hg, canonical: hg.directory })
|
||||
const directory = AbsolutePath.make(path.parse(input).root)
|
||||
return yield* persist({ id: ID.global, directory, canonical: directory, vcs: undefined })
|
||||
if (hg) return hg
|
||||
return { id: ID.global, directory: AbsolutePath.make(path.parse(input).root), vcs: undefined }
|
||||
})
|
||||
|
||||
const commit = Effect.fn("Project.commit")(function* (input: { store: AbsolutePath; id: ID }) {
|
||||
|
||||
@@ -3,7 +3,7 @@ export * from "./session/schema"
|
||||
|
||||
import { Effect, Layer, Schema, Context, Stream, Scope } from "effect"
|
||||
import { ListAnchor } from "@opencode-ai/schema/session"
|
||||
import { and, asc, desc, eq, gt, isNotNull, isNull, like, lt, ne, or, type SQL } from "drizzle-orm"
|
||||
import { and, asc, desc, eq, gt, isNull, like, lt, or, type SQL } from "drizzle-orm"
|
||||
import { Project } from "./project"
|
||||
import { Workspace } from "./workspace"
|
||||
import { Model } from "./model"
|
||||
@@ -325,22 +325,6 @@ const layer = Layer.effect(
|
||||
const shellLocks = KeyedMutex.makeUnsafe<SessionSchema.ID>()
|
||||
const decodeMessage = Schema.decodeUnknownEffect(SessionMessage.Info)
|
||||
const isDurableSessionEvent = Schema.is(SessionEvent.Durable)
|
||||
const persistProject = (project: Project.Resolved) => {
|
||||
const vcs = project.vcs?.type
|
||||
return db
|
||||
.insert(ProjectTable)
|
||||
.values({ id: project.id, worktree: project.canonical, vcs, sandboxes: [] })
|
||||
.onConflictDoUpdate({
|
||||
target: ProjectTable.id,
|
||||
set: { worktree: project.canonical, vcs: vcs ?? null },
|
||||
setWhere: or(
|
||||
ne(ProjectTable.worktree, project.canonical),
|
||||
vcs ? or(isNull(ProjectTable.vcs), ne(ProjectTable.vcs, vcs)) : isNotNull(ProjectTable.vcs),
|
||||
),
|
||||
})
|
||||
.run()
|
||||
.pipe(Effect.orDie)
|
||||
}
|
||||
const decode = (row: typeof SessionMessageTable.$inferSelect) =>
|
||||
decodeMessage({ ...row.data, id: row.id, type: row.type }).pipe(
|
||||
Effect.mapError(
|
||||
@@ -363,7 +347,12 @@ const layer = Layer.effect(
|
||||
if (location === undefined)
|
||||
return yield* Effect.die(new Error("Session.create requires either location or an existing parentID"))
|
||||
const project = yield* projects.resolve(location.directory)
|
||||
yield* persistProject(project)
|
||||
yield* db
|
||||
.insert(ProjectTable)
|
||||
.values({ id: project.id, worktree: project.directory, vcs: project.vcs?.type, sandboxes: [] })
|
||||
.onConflictDoNothing()
|
||||
.run()
|
||||
.pipe(Effect.orDie)
|
||||
const now = Date.now()
|
||||
const info = SessionV1.SessionInfo.make({
|
||||
id: sessionID,
|
||||
@@ -462,7 +451,6 @@ const layer = Layer.effect(
|
||||
if ("directory" in input) conditions.push(eq(SessionTable.directory, input.directory))
|
||||
if (input.workspaceID) conditions.push(eq(SessionTable.workspace_id, input.workspaceID))
|
||||
if ("project" in input) conditions.push(eq(SessionTable.project_id, input.project))
|
||||
if ("project" in input && input.subpath !== undefined) conditions.push(eq(SessionTable.path, input.subpath))
|
||||
if (input.search) conditions.push(like(SessionTable.title, `%${input.search}%`))
|
||||
if (input.parentID !== undefined)
|
||||
conditions.push(
|
||||
@@ -744,7 +732,12 @@ const layer = Layer.effect(
|
||||
)
|
||||
return
|
||||
const project = yield* projects.resolve(directory)
|
||||
yield* persistProject(project)
|
||||
yield* db
|
||||
.insert(ProjectTable)
|
||||
.values({ id: project.id, worktree: project.directory, vcs: project.vcs?.type, sandboxes: [] })
|
||||
.onConflictDoNothing()
|
||||
.run()
|
||||
.pipe(Effect.orDie)
|
||||
if ((yield* execution.active).has(input.sessionID)) {
|
||||
yield* execution.interrupt(input.sessionID)
|
||||
yield* execution.awaitIdle(input.sessionID)
|
||||
|
||||
@@ -10,13 +10,13 @@ import type { Context as PluginContext } from "@opencode-ai/plugin/effect/plugin
|
||||
import { ToolFailure } from "@opencode-ai/ai"
|
||||
import { FileDiff } from "@opencode-ai/schema/file-diff"
|
||||
import { Bom } from "@opencode-ai/util/bom"
|
||||
import { createTwoFilesPatch, diffLines } from "diff"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { FileMutation } from "../../file-mutation"
|
||||
import { Formatter } from "../../formatter"
|
||||
import { FSUtil } from "@opencode-ai/util/fs-util"
|
||||
import { LocationMutation } from "../../location-mutation"
|
||||
import { Permission } from "../../permission"
|
||||
import { fileDiff } from "./file-diff"
|
||||
|
||||
export const name = "edit"
|
||||
|
||||
@@ -238,3 +238,19 @@ export const Plugin = {
|
||||
.pipe(Effect.orDie)
|
||||
}),
|
||||
}
|
||||
|
||||
function fileDiff(file: string, before: string, after: string): typeof FileDiff.Info.Type {
|
||||
const counts = diffLines(before, after).reduce(
|
||||
(result, item) => ({
|
||||
additions: result.additions + (item.added ? (item.count ?? 0) : 0),
|
||||
deletions: result.deletions + (item.removed ? (item.count ?? 0) : 0),
|
||||
}),
|
||||
{ additions: 0, deletions: 0 },
|
||||
)
|
||||
return {
|
||||
file,
|
||||
patch: createTwoFilesPatch(file, file, before, after),
|
||||
status: "modified",
|
||||
...counts,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import { FileDiff } from "@opencode-ai/schema/file-diff"
|
||||
import { createTwoFilesPatch, diffLines } from "diff"
|
||||
|
||||
export function fileDiff(
|
||||
file: string,
|
||||
before: string,
|
||||
after: string,
|
||||
status: typeof FileDiff.Info.Type.status = "modified",
|
||||
): typeof FileDiff.Info.Type {
|
||||
const counts = diffLines(before, after).reduce(
|
||||
(result, item) => ({
|
||||
additions: result.additions + (item.added ? (item.count ?? 0) : 0),
|
||||
deletions: result.deletions + (item.removed ? (item.count ?? 0) : 0),
|
||||
}),
|
||||
{ additions: 0, deletions: 0 },
|
||||
)
|
||||
return {
|
||||
file,
|
||||
patch: createTwoFilesPatch(file, file, before, after),
|
||||
status,
|
||||
...counts,
|
||||
}
|
||||
}
|
||||
@@ -8,14 +8,15 @@ export * as WriteTool from "./write"
|
||||
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { ToolFailure } from "@opencode-ai/ai"
|
||||
import { FileDiff } from "@opencode-ai/schema/file-diff"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { createTwoFilesPatch, diffLines } from "diff"
|
||||
import { Bom } from "@opencode-ai/util/bom"
|
||||
import { FSUtil } from "@opencode-ai/util/fs-util"
|
||||
import { FileMutation } from "../../file-mutation"
|
||||
import { Formatter } from "../../formatter"
|
||||
import { LocationMutation } from "../../location-mutation"
|
||||
import { Permission } from "../../permission"
|
||||
import { fileDiff } from "./file-diff"
|
||||
|
||||
export const name = "write"
|
||||
|
||||
@@ -82,12 +83,19 @@ export const Plugin = {
|
||||
Effect.catchReason("PlatformError", "NotFound", () => Effect.succeed(undefined)),
|
||||
)
|
||||
const next = Bom.split(input.content)
|
||||
const preview = fileDiff(
|
||||
target.resource,
|
||||
current?.text ?? "",
|
||||
next.text,
|
||||
current ? "modified" : "added",
|
||||
const counts = diffLines(current?.text ?? "", next.text).reduce(
|
||||
(result, item) => ({
|
||||
additions: result.additions + (item.added ? (item.count ?? 0) : 0),
|
||||
deletions: result.deletions + (item.removed ? (item.count ?? 0) : 0),
|
||||
}),
|
||||
{ additions: 0, deletions: 0 },
|
||||
)
|
||||
const preview: typeof FileDiff.Info.Type = {
|
||||
file: target.resource,
|
||||
patch: createTwoFilesPatch(target.resource, target.resource, current?.text ?? "", next.text),
|
||||
status: current ? "modified" : "added",
|
||||
...counts,
|
||||
}
|
||||
yield* permission.assert({
|
||||
action: "edit",
|
||||
resources: [target.resource],
|
||||
|
||||
@@ -56,7 +56,7 @@ describe("node build", () => {
|
||||
Location.Service.of({
|
||||
directory: ref.directory,
|
||||
workspaceID: ref.workspaceID,
|
||||
project: { id: Project.ID.global, directory: service.directory, canonical: service.directory },
|
||||
project: { id: Project.ID.global, directory: service.directory },
|
||||
}),
|
||||
),
|
||||
{ idleTimeToLive: "1 minute" },
|
||||
@@ -79,7 +79,7 @@ describe("node build", () => {
|
||||
return Project.Service.of({
|
||||
list: () => Effect.succeed([]),
|
||||
directories: () => Effect.succeed([]),
|
||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory }),
|
||||
commit: () => Effect.void,
|
||||
})
|
||||
}),
|
||||
|
||||
@@ -5,11 +5,10 @@ import { Effect, Layer } from "effect"
|
||||
import { tmpdir } from "./tmpdir"
|
||||
|
||||
export function location(ref: Location.Ref, input: { projectDirectory?: AbsolutePath; vcs?: Project.Vcs } = {}) {
|
||||
const directory = input.projectDirectory ?? ref.directory
|
||||
return {
|
||||
directory: ref.directory,
|
||||
workspaceID: ref.workspaceID,
|
||||
project: { id: Project.ID.global, directory, canonical: directory },
|
||||
project: { id: Project.ID.global, directory: input.projectDirectory ?? ref.directory },
|
||||
vcs: input.vcs,
|
||||
} satisfies Location.Interface
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ const projectLayer = Layer.succeed(
|
||||
Effect.succeed({
|
||||
id: Project.ID.make("project"),
|
||||
directory: AbsolutePath.make("/repo"),
|
||||
canonical: AbsolutePath.make("/main/repo"),
|
||||
vcs: { type: "git", store: AbsolutePath.make("/repo/.git") },
|
||||
}),
|
||||
commit: () => Effect.void,
|
||||
@@ -35,7 +34,6 @@ describe("Location", () => {
|
||||
expect(location.workspaceID).toBe(workspaceID)
|
||||
expect(location.project.id).toBe(Project.ID.make("project"))
|
||||
expect(location.project.directory).toBe(AbsolutePath.make("/repo"))
|
||||
expect(location.project.canonical).toBe(AbsolutePath.make("/main/repo"))
|
||||
expect(location.vcs).toEqual({
|
||||
type: "git",
|
||||
store: AbsolutePath.make("/repo/.git"),
|
||||
|
||||
@@ -11,6 +11,7 @@ import { LayerNode } from "@opencode-ai/util/effect/layer-node"
|
||||
import { Bus } from "@opencode-ai/core/bus"
|
||||
import { Job } from "@opencode-ai/core/job"
|
||||
import { Project } from "@opencode-ai/core/project"
|
||||
import { ProjectTable } from "@opencode-ai/core/project/sql"
|
||||
import { ProjectDirectories } from "@opencode-ai/core/project/directories"
|
||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||
import { Session } from "@opencode-ai/core/session"
|
||||
@@ -87,6 +88,11 @@ describe("MoveSession", () => {
|
||||
const projectID = (yield* Project.Service.use((service) => service.resolve(source))).id
|
||||
const sessionID = Session.ID.make("ses_move")
|
||||
const { db } = yield* Database.Service
|
||||
yield* db
|
||||
.insert(ProjectTable)
|
||||
.values({ id: projectID, worktree: source, sandboxes: [], time_created: 1, time_updated: 1 })
|
||||
.run()
|
||||
.pipe(Effect.orDie)
|
||||
yield* db
|
||||
.insert(SessionTable)
|
||||
.values({
|
||||
@@ -138,6 +144,11 @@ describe("MoveSession", () => {
|
||||
const projectID = (yield* Project.Service.use((service) => service.resolve(source))).id
|
||||
const sessionID = Session.ID.make("ses_move_nested")
|
||||
const { db } = yield* Database.Service
|
||||
yield* db
|
||||
.insert(ProjectTable)
|
||||
.values({ id: projectID, worktree: source, sandboxes: [], time_created: 1, time_updated: 1 })
|
||||
.run()
|
||||
.pipe(Effect.orDie)
|
||||
yield* db
|
||||
.insert(SessionTable)
|
||||
.values({
|
||||
@@ -193,6 +204,11 @@ describe("MoveSession", () => {
|
||||
const destinationProjectID = (yield* Project.Service.use((service) => service.resolve(destination))).id
|
||||
const sessionID = Session.ID.make("ses_move_project")
|
||||
const { db } = yield* Database.Service
|
||||
yield* db
|
||||
.insert(ProjectTable)
|
||||
.values({ id: projectID, worktree: source, sandboxes: [], time_created: 1, time_updated: 1 })
|
||||
.run()
|
||||
.pipe(Effect.orDie)
|
||||
yield* db
|
||||
.insert(SessionTable)
|
||||
.values({
|
||||
@@ -252,6 +268,11 @@ describe("MoveSession", () => {
|
||||
const projectID = (yield* Project.Service.use((service) => service.resolve(source))).id
|
||||
const sessionID = Session.ID.make("ses_move_nested_checkout")
|
||||
const { db } = yield* Database.Service
|
||||
yield* db
|
||||
.insert(ProjectTable)
|
||||
.values({ id: projectID, worktree: source, sandboxes: [], time_created: 1, time_updated: 1 })
|
||||
.run()
|
||||
.pipe(Effect.orDie)
|
||||
yield* db
|
||||
.insert(SessionTable)
|
||||
.values({
|
||||
|
||||
@@ -121,11 +121,7 @@ export function agentHost(agent: Agent.Interface): Plugin.Context["agent"] {
|
||||
? Effect.succeed({
|
||||
location: new Location.Info({
|
||||
directory: AbsolutePath.make("/"),
|
||||
project: {
|
||||
id: Project.ID.make("test"),
|
||||
directory: AbsolutePath.make("/"),
|
||||
canonical: AbsolutePath.make("/"),
|
||||
},
|
||||
project: { id: Project.ID.make("test"), directory: AbsolutePath.make("/") },
|
||||
}),
|
||||
data: agentInfo(value),
|
||||
})
|
||||
@@ -167,11 +163,7 @@ export function catalogHost(catalog: Catalog.Interface): Plugin.Context["catalog
|
||||
Effect.map((data) => ({
|
||||
location: new Location.Info({
|
||||
directory: AbsolutePath.make("/"),
|
||||
project: {
|
||||
id: Project.ID.make("test"),
|
||||
directory: AbsolutePath.make("/"),
|
||||
canonical: AbsolutePath.make("/"),
|
||||
},
|
||||
project: { id: Project.ID.make("test"), directory: AbsolutePath.make("/") },
|
||||
}),
|
||||
data: data.map(modelInfo),
|
||||
})),
|
||||
@@ -365,11 +357,7 @@ export function integrationHost(integration: Integration.Interface): Plugin.Cont
|
||||
export function webSearchHost(websearch: WebSearch.Interface): Plugin.Context["websearch"] {
|
||||
const location = Location.Info.make({
|
||||
directory: AbsolutePath.make("/tmp/websearch-test"),
|
||||
project: {
|
||||
id: Project.ID.make("websearch-test"),
|
||||
directory: AbsolutePath.make("/tmp/websearch-test"),
|
||||
canonical: AbsolutePath.make("/tmp/websearch-test"),
|
||||
},
|
||||
project: { id: Project.ID.make("websearch-test"), directory: AbsolutePath.make("/tmp/websearch-test") },
|
||||
})
|
||||
return {
|
||||
providers: () => websearch.providers().pipe(Effect.map((data) => ({ location, data }))),
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { describe, expect } from "bun:test"
|
||||
import { Money } from "@opencode-ai/schema/money"
|
||||
import { Effect } from "effect"
|
||||
import { HttpClient, HttpClientResponse } from "effect/unstable/http"
|
||||
import { Catalog } from "@opencode-ai/core/catalog"
|
||||
import { Credential } from "@opencode-ai/core/credential"
|
||||
import { Bus } from "@opencode-ai/core/bus"
|
||||
@@ -88,102 +87,25 @@ describe("OpencodePlugin", () => {
|
||||
type: "oauth",
|
||||
label: "OpenCode Console account",
|
||||
},
|
||||
{ type: "key", label: "API key (managed inference service account; not Go)" },
|
||||
{ type: "key", label: "API key (service account)" },
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("uses the canonical OpenCode Console server by default", () =>
|
||||
Effect.gen(function* () {
|
||||
const requests: string[] = []
|
||||
const http = HttpClient.make((request) => {
|
||||
requests.push(request.url)
|
||||
return Effect.succeed(
|
||||
HttpClientResponse.fromWeb(
|
||||
request,
|
||||
Response.json({
|
||||
device_code: "device",
|
||||
user_code: "user",
|
||||
verification_uri_complete: "/console/verify",
|
||||
expires_in: 60,
|
||||
interval: 60,
|
||||
}),
|
||||
),
|
||||
)
|
||||
})
|
||||
const plugin = yield* Plugin.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
const bus = yield* Bus.Service
|
||||
const integration = yield* Integration.Service
|
||||
yield* OpencodePlugin.effect(host).pipe(
|
||||
Effect.provideService(Bus.Service, bus),
|
||||
Effect.provideService(Integration.Service, integration),
|
||||
Effect.provideService(HttpClient.HttpClient, http),
|
||||
)
|
||||
const attempt = yield* integration.oauth.connect({
|
||||
integrationID: Integration.ID.make("opencode"),
|
||||
methodID: Integration.MethodID.make("device"),
|
||||
inputs: {},
|
||||
})
|
||||
yield* integration.oauth.cancel({ integrationID: Integration.ID.make("opencode"), attemptID: attempt.attemptID })
|
||||
|
||||
expect(requests).toEqual(["https://opencode.ai/console/auth/device/code"])
|
||||
expect(attempt.url).toBe("https://opencode.ai/console/verify")
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("keeps an absolute verification URL", () =>
|
||||
Effect.gen(function* () {
|
||||
const http = HttpClient.make((request) =>
|
||||
Effect.succeed(
|
||||
HttpClientResponse.fromWeb(
|
||||
request,
|
||||
Response.json({
|
||||
device_code: "device",
|
||||
user_code: "user",
|
||||
verification_uri_complete: "https://login.example.com/device/verify",
|
||||
expires_in: 60,
|
||||
interval: 60,
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
const plugin = yield* Plugin.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
const bus = yield* Bus.Service
|
||||
const integration = yield* Integration.Service
|
||||
yield* OpencodePlugin.effect(host).pipe(
|
||||
Effect.provideService(Bus.Service, bus),
|
||||
Effect.provideService(Integration.Service, integration),
|
||||
Effect.provideService(HttpClient.HttpClient, http),
|
||||
)
|
||||
const attempt = yield* integration.oauth.connect({
|
||||
integrationID: Integration.ID.make("opencode"),
|
||||
methodID: Integration.MethodID.make("device"),
|
||||
inputs: {},
|
||||
})
|
||||
yield* integration.oauth.cancel({ integrationID: Integration.ID.make("opencode"), attemptID: attempt.attemptID })
|
||||
|
||||
expect(attempt.url).toBe("https://login.example.com/device/verify")
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("uses a canonical custom server throughout device authorization", () =>
|
||||
Effect.acquireUseRelease(
|
||||
Effect.sync(() => {
|
||||
const requests: string[] = []
|
||||
const requested = Promise.withResolvers<void>()
|
||||
const release = Promise.withResolvers<void>()
|
||||
const server = Bun.serve({
|
||||
port: 0,
|
||||
fetch: async (request) => {
|
||||
fetch: (request) => {
|
||||
const url = new URL(request.url)
|
||||
requests.push(`${request.method} ${url.pathname}`)
|
||||
if (url.pathname.endsWith("/auth/device/code")) {
|
||||
return Response.json({
|
||||
device_code: "device",
|
||||
user_code: "user",
|
||||
verification_uri_complete: "/console/verify",
|
||||
verification_uri_complete: `${url.origin}/verify`,
|
||||
expires_in: 60,
|
||||
interval: 0,
|
||||
})
|
||||
@@ -193,17 +115,12 @@ describe("OpencodePlugin", () => {
|
||||
}
|
||||
if (url.pathname.endsWith("/api/user")) return Response.json({ id: "user", email: "user@example.com" })
|
||||
if (url.pathname.endsWith("/api/orgs")) return Response.json([{ id: "org", name: "Org" }])
|
||||
if (url.pathname.endsWith("/api/config")) {
|
||||
requested.resolve()
|
||||
await release.promise
|
||||
return Response.json({ config: { enterprise: { url: url.origin }, provider: {} } })
|
||||
}
|
||||
return new Response("Not found", { status: 404 })
|
||||
},
|
||||
})
|
||||
return { release, requested, requests, server }
|
||||
return { requests, server }
|
||||
}),
|
||||
({ release, requested, requests, server }) =>
|
||||
({ requests, server }) =>
|
||||
Effect.gen(function* () {
|
||||
yield* addPlugin()
|
||||
const integrations = yield* Integration.Service
|
||||
@@ -213,12 +130,7 @@ describe("OpencodePlugin", () => {
|
||||
methodID: Integration.MethodID.make("device"),
|
||||
inputs: { server: `${server.url.origin}/console///?ignored=true#ignored` },
|
||||
})
|
||||
expect(attempt.url).toBe(`${server.url.origin}/console/verify`)
|
||||
yield* Effect.promise(() => requested.promise)
|
||||
expect(yield* integrations.oauth.status({ integrationID, attemptID: attempt.attemptID })).toMatchObject({
|
||||
status: "pending",
|
||||
})
|
||||
release.resolve()
|
||||
expect(attempt.url).toBe(`${server.url.origin}/verify`)
|
||||
yield* eventually(
|
||||
integrations.oauth.status({ integrationID, attemptID: attempt.attemptID }),
|
||||
(status) => status.status === "complete",
|
||||
@@ -228,166 +140,11 @@ describe("OpencodePlugin", () => {
|
||||
expect(requests).toContain("POST /console/auth/device/token")
|
||||
expect(requests).toContain("GET /console/api/user")
|
||||
expect(requests).toContain("GET /console/api/orgs")
|
||||
expect(requests).toContain("GET /console/api/config")
|
||||
expect((yield* (yield* Credential.Service).list(Integration.ID.make("opencode")))[0]?.value).toMatchObject({
|
||||
metadata: { server: `${server.url.origin}/console`, orgID: "org", orgName: "Org" },
|
||||
metadata: { server: `${server.url.origin}/console` },
|
||||
})
|
||||
}),
|
||||
({ release, server }) =>
|
||||
Effect.promise(() => {
|
||||
release.resolve()
|
||||
return server.stop(true)
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
it.live("rejects device login without an organization", () =>
|
||||
Effect.acquireUseRelease(
|
||||
Effect.sync(() =>
|
||||
Bun.serve({
|
||||
port: 0,
|
||||
fetch: (request) => {
|
||||
const url = new URL(request.url)
|
||||
if (url.pathname === "/auth/device/code") {
|
||||
return Response.json({
|
||||
device_code: "device",
|
||||
user_code: "user",
|
||||
verification_uri_complete: `${url.origin}/verify`,
|
||||
expires_in: 60,
|
||||
interval: 0,
|
||||
})
|
||||
}
|
||||
if (url.pathname === "/auth/device/token") {
|
||||
return Response.json({ access_token: "access", refresh_token: "refresh", expires_in: 600 })
|
||||
}
|
||||
if (url.pathname === "/api/user") return Response.json({ id: "user", email: "user@example.com" })
|
||||
if (url.pathname === "/api/orgs") return Response.json([])
|
||||
return new Response("Not found", { status: 404 })
|
||||
},
|
||||
}),
|
||||
),
|
||||
(server) =>
|
||||
Effect.gen(function* () {
|
||||
yield* addPlugin()
|
||||
const integrations = yield* Integration.Service
|
||||
const integrationID = Integration.ID.make("opencode")
|
||||
const attempt = yield* integrations.oauth.connect({
|
||||
integrationID,
|
||||
methodID: Integration.MethodID.make("device"),
|
||||
inputs: { server: server.url.origin },
|
||||
})
|
||||
const status = yield* eventually(
|
||||
integrations.oauth.status({ integrationID, attemptID: attempt.attemptID }),
|
||||
(value) => value.status !== "pending",
|
||||
)
|
||||
|
||||
expect(status).toMatchObject({ status: "failed" })
|
||||
if (status.status === "failed") expect(status.message).toContain("does not belong to an organization")
|
||||
expect(yield* (yield* Credential.Service).list(integrationID)).toEqual([])
|
||||
}),
|
||||
(server) => Effect.promise(() => server.stop(true)),
|
||||
),
|
||||
)
|
||||
|
||||
it.live("rejects device login with multiple organizations", () =>
|
||||
Effect.acquireUseRelease(
|
||||
Effect.sync(() =>
|
||||
Bun.serve({
|
||||
port: 0,
|
||||
fetch: (request) => {
|
||||
const url = new URL(request.url)
|
||||
if (url.pathname === "/auth/device/code") {
|
||||
return Response.json({
|
||||
device_code: "device",
|
||||
user_code: "user",
|
||||
verification_uri_complete: `${url.origin}/verify`,
|
||||
expires_in: 60,
|
||||
interval: 0,
|
||||
})
|
||||
}
|
||||
if (url.pathname === "/auth/device/token") {
|
||||
return Response.json({ access_token: "access", refresh_token: "refresh", expires_in: 600 })
|
||||
}
|
||||
if (url.pathname === "/api/user") return Response.json({ id: "user", email: "user@example.com" })
|
||||
if (url.pathname === "/api/orgs") {
|
||||
return Response.json([
|
||||
{ id: "org-b", name: "Beta" },
|
||||
{ id: "org-a", name: "Alpha" },
|
||||
])
|
||||
}
|
||||
return new Response("Not found", { status: 404 })
|
||||
},
|
||||
}),
|
||||
),
|
||||
(server) =>
|
||||
Effect.gen(function* () {
|
||||
yield* addPlugin()
|
||||
const integrations = yield* Integration.Service
|
||||
const integrationID = Integration.ID.make("opencode")
|
||||
const attempt = yield* integrations.oauth.connect({
|
||||
integrationID,
|
||||
methodID: Integration.MethodID.make("device"),
|
||||
inputs: { server: server.url.origin },
|
||||
})
|
||||
const status = yield* eventually(
|
||||
integrations.oauth.status({ integrationID, attemptID: attempt.attemptID }),
|
||||
(value) => value.status !== "pending",
|
||||
)
|
||||
|
||||
expect(status).toMatchObject({ status: "failed" })
|
||||
if (status.status === "failed") expect(status.message).toContain("multiple organizations")
|
||||
expect(yield* (yield* Credential.Service).list(integrationID)).toEqual([])
|
||||
}),
|
||||
(server) => Effect.promise(() => server.stop(true)),
|
||||
),
|
||||
)
|
||||
|
||||
it.live("does not complete device login before provider config loads", () =>
|
||||
Effect.acquireUseRelease(
|
||||
Effect.sync(() =>
|
||||
Bun.serve({
|
||||
port: 0,
|
||||
fetch: (request) => {
|
||||
const url = new URL(request.url)
|
||||
if (url.pathname === "/auth/device/code") {
|
||||
return Response.json({
|
||||
device_code: "device",
|
||||
user_code: "user",
|
||||
verification_uri_complete: `${url.origin}/verify`,
|
||||
expires_in: 60,
|
||||
interval: 0,
|
||||
})
|
||||
}
|
||||
if (url.pathname === "/auth/device/token") {
|
||||
return Response.json({ access_token: "access", refresh_token: "refresh", expires_in: 600 })
|
||||
}
|
||||
if (url.pathname === "/api/user") return Response.json({ id: "user", email: "user@example.com" })
|
||||
if (url.pathname === "/api/orgs") return Response.json([{ id: "org", name: "Org" }])
|
||||
if (url.pathname === "/api/config") return new Response("Forbidden", { status: 403 })
|
||||
return new Response("Not found", { status: 404 })
|
||||
},
|
||||
}),
|
||||
),
|
||||
(server) =>
|
||||
Effect.gen(function* () {
|
||||
yield* addPlugin()
|
||||
const integrations = yield* Integration.Service
|
||||
const integrationID = Integration.ID.make("opencode")
|
||||
const attempt = yield* integrations.oauth.connect({
|
||||
integrationID,
|
||||
methodID: Integration.MethodID.make("device"),
|
||||
inputs: { server: server.url.origin },
|
||||
})
|
||||
const status = yield* eventually(
|
||||
integrations.oauth.status({ integrationID, attemptID: attempt.attemptID }),
|
||||
(value) => value.status !== "pending",
|
||||
)
|
||||
|
||||
expect(status).toMatchObject({ status: "failed" })
|
||||
if (status.status === "failed") expect(status.message).toContain("forbidden for the selected organization")
|
||||
expect(yield* (yield* Credential.Service).list(integrationID)).toEqual([])
|
||||
}),
|
||||
(server) => Effect.promise(() => server.stop(true)),
|
||||
({ server }) => Effect.promise(() => server.stop(true)),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -47,13 +47,13 @@ describe("Project.list", () => {
|
||||
expect(yield* project.list()).toEqual([
|
||||
{
|
||||
id: Project.ID.make("newer"),
|
||||
canonical: abs("/newer"),
|
||||
worktree: abs("/newer"),
|
||||
time: { created: 2, updated: 2, initialized: 3 },
|
||||
sandboxes: [],
|
||||
},
|
||||
{
|
||||
id: Project.ID.make("older"),
|
||||
canonical: abs("/older"),
|
||||
worktree: abs("/older"),
|
||||
vcs: "git",
|
||||
name: "Older",
|
||||
icon: { color: "#000000" },
|
||||
@@ -105,7 +105,6 @@ describe("Project.resolve", () => {
|
||||
|
||||
expect(result.id).toBe(Project.ID.make("global"))
|
||||
expect(path.resolve(result.directory)).toBe(path.parse(tmp.path).root)
|
||||
expect(result.canonical).toBe(result.directory)
|
||||
expect(result.previous).toBeUndefined()
|
||||
expect(result.vcs).toBeUndefined()
|
||||
}),
|
||||
@@ -124,7 +123,6 @@ describe("Project.resolve", () => {
|
||||
|
||||
expect(result.id).toBe(Project.ID.make("global"))
|
||||
expect(result.directory).toBe(yield* real(tmp.path))
|
||||
expect(result.canonical).toBe(result.directory)
|
||||
expect(result.previous).toBeUndefined()
|
||||
expect(result.vcs?.type).toBe("git")
|
||||
}),
|
||||
@@ -329,46 +327,13 @@ describe("Project.resolve", () => {
|
||||
yield* Effect.promise(() => Bun.write(path.join(tmp.path, ".git", "opencode"), "old-id"))
|
||||
yield* Effect.promise(() => $`git worktree add ${worktree} -b test-${Date.now()}`.cwd(tmp.path).quiet())
|
||||
const project = yield* Project.Service
|
||||
const db = (yield* Database.Service).db
|
||||
const id = remoteID("github.com/owner/repo")
|
||||
yield* db
|
||||
.insert(ProjectTable)
|
||||
.values({
|
||||
id,
|
||||
worktree: abs("/stale-worktree"),
|
||||
vcs: "hg",
|
||||
name: "Preserved name",
|
||||
icon_color: "#123456",
|
||||
commands: { start: "bun dev" },
|
||||
sandboxes: [abs("/preserved-sandbox")],
|
||||
time_created: 1,
|
||||
time_updated: 1,
|
||||
time_initialized: 2,
|
||||
})
|
||||
.run()
|
||||
|
||||
const result = yield* project.resolve(abs(worktree))
|
||||
|
||||
expect(result.directory).toBe(yield* real(worktree))
|
||||
expect(result.canonical).toBe(yield* real(tmp.path))
|
||||
expect(result.previous).toBe(Project.ID.make("old-id"))
|
||||
expect(result.id).toBe(id)
|
||||
expect(result.id).toBe(remoteID("github.com/owner/repo"))
|
||||
expect(result.vcs?.type).toBe("git")
|
||||
expect((yield* project.list()).find((item) => item.id === id)).toMatchObject({
|
||||
canonical: yield* real(tmp.path),
|
||||
vcs: "git",
|
||||
name: "Preserved name",
|
||||
icon: { color: "#123456" },
|
||||
commands: { start: "bun dev" },
|
||||
sandboxes: [abs("/preserved-sandbox")],
|
||||
time: { created: 1, initialized: 2 },
|
||||
})
|
||||
expect(
|
||||
(yield* project.directories({ projectID: id })).toSorted((a, b) => a.directory.localeCompare(b.directory)),
|
||||
).toEqual([
|
||||
{ directory: yield* real(tmp.path) },
|
||||
{ directory: yield* real(worktree), strategy: "git_worktree" },
|
||||
])
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
@@ -34,7 +34,7 @@ const projects = Layer.succeed(
|
||||
Project.Service,
|
||||
Project.Service.of({
|
||||
list: () => Effect.succeed([]),
|
||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory }),
|
||||
directories: () => Effect.succeed([]),
|
||||
commit: () => Effect.void,
|
||||
}),
|
||||
|
||||
@@ -14,7 +14,7 @@ import { Model } from "@opencode-ai/core/model"
|
||||
import { Project } from "@opencode-ai/core/project"
|
||||
import { ProjectTable } from "@opencode-ai/core/project/sql"
|
||||
import { Provider } from "@opencode-ai/core/provider"
|
||||
import { AbsolutePath, RelativePath } from "@opencode-ai/core/schema"
|
||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||
import { Session } from "@opencode-ai/core/session"
|
||||
import { SessionV1 } from "@opencode-ai/core/v1/session"
|
||||
import { SessionMessage } from "@opencode-ai/core/session/message"
|
||||
@@ -32,7 +32,7 @@ const projects = Layer.succeed(
|
||||
Project.Service,
|
||||
Project.Service.of({
|
||||
list: () => Effect.succeed([]),
|
||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory }),
|
||||
directories: () => Effect.succeed([]),
|
||||
commit: () => Effect.void,
|
||||
}),
|
||||
@@ -184,26 +184,6 @@ describe("Session.create", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("filters project sessions by subpath", () =>
|
||||
Effect.gen(function* () {
|
||||
const session = yield* Session.Service
|
||||
const { db } = yield* Database.Service
|
||||
const root = yield* session.create({ location, title: "root" })
|
||||
const nested = yield* session.create({ location, title: "nested" })
|
||||
|
||||
yield* db.update(SessionTable).set({ path: "packages/tui" }).where(eq(SessionTable.id, nested.id)).run()
|
||||
|
||||
const page = yield* session.list({
|
||||
project: Project.ID.global,
|
||||
subpath: RelativePath.make("packages/tui"),
|
||||
parentID: null,
|
||||
})
|
||||
|
||||
expect(page.data.map((item) => item.id)).toEqual([nested.id])
|
||||
expect(page.data.map((item) => item.id)).not.toContain(root.id)
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("forks a session by replaying a durable fork event into copied projected rows", () =>
|
||||
Effect.gen(function* () {
|
||||
const session = yield* Session.Service
|
||||
|
||||
@@ -15,6 +15,7 @@ import { Location } from "@opencode-ai/core/location"
|
||||
import { McpInstructions } from "@opencode-ai/core/mcp/instructions"
|
||||
import { ID } from "@opencode-ai/core/model"
|
||||
import { Project } from "@opencode-ai/core/project"
|
||||
import { ProjectTable } from "@opencode-ai/core/project/sql"
|
||||
import { Provider } from "@opencode-ai/core/provider"
|
||||
import { ReferenceInstructions } from "@opencode-ai/core/reference/instructions"
|
||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||
@@ -190,6 +191,11 @@ const setup = Effect.gen(function* () {
|
||||
agent.mode = "primary"
|
||||
}),
|
||||
)
|
||||
yield* db
|
||||
.insert(ProjectTable)
|
||||
.values({ id: Project.ID.global, worktree: AbsolutePath.make("/project"), sandboxes: [] })
|
||||
.run()
|
||||
.pipe(Effect.orDie)
|
||||
yield* db
|
||||
.insert(SessionTable)
|
||||
.values({
|
||||
|
||||
@@ -54,7 +54,7 @@ const projects = Layer.succeed(
|
||||
Project.Service,
|
||||
Project.Service.of({
|
||||
list: () => Effect.succeed([]),
|
||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory }),
|
||||
directories: () => Effect.succeed([]),
|
||||
commit: () => Effect.void,
|
||||
}),
|
||||
|
||||
@@ -21,7 +21,7 @@ const projects = Layer.succeed(
|
||||
Project.Service,
|
||||
Project.Service.of({
|
||||
list: () => Effect.succeed([]),
|
||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory }),
|
||||
directories: () => Effect.succeed([]),
|
||||
commit: () => Effect.void,
|
||||
}),
|
||||
|
||||
@@ -17,7 +17,7 @@ const projects = Layer.succeed(
|
||||
Project.Service,
|
||||
Project.Service.of({
|
||||
list: () => Effect.succeed([]),
|
||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory }),
|
||||
directories: () => Effect.succeed([]),
|
||||
commit: () => Effect.void,
|
||||
}),
|
||||
|
||||
@@ -20,7 +20,7 @@ import { testEffect } from "./lib/effect"
|
||||
|
||||
const location = Location.Ref.make({ directory: AbsolutePath.make("/project") })
|
||||
const projects = Layer.mock(Project.Service, {
|
||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory }),
|
||||
})
|
||||
const skills = Layer.mock(Skill.Service, {
|
||||
list: () =>
|
||||
|
||||
@@ -17,7 +17,7 @@ import { testEffect } from "./lib/effect"
|
||||
const location = Location.Ref.make({ directory: AbsolutePath.make("/project") })
|
||||
const awaited: Session.ID[] = []
|
||||
const projects = Layer.mock(Project.Service, {
|
||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory }),
|
||||
})
|
||||
const execution = Layer.mock(SessionExecution.Service, {
|
||||
awaitIdle: (sessionID) => Effect.sync(() => awaited.push(sessionID)),
|
||||
|
||||
@@ -11,7 +11,6 @@ import type {
|
||||
OpenCodeEvent,
|
||||
PermissionSavedInfo,
|
||||
PermissionRequest,
|
||||
Project,
|
||||
ProviderInfo,
|
||||
ReferenceInfo,
|
||||
SessionInfo,
|
||||
@@ -78,10 +77,6 @@ export interface Data {
|
||||
}
|
||||
}
|
||||
readonly project: {
|
||||
list(): Project[]
|
||||
get(projectID: string): Project | undefined
|
||||
sync(): Promise<void>
|
||||
invalidate(): void
|
||||
readonly permission: {
|
||||
list(projectID: string): PermissionSavedInfo[] | undefined
|
||||
sync(projectID: string): Promise<void>
|
||||
@@ -351,25 +346,6 @@ export interface UI {
|
||||
navigate(destination: Destination): void
|
||||
current(): Route
|
||||
}
|
||||
readonly tabs: {
|
||||
/** Returns whether session tabs are enabled for this TUI. */
|
||||
enabled(): boolean
|
||||
/** Returns the currently open root-session tabs. Reactive when read in a Solid computation. */
|
||||
list(): readonly {
|
||||
readonly sessionID: string
|
||||
readonly title?: string
|
||||
readonly active: boolean
|
||||
readonly busy: boolean
|
||||
readonly attention: boolean
|
||||
readonly unread?: "activity" | "error"
|
||||
}[]
|
||||
/** Opens (or focuses) a tab for a session, adding it when not already open. Returns false when tabs are disabled. */
|
||||
open(sessionID: string): boolean
|
||||
/** Focuses an already-open tab and returns false when it is not open. */
|
||||
focus(sessionID: string): boolean
|
||||
/** Closes an open tab, or the active tab when omitted, and returns false when no tab matched. */
|
||||
close(sessionID?: string): boolean
|
||||
}
|
||||
readonly slot: <Name extends SlotName>(name: Name, render: Slot<Name>) => () => void
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ export class Info extends Schema.Class<Info>("Location.Info")({
|
||||
project: Schema.Struct({
|
||||
id: ProjectID,
|
||||
directory: AbsolutePath,
|
||||
canonical: AbsolutePath,
|
||||
}),
|
||||
}) {}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ export const Vcs = Schema.Literals(["git", "hg"]).annotate({ identifier: "Projec
|
||||
export const Current = Schema.Struct({
|
||||
id: ID,
|
||||
directory: AbsolutePath,
|
||||
canonical: AbsolutePath,
|
||||
}).annotate({ identifier: "Project.Current" })
|
||||
export interface Current extends Schema.Schema.Type<typeof Current> {}
|
||||
export const Directory = Schema.Struct({
|
||||
@@ -47,7 +46,7 @@ export interface Time extends Schema.Schema.Type<typeof Time> {}
|
||||
|
||||
export const Info = Schema.Struct({
|
||||
id: ID,
|
||||
canonical: AbsolutePath,
|
||||
worktree: Schema.String,
|
||||
vcs: optional(Vcs),
|
||||
name: optional(Schema.String),
|
||||
icon: optional(Icon),
|
||||
|
||||
@@ -9,11 +9,7 @@ export const ProjectHandler = HttpApiBuilder.group(Api, "server.project", (handl
|
||||
.handle("project.list", () => Project.Service.use((project) => project.list()))
|
||||
.handle("project.current", () =>
|
||||
Location.Service.use((location) =>
|
||||
Effect.succeed({
|
||||
id: location.project.id,
|
||||
directory: location.project.directory,
|
||||
canonical: location.project.canonical,
|
||||
}),
|
||||
Effect.succeed({ id: location.project.id, directory: location.project.directory }),
|
||||
),
|
||||
)
|
||||
.handle("project.directories", (ctx) =>
|
||||
|
||||
@@ -102,12 +102,12 @@ export function DialogIntegration(
|
||||
title="Connect a service"
|
||||
options={options()}
|
||||
emptyView={
|
||||
<box paddingLeft={4} paddingRight={4}>
|
||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||
<text fg={theme.text.subdued}>No integrations available</text>
|
||||
</box>
|
||||
}
|
||||
noMatchView={
|
||||
<box paddingLeft={4} paddingRight={4}>
|
||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||
<text fg={theme.text.subdued}>No integrations found</text>
|
||||
</box>
|
||||
}
|
||||
|
||||
@@ -328,7 +328,7 @@ export function DialogMoveSession(props: DialogMoveSessionProps) {
|
||||
options={options()}
|
||||
emptyView={
|
||||
showError() ? (
|
||||
<box paddingLeft={4} paddingRight={4}>
|
||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||
<text fg={theme.text.feedback.error.default} attributes={TextAttributes.BOLD}>
|
||||
Could not load project directories
|
||||
</text>
|
||||
@@ -336,17 +336,17 @@ export function DialogMoveSession(props: DialogMoveSessionProps) {
|
||||
<text fg={theme.text.subdued}>Close and reopen Move session to try again.</text>
|
||||
</box>
|
||||
) : directories.loading || loadedProject.loading ? (
|
||||
<box paddingLeft={4} paddingRight={4}>
|
||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||
<text fg={theme.text.subdued}>Loading project directories…</text>
|
||||
</box>
|
||||
) : (
|
||||
<box paddingLeft={4} paddingRight={4}>
|
||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||
<text fg={theme.text.subdued}>No project directories available</text>
|
||||
</box>
|
||||
)
|
||||
}
|
||||
noMatchView={
|
||||
<box paddingLeft={4} paddingRight={4}>
|
||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||
<text fg={theme.text.subdued}>No project directories found</text>
|
||||
</box>
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { createMemo, createResource, createSignal, onMount, Show } from "solid-js"
|
||||
import { createMemo, createResource, createSignal, onMount } from "solid-js"
|
||||
import path from "path"
|
||||
import type { SessionInfo } from "@opencode-ai/client"
|
||||
import { TextAttributes } from "@opentui/core"
|
||||
import { useDialog } from "../ui/dialog"
|
||||
import { DialogSelect } from "../ui/dialog-select"
|
||||
import { useRoute } from "../context/route"
|
||||
@@ -33,69 +32,52 @@ export function DialogSessionList() {
|
||||
const shortcuts = Keymap.useShortcuts()
|
||||
const [search, setSearch] = createDebouncedSignal("", 150)
|
||||
const [toDelete, setToDelete] = createSignal<string>()
|
||||
const [allProjects, setAllProjects] = createSignal(false)
|
||||
|
||||
const [searchResults, { mutate: setSearchResults }] = createResource(
|
||||
() => ({ query: search().trim(), allProjects: allProjects() }),
|
||||
async ({ query, allProjects }) => {
|
||||
try {
|
||||
if (!data.location.info()) await data.location.sync()
|
||||
const current = data.location.info()
|
||||
if (!current) throw new Error("Location unavailable")
|
||||
const response = await client.api.session.list({
|
||||
...(allProjects
|
||||
? {}
|
||||
: {
|
||||
project: current.project.id,
|
||||
subpath: path.relative(current.project.directory, current.directory).replaceAll("\\", "/"),
|
||||
}),
|
||||
...(query ? { search: query } : {}),
|
||||
limit: 50,
|
||||
order: "desc",
|
||||
parentID: null,
|
||||
})
|
||||
return { query, allProjects, sessions: response.data, error: undefined }
|
||||
} catch (error) {
|
||||
// A transient transport failure must degrade search, not crash the TUI
|
||||
// through the root ErrorBoundary when the errored resource is read.
|
||||
return { query, allProjects, sessions: [] as SessionInfo[], error }
|
||||
}
|
||||
},
|
||||
)
|
||||
const [searchResults] = createResource(search, async (query) => {
|
||||
if (!query) return
|
||||
try {
|
||||
if (!data.location.info()) await data.location.sync()
|
||||
const current = data.location.info()
|
||||
if (!current) throw new Error("Location unavailable")
|
||||
const response = await client.api.session.list({
|
||||
project: current.project.id,
|
||||
search: query,
|
||||
limit: 50,
|
||||
order: "desc",
|
||||
parentID: null,
|
||||
})
|
||||
return { query, sessions: response.data, error: undefined }
|
||||
} catch (error) {
|
||||
// A transient transport failure must degrade search, not crash the TUI
|
||||
// through the root ErrorBoundary when the errored resource is read.
|
||||
return { query, sessions: [] as SessionInfo[], error }
|
||||
}
|
||||
})
|
||||
|
||||
const currentSessionID = createMemo(() => (route.data.type === "session" ? route.data.sessionID : undefined))
|
||||
const localSessions = createMemo(() => {
|
||||
const query = filter().trim().toLowerCase()
|
||||
const current = data.location.info()
|
||||
const sessions = data.session
|
||||
.list()
|
||||
.filter(
|
||||
(session) =>
|
||||
allProjects() ||
|
||||
(session.projectID === current?.project.id && session.location.directory === current.directory),
|
||||
)
|
||||
const sessions = data.session.list()
|
||||
if (!query) return sessions
|
||||
return sessions.filter((session) => !session.parentID && session.title.toLowerCase().includes(query))
|
||||
})
|
||||
const sessions = createMemo(() => {
|
||||
const query = filter().trim()
|
||||
const query = filter()
|
||||
const local = localSessions()
|
||||
if (query !== search().trim() || searchResults.loading) return searchResults.latest?.sessions ?? local
|
||||
if (!query) return local
|
||||
if (query !== search() || searchResults.loading) return local
|
||||
const result = searchResults()
|
||||
if (result?.query !== query || result.allProjects !== allProjects() || result.error) return local
|
||||
if (result?.query !== query || result.error) return local
|
||||
return result.sessions
|
||||
})
|
||||
const searchState = createMemo(() => {
|
||||
const query = filter().trim()
|
||||
if (query !== search().trim() || searchResults.loading)
|
||||
return { message: query ? "Searching sessions…" : "Loading sessions…", error: false }
|
||||
const query = filter()
|
||||
if (!query) return { message: "No sessions available", error: false }
|
||||
if (query !== search() || searchResults.loading) return { message: "Searching sessions…", error: false }
|
||||
const result = searchResults()
|
||||
if (result?.query === query && result.error)
|
||||
return {
|
||||
message: query ? "Could not search sessions. Change the search to try again." : "Could not load sessions.",
|
||||
error: true,
|
||||
}
|
||||
return { message: query ? "No sessions found" : "No sessions available", error: false }
|
||||
return { message: "Could not search sessions. Change the search to try again.", error: true }
|
||||
return { message: "No sessions found", error: false }
|
||||
})
|
||||
|
||||
const quickSwitchHint = createMemo(() => {
|
||||
@@ -109,13 +91,6 @@ export function DialogSessionList() {
|
||||
const hint = quickSwitchHint()
|
||||
return hint && local.session.slots().length > 0 ? [{ title: "switch", label: hint }] : []
|
||||
})
|
||||
const currentProjectName = createMemo(() => {
|
||||
const current = data.location.info()
|
||||
if (!current) return ""
|
||||
const project = data.project.get(current.project.id)
|
||||
if (!project) return ""
|
||||
return project.name || path.basename(project.canonical)
|
||||
})
|
||||
|
||||
const options = createMemo(() => {
|
||||
const today = new Date().toDateString()
|
||||
@@ -130,12 +105,8 @@ export function DialogSessionList() {
|
||||
|
||||
const option = (session: SessionInfo, category: string) => {
|
||||
const directory = session.location.directory
|
||||
const project = data.project.get(session.projectID)
|
||||
const footer = allProjects()
|
||||
? Locale.truncate(project?.name || path.basename(project?.canonical ?? directory), 20)
|
||||
: directory !== data.location.info()?.project.directory
|
||||
? Locale.truncate(path.basename(directory), 20)
|
||||
: ""
|
||||
const footer =
|
||||
directory !== data.location.info()?.project.directory ? Locale.truncate(path.basename(directory), 20) : ""
|
||||
const slot = sessionTabs.enabled() ? undefined : slotByID.get(session.id)
|
||||
const deleting = toDelete() === session.id
|
||||
return {
|
||||
@@ -168,16 +139,6 @@ export function DialogSessionList() {
|
||||
return (
|
||||
<DialogSelect
|
||||
title="Sessions"
|
||||
titleView={
|
||||
<box flexDirection="row">
|
||||
<text fg={theme.text.default} attributes={TextAttributes.BOLD}>
|
||||
Sessions
|
||||
</text>
|
||||
<Show when={!allProjects() && currentProjectName()}>
|
||||
<text fg={theme.text.subdued}> for {currentProjectName()}</text>
|
||||
</Show>
|
||||
</box>
|
||||
}
|
||||
options={options()}
|
||||
skipFilter={true}
|
||||
current={currentSessionID()}
|
||||
@@ -185,25 +146,13 @@ export function DialogSessionList() {
|
||||
setFilter(query)
|
||||
setSearch(query)
|
||||
}}
|
||||
bindings={[
|
||||
{
|
||||
bind: "ctrl+a",
|
||||
title: allProjects() ? "Show current directory sessions" : "Show all project sessions",
|
||||
group: "Dialog",
|
||||
run: () => {
|
||||
setAllProjects((value) => !value)
|
||||
},
|
||||
},
|
||||
]}
|
||||
emptyView={
|
||||
<box paddingLeft={4} paddingRight={4}>
|
||||
<text fg={searchState().error ? theme.text.feedback.error.default : theme.text.subdued}>
|
||||
{searchState().message}
|
||||
</text>
|
||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||
<text fg={theme.text.subdued}>No sessions available</text>
|
||||
</box>
|
||||
}
|
||||
noMatchView={
|
||||
<box paddingLeft={4} paddingRight={4}>
|
||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||
<text fg={searchState().error ? theme.text.feedback.error.default : theme.text.subdued}>
|
||||
{searchState().message}
|
||||
</text>
|
||||
@@ -229,34 +178,24 @@ export function DialogSessionList() {
|
||||
setToDelete(option.value)
|
||||
return
|
||||
}
|
||||
void client.api.session
|
||||
.remove({ sessionID: option.value })
|
||||
.then(() => {
|
||||
setSearchResults((result) =>
|
||||
result ? { ...result, sessions: result.sessions.filter((session) => session.id !== option.value) } : result,
|
||||
)
|
||||
})
|
||||
.catch((error) => {
|
||||
setToDelete(undefined)
|
||||
toast.show({
|
||||
message: `Failed to delete session: ${errorMessage(error)}`,
|
||||
variant: "error",
|
||||
duration: 5000,
|
||||
})
|
||||
void client.api.session.remove({ sessionID: option.value }).catch((error) => {
|
||||
setToDelete(undefined)
|
||||
toast.show({
|
||||
message: `Failed to delete session: ${errorMessage(error)}`,
|
||||
variant: "error",
|
||||
duration: 5000,
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
command: "session.rename",
|
||||
title: "rename",
|
||||
onTrigger: (option: { value: string; title: string }) =>
|
||||
DialogSessionRename.show(dialog, option.value, option.title),
|
||||
onTrigger: (option: { value: string }) =>
|
||||
DialogSessionRename.show(dialog, option.value, data.session.get(option.value)?.title),
|
||||
},
|
||||
]}
|
||||
footerHints={[
|
||||
...quickSwitchFooterHints(),
|
||||
{ title: allProjects() ? "current directory" : "all projects", label: "ctrl+a", side: "right" },
|
||||
]}
|
||||
footerHints={quickSwitchFooterHints()}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -62,13 +62,13 @@ export function DialogSkill(props: DialogSkillProps) {
|
||||
emptyView={
|
||||
<Switch
|
||||
fallback={
|
||||
<box paddingLeft={4} paddingRight={4}>
|
||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||
<text fg={theme.text.subdued}>No skills available</text>
|
||||
</box>
|
||||
}
|
||||
>
|
||||
<Match when={showError()}>
|
||||
<box paddingLeft={4} paddingRight={4}>
|
||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||
<text fg={theme.text.feedback.error.default} attributes={TextAttributes.BOLD}>
|
||||
Could not load skills
|
||||
</text>
|
||||
@@ -77,14 +77,14 @@ export function DialogSkill(props: DialogSkillProps) {
|
||||
</box>
|
||||
</Match>
|
||||
<Match when={skills.loading}>
|
||||
<box paddingLeft={4} paddingRight={4}>
|
||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||
<text fg={theme.text.subdued}>Loading skills…</text>
|
||||
</box>
|
||||
</Match>
|
||||
</Switch>
|
||||
}
|
||||
noMatchView={
|
||||
<box paddingLeft={4} paddingRight={4}>
|
||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||
<text fg={theme.text.subdued}>No skills found</text>
|
||||
</box>
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import type {
|
||||
ModelInfo,
|
||||
PermissionSavedInfo,
|
||||
PermissionRequest,
|
||||
Project,
|
||||
ProviderInfo,
|
||||
ReferenceInfo,
|
||||
SessionMessageInfo,
|
||||
@@ -81,7 +80,6 @@ type Store = {
|
||||
form: Record<string, FormWithLocation[]>
|
||||
}
|
||||
project: {
|
||||
info: Record<string, Project>
|
||||
permission: Record<string, PermissionSavedInfo[]>
|
||||
}
|
||||
location: Record<string, LocationData>
|
||||
@@ -141,7 +139,6 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
form: {},
|
||||
},
|
||||
project: {
|
||||
info: {},
|
||||
permission: {},
|
||||
},
|
||||
location: {},
|
||||
@@ -957,26 +954,10 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
sync.invalidate(`session.pending:${sessionID}`)
|
||||
},
|
||||
},
|
||||
sync(sessionID: string, options?: { children?: boolean }) {
|
||||
return sync.run(options?.children ? `session.family:${sessionID}` : `session:${sessionID}`, async () => {
|
||||
const [info, children] = await Promise.all([
|
||||
client.api.session.get({ sessionID }),
|
||||
options?.children
|
||||
? client.api.session.list({ parentID: sessionID, order: "desc" }).then((response) => response.data)
|
||||
: [],
|
||||
])
|
||||
const sessions = [info, ...children]
|
||||
setStore(
|
||||
"session",
|
||||
"info",
|
||||
produce((draft) => {
|
||||
for (const session of sessions) draft[session.id] = session
|
||||
}),
|
||||
)
|
||||
for (const session of sessions) {
|
||||
sync.complete(`session:${session.id}`)
|
||||
registerSession(session.id)
|
||||
}
|
||||
sync(sessionID: string) {
|
||||
return sync.run(`session:${sessionID}`, async () => {
|
||||
setStore("session", "info", sessionID, await client.api.session.get({ sessionID }))
|
||||
registerSession(sessionID)
|
||||
})
|
||||
},
|
||||
invalidate(sessionID: string) {
|
||||
@@ -1056,21 +1037,6 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
},
|
||||
},
|
||||
project: {
|
||||
list() {
|
||||
return Object.values(store.project.info).toSorted((a, b) => b.time.updated - a.time.updated)
|
||||
},
|
||||
get(projectID: string) {
|
||||
return store.project.info[projectID]
|
||||
},
|
||||
sync() {
|
||||
return sync.run("project", async () => {
|
||||
const projects = await client.api.project.list()
|
||||
setStore("project", "info", reconcile(Object.fromEntries(projects.map((project) => [project.id, project]))))
|
||||
})
|
||||
},
|
||||
invalidate() {
|
||||
sync.invalidate("project")
|
||||
},
|
||||
permission: {
|
||||
list(projectID: string) {
|
||||
return store.project.permission[projectID]
|
||||
@@ -1352,9 +1318,27 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
.then((location) => {
|
||||
const key = locationKey(location)
|
||||
setStore("location", key, { ...store.location[key], info: location })
|
||||
return client.api.session.list({
|
||||
project: location.project.id,
|
||||
limit: 50,
|
||||
order: "desc",
|
||||
parentID: null,
|
||||
})
|
||||
})
|
||||
.catch((error) => console.error("Failed to preload location", error))
|
||||
void result.project.sync().catch((error) => console.error("Failed to preload projects", error))
|
||||
.then((response) => {
|
||||
setStore(
|
||||
"session",
|
||||
"info",
|
||||
produce((draft) => {
|
||||
for (const session of response.data) draft[session.id] = session
|
||||
}),
|
||||
)
|
||||
for (const session of response.data) {
|
||||
sync.complete(`session:${session.id}`)
|
||||
registerSession(session.id)
|
||||
}
|
||||
})
|
||||
.catch((error) => console.error("Failed to preload sessions", error))
|
||||
return
|
||||
}
|
||||
handleEvent(details)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { createEffect, createMemo, onCleanup } from "solid-js"
|
||||
import { createEffect, onCleanup } from "solid-js"
|
||||
import { isDeepEqual } from "remeda"
|
||||
import { createSimpleContext } from "./helper"
|
||||
import { useClient } from "./client"
|
||||
import { useData } from "./data"
|
||||
import { useEvent } from "./event"
|
||||
import { useRoute } from "./route"
|
||||
@@ -32,14 +31,10 @@ type PersistedState = {
|
||||
|
||||
const empty = (): TabsState => ({ tabs: [], unread: {} })
|
||||
|
||||
// Deliberately after connect settles: the visible session's mount syncs win the first slots.
|
||||
const TAB_PREFETCH_DELAY = 300
|
||||
|
||||
export const { use: useSessionTabs, provider: SessionTabsProvider } = createSimpleContext({
|
||||
name: "SessionTabs",
|
||||
init: () => {
|
||||
const route = useRoute()
|
||||
const client = useClient()
|
||||
const data = useData()
|
||||
const event = useEvent()
|
||||
const config = useConfig().data
|
||||
@@ -134,45 +129,6 @@ export const { use: useSessionTabs, provider: SessionTabsProvider } = createSimp
|
||||
})
|
||||
})
|
||||
|
||||
// Warm open tabs' session data so first switches render from cache instead of fetching inside
|
||||
// the switch gesture. Uses only existing sync methods (each dedupes internally), so reruns on
|
||||
// tab-set or connection changes are no-ops for already-warm sessions, and reconnects double as
|
||||
// a cache refresh after an SSE gap. The delay lets the current session's own mount syncs get
|
||||
// the first connection slots. The effect tracks only the id set: reorders, tab switches, and
|
||||
// title updates neither restart the timer nor an in-flight warm pass; the timer callback
|
||||
// itself runs untracked, where the current session is skipped.
|
||||
const openTabSessions = createMemo(() =>
|
||||
state()
|
||||
.tabs.map((tab) => tab.sessionID)
|
||||
.sort()
|
||||
.join("\n"),
|
||||
)
|
||||
createEffect(() => {
|
||||
if (!enabled()) return
|
||||
if (client.connection.status() !== "connected") return
|
||||
if (openTabSessions() === "") return
|
||||
let stale = false
|
||||
const timer = setTimeout(async () => {
|
||||
const sessions = state()
|
||||
.tabs.map((tab) => tab.sessionID)
|
||||
.filter((sessionID) => sessionID !== current())
|
||||
for (const sessionID of sessions) {
|
||||
if (stale) return
|
||||
await Promise.allSettled([
|
||||
data.session.sync(sessionID),
|
||||
data.session.message.sync(sessionID),
|
||||
data.session.pending.sync(sessionID),
|
||||
data.session.permission.sync(sessionID),
|
||||
data.session.form.sync(sessionID),
|
||||
])
|
||||
}
|
||||
}, TAB_PREFETCH_DELAY)
|
||||
onCleanup(() => {
|
||||
stale = true
|
||||
clearTimeout(timer)
|
||||
})
|
||||
})
|
||||
|
||||
onCleanup(event.on("session.execution.succeeded", (evt) => markUnread(evt.data.sessionID, "activity")))
|
||||
onCleanup(event.on("session.execution.interrupted", (evt) => markUnread(evt.data.sessionID, "activity")))
|
||||
onCleanup(event.on("session.execution.failed", (evt) => markUnread(evt.data.sessionID, "error")))
|
||||
|
||||
@@ -33,7 +33,6 @@ import { useDialog } from "../ui/dialog"
|
||||
import { useToast } from "../ui/toast"
|
||||
import { useAttention } from "../context/attention"
|
||||
import { useStorage } from "../context/storage"
|
||||
import { useSessionTabs } from "../context/session-tabs"
|
||||
import { abbreviateHome } from "../util/path-format"
|
||||
import { builtins } from "./builtins"
|
||||
import { discoverTuiPlugins } from "./discovery"
|
||||
@@ -95,7 +94,6 @@ export function PluginProvider(props: ParentProps<{ packages: PackageResolver }>
|
||||
const toast = useToast()
|
||||
const attention = useAttention()
|
||||
const storage = useStorage()
|
||||
const sessionTabs = useSessionTabs()
|
||||
const directory = config.path ? path.dirname(config.path) : process.cwd()
|
||||
const [store, setStore] = createStore({
|
||||
ready: false,
|
||||
@@ -280,33 +278,6 @@ export function PluginProvider(props: ParentProps<{ packages: PackageResolver }>
|
||||
return route.data
|
||||
},
|
||||
},
|
||||
tabs: {
|
||||
enabled: sessionTabs.enabled,
|
||||
list: () =>
|
||||
sessionTabs.tabs().map((tab) => ({
|
||||
...tab,
|
||||
active: sessionTabs.current() === tab.sessionID,
|
||||
...sessionTabs.status(tab.sessionID),
|
||||
})),
|
||||
open(sessionID) {
|
||||
if (!sessionTabs.enabled()) return false
|
||||
sessionTabs.select(sessionID)
|
||||
return true
|
||||
},
|
||||
focus(sessionID) {
|
||||
if (!sessionTabs.enabled()) return false
|
||||
if (!sessionTabs.tabs().some((tab) => tab.sessionID === sessionID)) return false
|
||||
sessionTabs.select(sessionID)
|
||||
return true
|
||||
},
|
||||
close(sessionID) {
|
||||
if (!sessionTabs.enabled()) return false
|
||||
const target = sessionID ?? sessionTabs.current()
|
||||
if (!target || !sessionTabs.tabs().some((tab) => tab.sessionID === target)) return false
|
||||
sessionTabs.close(target)
|
||||
return true
|
||||
},
|
||||
},
|
||||
slot(name, render) {
|
||||
if (store.registrations[item.plugin.id]?.slots[name]) throw new Error(`Slot already registered: ${name}`)
|
||||
setStore("registrations", item.plugin.id, "slots", name, () => (input: SlotMap[typeof name]) => (
|
||||
|
||||
@@ -98,13 +98,6 @@ addDefaultParsers(parsers.parsers)
|
||||
// Exclude temporary bottom space when measuring the real transcript height.
|
||||
const NAVIGATION_SLACK_ID = "session-navigation-slack"
|
||||
|
||||
// Tail-first transcript mounting: rows mounted with the session, then backfill cadence.
|
||||
// The tail comfortably overfills a tall viewport; backfill drains a 200-message transcript
|
||||
// in a few hundred milliseconds without a perceptible pause.
|
||||
const TRANSCRIPT_TAIL_ROWS = 40
|
||||
const TRANSCRIPT_BACKFILL_CHUNK = 60
|
||||
const TRANSCRIPT_BACKFILL_DELAY = 120
|
||||
|
||||
const context = createContext<{
|
||||
width: number
|
||||
sessionID: string
|
||||
@@ -263,7 +256,7 @@ export function Session() {
|
||||
const sessionID = route.sessionID
|
||||
void (async () => {
|
||||
await Promise.all([
|
||||
data.session.sync(sessionID, { children: true }),
|
||||
data.session.sync(sessionID),
|
||||
data.session.permission.sync(sessionID),
|
||||
data.session.form.sync(sessionID),
|
||||
])
|
||||
@@ -303,49 +296,6 @@ export function Session() {
|
||||
r.set(route.prompt)
|
||||
}
|
||||
|
||||
/** Runs after layout has settled (two frames), unless the transcript was torn down. */
|
||||
const afterLayout = (continuation: () => void) => {
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
if (!scroll || scroll.isDestroyed) return
|
||||
continuation()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Tail-first transcript mounting: only the newest rows mount when the session opens, and the
|
||||
// rest backfill in chunks shortly after, so switching to a long session costs the visible tail
|
||||
// instead of the whole transcript. Until backfill pins the count, the hidden span derives from
|
||||
// the row count, so it needs no effect ordering; the clamp keeps at least a tail visible when a
|
||||
// re-reduce shrinks the transcript. Streaming appends land at the end of the visible slice.
|
||||
const [hiddenRows, setHiddenRows] = createSignal<number>()
|
||||
const hidden = createMemo(() => Math.max(0, Math.min(hiddenRows() ?? Infinity, rows.length - TRANSCRIPT_TAIL_ROWS)))
|
||||
const visibleRows = createMemo(() => (hidden() === 0 ? rows : rows.slice(hidden())))
|
||||
createEffect(() => {
|
||||
const current = hidden()
|
||||
if (current === 0) return
|
||||
// Until the first chunk pins hiddenRows, appends change hidden() and reset this timer, so
|
||||
// backfill waits for a pause in streaming before starting. Once pinned, it drains on a fixed
|
||||
// cadence undisturbed by appends.
|
||||
const timer = setTimeout(() => {
|
||||
const before = scroll && !scroll.isDestroyed ? scroll.scrollHeight : undefined
|
||||
const viewportBottom = before === undefined ? 0 : scroll.scrollTop + scroll.viewport.height
|
||||
setHiddenRows(Math.max(0, current - TRANSCRIPT_BACKFILL_CHUNK))
|
||||
if (before === undefined) return
|
||||
// Sticky scroll holds bottom-anchored readers through the mount; compensation is only for
|
||||
// readers who have scrolled up.
|
||||
if (viewportBottom >= before - 1) return
|
||||
afterLayout(() => scroll.scrollBy(scroll.scrollHeight - before))
|
||||
}, TRANSCRIPT_BACKFILL_DELAY)
|
||||
onCleanup(() => clearTimeout(timer))
|
||||
})
|
||||
/** Message navigation needs the full transcript mounted before walking or jumping. */
|
||||
const ensureAllRows = (continuation: () => void) => {
|
||||
if (hidden() === 0) return continuation()
|
||||
setHiddenRows(0)
|
||||
afterLayout(continuation)
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
const current = prompt()
|
||||
if (sent || !current || !synced() || !local.model.ready) return
|
||||
@@ -372,36 +322,41 @@ export function Session() {
|
||||
currentSlack: scroll.getRenderable(NAVIGATION_SLACK_ID)?.height ?? 0,
|
||||
}),
|
||||
)
|
||||
afterLayout(() => {
|
||||
if (navigationMessage() !== messageID) return
|
||||
scroll.scrollTo(top)
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
if (scroll.isDestroyed || navigationMessage() !== messageID) return
|
||||
scroll.scrollTo(top)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const scrollToMessage = (direction: "next" | "prev", dialog: ReturnType<typeof useDialog>, userOnly = false) =>
|
||||
ensureAllRows(() => {
|
||||
const target = findMessageBoundary({
|
||||
direction,
|
||||
children: scroll.getChildren(),
|
||||
messages: messages(),
|
||||
scrollTop: scroll.scrollTop,
|
||||
viewportY: scroll.viewport.y,
|
||||
currentID: navigationMessage(),
|
||||
userOnly,
|
||||
})
|
||||
const scrollToMessage = (direction: "next" | "prev", dialog: ReturnType<typeof useDialog>, userOnly = false) => {
|
||||
const target = findMessageBoundary({
|
||||
direction,
|
||||
children: scroll.getChildren(),
|
||||
messages: messages(),
|
||||
scrollTop: scroll.scrollTop,
|
||||
viewportY: scroll.viewport.y,
|
||||
currentID: navigationMessage(),
|
||||
userOnly,
|
||||
})
|
||||
|
||||
if (target) alignMessage(target.id, target.top)
|
||||
if (!target) {
|
||||
dialog.clear()
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const jumpToMessage = (messageID: string) =>
|
||||
ensureAllRows(() => {
|
||||
const child = scroll.getRenderable(messageID)
|
||||
if (!child) return
|
||||
const y = scroll.scrollTop + child.y - scroll.viewport.y
|
||||
const message = data.session.message.get(route.sessionID, messageID)
|
||||
alignMessage(messageID, Math.max(0, y - (message?.type === "assistant" ? 1 : 0)))
|
||||
})
|
||||
alignMessage(target.id, target.top)
|
||||
dialog.clear()
|
||||
}
|
||||
|
||||
const jumpToMessage = (messageID: string) => {
|
||||
const child = scroll.getRenderable(messageID)
|
||||
if (!child) return
|
||||
const y = scroll.scrollTop + child.y - scroll.viewport.y
|
||||
const message = data.session.message.get(route.sessionID, messageID)
|
||||
alignMessage(messageID, Math.max(0, y - (message?.type === "assistant" ? 1 : 0)))
|
||||
}
|
||||
|
||||
function toBottom() {
|
||||
clearMessageNavigation()
|
||||
@@ -977,12 +932,12 @@ export function Session() {
|
||||
flexGrow={1}
|
||||
scrollAcceleration={scrollAcceleration()}
|
||||
>
|
||||
<For each={visibleRows()}>
|
||||
<For each={rows}>
|
||||
{(row, index) => (
|
||||
<SessionRowView
|
||||
row={row}
|
||||
message={(messageID) => data.session.message.get(route.sessionID, messageID)}
|
||||
boundaryID={boundaries()[index() + hidden()]}
|
||||
boundaryID={boundaries()[index()]}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
|
||||
@@ -97,16 +97,11 @@ export function createSessionRows(sessionID: Accessor<string>) {
|
||||
}),
|
||||
)
|
||||
|
||||
// Re-reduce when the revert boundary changes (stage/clear/commit). These reactions defer
|
||||
// their first run: the mount effect above has already reduced the same state.
|
||||
// Re-reduce when the revert boundary changes (stage/clear/commit).
|
||||
createEffect(
|
||||
on(
|
||||
revertBoundary,
|
||||
() => {
|
||||
setRows(reconcile(reduce()))
|
||||
},
|
||||
{ defer: true },
|
||||
),
|
||||
on(revertBoundary, () => {
|
||||
setRows(reconcile(reduce()))
|
||||
}),
|
||||
)
|
||||
|
||||
createEffect(
|
||||
@@ -117,7 +112,6 @@ export function createSessionRows(sessionID: Accessor<string>) {
|
||||
.filter((item) => item.type === "compaction")
|
||||
.map((item) => item.id),
|
||||
() => setRows(reconcile(reduce())),
|
||||
{ defer: true },
|
||||
),
|
||||
)
|
||||
|
||||
@@ -143,11 +137,12 @@ export function createSessionRows(sessionID: Accessor<string>) {
|
||||
: [],
|
||||
),
|
||||
() => setRows(reconcile(reduce())),
|
||||
{ defer: true },
|
||||
),
|
||||
)
|
||||
|
||||
createEffect(on(turnTokens, () => setRows(reconcile(reduce())), { defer: true }))
|
||||
createEffect(
|
||||
on(turnTokens, () => setRows(reconcile(reduce()))),
|
||||
)
|
||||
|
||||
const appendMessage = (messageID: string) =>
|
||||
setRows(
|
||||
|
||||
@@ -615,14 +615,14 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
||||
when={props.renderFilter !== false && store.filter.length > 0}
|
||||
fallback={
|
||||
props.emptyView ?? (
|
||||
<box paddingLeft={4} paddingRight={4}>
|
||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||
<text fg={theme.text.subdued}>No items available</text>
|
||||
</box>
|
||||
)
|
||||
}
|
||||
>
|
||||
{props.noMatchView ?? (
|
||||
<box paddingLeft={4} paddingRight={4}>
|
||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||
<text fg={theme.text.subdued}>No results found</text>
|
||||
</box>
|
||||
)}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { ClientProvider, useClient } from "../../../src/context/client"
|
||||
import { DataProvider as DataProviderBase, useData } from "../../../src/context/data"
|
||||
import { LocationProvider, useLocation } from "../../../src/context/location"
|
||||
import { createSessionRows, type SessionRow } from "../../../src/routes/session/rows"
|
||||
import { createApi, createEventStream, createFetch, directory, json, worktree } from "../../fixture/tui-client"
|
||||
import { createApi, createEventStream, createFetch, directory, json } from "../../fixture/tui-client"
|
||||
import { TestTuiContexts } from "../../fixture/tui-environment"
|
||||
import { createTuiResolvedConfig } from "../../fixture/tui-runtime"
|
||||
|
||||
@@ -71,13 +71,11 @@ function durable(sessionID: string, seq = 0, version = 1) {
|
||||
return { aggregateID: sessionID, seq, version }
|
||||
}
|
||||
|
||||
test("does not preload session summaries into the data context", async () => {
|
||||
test("preloads root sessions before applying the session limit", async () => {
|
||||
const events = createEventStream()
|
||||
let location = false
|
||||
let sessions = false
|
||||
let request: URL | undefined
|
||||
const calls = createFetch((url) => {
|
||||
if (url.pathname === "/api/location") location = true
|
||||
if (url.pathname === "/api/session") sessions = true
|
||||
if (url.pathname === "/api/session") request = url
|
||||
return undefined
|
||||
}, events)
|
||||
|
||||
@@ -94,58 +92,10 @@ test("does not preload session summaries into the data context", async () => {
|
||||
))
|
||||
|
||||
try {
|
||||
await wait(() => location)
|
||||
await Bun.sleep(20)
|
||||
expect(sessions).toBe(false)
|
||||
} finally {
|
||||
app.renderer.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
test("proactively syncs project metadata", async () => {
|
||||
const events = createEventStream()
|
||||
const calls = createFetch((url) => {
|
||||
if (url.pathname !== "/api/project") return
|
||||
return json([
|
||||
{
|
||||
id: "proj_test",
|
||||
canonical: worktree,
|
||||
name: "OpenCode",
|
||||
time: { created: 1, updated: 2 },
|
||||
sandboxes: [],
|
||||
},
|
||||
])
|
||||
}, events)
|
||||
let data!: ReturnType<typeof useData>
|
||||
|
||||
function Probe() {
|
||||
data = useData()
|
||||
return <box />
|
||||
}
|
||||
|
||||
const app = await testRender(() => (
|
||||
<TestTuiContexts>
|
||||
<ClientProvider api={createApi(calls.fetch)}>
|
||||
<ProjectProvider>
|
||||
<DataProvider>
|
||||
<Probe />
|
||||
</DataProvider>
|
||||
</ProjectProvider>
|
||||
</ClientProvider>
|
||||
</TestTuiContexts>
|
||||
))
|
||||
|
||||
try {
|
||||
await wait(() => data.project.get("proj_test") !== undefined)
|
||||
expect(data.project.list()).toEqual([
|
||||
{
|
||||
id: "proj_test",
|
||||
canonical: worktree,
|
||||
name: "OpenCode",
|
||||
time: { created: 1, updated: 2 },
|
||||
sandboxes: [],
|
||||
},
|
||||
])
|
||||
await wait(() => request !== undefined)
|
||||
expect(request?.searchParams.get("project")).toBe("proj_test")
|
||||
expect(request?.searchParams.get("limit")).toBe("50")
|
||||
expect(request?.searchParams.get("parentID")).toBe("null")
|
||||
} finally {
|
||||
app.renderer.destroy()
|
||||
}
|
||||
@@ -2669,18 +2619,8 @@ function sessionInfo(id: string, parentID: string | undefined, cost = 0) {
|
||||
// the family-index tests below.
|
||||
async function mountData(parents: Record<string, string>, costs: Record<string, number> = {}) {
|
||||
const calls = createFetch((url) => {
|
||||
if (url.pathname === "/api/session") {
|
||||
const parentID = url.searchParams.get("parentID")
|
||||
return json({
|
||||
data: Object.entries(parents)
|
||||
.filter(([, parent]) => parent === parentID)
|
||||
.map(([id, parent]) => sessionInfo(id, parent, costs[id])),
|
||||
cursor: {},
|
||||
})
|
||||
}
|
||||
const match = url.pathname.match(/^\/api\/session\/([^/]+)$/)
|
||||
if (match && match[1] !== "active")
|
||||
return json({ data: sessionInfo(match[1], parents[match[1]], costs[match[1]]) })
|
||||
if (match && match[1] !== "active") return json({ data: sessionInfo(match[1], parents[match[1]], costs[match[1]]) })
|
||||
})
|
||||
let data!: ReturnType<typeof useData>
|
||||
let ready!: () => void
|
||||
@@ -2707,20 +2647,6 @@ async function mountData(parents: Record<string, string>, costs: Record<string,
|
||||
return { data, app }
|
||||
}
|
||||
|
||||
test("syncs direct child session info with a navigated root", async () => {
|
||||
const { data, app } = await mountData({ child: "root", sibling: "root", grandchild: "child" })
|
||||
try {
|
||||
await data.session.sync("root", { children: true })
|
||||
expect(data.session.get("root")?.id).toBe("root")
|
||||
expect(data.session.get("child")?.parentID).toBe("root")
|
||||
expect(data.session.get("sibling")?.parentID).toBe("root")
|
||||
expect(data.session.get("grandchild")).toBeUndefined()
|
||||
expect(data.session.family("root")).toEqual(["root", "child", "sibling"])
|
||||
} finally {
|
||||
app.renderer.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
test("groups an orphan child under its missing parent until the root arrives", async () => {
|
||||
const { data, app } = await mountData({ child: "root" })
|
||||
try {
|
||||
|
||||
@@ -185,19 +185,6 @@ test("dialog actions run without options while row actions still require a selec
|
||||
}
|
||||
})
|
||||
|
||||
test("renders one gap before an empty state", async () => {
|
||||
await using tmp = await tmpdir()
|
||||
const app = await renderSelect(tmp.path, [], () => {}, () => {})
|
||||
|
||||
try {
|
||||
await app.waitForFrame((frame) => frame.includes("No items available"))
|
||||
const lines = app.captureCharFrame().split("\n").map((line) => line.trim())
|
||||
expect(lines.indexOf("No items available") - lines.indexOf("Search")).toBe(2)
|
||||
} finally {
|
||||
app.renderer.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
test("footer actions run when filtering leaves no selected row", async () => {
|
||||
await using tmp = await tmpdir()
|
||||
let global = 0
|
||||
|
||||
@@ -93,26 +93,24 @@ export function createFetch(override?: FetchHandler, events?: ReturnType<typeof
|
||||
if (url.pathname === "/experimental/console") return json({ consoleManagedProviders: [], switchableOrgCount: 0 })
|
||||
if (url.pathname === "/experimental/capabilities") return json({ backgroundSubagents: true })
|
||||
if (url.pathname === "/path") return json({ home: "", state: "", config: "", worktree, directory })
|
||||
if (url.pathname === "/api/location")
|
||||
return json({ directory, project: { id: "proj_test", directory: worktree, canonical: worktree } })
|
||||
if (url.pathname === "/api/location") return json({ directory, project: { id: "proj_test", directory: worktree } })
|
||||
if (url.pathname === "/api/fs/list")
|
||||
return json({ location: { directory, project: { id: "proj_test", directory: worktree, canonical: worktree } }, data: [] })
|
||||
return json({ location: { directory, project: { id: "proj_test", directory: worktree } }, data: [] })
|
||||
if (url.pathname === "/api/project/current") return json({ id: "proj_test", directory: worktree })
|
||||
if (url.pathname === "/api/project") return json([])
|
||||
if (url.pathname === "/api/project/proj_test/directories") return json([{ directory: worktree }])
|
||||
if (url.pathname === "/api/shell")
|
||||
return json({ location: { directory, project: { id: "proj_test", directory: worktree, canonical: worktree } }, data: [] })
|
||||
return json({ location: { directory, project: { id: "proj_test", directory: worktree } }, data: [] })
|
||||
if (url.pathname === "/api/mcp")
|
||||
return json({ location: { directory, project: { id: "proj_test", directory: worktree, canonical: worktree } }, data: [] })
|
||||
return json({ location: { directory, project: { id: "proj_test", directory: worktree } }, data: [] })
|
||||
if (url.pathname === "/api/mcp/resource")
|
||||
return json({
|
||||
location: { directory, project: { id: "proj_test", directory: worktree, canonical: worktree } },
|
||||
location: { directory, project: { id: "proj_test", directory: worktree } },
|
||||
data: { resources: [], templates: [] },
|
||||
})
|
||||
if (url.pathname === "/api/session") return json({ data: [], cursor: {} })
|
||||
if (url.pathname === "/api/session/active") return json({ data: {} })
|
||||
if (url.pathname === "/api/permission/request")
|
||||
return json({ location: { directory, project: { id: "proj_test", directory: worktree, canonical: worktree } }, data: [] })
|
||||
return json({ location: { directory, project: { id: "proj_test", directory: worktree } }, data: [] })
|
||||
if (url.pathname === "/api/form/request")
|
||||
return json({ location: { directory, project: { id: "proj_test", directory: worktree } }, data: [] })
|
||||
if (/^\/api\/session\/[^/]+\/form$/.test(url.pathname)) return json({ data: [] })
|
||||
@@ -122,13 +120,13 @@ export function createFetch(override?: FetchHandler, events?: ReturnType<typeof
|
||||
)
|
||||
)
|
||||
return json({
|
||||
location: { directory, project: { id: "proj_test", directory: worktree, canonical: worktree } },
|
||||
location: { directory, project: { id: "proj_test", directory: worktree } },
|
||||
data: [],
|
||||
})
|
||||
if (url.pathname === "/api/reference")
|
||||
return json({ location: { directory, project: { id: "proj_test", directory, canonical: directory } }, data: [] })
|
||||
return json({ location: { directory, project: { id: "proj_test", directory } }, data: [] })
|
||||
if (url.pathname === "/api/websearch/provider") {
|
||||
return json({ location: { directory, project: { id: "proj_test", directory, canonical: directory } }, data: [] })
|
||||
return json({ location: { directory, project: { id: "proj_test", directory } }, data: [] })
|
||||
}
|
||||
if (url.pathname === "/provider") return json({ all: [], default: {}, connected: [] })
|
||||
if (url.pathname === "/session") return json([])
|
||||
|
||||
@@ -78,7 +78,7 @@ describe("run interactive runtime", () => {
|
||||
directory: "/tmp",
|
||||
target: async () => ({
|
||||
sessionID: "ses_root",
|
||||
location: { directory: "/tmp", project: { id: "pro-1", directory: "/tmp", canonical: "/tmp" } },
|
||||
location: { directory: "/tmp", project: { id: "pro-1", directory: "/tmp" } },
|
||||
agent: "build",
|
||||
model: undefined,
|
||||
variant: undefined,
|
||||
@@ -130,7 +130,7 @@ describe("run interactive runtime", () => {
|
||||
await refreshCatalog?.()
|
||||
expect(defaultModel).toHaveBeenCalledTimes(1)
|
||||
selected.resolve({
|
||||
location: { directory: "/tmp", project: { id: "pro-1", directory: "/tmp", canonical: "/tmp" } },
|
||||
location: { directory: "/tmp", project: { id: "pro-1", directory: "/tmp" } },
|
||||
data: model,
|
||||
})
|
||||
while (defaultModel.mock.calls.length < 2) await Bun.sleep(0)
|
||||
@@ -165,7 +165,7 @@ describe("run interactive runtime", () => {
|
||||
directory: "/tmp",
|
||||
target: async () => ({
|
||||
sessionID: "ses_root",
|
||||
location: { directory: "/tmp", project: { id: "pro-1", directory: "/tmp", canonical: "/tmp" } },
|
||||
location: { directory: "/tmp", project: { id: "pro-1", directory: "/tmp" } },
|
||||
agent: "build",
|
||||
model: { providerID: "test", modelID: "model" },
|
||||
variant: undefined,
|
||||
@@ -261,7 +261,7 @@ describe("run interactive runtime", () => {
|
||||
return {
|
||||
sessionID: "ses-deferred",
|
||||
sessionTitle: "Deferred",
|
||||
location: { directory: "/tmp", project: { id: "pro-1", directory: "/tmp", canonical: "/tmp" } },
|
||||
location: { directory: "/tmp", project: { id: "pro-1", directory: "/tmp" } },
|
||||
agent: "build",
|
||||
model: { providerID: "openai", modelID: "gpt-5" },
|
||||
variant: undefined,
|
||||
@@ -349,7 +349,7 @@ describe("run interactive runtime", () => {
|
||||
target: async () => ({
|
||||
sessionID: "ses-resume",
|
||||
sessionTitle: "Resume",
|
||||
location: { directory: "/tmp", project: { id: "pro-1", directory: "/tmp", canonical: "/tmp" } },
|
||||
location: { directory: "/tmp", project: { id: "pro-1", directory: "/tmp" } },
|
||||
agent: "review",
|
||||
model: { providerID: "openai", modelID: "gpt-5" },
|
||||
variant: "high",
|
||||
@@ -432,7 +432,7 @@ describe("run interactive runtime", () => {
|
||||
target: async () => ({
|
||||
sessionID: "ses-resume-abort",
|
||||
sessionTitle: "Cached title",
|
||||
location: { directory: "/tmp", project: { id: "pro-1", directory: "/tmp", canonical: "/tmp" } },
|
||||
location: { directory: "/tmp", project: { id: "pro-1", directory: "/tmp" } },
|
||||
agent: "build",
|
||||
model: undefined,
|
||||
variant: undefined,
|
||||
@@ -490,7 +490,7 @@ describe("run interactive runtime", () => {
|
||||
location: {
|
||||
directory: "/session",
|
||||
workspaceID: "work-1",
|
||||
project: { id: "pro-1", directory: "/session", canonical: "/session" },
|
||||
project: { id: "pro-1", directory: "/session" },
|
||||
},
|
||||
data: [{ path: "src/index.ts", type: "file" }],
|
||||
} as never)
|
||||
@@ -507,7 +507,7 @@ describe("run interactive runtime", () => {
|
||||
location: {
|
||||
directory: "/session",
|
||||
workspaceID: "work-1",
|
||||
project: { id: "location-project", directory: "/session", canonical: "/session" },
|
||||
project: { id: "location-project", directory: "/session" },
|
||||
},
|
||||
agent: "review",
|
||||
model: { providerID: "openai", modelID: "gpt-5" },
|
||||
|
||||
@@ -167,11 +167,7 @@ function sdk(input: {
|
||||
location: {
|
||||
directory: input.globalLocation?.directory ?? "/tmp",
|
||||
workspaceID: input.globalLocation?.workspaceID,
|
||||
project: {
|
||||
id: "proj_1",
|
||||
directory: input.globalLocation?.directory ?? "/tmp",
|
||||
canonical: input.globalLocation?.directory ?? "/tmp",
|
||||
},
|
||||
project: { id: "proj_1", directory: input.globalLocation?.directory ?? "/tmp" },
|
||||
},
|
||||
data: input.globals ?? [],
|
||||
}),
|
||||
|
||||
@@ -7,7 +7,11 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
OpenCode Go هو اشتراك منخفض التكلفة — **$5 للشهر الأول**، ثم **$10/شهريًا** — يمنحك وصولًا موثوقًا إلى نماذج البرمجة المفتوحة الشائعة.
|
||||
|
||||
يعمل Go مثل أي مزود آخر في OpenCode. تشترك في OpenCode Go وتحصل على مفتاح API الخاص بك. وهو **اختياري تمامًا**، ولا تحتاج إلى استخدامه لاستخدام OpenCode.
|
||||
|
||||
صُمّم أساسًا للمستخدمين الدوليين، مع استضافة النماذج في الولايات المتحدة والاتحاد الأوروبي وسنغافورة لضمان وصول عالمي مستقر.
|
||||
|
||||
---
|
||||
|
||||
@@ -33,18 +37,37 @@ OpenCode Go access belongs to the named subscriber and is available only through
|
||||
|
||||
## كيف يعمل
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
يعمل OpenCode Go مثل أي مزود آخر في OpenCode.
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. تسجّل الدخول إلى **<a href={console}>OpenCode Zen</a>**، وتشترك في Go، ثم تنسخ مفتاح API الخاص بك.
|
||||
2. تشغّل الأمر `/connect` في TUI، وتختار `OpenCode Go`، ثم تلصق مفتاح API الخاص بك.
|
||||
3. شغّل `/models` في TUI لرؤية قائمة النماذج المتاحة عبر Go.
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
يمكن لعضو واحد فقط في كل workspace الاشتراك في OpenCode Go.
|
||||
:::
|
||||
|
||||
تشمل قائمة النماذج الحالية:
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
قد تتغير قائمة النماذج مع استمرارنا في اختبار نماذج جديدة وإضافتها.
|
||||
|
||||
---
|
||||
|
||||
## حدود الاستخدام
|
||||
@@ -147,6 +170,44 @@ External-agent and service-account support is deferred.
|
||||
|
||||
---
|
||||
|
||||
## نقاط النهاية
|
||||
|
||||
يمكنك أيضًا الوصول إلى نماذج Go عبر نقاط نهاية API التالية.
|
||||
|
||||
| Model | Model ID | Endpoint | AI SDK Package |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
يستخدم [model id](/docs/config/#models) في إعدادات OpenCode لديك التنسيق `opencode-go/<model-id>`. على سبيل المثال، بالنسبة إلى Kimi K3، ستستخدم `opencode-go/kimi-k3` في إعداداتك.
|
||||
|
||||
---
|
||||
|
||||
### النماذج
|
||||
|
||||
يمكنك جلب القائمة الكاملة بالنماذج المتاحة وبياناتها الوصفية من:
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## الخصوصية
|
||||
|
||||
صُمّمت هذه الخطة أساسًا للمستخدمين الدوليين، مع استضافة النماذج في الولايات المتحدة والاتحاد الأوروبي وسنغافورة لضمان وصول عالمي مستقر. ويتّبع مزودونا سياسة عدم الاحتفاظ بالبيانات، ولا يستخدمون بياناتك لتدريب النماذج.
|
||||
|
||||
@@ -85,18 +85,32 @@ OpenCode Zen هي قائمة نماذج يوفّرها فريق OpenCode وقد
|
||||
|
||||
## OpenCode Go
|
||||
|
||||
OpenCode Go belongs to the named subscriber and is available through OpenCode’s `opencode` provider.
|
||||
OpenCode Go هي خطة اشتراك منخفضة التكلفة توفّر وصولا موثوقا إلى نماذج البرمجة المفتوحة الشهيرة المقدّمة من فريق OpenCode، والتي تم اختبارها والتحقق من أنها تعمل بشكل جيد مع OpenCode.
|
||||
|
||||
1. [Subscribe in OpenCode Console](https://opencode.ai/console/go).
|
||||
2. Run the Console device login and approve it in your browser.
|
||||
1. شغّل الأمر `/connect` في TUI، واختر `OpenCode Go`، ثم انتقل إلى [opencode.ai/auth](https://opencode.ai/zen).
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```txt
|
||||
/connect
|
||||
```
|
||||
|
||||
3. Choose a model from the `opencode` provider.
|
||||
2. سجّل الدخول، وأضف تفاصيل الفوترة، ثم انسخ مفتاح API الخاص بك.
|
||||
|
||||
External-agent and service-account support is deferred. No separate Go provider or credential copy is required.
|
||||
3. الصق مفتاح API.
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
│
|
||||
│
|
||||
└ enter
|
||||
```
|
||||
|
||||
4. شغّل `/models` في TUI لعرض قائمة النماذج التي نوصي بها.
|
||||
|
||||
```txt
|
||||
/models
|
||||
```
|
||||
|
||||
يعمل مثل أي مزوّد آخر في OpenCode واستخدامه اختياري بالكامل.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,13 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
OpenCode Go je povoljna pretplata — **$5 za vaš prvi mjesec**, a zatim **$10/mjesečno** — koja vam pruža pouzdan pristup popularnim otvorenim modelima za programiranje.
|
||||
|
||||
Go radi kao bilo koji drugi provajder u OpenCode-u. Pretplatite se na OpenCode Go i
|
||||
dobijete svoj API ključ. On je **potpuno opcionalan** i ne morate ga koristiti da
|
||||
biste koristili OpenCode.
|
||||
|
||||
Dizajniran je prvenstveno za međunarodne korisnike, sa modelima hostovanim u SAD-u, EU i Singapuru za stabilan globalni pristup.
|
||||
|
||||
---
|
||||
|
||||
@@ -39,18 +45,39 @@ OpenCode Go vam daje pristup ovim modelima za **$5 za vaš prvi mjesec**, a zati
|
||||
|
||||
## Kako funkcioniše
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
OpenCode Go radi kao bilo koji drugi provajder u OpenCode-u.
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. Prijavite se na **<a href={console}>OpenCode Zen</a>**, pretplatite se na Go i
|
||||
kopirajte svoj API ključ.
|
||||
2. Pokrenite komandu `/connect` u TUI-ju, odaberite `OpenCode Go` i zalijepite
|
||||
svoj API ključ.
|
||||
3. Pokrenite `/models` u TUI-ju da vidite listu modela dostupnih kroz Go.
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
Samo jedan član po radnom prostoru (workspace) može se pretplatiti na OpenCode Go.
|
||||
:::
|
||||
|
||||
Trenutna lista modela uključuje:
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
Lista modela se može mijenjati dok testiramo i dodajemo nove.
|
||||
|
||||
---
|
||||
|
||||
## Ograničenja upotrebe
|
||||
@@ -155,6 +182,46 @@ Za ove modele i dalje dobijate malo više nego da direktno plaćate provajderima
|
||||
|
||||
---
|
||||
|
||||
## Endpointi
|
||||
|
||||
Također možete pristupiti Go modelima putem sljedećih API endpointa.
|
||||
|
||||
| Model | Model ID | Endpoint | AI SDK Paket |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
[Model id](/docs/config/#models) u vašoj OpenCode konfiguraciji
|
||||
koristi format `opencode-go/<model-id>`. Na primjer, za Kimi K3, koristili biste
|
||||
`opencode-go/kimi-k3` u svojoj konfiguraciji.
|
||||
|
||||
---
|
||||
|
||||
### Modeli
|
||||
|
||||
Pun spisak dostupnih modela i njihovih metapodataka možete preuzeti na:
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Privatnost
|
||||
|
||||
Plan je prvenstveno namijenjen međunarodnim korisnicima, a modeli su smješteni u US, EU i Singaporeu radi stabilnog globalnog pristupa. Naši pružaoci usluga primjenjuju politiku nultog zadržavanja podataka i ne koriste vaše podatke za treniranje modela.
|
||||
|
||||
@@ -86,18 +86,32 @@ Radi kao i svaki drugi provajder u OpenCode i potpuno je opcionalan za korišten
|
||||
|
||||
## OpenCode Go
|
||||
|
||||
OpenCode Go belongs to the named subscriber and is available through OpenCode’s `opencode` provider.
|
||||
OpenCode Go je jeftin plan pretplate koji pruža pouzdan pristup popularnim modelima otvorenog kodiranja koje pruža OpenCode tim i koji su testirani i verificirani da dobro rade s OpenCode-om.
|
||||
|
||||
1. [Subscribe in OpenCode Console](https://opencode.ai/console/go).
|
||||
2. Run the Console device login and approve it in your browser.
|
||||
1. Pokrenite naredbu `/connect` u TUI-u, odaberite `OpenCode Go` i idite na [opencode.ai/auth](https://opencode.ai/zen).
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```txt
|
||||
/connect
|
||||
```
|
||||
|
||||
3. Choose a model from the `opencode` provider.
|
||||
2. Prijavite se, dodajte svoje detalje naplate i kopirajte svoj API ključ.
|
||||
|
||||
External-agent and service-account support is deferred. No separate Go provider or credential copy is required.
|
||||
3. Zalijepite svoj API ključ.
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
│
|
||||
│
|
||||
└ enter
|
||||
```
|
||||
|
||||
4. Pokrenite naredbu `/models` u TUI da vidite listu modela koje preporučujemo.
|
||||
|
||||
```txt
|
||||
/models
|
||||
```
|
||||
|
||||
Radi kao i svaki drugi provajder u OpenCode i potpuno je opcionalan za korištenje.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,13 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
OpenCode Go er et lavprisabonnement — **$5 for din første måned**, derefter **$10/måned** — der giver dig pålidelig adgang til populære åbne kodningsmodeller.
|
||||
|
||||
Go fungerer som enhver anden udbyder i OpenCode. Du abonnerer på OpenCode Go og
|
||||
får din API-nøgle. Det er **helt valgfrit**, og du behøver ikke at bruge det for at
|
||||
bruge OpenCode.
|
||||
|
||||
Det er primært designet til internationale brugere, med modeller hostet i USA, EU og Singapore for at sikre stabil global adgang.
|
||||
|
||||
---
|
||||
|
||||
@@ -39,18 +45,39 @@ OpenCode Go giver dig adgang til disse modeller for **$5 for din første måned*
|
||||
|
||||
## Sådan fungerer det
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
OpenCode Go fungerer som enhver anden udbyder i OpenCode.
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. Du logger ind på **<a href={console}>OpenCode Zen</a>**, abonnerer på Go, og
|
||||
kopierer din API-nøgle.
|
||||
2. Du kører kommandoen `/connect` i TUI'en, vælger `OpenCode Go`, og indsætter
|
||||
din API-nøgle.
|
||||
3. Kør `/models` i TUI'en for at se listen over tilgængelige modeller gennem Go.
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
Kun ét medlem per arbejdsområde kan abonnere på OpenCode Go.
|
||||
:::
|
||||
|
||||
Den nuværende liste over modeller inkluderer:
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
Listen over modeller kan ændre sig, efterhånden som vi tester og tilføjer nye.
|
||||
|
||||
---
|
||||
|
||||
## Forbrugsgrænser
|
||||
@@ -155,6 +182,46 @@ Med disse modeller får du stadig lidt mere, end hvis du betalte modeludbyderne
|
||||
|
||||
---
|
||||
|
||||
## Endpoints
|
||||
|
||||
Du kan også få adgang til Go-modeller gennem følgende API-endpoints.
|
||||
|
||||
| Model | Model ID | Endpoint | AI SDK Package |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
Dit [model id](/docs/config/#models) i din OpenCode config
|
||||
bruger formatet `opencode-go/<model-id>`. For eksempel for Kimi K3, vil du
|
||||
bruge `opencode-go/kimi-k3` i din config.
|
||||
|
||||
---
|
||||
|
||||
### Modeller
|
||||
|
||||
Du kan hente den fulde liste over tilgængelige modeller og deres metadata fra:
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Privatliv
|
||||
|
||||
Planen er primært designet til internationale brugere med modeller hostet i US, EU og Singapore for stabil global adgang. Vores udbydere følger en zero-retention-policy og bruger ikke dine data til modeltræning.
|
||||
|
||||
@@ -83,18 +83,32 @@ Det fungerer som alle andre udbydere i OpenCode og er helt valgfrit at bruge.
|
||||
|
||||
## OpenCode Go
|
||||
|
||||
OpenCode Go belongs to the named subscriber and is available through OpenCode’s `opencode` provider.
|
||||
OpenCode Go er en billig abonnementsplan, der giver pålidelig adgang til populære åbne kodningsmodeller leveret af OpenCode-teamet, som er testet og verificeret til at fungere godt med OpenCode.
|
||||
|
||||
1. [Subscribe in OpenCode Console](https://opencode.ai/console/go).
|
||||
2. Run the Console device login and approve it in your browser.
|
||||
1. Kør kommandoen `/connect` i TUI, vælg `OpenCode Go`, og gå til [opencode.ai/auth](https://opencode.ai/zen).
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```txt
|
||||
/connect
|
||||
```
|
||||
|
||||
3. Choose a model from the `opencode` provider.
|
||||
2. Log ind, tilføj dine faktureringsoplysninger og kopier din API-nøgle.
|
||||
|
||||
External-agent and service-account support is deferred. No separate Go provider or credential copy is required.
|
||||
3. Indsæt din API-nøgle.
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
│
|
||||
│
|
||||
└ enter
|
||||
```
|
||||
|
||||
4. Kør `/models` i TUI for at se listen over modeller, vi anbefaler.
|
||||
|
||||
```txt
|
||||
/models
|
||||
```
|
||||
|
||||
Det fungerer som alle andre udbydere i OpenCode og er helt valgfrit at bruge.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,13 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
OpenCode Go ist ein kostengünstiges Abonnement — **5 $ für deinen ersten Monat**, danach **10 $/Monat** —, das dir zuverlässigen Zugriff auf beliebte offene Coding-Modelle bietet.
|
||||
|
||||
Go funktioniert wie jeder andere Provider in OpenCode. Du abonnierst OpenCode Go und
|
||||
erhältst deinen API-Key. Es ist **völlig optional** und du musst es nicht nutzen, um
|
||||
OpenCode zu verwenden.
|
||||
|
||||
Es wurde primär für internationale Nutzer entwickelt, wobei die Modelle für einen stabilen weltweiten Zugriff in den USA, der EU und Singapur gehostet werden.
|
||||
|
||||
---
|
||||
|
||||
@@ -33,18 +39,37 @@ OpenCode Go bietet dir Zugriff auf diese Modelle für **5 $ im ersten Monat**, d
|
||||
|
||||
## Wie es funktioniert
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
OpenCode Go funktioniert wie jeder andere Provider in OpenCode.
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. Du meldest dich bei **<a href={console}>OpenCode Zen</a>** an, abonnierst Go und kopierst deinen API-Key.
|
||||
2. Du führst den Befehl `/connect` in der TUI aus, wählst `OpenCode Go` und fügst deinen API-Key ein.
|
||||
3. Führe `/models` in der TUI aus, um die Liste der über Go verfügbaren Modelle zu sehen.
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
Nur ein Mitglied pro Workspace kann OpenCode Go abonnieren.
|
||||
:::
|
||||
|
||||
Die aktuelle Liste der Modelle umfasst:
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
Die Liste der Modelle kann sich ändern, während wir neue testen und hinzufügen.
|
||||
|
||||
---
|
||||
|
||||
## Nutzungslimits
|
||||
@@ -147,6 +172,44 @@ Bei diesen Modellen erhältst du immer noch etwas mehr, als wenn du die Modellan
|
||||
|
||||
---
|
||||
|
||||
## Endpunkte
|
||||
|
||||
Du kannst auf die Go-Modelle auch über die folgenden API-Endpunkte zugreifen.
|
||||
|
||||
| Modell | Modell-ID | Endpunkt | AI SDK Package |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
Die [Modell-ID](/docs/config/#models) in deiner OpenCode Config verwendet das Format `opencode-go/<model-id>`. Für Kimi K3 würdest du beispielsweise `opencode-go/kimi-k3` in deiner Config verwenden.
|
||||
|
||||
---
|
||||
|
||||
### Models
|
||||
|
||||
Du kannst die vollständige Liste der verfügbaren Modelle und ihrer Metadaten hier abrufen:
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Datenschutz
|
||||
|
||||
Der Plan ist in erster Linie für internationale Nutzer konzipiert, mit in US, EU und Singapore gehosteten Modellen für einen stabilen weltweiten Zugriff. Unsere Anbieter befolgen eine Zero-Retention-Richtlinie und verwenden Ihre Daten nicht für das Modelltraining.
|
||||
|
||||
@@ -86,18 +86,32 @@ Es funktioniert wie jeder andere Anbieter in OpenCode und ist völlig optional.
|
||||
|
||||
## OpenCode Go
|
||||
|
||||
OpenCode Go belongs to the named subscriber and is available through OpenCode’s `opencode` provider.
|
||||
OpenCode Go ist ein kostenguenstiges Abonnement, das zuverlaessigen Zugriff auf beliebte Open-Coding-Modelle bietet, die vom OpenCode-Team getestet und verifiziert wurden, dass sie gut mit OpenCode funktionieren.
|
||||
|
||||
1. [Subscribe in OpenCode Console](https://opencode.ai/console/go).
|
||||
2. Run the Console device login and approve it in your browser.
|
||||
1. Führen Sie den Befehl `/connect` in der TUI aus, waehlen Sie `OpenCode Go` und gehen Sie zu [opencode.ai/auth](https://opencode.ai/zen).
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```txt
|
||||
/connect
|
||||
```
|
||||
|
||||
3. Choose a model from the `opencode` provider.
|
||||
2. Melden Sie sich an, geben Sie Ihre Rechnungsdaten ein und kopieren Sie Ihren API-Schlüssel.
|
||||
|
||||
External-agent and service-account support is deferred. No separate Go provider or credential copy is required.
|
||||
3. Fügen Sie Ihren API-Schlüssel ein.
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
│
|
||||
│
|
||||
└ enter
|
||||
```
|
||||
|
||||
4. Führen Sie `/models` in der TUI aus, um die Liste der empfohlenen Modelle zu sehen.
|
||||
|
||||
```txt
|
||||
/models
|
||||
```
|
||||
|
||||
Es funktioniert wie jeder andere Anbieter in OpenCode und ist völlig optional.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,13 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
OpenCode Go es una suscripción de bajo costo — **$5 por tu primer mes**, luego **$10/mes** — que te brinda acceso confiable a modelos abiertos de programación populares.
|
||||
|
||||
Go funciona como cualquier otro proveedor en OpenCode. Te suscribes a OpenCode Go y
|
||||
obtienes tu API key. Es **completamente opcional** y no necesitas usarlo para
|
||||
usar OpenCode.
|
||||
|
||||
Está diseñado principalmente para usuarios internacionales, con modelos alojados en EE. UU., la UE y Singapur para un acceso global estable.
|
||||
|
||||
---
|
||||
|
||||
@@ -39,18 +45,39 @@ OpenCode Go te da acceso a estos modelos por **$5 por tu primer mes**, luego **$
|
||||
|
||||
## Cómo funciona
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
OpenCode Go funciona como cualquier otro proveedor en OpenCode.
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. Inicias sesión en **<a href={console}>OpenCode Zen</a>**, te suscribes a Go y
|
||||
copias tu API key.
|
||||
2. Ejecutas el comando `/connect` en la TUI, seleccionas `OpenCode Go` y pegas
|
||||
tu API key.
|
||||
3. Ejecutas `/models` en la TUI para ver la lista de modelos disponibles a través de Go.
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
Solo un miembro por espacio de trabajo puede suscribirse a OpenCode Go.
|
||||
:::
|
||||
|
||||
La lista actual de modelos incluye:
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
La lista de modelos puede cambiar a medida que probamos y agregamos otros nuevos.
|
||||
|
||||
---
|
||||
|
||||
## Límites de uso
|
||||
@@ -155,6 +182,46 @@ Con estos modelos, aun así obtienes un poco más que si pagaras directamente a
|
||||
|
||||
---
|
||||
|
||||
## Endpoints
|
||||
|
||||
También puedes acceder a los modelos de Go a través de los siguientes endpoints de la API.
|
||||
|
||||
| Modelo | ID del modelo | Endpoint | Paquete de AI SDK |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
El [ID del modelo](/docs/config/#models) en tu configuración de OpenCode
|
||||
usa el formato `opencode-go/<model-id>`. Por ejemplo, para Kimi K3, usarías
|
||||
`opencode-go/kimi-k3` en tu configuración.
|
||||
|
||||
---
|
||||
|
||||
### Modelos
|
||||
|
||||
Puedes obtener la lista completa de modelos disponibles y sus metadatos desde:
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Privacidad
|
||||
|
||||
El plan está diseñado principalmente para usuarios internacionales, con modelos alojados en US, EU y Singapore para ofrecer un acceso global estable. Nuestros proveedores siguen una política de retención cero y no utilizan tus datos para el entrenamiento de modelos.
|
||||
|
||||
@@ -86,18 +86,33 @@ Funciona como cualquier otro proveedor en OpenCode y su uso es completamente opc
|
||||
|
||||
## OpenCode Go
|
||||
|
||||
OpenCode Go belongs to the named subscriber and is available through OpenCode’s `opencode` provider.
|
||||
OpenCode Go es un plan de suscripción de bajo costo que brinda acceso confiable a modelos de codificación abiertos populares proporcionados por el equipo de OpenCode que han sido
|
||||
probado y verificado para funcionar bien con OpenCode.
|
||||
|
||||
1. [Subscribe in OpenCode Console](https://opencode.ai/console/go).
|
||||
2. Run the Console device login and approve it in your browser.
|
||||
1. Ejecute el comando `/connect` en TUI, seleccione `OpenCode Go` y diríjase a [opencode.ai/auth](https://opencode.ai/zen).
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```txt
|
||||
/connect
|
||||
```
|
||||
|
||||
3. Choose a model from the `opencode` provider.
|
||||
2. Inicie sesión, agregue sus datos de facturación y copie su clave API.
|
||||
|
||||
External-agent and service-account support is deferred. No separate Go provider or credential copy is required.
|
||||
3. Pegue su clave API.
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
│
|
||||
│
|
||||
└ enter
|
||||
```
|
||||
|
||||
4. Ejecute `/models` en TUI para ver la lista de modelos que recomendamos.
|
||||
|
||||
```txt
|
||||
/models
|
||||
```
|
||||
|
||||
Funciona como cualquier otro proveedor en OpenCode y su uso es completamente opcional.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,11 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
OpenCode Go est un abonnement à bas coût — **5 $ pour votre premier mois**, puis **10 $/mois** — qui vous donne un accès fiable aux modèles de codage ouverts populaires.
|
||||
|
||||
Go fonctionne comme n'importe quel autre fournisseur dans OpenCode. Vous vous abonnez à OpenCode Go et obtenez votre clé d'API. C'est **totalement facultatif** et vous n'avez pas besoin de l'utiliser pour utiliser OpenCode.
|
||||
|
||||
Il est conçu principalement pour les utilisateurs internationaux, avec des modèles hébergés aux États-Unis, dans l'UE et à Singapour pour un accès mondial stable.
|
||||
|
||||
---
|
||||
|
||||
@@ -33,18 +37,37 @@ OpenCode Go vous donne accès à ces modèles pour **5 $ pour votre premier mois
|
||||
|
||||
## Comment ça marche
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
OpenCode Go fonctionne comme n'importe quel autre fournisseur dans OpenCode.
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. Vous vous connectez à **<a href={console}>OpenCode Zen</a>**, vous vous abonnez à Go et copiez votre clé d'API.
|
||||
2. Vous exécutez la commande `/connect` dans la TUI, sélectionnez `OpenCode Go` et collez votre clé d'API.
|
||||
3. Exécutez `/models` dans la TUI pour voir la liste des modèles disponibles via Go.
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
Un seul membre par espace de travail peut s'abonner à OpenCode Go.
|
||||
:::
|
||||
|
||||
La liste actuelle des modèles comprend :
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
La liste des modèles peut changer au fur et à mesure que nous en testons et en ajoutons de nouveaux.
|
||||
|
||||
---
|
||||
|
||||
## Limites d'utilisation
|
||||
@@ -147,6 +170,44 @@ Pour ces modèles, vous obtenez tout de même un peu plus que si vous payiez dir
|
||||
|
||||
---
|
||||
|
||||
## Points de terminaison
|
||||
|
||||
Vous pouvez également accéder aux modèles Go via les points de terminaison d'API suivants.
|
||||
|
||||
| Modèle | ID de modèle | Point de terminaison | Package AI SDK |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
L'[ID de modèle](/docs/config/#models) dans votre configuration OpenCode utilise le format `opencode-go/<model-id>`. Par exemple, pour Kimi K3, vous utiliseriez `opencode-go/kimi-k3` dans votre configuration.
|
||||
|
||||
---
|
||||
|
||||
### Modèles
|
||||
|
||||
Vous pouvez récupérer la liste complète des modèles disponibles et leurs métadonnées à partir de :
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Confidentialité
|
||||
|
||||
Cette offre est conçue avant tout pour les utilisateurs internationaux, avec des modèles hébergés aux US, dans l’EU et à Singapore afin d’assurer un accès mondial stable. Nos fournisseurs appliquent une politique de rétention zéro et n’utilisent pas vos données pour l’entraînement des modèles.
|
||||
|
||||
@@ -86,18 +86,33 @@ Il fonctionne comme n’importe quel autre fournisseur dans OpenCode et son util
|
||||
|
||||
## OpenCode Go
|
||||
|
||||
OpenCode Go belongs to the named subscriber and is available through OpenCode’s `opencode` provider.
|
||||
OpenCode Go est un plan d'abonnement à faible coût qui offre un accès fiable aux modèles de codage ouverts populaires fournis par l'équipe OpenCode qui ont été
|
||||
testé et vérifié pour fonctionner correctement avec OpenCode.
|
||||
|
||||
1. [Subscribe in OpenCode Console](https://opencode.ai/console/go).
|
||||
2. Run the Console device login and approve it in your browser.
|
||||
1. Exécutez la commande `/connect` dans le TUI, sélectionnez `OpenCode Go` et rendez-vous sur [opencode.ai/auth](https://opencode.ai/zen).
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```txt
|
||||
/connect
|
||||
```
|
||||
|
||||
3. Choose a model from the `opencode` provider.
|
||||
2. Connectez-vous, ajoutez vos informations de facturation et copiez votre clé API.
|
||||
|
||||
External-agent and service-account support is deferred. No separate Go provider or credential copy is required.
|
||||
3. Collez votre clé API.
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
│
|
||||
│
|
||||
└ enter
|
||||
```
|
||||
|
||||
4. Exécutez `/models` dans le TUI pour voir la liste des modèles que nous recommandons.
|
||||
|
||||
```txt
|
||||
/models
|
||||
```
|
||||
|
||||
Il fonctionne comme n’importe quel autre fournisseur dans OpenCode et son utilisation est totalement facultative.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,13 @@ import config from "../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
OpenCode Go is a low cost subscription — **$5 for your first month**, then **$10/month** — that gives you reliable access to popular open coding models.
|
||||
|
||||
Go works like any other provider in OpenCode. You subscribe to OpenCode Go and
|
||||
get your API key. It's **completely optional** and you don't need to use it to
|
||||
use OpenCode.
|
||||
|
||||
It is designed primarily for international users, with models hosted in the US, EU, and Singapore for stable global access.
|
||||
|
||||
---
|
||||
|
||||
@@ -39,18 +45,39 @@ OpenCode Go gives you access to these models for **$5 for your first month**, th
|
||||
|
||||
## How it works
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
OpenCode Go works like any other provider in OpenCode.
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. You sign in to **<a href={console}>OpenCode Zen</a>**, subscribe to Go, and
|
||||
copy your API key.
|
||||
2. You run the `/connect` command in the TUI, select `OpenCode Go`, and paste
|
||||
your API key.
|
||||
3. Run `/models` in the TUI to see the list of models available through Go.
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
Only one member per workspace can subscribe to OpenCode Go.
|
||||
:::
|
||||
|
||||
The current list of models includes:
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
The list of models may change as we test and add new ones.
|
||||
|
||||
---
|
||||
|
||||
## Usage limits
|
||||
@@ -155,6 +182,46 @@ For these models, you still get a little more than if you paid the model provide
|
||||
|
||||
---
|
||||
|
||||
## Endpoints
|
||||
|
||||
You can also access Go models through the following API endpoints.
|
||||
|
||||
| Model | Model ID | Endpoint | AI SDK Package |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
The [model id](/docs/config/#models) in your OpenCode config
|
||||
uses the format `opencode-go/<model-id>`. For example, for Kimi K3, you would
|
||||
use `opencode-go/kimi-k3` in your config.
|
||||
|
||||
---
|
||||
|
||||
### Models
|
||||
|
||||
You can fetch the full list of available models and their metadata from:
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Privacy
|
||||
|
||||
The plan is designed primarily for international users, with models hosted in the US, EU, and Singapore for stable global access. Our providers follow a zero-retention policy and do not use your data for model training.
|
||||
|
||||
@@ -7,7 +7,13 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
OpenCode Go è un abbonamento a basso costo — **5 $ per il primo mese**, poi **10 $/mese** — che ti offre un accesso affidabile ai popolari modelli di programmazione aperti.
|
||||
|
||||
Go funziona come qualsiasi altro provider in OpenCode. Ti abboni a OpenCode Go e
|
||||
ottieni la tua chiave API. È **completamente facoltativo** e non hai bisogno di usarlo per
|
||||
utilizzare OpenCode.
|
||||
|
||||
È progettato principalmente per gli utenti internazionali, con modelli ospitati negli Stati Uniti, nell'Unione Europea e a Singapore per un accesso globale stabile.
|
||||
|
||||
---
|
||||
|
||||
@@ -37,18 +43,39 @@ OpenCode Go ti dà accesso a questi modelli a **5 $ per il primo mese**, poi a *
|
||||
|
||||
## Come funziona
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
OpenCode Go funziona come qualsiasi altro provider in OpenCode.
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. Accedi a **<a href={console}>OpenCode Zen</a>**, ti abboni a Go e
|
||||
copi la tua chiave API.
|
||||
2. Esegui il comando `/connect` nella TUI, selezioni `OpenCode Go` e incolli
|
||||
la tua chiave API.
|
||||
3. Esegui `/models` nella TUI per vedere l'elenco dei modelli disponibili tramite Go.
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
Solo un membro per workspace può abbonarsi a OpenCode Go.
|
||||
:::
|
||||
|
||||
L'elenco attuale dei modelli include:
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
L'elenco dei modelli potrebbe cambiare man mano che ne testiamo e aggiungiamo di nuovi.
|
||||
|
||||
---
|
||||
|
||||
## Limiti di utilizzo
|
||||
@@ -153,6 +180,46 @@ Per questi modelli, ottieni comunque un po' più di utilizzo rispetto a quanto o
|
||||
|
||||
---
|
||||
|
||||
## Endpoint
|
||||
|
||||
Puoi anche accedere ai modelli Go tramite i seguenti endpoint API.
|
||||
|
||||
| Modello | ID Modello | Endpoint | Pacchetto AI SDK |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
Il [model id](/docs/config/#models) nella tua OpenCode config
|
||||
utilizza il formato `opencode-go/<model-id>`. Ad esempio, per Kimi K3, useresti
|
||||
`opencode-go/kimi-k3` nella tua configurazione.
|
||||
|
||||
---
|
||||
|
||||
### Modelli
|
||||
|
||||
Puoi recuperare l'elenco completo dei modelli disponibili e i relativi metadati da:
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Privacy
|
||||
|
||||
Il piano è pensato principalmente per gli utenti internazionali, con modelli ospitati negli US, nell’EU e a Singapore per un accesso globale stabile. I nostri provider seguono una politica di zero-retention e non utilizzano i tuoi dati per l’addestramento dei modelli.
|
||||
|
||||
@@ -7,7 +7,11 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
OpenCode Goは低価格のサブスクリプションで、**初月は5ドル**、その後は**月額10ドル**で、人気のオープンなコーディングモデルに安定してアクセスできます。
|
||||
|
||||
GoはOpenCodeの他のプロバイダーと同様に機能します。OpenCode GoをサブスクライブしてAPIキーを取得します。これは**完全に任意**であり、OpenCodeを使用するために必須ではありません。
|
||||
|
||||
主に海外ユーザー向けに設計されており、世界中で安定してアクセスできるよう、モデルは米国、EU、シンガポールでホストされています。
|
||||
|
||||
---
|
||||
|
||||
@@ -33,18 +37,37 @@ OpenCode Goを使用すると、これらのモデルに**初月は5ドル**、
|
||||
|
||||
## 仕組み
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
OpenCode Goは、OpenCodeの他のプロバイダーと同様に機能します。
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. **<a href={console}>OpenCode Zen</a>**にサインインし、GoをサブスクライブしてAPIキーをコピーします。
|
||||
2. TUIで`/connect`コマンドを実行し、`OpenCode Go`を選択して、APIキーを貼り付けます。
|
||||
3. TUIで`/models`を実行すると、Goを通じて利用可能なモデルのリストが表示されます。
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
OpenCode Goをサブスクライブできるのは、1つのワークスペースにつき1メンバーのみです。
|
||||
:::
|
||||
|
||||
現在のモデルリストには以下が含まれます:
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
新しいモデルをテストして追加するにつれて、モデルのリストは変更される場合があります。
|
||||
|
||||
---
|
||||
|
||||
## 利用制限
|
||||
@@ -147,6 +170,44 @@ Goでは月額$10を支払い、その6倍の利用枠を提供することを
|
||||
|
||||
---
|
||||
|
||||
## エンドポイント
|
||||
|
||||
以下のAPIエンドポイントを通じて、Goモデルにアクセスすることもできます。
|
||||
|
||||
| Model | Model ID | Endpoint | AI SDK Package |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
OpenCode設定の[model id](/docs/config/#models)は、`opencode-go/<model-id>`という形式を使用します。たとえば、Kimi K3の場合は、設定で`opencode-go/kimi-k3`を使用します。
|
||||
|
||||
---
|
||||
|
||||
### モデル
|
||||
|
||||
利用可能なモデルとそのメタデータの完全な一覧は、次から取得できます。
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## プライバシー
|
||||
|
||||
このプランは主に海外ユーザー向けに設計されており、安定したグローバルアクセスのため、モデルは US、EU、Singapore でホストされています。各プロバイダーはデータを保持しないポリシーに従っており、お客様のデータをモデルのトレーニングに使用することはありません。
|
||||
|
||||
@@ -86,18 +86,32 @@ OpenCode で適切に動作することがテストおよび検証されてい
|
||||
|
||||
## OpenCode Go
|
||||
|
||||
OpenCode Go belongs to the named subscriber and is available through OpenCode’s `opencode` provider.
|
||||
OpenCode Go は、OpenCode チームによって提供される、人気のあるオープンコーディングモデルへの信頼性の高いアクセスを提供する低コストのサブスクリプションプランです。これらは OpenCode でうまく機能することがテストおよび検証されています。
|
||||
|
||||
1. [Subscribe in OpenCode Console](https://opencode.ai/console/go).
|
||||
2. Run the Console device login and approve it in your browser.
|
||||
1. TUI で `/connect` コマンドを実行し、`OpenCode Go` を選択して、[opencode.ai/zen](https://opencode.ai/zen) にアクセスします。
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```txt
|
||||
/connect
|
||||
```
|
||||
|
||||
3. Choose a model from the `opencode` provider.
|
||||
2. サインインし、お支払いの詳細を追加し、API キーをコピーします。
|
||||
|
||||
External-agent and service-account support is deferred. No separate Go provider or credential copy is required.
|
||||
3. API キーを貼り付けます。
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
│
|
||||
│
|
||||
└ enter
|
||||
```
|
||||
|
||||
4. TUI で `/models` を実行すると、推奨されるモデルのリストが表示されます。
|
||||
|
||||
```txt
|
||||
/models
|
||||
```
|
||||
|
||||
これは OpenCode の他のプロバイダーと同様に機能し、使用は完全にオプションです。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,11 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
OpenCode Go는 인기 있는 오픈 코딩 모델에 안정적으로 액세스할 수 있게 해주는 저비용 구독 서비스입니다. **첫 달은 $5**, 이후에는 **월 $10**입니다.
|
||||
|
||||
Go는 OpenCode의 다른 제공자와 똑같이 작동합니다. OpenCode Go를 구독하고 API 키를 발급받으면 됩니다. 이는 **완전히 선택 사항**이며, OpenCode를 사용하기 위해 꼭 필요하지는 않습니다.
|
||||
|
||||
주로 해외 사용자를 위해 설계되었으며, 안정적인 전 세계 액세스를 위해 모델은 미국, EU, 싱가포르에 호스팅됩니다.
|
||||
|
||||
---
|
||||
|
||||
@@ -33,18 +37,37 @@ OpenCode Go를 사용하면 **첫 달은 $5**, 이후에는 **월 $10**으로
|
||||
|
||||
## 작동 방식
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
OpenCode Go는 OpenCode의 다른 제공자와 똑같이 작동합니다.
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. **<a href={console}>OpenCode Zen</a>**에 로그인해 Go를 구독하고 API 키를 복사합니다.
|
||||
2. TUI에서 `/connect` 명령을 실행하고 `OpenCode Go`를 선택한 다음 API 키를 붙여넣습니다.
|
||||
3. TUI에서 `/models`를 실행해 Go를 통해 사용할 수 있는 모델 목록을 확인합니다.
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
workspace당 한 명의 멤버만 OpenCode Go를 구독할 수 있습니다.
|
||||
:::
|
||||
|
||||
현재 모델 목록에는 다음이 포함됩니다.
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
새로운 모델을 테스트하고 추가함에 따라 이 목록은 변경될 수 있습니다.
|
||||
|
||||
---
|
||||
|
||||
## 사용 한도
|
||||
@@ -147,6 +170,44 @@ Go에서는 월 $10를 지불하며, 저희는 그 6배의 사용량을 제공
|
||||
|
||||
---
|
||||
|
||||
## 엔드포인트
|
||||
|
||||
다음 API 엔드포인트를 통해서도 Go 모델에 액세스할 수 있습니다.
|
||||
|
||||
| 모델 | 모델 ID | 엔드포인트 | AI SDK 패키지 |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
OpenCode config의 [model id](/docs/config/#models)는 `opencode-go/<model-id>` 형식을 사용합니다. 예를 들어 Kimi K3의 경우 config에서 `opencode-go/kimi-k3`를 사용하면 됩니다.
|
||||
|
||||
---
|
||||
|
||||
### 모델
|
||||
|
||||
사용 가능한 전체 모델 목록과 메타데이터는 다음에서 가져올 수 있습니다.
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 개인정보 보호
|
||||
|
||||
이 플랜은 안정적인 전 세계 액세스를 위해 모델을 미국, EU, 싱가포르에 호스팅하며, 주로 해외 사용자를 위해 설계되었습니다. 저희 제공자는 zero-retention 정책을 따르며, 고객 데이터를 모델 학습에 사용하지 않습니다.
|
||||
|
||||
@@ -84,18 +84,32 @@ OpenCode의 다른 공급자처럼 작동하며 사용은 완전히 선택 사
|
||||
|
||||
## OpenCode Go
|
||||
|
||||
OpenCode Go belongs to the named subscriber and is available through OpenCode’s `opencode` provider.
|
||||
OpenCode Go는 OpenCode 팀이 테스트하고 검증하여 OpenCode와 잘 작동하는 인기 있는 오픈 코딩 모델에 안정적으로 액세스할 수 있는 저렴한 구독 요금제입니다.
|
||||
|
||||
1. [Subscribe in OpenCode Console](https://opencode.ai/console/go).
|
||||
2. Run the Console device login and approve it in your browser.
|
||||
1. TUI에서 `/connect` 명령을 실행하고 `OpenCode Go`를 선택한 뒤 [opencode.ai/auth](https://opencode.ai/zen)로 이동하십시오.
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```txt
|
||||
/connect
|
||||
```
|
||||
|
||||
3. Choose a model from the `opencode` provider.
|
||||
2. 로그인하고 결제 정보를 입력한 후 API 키를 복사하십시오.
|
||||
|
||||
External-agent and service-account support is deferred. No separate Go provider or credential copy is required.
|
||||
3. API 키를 붙여넣습니다.
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
│
|
||||
│
|
||||
└ enter
|
||||
```
|
||||
|
||||
4. TUI에서 `/models`를 실행하여 추천 모델 목록을 볼 수 있습니다.
|
||||
|
||||
```txt
|
||||
/models
|
||||
```
|
||||
|
||||
OpenCode의 다른 공급자처럼 작동하며 사용은 완전히 선택 사항입니다.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,13 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
OpenCode Go er et lavkostnadsabonnement — **$5 for din første måned**, deretter **$10/måned** — som gir deg pålitelig tilgang til populære åpne kodemodeller.
|
||||
|
||||
Go fungerer som enhver annen leverandør i OpenCode. Du abonnerer på OpenCode Go og
|
||||
får din API-nøkkel. Det er **helt valgfritt**, og du trenger ikke å bruke det for å
|
||||
bruke OpenCode.
|
||||
|
||||
Det er primært utformet for internasjonale brukere, med modeller driftet i USA, EU og Singapore for stabil global tilgang.
|
||||
|
||||
---
|
||||
|
||||
@@ -39,18 +45,39 @@ OpenCode Go gir deg tilgang til disse modellene for **$5 for din første måned*
|
||||
|
||||
## Hvordan det fungerer
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
OpenCode Go fungerer som enhver annen leverandør i OpenCode.
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. Du logger inn på **<a href={console}>OpenCode Zen</a>**, abonnerer på Go, og
|
||||
kopierer din API-nøkkel.
|
||||
2. Du kjører kommandoen `/connect` i TUI-en, velger `OpenCode Go`, og limer inn
|
||||
din API-nøkkel.
|
||||
3. Kjør `/models` i TUI-en for å se listen over modeller som er tilgjengelige gjennom Go.
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
Kun ett medlem per arbeidsområde kan abonnere på OpenCode Go.
|
||||
:::
|
||||
|
||||
Den nåværende listen over modeller inkluderer:
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
Listen over modeller kan endres etter hvert som vi tester og legger til nye.
|
||||
|
||||
---
|
||||
|
||||
## Bruksgrenser
|
||||
@@ -155,6 +182,46 @@ For disse modellene får du fortsatt litt mer enn om du betalte modellleverandø
|
||||
|
||||
---
|
||||
|
||||
## Endepunkter
|
||||
|
||||
Du kan også få tilgang til Go-modeller gjennom følgende API-endepunkter.
|
||||
|
||||
| Modell | Modell-ID | Endepunkt | AI SDK Package |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
[Modell-ID-en](/docs/config/#models) i din OpenCode-konfigurasjon
|
||||
bruker formatet `opencode-go/<model-id>`. For eksempel, for Kimi K3, vil du
|
||||
bruke `opencode-go/kimi-k3` i konfigurasjonen din.
|
||||
|
||||
---
|
||||
|
||||
### Modeller
|
||||
|
||||
Du kan hente hele listen over tilgjengelige modeller og metadataene deres fra:
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Personvern
|
||||
|
||||
Planen er primært utformet for internasjonale brukere, med modeller hostet i US, EU og Singapore for stabil global tilgang. Våre leverandører følger en zero-retention-policy og bruker ikke dataene dine til modelltrening.
|
||||
|
||||
@@ -86,18 +86,34 @@ Det fungerer som alle andre leverandører i OpenCode og er helt valgfritt å bru
|
||||
|
||||
## OpenCode Go
|
||||
|
||||
OpenCode Go belongs to the named subscriber and is available through OpenCode’s `opencode` provider.
|
||||
OpenCode Go er en lavpris abonnementsplan som gir pålitelig tilgang til populære åpne kodemodeller levert av OpenCode-teamet som har vært
|
||||
testet og verifisert for å fungere godt med OpenCode.
|
||||
|
||||
1. [Subscribe in OpenCode Console](https://opencode.ai/console/go).
|
||||
2. Run the Console device login and approve it in your browser.
|
||||
1. Kjør kommandoen `/connect` i TUI, velg `OpenCode Go`, og gå til [opencode.ai/auth](https://opencode.ai/zen).
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```txt
|
||||
/connect
|
||||
```
|
||||
|
||||
3. Choose a model from the `opencode` provider.
|
||||
2. Logg på, legg til faktureringsdetaljene dine og kopier API-nøkkelen.
|
||||
|
||||
External-agent and service-account support is deferred. No separate Go provider or credential copy is required.
|
||||
3. Lim inn API-nøkkelen.
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
│
|
||||
│
|
||||
│
|
||||
└ enter
|
||||
```
|
||||
|
||||
4. Kjør `/models` i TUI for å se listen over modeller vi anbefaler.
|
||||
|
||||
```txt
|
||||
/models
|
||||
```
|
||||
|
||||
Det fungerer som alle andre leverandører i OpenCode og er helt valgfritt å bruke.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,13 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
OpenCode Go to niskokosztowa subskrypcja — **5 $ za pierwszy miesiąc**, a następnie **10 $/miesiąc** — która zapewnia niezawodny dostęp do popularnych otwartych modeli do kodowania.
|
||||
|
||||
Go działa jak każdy inny dostawca w OpenCode. Subskrybujesz OpenCode Go i
|
||||
otrzymujesz swój klucz API. Jest to **całkowicie opcjonalne** i nie musisz z tego korzystać, aby
|
||||
używać OpenCode.
|
||||
|
||||
Jest przeznaczony przede wszystkim dla użytkowników międzynarodowych, a modele są hostowane w USA, UE i Singapurze, co zapewnia stabilny globalny dostęp.
|
||||
|
||||
---
|
||||
|
||||
@@ -33,18 +39,39 @@ OpenCode Go daje Ci dostęp do tych modeli za **5 $ za pierwszy miesiąc**, a na
|
||||
|
||||
## Jak to działa
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
OpenCode Go działa jak każdy inny dostawca w OpenCode.
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. Logujesz się do **<a href={console}>OpenCode Zen</a>**, subskrybujesz Go i
|
||||
kopiujesz swój klucz API.
|
||||
2. Uruchamiasz komendę `/connect` w TUI, wybierasz `OpenCode Go` i wklejasz
|
||||
swój klucz API.
|
||||
3. Uruchom `/models` w TUI, aby zobaczyć listę modeli dostępnych w ramach Go.
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
Tylko jeden członek na obszar roboczy (workspace) może zasubskrybować OpenCode Go.
|
||||
:::
|
||||
|
||||
Obecna lista modeli obejmuje:
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
Lista modeli może ulec zmianie w miarę testowania i dodawania nowych.
|
||||
|
||||
---
|
||||
|
||||
## Limity użycia
|
||||
@@ -147,6 +174,46 @@ W przypadku tych modeli nadal otrzymujesz nieco więcej, niż płacąc bezpośre
|
||||
|
||||
---
|
||||
|
||||
## Punkty końcowe
|
||||
|
||||
Możesz również uzyskać dostęp do modeli Go za pośrednictwem następujących punktów końcowych API.
|
||||
|
||||
| Model | ID modelu | Punkt końcowy | Pakiet AI SDK |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
[ID modelu](/docs/config/#models) w Twojej konfiguracji OpenCode
|
||||
używa formatu `opencode-go/<model-id>`. Na przykład dla Kimi K3 należy użyć
|
||||
`opencode-go/kimi-k3` w swojej konfiguracji.
|
||||
|
||||
---
|
||||
|
||||
### Modele
|
||||
|
||||
Pełną listę dostępnych modeli i ich metadane możesz pobrać z:
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Prywatność
|
||||
|
||||
Plan został zaprojektowany przede wszystkim z myślą o użytkownikach międzynarodowych, a modele są hostowane w US, EU i Singapore, aby zapewnić stabilny dostęp na całym świecie. Nasi dostawcy stosują politykę zerowej retencji i nie wykorzystują Twoich danych do trenowania modeli.
|
||||
|
||||
@@ -86,18 +86,32 @@ Działa jak każdy inny dostawca w opencode i jest całkowicie opcjonalny w uży
|
||||
|
||||
## OpenCode Go
|
||||
|
||||
OpenCode Go belongs to the named subscriber and is available through OpenCode’s `opencode` provider.
|
||||
OpenCode Go to tani plan subskrypcji, który zapewnia niezawodny dostęp do popularnych modeli open coding dostarczanych przez zespół opencode, które zostały przetestowane i zweryfikowane pod kątem dobrej współpracy z opencode.
|
||||
|
||||
1. [Subscribe in OpenCode Console](https://opencode.ai/console/go).
|
||||
2. Run the Console device login and approve it in your browser.
|
||||
1. Uruchom polecenie `/connect` w TUI, wybierz `OpenCode Go` i przejdź do [opencode.ai/auth](https://opencode.ai/zen).
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```txt
|
||||
/connect
|
||||
```
|
||||
|
||||
3. Choose a model from the `opencode` provider.
|
||||
2. Zaloguj się, dodaj szczegóły rozliczeniowe i skopiuj klucz API.
|
||||
|
||||
External-agent and service-account support is deferred. No separate Go provider or credential copy is required.
|
||||
3. Wklej swój klucz API.
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
│
|
||||
│
|
||||
└ enter
|
||||
```
|
||||
|
||||
4. Uruchom `/models` w TUI, aby zobaczyć listę zalecanych przez nas modeli.
|
||||
|
||||
```txt
|
||||
/models
|
||||
```
|
||||
|
||||
Działa jak każdy inny dostawca w opencode i jest całkowicie opcjonalny w użyciu.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -125,18 +125,30 @@ It works like any other provider in OpenCode and is completely optional to use.
|
||||
OpenCode Go is a low cost subscription plan that provides reliable access to popular open coding models provided by the OpenCode team that have been
|
||||
tested and verified to work well with OpenCode.
|
||||
|
||||
1. [Subscribe to Go in OpenCode Console](https://opencode.ai/console/go).
|
||||
1. Run the `/connect` command in the TUI, select `OpenCode Go`, and head to [opencode.ai/auth](https://opencode.ai/zen).
|
||||
|
||||
2. Run the Console device login and authorize it in your browser.
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```txt
|
||||
/connect
|
||||
```
|
||||
|
||||
3. Choose a model from the `opencode` provider.
|
||||
2. Sign in, add your billing details, and copy your API key.
|
||||
|
||||
Go belongs to the named subscriber and works only through OpenCode's `opencode` provider. Do not copy an API key.
|
||||
Service accounts can use ordinary managed inference, but they are not eligible for Go.
|
||||
3. Paste your API key.
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
│
|
||||
│
|
||||
└ enter
|
||||
```
|
||||
|
||||
4. Run `/models` in the TUI to see the list of models we recommend.
|
||||
|
||||
```txt
|
||||
/models
|
||||
```
|
||||
|
||||
It works like any other provider in OpenCode and is completely optional to use.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,13 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
O OpenCode Go é uma assinatura de baixo custo — **US$ 5 no seu primeiro mês**, depois **US$ 10/mês** — que oferece acesso confiável a modelos abertos de programação populares.
|
||||
|
||||
O Go funciona como qualquer outro provedor no OpenCode. Você assina o OpenCode Go e
|
||||
obtém a sua chave de API. Ele é **totalmente opcional** e você não precisa usá-lo para
|
||||
usar o OpenCode.
|
||||
|
||||
Ele foi projetado principalmente para usuários internacionais, com modelos hospedados nos EUA, na UE e em Singapura para um acesso global estável.
|
||||
|
||||
---
|
||||
|
||||
@@ -39,18 +45,39 @@ O OpenCode Go lhe dá acesso a esses modelos por **US$ 5 no seu primeiro mês**,
|
||||
|
||||
## Como funciona
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
O OpenCode Go funciona como qualquer outro provedor no OpenCode.
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. Você entra no **<a href={console}>OpenCode Zen</a>**, assina o Go e
|
||||
copia a sua chave de API.
|
||||
2. Você executa o comando `/connect` na TUI, seleciona `OpenCode Go` e cola
|
||||
a sua chave de API.
|
||||
3. Execute `/models` na TUI para ver a lista de modelos disponíveis através do Go.
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
Apenas um membro por workspace pode assinar o OpenCode Go.
|
||||
:::
|
||||
|
||||
A lista atual de modelos inclui:
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
A lista de modelos pode mudar conforme testamos e adicionamos novos.
|
||||
|
||||
---
|
||||
|
||||
## Limites de uso
|
||||
@@ -155,6 +182,46 @@ Para esses modelos, você ainda recebe um pouco mais do que receberia se pagasse
|
||||
|
||||
---
|
||||
|
||||
## Endpoints
|
||||
|
||||
Você também pode acessar os modelos do Go através dos seguintes endpoints de API.
|
||||
|
||||
| Modelo | ID do Modelo | Endpoint | Pacote do AI SDK |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
O [ID do modelo](/docs/config/#models) na sua configuração do OpenCode
|
||||
usa o formato `opencode-go/<model-id>`. Por exemplo, para o Kimi K3, você usaria
|
||||
`opencode-go/kimi-k3` na sua configuração.
|
||||
|
||||
---
|
||||
|
||||
### Modelos
|
||||
|
||||
Você pode buscar a lista completa de modelos disponíveis e seus metadados em:
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Privacidade
|
||||
|
||||
O plano foi projetado principalmente para usuários internacionais, com modelos hospedados em US, EU e Singapore para garantir acesso global estável. Nossos provedores seguem uma política de retenção zero e não usam seus dados para treinamento de modelos.
|
||||
|
||||
@@ -83,18 +83,33 @@ Funciona como qualquer outro provedor no opencode e é completamente opcional.
|
||||
|
||||
## OpenCode Go
|
||||
|
||||
OpenCode Go belongs to the named subscriber and is available through OpenCode’s `opencode` provider.
|
||||
OpenCode Go é um plano de assinatura de baixo custo que fornece acesso confiável a modelos de codificação abertos populares fornecidos pela equipe do opencode que foram
|
||||
testados e verificados para funcionar bem com o opencode.
|
||||
|
||||
1. [Subscribe in OpenCode Console](https://opencode.ai/console/go).
|
||||
2. Run the Console device login and approve it in your browser.
|
||||
1. Execute o comando `/connect` no TUI, selecione `OpenCode Go` e acesse [opencode.ai/zen](https://opencode.ai/zen).
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```txt
|
||||
/connect
|
||||
```
|
||||
|
||||
3. Choose a model from the `opencode` provider.
|
||||
2. Faça login, adicione seus dados de cobrança e copie sua chave da API.
|
||||
|
||||
External-agent and service-account support is deferred. No separate Go provider or credential copy is required.
|
||||
3. Cole sua chave da API.
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
│
|
||||
│
|
||||
└ enter
|
||||
```
|
||||
|
||||
4. Execute `/models` no TUI para ver a lista de modelos que recomendamos.
|
||||
|
||||
```txt
|
||||
/models
|
||||
```
|
||||
|
||||
Funciona como qualquer outro provedor no opencode e é completamente opcional.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,13 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
OpenCode Go — это недорогая подписка (**$5 за первый месяц**, далее **$10 в месяц**), которая предоставляет надежный доступ к популярным открытым моделям для программирования.
|
||||
|
||||
Go работает так же, как и любой другой провайдер в OpenCode. Вы оформляете подписку на OpenCode Go и
|
||||
получаете свой API-ключ. Использование Go **абсолютно необязательно**, и вам не нужно использовать его, чтобы
|
||||
пользоваться OpenCode.
|
||||
|
||||
Она предназначена в первую очередь для пользователей со всего мира, а модели размещены в США, ЕС и Сингапуре для стабильного глобального доступа.
|
||||
|
||||
---
|
||||
|
||||
@@ -39,18 +45,39 @@ OpenCode Go дает вам доступ к этим моделям за **$5 в
|
||||
|
||||
## Как это работает
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
OpenCode Go работает так же, как и любой другой провайдер в OpenCode.
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. Вы входите в **<a href={console}>OpenCode Zen</a>**, подписываетесь на Go и
|
||||
копируете свой API-ключ.
|
||||
2. Вы выполняете команду `/connect` в TUI, выбираете `OpenCode Go` и вставляете
|
||||
свой API-ключ.
|
||||
3. Запустите `/models` в TUI, чтобы увидеть список моделей, доступных через Go.
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
Только один участник рабочего пространства может подписаться на OpenCode Go.
|
||||
:::
|
||||
|
||||
Текущий список моделей включает:
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
Список моделей может меняться по мере того, как мы тестируем и добавляем новые.
|
||||
|
||||
---
|
||||
|
||||
## Лимиты использования
|
||||
@@ -155,6 +182,46 @@ OpenCode Go включает следующие лимиты:
|
||||
|
||||
---
|
||||
|
||||
## Эндпоинты
|
||||
|
||||
Вы также можете получить доступ к моделям Go через следующие API-эндпоинты.
|
||||
|
||||
| Модель | ID модели | Эндпоинт | Пакет AI SDK |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
[ID модели](/docs/config/#models) в вашем конфиге OpenCode
|
||||
использует формат `opencode-go/<model-id>`. Например, для Kimi K3 вам нужно
|
||||
использовать `opencode-go/kimi-k3` в вашем конфиге.
|
||||
|
||||
---
|
||||
|
||||
### Модели
|
||||
|
||||
Вы можете получить полный список доступных моделей и их метаданных по адресу:
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Конфиденциальность
|
||||
|
||||
Этот план разработан в первую очередь для международных пользователей: модели размещены в US, EU и Singapore, чтобы обеспечить стабильный доступ по всему миру. Наши провайдеры придерживаются политики zero-retention и не используют ваши данные для обучения моделей.
|
||||
|
||||
@@ -86,18 +86,33 @@ OpenCode Zen — это список моделей, предоставленн
|
||||
|
||||
## OpenCode Go
|
||||
|
||||
OpenCode Go belongs to the named subscriber and is available through OpenCode’s `opencode` provider.
|
||||
OpenCode Go — это недорогой план подписки, обеспечивающий надежный доступ к популярным открытым моделям кодирования, предоставляемым командой opencode, которые были
|
||||
протестированы и проверены на хорошую работу с opencode.
|
||||
|
||||
1. [Subscribe in OpenCode Console](https://opencode.ai/console/go).
|
||||
2. Run the Console device login and approve it in your browser.
|
||||
1. Запустите команду `/connect` в TUI, выберите `OpenCode Go` и перейдите по адресу [opencode.ai/auth](https://opencode.ai/zen).
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```txt
|
||||
/connect
|
||||
```
|
||||
|
||||
3. Choose a model from the `opencode` provider.
|
||||
2. Войдите в систему, добавьте свои платежные данные и скопируйте ключ API.
|
||||
|
||||
External-agent and service-account support is deferred. No separate Go provider or credential copy is required.
|
||||
3. Вставьте свой ключ API.
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
│
|
||||
│
|
||||
└ enter
|
||||
```
|
||||
|
||||
4. Запустите `/models` в TUI, чтобы просмотреть список рекомендуемых нами моделей.
|
||||
|
||||
```txt
|
||||
/models
|
||||
```
|
||||
|
||||
Он работает как любой другой поставщик в opencode и его использование совершенно необязательно.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,11 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
OpenCode Go คือการสมัครสมาชิกในราคาประหยัด — **$5 สำหรับเดือนแรก** จากนั้น **$10/เดือน** — ซึ่งให้คุณเข้าถึงโมเดลโอเพนซอร์สยอดนิยมสำหรับการเขียนโค้ดได้อย่างเสถียร
|
||||
|
||||
Go ทำงานเหมือนกับผู้ให้บริการ (provider) รายอื่นๆ ใน OpenCode คุณสามารถสมัครสมาชิก OpenCode Go และรับ API key ของคุณ บริการนี้เป็น**ทางเลือกเพิ่มเติม** และคุณไม่จำเป็นต้องใช้มันเพื่อใช้งาน OpenCode
|
||||
|
||||
บริการนี้ออกแบบมาเพื่อผู้ใช้ในระดับสากลเป็นหลัก โดยมีโมเดลโฮสต์อยู่ในสหรัฐอเมริกา สหภาพยุโรป และสิงคโปร์ เพื่อการเข้าถึงทั่วโลกที่เสถียร
|
||||
|
||||
---
|
||||
|
||||
@@ -33,18 +37,37 @@ OpenCode Go ให้คุณเข้าถึงโมเดลเหล่
|
||||
|
||||
## How it works
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
OpenCode Go ทำงานเหมือนกับผู้ให้บริการรายอื่นๆ ใน OpenCode
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. ลงชื่อเข้าใช้ที่ **<a href={console}>OpenCode Zen</a>**, สมัครสมาชิก Go และคัดลอก API key ของคุณ
|
||||
2. รันคำสั่ง `/connect` ใน TUI, เลือก `OpenCode Go`, และวาง API key ของคุณ
|
||||
3. รัน `/models` ใน TUI เพื่อดูรายชื่อโมเดลที่ใช้งานได้ผ่าน Go
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
มีเพียงสมาชิกหนึ่งคนต่อ workspace เท่านั้นที่สามารถสมัครสมาชิก OpenCode Go ได้
|
||||
:::
|
||||
|
||||
รายชื่อโมเดลในปัจจุบันประกอบด้วย:
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
รายชื่อโมเดลอาจมีการเปลี่ยนแปลงเมื่อเราทำการทดสอบและเพิ่มโมเดลใหม่ๆ
|
||||
|
||||
---
|
||||
|
||||
## Usage limits
|
||||
@@ -147,6 +170,44 @@ OpenCode Go มีขีดจำกัดดังต่อไปนี้:
|
||||
|
||||
---
|
||||
|
||||
## Endpoints
|
||||
|
||||
คุณสามารถเข้าถึงโมเดลของ Go ผ่าน API endpoints ต่อไปนี้ได้เช่นกัน
|
||||
|
||||
| Model | Model ID | Endpoint | AI SDK Package |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
[model id](/docs/config/#models) ใน OpenCode config ของคุณจะใช้รูปแบบ `opencode-go/<model-id>` ตัวอย่างเช่น สำหรับ Kimi K3 คุณจะใช้ `opencode-go/kimi-k3` ใน config ของคุณ
|
||||
|
||||
---
|
||||
|
||||
### Models
|
||||
|
||||
คุณสามารถดึงรายการโมเดลทั้งหมดที่พร้อมใช้งานและ metadata ของมันได้จาก:
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Privacy
|
||||
|
||||
แพลนนี้ออกแบบมาสำหรับผู้ใช้ทั่วโลกเป็นหลัก โดยโฮสต์โมเดลไว้ใน US, EU และ Singapore เพื่อให้เข้าถึงได้อย่างเสถียรจากทั่วโลก ผู้ให้บริการของเราปฏิบัติตามนโยบาย zero-retention และไม่นำข้อมูลของคุณไปใช้ในการฝึกโมเดล
|
||||
|
||||
@@ -86,18 +86,32 @@ OpenCode Zen คือรายชื่อโมเดลที่จัดท
|
||||
|
||||
## OpenCode Go
|
||||
|
||||
OpenCode Go belongs to the named subscriber and is available through OpenCode’s `opencode` provider.
|
||||
OpenCode Go คือแผนการสมัครสมาชิกราคาประหยัดที่ให้การเข้าถึงโมเดลการเขียนโค้ดแบบเปิดยอดนิยมที่เชื่อถือได้ ซึ่งจัดเตรียมโดยทีมงาน OpenCode ที่ได้รับการทดสอบและตรวจสอบแล้วว่าทำงานได้ดีกับ OpenCode
|
||||
|
||||
1. [Subscribe in OpenCode Console](https://opencode.ai/console/go).
|
||||
2. Run the Console device login and approve it in your browser.
|
||||
1. เรียกใช้คำสั่ง `/connect` ใน TUI เลือก `OpenCode Go` และไปที่ [opencode.ai/auth](https://opencode.ai/zen)
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```txt
|
||||
/connect
|
||||
```
|
||||
|
||||
3. Choose a model from the `opencode` provider.
|
||||
2. ลงชื่อเข้าใช้ เพิ่มรายละเอียดการเรียกเก็บเงินของคุณ และคัดลอกรหัส API ของคุณ
|
||||
|
||||
External-agent and service-account support is deferred. No separate Go provider or credential copy is required.
|
||||
3. วางคีย์ API ของคุณ
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
│
|
||||
│
|
||||
└ enter
|
||||
```
|
||||
|
||||
4. เรียกใช้ `/models` ใน TUI เพื่อดูรายการรุ่นที่เราแนะนำ
|
||||
|
||||
```txt
|
||||
/models
|
||||
```
|
||||
|
||||
มันทำงานเหมือนกับผู้ให้บริการรายอื่นใน OpenCode และเป็นทางเลือกในการใช้งานโดยสมบูรณ์
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,11 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
OpenCode Go, popüler açık kodlama modellerine güvenilir erişim sağlayan düşük maliyetli bir aboneliktir — **ilk ayınız için 5$**, sonrasında **aylık 10$**.
|
||||
|
||||
Go, OpenCode'daki diğer sağlayıcılar gibi çalışır. OpenCode Go'ya abone olur ve API anahtarınızı alırsınız. Bu **tamamen isteğe bağlıdır** ve OpenCode'u kullanmak için bunu kullanmanıza gerek yoktur.
|
||||
|
||||
Dünya çapında istikrarlı erişim için ABD, AB ve Singapur'da barındırılan modellerle temel olarak uluslararası kullanıcılar için tasarlanmıştır.
|
||||
|
||||
---
|
||||
|
||||
@@ -33,18 +37,37 @@ OpenCode Go, bu modellere **ilk ayınız için 5$**, ardından **aylık 10$** ka
|
||||
|
||||
## Nasıl çalışır?
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
OpenCode Go, OpenCode'daki diğer sağlayıcılar gibi çalışır.
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. **<a href={console}>OpenCode Zen</a>**'e giriş yapın, Go'ya abone olun ve API anahtarınızı kopyalayın.
|
||||
2. TUI'de `/connect` komutunu çalıştırın, `OpenCode Go`yu seçin ve API anahtarınızı yapıştırın.
|
||||
3. Go üzerinden kullanabileceğiniz modellerin listesini görmek için TUI'de `/models` komutunu çalıştırın.
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
Her çalışma alanından yalnızca bir üye OpenCode Go'ya abone olabilir.
|
||||
:::
|
||||
|
||||
Mevcut model listesi şunları içerir:
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
Test edip yenilerini ekledikçe model listesi değişebilir.
|
||||
|
||||
---
|
||||
|
||||
## Kullanım limitleri
|
||||
@@ -147,6 +170,44 @@ Bu modellerde bile model sağlayıcılarına doğrudan ödeme yaptığınız dur
|
||||
|
||||
---
|
||||
|
||||
## Uç Noktalar
|
||||
|
||||
Go modellerine aşağıdaki API uç noktaları aracılığıyla da erişebilirsiniz.
|
||||
|
||||
| Model | Model ID | Uç Nokta | AI SDK Paketi |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
OpenCode yapılandırmanızdaki [model id](/docs/config/#models) formatı `opencode-go/<model-id>` şeklindedir. Örneğin, Kimi K3 için yapılandırmanızda `opencode-go/kimi-k3` kullanmalısınız.
|
||||
|
||||
---
|
||||
|
||||
### Modeller
|
||||
|
||||
Mevcut modellerin tam listesini ve metadata'larını şuradan alabilirsiniz:
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Gizlilik
|
||||
|
||||
Plan, öncelikle uluslararası kullanıcılar için tasarlanmıştır; dünya genelinde istikrarlı erişim sağlamak için modeller US, EU ve Singapore'da barındırılır. Sağlayıcılarımız sıfır veri saklama politikası uygular ve verilerinizi model eğitimi için kullanmaz.
|
||||
|
||||
@@ -86,18 +86,32 @@ opencode'daki diğer sağlayıcılar gibi çalışır ve kullanımı tamamen ist
|
||||
|
||||
## OpenCode Go
|
||||
|
||||
OpenCode Go belongs to the named subscriber and is available through OpenCode’s `opencode` provider.
|
||||
OpenCode Go, opencode ile iyi çalıştığı test edilmiş ve doğrulanmış, opencode ekibi tarafından sağlanan popüler açık kodlama modellerine güvenilir erişim sağlayan düşük maliyetli bir abonelik planıdır.
|
||||
|
||||
1. [Subscribe in OpenCode Console](https://opencode.ai/console/go).
|
||||
2. Run the Console device login and approve it in your browser.
|
||||
1. TUI'de `/connect` komutunu çalıştırın, `OpenCode Go`'yu seçin ve [opencode.ai/auth](https://opencode.ai/zen) adresine gidin.
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```txt
|
||||
/connect
|
||||
```
|
||||
|
||||
3. Choose a model from the `opencode` provider.
|
||||
2. Oturum açın, fatura ayrıntılarınızı ekleyin ve API anahtarınızı kopyalayın.
|
||||
|
||||
External-agent and service-account support is deferred. No separate Go provider or credential copy is required.
|
||||
3. API anahtarınızı yapıştırın.
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
│
|
||||
│
|
||||
└ enter
|
||||
```
|
||||
|
||||
4. Önerdiğimiz modellerin listesini görmek için TUI'de `/models` komutunu çalıştırın.
|
||||
|
||||
```txt
|
||||
/models
|
||||
```
|
||||
|
||||
opencode'daki diğer sağlayıcılar gibi çalışır ve kullanımı tamamen isteğe bağlıdır.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,11 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
OpenCode Go 是一项低成本的订阅服务 —— **首月 5 美元**,之后 **每月 10 美元** —— 让你能够稳定地访问流行的开源编程模型。
|
||||
|
||||
Go 的工作方式与 OpenCode 中的任何其他提供商(provider)一样。订阅 OpenCode Go 后你将获得 API 密钥。它是 **完全可选** 的,并非使用 OpenCode 所必需的条件。
|
||||
|
||||
它主要为国际用户设计,模型托管在美国、欧盟和新加坡,以确保稳定的全球访问。
|
||||
|
||||
---
|
||||
|
||||
@@ -33,18 +37,37 @@ OpenCode Go 让你能够访问这些模型,**首月只需 5 美元**,之后
|
||||
|
||||
## 工作原理
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
OpenCode Go 的工作方式与 OpenCode 中的其他提供商一样。
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. 登录 **<a href={console}>OpenCode Zen</a>**,订阅 Go,然后复制你的 API 密钥。
|
||||
2. 在 TUI 中运行 `/connect` 命令,选择 `OpenCode Go`,然后粘贴你的 API 密钥。
|
||||
3. 在 TUI 中运行 `/models` 以查看通过 Go 可用的模型列表。
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
每个工作空间只能有一名成员订阅 OpenCode Go。
|
||||
:::
|
||||
|
||||
当前支持的模型列表包括:
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
随着我们进行测试和添加新模型,该列表可能会发生变化。
|
||||
|
||||
---
|
||||
|
||||
## 使用限制
|
||||
@@ -147,6 +170,44 @@ OpenCode Go 包含以下限制:
|
||||
|
||||
---
|
||||
|
||||
## API 端点
|
||||
|
||||
你也可以通过以下 API 端点访问 Go 模型。
|
||||
|
||||
| 模型 | 模型 ID | 端点 | AI SDK 包 |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
你的 OpenCode 配置中的 [模型 ID](/docs/config/#models) 使用 `opencode-go/<model-id>` 格式。例如,对于 Kimi K3,你将在配置中使用 `opencode-go/kimi-k3`。
|
||||
|
||||
---
|
||||
|
||||
### 模型
|
||||
|
||||
你可以从以下地址获取可用模型及其元数据的完整列表:
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 隐私保护
|
||||
|
||||
该方案主要面向国际用户,模型托管在 US、EU 和 Singapore,以提供稳定的全球访问。我们的提供商遵循零保留政策,不会将您的数据用于模型训练。
|
||||
|
||||
@@ -7,7 +7,11 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Go access belongs to the named subscriber and is available only through OpenCode’s `opencode` provider. External-agent and service-account support is deferred.
|
||||
OpenCode Go 是一項低成本的訂閱服務——**首月 $5 美元**,之後**每月 $10 美元**——讓您能穩定使用受歡迎的開源寫程式模型。
|
||||
|
||||
Go 的運作方式與 OpenCode 中的任何其他供應商相同。您訂閱 OpenCode Go 並取得您的 API key。這是**完全可選的**,您不需要使用它也能使用 OpenCode。
|
||||
|
||||
它主要為國際使用者設計,模型託管於美國、歐盟和新加坡,以提供全球穩定的存取。
|
||||
|
||||
---
|
||||
|
||||
@@ -33,18 +37,37 @@ OpenCode Go 讓您可以存取這些模型,**首月只需 $5 美元**,之後
|
||||
|
||||
## 運作方式
|
||||
|
||||
Subscribe in [OpenCode Console](https://opencode.ai/console/go), then connect OpenCode:
|
||||
OpenCode Go 的運作方式與 OpenCode 中的任何其他供應商相同。
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```
|
||||
|
||||
Approve the device in your browser. OpenCode loads the models into the `opencode` provider; no separate Go provider or credential copy is required.
|
||||
1. 您登入 **<a href={console}>OpenCode Zen</a>**,訂閱 Go,然後複製您的 API key。
|
||||
2. 您在 TUI 中執行 `/connect` 命令,選擇 `OpenCode Go`,然後貼上您的 API key。
|
||||
3. 在 TUI 中執行 `/models` 即可查看透過 Go 可用的模型清單。
|
||||
|
||||
:::note
|
||||
External-agent and service-account support is deferred.
|
||||
每個工作區只能有一位成員訂閱 OpenCode Go。
|
||||
:::
|
||||
|
||||
目前的模型清單包括:
|
||||
|
||||
- **Grok 4.5**
|
||||
- **GLM-5.2**
|
||||
- **GLM-5.1**
|
||||
- **Kimi K3**
|
||||
- **Kimi K2.7 Code**
|
||||
- **Kimi K2.6**
|
||||
- **MiMo-V2.5**
|
||||
- **MiMo-V2.5-Pro**
|
||||
- **MiniMax M3**
|
||||
- **MiniMax M2.7**
|
||||
- **Qwen3.7 Max**
|
||||
- **Qwen3.7 Plus**
|
||||
- **Qwen3.6 Plus**
|
||||
- **DeepSeek V4 Pro**
|
||||
- **DeepSeek V4 Flash**
|
||||
- **Hy3**
|
||||
|
||||
隨著我們測試並加入新模型,模型清單可能會有所變動。
|
||||
|
||||
---
|
||||
|
||||
## 使用限制
|
||||
@@ -147,6 +170,44 @@ OpenCode Go 包含以下限制:
|
||||
|
||||
---
|
||||
|
||||
## 端點
|
||||
|
||||
您也可以透過以下 API 端點存取 Go 模型。
|
||||
|
||||
| 模型 | 模型 ID | 端點 | AI SDK 套件 |
|
||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K3 | kimi-k3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.7 Code | kimi-k2.7-code | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5 | mimo-v2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
| MiniMax M3 | minimax-m3 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| 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.7 Plus | qwen3.7-plus | `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` |
|
||||
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
|
||||
您的 OpenCode 設定中的 [model id](/docs/config/#models) 使用 `opencode-go/<model-id>` 格式。例如,Kimi K3 在設定中應使用 `opencode-go/kimi-k3`。
|
||||
|
||||
---
|
||||
|
||||
### 模型
|
||||
|
||||
你可以從以下位置取得所有可用模型及其中繼資料的完整清單:
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/go/v1/models
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 隱私權
|
||||
|
||||
此方案主要為國際使用者設計,模型部署於 US、EU 與 Singapore,以提供穩定的全球存取體驗。我們的供應商遵循零保留政策,不會將你的資料用於模型訓練。
|
||||
|
||||
@@ -84,18 +84,32 @@ OpenCode Zen 是由 OpenCode 團隊提供的模型列表,這些模型已經過
|
||||
|
||||
## OpenCode Go
|
||||
|
||||
OpenCode Go belongs to the named subscriber and is available through OpenCode’s `opencode` provider.
|
||||
OpenCode Go 是一個低成本的訂閱計畫,提供對 OpenCode 團隊提供的流行開放編碼模型的可靠存取,這些模型已經過測試和驗證,能夠與 OpenCode 良好配合使用。
|
||||
|
||||
1. [Subscribe in OpenCode Console](https://opencode.ai/console/go).
|
||||
2. Run the Console device login and approve it in your browser.
|
||||
1. 在 TUI 中執行 `/connect` 指令,選擇 `OpenCode Go`,然後前往 [opencode.ai/auth](https://opencode.ai/zen)。
|
||||
|
||||
```bash
|
||||
opencode2 console login
|
||||
```txt
|
||||
/connect
|
||||
```
|
||||
|
||||
3. Choose a model from the `opencode` provider.
|
||||
2. 登入後新增帳單資訊,然後複製您的 API 金鑰。
|
||||
|
||||
External-agent and service-account support is deferred. No separate Go provider or credential copy is required.
|
||||
3. 貼上您的 API 金鑰。
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
│
|
||||
│
|
||||
└ enter
|
||||
```
|
||||
|
||||
4. 在 TUI 中執行 `/models` 查看我們推薦的模型列表。
|
||||
|
||||
```txt
|
||||
/models
|
||||
```
|
||||
|
||||
它的使用方式與 OpenCode 中的任何其他提供商相同,且完全可選。
|
||||
|
||||
---
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user