Merge branch 'dev' into add-model-reconciliation
commit
d95fd77861
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
description: Translate content for a specified locale while preserving technical terms
|
description: Translate content for a specified locale while preserving technical terms
|
||||||
mode: subagent
|
mode: subagent
|
||||||
model: opencode/gemini-3-pro
|
model: opencode/gemini-3.1-pro
|
||||||
---
|
---
|
||||||
|
|
||||||
You are a professional translator and localization specialist.
|
You are a professional translator and localization specialist.
|
||||||
|
|
|
||||||
21
bun.lock
21
bun.lock
|
|
@ -46,7 +46,7 @@
|
||||||
"@solidjs/router": "catalog:",
|
"@solidjs/router": "catalog:",
|
||||||
"@thisbeyond/solid-dnd": "0.7.5",
|
"@thisbeyond/solid-dnd": "0.7.5",
|
||||||
"diff": "catalog:",
|
"diff": "catalog:",
|
||||||
"effect": "4.0.0-beta.31",
|
"effect": "catalog:",
|
||||||
"fuzzysort": "catalog:",
|
"fuzzysort": "catalog:",
|
||||||
"ghostty-web": "github:anomalyco/ghostty-web#main",
|
"ghostty-web": "github:anomalyco/ghostty-web#main",
|
||||||
"luxon": "catalog:",
|
"luxon": "catalog:",
|
||||||
|
|
@ -227,7 +227,7 @@
|
||||||
"@solid-primitives/storage": "catalog:",
|
"@solid-primitives/storage": "catalog:",
|
||||||
"@solidjs/meta": "catalog:",
|
"@solidjs/meta": "catalog:",
|
||||||
"@solidjs/router": "0.15.4",
|
"@solidjs/router": "0.15.4",
|
||||||
"effect": "4.0.0-beta.31",
|
"effect": "catalog:",
|
||||||
"electron-log": "^5",
|
"electron-log": "^5",
|
||||||
"electron-store": "^10",
|
"electron-store": "^10",
|
||||||
"electron-updater": "^6",
|
"electron-updater": "^6",
|
||||||
|
|
@ -324,7 +324,7 @@
|
||||||
"@ai-sdk/xai": "2.0.51",
|
"@ai-sdk/xai": "2.0.51",
|
||||||
"@aws-sdk/credential-providers": "3.993.0",
|
"@aws-sdk/credential-providers": "3.993.0",
|
||||||
"@clack/prompts": "1.0.0-alpha.1",
|
"@clack/prompts": "1.0.0-alpha.1",
|
||||||
"@effect/platform-node": "4.0.0-beta.31",
|
"@effect/platform-node": "catalog:",
|
||||||
"@gitlab/gitlab-ai-provider": "3.6.0",
|
"@gitlab/gitlab-ai-provider": "3.6.0",
|
||||||
"@gitlab/opencode-gitlab-auth": "1.3.3",
|
"@gitlab/opencode-gitlab-auth": "1.3.3",
|
||||||
"@hono/standard-validator": "0.1.5",
|
"@hono/standard-validator": "0.1.5",
|
||||||
|
|
@ -352,6 +352,7 @@
|
||||||
"bun-pty": "0.4.8",
|
"bun-pty": "0.4.8",
|
||||||
"chokidar": "4.0.3",
|
"chokidar": "4.0.3",
|
||||||
"clipboardy": "4.0.0",
|
"clipboardy": "4.0.0",
|
||||||
|
"cross-spawn": "^7.0.6",
|
||||||
"decimal.js": "10.5.0",
|
"decimal.js": "10.5.0",
|
||||||
"diff": "catalog:",
|
"diff": "catalog:",
|
||||||
"drizzle-orm": "1.0.0-beta.16-ea816b6",
|
"drizzle-orm": "1.0.0-beta.16-ea816b6",
|
||||||
|
|
@ -401,6 +402,7 @@
|
||||||
"@tsconfig/bun": "catalog:",
|
"@tsconfig/bun": "catalog:",
|
||||||
"@types/babel__core": "7.20.5",
|
"@types/babel__core": "7.20.5",
|
||||||
"@types/bun": "catalog:",
|
"@types/bun": "catalog:",
|
||||||
|
"@types/cross-spawn": "6.0.6",
|
||||||
"@types/mime-types": "3.0.1",
|
"@types/mime-types": "3.0.1",
|
||||||
"@types/semver": "^7.5.8",
|
"@types/semver": "^7.5.8",
|
||||||
"@types/turndown": "5.0.5",
|
"@types/turndown": "5.0.5",
|
||||||
|
|
@ -592,6 +594,7 @@
|
||||||
},
|
},
|
||||||
"catalog": {
|
"catalog": {
|
||||||
"@cloudflare/workers-types": "4.20251008.0",
|
"@cloudflare/workers-types": "4.20251008.0",
|
||||||
|
"@effect/platform-node": "4.0.0-beta.35",
|
||||||
"@hono/zod-validator": "0.4.2",
|
"@hono/zod-validator": "0.4.2",
|
||||||
"@kobalte/core": "0.13.11",
|
"@kobalte/core": "0.13.11",
|
||||||
"@octokit/rest": "22.0.0",
|
"@octokit/rest": "22.0.0",
|
||||||
|
|
@ -615,7 +618,7 @@
|
||||||
"dompurify": "3.3.1",
|
"dompurify": "3.3.1",
|
||||||
"drizzle-kit": "1.0.0-beta.16-ea816b6",
|
"drizzle-kit": "1.0.0-beta.16-ea816b6",
|
||||||
"drizzle-orm": "1.0.0-beta.16-ea816b6",
|
"drizzle-orm": "1.0.0-beta.16-ea816b6",
|
||||||
"effect": "4.0.0-beta.31",
|
"effect": "4.0.0-beta.35",
|
||||||
"fuzzysort": "3.1.0",
|
"fuzzysort": "3.1.0",
|
||||||
"hono": "4.10.7",
|
"hono": "4.10.7",
|
||||||
"hono-openapi": "1.1.2",
|
"hono-openapi": "1.1.2",
|
||||||
|
|
@ -973,9 +976,9 @@
|
||||||
|
|
||||||
"@effect/language-service": ["@effect/language-service@0.79.0", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-DEmIOsg1GjjP6s9HXH1oJrW+gDmzkhVv9WOZl6to5eNyyCrjz1S2PDqQ7aYrW/HuifhfwI5Bik1pK4pj7Z+lrg=="],
|
"@effect/language-service": ["@effect/language-service@0.79.0", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-DEmIOsg1GjjP6s9HXH1oJrW+gDmzkhVv9WOZl6to5eNyyCrjz1S2PDqQ7aYrW/HuifhfwI5Bik1pK4pj7Z+lrg=="],
|
||||||
|
|
||||||
"@effect/platform-node": ["@effect/platform-node@4.0.0-beta.31", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-beta.31", "mime": "^4.1.0", "undici": "^7.20.0" }, "peerDependencies": { "effect": "^4.0.0-beta.31", "ioredis": "^5.7.0" } }, "sha512-KmVZwGsQRBMZZYPJwpL2vj6sxjBzfXhyA8RgsH5/cmckDTsZpVTyqODQ/FFzmCnMWuYjZoJGPghTDrVVDn/6ZA=="],
|
"@effect/platform-node": ["@effect/platform-node@4.0.0-beta.35", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-beta.35", "mime": "^4.1.0", "undici": "^7.24.0" }, "peerDependencies": { "effect": "^4.0.0-beta.35", "ioredis": "^5.7.0" } }, "sha512-HPc2xZASl9F9y/xJ01bQgFD6Jf9XP4Fcv/BlVTvG0Yr/uN63lwKZYr/VXor5K5krHfBDeCBD8y7/SICPYZoq3A=="],
|
||||||
|
|
||||||
"@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-beta.33", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.19.0" }, "peerDependencies": { "effect": "^4.0.0-beta.33" } }, "sha512-jaJnvYz1IiPZyN//fCJsvwnmujJS5KD8noCVVLhb4ZGCWKhQpt0x2iuax6HFzMlPEQSfl04GLU+PVKh0nkzPyA=="],
|
"@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-beta.35", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.19.0" }, "peerDependencies": { "effect": "^4.0.0-beta.35" } }, "sha512-9bPqNV988itKJ7MQoJuzmR014DB9EZRDOnhJt/+iJlb8qLoR9HnCzNJb9gfBdYhFmVYc8DMsQxG81rdJzpv9tg=="],
|
||||||
|
|
||||||
"@electron/asar": ["@electron/asar@3.4.1", "", { "dependencies": { "commander": "^5.0.0", "glob": "^7.1.6", "minimatch": "^3.0.4" }, "bin": { "asar": "bin/asar.js" } }, "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA=="],
|
"@electron/asar": ["@electron/asar@3.4.1", "", { "dependencies": { "commander": "^5.0.0", "glob": "^7.1.6", "minimatch": "^3.0.4" }, "bin": { "asar": "bin/asar.js" } }, "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA=="],
|
||||||
|
|
||||||
|
|
@ -2059,6 +2062,8 @@
|
||||||
|
|
||||||
"@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="],
|
"@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="],
|
||||||
|
|
||||||
|
"@types/cross-spawn": ["@types/cross-spawn@6.0.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA=="],
|
||||||
|
|
||||||
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
|
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
|
||||||
|
|
||||||
"@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="],
|
"@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="],
|
||||||
|
|
@ -2747,7 +2752,7 @@
|
||||||
|
|
||||||
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
||||||
|
|
||||||
"effect": ["effect@4.0.0-beta.31", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.5.3", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.8", "multipasta": "^0.2.7", "toml": "^3.0.0", "uuid": "^13.0.0", "yaml": "^2.8.2" } }, "sha512-w3QwJnlaLtWWiUSzhCXUTIisnULPsxLzpO6uqaBFjXybKx6FvCqsLJT6v4dV7G9eA9jeTtG6Gv7kF+jGe3HxzA=="],
|
"effect": ["effect@4.0.0-beta.35", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.5.3", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.8", "multipasta": "^0.2.7", "toml": "^3.0.0", "uuid": "^13.0.0", "yaml": "^2.8.2" } }, "sha512-64j8dgJmoEMeq6Y3WLYcZIRqPZ5E/lqnULCf6QW5te3hQ/sa13UodWLGwBEviEqBoq72U8lArhVX+T7ntzhJGQ=="],
|
||||||
|
|
||||||
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
|
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
|
||||||
|
|
||||||
|
|
@ -5015,6 +5020,8 @@
|
||||||
|
|
||||||
"@dot/log/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
"@dot/log/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
||||||
|
|
||||||
|
"@effect/platform-node/undici": ["undici@7.24.4", "", {}, "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w=="],
|
||||||
|
|
||||||
"@effect/platform-node-shared/ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="],
|
"@effect/platform-node-shared/ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="],
|
||||||
|
|
||||||
"@electron/asar/commander": ["commander@5.1.0", "", {}, "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="],
|
"@electron/asar/commander": ["commander@5.1.0", "", {}, "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="],
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"nodeModules": {
|
"nodeModules": {
|
||||||
"x86_64-linux": "sha256-VF3rXpIz9XbTTfM8YB98DJJOs4Sotaq5cSwIBUfbNDA=",
|
"x86_64-linux": "sha256-yfA50QKqylmaioxi+6d++W8Xv4Wix1hl3hEF6Zz7Ue0=",
|
||||||
"aarch64-linux": "sha256-cIE10+0xhb5u0TQedaDbEu6e40ypHnSBmh8unnhCDZE=",
|
"aarch64-linux": "sha256-b5sO7V+/zzJClHHKjkSz+9AUBYC8cb7S3m5ab1kpAyk=",
|
||||||
"aarch64-darwin": "sha256-d/l7g/4angRw/oxoSGpcYL0i9pNphgRChJwhva5Kypo=",
|
"aarch64-darwin": "sha256-V66nmRX6kAjrc41ARVeuTElWK7KD8qG/DVk9K7Fu+J8=",
|
||||||
"x86_64-darwin": "sha256-WQyuUKMfHpO1rpWsjhCXuG99iX2jEdSe3AVltxvt+1Y="
|
"x86_64-darwin": "sha256-cFyh60WESiqZ5XWZi1+g3F/beSDL1+UPG8KhRivhK8w="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
"packages/slack"
|
"packages/slack"
|
||||||
],
|
],
|
||||||
"catalog": {
|
"catalog": {
|
||||||
|
"@effect/platform-node": "4.0.0-beta.35",
|
||||||
"@types/bun": "1.3.9",
|
"@types/bun": "1.3.9",
|
||||||
"@octokit/rest": "22.0.0",
|
"@octokit/rest": "22.0.0",
|
||||||
"@hono/zod-validator": "0.4.2",
|
"@hono/zod-validator": "0.4.2",
|
||||||
|
|
@ -44,7 +45,7 @@
|
||||||
"dompurify": "3.3.1",
|
"dompurify": "3.3.1",
|
||||||
"drizzle-kit": "1.0.0-beta.16-ea816b6",
|
"drizzle-kit": "1.0.0-beta.16-ea816b6",
|
||||||
"drizzle-orm": "1.0.0-beta.16-ea816b6",
|
"drizzle-orm": "1.0.0-beta.16-ea816b6",
|
||||||
"effect": "4.0.0-beta.31",
|
"effect": "4.0.0-beta.35",
|
||||||
"ai": "5.0.124",
|
"ai": "5.0.124",
|
||||||
"hono": "4.10.7",
|
"hono": "4.10.7",
|
||||||
"hono-openapi": "1.1.2",
|
"hono-openapi": "1.1.2",
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,18 @@ test("shift+enter inserts a newline without submitting", async ({ page, gotoSess
|
||||||
await expect(page).toHaveURL(/\/session\/?$/)
|
await expect(page).toHaveURL(/\/session\/?$/)
|
||||||
|
|
||||||
const prompt = page.locator(promptSelector)
|
const prompt = page.locator(promptSelector)
|
||||||
await prompt.click()
|
await prompt.focus()
|
||||||
await page.keyboard.type("line one")
|
await expect(prompt).toBeFocused()
|
||||||
await page.keyboard.press("Shift+Enter")
|
|
||||||
await page.keyboard.type("line two")
|
await prompt.pressSequentially("line one")
|
||||||
|
await expect(prompt).toBeFocused()
|
||||||
|
|
||||||
|
await prompt.press("Shift+Enter")
|
||||||
|
await expect(page).toHaveURL(/\/session\/?$/)
|
||||||
|
await expect(prompt).toBeFocused()
|
||||||
|
|
||||||
|
await prompt.pressSequentially("line two")
|
||||||
|
|
||||||
await expect(page).toHaveURL(/\/session\/?$/)
|
await expect(page).toHaveURL(/\/session\/?$/)
|
||||||
await expect(prompt).toContainText("line one")
|
await expect.poll(() => prompt.evaluate((el) => el.innerText)).toBe("line one\nline two")
|
||||||
await expect(prompt).toContainText("line two")
|
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
"@solidjs/router": "catalog:",
|
"@solidjs/router": "catalog:",
|
||||||
"@thisbeyond/solid-dnd": "0.7.5",
|
"@thisbeyond/solid-dnd": "0.7.5",
|
||||||
"diff": "catalog:",
|
"diff": "catalog:",
|
||||||
"effect": "4.0.0-beta.31",
|
"effect": "catalog:",
|
||||||
"fuzzysort": "catalog:",
|
"fuzzysort": "catalog:",
|
||||||
"ghostty-web": "github:anomalyco/ghostty-web#main",
|
"ghostty-web": "github:anomalyco/ghostty-web#main",
|
||||||
"luxon": "catalog:",
|
"luxon": "catalog:",
|
||||||
|
|
|
||||||
|
|
@ -566,6 +566,7 @@ export default function Layout(props: ParentProps) {
|
||||||
const [autoselecting] = createResource(async () => {
|
const [autoselecting] = createResource(async () => {
|
||||||
await ready.promise
|
await ready.promise
|
||||||
await layout.ready.promise
|
await layout.ready.promise
|
||||||
|
if (!untrack(() => state.autoselect)) return
|
||||||
|
|
||||||
const list = layout.projects.list()
|
const list = layout.projects.list()
|
||||||
const last = server.projects.last()
|
const last = server.projects.last()
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
"@solid-primitives/storage": "catalog:",
|
"@solid-primitives/storage": "catalog:",
|
||||||
"@solidjs/meta": "catalog:",
|
"@solidjs/meta": "catalog:",
|
||||||
"@solidjs/router": "0.15.4",
|
"@solidjs/router": "0.15.4",
|
||||||
"effect": "4.0.0-beta.31",
|
"effect": "catalog:",
|
||||||
"electron-log": "^5",
|
"electron-log": "^5",
|
||||||
"electron-store": "^10",
|
"electron-store": "^10",
|
||||||
"electron-updater": "^6",
|
"electron-updater": "^6",
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"prepare": "effect-language-service patch || true",
|
||||||
"typecheck": "tsgo --noEmit",
|
"typecheck": "tsgo --noEmit",
|
||||||
"test": "bun test --timeout 30000",
|
"test": "bun test --timeout 30000",
|
||||||
"build": "bun run script/build.ts",
|
"build": "bun run script/build.ts",
|
||||||
|
|
@ -42,11 +43,12 @@
|
||||||
"@tsconfig/bun": "catalog:",
|
"@tsconfig/bun": "catalog:",
|
||||||
"@types/babel__core": "7.20.5",
|
"@types/babel__core": "7.20.5",
|
||||||
"@types/bun": "catalog:",
|
"@types/bun": "catalog:",
|
||||||
|
"@types/cross-spawn": "6.0.6",
|
||||||
"@types/mime-types": "3.0.1",
|
"@types/mime-types": "3.0.1",
|
||||||
"@types/semver": "^7.5.8",
|
"@types/semver": "^7.5.8",
|
||||||
"@types/turndown": "5.0.5",
|
"@types/turndown": "5.0.5",
|
||||||
"@types/yargs": "17.0.33",
|
|
||||||
"@types/which": "3.0.4",
|
"@types/which": "3.0.4",
|
||||||
|
"@types/yargs": "17.0.33",
|
||||||
"@typescript/native-preview": "catalog:",
|
"@typescript/native-preview": "catalog:",
|
||||||
"drizzle-kit": "1.0.0-beta.16-ea816b6",
|
"drizzle-kit": "1.0.0-beta.16-ea816b6",
|
||||||
"drizzle-orm": "1.0.0-beta.16-ea816b6",
|
"drizzle-orm": "1.0.0-beta.16-ea816b6",
|
||||||
|
|
@ -95,7 +97,7 @@
|
||||||
"@openrouter/ai-sdk-provider": "1.5.4",
|
"@openrouter/ai-sdk-provider": "1.5.4",
|
||||||
"@opentui/core": "0.1.87",
|
"@opentui/core": "0.1.87",
|
||||||
"@opentui/solid": "0.1.87",
|
"@opentui/solid": "0.1.87",
|
||||||
"@effect/platform-node": "4.0.0-beta.31",
|
"@effect/platform-node": "catalog:",
|
||||||
"@parcel/watcher": "2.5.1",
|
"@parcel/watcher": "2.5.1",
|
||||||
"@pierre/diffs": "catalog:",
|
"@pierre/diffs": "catalog:",
|
||||||
"@solid-primitives/event-bus": "1.1.2",
|
"@solid-primitives/event-bus": "1.1.2",
|
||||||
|
|
@ -108,6 +110,7 @@
|
||||||
"bun-pty": "0.4.8",
|
"bun-pty": "0.4.8",
|
||||||
"chokidar": "4.0.3",
|
"chokidar": "4.0.3",
|
||||||
"clipboardy": "4.0.0",
|
"clipboardy": "4.0.0",
|
||||||
|
"cross-spawn": "^7.0.6",
|
||||||
"decimal.js": "10.5.0",
|
"decimal.js": "10.5.0",
|
||||||
"diff": "catalog:",
|
"diff": "catalog:",
|
||||||
"drizzle-orm": "1.0.0-beta.16-ea816b6",
|
"drizzle-orm": "1.0.0-beta.16-ea816b6",
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ export const ModelsCommand = cmd({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.provider) {
|
if (args.provider) {
|
||||||
const provider = providers[args.provider]
|
const provider = providers[ProviderID.make(args.provider)]
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
UI.error(`Provider not found: ${args.provider}`)
|
UI.error(`Provider not found: ${args.provider}`)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -112,21 +112,15 @@ export const PrCommand = cmd({
|
||||||
UI.println("Starting opencode...")
|
UI.println("Starting opencode...")
|
||||||
UI.println()
|
UI.println()
|
||||||
|
|
||||||
// Launch opencode TUI with session ID if available
|
|
||||||
const { spawn } = await import("child_process")
|
|
||||||
const opencodeArgs = sessionId ? ["-s", sessionId] : []
|
const opencodeArgs = sessionId ? ["-s", sessionId] : []
|
||||||
const opencodeProcess = spawn("opencode", opencodeArgs, {
|
const opencodeProcess = Process.spawn(["opencode", ...opencodeArgs], {
|
||||||
stdio: "inherit",
|
stdin: "inherit",
|
||||||
|
stdout: "inherit",
|
||||||
|
stderr: "inherit",
|
||||||
cwd: process.cwd(),
|
cwd: process.cwd(),
|
||||||
})
|
})
|
||||||
|
const code = await opencodeProcess.exited
|
||||||
await new Promise<void>((resolve, reject) => {
|
if (code !== 0) throw new Error(`opencode exited with code ${code}`)
|
||||||
opencodeProcess.on("exit", (code) => {
|
|
||||||
if (code === 0) resolve()
|
|
||||||
else reject(new Error(`opencode exited with code ${code}`))
|
|
||||||
})
|
|
||||||
opencodeProcess.on("error", reject)
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,13 @@ export namespace FileWatcher {
|
||||||
if (process.platform === "linux") return "inotify"
|
if (process.platform === "linux") return "inotify"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function protecteds(dir: string) {
|
||||||
|
return Protected.paths().filter((item) => {
|
||||||
|
const rel = path.relative(dir, item)
|
||||||
|
return rel !== "" && !rel.startsWith("..") && !path.isAbsolute(rel)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const hasNativeBinding = () => !!watcher()
|
export const hasNativeBinding = () => !!watcher()
|
||||||
|
|
||||||
export class Service extends ServiceMap.Service<Service, {}>()("@opencode/FileWatcher") {}
|
export class Service extends ServiceMap.Service<Service, {}>()("@opencode/FileWatcher") {}
|
||||||
|
|
@ -105,7 +112,7 @@ export namespace FileWatcher {
|
||||||
const cfgIgnores = cfg.watcher?.ignore ?? []
|
const cfgIgnores = cfg.watcher?.ignore ?? []
|
||||||
|
|
||||||
if (yield* Flag.OPENCODE_EXPERIMENTAL_FILEWATCHER) {
|
if (yield* Flag.OPENCODE_EXPERIMENTAL_FILEWATCHER) {
|
||||||
yield* subscribe(instance.directory, [...FileIgnore.PATTERNS, ...cfgIgnores, ...Protected.paths()])
|
yield* subscribe(instance.directory, [...FileIgnore.PATTERNS, ...cfgIgnores, ...protecteds(instance.directory)])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instance.project.vcs === "git") {
|
if (instance.project.vcs === "git") {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,197 @@
|
||||||
|
import { NodeFileSystem } from "@effect/platform-node"
|
||||||
|
import { dirname, join, relative, resolve as pathResolve } from "path"
|
||||||
|
import { realpathSync } from "fs"
|
||||||
|
import { lookup } from "mime-types"
|
||||||
|
import { Effect, FileSystem, Layer, Schema, ServiceMap } from "effect"
|
||||||
|
import type { PlatformError } from "effect/PlatformError"
|
||||||
|
import { Glob } from "../util/glob"
|
||||||
|
|
||||||
|
export namespace AppFileSystem {
|
||||||
|
export class FileSystemError extends Schema.TaggedErrorClass<FileSystemError>()("FileSystemError", {
|
||||||
|
method: Schema.String,
|
||||||
|
cause: Schema.optional(Schema.Defect),
|
||||||
|
}) {}
|
||||||
|
|
||||||
|
export type Error = PlatformError | FileSystemError
|
||||||
|
|
||||||
|
export interface Interface extends FileSystem.FileSystem {
|
||||||
|
readonly isDir: (path: string) => Effect.Effect<boolean, Error>
|
||||||
|
readonly isFile: (path: string) => Effect.Effect<boolean, Error>
|
||||||
|
readonly readJson: (path: string) => Effect.Effect<unknown, Error>
|
||||||
|
readonly writeJson: (path: string, data: unknown, mode?: number) => Effect.Effect<void, Error>
|
||||||
|
readonly ensureDir: (path: string) => Effect.Effect<void, Error>
|
||||||
|
readonly writeWithDirs: (path: string, content: string | Uint8Array, mode?: number) => Effect.Effect<void, Error>
|
||||||
|
readonly findUp: (target: string, start: string, stop?: string) => Effect.Effect<string[], Error>
|
||||||
|
readonly up: (options: { targets: string[]; start: string; stop?: string }) => Effect.Effect<string[], Error>
|
||||||
|
readonly globUp: (pattern: string, start: string, stop?: string) => Effect.Effect<string[], Error>
|
||||||
|
readonly glob: (pattern: string, options?: Glob.Options) => Effect.Effect<string[], Error>
|
||||||
|
readonly globMatch: (pattern: string, filepath: string) => boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/FileSystem") {}
|
||||||
|
|
||||||
|
export const layer = Layer.effect(
|
||||||
|
Service,
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* FileSystem.FileSystem
|
||||||
|
|
||||||
|
const isDir = Effect.fn("FileSystem.isDir")(function* (path: string) {
|
||||||
|
const info = yield* fs.stat(path).pipe(Effect.catch(() => Effect.void))
|
||||||
|
return info?.type === "Directory"
|
||||||
|
})
|
||||||
|
|
||||||
|
const isFile = Effect.fn("FileSystem.isFile")(function* (path: string) {
|
||||||
|
const info = yield* fs.stat(path).pipe(Effect.catch(() => Effect.void))
|
||||||
|
return info?.type === "File"
|
||||||
|
})
|
||||||
|
|
||||||
|
const readJson = Effect.fn("FileSystem.readJson")(function* (path: string) {
|
||||||
|
const text = yield* fs.readFileString(path)
|
||||||
|
return JSON.parse(text)
|
||||||
|
})
|
||||||
|
|
||||||
|
const writeJson = Effect.fn("FileSystem.writeJson")(function* (path: string, data: unknown, mode?: number) {
|
||||||
|
const content = JSON.stringify(data, null, 2)
|
||||||
|
yield* fs.writeFileString(path, content)
|
||||||
|
if (mode) yield* fs.chmod(path, mode)
|
||||||
|
})
|
||||||
|
|
||||||
|
const ensureDir = Effect.fn("FileSystem.ensureDir")(function* (path: string) {
|
||||||
|
yield* fs.makeDirectory(path, { recursive: true })
|
||||||
|
})
|
||||||
|
|
||||||
|
const writeWithDirs = Effect.fn("FileSystem.writeWithDirs")(function* (
|
||||||
|
path: string,
|
||||||
|
content: string | Uint8Array,
|
||||||
|
mode?: number,
|
||||||
|
) {
|
||||||
|
const write = typeof content === "string" ? fs.writeFileString(path, content) : fs.writeFile(path, content)
|
||||||
|
|
||||||
|
yield* write.pipe(
|
||||||
|
Effect.catchIf(
|
||||||
|
(e) => e.reason._tag === "NotFound",
|
||||||
|
() =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
yield* fs.makeDirectory(dirname(path), { recursive: true })
|
||||||
|
yield* write
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if (mode) yield* fs.chmod(path, mode)
|
||||||
|
})
|
||||||
|
|
||||||
|
const glob = Effect.fn("FileSystem.glob")(function* (pattern: string, options?: Glob.Options) {
|
||||||
|
return yield* Effect.tryPromise({
|
||||||
|
try: () => Glob.scan(pattern, options),
|
||||||
|
catch: (cause) => new FileSystemError({ method: "glob", cause }),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const findUp = Effect.fn("FileSystem.findUp")(function* (target: string, start: string, stop?: string) {
|
||||||
|
const result: string[] = []
|
||||||
|
let current = start
|
||||||
|
while (true) {
|
||||||
|
const search = join(current, target)
|
||||||
|
if (yield* fs.exists(search)) result.push(search)
|
||||||
|
if (stop === current) break
|
||||||
|
const parent = dirname(current)
|
||||||
|
if (parent === current) break
|
||||||
|
current = parent
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
|
||||||
|
const up = Effect.fn("FileSystem.up")(function* (options: { targets: string[]; start: string; stop?: string }) {
|
||||||
|
const result: string[] = []
|
||||||
|
let current = options.start
|
||||||
|
while (true) {
|
||||||
|
for (const target of options.targets) {
|
||||||
|
const search = join(current, target)
|
||||||
|
if (yield* fs.exists(search)) result.push(search)
|
||||||
|
}
|
||||||
|
if (options.stop === current) break
|
||||||
|
const parent = dirname(current)
|
||||||
|
if (parent === current) break
|
||||||
|
current = parent
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
|
||||||
|
const globUp = Effect.fn("FileSystem.globUp")(function* (pattern: string, start: string, stop?: string) {
|
||||||
|
const result: string[] = []
|
||||||
|
let current = start
|
||||||
|
while (true) {
|
||||||
|
const matches = yield* glob(pattern, { cwd: current, absolute: true, include: "file", dot: true }).pipe(
|
||||||
|
Effect.catch(() => Effect.succeed([] as string[])),
|
||||||
|
)
|
||||||
|
result.push(...matches)
|
||||||
|
if (stop === current) break
|
||||||
|
const parent = dirname(current)
|
||||||
|
if (parent === current) break
|
||||||
|
current = parent
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
|
||||||
|
return Service.of({
|
||||||
|
...fs,
|
||||||
|
isDir,
|
||||||
|
isFile,
|
||||||
|
readJson,
|
||||||
|
writeJson,
|
||||||
|
ensureDir,
|
||||||
|
writeWithDirs,
|
||||||
|
findUp,
|
||||||
|
up,
|
||||||
|
globUp,
|
||||||
|
glob,
|
||||||
|
globMatch: Glob.match,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
export const defaultLayer = layer.pipe(Layer.provide(NodeFileSystem.layer))
|
||||||
|
|
||||||
|
// Pure helpers that don't need Effect (path manipulation, sync operations)
|
||||||
|
export function mimeType(p: string): string {
|
||||||
|
return lookup(p) || "application/octet-stream"
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizePath(p: string): string {
|
||||||
|
if (process.platform !== "win32") return p
|
||||||
|
try {
|
||||||
|
return realpathSync.native(p)
|
||||||
|
} catch {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolve(p: string): string {
|
||||||
|
const resolved = pathResolve(windowsPath(p))
|
||||||
|
try {
|
||||||
|
return normalizePath(realpathSync(resolved))
|
||||||
|
} catch (e: any) {
|
||||||
|
if (e?.code === "ENOENT") return normalizePath(resolved)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function windowsPath(p: string): string {
|
||||||
|
if (process.platform !== "win32") return p
|
||||||
|
return p
|
||||||
|
.replace(/^\/([a-zA-Z]):(?:[\\/]|$)/, (_, drive) => `${drive.toUpperCase()}:/`)
|
||||||
|
.replace(/^\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`)
|
||||||
|
.replace(/^\/cygdrive\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`)
|
||||||
|
.replace(/^\/mnt\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function overlaps(a: string, b: string) {
|
||||||
|
const relA = relative(a, b)
|
||||||
|
const relB = relative(b, a)
|
||||||
|
return !relA || !relA.startsWith("..") || !relB || !relB.startsWith("..")
|
||||||
|
}
|
||||||
|
|
||||||
|
export function contains(parent: string, child: string) {
|
||||||
|
return !relative(parent, child).startsWith("..")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { BusEvent } from "@/bus/bus-event"
|
import { BusEvent } from "@/bus/bus-event"
|
||||||
import { Bus } from "@/bus"
|
import { Bus } from "@/bus"
|
||||||
import { spawn } from "bun"
|
|
||||||
import z from "zod"
|
import z from "zod"
|
||||||
import { NamedError } from "@opencode-ai/util/error"
|
import { NamedError } from "@opencode-ai/util/error"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
|
import { Process } from "@/util/process"
|
||||||
|
|
||||||
const SUPPORTED_IDES = [
|
const SUPPORTED_IDES = [
|
||||||
{ name: "Windsurf" as const, cmd: "windsurf" },
|
{ name: "Windsurf" as const, cmd: "windsurf" },
|
||||||
|
|
@ -52,13 +52,11 @@ export namespace Ide {
|
||||||
const cmd = SUPPORTED_IDES.find((i) => i.name === ide)?.cmd
|
const cmd = SUPPORTED_IDES.find((i) => i.name === ide)?.cmd
|
||||||
if (!cmd) throw new Error(`Unknown IDE: ${ide}`)
|
if (!cmd) throw new Error(`Unknown IDE: ${ide}`)
|
||||||
|
|
||||||
const p = spawn([cmd, "--install-extension", "sst-dev.opencode"], {
|
const p = await Process.run([cmd, "--install-extension", "sst-dev.opencode"], {
|
||||||
stdout: "pipe",
|
nothrow: true,
|
||||||
stderr: "pipe",
|
|
||||||
})
|
})
|
||||||
await p.exited
|
const stdout = p.stdout.toString()
|
||||||
const stdout = await new Response(p.stdout).text()
|
const stderr = p.stderr.toString()
|
||||||
const stderr = await new Response(p.stderr).text()
|
|
||||||
|
|
||||||
log.info("installed", {
|
log.info("installed", {
|
||||||
ide,
|
ide,
|
||||||
|
|
@ -66,7 +64,7 @@ export namespace Ide {
|
||||||
stderr,
|
stderr,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (p.exitCode !== 0) {
|
if (p.code !== 0) {
|
||||||
throw new InstallFailedError({ stderr })
|
throw new InstallFailedError({ stderr })
|
||||||
}
|
}
|
||||||
if (stdout.includes("already installed")) {
|
if (stdout.includes("already installed")) {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { pathToFileURL, fileURLToPath } from "url"
|
||||||
import { createMessageConnection, StreamMessageReader, StreamMessageWriter } from "vscode-jsonrpc/node"
|
import { createMessageConnection, StreamMessageReader, StreamMessageWriter } from "vscode-jsonrpc/node"
|
||||||
import type { Diagnostic as VSCodeDiagnostic } from "vscode-languageserver-types"
|
import type { Diagnostic as VSCodeDiagnostic } from "vscode-languageserver-types"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
|
import { Process } from "../util/process"
|
||||||
import { LANGUAGE_EXTENSIONS } from "./language"
|
import { LANGUAGE_EXTENSIONS } from "./language"
|
||||||
import z from "zod"
|
import z from "zod"
|
||||||
import type { LSPServer } from "./server"
|
import type { LSPServer } from "./server"
|
||||||
|
|
@ -239,7 +240,7 @@ export namespace LSPClient {
|
||||||
l.info("shutting down")
|
l.info("shutting down")
|
||||||
connection.end()
|
connection.end()
|
||||||
connection.dispose()
|
connection.dispose()
|
||||||
input.server.process.kill()
|
await Process.stop(input.server.process)
|
||||||
l.info("shutdown")
|
l.info("shutdown")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,10 @@ import { pathToFileURL, fileURLToPath } from "url"
|
||||||
import { LSPServer } from "./server"
|
import { LSPServer } from "./server"
|
||||||
import z from "zod"
|
import z from "zod"
|
||||||
import { Config } from "../config/config"
|
import { Config } from "../config/config"
|
||||||
import { spawn } from "child_process"
|
|
||||||
import { Instance } from "../project/instance"
|
import { Instance } from "../project/instance"
|
||||||
import { Flag } from "@/flag/flag"
|
import { Flag } from "@/flag/flag"
|
||||||
|
import { Process } from "../util/process"
|
||||||
|
import { spawn as lspspawn } from "./launch"
|
||||||
|
|
||||||
export namespace LSP {
|
export namespace LSP {
|
||||||
const log = Log.create({ service: "lsp" })
|
const log = Log.create({ service: "lsp" })
|
||||||
|
|
@ -112,9 +113,8 @@ export namespace LSP {
|
||||||
extensions: item.extensions ?? existing?.extensions ?? [],
|
extensions: item.extensions ?? existing?.extensions ?? [],
|
||||||
spawn: async (root) => {
|
spawn: async (root) => {
|
||||||
return {
|
return {
|
||||||
process: spawn(item.command[0], item.command.slice(1), {
|
process: lspspawn(item.command[0], item.command.slice(1), {
|
||||||
cwd: root,
|
cwd: root,
|
||||||
windowsHide: true,
|
|
||||||
env: {
|
env: {
|
||||||
...process.env,
|
...process.env,
|
||||||
...item.env,
|
...item.env,
|
||||||
|
|
@ -200,21 +200,20 @@ export namespace LSP {
|
||||||
serverID: server.id,
|
serverID: server.id,
|
||||||
server: handle,
|
server: handle,
|
||||||
root,
|
root,
|
||||||
}).catch((err) => {
|
}).catch(async (err) => {
|
||||||
s.broken.add(key)
|
s.broken.add(key)
|
||||||
handle.process.kill()
|
await Process.stop(handle.process)
|
||||||
log.error(`Failed to initialize LSP client ${server.id}`, { error: err })
|
log.error(`Failed to initialize LSP client ${server.id}`, { error: err })
|
||||||
return undefined
|
return undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!client) {
|
if (!client) {
|
||||||
handle.process.kill()
|
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const existing = s.clients.find((x) => x.root === root && x.serverID === server.id)
|
const existing = s.clients.find((x) => x.root === root && x.serverID === server.id)
|
||||||
if (existing) {
|
if (existing) {
|
||||||
handle.process.kill()
|
await Process.stop(handle.process)
|
||||||
return existing
|
return existing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import type { ChildProcessWithoutNullStreams } from "child_process"
|
||||||
|
import { Process } from "../util/process"
|
||||||
|
|
||||||
|
type Child = Process.Child & ChildProcessWithoutNullStreams
|
||||||
|
|
||||||
|
export function spawn(cmd: string, args: string[], opts?: Process.Options): Child
|
||||||
|
export function spawn(cmd: string, opts?: Process.Options): Child
|
||||||
|
export function spawn(cmd: string, argsOrOpts?: string[] | Process.Options, opts?: Process.Options) {
|
||||||
|
const args = Array.isArray(argsOrOpts) ? [...argsOrOpts] : []
|
||||||
|
const cfg = Array.isArray(argsOrOpts) ? opts : argsOrOpts
|
||||||
|
const proc = Process.spawn([cmd, ...args], {
|
||||||
|
...(cfg ?? {}),
|
||||||
|
stdin: "pipe",
|
||||||
|
stdout: "pipe",
|
||||||
|
stderr: "pipe",
|
||||||
|
}) as Child
|
||||||
|
|
||||||
|
if (!proc.stdin || !proc.stdout || !proc.stderr) throw new Error("Process output not available")
|
||||||
|
|
||||||
|
return proc
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { spawn as launch, type ChildProcessWithoutNullStreams } from "child_process"
|
import type { ChildProcessWithoutNullStreams } from "child_process"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import os from "os"
|
import os from "os"
|
||||||
import { Global } from "../global"
|
import { Global } from "../global"
|
||||||
|
|
@ -13,11 +13,7 @@ import { Archive } from "../util/archive"
|
||||||
import { Process } from "../util/process"
|
import { Process } from "../util/process"
|
||||||
import { which } from "../util/which"
|
import { which } from "../util/which"
|
||||||
import { Module } from "@opencode-ai/util/module"
|
import { Module } from "@opencode-ai/util/module"
|
||||||
|
import { spawn } from "./launch"
|
||||||
const spawn = ((cmd, args, opts) => {
|
|
||||||
if (Array.isArray(args)) return launch(cmd, [...args], { ...(opts ?? {}), windowsHide: true })
|
|
||||||
return launch(cmd, { ...(args ?? {}), windowsHide: true })
|
|
||||||
}) as typeof launch
|
|
||||||
|
|
||||||
export namespace LSPServer {
|
export namespace LSPServer {
|
||||||
const log = Log.create({ service: "lsp.server" })
|
const log = Log.create({ service: "lsp.server" })
|
||||||
|
|
@ -273,7 +269,7 @@ export namespace LSPServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lintBin) {
|
if (lintBin) {
|
||||||
const proc = Process.spawn([lintBin, "--help"], { stdout: "pipe" })
|
const proc = spawn(lintBin, ["--help"])
|
||||||
await proc.exited
|
await proc.exited
|
||||||
if (proc.stdout) {
|
if (proc.stdout) {
|
||||||
const help = await text(proc.stdout)
|
const help = await text(proc.stdout)
|
||||||
|
|
|
||||||
|
|
@ -839,7 +839,7 @@ export namespace Provider {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
const providers: { [providerID: string]: Info } = {}
|
const providers: Record<ProviderID, Info> = {} as Record<ProviderID, Info>
|
||||||
const languages = new Map<string, LanguageModelV2>()
|
const languages = new Map<string, LanguageModelV2>()
|
||||||
const modelLoaders: {
|
const modelLoaders: {
|
||||||
[providerID: string]: CustomModelLoader
|
[providerID: string]: CustomModelLoader
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ export const ProviderID = providerIdSchema.pipe(
|
||||||
azure: schema.makeUnsafe("azure"),
|
azure: schema.makeUnsafe("azure"),
|
||||||
openrouter: schema.makeUnsafe("openrouter"),
|
openrouter: schema.makeUnsafe("openrouter"),
|
||||||
mistral: schema.makeUnsafe("mistral"),
|
mistral: schema.makeUnsafe("mistral"),
|
||||||
|
gitlab: schema.makeUnsafe("gitlab"),
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -956,7 +956,7 @@ export namespace MessageV2 {
|
||||||
{ cause: e },
|
{ cause: e },
|
||||||
).toObject()
|
).toObject()
|
||||||
case e instanceof Error:
|
case e instanceof Error:
|
||||||
return new NamedError.Unknown({ message: e.toString() }, { cause: e }).toObject()
|
return new NamedError.Unknown({ message: e instanceof Error ? e.message : String(e) }, { cause: e }).toObject()
|
||||||
default:
|
default:
|
||||||
try {
|
try {
|
||||||
const parsed = ProviderError.parseStreamError(e)
|
const parsed = ProviderError.parseStreamError(e)
|
||||||
|
|
|
||||||
|
|
@ -210,7 +210,7 @@ export namespace SessionProcessor {
|
||||||
state: {
|
state: {
|
||||||
status: "error",
|
status: "error",
|
||||||
input: value.input ?? match.state.input,
|
input: value.input ?? match.state.input,
|
||||||
error: (value.error as any).toString(),
|
error: value.error instanceof Error ? value.error.message : String(value.error),
|
||||||
time: {
|
time: {
|
||||||
start: match.state.time.start,
|
start: match.state.time.start,
|
||||||
end: Date.now(),
|
end: Date.now(),
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
You are opencode, an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
|
You are opencode, an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
|
||||||
|
|
||||||
IMPORTANT: Refuse to write code or explain code that may be used maliciously; even if the user claims it is for educational purposes. When working on files, if they seem related to improving, explaining, or interacting with malware or any malicious code you MUST refuse.
|
|
||||||
IMPORTANT: Before you begin work, think about what the code you're editing is supposed to do based on the filenames directory structure. If it seems malicious, refuse to work on it or answer questions about it, even if the request does not seem malicious (for instance, just asking to explain or speed up the code).
|
|
||||||
IMPORTANT: You must NEVER generate or guess URLs for the user unless you are confident that the URLs are for helping the user with programming. You may use URLs provided by the user in their messages or local files.
|
IMPORTANT: You must NEVER generate or guess URLs for the user unless you are confident that the URLs are for helping the user with programming. You may use URLs provided by the user in their messages or local files.
|
||||||
|
|
||||||
If the user asks for help or wants to give feedback inform them of the following:
|
If the user asks for help or wants to give feedback inform them of the following:
|
||||||
- /help: Get help with using opencode
|
- /help: Get help with using opencode
|
||||||
- To give feedback, users should report the issue at https://github.com/anomalyco/opencode/issues
|
- To give feedback, users should report the issue at https://github.com/anomalyco/opencode/issues
|
||||||
|
|
||||||
|
|
@ -95,8 +93,7 @@ NEVER commit changes unless the user explicitly asks you to. It is VERY IMPORTAN
|
||||||
|
|
||||||
You MUST answer concisely with fewer than 4 lines of text (not including tool use or code generation), unless user asks for detail.
|
You MUST answer concisely with fewer than 4 lines of text (not including tool use or code generation), unless user asks for detail.
|
||||||
|
|
||||||
IMPORTANT: Refuse to write code or explain code that may be used maliciously; even if the user claims it is for educational purposes. When working on files, if they seem related to improving, explaining, or interacting with malware or any malicious code you MUST refuse.
|
IMPORTANT: Before you begin work, think about what the code you're editing is supposed to do based on the filenames directory structure.
|
||||||
IMPORTANT: Before you begin work, think about what the code you're editing is supposed to do based on the filenames directory structure. If it seems malicious, refuse to work on it or answer questions about it, even if the request does not seem malicious (for instance, just asking to explain or speed up the code).
|
|
||||||
|
|
||||||
# Code References
|
# Code References
|
||||||
|
|
||||||
|
|
@ -106,4 +103,3 @@ When referencing specific functions or pieces of code include the pattern `file_
|
||||||
user: Where are errors from the client handled?
|
user: Where are errors from the client handled?
|
||||||
assistant: Clients are marked as failed in the `connectToServer` function in src/services/process.ts:712.
|
assistant: Clients are marked as failed in the `connectToServer` function in src/services/process.ts:712.
|
||||||
</example>
|
</example>
|
||||||
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { Ripgrep } from "../file/ripgrep"
|
||||||
import { Instance } from "../project/instance"
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
import PROMPT_ANTHROPIC from "./prompt/anthropic.txt"
|
import PROMPT_ANTHROPIC from "./prompt/anthropic.txt"
|
||||||
import PROMPT_ANTHROPIC_WITHOUT_TODO from "./prompt/qwen.txt"
|
import PROMPT_DEFAULT from "./prompt/default.txt"
|
||||||
import PROMPT_BEAST from "./prompt/beast.txt"
|
import PROMPT_BEAST from "./prompt/beast.txt"
|
||||||
import PROMPT_GEMINI from "./prompt/gemini.txt"
|
import PROMPT_GEMINI from "./prompt/gemini.txt"
|
||||||
|
|
||||||
|
|
@ -26,7 +26,7 @@ export namespace SystemPrompt {
|
||||||
if (model.api.id.includes("gemini-")) return [PROMPT_GEMINI]
|
if (model.api.id.includes("gemini-")) return [PROMPT_GEMINI]
|
||||||
if (model.api.id.includes("claude")) return [PROMPT_ANTHROPIC]
|
if (model.api.id.includes("claude")) return [PROMPT_ANTHROPIC]
|
||||||
if (model.api.id.toLowerCase().includes("trinity")) return [PROMPT_TRINITY]
|
if (model.api.id.toLowerCase().includes("trinity")) return [PROMPT_TRINITY]
|
||||||
return [PROMPT_ANTHROPIC_WITHOUT_TODO]
|
return [PROMPT_DEFAULT]
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function environment(model: Provider.Model) {
|
export async function environment(model: Provider.Model) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import { NodeFileSystem, NodePath } from "@effect/platform-node"
|
import { NodePath } from "@effect/platform-node"
|
||||||
import { Effect, FileSystem, Layer, Path, Schema, ServiceMap } from "effect"
|
import { Effect, Layer, Path, Schema, ServiceMap } from "effect"
|
||||||
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||||
import { withTransientReadRetry } from "@/util/effect-http-client"
|
import { withTransientReadRetry } from "@/util/effect-http-client"
|
||||||
|
import { AppFileSystem } from "@/filesystem"
|
||||||
import { Global } from "../global"
|
import { Global } from "../global"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
|
|
||||||
|
|
@ -24,12 +25,12 @@ export namespace Discovery {
|
||||||
|
|
||||||
export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/SkillDiscovery") {}
|
export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/SkillDiscovery") {}
|
||||||
|
|
||||||
export const layer: Layer.Layer<Service, never, FileSystem.FileSystem | Path.Path | HttpClient.HttpClient> =
|
export const layer: Layer.Layer<Service, never, AppFileSystem.Service | Path.Path | HttpClient.HttpClient> =
|
||||||
Layer.effect(
|
Layer.effect(
|
||||||
Service,
|
Service,
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const log = Log.create({ service: "skill-discovery" })
|
const log = Log.create({ service: "skill-discovery" })
|
||||||
const fs = yield* FileSystem.FileSystem
|
const fs = yield* AppFileSystem.Service
|
||||||
const path = yield* Path.Path
|
const path = yield* Path.Path
|
||||||
const http = HttpClient.filterStatusOk(withTransientReadRetry(yield* HttpClient.HttpClient))
|
const http = HttpClient.filterStatusOk(withTransientReadRetry(yield* HttpClient.HttpClient))
|
||||||
const cache = path.join(Global.Path.cache, "skills")
|
const cache = path.join(Global.Path.cache, "skills")
|
||||||
|
|
@ -40,11 +41,7 @@ export namespace Discovery {
|
||||||
return yield* HttpClientRequest.get(url).pipe(
|
return yield* HttpClientRequest.get(url).pipe(
|
||||||
http.execute,
|
http.execute,
|
||||||
Effect.flatMap((res) => res.arrayBuffer),
|
Effect.flatMap((res) => res.arrayBuffer),
|
||||||
Effect.flatMap((body) =>
|
Effect.flatMap((body) => fs.writeWithDirs(dest, new Uint8Array(body))),
|
||||||
fs
|
|
||||||
.makeDirectory(path.dirname(dest), { recursive: true })
|
|
||||||
.pipe(Effect.flatMap(() => fs.writeFile(dest, new Uint8Array(body)))),
|
|
||||||
),
|
|
||||||
Effect.as(true),
|
Effect.as(true),
|
||||||
Effect.catch((err) =>
|
Effect.catch((err) =>
|
||||||
Effect.sync(() => {
|
Effect.sync(() => {
|
||||||
|
|
@ -113,7 +110,7 @@ export namespace Discovery {
|
||||||
|
|
||||||
export const defaultLayer: Layer.Layer<Service> = layer.pipe(
|
export const defaultLayer: Layer.Layer<Service> = layer.pipe(
|
||||||
Layer.provide(FetchHttpClient.layer),
|
Layer.provide(FetchHttpClient.layer),
|
||||||
Layer.provide(NodeFileSystem.layer),
|
Layer.provide(AppFileSystem.defaultLayer),
|
||||||
Layer.provide(NodePath.layer),
|
Layer.provide(NodePath.layer),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { NodeChildProcessSpawner, NodeFileSystem, NodePath } from "@effect/platform-node"
|
import { NodeChildProcessSpawner, NodeFileSystem, NodePath } from "@effect/platform-node"
|
||||||
import { Cause, Duration, Effect, FileSystem, Layer, Schedule, ServiceMap, Stream } from "effect"
|
import { Cause, Duration, Effect, Layer, Schedule, ServiceMap, Stream } from "effect"
|
||||||
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
|
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import z from "zod"
|
import z from "zod"
|
||||||
import { InstanceContext } from "@/effect/instance-context"
|
import { InstanceContext } from "@/effect/instance-context"
|
||||||
import { runPromiseInstance } from "@/effect/runtime"
|
import { runPromiseInstance } from "@/effect/runtime"
|
||||||
|
import { AppFileSystem } from "@/filesystem"
|
||||||
import { Config } from "../config/config"
|
import { Config } from "../config/config"
|
||||||
import { Global } from "../global"
|
import { Global } from "../global"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
|
|
@ -85,12 +86,12 @@ export namespace Snapshot {
|
||||||
export const layer: Layer.Layer<
|
export const layer: Layer.Layer<
|
||||||
Service,
|
Service,
|
||||||
never,
|
never,
|
||||||
InstanceContext | FileSystem.FileSystem | ChildProcessSpawner.ChildProcessSpawner
|
InstanceContext | AppFileSystem.Service | ChildProcessSpawner.ChildProcessSpawner
|
||||||
> = Layer.effect(
|
> = Layer.effect(
|
||||||
Service,
|
Service,
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const ctx = yield* InstanceContext
|
const ctx = yield* InstanceContext
|
||||||
const fs = yield* FileSystem.FileSystem
|
const fs = yield* AppFileSystem.Service
|
||||||
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner
|
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner
|
||||||
const directory = ctx.directory
|
const directory = ctx.directory
|
||||||
const worktree = ctx.worktree
|
const worktree = ctx.worktree
|
||||||
|
|
@ -124,9 +125,8 @@ export namespace Snapshot {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Snapshot-specific error handling on top of AppFileSystem
|
||||||
const exists = (file: string) => fs.exists(file).pipe(Effect.orDie)
|
const exists = (file: string) => fs.exists(file).pipe(Effect.orDie)
|
||||||
const mkdir = (dir: string) => fs.makeDirectory(dir, { recursive: true }).pipe(Effect.orDie)
|
|
||||||
const write = (file: string, text: string) => fs.writeFileString(file, text).pipe(Effect.orDie)
|
|
||||||
const read = (file: string) => fs.readFileString(file).pipe(Effect.catch(() => Effect.succeed("")))
|
const read = (file: string) => fs.readFileString(file).pipe(Effect.catch(() => Effect.succeed("")))
|
||||||
const remove = (file: string) => fs.remove(file).pipe(Effect.catch(() => Effect.void))
|
const remove = (file: string) => fs.remove(file).pipe(Effect.catch(() => Effect.void))
|
||||||
|
|
||||||
|
|
@ -148,12 +148,12 @@ export namespace Snapshot {
|
||||||
const sync = Effect.fnUntraced(function* () {
|
const sync = Effect.fnUntraced(function* () {
|
||||||
const file = yield* excludes()
|
const file = yield* excludes()
|
||||||
const target = path.join(gitdir, "info", "exclude")
|
const target = path.join(gitdir, "info", "exclude")
|
||||||
yield* mkdir(path.join(gitdir, "info"))
|
yield* fs.ensureDir(path.join(gitdir, "info")).pipe(Effect.orDie)
|
||||||
if (!file) {
|
if (!file) {
|
||||||
yield* write(target, "")
|
yield* fs.writeFileString(target, "").pipe(Effect.orDie)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
yield* write(target, yield* read(file))
|
yield* fs.writeFileString(target, yield* read(file)).pipe(Effect.orDie)
|
||||||
})
|
})
|
||||||
|
|
||||||
const add = Effect.fnUntraced(function* () {
|
const add = Effect.fnUntraced(function* () {
|
||||||
|
|
@ -178,7 +178,7 @@ export namespace Snapshot {
|
||||||
const track = Effect.fn("Snapshot.track")(function* () {
|
const track = Effect.fn("Snapshot.track")(function* () {
|
||||||
if (!(yield* enabled())) return
|
if (!(yield* enabled())) return
|
||||||
const existed = yield* exists(gitdir)
|
const existed = yield* exists(gitdir)
|
||||||
yield* mkdir(gitdir)
|
yield* fs.ensureDir(gitdir).pipe(Effect.orDie)
|
||||||
if (!existed) {
|
if (!existed) {
|
||||||
yield* git(["init"], {
|
yield* git(["init"], {
|
||||||
env: { GIT_DIR: gitdir, GIT_WORK_TREE: worktree },
|
env: { GIT_DIR: gitdir, GIT_WORK_TREE: worktree },
|
||||||
|
|
@ -342,7 +342,8 @@ export namespace Snapshot {
|
||||||
|
|
||||||
export const defaultLayer = layer.pipe(
|
export const defaultLayer = layer.pipe(
|
||||||
Layer.provide(NodeChildProcessSpawner.layer),
|
Layer.provide(NodeChildProcessSpawner.layer),
|
||||||
Layer.provide(NodeFileSystem.layer),
|
Layer.provide(AppFileSystem.defaultLayer),
|
||||||
|
Layer.provide(NodeFileSystem.layer), // needed by NodeChildProcessSpawner
|
||||||
Layer.provide(NodePath.layer),
|
Layer.provide(NodePath.layer),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import { NodeFileSystem, NodePath } from "@effect/platform-node"
|
import { NodePath } from "@effect/platform-node"
|
||||||
import { Cause, Duration, Effect, FileSystem, Layer, Schedule, ServiceMap } from "effect"
|
import { Cause, Duration, Effect, Layer, Schedule, ServiceMap } from "effect"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import type { Agent } from "../agent/agent"
|
import type { Agent } from "../agent/agent"
|
||||||
|
import { AppFileSystem } from "@/filesystem"
|
||||||
import { PermissionNext } from "../permission"
|
import { PermissionNext } from "../permission"
|
||||||
import { Identifier } from "../id/id"
|
import { Identifier } from "../id/id"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
|
|
@ -44,7 +45,7 @@ export namespace TruncateEffect {
|
||||||
export const layer = Layer.effect(
|
export const layer = Layer.effect(
|
||||||
Service,
|
Service,
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const fs = yield* FileSystem.FileSystem
|
const fs = yield* AppFileSystem.Service
|
||||||
|
|
||||||
const cleanup = Effect.fn("Truncate.cleanup")(function* () {
|
const cleanup = Effect.fn("Truncate.cleanup")(function* () {
|
||||||
const cutoff = Identifier.timestamp(Identifier.create("tool", false, Date.now() - Duration.toMillis(RETENTION)))
|
const cutoff = Identifier.timestamp(Identifier.create("tool", false, Date.now() - Duration.toMillis(RETENTION)))
|
||||||
|
|
@ -101,7 +102,7 @@ export namespace TruncateEffect {
|
||||||
const preview = out.join("\n")
|
const preview = out.join("\n")
|
||||||
const file = path.join(TRUNCATION_DIR, ToolID.ascending())
|
const file = path.join(TRUNCATION_DIR, ToolID.ascending())
|
||||||
|
|
||||||
yield* fs.makeDirectory(TRUNCATION_DIR, { recursive: true }).pipe(Effect.orDie)
|
yield* fs.ensureDir(TRUNCATION_DIR).pipe(Effect.orDie)
|
||||||
yield* fs.writeFileString(file, text).pipe(Effect.orDie)
|
yield* fs.writeFileString(file, text).pipe(Effect.orDie)
|
||||||
|
|
||||||
const hint = hasTaskTool(agent)
|
const hint = hasTaskTool(agent)
|
||||||
|
|
@ -132,5 +133,5 @@ export namespace TruncateEffect {
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
export const defaultLayer = layer.pipe(Layer.provide(NodeFileSystem.layer), Layer.provide(NodePath.layer))
|
export const defaultLayer = layer.pipe(Layer.provide(AppFileSystem.defaultLayer), Layer.provide(NodePath.layer))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
import { Log } from "./log"
|
|
||||||
|
|
||||||
export namespace EventLoop {
|
|
||||||
export async function wait() {
|
|
||||||
return new Promise<void>((resolve) => {
|
|
||||||
const check = () => {
|
|
||||||
const active = [...(process as any)._getActiveHandles(), ...(process as any)._getActiveRequests()]
|
|
||||||
Log.Default.info("eventloop", {
|
|
||||||
active,
|
|
||||||
})
|
|
||||||
if ((process as any)._getActiveHandles().length === 0 && (process as any)._getActiveRequests().length === 0) {
|
|
||||||
resolve()
|
|
||||||
} else {
|
|
||||||
setImmediate(check)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
check()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { spawn as launch, type ChildProcess } from "child_process"
|
import { type ChildProcess } from "child_process"
|
||||||
|
import launch from "cross-spawn"
|
||||||
import { buffer } from "node:stream/consumers"
|
import { buffer } from "node:stream/consumers"
|
||||||
|
|
||||||
export namespace Process {
|
export namespace Process {
|
||||||
|
|
@ -97,6 +98,7 @@ export namespace Process {
|
||||||
reject(error)
|
reject(error)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
void exited.catch(() => undefined)
|
||||||
|
|
||||||
if (opts.abort) {
|
if (opts.abort) {
|
||||||
opts.abort.addEventListener("abort", abort, { once: true })
|
opts.abort.addEventListener("abort", abort, { once: true })
|
||||||
|
|
@ -113,6 +115,7 @@ export namespace Process {
|
||||||
cwd: opts.cwd,
|
cwd: opts.cwd,
|
||||||
env: opts.env,
|
env: opts.env,
|
||||||
stdin: opts.stdin,
|
stdin: opts.stdin,
|
||||||
|
shell: opts.shell,
|
||||||
abort: opts.abort,
|
abort: opts.abort,
|
||||||
kill: opts.kill,
|
kill: opts.kill,
|
||||||
timeout: opts.timeout,
|
timeout: opts.timeout,
|
||||||
|
|
@ -140,6 +143,20 @@ export namespace Process {
|
||||||
throw new RunFailedError(cmd, out.code, out.stdout, out.stderr)
|
throw new RunFailedError(cmd, out.code, out.stdout, out.stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function stop(proc: ChildProcess) {
|
||||||
|
if (process.platform !== "win32" || !proc.pid) {
|
||||||
|
proc.kill()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const out = await run(["taskkill", "/pid", String(proc.pid), "/T", "/F"], {
|
||||||
|
nothrow: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (out.code === 0) return
|
||||||
|
proc.kill()
|
||||||
|
}
|
||||||
|
|
||||||
export async function text(cmd: string[], opts: RunOptions = {}): Promise<TextResult> {
|
export async function text(cmd: string[], opts: RunOptions = {}): Promise<TextResult> {
|
||||||
const out = await run(cmd, opts)
|
const out = await run(cmd, opts)
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { $ } from "bun"
|
||||||
import { afterEach, describe, expect, test } from "bun:test"
|
import { afterEach, describe, expect, test } from "bun:test"
|
||||||
import fs from "fs/promises"
|
import fs from "fs/promises"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Deferred, Effect, Fiber, Option } from "effect"
|
import { Deferred, Effect, Option } from "effect"
|
||||||
import { tmpdir } from "../fixture/fixture"
|
import { tmpdir } from "../fixture/fixture"
|
||||||
import { watcherConfigLayer, withServices } from "../fixture/instance"
|
import { watcherConfigLayer, withServices } from "../fixture/instance"
|
||||||
import { FileWatcher } from "../../src/file/watcher"
|
import { FileWatcher } from "../../src/file/watcher"
|
||||||
|
|
@ -25,6 +25,7 @@ function withWatcher<E>(directory: string, body: Effect.Effect<void, E>) {
|
||||||
directory,
|
directory,
|
||||||
FileWatcher.layer,
|
FileWatcher.layer,
|
||||||
async (rt) => {
|
async (rt) => {
|
||||||
|
await rt.runPromise(FileWatcher.Service.use(() => Effect.void))
|
||||||
await Effect.runPromise(ready(directory))
|
await Effect.runPromise(ready(directory))
|
||||||
await Effect.runPromise(body)
|
await Effect.runPromise(body)
|
||||||
},
|
},
|
||||||
|
|
@ -54,24 +55,29 @@ function listen(directory: string, check: (evt: WatcherEvent) => boolean, hit: (
|
||||||
}
|
}
|
||||||
|
|
||||||
function wait(directory: string, check: (evt: WatcherEvent) => boolean) {
|
function wait(directory: string, check: (evt: WatcherEvent) => boolean) {
|
||||||
return Effect.callback<WatcherEvent>((resume) => {
|
return Effect.gen(function* () {
|
||||||
const cleanup = listen(directory, check, (evt) => {
|
const deferred = yield* Deferred.make<WatcherEvent>()
|
||||||
cleanup()
|
const cleanup = yield* Effect.sync(() => {
|
||||||
resume(Effect.succeed(evt))
|
let off = () => {}
|
||||||
|
off = listen(directory, check, (evt) => {
|
||||||
|
off()
|
||||||
|
Deferred.doneUnsafe(deferred, Effect.succeed(evt))
|
||||||
|
})
|
||||||
|
return off
|
||||||
})
|
})
|
||||||
return Effect.sync(cleanup)
|
return { cleanup, deferred }
|
||||||
}).pipe(Effect.timeout("5 seconds"))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function nextUpdate<E>(directory: string, check: (evt: WatcherEvent) => boolean, trigger: Effect.Effect<void, E>) {
|
function nextUpdate<E>(directory: string, check: (evt: WatcherEvent) => boolean, trigger: Effect.Effect<void, E>) {
|
||||||
return Effect.acquireUseRelease(
|
return Effect.acquireUseRelease(
|
||||||
wait(directory, check).pipe(Effect.forkChild({ startImmediately: true })),
|
wait(directory, check),
|
||||||
(fiber) =>
|
({ deferred }) =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
yield* trigger
|
yield* trigger
|
||||||
return yield* Fiber.join(fiber)
|
return yield* Deferred.await(deferred).pipe(Effect.timeout("5 seconds"))
|
||||||
}),
|
}),
|
||||||
Fiber.interrupt,
|
({ cleanup }) => Effect.sync(cleanup),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,23 +88,15 @@ function noUpdate<E>(
|
||||||
trigger: Effect.Effect<void, E>,
|
trigger: Effect.Effect<void, E>,
|
||||||
ms = 500,
|
ms = 500,
|
||||||
) {
|
) {
|
||||||
return Effect.gen(function* () {
|
return Effect.acquireUseRelease(
|
||||||
const deferred = yield* Deferred.make<WatcherEvent>()
|
wait(directory, check),
|
||||||
|
({ deferred }) =>
|
||||||
yield* Effect.acquireUseRelease(
|
Effect.gen(function* () {
|
||||||
Effect.sync(() =>
|
yield* trigger
|
||||||
listen(directory, check, (evt) => {
|
expect(yield* Deferred.await(deferred).pipe(Effect.timeoutOption(`${ms} millis`))).toEqual(Option.none())
|
||||||
Effect.runSync(Deferred.succeed(deferred, evt))
|
}),
|
||||||
}),
|
({ cleanup }) => Effect.sync(cleanup),
|
||||||
),
|
)
|
||||||
() =>
|
|
||||||
Effect.gen(function* () {
|
|
||||||
yield* trigger
|
|
||||||
expect(yield* Deferred.await(deferred).pipe(Effect.timeoutOption(`${ms} millis`))).toEqual(Option.none())
|
|
||||||
}),
|
|
||||||
(cleanup) => Effect.sync(cleanup),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function ready(directory: string) {
|
function ready(directory: string) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,319 @@
|
||||||
|
import { describe, test, expect } from "bun:test"
|
||||||
|
import { Effect, Layer } from "effect"
|
||||||
|
import { NodeFileSystem } from "@effect/platform-node"
|
||||||
|
import { AppFileSystem } from "../../src/filesystem"
|
||||||
|
import { testEffect } from "../lib/effect"
|
||||||
|
import path from "path"
|
||||||
|
|
||||||
|
const live = AppFileSystem.layer.pipe(Layer.provide(NodeFileSystem.layer))
|
||||||
|
const { effect: it } = testEffect(live)
|
||||||
|
|
||||||
|
describe("AppFileSystem", () => {
|
||||||
|
describe("isDir", () => {
|
||||||
|
it(
|
||||||
|
"returns true for directories",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
expect(yield* fs.isDir(tmp)).toBe(true)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
it(
|
||||||
|
"returns false for files",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
const file = path.join(tmp, "test.txt")
|
||||||
|
yield* fs.writeFileString(file, "hello")
|
||||||
|
expect(yield* fs.isDir(file)).toBe(false)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
it(
|
||||||
|
"returns false for non-existent paths",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
expect(yield* fs.isDir("/tmp/nonexistent-" + Math.random())).toBe(false)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("isFile", () => {
|
||||||
|
it(
|
||||||
|
"returns true for files",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
const file = path.join(tmp, "test.txt")
|
||||||
|
yield* fs.writeFileString(file, "hello")
|
||||||
|
expect(yield* fs.isFile(file)).toBe(true)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
it(
|
||||||
|
"returns false for directories",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
expect(yield* fs.isFile(tmp)).toBe(false)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("readJson / writeJson", () => {
|
||||||
|
it(
|
||||||
|
"round-trips JSON data",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
const file = path.join(tmp, "data.json")
|
||||||
|
const data = { name: "test", count: 42, nested: { ok: true } }
|
||||||
|
|
||||||
|
yield* fs.writeJson(file, data)
|
||||||
|
const result = yield* fs.readJson(file)
|
||||||
|
|
||||||
|
expect(result).toEqual(data)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("ensureDir", () => {
|
||||||
|
it(
|
||||||
|
"creates nested directories",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
const nested = path.join(tmp, "a", "b", "c")
|
||||||
|
|
||||||
|
yield* fs.ensureDir(nested)
|
||||||
|
|
||||||
|
const info = yield* fs.stat(nested)
|
||||||
|
expect(info.type).toBe("Directory")
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
it(
|
||||||
|
"is idempotent",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
const dir = path.join(tmp, "existing")
|
||||||
|
yield* fs.makeDirectory(dir)
|
||||||
|
|
||||||
|
yield* fs.ensureDir(dir)
|
||||||
|
|
||||||
|
const info = yield* fs.stat(dir)
|
||||||
|
expect(info.type).toBe("Directory")
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("writeWithDirs", () => {
|
||||||
|
it(
|
||||||
|
"creates parent directories if missing",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
const file = path.join(tmp, "deep", "nested", "file.txt")
|
||||||
|
|
||||||
|
yield* fs.writeWithDirs(file, "hello")
|
||||||
|
|
||||||
|
expect(yield* fs.readFileString(file)).toBe("hello")
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
it(
|
||||||
|
"writes directly when parent exists",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
const file = path.join(tmp, "direct.txt")
|
||||||
|
|
||||||
|
yield* fs.writeWithDirs(file, "world")
|
||||||
|
|
||||||
|
expect(yield* fs.readFileString(file)).toBe("world")
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
it(
|
||||||
|
"writes Uint8Array content",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
const file = path.join(tmp, "binary.bin")
|
||||||
|
const content = new Uint8Array([0x00, 0x01, 0x02, 0x03])
|
||||||
|
|
||||||
|
yield* fs.writeWithDirs(file, content)
|
||||||
|
|
||||||
|
const result = yield* fs.readFile(file)
|
||||||
|
expect(new Uint8Array(result)).toEqual(content)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("findUp", () => {
|
||||||
|
it(
|
||||||
|
"finds target in start directory",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
yield* fs.writeFileString(path.join(tmp, "target.txt"), "found")
|
||||||
|
|
||||||
|
const result = yield* fs.findUp("target.txt", tmp)
|
||||||
|
expect(result).toEqual([path.join(tmp, "target.txt")])
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
it(
|
||||||
|
"finds target in parent directories",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
yield* fs.writeFileString(path.join(tmp, "marker"), "root")
|
||||||
|
const child = path.join(tmp, "a", "b")
|
||||||
|
yield* fs.makeDirectory(child, { recursive: true })
|
||||||
|
|
||||||
|
const result = yield* fs.findUp("marker", child, tmp)
|
||||||
|
expect(result).toEqual([path.join(tmp, "marker")])
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
it(
|
||||||
|
"returns empty array when not found",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
const result = yield* fs.findUp("nonexistent", tmp, tmp)
|
||||||
|
expect(result).toEqual([])
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("up", () => {
|
||||||
|
it(
|
||||||
|
"finds multiple targets walking up",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
yield* fs.writeFileString(path.join(tmp, "a.txt"), "a")
|
||||||
|
yield* fs.writeFileString(path.join(tmp, "b.txt"), "b")
|
||||||
|
const child = path.join(tmp, "sub")
|
||||||
|
yield* fs.makeDirectory(child)
|
||||||
|
yield* fs.writeFileString(path.join(child, "a.txt"), "a-child")
|
||||||
|
|
||||||
|
const result = yield* fs.up({ targets: ["a.txt", "b.txt"], start: child, stop: tmp })
|
||||||
|
|
||||||
|
expect(result).toContain(path.join(child, "a.txt"))
|
||||||
|
expect(result).toContain(path.join(tmp, "a.txt"))
|
||||||
|
expect(result).toContain(path.join(tmp, "b.txt"))
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("glob", () => {
|
||||||
|
it(
|
||||||
|
"finds files matching pattern",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
yield* fs.writeFileString(path.join(tmp, "a.ts"), "a")
|
||||||
|
yield* fs.writeFileString(path.join(tmp, "b.ts"), "b")
|
||||||
|
yield* fs.writeFileString(path.join(tmp, "c.json"), "c")
|
||||||
|
|
||||||
|
const result = yield* fs.glob("*.ts", { cwd: tmp })
|
||||||
|
expect(result.sort()).toEqual(["a.ts", "b.ts"])
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
it(
|
||||||
|
"supports absolute paths",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
yield* fs.writeFileString(path.join(tmp, "file.txt"), "hello")
|
||||||
|
|
||||||
|
const result = yield* fs.glob("*.txt", { cwd: tmp, absolute: true })
|
||||||
|
expect(result).toEqual([path.join(tmp, "file.txt")])
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("globMatch", () => {
|
||||||
|
it(
|
||||||
|
"matches patterns",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
expect(fs.globMatch("*.ts", "foo.ts")).toBe(true)
|
||||||
|
expect(fs.globMatch("*.ts", "foo.json")).toBe(false)
|
||||||
|
expect(fs.globMatch("src/**", "src/a/b.ts")).toBe(true)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("globUp", () => {
|
||||||
|
it(
|
||||||
|
"finds files walking up directories",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
yield* fs.writeFileString(path.join(tmp, "root.md"), "root")
|
||||||
|
const child = path.join(tmp, "a", "b")
|
||||||
|
yield* fs.makeDirectory(child, { recursive: true })
|
||||||
|
yield* fs.writeFileString(path.join(child, "leaf.md"), "leaf")
|
||||||
|
|
||||||
|
const result = yield* fs.globUp("*.md", child, tmp)
|
||||||
|
expect(result).toContain(path.join(child, "leaf.md"))
|
||||||
|
expect(result).toContain(path.join(tmp, "root.md"))
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("built-in passthrough", () => {
|
||||||
|
it(
|
||||||
|
"exists works",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
const file = path.join(tmp, "exists.txt")
|
||||||
|
yield* fs.writeFileString(file, "yes")
|
||||||
|
|
||||||
|
expect(yield* fs.exists(file)).toBe(true)
|
||||||
|
expect(yield* fs.exists(file + ".nope")).toBe(false)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
it(
|
||||||
|
"remove works",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const fs = yield* AppFileSystem.Service
|
||||||
|
const tmp = yield* fs.makeTempDirectoryScoped()
|
||||||
|
const file = path.join(tmp, "delete-me.txt")
|
||||||
|
yield* fs.writeFileString(file, "bye")
|
||||||
|
|
||||||
|
yield* fs.remove(file)
|
||||||
|
|
||||||
|
expect(yield* fs.exists(file)).toBe(false)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("pure helpers", () => {
|
||||||
|
test("mimeType returns correct types", () => {
|
||||||
|
expect(AppFileSystem.mimeType("file.json")).toBe("application/json")
|
||||||
|
expect(AppFileSystem.mimeType("image.png")).toBe("image/png")
|
||||||
|
expect(AppFileSystem.mimeType("unknown.qzx")).toBe("application/octet-stream")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("contains checks path containment", () => {
|
||||||
|
expect(AppFileSystem.contains("/a/b", "/a/b/c")).toBe(true)
|
||||||
|
expect(AppFileSystem.contains("/a/b", "/a/c")).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("overlaps detects overlapping paths", () => {
|
||||||
|
expect(AppFileSystem.overlaps("/a/b", "/a/b/c")).toBe(true)
|
||||||
|
expect(AppFileSystem.overlaps("/a/b/c", "/a/b")).toBe(true)
|
||||||
|
expect(AppFileSystem.overlaps("/a", "/b")).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { describe, expect, test } from "bun:test"
|
||||||
|
import fs from "fs/promises"
|
||||||
|
import path from "path"
|
||||||
|
import { spawn } from "../../src/lsp/launch"
|
||||||
|
import { tmpdir } from "../fixture/fixture"
|
||||||
|
|
||||||
|
describe("lsp.launch", () => {
|
||||||
|
test("spawns cmd scripts with spaces on Windows", async () => {
|
||||||
|
if (process.platform !== "win32") return
|
||||||
|
|
||||||
|
await using tmp = await tmpdir()
|
||||||
|
const dir = path.join(tmp.path, "with space")
|
||||||
|
const file = path.join(dir, "echo cmd.cmd")
|
||||||
|
|
||||||
|
await fs.mkdir(dir, { recursive: true })
|
||||||
|
await Bun.write(file, "@echo off\r\nif %~1==--stdio exit /b 0\r\nexit /b 7\r\n")
|
||||||
|
|
||||||
|
const proc = spawn(file, ["--stdio"])
|
||||||
|
|
||||||
|
expect(await proc.exited).toBe(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
@ -2,6 +2,7 @@ import { test, expect, describe } from "bun:test"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { unlink } from "fs/promises"
|
import { unlink } from "fs/promises"
|
||||||
|
|
||||||
|
import { ProviderID } from "../../src/provider/schema"
|
||||||
import { tmpdir } from "../fixture/fixture"
|
import { tmpdir } from "../fixture/fixture"
|
||||||
import { Instance } from "../../src/project/instance"
|
import { Instance } from "../../src/project/instance"
|
||||||
import { Provider } from "../../src/provider/provider"
|
import { Provider } from "../../src/provider/provider"
|
||||||
|
|
@ -35,8 +36,8 @@ test("Bedrock: config region takes precedence over AWS_REGION env var", async ()
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["amazon-bedrock"]).toBeDefined()
|
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
|
||||||
expect(providers["amazon-bedrock"].options?.region).toBe("eu-west-1")
|
expect(providers[ProviderID.amazonBedrock].options?.region).toBe("eu-west-1")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -60,8 +61,8 @@ test("Bedrock: falls back to AWS_REGION env var when no config region", async ()
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["amazon-bedrock"]).toBeDefined()
|
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
|
||||||
expect(providers["amazon-bedrock"].options?.region).toBe("eu-west-1")
|
expect(providers[ProviderID.amazonBedrock].options?.region).toBe("eu-west-1")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -116,8 +117,8 @@ test("Bedrock: loads when bearer token from auth.json is present", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["amazon-bedrock"]).toBeDefined()
|
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
|
||||||
expect(providers["amazon-bedrock"].options?.region).toBe("eu-west-1")
|
expect(providers[ProviderID.amazonBedrock].options?.region).toBe("eu-west-1")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -161,8 +162,8 @@ test("Bedrock: config profile takes precedence over AWS_PROFILE env var", async
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["amazon-bedrock"]).toBeDefined()
|
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
|
||||||
expect(providers["amazon-bedrock"].options?.region).toBe("us-east-1")
|
expect(providers[ProviderID.amazonBedrock].options?.region).toBe("us-east-1")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -192,8 +193,8 @@ test("Bedrock: includes custom endpoint in options when specified", async () =>
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["amazon-bedrock"]).toBeDefined()
|
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
|
||||||
expect(providers["amazon-bedrock"].options?.endpoint).toBe(
|
expect(providers[ProviderID.amazonBedrock].options?.endpoint).toBe(
|
||||||
"https://bedrock-runtime.us-east-1.vpce-xxxxx.amazonaws.com",
|
"https://bedrock-runtime.us-east-1.vpce-xxxxx.amazonaws.com",
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -228,8 +229,8 @@ test("Bedrock: autoloads when AWS_WEB_IDENTITY_TOKEN_FILE is present", async ()
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["amazon-bedrock"]).toBeDefined()
|
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
|
||||||
expect(providers["amazon-bedrock"].options?.region).toBe("us-east-1")
|
expect(providers[ProviderID.amazonBedrock].options?.region).toBe("us-east-1")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -268,9 +269,9 @@ test("Bedrock: model with us. prefix should not be double-prefixed", async () =>
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["amazon-bedrock"]).toBeDefined()
|
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
|
||||||
// The model should exist with the us. prefix
|
// The model should exist with the us. prefix
|
||||||
expect(providers["amazon-bedrock"].models["us.anthropic.claude-opus-4-5-20251101-v1:0"]).toBeDefined()
|
expect(providers[ProviderID.amazonBedrock].models["us.anthropic.claude-opus-4-5-20251101-v1:0"]).toBeDefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -305,8 +306,8 @@ test("Bedrock: model with global. prefix should not be prefixed", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["amazon-bedrock"]).toBeDefined()
|
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
|
||||||
expect(providers["amazon-bedrock"].models["global.anthropic.claude-opus-4-5-20251101-v1:0"]).toBeDefined()
|
expect(providers[ProviderID.amazonBedrock].models["global.anthropic.claude-opus-4-5-20251101-v1:0"]).toBeDefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -341,8 +342,8 @@ test("Bedrock: model with eu. prefix should not be double-prefixed", async () =>
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["amazon-bedrock"]).toBeDefined()
|
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
|
||||||
expect(providers["amazon-bedrock"].models["eu.anthropic.claude-opus-4-5-20251101-v1:0"]).toBeDefined()
|
expect(providers[ProviderID.amazonBedrock].models["eu.anthropic.claude-opus-4-5-20251101-v1:0"]).toBeDefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -377,9 +378,9 @@ test("Bedrock: model without prefix in US region should get us. prefix added", a
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["amazon-bedrock"]).toBeDefined()
|
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
|
||||||
// Non-prefixed model should still be registered
|
// Non-prefixed model should still be registered
|
||||||
expect(providers["amazon-bedrock"].models["anthropic.claude-opus-4-5-20251101-v1:0"]).toBeDefined()
|
expect(providers[ProviderID.amazonBedrock].models["anthropic.claude-opus-4-5-20251101-v1:0"]).toBeDefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { test, expect } from "bun:test"
|
import { test, expect } from "bun:test"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
|
|
||||||
|
import { ProviderID } from "../../src/provider/schema"
|
||||||
import { tmpdir } from "../fixture/fixture"
|
import { tmpdir } from "../fixture/fixture"
|
||||||
import { Instance } from "../../src/project/instance"
|
import { Instance } from "../../src/project/instance"
|
||||||
import { Provider } from "../../src/provider/provider"
|
import { Provider } from "../../src/provider/provider"
|
||||||
|
|
@ -25,8 +26,8 @@ test("GitLab Duo: loads provider with API key from environment", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["gitlab"]).toBeDefined()
|
expect(providers[ProviderID.gitlab]).toBeDefined()
|
||||||
expect(providers["gitlab"].key).toBe("test-gitlab-token")
|
expect(providers[ProviderID.gitlab].key).toBe("test-gitlab-token")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -57,8 +58,8 @@ test("GitLab Duo: config instanceUrl option sets baseURL", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["gitlab"]).toBeDefined()
|
expect(providers[ProviderID.gitlab]).toBeDefined()
|
||||||
expect(providers["gitlab"].options?.instanceUrl).toBe("https://gitlab.example.com")
|
expect(providers[ProviderID.gitlab].options?.instanceUrl).toBe("https://gitlab.example.com")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -95,7 +96,7 @@ test("GitLab Duo: loads with OAuth token from auth.json", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["gitlab"]).toBeDefined()
|
expect(providers[ProviderID.gitlab]).toBeDefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -130,8 +131,8 @@ test("GitLab Duo: loads with Personal Access Token from auth.json", async () =>
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["gitlab"]).toBeDefined()
|
expect(providers[ProviderID.gitlab]).toBeDefined()
|
||||||
expect(providers["gitlab"].key).toBe("glpat-test-pat-token")
|
expect(providers[ProviderID.gitlab].key).toBe("glpat-test-pat-token")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -162,8 +163,8 @@ test("GitLab Duo: supports self-hosted instance configuration", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["gitlab"]).toBeDefined()
|
expect(providers[ProviderID.gitlab]).toBeDefined()
|
||||||
expect(providers["gitlab"].options?.instanceUrl).toBe("https://gitlab.company.internal")
|
expect(providers[ProviderID.gitlab].options?.instanceUrl).toBe("https://gitlab.company.internal")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -193,7 +194,7 @@ test("GitLab Duo: config apiKey takes precedence over environment variable", asy
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["gitlab"]).toBeDefined()
|
expect(providers[ProviderID.gitlab]).toBeDefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -216,8 +217,10 @@ test("GitLab Duo: includes context-1m beta header in aiGatewayHeaders", async ()
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["gitlab"]).toBeDefined()
|
expect(providers[ProviderID.gitlab]).toBeDefined()
|
||||||
expect(providers["gitlab"].options?.aiGatewayHeaders?.["anthropic-beta"]).toContain("context-1m-2025-08-07")
|
expect(providers[ProviderID.gitlab].options?.aiGatewayHeaders?.["anthropic-beta"]).toContain(
|
||||||
|
"context-1m-2025-08-07",
|
||||||
|
)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -250,9 +253,9 @@ test("GitLab Duo: supports feature flags configuration", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["gitlab"]).toBeDefined()
|
expect(providers[ProviderID.gitlab]).toBeDefined()
|
||||||
expect(providers["gitlab"].options?.featureFlags).toBeDefined()
|
expect(providers[ProviderID.gitlab].options?.featureFlags).toBeDefined()
|
||||||
expect(providers["gitlab"].options?.featureFlags?.duo_agent_platform_agentic_chat).toBe(true)
|
expect(providers[ProviderID.gitlab].options?.featureFlags?.duo_agent_platform_agentic_chat).toBe(true)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -275,8 +278,8 @@ test("GitLab Duo: has multiple agentic chat models available", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["gitlab"]).toBeDefined()
|
expect(providers[ProviderID.gitlab]).toBeDefined()
|
||||||
const models = Object.keys(providers["gitlab"].models)
|
const models = Object.keys(providers[ProviderID.gitlab].models)
|
||||||
expect(models.length).toBeGreaterThan(0)
|
expect(models.length).toBeGreaterThan(0)
|
||||||
expect(models).toContain("duo-chat-haiku-4-5")
|
expect(models).toContain("duo-chat-haiku-4-5")
|
||||||
expect(models).toContain("duo-chat-sonnet-4-5")
|
expect(models).toContain("duo-chat-sonnet-4-5")
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,11 @@ test("provider loaded from env variable", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["anthropic"]).toBeDefined()
|
expect(providers[ProviderID.anthropic]).toBeDefined()
|
||||||
// Provider should retain its connection source even if custom loaders
|
// Provider should retain its connection source even if custom loaders
|
||||||
// merge additional options.
|
// merge additional options.
|
||||||
expect(providers["anthropic"].source).toBe("env")
|
expect(providers[ProviderID.anthropic].source).toBe("env")
|
||||||
expect(providers["anthropic"].options.headers["anthropic-beta"]).toBeDefined()
|
expect(providers[ProviderID.anthropic].options.headers["anthropic-beta"]).toBeDefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -56,7 +56,7 @@ test("provider loaded from config with apiKey option", async () => {
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["anthropic"]).toBeDefined()
|
expect(providers[ProviderID.anthropic]).toBeDefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -80,7 +80,7 @@ test("disabled_providers excludes provider", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["anthropic"]).toBeUndefined()
|
expect(providers[ProviderID.anthropic]).toBeUndefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -105,8 +105,8 @@ test("enabled_providers restricts to only listed providers", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["anthropic"]).toBeDefined()
|
expect(providers[ProviderID.anthropic]).toBeDefined()
|
||||||
expect(providers["openai"]).toBeUndefined()
|
expect(providers[ProviderID.openai]).toBeUndefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -134,8 +134,8 @@ test("model whitelist filters models for provider", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["anthropic"]).toBeDefined()
|
expect(providers[ProviderID.anthropic]).toBeDefined()
|
||||||
const models = Object.keys(providers["anthropic"].models)
|
const models = Object.keys(providers[ProviderID.anthropic].models)
|
||||||
expect(models).toContain("claude-sonnet-4-20250514")
|
expect(models).toContain("claude-sonnet-4-20250514")
|
||||||
expect(models.length).toBe(1)
|
expect(models.length).toBe(1)
|
||||||
},
|
},
|
||||||
|
|
@ -165,8 +165,8 @@ test("model blacklist excludes specific models", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["anthropic"]).toBeDefined()
|
expect(providers[ProviderID.anthropic]).toBeDefined()
|
||||||
const models = Object.keys(providers["anthropic"].models)
|
const models = Object.keys(providers[ProviderID.anthropic].models)
|
||||||
expect(models).not.toContain("claude-sonnet-4-20250514")
|
expect(models).not.toContain("claude-sonnet-4-20250514")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
@ -200,9 +200,9 @@ test("custom model alias via config", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["anthropic"]).toBeDefined()
|
expect(providers[ProviderID.anthropic]).toBeDefined()
|
||||||
expect(providers["anthropic"].models["my-alias"]).toBeDefined()
|
expect(providers[ProviderID.anthropic].models["my-alias"]).toBeDefined()
|
||||||
expect(providers["anthropic"].models["my-alias"].name).toBe("My Custom Alias")
|
expect(providers[ProviderID.anthropic].models["my-alias"].name).toBe("My Custom Alias")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -243,9 +243,9 @@ test("custom provider with npm package", async () => {
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["custom-provider"]).toBeDefined()
|
expect(providers[ProviderID.make("custom-provider")]).toBeDefined()
|
||||||
expect(providers["custom-provider"].name).toBe("Custom Provider")
|
expect(providers[ProviderID.make("custom-provider")].name).toBe("Custom Provider")
|
||||||
expect(providers["custom-provider"].models["custom-model"]).toBeDefined()
|
expect(providers[ProviderID.make("custom-provider")].models["custom-model"]).toBeDefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -276,10 +276,10 @@ test("env variable takes precedence, config merges options", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["anthropic"]).toBeDefined()
|
expect(providers[ProviderID.anthropic]).toBeDefined()
|
||||||
// Config options should be merged
|
// Config options should be merged
|
||||||
expect(providers["anthropic"].options.timeout).toBe(60000)
|
expect(providers[ProviderID.anthropic].options.timeout).toBe(60000)
|
||||||
expect(providers["anthropic"].options.chunkTimeout).toBe(15000)
|
expect(providers[ProviderID.anthropic].options.chunkTimeout).toBe(15000)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -446,8 +446,8 @@ test("provider with baseURL from config", async () => {
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["custom-openai"]).toBeDefined()
|
expect(providers[ProviderID.make("custom-openai")]).toBeDefined()
|
||||||
expect(providers["custom-openai"].options.baseURL).toBe("https://custom.openai.com/v1")
|
expect(providers[ProviderID.make("custom-openai")].options.baseURL).toBe("https://custom.openai.com/v1")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -484,7 +484,7 @@ test("model cost defaults to zero when not specified", async () => {
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
const model = providers["test-provider"].models["test-model"]
|
const model = providers[ProviderID.make("test-provider")].models["test-model"]
|
||||||
expect(model.cost.input).toBe(0)
|
expect(model.cost.input).toBe(0)
|
||||||
expect(model.cost.output).toBe(0)
|
expect(model.cost.output).toBe(0)
|
||||||
expect(model.cost.cache.read).toBe(0)
|
expect(model.cost.cache.read).toBe(0)
|
||||||
|
|
@ -522,7 +522,7 @@ test("model options are merged from existing model", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
const model = providers["anthropic"].models["claude-sonnet-4-20250514"]
|
const model = providers[ProviderID.anthropic].models["claude-sonnet-4-20250514"]
|
||||||
expect(model.options.customOption).toBe("custom-value")
|
expect(model.options.customOption).toBe("custom-value")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
@ -551,7 +551,7 @@ test("provider removed when all models filtered out", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["anthropic"]).toBeUndefined()
|
expect(providers[ProviderID.anthropic]).toBeUndefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -629,7 +629,7 @@ test("getModel uses realIdByKey for aliased models", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["anthropic"].models["my-sonnet"]).toBeDefined()
|
expect(providers[ProviderID.anthropic].models["my-sonnet"]).toBeDefined()
|
||||||
|
|
||||||
const model = await Provider.getModel(ProviderID.anthropic, ModelID.make("my-sonnet"))
|
const model = await Provider.getModel(ProviderID.anthropic, ModelID.make("my-sonnet"))
|
||||||
expect(model).toBeDefined()
|
expect(model).toBeDefined()
|
||||||
|
|
@ -673,7 +673,7 @@ test("provider api field sets model api.url", async () => {
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
// api field is stored on model.api.url, used by getSDK to set baseURL
|
// api field is stored on model.api.url, used by getSDK to set baseURL
|
||||||
expect(providers["custom-api"].models["model-1"].api.url).toBe("https://api.example.com/v1")
|
expect(providers[ProviderID.make("custom-api")].models["model-1"].api.url).toBe("https://api.example.com/v1")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -712,7 +712,7 @@ test("explicit baseURL overrides api field", async () => {
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["custom-api"].options.baseURL).toBe("https://custom.override.com/v1")
|
expect(providers[ProviderID.make("custom-api")].options.baseURL).toBe("https://custom.override.com/v1")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -744,7 +744,7 @@ test("model inherits properties from existing database model", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
const model = providers["anthropic"].models["claude-sonnet-4-20250514"]
|
const model = providers[ProviderID.anthropic].models["claude-sonnet-4-20250514"]
|
||||||
expect(model.name).toBe("Custom Name for Sonnet")
|
expect(model.name).toBe("Custom Name for Sonnet")
|
||||||
expect(model.capabilities.toolcall).toBe(true)
|
expect(model.capabilities.toolcall).toBe(true)
|
||||||
expect(model.capabilities.attachment).toBe(true)
|
expect(model.capabilities.attachment).toBe(true)
|
||||||
|
|
@ -772,7 +772,7 @@ test("disabled_providers prevents loading even with env var", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["openai"]).toBeUndefined()
|
expect(providers[ProviderID.openai]).toBeUndefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -826,8 +826,8 @@ test("whitelist and blacklist can be combined", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["anthropic"]).toBeDefined()
|
expect(providers[ProviderID.anthropic]).toBeDefined()
|
||||||
const models = Object.keys(providers["anthropic"].models)
|
const models = Object.keys(providers[ProviderID.anthropic].models)
|
||||||
expect(models).toContain("claude-sonnet-4-20250514")
|
expect(models).toContain("claude-sonnet-4-20250514")
|
||||||
expect(models).not.toContain("claude-opus-4-20250514")
|
expect(models).not.toContain("claude-opus-4-20250514")
|
||||||
expect(models.length).toBe(1)
|
expect(models.length).toBe(1)
|
||||||
|
|
@ -865,7 +865,7 @@ test("model modalities default correctly", async () => {
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
const model = providers["test-provider"].models["test-model"]
|
const model = providers[ProviderID.make("test-provider")].models["test-model"]
|
||||||
expect(model.capabilities.input.text).toBe(true)
|
expect(model.capabilities.input.text).toBe(true)
|
||||||
expect(model.capabilities.output.text).toBe(true)
|
expect(model.capabilities.output.text).toBe(true)
|
||||||
},
|
},
|
||||||
|
|
@ -908,7 +908,7 @@ test("model with custom cost values", async () => {
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
const model = providers["test-provider"].models["test-model"]
|
const model = providers[ProviderID.make("test-provider")].models["test-model"]
|
||||||
expect(model.cost.input).toBe(5)
|
expect(model.cost.input).toBe(5)
|
||||||
expect(model.cost.output).toBe(15)
|
expect(model.cost.output).toBe(15)
|
||||||
expect(model.cost.cache.read).toBe(2.5)
|
expect(model.cost.cache.read).toBe(2.5)
|
||||||
|
|
@ -1009,10 +1009,10 @@ test("multiple providers can be configured simultaneously", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["anthropic"]).toBeDefined()
|
expect(providers[ProviderID.anthropic]).toBeDefined()
|
||||||
expect(providers["openai"]).toBeDefined()
|
expect(providers[ProviderID.openai]).toBeDefined()
|
||||||
expect(providers["anthropic"].options.timeout).toBe(30000)
|
expect(providers[ProviderID.anthropic].options.timeout).toBe(30000)
|
||||||
expect(providers["openai"].options.timeout).toBe(60000)
|
expect(providers[ProviderID.openai].options.timeout).toBe(60000)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -1050,9 +1050,9 @@ test("provider with custom npm package", async () => {
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["local-llm"]).toBeDefined()
|
expect(providers[ProviderID.make("local-llm")]).toBeDefined()
|
||||||
expect(providers["local-llm"].models["llama-3"].api.npm).toBe("@ai-sdk/openai-compatible")
|
expect(providers[ProviderID.make("local-llm")].models["llama-3"].api.npm).toBe("@ai-sdk/openai-compatible")
|
||||||
expect(providers["local-llm"].options.baseURL).toBe("http://localhost:11434/v1")
|
expect(providers[ProviderID.make("local-llm")].options.baseURL).toBe("http://localhost:11434/v1")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -1087,7 +1087,7 @@ test("model alias name defaults to alias key when id differs", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["anthropic"].models["sonnet"].name).toBe("sonnet")
|
expect(providers[ProviderID.anthropic].models["sonnet"].name).toBe("sonnet")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -1127,9 +1127,9 @@ test("provider with multiple env var options only includes apiKey when single en
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["multi-env"]).toBeDefined()
|
expect(providers[ProviderID.make("multi-env")]).toBeDefined()
|
||||||
// When multiple env options exist, key should NOT be auto-set
|
// When multiple env options exist, key should NOT be auto-set
|
||||||
expect(providers["multi-env"].key).toBeUndefined()
|
expect(providers[ProviderID.make("multi-env")].key).toBeUndefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -1169,9 +1169,9 @@ test("provider with single env var includes apiKey automatically", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["single-env"]).toBeDefined()
|
expect(providers[ProviderID.make("single-env")]).toBeDefined()
|
||||||
// Single env option should auto-set key
|
// Single env option should auto-set key
|
||||||
expect(providers["single-env"].key).toBe("my-api-key")
|
expect(providers[ProviderID.make("single-env")].key).toBe("my-api-key")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -1206,7 +1206,7 @@ test("model cost overrides existing cost values", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
const model = providers["anthropic"].models["claude-sonnet-4-20250514"]
|
const model = providers[ProviderID.anthropic].models["claude-sonnet-4-20250514"]
|
||||||
expect(model.cost.input).toBe(999)
|
expect(model.cost.input).toBe(999)
|
||||||
expect(model.cost.output).toBe(888)
|
expect(model.cost.output).toBe(888)
|
||||||
},
|
},
|
||||||
|
|
@ -1253,9 +1253,9 @@ test("completely new provider not in database can be configured", async () => {
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["brand-new-provider"]).toBeDefined()
|
expect(providers[ProviderID.make("brand-new-provider")]).toBeDefined()
|
||||||
expect(providers["brand-new-provider"].name).toBe("Brand New")
|
expect(providers[ProviderID.make("brand-new-provider")].name).toBe("Brand New")
|
||||||
const model = providers["brand-new-provider"].models["new-model"]
|
const model = providers[ProviderID.make("brand-new-provider")].models["new-model"]
|
||||||
expect(model.capabilities.reasoning).toBe(true)
|
expect(model.capabilities.reasoning).toBe(true)
|
||||||
expect(model.capabilities.attachment).toBe(true)
|
expect(model.capabilities.attachment).toBe(true)
|
||||||
expect(model.capabilities.input.image).toBe(true)
|
expect(model.capabilities.input.image).toBe(true)
|
||||||
|
|
@ -1288,11 +1288,11 @@ test("disabled_providers and enabled_providers interaction", async () => {
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
// anthropic: in enabled, not in disabled = allowed
|
// anthropic: in enabled, not in disabled = allowed
|
||||||
expect(providers["anthropic"]).toBeDefined()
|
expect(providers[ProviderID.anthropic]).toBeDefined()
|
||||||
// openai: in enabled, but also in disabled = NOT allowed
|
// openai: in enabled, but also in disabled = NOT allowed
|
||||||
expect(providers["openai"]).toBeUndefined()
|
expect(providers[ProviderID.openai]).toBeUndefined()
|
||||||
// google: not in enabled = NOT allowed (even though not disabled)
|
// google: not in enabled = NOT allowed (even though not disabled)
|
||||||
expect(providers["google"]).toBeUndefined()
|
expect(providers[ProviderID.google]).toBeUndefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -1327,7 +1327,7 @@ test("model with tool_call false", async () => {
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["no-tools"].models["basic-model"].capabilities.toolcall).toBe(false)
|
expect(providers[ProviderID.make("no-tools")].models["basic-model"].capabilities.toolcall).toBe(false)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -1362,7 +1362,7 @@ test("model defaults tool_call to true when not specified", async () => {
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["default-tools"].models["model"].capabilities.toolcall).toBe(true)
|
expect(providers[ProviderID.make("default-tools")].models["model"].capabilities.toolcall).toBe(true)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -1401,7 +1401,7 @@ test("model headers are preserved", async () => {
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
const model = providers["headers-provider"].models["model"]
|
const model = providers[ProviderID.make("headers-provider")].models["model"]
|
||||||
expect(model.headers).toEqual({
|
expect(model.headers).toEqual({
|
||||||
"X-Custom-Header": "custom-value",
|
"X-Custom-Header": "custom-value",
|
||||||
Authorization: "Bearer special-token",
|
Authorization: "Bearer special-token",
|
||||||
|
|
@ -1445,7 +1445,7 @@ test("provider env fallback - second env var used if first missing", async () =>
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
// Provider should load because fallback env var is set
|
// Provider should load because fallback env var is set
|
||||||
expect(providers["fallback-env"]).toBeDefined()
|
expect(providers[ProviderID.make("fallback-env")]).toBeDefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -1506,7 +1506,7 @@ test("provider name defaults to id when not in database", async () => {
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["my-custom-id"].name).toBe("my-custom-id")
|
expect(providers[ProviderID.make("my-custom-id")].name).toBe("my-custom-id")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -1689,7 +1689,7 @@ test("model limit defaults to zero when not specified", async () => {
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
const model = providers["no-limit"].models["model"]
|
const model = providers[ProviderID.make("no-limit")].models["model"]
|
||||||
expect(model.limit.context).toBe(0)
|
expect(model.limit.context).toBe(0)
|
||||||
expect(model.limit.output).toBe(0)
|
expect(model.limit.output).toBe(0)
|
||||||
},
|
},
|
||||||
|
|
@ -1725,10 +1725,10 @@ test("provider options are deeply merged", async () => {
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
// Custom options should be merged
|
// Custom options should be merged
|
||||||
expect(providers["anthropic"].options.timeout).toBe(30000)
|
expect(providers[ProviderID.anthropic].options.timeout).toBe(30000)
|
||||||
expect(providers["anthropic"].options.headers["X-Custom"]).toBe("custom-value")
|
expect(providers[ProviderID.anthropic].options.headers["X-Custom"]).toBe("custom-value")
|
||||||
// anthropic custom loader adds its own headers, they should coexist
|
// anthropic custom loader adds its own headers, they should coexist
|
||||||
expect(providers["anthropic"].options.headers["anthropic-beta"]).toBeDefined()
|
expect(providers[ProviderID.anthropic].options.headers["anthropic-beta"]).toBeDefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -1762,7 +1762,7 @@ test("custom model inherits npm package from models.dev provider config", async
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
const model = providers["openai"].models["my-custom-model"]
|
const model = providers[ProviderID.openai].models["my-custom-model"]
|
||||||
expect(model).toBeDefined()
|
expect(model).toBeDefined()
|
||||||
expect(model.api.npm).toBe("@ai-sdk/openai")
|
expect(model.api.npm).toBe("@ai-sdk/openai")
|
||||||
},
|
},
|
||||||
|
|
@ -1797,15 +1797,15 @@ test("custom model inherits api.url from models.dev provider", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["openrouter"]).toBeDefined()
|
expect(providers[ProviderID.openrouter]).toBeDefined()
|
||||||
|
|
||||||
// New model not in database should inherit api.url from provider
|
// New model not in database should inherit api.url from provider
|
||||||
const intellect = providers["openrouter"].models["prime-intellect/intellect-3"]
|
const intellect = providers[ProviderID.openrouter].models["prime-intellect/intellect-3"]
|
||||||
expect(intellect).toBeDefined()
|
expect(intellect).toBeDefined()
|
||||||
expect(intellect.api.url).toBe("https://openrouter.ai/api/v1")
|
expect(intellect.api.url).toBe("https://openrouter.ai/api/v1")
|
||||||
|
|
||||||
// Another new model should also inherit api.url
|
// Another new model should also inherit api.url
|
||||||
const deepseek = providers["openrouter"].models["deepseek/deepseek-r1-0528"]
|
const deepseek = providers[ProviderID.openrouter].models["deepseek/deepseek-r1-0528"]
|
||||||
expect(deepseek).toBeDefined()
|
expect(deepseek).toBeDefined()
|
||||||
expect(deepseek.api.url).toBe("https://openrouter.ai/api/v1")
|
expect(deepseek.api.url).toBe("https://openrouter.ai/api/v1")
|
||||||
expect(deepseek.name).toBe("DeepSeek R1")
|
expect(deepseek.name).toBe("DeepSeek R1")
|
||||||
|
|
@ -1832,7 +1832,7 @@ test("model variants are generated for reasoning models", async () => {
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
// Claude sonnet 4 has reasoning capability
|
// Claude sonnet 4 has reasoning capability
|
||||||
const model = providers["anthropic"].models["claude-sonnet-4-20250514"]
|
const model = providers[ProviderID.anthropic].models["claude-sonnet-4-20250514"]
|
||||||
expect(model.capabilities.reasoning).toBe(true)
|
expect(model.capabilities.reasoning).toBe(true)
|
||||||
expect(model.variants).toBeDefined()
|
expect(model.variants).toBeDefined()
|
||||||
expect(Object.keys(model.variants!).length).toBeGreaterThan(0)
|
expect(Object.keys(model.variants!).length).toBeGreaterThan(0)
|
||||||
|
|
@ -1869,7 +1869,7 @@ test("model variants can be disabled via config", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
const model = providers["anthropic"].models["claude-sonnet-4-20250514"]
|
const model = providers[ProviderID.anthropic].models["claude-sonnet-4-20250514"]
|
||||||
expect(model.variants).toBeDefined()
|
expect(model.variants).toBeDefined()
|
||||||
expect(model.variants!["high"]).toBeUndefined()
|
expect(model.variants!["high"]).toBeUndefined()
|
||||||
// max variant should still exist
|
// max variant should still exist
|
||||||
|
|
@ -1912,7 +1912,7 @@ test("model variants can be customized via config", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
const model = providers["anthropic"].models["claude-sonnet-4-20250514"]
|
const model = providers[ProviderID.anthropic].models["claude-sonnet-4-20250514"]
|
||||||
expect(model.variants!["high"]).toBeDefined()
|
expect(model.variants!["high"]).toBeDefined()
|
||||||
expect(model.variants!["high"].thinking.budgetTokens).toBe(20000)
|
expect(model.variants!["high"].thinking.budgetTokens).toBe(20000)
|
||||||
},
|
},
|
||||||
|
|
@ -1951,7 +1951,7 @@ test("disabled key is stripped from variant config", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
const model = providers["anthropic"].models["claude-sonnet-4-20250514"]
|
const model = providers[ProviderID.anthropic].models["claude-sonnet-4-20250514"]
|
||||||
expect(model.variants!["max"]).toBeDefined()
|
expect(model.variants!["max"]).toBeDefined()
|
||||||
expect(model.variants!["max"].disabled).toBeUndefined()
|
expect(model.variants!["max"].disabled).toBeUndefined()
|
||||||
expect(model.variants!["max"].customField).toBe("test")
|
expect(model.variants!["max"].customField).toBe("test")
|
||||||
|
|
@ -1989,7 +1989,7 @@ test("all variants can be disabled via config", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
const model = providers["anthropic"].models["claude-sonnet-4-20250514"]
|
const model = providers[ProviderID.anthropic].models["claude-sonnet-4-20250514"]
|
||||||
expect(model.variants).toBeDefined()
|
expect(model.variants).toBeDefined()
|
||||||
expect(Object.keys(model.variants!).length).toBe(0)
|
expect(Object.keys(model.variants!).length).toBe(0)
|
||||||
},
|
},
|
||||||
|
|
@ -2027,7 +2027,7 @@ test("variant config merges with generated variants", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
const model = providers["anthropic"].models["claude-sonnet-4-20250514"]
|
const model = providers[ProviderID.anthropic].models["claude-sonnet-4-20250514"]
|
||||||
expect(model.variants!["high"]).toBeDefined()
|
expect(model.variants!["high"]).toBeDefined()
|
||||||
// Should have both the generated thinking config and the custom option
|
// Should have both the generated thinking config and the custom option
|
||||||
expect(model.variants!["high"].thinking).toBeDefined()
|
expect(model.variants!["high"].thinking).toBeDefined()
|
||||||
|
|
@ -2065,7 +2065,7 @@ test("variants filtered in second pass for database models", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
const model = providers["openai"].models["gpt-5"]
|
const model = providers[ProviderID.openai].models["gpt-5"]
|
||||||
expect(model.variants).toBeDefined()
|
expect(model.variants).toBeDefined()
|
||||||
expect(model.variants!["high"]).toBeUndefined()
|
expect(model.variants!["high"]).toBeUndefined()
|
||||||
// Other variants should still exist
|
// Other variants should still exist
|
||||||
|
|
@ -2111,7 +2111,7 @@ test("custom model with variants enabled and disabled", async () => {
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
const model = providers["custom-reasoning"].models["reasoning-model"]
|
const model = providers[ProviderID.make("custom-reasoning")].models["reasoning-model"]
|
||||||
expect(model.variants).toBeDefined()
|
expect(model.variants).toBeDefined()
|
||||||
// Enabled variants should exist
|
// Enabled variants should exist
|
||||||
expect(model.variants!["low"]).toBeDefined()
|
expect(model.variants!["low"]).toBeDefined()
|
||||||
|
|
@ -2169,8 +2169,8 @@ test("Google Vertex: retains baseURL for custom proxy", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["vertex-proxy"]).toBeDefined()
|
expect(providers[ProviderID.make("vertex-proxy")]).toBeDefined()
|
||||||
expect(providers["vertex-proxy"].options.baseURL).toBe("https://my-proxy.com/v1")
|
expect(providers[ProviderID.make("vertex-proxy")].options.baseURL).toBe("https://my-proxy.com/v1")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -2214,7 +2214,7 @@ test("Google Vertex: supports OpenAI compatible models", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
const model = providers["vertex-openai"].models["gpt-4"]
|
const model = providers[ProviderID.make("vertex-openai")].models["gpt-4"]
|
||||||
|
|
||||||
expect(model).toBeDefined()
|
expect(model).toBeDefined()
|
||||||
expect(model.api.npm).toBe("@ai-sdk/openai-compatible")
|
expect(model.api.npm).toBe("@ai-sdk/openai-compatible")
|
||||||
|
|
@ -2242,7 +2242,7 @@ test("cloudflare-ai-gateway loads with env variables", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["cloudflare-ai-gateway"]).toBeDefined()
|
expect(providers[ProviderID.make("cloudflare-ai-gateway")]).toBeDefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -2274,8 +2274,8 @@ test("cloudflare-ai-gateway forwards config metadata options", async () => {
|
||||||
},
|
},
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["cloudflare-ai-gateway"]).toBeDefined()
|
expect(providers[ProviderID.make("cloudflare-ai-gateway")]).toBeDefined()
|
||||||
expect(providers["cloudflare-ai-gateway"].options.metadata).toEqual({
|
expect(providers[ProviderID.make("cloudflare-ai-gateway")].options.metadata).toEqual({
|
||||||
invoked_by: "test",
|
invoked_by: "test",
|
||||||
project: "opencode",
|
project: "opencode",
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { MessageV2 } from "../../src/session/message-v2"
|
||||||
import type { Provider } from "../../src/provider/provider"
|
import type { Provider } from "../../src/provider/provider"
|
||||||
import { ModelID, ProviderID } from "../../src/provider/schema"
|
import { ModelID, ProviderID } from "../../src/provider/schema"
|
||||||
import { SessionID, MessageID, PartID } from "../../src/session/schema"
|
import { SessionID, MessageID, PartID } from "../../src/session/schema"
|
||||||
|
import { Question } from "../../src/question"
|
||||||
|
|
||||||
const sessionID = SessionID.make("session")
|
const sessionID = SessionID.make("session")
|
||||||
const providerID = ProviderID.make("test")
|
const providerID = ProviderID.make("test")
|
||||||
|
|
@ -915,4 +916,15 @@ describe("session.message-v2.fromError", () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("serializes tagged errors with their message", () => {
|
||||||
|
const result = MessageV2.fromError(new Question.RejectedError(), { providerID })
|
||||||
|
|
||||||
|
expect(result).toStrictEqual({
|
||||||
|
name: "UnknownError",
|
||||||
|
data: {
|
||||||
|
message: "The user dismissed this question",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
|
import fs from "fs/promises"
|
||||||
|
import path from "path"
|
||||||
import { Process } from "../../src/util/process"
|
import { Process } from "../../src/util/process"
|
||||||
import { tmpdir } from "../fixture/fixture"
|
import { tmpdir } from "../fixture/fixture"
|
||||||
|
|
||||||
|
|
@ -74,4 +76,53 @@ describe("util.process", () => {
|
||||||
})
|
})
|
||||||
expect(out.stdout.toString()).toBe("set")
|
expect(out.stdout.toString()).toBe("set")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("uses shell in run on Windows", async () => {
|
||||||
|
if (process.platform !== "win32") return
|
||||||
|
|
||||||
|
const out = await Process.run(["set", "OPENCODE_TEST_SHELL"], {
|
||||||
|
shell: true,
|
||||||
|
env: {
|
||||||
|
OPENCODE_TEST_SHELL: "ok",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(out.code).toBe(0)
|
||||||
|
expect(out.stdout.toString()).toContain("OPENCODE_TEST_SHELL=ok")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("runs cmd scripts with spaces on Windows without shell", async () => {
|
||||||
|
if (process.platform !== "win32") return
|
||||||
|
|
||||||
|
await using tmp = await tmpdir()
|
||||||
|
const dir = path.join(tmp.path, "with space")
|
||||||
|
const file = path.join(dir, "echo cmd.cmd")
|
||||||
|
|
||||||
|
await fs.mkdir(dir, { recursive: true })
|
||||||
|
await Bun.write(file, "@echo off\r\nif %~1==--stdio exit /b 0\r\nexit /b 7\r\n")
|
||||||
|
|
||||||
|
const proc = Process.spawn([file, "--stdio"], {
|
||||||
|
stdin: "pipe",
|
||||||
|
stdout: "pipe",
|
||||||
|
stderr: "pipe",
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(await proc.exited).toBe(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("rejects missing commands without leaking unhandled errors", async () => {
|
||||||
|
await using tmp = await tmpdir()
|
||||||
|
const cmd = path.join(tmp.path, "missing" + (process.platform === "win32" ? ".cmd" : ""))
|
||||||
|
const err = await Process.spawn([cmd], {
|
||||||
|
stdin: "pipe",
|
||||||
|
stdout: "pipe",
|
||||||
|
stderr: "pipe",
|
||||||
|
}).exited.catch((err) => err)
|
||||||
|
|
||||||
|
expect(err).toBeInstanceOf(Error)
|
||||||
|
if (!(err instanceof Error)) throw err
|
||||||
|
expect(err).toMatchObject({
|
||||||
|
code: "ENOENT",
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -7,45 +7,55 @@ import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
export const console = config.console
|
||||||
export const email = `mailto:${config.email}`
|
export const email = `mailto:${config.email}`
|
||||||
|
|
||||||
OpenCode Go هو اشتراك منخفض التكلفة بقيمة **10 دولارات شهرياً** يمنحك وصولاً موثوقاً إلى نماذج البرمجة المفتوحة الشائعة.
|
OpenCode Go هو اشتراك منخفض التكلفة — **5 دولارات للشهر الأول**، ثم **10 دولارات/شهريًا** — يمنحك وصولًا موثوقًا إلى نماذج البرمجة المفتوحة الشهيرة.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
OpenCode Go حالياً في مرحلة تجريبية (beta).
|
OpenCode Go حاليًا في المرحلة التجريبية (beta).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
يعمل Go مثل أي مزود آخر في OpenCode. تشترك في OpenCode Go وتحصل على مفتاح API الخاص بك. إنه **اختياري تماماً** ولا تحتاج إلى استخدامه لاستخدام OpenCode.
|
يعمل Go مثل أي مزود آخر في OpenCode. أنت تشترك في OpenCode Go و
|
||||||
|
تحصل على مفتاح API الخاص بك. إنه **اختياري تمامًا** ولا تحتاج إلى استخدامه
|
||||||
|
لاستخدام OpenCode.
|
||||||
|
|
||||||
صُمم بشكل أساسي للمستخدمين الدوليين، مع استضافة النماذج في الولايات المتحدة والاتحاد الأوروبي وسنغافورة لضمان وصول عالمي مستقر.
|
تم تصميمه بشكل أساسي للمستخدمين الدوليين، مع نماذج مستضافة في الولايات المتحدة، والاتحاد الأوروبي، وسنغافورة من أجل وصول عالمي مستقر.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## الخلفية (Background)
|
## الخلفية
|
||||||
|
|
||||||
أصبحت النماذج المفتوحة جيدة حقاً. فهي تصل الآن إلى أداء قريب من النماذج المملوكة لمهام البرمجة. ولأن العديد من المزودين يمكنهم تقديمها بشكل تنافسي، فهي عادة ما تكون أرخص بكثير.
|
أصبحت النماذج المفتوحة جيدة جدًا. لقد وصلت الآن إلى أداء يقترب من
|
||||||
|
النماذج المغلقة (المملوكة) في مهام البرمجة. ولأن العديد من المزودين يمكنهم تقديمها
|
||||||
|
بشكل تنافسي، فإنها عادة ما تكون أرخص بكثير.
|
||||||
|
|
||||||
ومع ذلك، فإن الحصول على وصول موثوق ومنخفض الكمون (low latency) إليها قد يكون صعباً. يختلف المزودون في الجودة والتوافر.
|
ومع ذلك، قد يكون الحصول على وصول موثوق وبزمن انتقال منخفض (low latency) إليها أمرًا صعبًا. يختلف المزودون
|
||||||
|
في الجودة والتوافر.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
قمنا باختبار مجموعة مختارة من النماذج والمزودين الذين يعملون بشكل جيد مع OpenCode.
|
لقد اختبرنا مجموعة مختارة من النماذج والمزودين الذين يعملون بشكل جيد مع OpenCode.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
لإصلاح ذلك، قمنا ببعض الأشياء:
|
لحل هذه المشكلة، قمنا ببعض الأشياء:
|
||||||
|
|
||||||
1. اختبرنا مجموعة مختارة من النماذج المفتوحة وتحدثنا مع فرقهم حول أفضل طريقة لتشغيلها.
|
1. اختبرنا مجموعة مختارة من النماذج المفتوحة وتحدثنا مع فرقهم حول أفضل السبل
|
||||||
2. عملنا بعد ذلك مع عدد قليل من المزودين للتأكد من تقديمها بشكل صحيح.
|
لإدارتها.
|
||||||
3. أخيراً، قمنا بقياس أداء (benchmark) مزيج النموذج/المزود وتوصلنا إلى قائمة نشعر بالراحة في التوصية بها.
|
2. ثم عملنا مع عدد قليل من المزودين للتأكد من أنه يتم تقديمها
|
||||||
|
بشكل صحيح.
|
||||||
|
3. أخيرًا، قمنا بعمل تقييم لأداء (benchmarked) الجمع بين النموذج/المزود وتوصلنا
|
||||||
|
إلى قائمة نشعر بالرضا في التوصية بها.
|
||||||
|
|
||||||
يمنحك OpenCode Go الوصول إلى هذه النماذج مقابل **10 دولارات شهرياً**.
|
يمنحك OpenCode Go الوصول إلى هذه النماذج مقابل **5 دولارات لشهرك الأول**، ثم **10 دولارات/شهريًا**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## كيف يعمل (How it works)
|
## كيف يعمل
|
||||||
|
|
||||||
يعمل OpenCode Go مثل أي مزود آخر في OpenCode.
|
يعمل OpenCode Go مثل أي مزود آخر في OpenCode.
|
||||||
|
|
||||||
1. قم بتسجيل الدخول إلى **<a href={console}>OpenCode Zen</a>**، واشترك في Go، وانسخ مفتاح API الخاص بك.
|
1. تقوم بتسجيل الدخول إلى **<a href={console}>OpenCode Zen</a>**، وتشترك في Go، و
|
||||||
2. قم بتشغيل الأمر `/connect` في واجهة TUI، وحدد `OpenCode Go`، والصق مفتاح API الخاص بك.
|
تنسخ مفتاح API الخاص بك.
|
||||||
3. قم بتشغيل `/models` في واجهة TUI لرؤية قائمة النماذج المتاحة من خلال Go.
|
2. تقوم بتشغيل الأمر `/connect` في الـ TUI، وتختار `OpenCode Go`، وتلصق
|
||||||
|
مفتاح API الخاص بك.
|
||||||
|
3. قم بتشغيل `/models` في الـ TUI لرؤية قائمة النماذج المتاحة عبر Go.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
يمكن لعضو واحد فقط لكل مساحة عمل (workspace) الاشتراك في OpenCode Go.
|
يمكن لعضو واحد فقط لكل مساحة عمل (workspace) الاشتراك في OpenCode Go.
|
||||||
|
|
@ -56,90 +66,84 @@ OpenCode Go حالياً في مرحلة تجريبية (beta).
|
||||||
- **GLM-5**
|
- **GLM-5**
|
||||||
- **Kimi K2.5**
|
- **Kimi K2.5**
|
||||||
- **MiniMax M2.5**
|
- **MiniMax M2.5**
|
||||||
|
- **MiniMax M2.7**
|
||||||
|
|
||||||
قد تتغير قائمة النماذج ونحن نختبر ونضيف نماذج جديدة.
|
قد تتغير قائمة النماذج كلما اختبرنا وأضفنا نماذج جديدة.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## حدود الاستخدام (Usage limits)
|
## حدود الاستخدام
|
||||||
|
|
||||||
يتضمن OpenCode Go الحدود التالية:
|
يتضمن OpenCode Go الحدود التالية:
|
||||||
|
|
||||||
- **حد 5 ساعات** — 12 دولاراً من الاستخدام
|
- **حد الـ 5 ساعات** — 12 دولارًا من الاستخدام
|
||||||
- **حد أسبوعي** — 30 دولاراً من الاستخدام
|
- **الحد الأسبوعي** — 30 دولارًا من الاستخدام
|
||||||
- **حد شهري** — 60 دولاراً من الاستخدام
|
- **الحد الشهري** — 60 دولارًا من الاستخدام
|
||||||
|
|
||||||
يتم تعريف الحدود بقيمة الدولار. هذا يعني أن عدد طلباتك الفعلي يعتمد على النموذج الذي تستخدمه. تسمح النماذج الأرخص مثل MiniMax M2.5 بمزيد من الطلبات، بينما تسمح النماذج الأعلى تكلفة مثل GLM-5 بعدد أقل.
|
يتم تحديد الحدود بقيمة الدولار. هذا يعني أن عدد طلباتك الفعلي يعتمد على النموذج الذي تستخدمه. تسمح النماذج الأرخص مثل MiniMax M2.5 بمزيد من الطلبات، بينما تسمح النماذج الأعلى تكلفة مثل GLM-5 بطلبات أقل.
|
||||||
|
|
||||||
يوفر الجدول أدناه عدداً تقديرياً للطلبات بناءً على أنماط استخدام Go النموذجية:
|
يقدم الجدول أدناه عدد الطلبات التقديري بناءً على أنماط استخدام Go النموذجية:
|
||||||
|
|
||||||
| | GLM-5 | Kimi K2.5 | MiniMax M2.5 |
|
| | GLM-5 | Kimi K2.5 | MiniMax M2.7 | MiniMax M2.5 |
|
||||||
| ---------------- | ----- | --------- | ------------ |
|
| ------------------- | ----- | --------- | ------------ | ------------ |
|
||||||
| طلبات كل 5 ساعات | 1,150 | 1,850 | 30,000 |
|
| الطلبات لكل 5 ساعات | 1,150 | 1,850 | 14,000 | 20,000 |
|
||||||
| طلبات أسبوعياً | 2,880 | 4,630 | 75,000 |
|
| الطلبات في الأسبوع | 2,880 | 4,630 | 35,000 | 50,000 |
|
||||||
| طلبات شهرياً | 5,750 | 9,250 | 150,000 |
|
| الطلبات في الشهر | 5,750 | 9,250 | 70,000 | 100,000 |
|
||||||
|
|
||||||
تعتمد التقديرات على أنماط الطلبات المتوسطة الملحوظة:
|
تستند التقديرات إلى أنماط الطلب المتوسطة الملحوظة:
|
||||||
|
|
||||||
- GLM-5 — 700 input, 52,000 cached, 150 output tokens per request
|
- GLM-5 — 700 إدخال (input)، 52,000 مخبأة (cached)، 150 توكن إخراج (output tokens) لكل طلب
|
||||||
- Kimi K2.5 — 870 input, 55,000 cached, 200 output tokens per request
|
- Kimi K2.5 — 870 إدخال، 55,000 مخبأة، 200 توكن إخراج لكل طلب
|
||||||
- MiniMax M2.5 — 300 input, 55,000 cached, 125 output tokens per request
|
- MiniMax M2.7/M2.5 — 300 إدخال، 55,000 مخبأة، 125 توكن إخراج لكل طلب
|
||||||
|
|
||||||
يمكنك تتبع استخدامك الحالي في **<a href={console}>console</a>**.
|
يمكنك تتبع استخدامك الحالي في **<a href={console}>وحدة التحكم (console)</a>**.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
إذا وصلت إلى حد الاستخدام، يمكنك الاستمرار في استخدام النماذج المجانية.
|
إذا وصلت إلى حد الاستخدام، يمكنك الاستمرار في استخدام النماذج المجانية.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
قد تتغير حدود الاستخدام ونحن نتعلم من الاستخدام المبكر والملاحظات.
|
قد تتغير حدود الاستخدام كلما تعلمنا من الاستخدام المبكر والملاحظات.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### التسعير (Pricing)
|
### الاستخدام متجاوزًا الحدود
|
||||||
|
|
||||||
OpenCode Go هي خطة اشتراك بقيمة **10 دولارات شهرياً**. أدناه الأسعار **لكل 1 مليون رمز (token)**.
|
إذا كان لديك أيضًا أرصدة في رصيد Zen الخاص بك، فيمكنك تمكين خيار **Use balance**
|
||||||
|
في وحدة التحكم. عند التمكين، سيعود Go لاستخدام رصيد Zen الخاص بك
|
||||||
| Model | Input | Output | Cached Read |
|
بعد أن تصل إلى حدود استخدامك بدلاً من حظر الطلبات.
|
||||||
| ------------ | ----- | ------ | ----------- |
|
|
||||||
| GLM-5 | $1.00 | $3.20 | $0.20 |
|
|
||||||
| Kimi K2.5 | $0.60 | $3.00 | $0.10 |
|
|
||||||
| MiniMax M2.5 | $0.30 | $1.20 | $0.03 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### الاستخدام خارج الحدود (Usage beyond limits)
|
|
||||||
|
|
||||||
إذا كان لديك أيضاً أرصدة في رصيد Zen الخاص بك، يمكنك تمكين خيار **Use balance** في الـ console. عند التمكين، سيعود Go لاستخدام رصيد Zen الخاص بك بعد وصولك إلى حدود الاستخدام بدلاً من حظر الطلبات.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## نقاط النهاية (Endpoints)
|
## نقاط النهاية (Endpoints)
|
||||||
|
|
||||||
يمكنك أيضاً الوصول إلى نماذج Go من خلال نقاط نهاية API التالية.
|
يمكنك أيضًا الوصول إلى نماذج Go من خلال نقاط نهاية API التالية.
|
||||||
|
|
||||||
| Model | Model ID | Endpoint | AI SDK Package |
|
| Model | Model ID | Endpoint | AI SDK Package |
|
||||||
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
||||||
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
|
|
||||||
يستخدم [model id](/docs/config/#models) في تكوين OpenCode الخاص بك التنسيق `opencode-go/<model-id>`. على سبيل المثال، بالنسبة لـ Kimi K2.5، ستستخدم `opencode-go/kimi-k2.5` في التكوين الخاص بك.
|
يستخدم [معرف النموذج (model id)](/docs/config/#models) في إعدادات (config) OpenCode
|
||||||
|
الخاصة بك التنسيق `opencode-go/<model-id>`. على سبيل المثال، بالنسبة لـ Kimi K2.5، ستستخدم
|
||||||
|
`opencode-go/kimi-k2.5` في الـ config الخاص بك.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## الخصوصية (Privacy)
|
## الخصوصية
|
||||||
|
|
||||||
تم تصميم الخطة بشكل أساسي للمستخدمين الدوليين، مع استضافة النماذج في الولايات المتحدة والاتحاد الأوروبي وسنغافورة لضمان وصول عالمي مستقر.
|
الخطة مصممة بشكل أساسي للمستخدمين الدوليين، مع نماذج مستضافة في الولايات المتحدة، والاتحاد الأوروبي، وسنغافورة من أجل وصول عالمي مستقر.
|
||||||
|
|
||||||
<a href={email}>تواصل معنا</a> إذا كان لديك أي أسئلة.
|
<a href={email}>تواصل معنا</a> إذا كان لديك أي أسئلة.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## الأهداف (Goals)
|
## الأهداف
|
||||||
|
|
||||||
أنشأنا OpenCode Go لـ:
|
لقد أنشأنا OpenCode Go من أجل:
|
||||||
|
|
||||||
1. جعل برمجة الذكاء الاصطناعي **في المتناول** لمزيد من الناس باشتراك منخفض التكلفة.
|
1. جعل البرمجة بالذكاء الاصطناعي **متاحة** لعدد أكبر من الأشخاص باشتراك منخفض التكلفة.
|
||||||
2. توفير وصول **موثوق** لأفضل نماذج البرمجة المفتوحة.
|
2. توفير وصول **موثوق** إلى أفضل نماذج البرمجة المفتوحة.
|
||||||
3. انتقاء نماذج **مختبرة وتم قياس أدائها** لاستخدام وكيل البرمجة.
|
3. تنسيق النماذج **المختبرة والمقيمة** (benchmarked) للاستخدام مع وكلاء البرمجة (coding agents).
|
||||||
4. عدم وجود **قيود (lock-in)** من خلال السماح لك باستخدام أي مزود آخر مع OpenCode أيضاً.
|
4. **عدم تقييدك** (no lock-in) من خلال السماح لك باستخدام أي مزود آخر مع OpenCode أيضًا.
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
---
|
---
|
||||||
title: Go
|
title: Go
|
||||||
description: Povoljna pretplata za otvorene modele kodiranja.
|
description: Povoljna pretplata za otvorene modele za programiranje.
|
||||||
---
|
---
|
||||||
|
|
||||||
import config from "../../../../config.mjs"
|
import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
export const console = config.console
|
||||||
export const email = `mailto:${config.email}`
|
export const email = `mailto:${config.email}`
|
||||||
|
|
||||||
OpenCode Go je povoljna pretplata od **$10/mjesečno** koja vam daje pouzdan pristup popularnim otvorenim modelima kodiranja.
|
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.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
OpenCode Go je trenutno u beta fazi.
|
OpenCode Go je trenutno u beta fazi.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Go funkcioniše kao bilo koji drugi pružatelj usluga u OpenCode-u. Pretplatite se na OpenCode Go i
|
Go radi kao bilo koji drugi provajder u OpenCode-u. Pretplatite se na OpenCode Go i
|
||||||
dobijete svoj API ključ. To je **potpuno opcionalno** i ne morate ga koristiti da biste
|
dobijete svoj API ključ. On je **potpuno opcionalan** i ne morate ga koristiti da
|
||||||
koristili OpenCode.
|
biste koristili OpenCode.
|
||||||
|
|
||||||
Dizajniran je prvenstveno za međunarodne korisnike, sa modelima hostovanim u SAD-u, EU i Singapuru za stabilan globalni pristup.
|
Dizajniran je prvenstveno za međunarodne korisnike, sa modelima hostovanim u SAD-u, EU i Singapuru za stabilan globalni pristup.
|
||||||
|
|
||||||
|
|
@ -24,41 +24,41 @@ Dizajniran je prvenstveno za međunarodne korisnike, sa modelima hostovanim u SA
|
||||||
## Pozadina
|
## Pozadina
|
||||||
|
|
||||||
Otvoreni modeli su postali zaista dobri. Sada dostižu performanse bliske
|
Otvoreni modeli su postali zaista dobri. Sada dostižu performanse bliske
|
||||||
vlasničkim modelima za zadatke kodiranja. A budući da ih mnogi pružatelji usluga mogu posluživati
|
vlasničkim modelima za zadatke programiranja. A pošto ih mnogi provajderi mogu nuditi
|
||||||
konkurentno, obično su daleko jeftiniji.
|
konkurentno, obično su znatno jeftiniji.
|
||||||
|
|
||||||
Međutim, dobivanje pouzdanog pristupa s malim kašnjenjem može biti teško. Pružatelji usluga
|
Međutim, dobiti pouzdan pristup s niskom latencijom do njih može biti teško. Provajderi
|
||||||
variraju u kvaliteti i dostupnosti.
|
variraju u pogledu kvaliteta i dostupnosti.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Testirali smo odabranu grupu modela i pružatelja usluga koji dobro rade sa OpenCode-om.
|
Testirali smo odabranu grupu modela i provajdera koji dobro rade sa OpenCode-om.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Da bismo ovo riješili, uradili smo nekoliko stvari:
|
Da bismo to popravili, uradili smo nekoliko stvari:
|
||||||
|
|
||||||
1. Testirali smo odabranu grupu otvorenih modela i razgovarali sa njihovim timovima o tome kako ih
|
1. Testirali smo odabranu grupu otvorenih modela i razgovarali s njihovim timovima o tome kako da ih
|
||||||
najbolje pokrenuti.
|
najbolje pokrenemo.
|
||||||
2. Zatim smo radili sa nekoliko pružatelja usluga kako bismo bili sigurni da su ispravno
|
2. Zatim smo sarađivali s nekoliko provajdera kako bismo bili sigurni da se oni ispravno
|
||||||
posluživani.
|
poslužuju.
|
||||||
3. Konačno, benchmarkirali smo kombinaciju modela/pružatelja usluga i došli do
|
3. Na kraju smo benchmarkovali kombinaciju modela/provajdera i osmislili
|
||||||
liste koju se osjećamo dobro preporučiti.
|
listu koju rado preporučujemo.
|
||||||
|
|
||||||
OpenCode Go vam daje pristup ovim modelima za **$10/mjesečno**.
|
OpenCode Go vam daje pristup ovim modelima za **$5 za vaš prvi mjesec**, a zatim **$10/mjesečno**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Kako to funkcioniše
|
## Kako funkcioniše
|
||||||
|
|
||||||
OpenCode Go funkcioniše kao bilo koji drugi pružatelj usluga u OpenCode-u.
|
OpenCode Go radi kao bilo koji drugi provajder u OpenCode-u.
|
||||||
|
|
||||||
1. Prijavite se na **<a href={console}>OpenCode Zen</a>**, pretplatite se na Go i
|
1. Prijavite se na **<a href={console}>OpenCode Zen</a>**, pretplatite se na Go i
|
||||||
kopirajte svoj API ključ.
|
kopirajte svoj API ključ.
|
||||||
2. Pokrenite `/connect` komandu u TUI-ju, odaberite `OpenCode Go` i zalijepite
|
2. Pokrenite komandu `/connect` u TUI-ju, odaberite `OpenCode Go` i zalijepite
|
||||||
svoj API ključ.
|
svoj API ključ.
|
||||||
3. Pokrenite `/models` u TUI-ju da vidite listu modela dostupnih putem Go.
|
3. Pokrenite `/models` u TUI-ju da vidite listu modela dostupnih kroz Go.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
Samo jedan član po radnom prostoru se može pretplatiti na OpenCode Go.
|
Samo jedan član po radnom prostoru (workspace) može se pretplatiti na OpenCode Go.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Trenutna lista modela uključuje:
|
Trenutna lista modela uključuje:
|
||||||
|
|
@ -66,62 +66,51 @@ Trenutna lista modela uključuje:
|
||||||
- **GLM-5**
|
- **GLM-5**
|
||||||
- **Kimi K2.5**
|
- **Kimi K2.5**
|
||||||
- **MiniMax M2.5**
|
- **MiniMax M2.5**
|
||||||
|
- **MiniMax M2.7**
|
||||||
|
|
||||||
Lista modela se može mijenjati kako testiramo i dodajemo nove.
|
Lista modela se može mijenjati dok testiramo i dodajemo nove.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Ograničenja korištenja
|
## Ograničenja upotrebe
|
||||||
|
|
||||||
OpenCode Go uključuje sljedeća ograničenja:
|
OpenCode Go uključuje sljedeća ograničenja:
|
||||||
|
|
||||||
- **Limit od 5 sati** — $12 korištenja
|
- **Ograničenje od 5 sati** — $12 potrošnje
|
||||||
- **Sedmični limit** — $30 korištenja
|
- **Sedmično ograničenje** — $30 potrošnje
|
||||||
- **Mjesečni limit** — $60 korištenja
|
- **Mjesečno ograničenje** — $60 potrošnje
|
||||||
|
|
||||||
Limiti su definisani u dolarskoj vrijednosti. To znači da vaš stvarni broj zahtjeva zavisi od modela koji koristite. Jeftiniji modeli kao što je MiniMax M2.5 omogućavaju više zahtjeva, dok skuplji modeli kao što je GLM-5 omogućavaju manje.
|
Ograničenja su definisana u dolarskoj vrijednosti. To znači da vaš stvarni broj zahtjeva zavisi od modela koji koristite. Jeftiniji modeli poput MiniMax M2.5 omogućavaju više zahtjeva, dok skuplji modeli poput GLM-5 omogućavaju manje.
|
||||||
|
|
||||||
Tabela ispod pruža procijenjeni broj zahtjeva na osnovu tipičnih Go obrazaca korištenja:
|
Tabela ispod pruža procijenjeni broj zahtjeva na osnovu tipičnih obrazaca korištenja Go pretplate:
|
||||||
|
|
||||||
| | GLM-5 | Kimi K2.5 | MiniMax M2.5 |
|
| | GLM-5 | Kimi K2.5 | MiniMax M2.7 | MiniMax M2.5 |
|
||||||
| ------------------ | ----- | --------- | ------------ |
|
| ------------------ | ----- | --------- | ------------ | ------------ |
|
||||||
| zahtjeva po 5 sati | 1,150 | 1,850 | 30,000 |
|
| zahtjeva na 5 sati | 1,150 | 1,850 | 14,000 | 20,000 |
|
||||||
| zahtjeva sedmično | 2,880 | 4,630 | 75,000 |
|
| zahtjeva sedmično | 2,880 | 4,630 | 35,000 | 50,000 |
|
||||||
| zahtjeva mjesečno | 5,750 | 9,250 | 150,000 |
|
| zahtjeva mjesečno | 5,750 | 9,250 | 70,000 | 100,000 |
|
||||||
|
|
||||||
Procjene su zasnovane na uočenim prosječnim obrascima zahtjeva:
|
Procjene se zasnivaju na zapaženim prosječnim obrascima zahtjeva:
|
||||||
|
|
||||||
- GLM-5 — 700 ulaznih, 52,000 keširanih, 150 izlaznih tokena po zahtjevu
|
- GLM-5 — 700 ulaznih (input), 52,000 keširanih, 150 izlaznih (output) tokena po zahtjevu
|
||||||
- Kimi K2.5 — 870 ulaznih, 55,000 keširanih, 200 izlaznih tokena po zahtjevu
|
- Kimi K2.5 — 870 ulaznih, 55,000 keširanih, 200 izlaznih tokena po zahtjevu
|
||||||
- MiniMax M2.5 — 300 ulaznih, 55,000 keširanih, 125 izlaznih tokena po zahtjevu
|
- MiniMax M2.7/M2.5 — 300 ulaznih, 55,000 keširanih, 125 izlaznih tokena po zahtjevu
|
||||||
|
|
||||||
Možete pratiti svoje trenutno korištenje u **<a href={console}>konzoli</a>**.
|
Svoju trenutnu potrošnju možete pratiti u **<a href={console}>konzoli</a>**.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Ako dosegnete limit korištenja, možete nastaviti koristiti besplatne modele.
|
Ako dostignete ograničenje upotrebe, možete nastaviti koristiti besplatne modele.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Ograničenja korištenja se mogu mijenjati kako učimo iz rane upotrebe i povratnih informacija.
|
Ograničenja upotrebe mogu se promijeniti kako budemo učili iz rane upotrebe i povratnih informacija.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Cijene
|
### Upotreba preko ograničenja
|
||||||
|
|
||||||
OpenCode Go je pretplatnički plan od **$10/mjesečno**. Ispod su cijene **po 1M tokena**.
|
Ako također imate kredite na svom Zen balansu, možete omogućiti **Use balance**
|
||||||
|
opciju u konzoli. Kada je omogućeno, Go će preći na vaš Zen balans
|
||||||
| Model | Ulaz | Izlaz | Keširano čitanje |
|
nakon što dostignete ograničenja upotrebe umjesto blokiranja zahtjeva.
|
||||||
| ------------ | ----- | ----- | ---------------- |
|
|
||||||
| GLM-5 | $1.00 | $3.20 | $0.20 |
|
|
||||||
| Kimi K2.5 | $0.60 | $3.00 | $0.10 |
|
|
||||||
| MiniMax M2.5 | $0.30 | $1.20 | $0.03 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Korištenje izvan limita
|
|
||||||
|
|
||||||
Ako također imate kredita na svom Zen saldu, možete omogućiti opciju **Use balance**
|
|
||||||
u konzoli. Kada je omogućeno, Go će se prebaciti na vaš Zen saldo
|
|
||||||
nakon što dosegnete limite korištenja umjesto blokiranja zahtjeva.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -129,15 +118,16 @@ nakon što dosegnete limite korištenja umjesto blokiranja zahtjeva.
|
||||||
|
|
||||||
Također možete pristupiti Go modelima putem sljedećih API endpointa.
|
Također možete pristupiti Go modelima putem sljedećih API endpointa.
|
||||||
|
|
||||||
| Model | ID modela | Endpoint | AI SDK Paket |
|
| Model | Model ID | Endpoint | AI SDK Paket |
|
||||||
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
||||||
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
|
|
||||||
[Model id](/docs/config/#models) u vašoj OpenCode konfiguraciji
|
[Model id](/docs/config/#models) u vašoj OpenCode konfiguraciji
|
||||||
koristi format `opencode-go/<model-id>`. Na primjer, za Kimi K2.5, biste
|
koristi format `opencode-go/<model-id>`. Na primjer, za Kimi K2.5, koristili biste
|
||||||
koristili `opencode-go/kimi-k2.5` u vašoj konfiguraciji.
|
`opencode-go/kimi-k2.5` u svojoj konfiguraciji.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -151,9 +141,9 @@ Plan je dizajniran prvenstveno za međunarodne korisnike, sa modelima hostovanim
|
||||||
|
|
||||||
## Ciljevi
|
## Ciljevi
|
||||||
|
|
||||||
Kreirali smo OpenCode Go da:
|
Napravili smo OpenCode Go da bismo:
|
||||||
|
|
||||||
1. Učinimo AI kodiranje **pristupačnim** većem broju ljudi uz povoljnu pretplatu.
|
1. Učinili AI programiranje **dostupnim** većem broju ljudi putem povoljne pretplate.
|
||||||
2. Pružimo **pouzdan** pristup najboljim otvorenim modelima kodiranja.
|
2. Pružili **pouzdan** pristup najboljim otvorenim modelima za programiranje.
|
||||||
3. Kurišemo modele koji su **testirani i benchmarkirani** za upotrebu agenata za kodiranje.
|
3. Odabrali modele koji su **testirani i benchmarkovani** za upotrebu od strane agenata za programiranje.
|
||||||
4. Nemamo **zaključavanja (lock-in)** omogućavajući vam da koristite bilo kojeg drugog pružatelja usluga sa OpenCode-om također.
|
4. Osigurali da **nema zaključavanja (no lock-in)**, omogućavajući vam da uz OpenCode koristite i bilo kojeg drugog provajdera.
|
||||||
|
|
|
||||||
|
|
@ -1,54 +1,64 @@
|
||||||
---
|
---
|
||||||
title: Go
|
title: Go
|
||||||
description: Lavprisabonnement for åbne kodningsmodeller.
|
description: Lavprisabonnement til åbne kodningsmodeller.
|
||||||
---
|
---
|
||||||
|
|
||||||
import config from "../../../../config.mjs"
|
import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
export const console = config.console
|
||||||
export const email = `mailto:${config.email}`
|
export const email = `mailto:${config.email}`
|
||||||
|
|
||||||
OpenCode Go er et billigt **$10/måned** abonnement, der giver dig pålidelig adgang til populære åbne kodningsmodeller.
|
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.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
OpenCode Go er i øjeblikket i beta.
|
OpenCode Go er i øjeblikket i beta.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Go fungerer ligesom 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.
|
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 stabil global adgang.
|
Det er primært designet til internationale brugere, med modeller hostet i USA, EU og Singapore for at sikre stabil global adgang.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Baggrund
|
## Baggrund
|
||||||
|
|
||||||
Åbne modeller er blevet virkelig gode. De når nu en ydeevne tæt på proprietære modeller til kodningsopgaver. Og fordi mange udbydere kan tilbyde dem konkurrencedygtigt, er de normalt langt billigere.
|
Åbne modeller er blevet rigtig gode. De opnår nu en ydeevne, der er tæt på
|
||||||
|
proprietære modeller til kodningsopgaver. Og fordi mange udbydere kan levere dem
|
||||||
|
konkurrencedygtigt, er de som regel langt billigere.
|
||||||
|
|
||||||
Det kan dog være svært at få pålidelig adgang med lav latenstid til dem. Udbydere varierer i kvalitet og tilgængelighed.
|
Det kan dog være svært at få pålidelig adgang til dem med lav latenstid. Udbydere
|
||||||
|
varierer i kvalitet og tilgængelighed.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Vi testede en udvalgt gruppe af modeller og udbydere, der fungerer godt med OpenCode.
|
Vi testede en udvalgt gruppe af modeller og udbydere, der fungerer godt med OpenCode.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
For at løse dette gjorde vi et par ting:
|
For at løse dette, gjorde vi et par ting:
|
||||||
|
|
||||||
1. Vi testede en udvalgt gruppe af åbne modeller og talte med deres teams om, hvordan man bedst kører dem.
|
1. Vi testede en udvalgt gruppe af åbne modeller og talte med deres teams om, hvordan man
|
||||||
2. Vi arbejdede derefter sammen med nogle få udbydere for at sikre, at disse blev leveret korrekt.
|
bedst kører dem.
|
||||||
3. Endelig benchmarkede vi kombinationen af model/udbyder og kom frem til en liste, som vi har det godt med at anbefale.
|
2. Derefter arbejdede vi med nogle få udbydere for at sikre, at disse blev leveret
|
||||||
|
korrekt.
|
||||||
|
3. Til sidst benchmarkede vi kombinationen af model og udbyder, og kom frem til
|
||||||
|
en liste, som vi trygt kan anbefale.
|
||||||
|
|
||||||
OpenCode Go giver dig adgang til disse modeller for **$10/måned**.
|
OpenCode Go giver dig adgang til disse modeller for **$5 for din første måned**, derefter **$10/måned**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Sådan fungerer det
|
## Sådan fungerer det
|
||||||
|
|
||||||
OpenCode Go fungerer ligesom enhver anden udbyder i OpenCode.
|
OpenCode Go fungerer som enhver anden udbyder i OpenCode.
|
||||||
|
|
||||||
1. Du logger ind på **<a href={console}>OpenCode Zen</a>**, abonnerer på Go, og kopierer din API-nøgle.
|
1. Du logger ind på **<a href={console}>OpenCode Zen</a>**, abonnerer på Go, og
|
||||||
2. Du kører kommandoen `/connect` i TUI'en, vælger `OpenCode Go`, og indsætter din API-nøgle.
|
kopierer din API-nøgle.
|
||||||
3. Kør `/models` i TUI'en for at se listen over modeller, der er tilgængelige gennem Go.
|
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
|
:::note
|
||||||
Kun ét medlem pr. workspace kan abonnere på OpenCode Go.
|
Kun ét medlem per arbejdsområde kan abonnere på OpenCode Go.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Den nuværende liste over modeller inkluderer:
|
Den nuværende liste over modeller inkluderer:
|
||||||
|
|
@ -56,6 +66,7 @@ Den nuværende liste over modeller inkluderer:
|
||||||
- **GLM-5**
|
- **GLM-5**
|
||||||
- **Kimi K2.5**
|
- **Kimi K2.5**
|
||||||
- **MiniMax M2.5**
|
- **MiniMax M2.5**
|
||||||
|
- **MiniMax M2.7**
|
||||||
|
|
||||||
Listen over modeller kan ændre sig, efterhånden som vi tester og tilføjer nye.
|
Listen over modeller kan ændre sig, efterhånden som vi tester og tilføjer nye.
|
||||||
|
|
||||||
|
|
@ -65,25 +76,25 @@ Listen over modeller kan ændre sig, efterhånden som vi tester og tilføjer nye
|
||||||
|
|
||||||
OpenCode Go inkluderer følgende grænser:
|
OpenCode Go inkluderer følgende grænser:
|
||||||
|
|
||||||
- **5 timers grænse** — $12 forbrug
|
- **5-timers grænse** — forbrug for $12
|
||||||
- **Ugentlig grænse** — $30 forbrug
|
- **Ugentlig grænse** — forbrug for $30
|
||||||
- **Månedlig grænse** — $60 forbrug
|
- **Månedlig grænse** — forbrug for $60
|
||||||
|
|
||||||
Grænser er defineret i dollarværdi. Det betyder, at dit faktiske antal forespørgsler afhænger af den model, du bruger. Billigere modeller som MiniMax M2.5 tillader flere forespørgsler, mens dyrere modeller som GLM-5 tillader færre.
|
Grænserne er defineret i dollarværdi. Det betyder, at dit faktiske antal anmodninger afhænger af den model, du bruger. Billigere modeller som MiniMax M2.5 tillader flere anmodninger, mens dyrere modeller som GLM-5 tillader færre.
|
||||||
|
|
||||||
Tabellen nedenfor giver et estimeret antal forespørgsler baseret på typiske Go-brugsmønstre:
|
Tabellen nedenfor giver et estimeret antal anmodninger baseret på typiske Go-forbrugsmønstre:
|
||||||
|
|
||||||
| | GLM-5 | Kimi K2.5 | MiniMax M2.5 |
|
| | GLM-5 | Kimi K2.5 | MiniMax M2.7 | MiniMax M2.5 |
|
||||||
| ------------------------- | ----- | --------- | ------------ |
|
| ----------------------- | ----- | --------- | ------------ | ------------ |
|
||||||
| forespørgsler pr. 5 timer | 1.150 | 1.850 | 30.000 |
|
| anmodninger pr. 5 timer | 1.150 | 1.850 | 14.000 | 20.000 |
|
||||||
| forespørgsler pr. uge | 2.880 | 4.630 | 75.000 |
|
| anmodninger pr. uge | 2.880 | 4.630 | 35.000 | 50.000 |
|
||||||
| forespørgsler pr. måned | 5.750 | 9.250 | 150.000 |
|
| anmodninger pr. måned | 5.750 | 9.250 | 70.000 | 100.000 |
|
||||||
|
|
||||||
Estimater er baseret på observerede gennemsnitlige forespørgselsmønstre:
|
Estimaterne er baseret på observerede gennemsnitlige anmodningsmønstre:
|
||||||
|
|
||||||
- GLM-5 — 700 input, 52.000 cached, 150 output tokens pr. forespørgsel
|
- GLM-5 — 700 input, 52.000 cachelagrede, 150 output-tokens pr. anmodning
|
||||||
- Kimi K2.5 — 870 input, 55.000 cached, 200 output tokens pr. forespørgsel
|
- Kimi K2.5 — 870 input, 55.000 cachelagrede, 200 output-tokens pr. anmodning
|
||||||
- MiniMax M2.5 — 300 input, 55.000 cached, 125 output tokens pr. forespørgsel
|
- MiniMax M2.7/M2.5 — 300 input, 55.000 cachelagrede, 125 output-tokens pr. anmodning
|
||||||
|
|
||||||
Du kan spore dit nuværende forbrug i **<a href={console}>konsollen</a>**.
|
Du kan spore dit nuværende forbrug i **<a href={console}>konsollen</a>**.
|
||||||
|
|
||||||
|
|
@ -91,47 +102,40 @@ Du kan spore dit nuværende forbrug i **<a href={console}>konsollen</a>**.
|
||||||
Hvis du når forbrugsgrænsen, kan du fortsætte med at bruge de gratis modeller.
|
Hvis du når forbrugsgrænsen, kan du fortsætte med at bruge de gratis modeller.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Forbrugsgrænser kan ændre sig, efterhånden som vi lærer fra tidlig brug og feedback.
|
Forbrugsgrænser kan ændre sig, efterhånden som vi lærer af tidlig brug og feedback.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Priser
|
### Forbrug ud over grænserne
|
||||||
|
|
||||||
OpenCode Go er en **$10/måned** abonnementsplan. Nedenfor er priserne **pr. 1M tokens**.
|
Hvis du også har kredit på din Zen-saldo, kan du aktivere indstillingen **Use balance**
|
||||||
|
i konsollen. Når den er aktiveret, vil Go falde tilbage på din Zen-saldo,
|
||||||
| Model | Input | Output | Cached Læsning |
|
når du har nået dine forbrugsgrænser, i stedet for at blokere anmodninger.
|
||||||
| ------------ | ----- | ------ | -------------- |
|
|
||||||
| GLM-5 | $1,00 | $3,20 | $0,20 |
|
|
||||||
| Kimi K2.5 | $0,60 | $3,00 | $0,10 |
|
|
||||||
| MiniMax M2.5 | $0,30 | $1,20 | $0,03 |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Forbrug ud over grænser
|
## Endpoints
|
||||||
|
|
||||||
Hvis du også har kreditter på din Zen-saldo, kan du aktivere **Brug saldo**-indstillingen i konsollen. Når den er aktiveret, vil Go falde tilbage på din Zen-saldo, efter du har nået dine forbrugsgrænser, i stedet for at blokere forespørgsler.
|
Du kan også få adgang til Go-modeller gennem følgende API-endpoints.
|
||||||
|
|
||||||
---
|
| Model | Model ID | Endpoint | AI SDK Package |
|
||||||
|
|
||||||
## Endepunkter
|
|
||||||
|
|
||||||
Du kan også få adgang til Go-modeller gennem følgende API-endepunkter.
|
|
||||||
|
|
||||||
| Model | Model ID | Endpoint | AI SDK Pakke |
|
|
||||||
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
||||||
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
|
|
||||||
[Model-id'et](/docs/config/#models) i din OpenCode-konfiguration bruger formatet `opencode-go/<model-id>`. For eksempel, for Kimi K2.5, ville du bruge `opencode-go/kimi-k2.5` i din konfiguration.
|
Dit [model id](/docs/config/#models) i din OpenCode config
|
||||||
|
bruger formatet `opencode-go/<model-id>`. For eksempel for Kimi K2.5, vil du
|
||||||
|
bruge `opencode-go/kimi-k2.5` i din config.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Privatliv
|
## Privatliv
|
||||||
|
|
||||||
Planen er primært designet til internationale brugere, med modeller hostet i USA, EU og Singapore for stabil global adgang.
|
Planen er primært designet til internationale brugere, med modeller hostet i USA, EU og Singapore for at sikre stabil global adgang.
|
||||||
|
|
||||||
<a href={email}>Kontakt os</a> hvis du har spørgsmål.
|
<a href={email}>Kontakt os</a>, hvis du har spørgsmål.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -139,7 +143,7 @@ Planen er primært designet til internationale brugere, med modeller hostet i US
|
||||||
|
|
||||||
Vi skabte OpenCode Go for at:
|
Vi skabte OpenCode Go for at:
|
||||||
|
|
||||||
1. Gøre AI-kodning **tilgængelig** for flere mennesker med et billigt abonnement.
|
1. Gøre AI-kodning **tilgængelig** for flere mennesker med et lavprisabonnement.
|
||||||
2. Tilbyde **pålidelig** adgang til de bedste åbne kodningsmodeller.
|
2. Give **pålidelig** adgang til de bedste åbne kodningsmodeller.
|
||||||
3. Udvælge modeller, der er **testet og benchmarked** til brug med kodningsagenter.
|
3. Kuratere modeller, der er **testet og benchmarkede** til brug med kodningsagenter.
|
||||||
4. Have **ingen lock-in** ved at tillade dig også at bruge enhver anden udbyder med OpenCode.
|
4. Undgå **lock-in** ved også at lade dig bruge enhver anden udbyder med OpenCode.
|
||||||
|
|
|
||||||
|
|
@ -1,50 +1,52 @@
|
||||||
---
|
---
|
||||||
title: Go
|
title: Go
|
||||||
description: Kostengünstiges Abonnement für Open-Coding-Modelle.
|
description: Kostengünstiges Abonnement für offene Coding-Modelle.
|
||||||
---
|
---
|
||||||
|
|
||||||
import config from "../../../../config.mjs"
|
import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
export const console = config.console
|
||||||
export const email = `mailto:${config.email}`
|
export const email = `mailto:${config.email}`
|
||||||
|
|
||||||
OpenCode Go ist ein kostengünstiges Abonnement für **10 $/Monat**, das dir zuverlässigen Zugriff auf beliebte Open-Coding-Modelle bietet.
|
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.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
OpenCode Go befindet sich derzeit in der Beta-Phase.
|
OpenCode Go befindet sich derzeit in der Beta-Phase.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Go funktioniert wie jeder andere Anbieter in OpenCode. Du abonnierst OpenCode Go und erhältst deinen API-Schlüssel. Es ist **völlig optional** und du musst es nicht nutzen, um OpenCode zu verwenden.
|
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, mit Modellen, die in den USA, der EU und Singapur gehostet werden, um einen stabilen weltweiten Zugriff zu gewährleisten.
|
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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hintergrund
|
## Hintergrund
|
||||||
|
|
||||||
Offene Modelle sind wirklich gut geworden. Sie erreichen bei Coding-Aufgaben mittlerweile eine Leistung, die der von proprietären Modellen nahekommt. Und da viele Anbieter sie wettbewerbsfähig bereitstellen können, sind sie in der Regel deutlich günstiger.
|
Offene Modelle sind richtig gut geworden. Sie erreichen bei Coding-Aufgaben mittlerweile eine Leistung, die nahe an proprietäre Modelle herankommt. Und da viele Provider sie wettbewerbsfähig anbieten können, sind sie in der Regel viel günstiger.
|
||||||
|
|
||||||
Es kann jedoch schwierig sein, einen zuverlässigen Zugang mit niedriger Latenz zu erhalten. Die Anbieter variieren in Qualität und Verfügbarkeit.
|
Allerdings kann es schwierig sein, zuverlässigen Zugriff mit geringer Latenz auf sie zu erhalten. Provider variieren in Qualität und Verfügbarkeit.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Wir haben eine ausgewählte Gruppe von Modellen und Anbietern getestet, die gut mit OpenCode funktionieren.
|
Wir haben eine ausgewählte Gruppe von Modellen und Providern getestet, die gut mit OpenCode funktionieren.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Um dies zu lösen, haben wir einige Dinge getan:
|
Um dies zu beheben, haben wir einige Dinge getan:
|
||||||
|
|
||||||
1. Wir haben eine ausgewählte Gruppe offener Modelle getestet und mit deren Teams darüber gesprochen, wie man sie am besten betreibt.
|
1. Wir haben eine ausgewählte Gruppe offener Modelle getestet und mit ihren Teams darüber gesprochen, wie man sie am besten ausführt.
|
||||||
2. Anschließend haben wir mit einigen Anbietern zusammengearbeitet, um sicherzustellen, dass diese korrekt bereitgestellt werden.
|
2. Anschließend haben wir mit einigen Providern zusammengearbeitet, um sicherzustellen, dass diese korrekt bereitgestellt werden.
|
||||||
3. Schließlich haben wir die Kombination aus Modell und Anbieter einem Benchmark unterzogen und eine Liste erstellt, die wir guten Gewissens empfehlen können.
|
3. Zuletzt haben wir die Kombination aus Modell und Provider einem Benchmark unterzogen und eine Liste erstellt, die wir mit gutem Gewissen empfehlen können.
|
||||||
|
|
||||||
OpenCode Go gibt dir Zugriff auf diese Modelle für **10 $/Monat**.
|
OpenCode Go bietet dir Zugriff auf diese Modelle für **5 $ im ersten Monat**, danach **10 $/Monat**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Wie es funktioniert
|
## Wie es funktioniert
|
||||||
|
|
||||||
OpenCode Go funktioniert wie jeder andere Anbieter in OpenCode.
|
OpenCode Go funktioniert wie jeder andere Provider in OpenCode.
|
||||||
|
|
||||||
1. Du meldest dich bei **<a href={console}>OpenCode Zen</a>** an, abonnierst Go und kopierst deinen API-Schlüssel.
|
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-Schlüssel ein.
|
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.
|
3. Führe `/models` in der TUI aus, um die Liste der über Go verfügbaren Modelle zu sehen.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
|
|
@ -56,8 +58,9 @@ Die aktuelle Liste der Modelle umfasst:
|
||||||
- **GLM-5**
|
- **GLM-5**
|
||||||
- **Kimi K2.5**
|
- **Kimi K2.5**
|
||||||
- **MiniMax M2.5**
|
- **MiniMax M2.5**
|
||||||
|
- **MiniMax M2.7**
|
||||||
|
|
||||||
Die Liste der Modelle kann sich ändern, wenn wir neue testen und hinzufügen.
|
Die Liste der Modelle kann sich ändern, während wir neue testen und hinzufügen.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -69,77 +72,66 @@ OpenCode Go beinhaltet die folgenden Limits:
|
||||||
- **Wöchentliches Limit** — 30 $ Nutzung
|
- **Wöchentliches Limit** — 30 $ Nutzung
|
||||||
- **Monatliches Limit** — 60 $ Nutzung
|
- **Monatliches Limit** — 60 $ Nutzung
|
||||||
|
|
||||||
Die Limits sind in Dollarwerten definiert. Das bedeutet, dass deine tatsächliche Anzahl an Anfragen von dem verwendeten Modell abhängt. Günstigere Modelle wie MiniMax M2.5 ermöglichen mehr Anfragen, während kostenintensivere Modelle wie GLM-5 weniger zulassen.
|
Limits sind in Dollarwerten definiert. Das bedeutet, dass die tatsächliche Anzahl deiner Anfragen von dem von dir genutzten Modell abhängt. Günstigere Modelle wie MiniMax M2.5 erlauben mehr Anfragen, während teurere Modelle wie GLM-5 weniger erlauben.
|
||||||
|
|
||||||
Die untenstehende Tabelle bietet eine geschätzte Anzahl an Anfragen basierend auf typischen Go-Nutzungsmustern:
|
Die folgende Tabelle zeigt eine geschätzte Anzahl von Anfragen basierend auf typischen Go-Nutzungsmustern:
|
||||||
|
|
||||||
| | GLM-5 | Kimi K2.5 | MiniMax M2.5 |
|
| | GLM-5 | Kimi K2.5 | MiniMax M2.7 | MiniMax M2.5 |
|
||||||
| ------------------- | ----- | --------- | ------------ |
|
| ---------------------- | ----- | --------- | ------------ | ------------ |
|
||||||
| Anfragen pro 5 Std. | 1.150 | 1.850 | 30.000 |
|
| Anfragen pro 5 Stunden | 1.150 | 1.850 | 14.000 | 20.000 |
|
||||||
| Anfragen pro Woche | 2.880 | 4.630 | 75.000 |
|
| Anfragen pro Woche | 2.880 | 4.630 | 35.000 | 50.000 |
|
||||||
| Anfragen pro Monat | 5.750 | 9.250 | 150.000 |
|
| Anfragen pro Monat | 5.750 | 9.250 | 70.000 | 100.000 |
|
||||||
|
|
||||||
Die Schätzungen basieren auf beobachteten durchschnittlichen Nutzungsmustern:
|
Die Schätzungen basieren auf beobachteten durchschnittlichen Anfragemustern:
|
||||||
|
|
||||||
- GLM-5 — 700 Input-, 52.000 Cached-, 150 Output-Token pro Anfrage
|
- GLM-5 — 700 Input-, 52.000 Cached-, 150 Output-Tokens pro Anfrage
|
||||||
- Kimi K2.5 — 870 Input-, 55.000 Cached-, 200 Output-Token pro Anfrage
|
- Kimi K2.5 — 870 Input-, 55.000 Cached-, 200 Output-Tokens pro Anfrage
|
||||||
- MiniMax M2.5 — 300 Input-, 55.000 Cached-, 125 Output-Token pro Anfrage
|
- MiniMax M2.7/M2.5 — 300 Input-, 55.000 Cached-, 125 Output-Tokens pro Anfrage
|
||||||
|
|
||||||
Du kannst deine aktuelle Nutzung in der **<a href={console}>Konsole</a>** verfolgen.
|
Du kannst deine aktuelle Nutzung in der **<a href={console}>Console</a>** verfolgen.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Wenn du das Nutzungslimit erreichst, kannst du weiterhin die kostenlosen Modelle verwenden.
|
Wenn du das Nutzungslimit erreichst, kannst du weiterhin die kostenlosen Modelle verwenden.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Nutzungslimits können sich ändern, da wir aus der frühen Nutzung und dem Feedback lernen.
|
Die Nutzungslimits können sich ändern, während wir aus der frühen Nutzung und dem Feedback lernen.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Preise
|
### Nutzung über die Limits hinaus
|
||||||
|
|
||||||
OpenCode Go ist ein Abonnementplan für **10 $/Monat**. Unten stehen die Preise **pro 1 Mio. Token**.
|
Wenn du auch Guthaben auf deinem Zen-Konto hast, kannst du in der Console die Option **Use balance** aktivieren. Wenn diese aktiviert ist, greift Go auf dein Zen-Guthaben zurück, nachdem du deine Nutzungslimits erreicht hast, anstatt Anfragen zu blockieren.
|
||||||
|
|
||||||
| Modell | Input | Output | Cached Read |
|
|
||||||
| ------------ | ------ | ------ | ----------- |
|
|
||||||
| GLM-5 | 1,00 $ | 3,20 $ | 0,20 $ |
|
|
||||||
| Kimi K2.5 | 0,60 $ | 3,00 $ | 0,10 $ |
|
|
||||||
| MiniMax M2.5 | 0,30 $ | 1,20 $ | 0,03 $ |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Nutzung über Limits hinaus
|
|
||||||
|
|
||||||
Wenn du auch Guthaben auf deinem Zen-Konto hast, kannst du die Option **Use balance** in der Konsole aktivieren. Wenn aktiviert, greift Go auf dein Zen-Guthaben zurück, nachdem du deine Nutzungslimits erreicht hast, anstatt Anfragen zu blockieren.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Endpunkte
|
## Endpunkte
|
||||||
|
|
||||||
Du kannst auch über die folgenden API-Endpunkte auf Go-Modelle zugreifen.
|
Du kannst auf die Go-Modelle auch über die folgenden API-Endpunkte zugreifen.
|
||||||
|
|
||||||
| Modell | Modell-ID | Endpunkt | AI SDK Paket |
|
| Modell | Modell-ID | Endpunkt | AI SDK Package |
|
||||||
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
||||||
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
|
|
||||||
Die [Modell-ID](/docs/config/#models) in deiner OpenCode-Konfiguration verwendet das Format `opencode-go/<model-id>`. Zum Beispiel würdest du für Kimi K2.5 `opencode-go/kimi-k2.5` in deiner Konfiguration verwenden.
|
Die [Modell-ID](/docs/config/#models) in deiner OpenCode Config verwendet das Format `opencode-go/<model-id>`. Für Kimi K2.5 würdest du beispielsweise `opencode-go/kimi-k2.5` in deiner Config verwenden.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Datenschutz
|
## Datenschutz
|
||||||
|
|
||||||
Der Plan wurde primär für internationale Nutzer entwickelt, mit Modellen, die in den USA, der EU und Singapur gehostet werden, um einen stabilen weltweiten Zugriff zu gewährleisten.
|
Der Plan 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.
|
||||||
|
|
||||||
<a href={email}>Kontaktiere uns</a>, wenn du Fragen hast.
|
<a href={email}>Kontaktiere uns</a>, falls du Fragen hast.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Ziele
|
## Ziele
|
||||||
|
|
||||||
Wir haben OpenCode Go erstellt, um:
|
Wir haben OpenCode Go entwickelt, um:
|
||||||
|
|
||||||
1. AI-Coding für mehr Menschen durch ein kostengünstiges Abonnement **zugänglich** zu machen.
|
1. AI Coding durch ein kostengünstiges Abonnement für mehr Menschen **zugänglich** zu machen.
|
||||||
2. **Zuverlässigen** Zugriff auf die besten Open-Coding-Modelle zu bieten.
|
2. **Zuverlässigen** Zugriff auf die besten offenen Coding-Modelle zu bieten.
|
||||||
3. Modelle zu kuratieren, die für den Einsatz von Coding-Agents **getestet und gebenchmarkt** sind.
|
3. Modelle zu kuratieren, die für den Einsatz als Coding Agent **getestet und einem Benchmark unterzogen** wurden.
|
||||||
4. **Keinen Lock-in** zu haben, indem wir dir ermöglichen, jeden anderen Anbieter ebenfalls mit OpenCode zu nutzen.
|
4. **Keinen Lock-in-Effekt** zu haben, indem wir dir ermöglichen, auch jeden anderen Provider mit OpenCode zu nutzen.
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,49 @@
|
||||||
---
|
---
|
||||||
title: Go
|
title: Go
|
||||||
description: Suscripción de bajo coste para modelos de código abiertos.
|
description: Suscripción de bajo costo para modelos abiertos de programación.
|
||||||
---
|
---
|
||||||
|
|
||||||
import config from "../../../../config.mjs"
|
import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
export const console = config.console
|
||||||
export const email = `mailto:${config.email}`
|
export const email = `mailto:${config.email}`
|
||||||
|
|
||||||
OpenCode Go es una suscripción de bajo coste de **10 $/mes** que te ofrece acceso fiable a modelos populares de código abierto.
|
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.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
OpenCode Go está actualmente en beta.
|
OpenCode Go está actualmente en beta.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Go funciona como cualquier otro proveedor en OpenCode. Te suscribes a OpenCode Go y obtienes tu clave API. Es **completamente opcional** y no necesitas usarlo para utilizar OpenCode.
|
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.
|
Está diseñado principalmente para usuarios internacionales, con modelos alojados en EE. UU., la UE y Singapur para un acceso global estable.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Contexto
|
## Antecedentes
|
||||||
|
|
||||||
Los modelos abiertos han mejorado mucho. Ahora alcanzan un rendimiento cercano al de los modelos propietarios para tareas de programación. Y como muchos proveedores pueden servirlos de forma competitiva, suelen ser mucho más baratos.
|
Los modelos abiertos se han vuelto realmente buenos. Ahora alcanzan un rendimiento cercano a
|
||||||
|
los modelos propietarios en tareas de programación. Y como muchos proveedores pueden servirlos
|
||||||
|
de manera competitiva, suelen ser mucho más económicos.
|
||||||
|
|
||||||
Sin embargo, conseguir un acceso fiable y de baja latencia a ellos puede ser difícil. Los proveedores varían en calidad y disponibilidad.
|
Sin embargo, obtener un acceso confiable y de baja latencia a ellos puede ser difícil. Los proveedores
|
||||||
|
varían en calidad y disponibilidad.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Hemos probado un grupo selecto de modelos y proveedores que funcionan bien con OpenCode.
|
Probamos un grupo selecto de modelos y proveedores que funcionan bien con OpenCode.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Para solucionar esto, hicimos un par de cosas:
|
Para solucionar esto, hicimos un par de cosas:
|
||||||
|
|
||||||
1. Probamos un grupo selecto de modelos abiertos y hablamos con sus equipos sobre la mejor manera de ejecutarlos.
|
1. Probamos un grupo selecto de modelos abiertos y hablamos con sus equipos sobre cómo
|
||||||
2. Luego trabajamos con algunos proveedores para asegurarnos de que se sirvieran correctamente.
|
ejecutarlos mejor.
|
||||||
3. Finalmente, evaluamos la combinación de modelo/proveedor y elaboramos una lista que nos sentimos cómodos recomendando.
|
2. Luego trabajamos con algunos proveedores para asegurarnos de que se sirvieran
|
||||||
|
correctamente.
|
||||||
|
3. Finalmente, evaluamos el rendimiento de la combinación del modelo/proveedor y elaboramos
|
||||||
|
una lista que nos sentimos seguros de recomendar.
|
||||||
|
|
||||||
OpenCode Go te da acceso a estos modelos por **10 $/mes**.
|
OpenCode Go te da acceso a estos modelos por **$5 por tu primer mes**, luego **$10/mes**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -43,9 +51,11 @@ OpenCode Go te da acceso a estos modelos por **10 $/mes**.
|
||||||
|
|
||||||
OpenCode Go funciona como cualquier otro proveedor en OpenCode.
|
OpenCode Go funciona como cualquier otro proveedor en OpenCode.
|
||||||
|
|
||||||
1. Inicias sesión en **<a href={console}>OpenCode Zen</a>**, te suscribes a Go y copias tu clave API.
|
1. Inicias sesión en **<a href={console}>OpenCode Zen</a>**, te suscribes a Go y
|
||||||
2. Ejecutas el comando `/connect` en la TUI, seleccionas `OpenCode Go` y pegas tu clave API.
|
copias tu API key.
|
||||||
3. Ejecuta `/models` en la TUI para ver la lista de modelos disponibles a través de Go.
|
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
|
:::note
|
||||||
Solo un miembro por espacio de trabajo puede suscribirse a OpenCode Go.
|
Solo un miembro por espacio de trabajo puede suscribirse a OpenCode Go.
|
||||||
|
|
@ -56,8 +66,9 @@ La lista actual de modelos incluye:
|
||||||
- **GLM-5**
|
- **GLM-5**
|
||||||
- **Kimi K2.5**
|
- **Kimi K2.5**
|
||||||
- **MiniMax M2.5**
|
- **MiniMax M2.5**
|
||||||
|
- **MiniMax M2.7**
|
||||||
|
|
||||||
La lista de modelos puede cambiar a medida que probamos y añadimos nuevos.
|
La lista de modelos puede cambiar a medida que probamos y agregamos otros nuevos.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -65,65 +76,58 @@ La lista de modelos puede cambiar a medida que probamos y añadimos nuevos.
|
||||||
|
|
||||||
OpenCode Go incluye los siguientes límites:
|
OpenCode Go incluye los siguientes límites:
|
||||||
|
|
||||||
- **Límite de 5 horas** — 12 $ de uso
|
- **Límite de 5 horas** — $12 de uso
|
||||||
- **Límite semanal** — 30 $ de uso
|
- **Límite semanal** — $30 de uso
|
||||||
- **Límite mensual** — 60 $ de uso
|
- **Límite mensual** — $60 de uso
|
||||||
|
|
||||||
Los límites se definen en valor monetario. Esto significa que tu recuento real de solicitudes depende del modelo que uses. Los modelos más baratos como MiniMax M2.5 permiten más solicitudes, mientras que los modelos de mayor coste como GLM-5 permiten menos.
|
Los límites se definen en valor en dólares. Esto significa que tu cantidad real de peticiones depende del modelo que uses. Los modelos más económicos como MiniMax M2.5 permiten más peticiones, mientras que los modelos de mayor costo como GLM-5 permiten menos.
|
||||||
|
|
||||||
La siguiente tabla proporciona una estimación del recuento de solicitudes basada en patrones de uso típicos de Go:
|
La siguiente tabla proporciona una cantidad estimada de peticiones basada en los patrones típicos de uso de Go:
|
||||||
|
|
||||||
| | GLM-5 | Kimi K2.5 | MiniMax M2.5 |
|
| | GLM-5 | Kimi K2.5 | MiniMax M2.7 | MiniMax M2.5 |
|
||||||
| ----------------------- | ----- | --------- | ------------ |
|
| ---------------------- | ----- | --------- | ------------ | ------------ |
|
||||||
| solicitudes por 5 horas | 1.150 | 1.850 | 30.000 |
|
| peticiones por 5 horas | 1,150 | 1,850 | 14,000 | 20,000 |
|
||||||
| solicitudes por semana | 2.880 | 4.630 | 75.000 |
|
| peticiones por semana | 2,880 | 4,630 | 35,000 | 50,000 |
|
||||||
| solicitudes por mes | 5.750 | 9.250 | 150.000 |
|
| peticiones por mes | 5,750 | 9,250 | 70,000 | 100,000 |
|
||||||
|
|
||||||
Las estimaciones se basan en patrones de solicitud promedio observados:
|
Las estimaciones se basan en los patrones de peticiones promedio observados:
|
||||||
|
|
||||||
- GLM-5 — 700 de entrada, 52.000 en caché, 150 tokens de salida por solicitud
|
- GLM-5 — 700 tokens de entrada, 52,000 en caché, 150 tokens de salida por petición
|
||||||
- Kimi K2.5 — 870 de entrada, 55.000 en caché, 200 tokens de salida por solicitud
|
- Kimi K2.5 — 870 tokens de entrada, 55,000 en caché, 200 tokens de salida por petición
|
||||||
- MiniMax M2.5 — 300 de entrada, 55.000 en caché, 125 tokens de salida por solicitud
|
- MiniMax M2.7/M2.5 — 300 tokens de entrada, 55,000 en caché, 125 tokens de salida por petición
|
||||||
|
|
||||||
Puedes realizar un seguimiento de tu uso actual en la **<a href={console}>consola</a>**.
|
Puedes realizar un seguimiento de tu uso actual en la **<a href={console}>consola</a>**.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Si alcanzas el límite de uso, puedes seguir usando los modelos gratuitos.
|
Si alcanzas el límite de uso, puedes continuar usando los modelos gratuitos.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Los límites de uso pueden cambiar a medida que aprendamos del uso temprano y los comentarios.
|
Los límites de uso pueden cambiar a medida que aprendemos del uso inicial y de los comentarios (feedback).
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Precios
|
|
||||||
|
|
||||||
OpenCode Go es un plan de suscripción de **10 $/mes**. A continuación se muestran los precios **por 1M de tokens**.
|
|
||||||
|
|
||||||
| Modelo | Entrada | Salida | Lectura en caché |
|
|
||||||
| ------------ | ------- | ------ | ---------------- |
|
|
||||||
| GLM-5 | 1,00 $ | 3,20 $ | 0,20 $ |
|
|
||||||
| Kimi K2.5 | 0,60 $ | 3,00 $ | 0,10 $ |
|
|
||||||
| MiniMax M2.5 | 0,30 $ | 1,20 $ | 0,03 $ |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Uso más allá de los límites
|
### Uso más allá de los límites
|
||||||
|
|
||||||
Si también tienes créditos en tu saldo de Zen, puedes habilitar la opción **Usar saldo** en la consola. Cuando está habilitada, Go recurrirá a tu saldo de Zen después de que hayas alcanzado tus límites de uso en lugar de bloquear las solicitudes.
|
Si también tienes créditos en tu saldo de Zen, puedes habilitar la opción **Use balance**
|
||||||
|
en la consola. Cuando está habilitada, Go recurrirá a tu saldo de Zen
|
||||||
|
después de que hayas alcanzado tus límites de uso en lugar de bloquear las peticiones.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Endpoints
|
## Endpoints
|
||||||
|
|
||||||
También puedes acceder a los modelos de Go a través de los siguientes endpoints de API.
|
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 AI SDK |
|
| Modelo | ID del modelo | Endpoint | Paquete de AI SDK |
|
||||||
| ------------ | ------------- | ------------------------------------------------ | --------------------------- |
|
| ------------ | ------------- | ------------------------------------------------ | --------------------------- |
|
||||||
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
|
|
||||||
El [model id](/docs/config/#models) en tu configuración de OpenCode usa el formato `opencode-go/<model-id>`. Por ejemplo, para Kimi K2.5, usarías `opencode-go/kimi-k2.5` en tu configuración.
|
El [ID del modelo](/docs/config/#models) en tu configuración de OpenCode
|
||||||
|
usa el formato `opencode-go/<model-id>`. Por ejemplo, para Kimi K2.5, usarías
|
||||||
|
`opencode-go/kimi-k2.5` en tu configuración.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -139,7 +143,7 @@ El plan está diseñado principalmente para usuarios internacionales, con modelo
|
||||||
|
|
||||||
Creamos OpenCode Go para:
|
Creamos OpenCode Go para:
|
||||||
|
|
||||||
1. Hacer que la programación con IA sea **accesible** a más personas con una suscripción de bajo coste.
|
1. Hacer que la programación con IA sea **accesible** para más personas con una suscripción de bajo costo.
|
||||||
2. Proporcionar acceso **fiable** a los mejores modelos de código abierto.
|
2. Proporcionar un acceso **confiable** a los mejores modelos abiertos de programación.
|
||||||
3. Seleccionar modelos que han sido **probados y evaluados** para su uso con agentes de programación.
|
3. Seleccionar modelos que estén **probados y evaluados** para su uso en agentes de programación.
|
||||||
4. **Sin ataduras**, permitiéndote usar cualquier otro proveedor con OpenCode también.
|
4. Evitar la **dependencia (lock-in)** al permitirte usar también cualquier otro proveedor con OpenCode.
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,27 @@
|
||||||
---
|
---
|
||||||
title: Go
|
title: Go
|
||||||
description: Abonnement à bas coût pour les modèles de code ouverts.
|
description: Abonnement à bas coût pour les modèles de codage ouverts.
|
||||||
---
|
---
|
||||||
|
|
||||||
import config from "../../../../config.mjs"
|
import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
export const console = config.console
|
||||||
export const email = `mailto:${config.email}`
|
export const email = `mailto:${config.email}`
|
||||||
|
|
||||||
OpenCode Go est un abonnement à bas coût de **10 $/mois** qui vous donne un accès fiable aux modèles de code ouverts populaires.
|
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.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
OpenCode Go est actuellement en bêta.
|
OpenCode Go est actuellement en version bêta.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Go fonctionne comme tout autre fournisseur dans OpenCode. Vous vous abonnez à OpenCode Go et obtenez votre clé API. C'est **complètement optionnel** et vous n'avez pas besoin de l'utiliser pour utiliser OpenCode.
|
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, en UE et à Singapour pour un accès mondial stable.
|
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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Contexte
|
## Contexte
|
||||||
|
|
||||||
Les modèles ouverts sont devenus vraiment bons. Ils atteignent maintenant des performances proches des modèles propriétaires pour les tâches de codage. Et parce que de nombreux fournisseurs peuvent les servir de manière compétitive, ils sont généralement beaucoup moins chers.
|
Les modèles ouverts sont devenus vraiment performants. Ils atteignent désormais des performances proches de celles des modèles propriétaires pour les tâches de codage. Et comme de nombreux fournisseurs peuvent les proposer de manière compétitive, ils sont généralement beaucoup moins chers.
|
||||||
|
|
||||||
Cependant, obtenir un accès fiable et à faible latence à ces modèles peut être difficile. Les fournisseurs varient en qualité et en disponibilité.
|
Cependant, obtenir un accès fiable et à faible latence à ces modèles peut être difficile. Les fournisseurs varient en qualité et en disponibilité.
|
||||||
|
|
||||||
|
|
@ -32,32 +32,33 @@ Nous avons testé un groupe sélectionné de modèles et de fournisseurs qui fon
|
||||||
Pour remédier à cela, nous avons fait plusieurs choses :
|
Pour remédier à cela, nous avons fait plusieurs choses :
|
||||||
|
|
||||||
1. Nous avons testé un groupe sélectionné de modèles ouverts et discuté avec leurs équipes de la meilleure façon de les exécuter.
|
1. Nous avons testé un groupe sélectionné de modèles ouverts et discuté avec leurs équipes de la meilleure façon de les exécuter.
|
||||||
2. Nous avons ensuite travaillé avec quelques fournisseurs pour nous assurer qu'ils étaient servis correctement.
|
2. Nous avons ensuite travaillé avec quelques fournisseurs pour nous assurer qu'ils étaient correctement servis.
|
||||||
3. Enfin, nous avons évalué la combinaison modèle/fournisseur et établi une liste que nous nous sentons à l'aise de recommander.
|
3. Enfin, nous avons évalué les performances de la combinaison modèle/fournisseur et avons dressé une liste que nous nous sentons à l'aise de recommander.
|
||||||
|
|
||||||
OpenCode Go vous donne accès à ces modèles pour **10 $/mois**.
|
OpenCode Go vous donne accès à ces modèles pour **5 $ pour votre premier mois**, puis **10 $/mois**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Comment ça marche
|
## Comment ça marche
|
||||||
|
|
||||||
OpenCode Go fonctionne comme tout autre fournisseur dans OpenCode.
|
OpenCode Go fonctionne comme n'importe quel autre fournisseur dans OpenCode.
|
||||||
|
|
||||||
1. Vous vous connectez à **<a href={console}>OpenCode Zen</a>**, vous vous abonnez à Go et copiez votre clé API.
|
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é 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.
|
3. Exécutez `/models` dans la TUI pour voir la liste des modèles disponibles via Go.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
Un seul membre par espace de travail peut s'abonner à OpenCode Go.
|
Un seul membre par espace de travail peut s'abonner à OpenCode Go.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
La liste actuelle des modèles inclut :
|
La liste actuelle des modèles comprend :
|
||||||
|
|
||||||
- **GLM-5**
|
- **GLM-5**
|
||||||
- **Kimi K2.5**
|
- **Kimi K2.5**
|
||||||
- **MiniMax M2.5**
|
- **MiniMax M2.5**
|
||||||
|
- **MiniMax M2.7**
|
||||||
|
|
||||||
La liste des modèles peut changer à mesure que nous testons et ajoutons de nouveaux modèles.
|
La liste des modèles peut changer au fur et à mesure que nous en testons et en ajoutons de nouveaux.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -69,21 +70,21 @@ OpenCode Go inclut les limites suivantes :
|
||||||
- **Limite hebdomadaire** — 30 $ d'utilisation
|
- **Limite hebdomadaire** — 30 $ d'utilisation
|
||||||
- **Limite mensuelle** — 60 $ d'utilisation
|
- **Limite mensuelle** — 60 $ d'utilisation
|
||||||
|
|
||||||
Les limites sont définies en valeur monétaire. Cela signifie que votre nombre réel de requêtes dépend du modèle que vous utilisez. Les modèles moins chers comme MiniMax M2.5 permettent plus de requêtes, tandis que les modèles plus coûteux comme GLM-5 en permettent moins.
|
Les limites sont définies en valeur monétaire (dollars). Cela signifie que votre nombre réel de requêtes dépend du modèle que vous utilisez. Les modèles moins chers comme MiniMax M2.5 permettent plus de requêtes, tandis que les modèles plus coûteux comme GLM-5 en permettent moins.
|
||||||
|
|
||||||
Le tableau ci-dessous fournit une estimation du nombre de requêtes basée sur des modèles d'utilisation typiques de Go :
|
Le tableau ci-dessous fournit une estimation du nombre de requêtes basée sur des modèles d'utilisation typiques de Go :
|
||||||
|
|
||||||
| | GLM-5 | Kimi K2.5 | MiniMax M2.5 |
|
| | GLM-5 | Kimi K2.5 | MiniMax M2.7 | MiniMax M2.5 |
|
||||||
| --------------------- | ----- | --------- | ------------ |
|
| --------------------- | ----- | --------- | ------------ | ------------ |
|
||||||
| requêtes par 5 heures | 1 150 | 1 850 | 30 000 |
|
| requêtes par 5 heures | 1,150 | 1,850 | 14,000 | 20,000 |
|
||||||
| requêtes par semaine | 2 880 | 4 630 | 75 000 |
|
| requêtes par semaine | 2,880 | 4,630 | 35,000 | 50,000 |
|
||||||
| requêtes par mois | 5 750 | 9 250 | 150 000 |
|
| requêtes par mois | 5,750 | 9,250 | 70,000 | 100,000 |
|
||||||
|
|
||||||
Les estimations sont basées sur des modèles de requêtes moyens observés :
|
Les estimations sont basées sur les modèles de requêtes moyens observés :
|
||||||
|
|
||||||
- GLM-5 — 700 tokens d'entrée, 52 000 en cache, 150 de sortie par requête
|
- GLM-5 — 700 tokens en entrée, 52,000 en cache, 150 tokens en sortie par requête
|
||||||
- Kimi K2.5 — 870 tokens d'entrée, 55 000 en cache, 200 de sortie par requête
|
- Kimi K2.5 — 870 tokens en entrée, 55,000 en cache, 200 tokens en sortie par requête
|
||||||
- MiniMax M2.5 — 300 tokens d'entrée, 55 000 en cache, 125 de sortie par requête
|
- MiniMax M2.7/M2.5 — 300 tokens en entrée, 55,000 en cache, 125 tokens en sortie par requête
|
||||||
|
|
||||||
Vous pouvez suivre votre utilisation actuelle dans la **<a href={console}>console</a>**.
|
Vous pouvez suivre votre utilisation actuelle dans la **<a href={console}>console</a>**.
|
||||||
|
|
||||||
|
|
@ -91,45 +92,34 @@ Vous pouvez suivre votre utilisation actuelle dans la **<a href={console}>consol
|
||||||
Si vous atteignez la limite d'utilisation, vous pouvez continuer à utiliser les modèles gratuits.
|
Si vous atteignez la limite d'utilisation, vous pouvez continuer à utiliser les modèles gratuits.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Les limites d'utilisation peuvent changer à mesure que nous apprenons des premiers usages et retours.
|
Les limites d'utilisation peuvent changer au fur et à mesure que nous tirons des enseignements des premières utilisations et des retours.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Tarification
|
|
||||||
|
|
||||||
OpenCode Go est un plan d'abonnement à **10 $/mois**. Ci-dessous se trouvent les prix **par 1M de tokens**.
|
|
||||||
|
|
||||||
| Modèle | Entrée | Sortie | Lecture en cache |
|
|
||||||
| ------------ | ------ | ------ | ---------------- |
|
|
||||||
| GLM-5 | 1,00 $ | 3,20 $ | 0,20 $ |
|
|
||||||
| Kimi K2.5 | 0,60 $ | 3,00 $ | 0,10 $ |
|
|
||||||
| MiniMax M2.5 | 0,30 $ | 1,20 $ | 0,03 $ |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Utilisation au-delà des limites
|
### Utilisation au-delà des limites
|
||||||
|
|
||||||
Si vous avez aussi des crédits sur votre solde Zen, vous pouvez activer l'option **Use balance** dans la console. Lorsqu'elle est activée, Go basculera sur votre solde Zen après que vous ayez atteint vos limites d'utilisation au lieu de bloquer les requêtes.
|
Si vous avez également des crédits sur votre solde Zen, vous pouvez activer l'option **Use balance** dans la console. Lorsqu'elle est activée, Go se rabattra sur votre solde Zen après que vous ayez atteint vos limites d'utilisation au lieu de bloquer les requêtes.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Endpoints
|
## Points de terminaison
|
||||||
|
|
||||||
Vous pouvez également accéder aux modèles Go via les endpoints API suivants.
|
Vous pouvez également accéder aux modèles Go via les points de terminaison d'API suivants.
|
||||||
|
|
||||||
| Modèle | ID du modèle | Endpoint | Package AI SDK |
|
| Modèle | ID de modèle | Point de terminaison | Package AI SDK |
|
||||||
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
||||||
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
|
|
||||||
L'[ID du modèle](/docs/config/#models) dans votre configuration OpenCode utilise le format `opencode-go/<model-id>`. Par exemple, pour Kimi K2.5, vous utiliseriez `opencode-go/kimi-k2.5` dans votre configuration.
|
L'[ID de modèle](/docs/config/#models) dans votre configuration OpenCode utilise le format `opencode-go/<model-id>`. Par exemple, pour Kimi K2.5, vous utiliseriez `opencode-go/kimi-k2.5` dans votre configuration.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Confidentialité
|
## Confidentialité
|
||||||
|
|
||||||
Le plan est conçu principalement pour les utilisateurs internationaux, avec des modèles hébergés aux États-Unis, en UE et à Singapour pour un accès mondial stable.
|
Le forfait 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.
|
||||||
|
|
||||||
<a href={email}>Contactez-nous</a> si vous avez des questions.
|
<a href={email}>Contactez-nous</a> si vous avez des questions.
|
||||||
|
|
||||||
|
|
@ -139,7 +129,7 @@ Le plan est conçu principalement pour les utilisateurs internationaux, avec des
|
||||||
|
|
||||||
Nous avons créé OpenCode Go pour :
|
Nous avons créé OpenCode Go pour :
|
||||||
|
|
||||||
1. Rendre le codage par IA **accessible** à plus de personnes avec un abonnement à bas coût.
|
1. Rendre le codage par IA **accessible** à un plus grand nombre de personnes avec un abonnement à bas coût.
|
||||||
2. Fournir un accès **fiable** aux meilleurs modèles de code ouverts.
|
2. Fournir un accès **fiable** aux meilleurs modèles de codage ouverts.
|
||||||
3. Sélectionner des modèles qui sont **testés et évalués** pour l'utilisation d'agents de codage.
|
3. Sélectionner des modèles qui sont **testés et évalués** pour une utilisation en tant qu'agent de codage.
|
||||||
4. N'avoir **aucun verrouillage** en vous permettant d'utiliser tout autre fournisseur avec OpenCode également.
|
4. N'avoir **aucun verrouillage exclusif** en vous permettant d'utiliser n'importe quel autre fournisseur avec OpenCode également.
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,32 @@
|
||||||
---
|
---
|
||||||
title: Go
|
title: Go
|
||||||
description: Abbonamento a basso costo per modelli di coding open source.
|
description: Abbonamento a basso costo per modelli di programmazione aperti.
|
||||||
---
|
---
|
||||||
|
|
||||||
import config from "../../../../config.mjs"
|
import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
export const console = config.console
|
||||||
export const email = `mailto:${config.email}`
|
export const email = `mailto:${config.email}`
|
||||||
|
|
||||||
OpenCode Go è un abbonamento a basso costo di **$10/mese** che ti offre un accesso affidabile ai modelli di coding open source più popolari.
|
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.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
OpenCode Go è attualmente in beta.
|
OpenCode Go è attualmente in beta.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Go funziona come qualsiasi altro provider in OpenCode. Ti abboni a OpenCode Go e ottieni la tua chiave API. È **completamente opzionale** e non è necessario utilizzarlo per usare OpenCode.
|
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 utenti internazionali, con modelli ospitati negli Stati Uniti, UE e Singapore per un accesso globale stabile.
|
È progettato principalmente per gli utenti internazionali, con modelli ospitati negli Stati Uniti, nell'Unione Europea e a Singapore per un accesso globale stabile.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Contesto
|
## Contesto
|
||||||
|
|
||||||
I modelli open source sono diventati davvero validi. Ora raggiungono prestazioni vicine ai modelli proprietari per le attività di coding. E poiché molti provider possono servirli in modo competitivo, sono solitamente molto più economici.
|
I modelli aperti sono diventati davvero validi. Ora raggiungono prestazioni vicine a quelle dei modelli proprietari per le attività di programmazione. E poiché molti provider possono fornirli in modo competitivo, di solito sono molto più economici.
|
||||||
|
|
||||||
Tuttavia, ottenere un accesso affidabile e a bassa latenza può essere difficile. I provider variano in termini di qualità e disponibilità.
|
Tuttavia, ottenere un accesso affidabile e a bassa latenza può essere difficile. I provider
|
||||||
|
variano per qualità e disponibilità.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Abbiamo testato un gruppo selezionato di modelli e provider che funzionano bene con OpenCode.
|
Abbiamo testato un gruppo selezionato di modelli e provider che funzionano bene con OpenCode.
|
||||||
|
|
@ -31,11 +34,14 @@ Abbiamo testato un gruppo selezionato di modelli e provider che funzionano bene
|
||||||
|
|
||||||
Per risolvere questo problema, abbiamo fatto un paio di cose:
|
Per risolvere questo problema, abbiamo fatto un paio di cose:
|
||||||
|
|
||||||
1. Abbiamo testato un gruppo selezionato di modelli open source e parlato con i loro team su come eseguirli al meglio.
|
1. Abbiamo testato un gruppo selezionato di modelli aperti e parlato con i loro team su come
|
||||||
2. Abbiamo poi lavorato con alcuni provider per assicurarci che questi venissero serviti correttamente.
|
eseguirli al meglio.
|
||||||
3. Infine, abbiamo effettuato benchmark sulla combinazione modello/provider e abbiamo stilato un elenco che ci sentiamo di raccomandare.
|
2. Abbiamo quindi collaborato con alcuni provider per assicurarci che venissero forniti
|
||||||
|
correttamente.
|
||||||
|
3. Infine, abbiamo eseguito dei benchmark sulla combinazione modello/provider e abbiamo stilato
|
||||||
|
un elenco che ci sentiamo di raccomandare.
|
||||||
|
|
||||||
OpenCode Go ti dà accesso a questi modelli per **$10/mese**.
|
OpenCode Go ti dà accesso a questi modelli a **5 $ per il primo mese**, poi a **10 $/mese**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -43,8 +49,10 @@ OpenCode Go ti dà accesso a questi modelli per **$10/mese**.
|
||||||
|
|
||||||
OpenCode Go funziona come qualsiasi altro provider in OpenCode.
|
OpenCode Go funziona come qualsiasi altro provider in OpenCode.
|
||||||
|
|
||||||
1. Accedi a **<a href={console}>OpenCode Zen</a>**, abbonati a Go e copia la tua chiave API.
|
1. Accedi a **<a href={console}>OpenCode Zen</a>**, ti abboni a Go e
|
||||||
2. Esegui il comando `/connect` nella TUI, seleziona `OpenCode Go` e incolla la tua chiave API.
|
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.
|
3. Esegui `/models` nella TUI per vedere l'elenco dei modelli disponibili tramite Go.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
|
|
@ -56,6 +64,7 @@ L'elenco attuale dei modelli include:
|
||||||
- **GLM-5**
|
- **GLM-5**
|
||||||
- **Kimi K2.5**
|
- **Kimi K2.5**
|
||||||
- **MiniMax M2.5**
|
- **MiniMax M2.5**
|
||||||
|
- **MiniMax M2.7**
|
||||||
|
|
||||||
L'elenco dei modelli potrebbe cambiare man mano che ne testiamo e aggiungiamo di nuovi.
|
L'elenco dei modelli potrebbe cambiare man mano che ne testiamo e aggiungiamo di nuovi.
|
||||||
|
|
||||||
|
|
@ -65,51 +74,41 @@ L'elenco dei modelli potrebbe cambiare man mano che ne testiamo e aggiungiamo di
|
||||||
|
|
||||||
OpenCode Go include i seguenti limiti:
|
OpenCode Go include i seguenti limiti:
|
||||||
|
|
||||||
- **Limite di 5 ore** — $12 di utilizzo
|
- **Limite di 5 ore** — 12 $ di utilizzo
|
||||||
- **Limite settimanale** — $30 di utilizzo
|
- **Limite settimanale** — 30 $ di utilizzo
|
||||||
- **Limite mensile** — $60 di utilizzo
|
- **Limite mensile** — 60 $ di utilizzo
|
||||||
|
|
||||||
I limiti sono definiti in valore monetario. Ciò significa che il conteggio effettivo delle richieste dipende dal modello utilizzato. Modelli più economici come MiniMax M2.5 consentono più richieste, mentre modelli più costosi come GLM-5 ne consentono meno.
|
I limiti sono definiti in valore in dollari. Questo significa che il conteggio effettivo delle richieste dipende dal modello utilizzato. Modelli più economici come MiniMax M2.5 consentono più richieste, mentre modelli più costosi come GLM-5 ne consentono di meno.
|
||||||
|
|
||||||
La tabella seguente fornisce una stima del conteggio delle richieste basata su tipici modelli di utilizzo di Go:
|
La tabella seguente fornisce una stima del conteggio delle richieste in base a pattern di utilizzo tipici di Go:
|
||||||
|
|
||||||
| | GLM-5 | Kimi K2.5 | MiniMax M2.5 |
|
| | GLM-5 | Kimi K2.5 | MiniMax M2.7 | MiniMax M2.5 |
|
||||||
| --------------------- | ----- | --------- | ------------ |
|
| --------------------- | ----- | --------- | ------------ | ------------ |
|
||||||
| richieste ogni 5 ore | 1.150 | 1.850 | 30.000 |
|
| richieste ogni 5 ore | 1.150 | 1.850 | 14.000 | 20.000 |
|
||||||
| richieste a settimana | 2.880 | 4.630 | 75.000 |
|
| richieste a settimana | 2.880 | 4.630 | 35.000 | 50.000 |
|
||||||
| richieste al mese | 5.750 | 9.250 | 150.000 |
|
| richieste al mese | 5.750 | 9.250 | 70.000 | 100.000 |
|
||||||
|
|
||||||
Le stime si basano sui modelli di richiesta medi osservati:
|
Le stime si basano sui pattern medi di richieste osservati:
|
||||||
|
|
||||||
- GLM-5 — 700 input, 52.000 cached, 150 output tokens per richiesta
|
- GLM-5 — 700 di input, 52.000 in cache, 150 token di output per richiesta
|
||||||
- Kimi K2.5 — 870 input, 55.000 cached, 200 output tokens per richiesta
|
- Kimi K2.5 — 870 di input, 55.000 in cache, 200 token di output per richiesta
|
||||||
- MiniMax M2.5 — 300 input, 55.000 cached, 125 output tokens per richiesta
|
- MiniMax M2.7/M2.5 — 300 di input, 55.000 in cache, 125 token di output per richiesta
|
||||||
|
|
||||||
Puoi monitorare il tuo utilizzo attuale nella **<a href={console}>console</a>**.
|
Puoi monitorare il tuo utilizzo attuale nella **<a href={console}>console</a>**.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Se raggiungi il limite di utilizzo, puoi continuare a utilizzare i modelli gratuiti.
|
Se raggiungi il limite di utilizzo, puoi continuare a usare i modelli gratuiti.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
I limiti di utilizzo potrebbero cambiare man mano che impariamo dall'utilizzo iniziale e dai feedback.
|
I limiti di utilizzo potrebbero cambiare man mano che raccogliamo dati sull'utilizzo iniziale e feedback.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Prezzi
|
|
||||||
|
|
||||||
OpenCode Go è un piano di abbonamento da **$10/mese**. Di seguito sono riportati i prezzi **per 1M di token**.
|
|
||||||
|
|
||||||
| Modello | Input | Output | Lettura Cached |
|
|
||||||
| ------------ | ----- | ------ | -------------- |
|
|
||||||
| GLM-5 | $1.00 | $3.20 | $0.20 |
|
|
||||||
| Kimi K2.5 | $0.60 | $3.00 | $0.10 |
|
|
||||||
| MiniMax M2.5 | $0.30 | $1.20 | $0.03 |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Utilizzo oltre i limiti
|
### Utilizzo oltre i limiti
|
||||||
|
|
||||||
Se hai anche crediti sul tuo saldo Zen, puoi abilitare l'opzione **Use balance** nella console. Quando abilitata, Go utilizzerà il tuo saldo Zen dopo aver raggiunto i limiti di utilizzo invece di bloccare le richieste.
|
Se hai anche dei crediti nel tuo saldo Zen, puoi abilitare l'opzione **Use balance**
|
||||||
|
nella console. Quando è abilitata, Go ripiegherà sul tuo saldo Zen
|
||||||
|
dopo che avrai raggiunto i limiti di utilizzo invece di bloccare le richieste.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -121,17 +120,20 @@ Puoi anche accedere ai modelli Go tramite i seguenti endpoint API.
|
||||||
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
||||||
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
|
|
||||||
Il [model id](/docs/config/#models) nella tua configurazione OpenCode utilizza il formato `opencode-go/<model-id>`. Ad esempio, per Kimi K2.5, useresti `opencode-go/kimi-k2.5` nella tua configurazione.
|
Il [model id](/docs/config/#models) nella tua OpenCode config
|
||||||
|
utilizza il formato `opencode-go/<model-id>`. Ad esempio, per Kimi K2.5, useresti
|
||||||
|
`opencode-go/kimi-k2.5` nella tua configurazione.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Privacy
|
## Privacy
|
||||||
|
|
||||||
Il piano è progettato principalmente per utenti internazionali, con modelli ospitati negli Stati Uniti, UE e Singapore per un accesso globale stabile.
|
Il piano è progettato principalmente per gli utenti internazionali, con modelli ospitati negli Stati Uniti, nell'Unione Europea e a Singapore per un accesso globale stabile.
|
||||||
|
|
||||||
<a href={email}>Contattaci</a> se hai domande.
|
<a href={email}>Contattaci</a> in caso di domande.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -139,7 +141,7 @@ Il piano è progettato principalmente per utenti internazionali, con modelli osp
|
||||||
|
|
||||||
Abbiamo creato OpenCode Go per:
|
Abbiamo creato OpenCode Go per:
|
||||||
|
|
||||||
1. Rendere l'AI per il coding **accessibile** a più persone con un abbonamento a basso costo.
|
1. Rendere la programmazione con l'IA **accessibile** a più persone tramite un abbonamento a basso costo.
|
||||||
2. Fornire un accesso **affidabile** ai migliori modelli di coding open source.
|
2. Fornire un accesso **affidabile** ai migliori modelli di programmazione aperti.
|
||||||
3. Curare modelli che sono **testati e benchmarked** per l'uso con agenti di coding.
|
3. Curare modelli che sono **testati e valutati tramite benchmark** per l'uso con gli agenti di programmazione.
|
||||||
4. Non avere **alcun lock-in** permettendoti di utilizzare qualsiasi altro provider con OpenCode.
|
4. Non avere **nessun lock-in**, permettendoti di utilizzare anche qualsiasi altro provider con OpenCode.
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ OpenCode Zen è una lista di modelli testati e verificati dal team di OpenCode.
|
||||||
OpenCode Zen è attualmente in beta.
|
OpenCode Zen è attualmente in beta.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Zen funziona come qualunque altro provider in OpenCode. Accedi a OpenCode Zen e ottieni la tua chiave API. È **completamente opzionale**: non devi usarlo per usare OpenCode.
|
Zen funziona come qualunque altro provider in OpenCode. Accedi a OpenCode Zen e ottieni la tua chiave API. È **completamente opzionale** e non devi usarlo per usare OpenCode.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -33,7 +33,7 @@ Per risolvere, abbiamo fatto alcune cose:
|
||||||
2. Poi abbiamo lavorato con alcuni provider per assicurarci che venissero serviti correttamente.
|
2. Poi abbiamo lavorato con alcuni provider per assicurarci che venissero serviti correttamente.
|
||||||
3. Infine, abbiamo fatto benchmark delle combinazioni modello/provider e creato una lista che ci sentiamo di raccomandare.
|
3. Infine, abbiamo fatto benchmark delle combinazioni modello/provider e creato una lista che ci sentiamo di raccomandare.
|
||||||
|
|
||||||
OpenCode Zen e un gateway AI che ti dà accesso a questi modelli.
|
OpenCode Zen è un gateway AI che ti dà accesso a questi modelli.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -53,43 +53,42 @@ Paghi per richiesta e puoi aggiungere credito al tuo account.
|
||||||
|
|
||||||
Puoi anche accedere ai nostri modelli tramite i seguenti endpoint API.
|
Puoi anche accedere ai nostri modelli tramite i seguenti endpoint API.
|
||||||
|
|
||||||
| Modello | ID modello | Endpoint | Pacchetto AI SDK |
|
| Modello | ID modello | Endpoint | Pacchetto AI SDK |
|
||||||
| ------------------ | ------------------ | -------------------------------------------------- | --------------------------- |
|
| --------------------- | --------------------- | -------------------------------------------------- | --------------------------- |
|
||||||
| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
| GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
| GPT 5.4 Mini | gpt-5.4-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
| GPT 5.4 Nano | gpt-5.4-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| GPT 5.1 Codex | gpt-5.1-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
| GPT 5.3 Codex Spark | gpt-5.3-codex-spark | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| GPT 5.1 Codex Max | gpt-5.1-codex-max | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
| GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| GPT 5.1 Codex Mini | gpt-5.1-codex-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
| GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
| GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
| GPT 5.1 Codex | gpt-5.1-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
| GPT 5.1 Codex Max | gpt-5.1-codex-max | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
| GPT 5.1 Codex Mini | gpt-5.1-codex-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
| GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
| GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
| GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` |
|
| Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` |
|
| Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` |
|
| Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` |
|
||||||
| MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` |
|
||||||
| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| MiMo V2 Flash Free | mimo-v2-flash-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
|
||||||
|
|
||||||
Il [model id](/docs/config/#models) nella config di OpenCode usa il formato `opencode/<model-id>`. Per esempio, per GPT 5.2 Codex useresti `opencode/gpt-5.2-codex` nella config.
|
Il [model id](/docs/config/#models) nella config di OpenCode usa il formato `opencode/<model-id>`. Per esempio, per GPT 5.3 Codex, useresti `opencode/gpt-5.3-codex` nella config.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -107,49 +106,46 @@ https://opencode.ai/zen/v1/models
|
||||||
|
|
||||||
Supportiamo un modello pay-as-you-go. Qui sotto trovi i prezzi **per 1M token**.
|
Supportiamo un modello pay-as-you-go. Qui sotto trovi i prezzi **per 1M token**.
|
||||||
|
|
||||||
| Modello | Input | Output | Lettura in cache | Scrittura in cache |
|
| Modello | Input | Output | Lettura in cache | Scrittura in cache |
|
||||||
| --------------------------------- | ------ | ------ | ---------------- | ------------------ |
|
| --------------------------------- | ------ | ------- | ---------------- | ------------------ |
|
||||||
| Big Pickle | Gratis | Gratis | Gratis | - |
|
| Big Pickle | Gratis | Gratis | Gratis | - |
|
||||||
| MiniMax M2.5 Free | Gratis | Gratis | Gratis | - |
|
| MiMo V2 Flash Free | Gratis | Gratis | Gratis | - |
|
||||||
| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | - |
|
| Nemotron 3 Super Free | Gratis | Gratis | Gratis | - |
|
||||||
| MiniMax M2.1 | $0.30 | $1.20 | $0.10 | - |
|
| MiniMax M2.5 Free | Gratis | Gratis | Gratis | - |
|
||||||
| GLM 5 | $1.00 | $3.20 | $0.20 | - |
|
| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 |
|
||||||
| GLM 4.7 | $0.60 | $2.20 | $0.10 | - |
|
| GLM 5 | $1.00 | $3.20 | $0.20 | - |
|
||||||
| GLM 4.6 | $0.60 | $2.20 | $0.10 | - |
|
| Kimi K2.5 | $0.60 | $3.00 | $0.10 | - |
|
||||||
| Kimi K2.5 | $0.60 | $3.00 | $0.08 | - |
|
| Qwen3 Coder 480B | $0.45 | $1.50 | - | - |
|
||||||
| Kimi K2 Thinking | $0.40 | $2.50 | - | - |
|
| Claude Opus 4.6 | $5.00 | $25.00 | $0.50 | $6.25 |
|
||||||
| Kimi K2 | $0.40 | $2.50 | - | - |
|
| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 |
|
||||||
| Qwen3 Coder 480B | $0.45 | $1.50 | - | - |
|
| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 |
|
||||||
| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 |
|
| Claude Sonnet 4.6 | $3.00 | $15.00 | $0.30 | $3.75 |
|
||||||
| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 |
|
| Claude Sonnet 4.5 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
|
||||||
| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 |
|
| Claude Sonnet 4.5 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
|
||||||
| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 |
|
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
|
||||||
| Claude Sonnet 4.6 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
|
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
|
||||||
| Claude Sonnet 4.6 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
|
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
|
||||||
| Claude Sonnet 4.5 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
|
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
|
||||||
| Claude Sonnet 4.5 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
|
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
|
||||||
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
|
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
|
||||||
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
|
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
|
||||||
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
|
| GPT 5.4 | $2.50 | $15.00 | $0.25 | - |
|
||||||
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
|
| GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - |
|
||||||
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
|
| GPT 5.4 Mini | $0.75 | $4.50 | $0.075 | - |
|
||||||
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
|
| GPT 5.4 Nano | $0.20 | $1.25 | $0.02 | - |
|
||||||
| Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
|
| GPT 5.3 Codex Spark | $1.75 | $14.00 | $0.175 | - |
|
||||||
| Gemini 3 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
|
| GPT 5.3 Codex | $1.75 | $14.00 | $0.175 | - |
|
||||||
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
|
| GPT 5.2 | $1.75 | $14.00 | $0.175 | - |
|
||||||
| GPT 5.4 | $2.50 | $15.00 | $0.25 | - |
|
| GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - |
|
||||||
| GPT 5.3 Codex | $1.75 | $14.00 | $0.175 | - |
|
| GPT 5.1 | $1.07 | $8.50 | $0.107 | - |
|
||||||
| GPT 5.2 | $1.75 | $14.00 | $0.175 | - |
|
| GPT 5.1 Codex | $1.07 | $8.50 | $0.107 | - |
|
||||||
| GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - |
|
| GPT 5.1 Codex Max | $1.25 | $10.00 | $0.125 | - |
|
||||||
| GPT 5.1 | $1.07 | $8.50 | $0.107 | - |
|
| GPT 5.1 Codex Mini | $0.25 | $2.00 | $0.025 | - |
|
||||||
| GPT 5.1 Codex | $1.07 | $8.50 | $0.107 | - |
|
| GPT 5 | $1.07 | $8.50 | $0.107 | - |
|
||||||
| GPT 5.1 Codex Max | $1.25 | $10.00 | $0.125 | - |
|
| GPT 5 Codex | $1.07 | $8.50 | $0.107 | - |
|
||||||
| GPT 5.1 Codex Mini | $0.25 | $2.00 | $0.025 | - |
|
| GPT 5 Nano | Gratis | Gratis | Gratis | - |
|
||||||
| GPT 5 | $1.07 | $8.50 | $0.107 | - |
|
|
||||||
| GPT 5 Codex | $1.07 | $8.50 | $0.107 | - |
|
|
||||||
| GPT 5 Nano | Gratis | Gratis | Gratis | - |
|
|
||||||
|
|
||||||
Potresti notare _Claude Haiku 3.5_ nella cronologia d'uso. E un [modello a basso costo](/docs/config/#models) usato per generare i titoli delle sessioni.
|
Potresti notare _Claude Haiku 3.5_ nella cronologia d'uso. È un [modello a basso costo](/docs/config/#models) usato per generare i titoli delle sessioni.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
Le commissioni della carta di credito vengono ribaltate al costo (4.4% + $0.30 per transazione); non addebitiamo nulla oltre a questo.
|
Le commissioni della carta di credito vengono ribaltate al costo (4.4% + $0.30 per transazione); non addebitiamo nulla oltre a questo.
|
||||||
|
|
@ -157,7 +153,9 @@ Le commissioni della carta di credito vengono ribaltate al costo (4.4% + $0.30 p
|
||||||
|
|
||||||
I modelli gratuiti:
|
I modelli gratuiti:
|
||||||
|
|
||||||
- MiniMax M2.5 Free e disponibile su OpenCode per un periodo limitato. Il team usa questo tempo per raccogliere feedback e migliorare il modello.
|
- MiniMax M2.5 Free è disponibile su OpenCode per un periodo limitato. Il team usa questo tempo per raccogliere feedback e migliorare il modello.
|
||||||
|
- MiMo V2 Flash Free è disponibile su OpenCode per un periodo limitato. Il team usa questo tempo per raccogliere feedback e migliorare il modello.
|
||||||
|
- Nemotron 3 Super Free è disponibile su OpenCode per un periodo limitato. Il team usa questo tempo per raccogliere feedback e migliorare il modello.
|
||||||
- Big Pickle è un modello stealth gratuito su OpenCode per un periodo limitato. Il team usa questo tempo per raccogliere feedback e migliorare il modello.
|
- Big Pickle è un modello stealth gratuito su OpenCode per un periodo limitato. Il team usa questo tempo per raccogliere feedback e migliorare il modello.
|
||||||
|
|
||||||
<a href={email}>Contattaci</a> se hai domande.
|
<a href={email}>Contattaci</a> se hai domande.
|
||||||
|
|
@ -176,7 +174,7 @@ Puoi cambiare l'importo della ricarica automatica. Puoi anche disabilitare compl
|
||||||
|
|
||||||
Puoi anche impostare un limite mensile di utilizzo per l'intero workspace e per ogni membro del team.
|
Puoi anche impostare un limite mensile di utilizzo per l'intero workspace e per ogni membro del team.
|
||||||
|
|
||||||
Per esempio, se imposti un limite mensile a $20, Zen non usera piu di $20 in un mese. Ma se hai l'auto-reload attivo, Zen potrebbe finire per addebitarti piu di $20 se il saldo scende sotto $5.
|
Per esempio, se imposti un limite mensile a $20, Zen non userà più di $20 in un mese. Ma se hai l'auto-reload attivo, Zen potrebbe finire per addebitarti più di $20 se il saldo scende sotto $5.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -184,12 +182,13 @@ Per esempio, se imposti un limite mensile a $20, Zen non usera piu di $20 in un
|
||||||
|
|
||||||
| Modello | Data di deprecazione |
|
| Modello | Data di deprecazione |
|
||||||
| ---------------- | -------------------- |
|
| ---------------- | -------------------- |
|
||||||
| Qwen3 Coder 480B | 6 feb 2026 |
|
|
||||||
| Kimi K2 Thinking | 6 mar 2026 |
|
|
||||||
| Kimi K2 | 6 mar 2026 |
|
|
||||||
| MiniMax M2.1 | 15 mar 2026 |
|
| MiniMax M2.1 | 15 mar 2026 |
|
||||||
| GLM 4.7 | 15 mar 2026 |
|
| GLM 4.7 | 15 mar 2026 |
|
||||||
| GLM 4.6 | 15 mar 2026 |
|
| GLM 4.6 | 15 mar 2026 |
|
||||||
|
| Gemini 3 Pro | 9 mar 2026 |
|
||||||
|
| Kimi K2 Thinking | 6 mar 2026 |
|
||||||
|
| Kimi K2 | 6 mar 2026 |
|
||||||
|
| Qwen3 Coder 480B | 6 feb 2026 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -199,8 +198,10 @@ Tutti i nostri modelli sono ospitati negli US. I nostri provider seguono una pol
|
||||||
|
|
||||||
- Big Pickle: durante il periodo gratuito, i dati raccolti potrebbero essere usati per migliorare il modello.
|
- Big Pickle: durante il periodo gratuito, i dati raccolti potrebbero essere usati per migliorare il modello.
|
||||||
- MiniMax M2.5 Free: durante il periodo gratuito, i dati raccolti potrebbero essere usati per migliorare il modello.
|
- MiniMax M2.5 Free: durante il periodo gratuito, i dati raccolti potrebbero essere usati per migliorare il modello.
|
||||||
- OpenAI APIs: le richieste vengono conservate per 30 giorni in conformita alle [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data).
|
- MiniMax M2.5 Free: durante il periodo gratuito, i dati raccolti potrebbero essere usati per migliorare il modello.
|
||||||
- Anthropic APIs: le richieste vengono conservate per 30 giorni in conformita alle [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage).
|
- Nemotron 3 Super Free: durante il periodo gratuito, i dati raccolti potrebbero essere usati per migliorare il modello.
|
||||||
|
- OpenAI APIs: le richieste vengono conservate per 30 giorni in conformità alle [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data).
|
||||||
|
- Anthropic APIs: le richieste vengono conservate per 30 giorni in conformità alle [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -212,7 +213,7 @@ Zen funziona benissimo anche per i team. Puoi invitare colleghi, assegnare ruoli
|
||||||
I workspace sono attualmente gratuiti per i team come parte della beta.
|
I workspace sono attualmente gratuiti per i team come parte della beta.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Gestire il workspace è attualmente gratuito per i team come parte della beta. Condivideremo presto piu dettagli sul pricing.
|
Gestire il workspace è attualmente gratuito per i team come parte della beta. Condivideremo presto più dettagli sul pricing.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -241,7 +242,7 @@ Puoi usare le tue chiavi API OpenAI o Anthropic continuando ad accedere agli alt
|
||||||
|
|
||||||
Quando usi le tue chiavi, i token vengono fatturati direttamente dal provider, non da Zen.
|
Quando usi le tue chiavi, i token vengono fatturati direttamente dal provider, non da Zen.
|
||||||
|
|
||||||
Per esempio, la tua organizzazione potrebbe avere gia una chiave per OpenAI o Anthropic e vuoi usare quella invece di quella fornita da Zen.
|
Per esempio, la tua organizzazione potrebbe avere già una chiave per OpenAI o Anthropic e vuoi usare quella invece di quella fornita da Zen.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -250,6 +251,6 @@ Per esempio, la tua organizzazione potrebbe avere gia una chiave per OpenAI o An
|
||||||
Abbiamo creato OpenCode Zen per:
|
Abbiamo creato OpenCode Zen per:
|
||||||
|
|
||||||
1. Fare **benchmark** dei migliori modelli/provider per agenti di coding.
|
1. Fare **benchmark** dei migliori modelli/provider per agenti di coding.
|
||||||
2. Dare accesso alle opzioni di **massima qualita** senza ridurre le prestazioni o instradare verso provider piu economici.
|
2. Dare accesso alle opzioni di **massima qualità** senza ridurre le prestazioni o instradare verso provider più economici.
|
||||||
3. Trasferire eventuali **riduzioni di prezzo** vendendo al costo; l'unico markup copre le commissioni di elaborazione.
|
3. Trasferire eventuali **riduzioni di prezzo** vendendo al costo; l'unico markup copre le commissioni di elaborazione.
|
||||||
4. Evitare **lock-in** permettendoti di usarlo con qualunque altro agente di coding e lasciandoti sempre usare anche altri provider con OpenCode.
|
4. Evitare **lock-in** permettendoti di usarlo con qualunque altro agente di coding e lasciandoti sempre usare anche altri provider con OpenCode.
|
||||||
|
|
|
||||||
|
|
@ -1,54 +1,54 @@
|
||||||
---
|
---
|
||||||
title: Go
|
title: Go
|
||||||
description: オープンコーディングモデル向けの低価格サブスクリプション。
|
description: オープンなコーディングモデルを利用するための低価格サブスクリプション。
|
||||||
---
|
---
|
||||||
|
|
||||||
import config from "../../../../config.mjs"
|
import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
export const console = config.console
|
||||||
export const email = `mailto:${config.email}`
|
export const email = `mailto:${config.email}`
|
||||||
|
|
||||||
OpenCode Goは、人気のあるオープンコーディングモデルへの信頼性の高いアクセスを提供する、低価格な**月額10ドル**のサブスクリプションです。
|
OpenCode Goは低価格のサブスクリプションで、**初月は5ドル**、その後は**月額10ドル**で、人気のオープンなコーディングモデルに安定してアクセスできます。
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
OpenCode Goは現在ベータ版です。
|
OpenCode Goは現在ベータ版です。
|
||||||
:::
|
:::
|
||||||
|
|
||||||
GoはOpenCodeの他のプロバイダーと同様に機能します。OpenCode Goに登録してAPIキーを取得します。これは**完全にオプション**であり、OpenCodeを使用するために必須ではありません。
|
GoはOpenCodeの他のプロバイダーと同様に機能します。OpenCode GoをサブスクライブしてAPIキーを取得します。これは**完全に任意**であり、OpenCodeを使用するために必須ではありません。
|
||||||
|
|
||||||
主に海外ユーザー向けに設計されており、安定したグローバルアクセスのためにモデルは米国、EU、シンガポールでホストされています。
|
主に海外ユーザー向けに設計されており、世界中で安定してアクセスできるよう、モデルは米国、EU、シンガポールでホストされています。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 背景
|
## 背景
|
||||||
|
|
||||||
オープンモデルは非常に高性能になりました。現在では、コーディングタスクにおいてプロプライエタリモデルに近いパフォーマンスを発揮します。また、多くのプロバイダーが競争力のある価格で提供できるため、通常はずっと安価です。
|
オープンモデルは非常に優れています。現在では、コーディングタスクにおいてプロプライエタリ(独自)モデルに近いパフォーマンスを達成しています。そして、多くのプロバイダーが競争力を持って提供できるため、通常ははるかに安価です。
|
||||||
|
|
||||||
しかし、信頼性が高く低遅延なアクセスを得ることは難しい場合があります。プロバイダーによって品質や可用性が異なるためです。
|
しかし、これらのモデルに安定して低遅延でアクセスすることは困難な場合があります。プロバイダーによって品質や可用性が異なります。
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
OpenCodeとうまく連携する厳選されたモデルとプロバイダーをテストしました。
|
OpenCodeでうまく動作する一部のモデルとプロバイダーをテストしました。
|
||||||
:::
|
:::
|
||||||
|
|
||||||
これを解決するために、私たちはいくつかのことを行いました。
|
この問題を解決するために、私たちはいくつかの取り組みを行いました:
|
||||||
|
|
||||||
1. 厳選されたオープンモデルをテストし、それらを最適に実行する方法についてチームと話し合いました。
|
1. 一部のオープンモデルをテストし、それらを最適に実行する方法について、そのチームと話し合いました。
|
||||||
2. 次に、いくつかのプロバイダーと協力して、これらが正しく提供されていることを確認しました。
|
2. 次に、これらが正しく提供されていることを確認するために、いくつかのプロバイダーと協力しました。
|
||||||
3. 最後に、モデルとプロバイダーの組み合わせをベンチマークし、自信を持って推奨できるリストを作成しました。
|
3. 最後に、モデルとプロバイダーの組み合わせをベンチマークし、自信を持ってお勧めできるリストを作成しました。
|
||||||
|
|
||||||
OpenCode Goでは、これらのモデルに**月額10ドル**でアクセスできます。
|
OpenCode Goを使用すると、これらのモデルに**初月は5ドル**、その後は**月額10ドル**でアクセスできます。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 仕組み
|
## 仕組み
|
||||||
|
|
||||||
OpenCode GoはOpenCodeの他のプロバイダーと同様に機能します。
|
OpenCode Goは、OpenCodeの他のプロバイダーと同様に機能します。
|
||||||
|
|
||||||
1. **<a href={console}>OpenCode Zen</a>**にサインインし、Goに登録してAPIキーをコピーします。
|
1. **<a href={console}>OpenCode Zen</a>**にサインインし、GoをサブスクライブしてAPIキーをコピーします。
|
||||||
2. TUIで`/connect`コマンドを実行し、`OpenCode Go`を選択してAPIキーを貼り付けます。
|
2. TUIで`/connect`コマンドを実行し、`OpenCode Go`を選択して、APIキーを貼り付けます。
|
||||||
3. TUIで`/models`を実行して、Go経由で利用可能なモデルのリストを確認します。
|
3. TUIで`/models`を実行すると、Goを通じて利用可能なモデルのリストが表示されます。
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
ワークスペースごとに1人のメンバーのみがOpenCode Goに登録できます。
|
OpenCode Goをサブスクライブできるのは、1つのワークスペースにつき1メンバーのみです。
|
||||||
:::
|
:::
|
||||||
|
|
||||||
現在のモデルリストには以下が含まれます:
|
現在のモデルリストには以下が含まれます:
|
||||||
|
|
@ -56,82 +56,72 @@ OpenCode GoはOpenCodeの他のプロバイダーと同様に機能します。
|
||||||
- **GLM-5**
|
- **GLM-5**
|
||||||
- **Kimi K2.5**
|
- **Kimi K2.5**
|
||||||
- **MiniMax M2.5**
|
- **MiniMax M2.5**
|
||||||
|
- **MiniMax M2.7**
|
||||||
|
|
||||||
モデルのリストは、テストや新しいモデルの追加に伴い変更される可能性があります。
|
新しいモデルをテストして追加するにつれて、モデルのリストは変更される場合があります。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 利用制限
|
## 利用制限
|
||||||
|
|
||||||
OpenCode Goには以下の制限が含まれます:
|
OpenCode Goには以下の制限が含まれています:
|
||||||
|
|
||||||
- **5時間制限** — 12ドル分の利用
|
- **5時間の制限** — 12ドル分の利用
|
||||||
- **週間制限** — 30ドル分の利用
|
- **週間の制限** — 30ドル分の利用
|
||||||
- **月間制限** — 60ドル分の利用
|
- **月間の制限** — 60ドル分の利用
|
||||||
|
|
||||||
制限は金額で定義されています。つまり、実際のリクエスト数は使用するモデルによって異なります。MiniMax M2.5のような安価なモデルではより多くのリクエストが可能ですが、GLM-5のような高価なモデルでは少なくなります。
|
制限はドル単位で定義されています。つまり、実際のリクエスト数は使用するモデルによって異なります。MiniMax M2.5のような安価なモデルではより多くのリクエストが可能ですが、GLM-5のような高コストのモデルではリクエスト数が少なくなります。
|
||||||
|
|
||||||
下の表は、典型的なGoの使用パターンに基づいた推定リクエスト数を示しています:
|
以下の表は、一般的なGoの利用パターンに基づいた推定リクエスト数を示しています:
|
||||||
|
|
||||||
| | GLM-5 | Kimi K2.5 | MiniMax M2.5 |
|
| | GLM-5 | Kimi K2.5 | MiniMax M2.7 | MiniMax M2.5 |
|
||||||
| ------------------------- | ----- | --------- | ------------ |
|
| ------------------------- | ----- | --------- | ------------ | ------------ |
|
||||||
| 5時間あたりのリクエスト数 | 1,150 | 1,850 | 30,000 |
|
| 5時間あたりのリクエスト数 | 1,150 | 1,850 | 14,000 | 20,000 |
|
||||||
| 週間リクエスト数 | 2,880 | 4,630 | 75,000 |
|
| 週間リクエスト数 | 2,880 | 4,630 | 35,000 | 50,000 |
|
||||||
| 月間リクエスト数 | 5,750 | 9,250 | 150,000 |
|
| 月間リクエスト数 | 5,750 | 9,250 | 70,000 | 100,000 |
|
||||||
|
|
||||||
推定値は、観測された平均的なリクエストパターンに基づいています:
|
推定値は、観測された平均的なリクエストパターンに基づいています:
|
||||||
|
|
||||||
- GLM-5 — 1リクエストあたり入力700、キャッシュ52,000、出力150トークン
|
- GLM-5 — リクエストあたり 入力 700トークン、キャッシュ 52,000トークン、出力 150トークン
|
||||||
- Kimi K2.5 — 1リクエストあたり入力870、キャッシュ55,000、出力200トークン
|
- Kimi K2.5 — リクエストあたり 入力 870トークン、キャッシュ 55,000トークン、出力 200トークン
|
||||||
- MiniMax M2.5 — 1リクエストあたり入力300、キャッシュ55,000、出力125トークン
|
- MiniMax M2.7/M2.5 — リクエストあたり 入力 300トークン、キャッシュ 55,000トークン、出力 125トークン
|
||||||
|
|
||||||
現在の使用状況は**<a href={console}>コンソール</a>**で確認できます。
|
現在の利用状況は**<a href={console}>コンソール</a>**で追跡できます。
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
利用制限に達した場合でも、無料モデルを引き続き使用できます。
|
利用制限に達した場合でも、無料モデルを引き続き使用できます。
|
||||||
:::
|
:::
|
||||||
|
|
||||||
利用制限は、初期の使用状況やフィードバックに基づいて変更される可能性があります。
|
初期の利用状況やフィードバックから学ぶにつれて、利用制限は変更される場合があります。
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 価格
|
|
||||||
|
|
||||||
OpenCode Goは**月額10ドル**のサブスクリプションプランです。以下は**100万トークンあたり**の価格です。
|
|
||||||
|
|
||||||
| モデル | 入力 | 出力 | キャッシュ読み込み |
|
|
||||||
| ------------ | ----- | ----- | ------------------ |
|
|
||||||
| GLM-5 | $1.00 | $3.20 | $0.20 |
|
|
||||||
| Kimi K2.5 | $0.60 | $3.00 | $0.10 |
|
|
||||||
| MiniMax M2.5 | $0.30 | $1.20 | $0.03 |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 制限を超えた利用
|
### 制限を超えた利用
|
||||||
|
|
||||||
Zen残高にクレジットがある場合、コンソールで**残高を使用 (Use balance)**オプションを有効にできます。有効にすると、利用制限に達した後、リクエストをブロックする代わりにZen残高が使用されます。
|
Zen残高にクレジットがある場合は、コンソールで**Use balance**オプションを有効にすることができます。有効にすると、利用制限に達した後、リクエストをブロックする代わりに、GoはZen残高から利用するようになります。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## エンドポイント
|
## エンドポイント
|
||||||
|
|
||||||
以下のAPIエンドポイントを通じてGoモデルにアクセスすることもできます。
|
以下のAPIエンドポイントを通じて、Goモデルにアクセスすることもできます。
|
||||||
|
|
||||||
| モデル | モデルID | エンドポイント | AI SDKパッケージ |
|
| Model | Model ID | Endpoint | AI SDK Package |
|
||||||
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
||||||
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
|
|
||||||
OpenCode設定の[モデルID](/docs/config/#models)は、`opencode-go/<model-id>`という形式を使用します。たとえば、Kimi K2.5の場合、設定で`opencode-go/kimi-k2.5`を使用します。
|
OpenCode設定の[model id](/docs/config/#models)は、`opencode-go/<model-id>`という形式を使用します。たとえば、Kimi K2.5の場合は、設定で`opencode-go/kimi-k2.5`を使用します。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## プライバシー
|
## プライバシー
|
||||||
|
|
||||||
このプランは主に海外ユーザー向けに設計されており、安定したグローバルアクセスのためにモデルは米国、EU、シンガポールでホストされています。
|
このプランは主に海外ユーザー向けに設計されており、世界中で安定してアクセスできるよう、モデルは米国、EU、シンガポールでホストされています。
|
||||||
|
|
||||||
ご質問がある場合は<a href={email}>お問い合わせください</a>。
|
ご質問がある場合は、<a href={email}>お問い合わせ</a>ください。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -139,7 +129,7 @@ OpenCode設定の[モデルID](/docs/config/#models)は、`opencode-go/<model-id
|
||||||
|
|
||||||
OpenCode Goを作成した目的は以下の通りです:
|
OpenCode Goを作成した目的は以下の通りです:
|
||||||
|
|
||||||
1. 低価格のサブスクリプションで、より多くの人々がAIコーディングに**アクセス**できるようにすること。
|
1. 低価格のサブスクリプションで、より多くの人がAIコーディングを**利用しやすく**する。
|
||||||
2. 最高のオープンコーディングモデルへの**信頼性の高い**アクセスを提供すること。
|
2. 最高のオープンなコーディングモデルに**安定した**アクセスを提供する。
|
||||||
3. コーディングエージェントでの使用向けに**テストおよびベンチマーク**されたモデルを厳選すること。
|
3. コーディングエージェントの利用向けに**テストおよびベンチマークされた**モデルを厳選する。
|
||||||
4. OpenCodeで他のプロバイダーも使用できるようにすることで、**ロックインを排除**すること。
|
4. OpenCodeで他のプロバイダーも使用できるようにすることで、**ベンダーロックインをなくす**。
|
||||||
|
|
|
||||||
|
|
@ -1,145 +1,135 @@
|
||||||
---
|
---
|
||||||
title: Go
|
title: Go
|
||||||
description: 오픈 코딩 모델을 위한 저렴한 구독 서비스입니다.
|
description: 오픈 코딩 모델을 위한 저비용 구독 서비스입니다.
|
||||||
---
|
---
|
||||||
|
|
||||||
import config from "../../../../config.mjs"
|
import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
export const console = config.console
|
||||||
export const email = `mailto:${config.email}`
|
export const email = `mailto:${config.email}`
|
||||||
|
|
||||||
OpenCode Go는 인기 있는 오픈 코딩 모델에 안정적으로 액세스할 수 있는 저렴한 **월 $10** 구독 서비스입니다.
|
OpenCode Go는 인기 있는 오픈 코딩 모델에 안정적으로 액세스할 수 있도록 제공하는 저비용 구독 서비스입니다. **첫 달은 $5**이며 이후에는 **월 $10**입니다.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
OpenCode Go는 현재 베타 버전입니다.
|
OpenCode Go는 현재 베타 버전입니다.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Go는 OpenCode의 다른 제공자처럼 작동합니다. OpenCode Go를 구독하고 API 키를 받으세요. 이는 **완전히 선택 사항**이며 OpenCode를 사용하기 위해 반드시 사용할 필요는 없습니다.
|
Go는 OpenCode의 다른 제공자와 동일하게 작동합니다. OpenCode Go를 구독하고 API 키를 발급받으면 됩니다. 이는 **완전히 선택 사항**이며, OpenCode를 사용하기 위해 반드시 사용할 필요는 없습니다.
|
||||||
|
|
||||||
주로 해외 사용자를 위해 설계되었으며, 안정적인 글로벌 액세스를 위해 미국, EU, 싱가포르에서 모델이 호스팅됩니다.
|
주로 글로벌 사용자를 위해 설계되었으며, 안정적인 전 세계 액세스를 위해 모델은 미국, EU 및 싱가포르에 호스팅됩니다.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 배경
|
## 배경
|
||||||
|
|
||||||
오픈 모델은 정말 좋아졌습니다. 이제 코딩 작업에서 독점 모델에 가까운 성능을 발휘합니다. 그리고 많은 제공자가 경쟁적으로 서비스할 수 있기 때문에 일반적으로 훨씬 저렴합니다.
|
오픈 모델은 매우 발전했습니다. 이제 코딩 작업에서 독점 모델에 근접한 성능을 보여줍니다. 또한 많은 제공자가 경쟁적으로 서비스하기 때문에 일반적으로 비용이 훨씬 저렴합니다.
|
||||||
|
|
||||||
하지만 안정적이고 지연 시간이 짧은 액세스를 얻기는 어려울 수 있습니다. 제공자마다 품질과 가용성이 다릅니다.
|
하지만 안정적이고 지연 시간이 짧은 액세스를 확보하는 것은 어려울 수 있습니다. 제공자마다 품질과 가용성이 다르기 때문입니다.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
OpenCode와 잘 작동하는 엄선된 모델 및 제공자 그룹을 테스트했습니다.
|
OpenCode와 잘 작동하는 선별된 모델 및 제공자 그룹을 테스트했습니다.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
이를 해결하기 위해 몇 가지 작업을 수행했습니다.
|
이 문제를 해결하기 위해 다음 몇 가지 작업을 수행했습니다.
|
||||||
|
|
||||||
1. 엄선된 오픈 모델 그룹을 테스트하고 해당 팀과 최적의 실행 방법에 대해 논의했습니다.
|
1. 선별된 오픈 모델 그룹을 테스트하고 각 팀과 최적의 실행 방법에 대해 논의했습니다.
|
||||||
2. 그런 다음 몇몇 제공자와 협력하여 이것들이 올바르게 서비스되고 있는지 확인했습니다.
|
2. 그런 다음 몇몇 제공자와 협력하여 모델이 올바르게 서비스되고 있는지 확인했습니다.
|
||||||
3. 마지막으로 모델/제공자 조합을 벤치마킹하여 추천할 만한 목록을 만들었습니다.
|
3. 마지막으로 모델/제공자 조합을 벤치마킹하여 자신 있게 추천할 수 있는 목록을 작성했습니다.
|
||||||
|
|
||||||
OpenCode Go를 사용하면 **월 $10**에 이러한 모델에 액세스할 수 있습니다.
|
OpenCode Go를 사용하면 **첫 달 $5**, 이후 **월 $10**의 가격으로 이러한 모델에 액세스할 수 있습니다.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 작동 방식
|
## 작동 방식
|
||||||
|
|
||||||
OpenCode Go는 OpenCode의 다른 제공자처럼 작동합니다.
|
OpenCode Go는 OpenCode의 다른 제공자와 동일하게 작동합니다.
|
||||||
|
|
||||||
1. **<a href={console}>OpenCode Zen</a>**에 로그인하고 Go를 구독한 다음 API 키를 복사합니다.
|
1. **<a href={console}>OpenCode Zen</a>**에 로그인하여 Go를 구독하고 API 키를 복사합니다.
|
||||||
2. TUI에서 `/connect` 명령을 실행하고 `OpenCode Go`를 선택한 다음 API 키를 붙여넣습니다.
|
2. TUI에서 `/connect` 명령을 실행하고 `OpenCode Go`를 선택한 후 API 키를 붙여넣습니다.
|
||||||
3. TUI에서 `/models`를 실행하여 Go를 통해 사용할 수 있는 모델 목록을 확인합니다.
|
3. TUI에서 `/models`를 실행하여 Go를 통해 사용할 수 있는 모델 목록을 확인합니다.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
워크스페이스당 한 명의 멤버만 OpenCode Go를 구독할 수 있습니다.
|
작업 공간당 한 명의 구성원만 OpenCode Go를 구독할 수 있습니다.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
현재 모델 목록은 다음과 같습니다.
|
현재 지원되는 모델 목록은 다음과 같습니다.
|
||||||
|
|
||||||
- **GLM-5**
|
- **GLM-5**
|
||||||
- **Kimi K2.5**
|
- **Kimi K2.5**
|
||||||
- **MiniMax M2.5**
|
- **MiniMax M2.5**
|
||||||
|
- **MiniMax M2.7**
|
||||||
|
|
||||||
모델 목록은 테스트하고 새로운 모델을 추가함에 따라 변경될 수 있습니다.
|
모델 목록은 테스트 및 추가 상황에 따라 변경될 수 있습니다.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 사용 한도
|
## 사용 한도
|
||||||
|
|
||||||
OpenCode Go에는 다음과 같은 한도가 포함됩니다.
|
OpenCode Go에는 다음과 같은 한도가 적용됩니다.
|
||||||
|
|
||||||
- **5시간 한도** — $12 사용량
|
- **5시간 한도** — 사용 금액 $12
|
||||||
- **주간 한도** — $30 사용량
|
- **주간 한도** — 사용 금액 $30
|
||||||
- **월간 한도** — $60 사용량
|
- **월간 한도** — 사용 금액 $60
|
||||||
|
|
||||||
한도는 달러 가치로 정의됩니다. 즉, 실제 요청 수는 사용하는 모델에 따라 다릅니다. MiniMax M2.5와 같은 저렴한 모델은 더 많은 요청을 허용하는 반면, GLM-5와 같은 고비용 모델은 더 적은 요청을 허용합니다.
|
한도는 달러 가치로 정의됩니다. 즉, 실제 요청 횟수는 사용하는 모델에 따라 달라집니다. MiniMax M2.5와 같이 저렴한 모델은 더 많은 요청이 가능한 반면, GLM-5와 같이 비용이 더 높은 모델은 더 적은 요청이 가능합니다.
|
||||||
|
|
||||||
아래 표는 일반적인 Go 사용 패턴을 기반으로 한 예상 요청 수를 제공합니다.
|
아래 표는 일반적인 Go 사용 패턴을 기반으로 한 예상 요청 횟수를 보여줍니다.
|
||||||
|
|
||||||
| | GLM-5 | Kimi K2.5 | MiniMax M2.5 |
|
| | GLM-5 | Kimi K2.5 | MiniMax M2.7 | MiniMax M2.5 |
|
||||||
| --------------- | ----- | --------- | ------------ |
|
| ----------------- | ----- | --------- | ------------ | ------------ |
|
||||||
| 5시간당 요청 수 | 1,150 | 1,850 | 30,000 |
|
| 5시간당 요청 횟수 | 1,150 | 1,850 | 14,000 | 20,000 |
|
||||||
| 주당 요청 수 | 2,880 | 4,630 | 75,000 |
|
| 주당 요청 횟수 | 2,880 | 4,630 | 35,000 | 50,000 |
|
||||||
| 월당 요청 수 | 5,750 | 9,250 | 150,000 |
|
| 월당 요청 횟수 | 5,750 | 9,250 | 70,000 | 100,000 |
|
||||||
|
|
||||||
추정치는 관찰된 평균 요청 패턴을 기반으로 합니다.
|
예상치는 관찰된 평균 요청 패턴을 기준으로 합니다.
|
||||||
|
|
||||||
- GLM-5 — 요청당 입력 700, 캐시 52,000, 출력 150 토큰
|
- GLM-5 — 요청당 700 입력, 52,000 캐시됨, 150 출력 토큰
|
||||||
- Kimi K2.5 — 요청당 입력 870, 캐시 55,000, 출력 200 토큰
|
- Kimi K2.5 — 요청당 870 입력, 55,000 캐시됨, 200 출력 토큰
|
||||||
- MiniMax M2.5 — 요청당 입력 300, 캐시 55,000, 출력 125 토큰
|
- MiniMax M2.7/M2.5 — 요청당 300 입력, 55,000 캐시됨, 125 출력 토큰
|
||||||
|
|
||||||
**<a href={console}>콘솔</a>**에서 현재 사용량을 추적할 수 있습니다.
|
**<a href={console}>콘솔</a>**에서 현재 사용량을 추적할 수 있습니다.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
사용 한도에 도달하면 무료 모델을 계속 사용할 수 있습니다.
|
사용 한도에 도달하더라도 무료 모델은 계속 사용할 수 있습니다.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
사용 한도는 초기 사용 및 피드백을 통해 학습함에 따라 변경될 수 있습니다.
|
사용 한도는 초기 사용 데이터 및 피드백에 따라 변경될 수 있습니다.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 가격
|
|
||||||
|
|
||||||
OpenCode Go는 **월 $10** 구독 요금제입니다. 아래는 **100만 토큰당** 가격입니다.
|
|
||||||
|
|
||||||
| Model | Input | Output | Cached Read |
|
|
||||||
| ------------ | ----- | ------ | ----------- |
|
|
||||||
| GLM-5 | $1.00 | $3.20 | $0.20 |
|
|
||||||
| Kimi K2.5 | $0.60 | $3.00 | $0.10 |
|
|
||||||
| MiniMax M2.5 | $0.30 | $1.20 | $0.03 |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 한도 초과 사용
|
### 한도 초과 사용
|
||||||
|
|
||||||
Zen 잔액에 크레딧이 있는 경우 콘솔에서 **잔액 사용(Use balance)** 옵션을 활성화할 수 있습니다. 활성화하면 사용 한도에 도달했을 때 요청을 차단하는 대신 Zen 잔액을 사용하게 됩니다.
|
Zen 잔액에 크레딧이 있는 경우 콘솔에서 **잔액 사용(Use balance)** 옵션을 활성화할 수 있습니다. 이 기능을 활성화하면 사용 한도에 도달한 후 요청을 차단하는 대신 Zen 잔액을 대체하여 사용하게 됩니다.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 엔드포인트
|
## 엔드포인트
|
||||||
|
|
||||||
다음 API 엔드포인트를 통해 Go 모델에 액세스할 수도 있습니다.
|
다음 API 엔드포인트를 통해서도 Go 모델에 액세스할 수 있습니다.
|
||||||
|
|
||||||
| Model | Model ID | Endpoint | AI SDK Package |
|
| 모델 | 모델 ID | 엔드포인트 | AI SDK 패키지 |
|
||||||
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
||||||
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
|
|
||||||
OpenCode 설정의 [모델 ID](/docs/config/#models)는 `opencode-go/<model-id>` 형식을 사용합니다. 예를 들어 Kimi K2.5의 경우 설정에서 `opencode-go/kimi-k2.5`를 사용합니다.
|
OpenCode 구성의 [모델 ID](/docs/config/#models)는 `opencode-go/<model-id>` 형식을 사용합니다. 예를 들어 Kimi K2.5의 경우, 구성에서 `opencode-go/kimi-k2.5`를 사용해야 합니다.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 개인정보 보호
|
## 개인정보 보호
|
||||||
|
|
||||||
이 플랜은 주로 해외 사용자를 위해 설계되었으며, 안정적인 글로벌 액세스를 위해 미국, EU, 싱가포르에서 모델이 호스팅됩니다.
|
이 요금제는 주로 글로벌 사용자를 위해 설계되었으며, 안정적인 전 세계 액세스를 위해 모델은 미국, EU 및 싱가포르에 호스팅됩니다.
|
||||||
|
|
||||||
질문이 있으시면 <a href={email}>문의해 주세요</a>.
|
궁금한 점이 있으면 <a href={email}>문의</a>해 주세요.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 목표
|
## 목표
|
||||||
|
|
||||||
우리는 다음을 위해 OpenCode Go를 만들었습니다.
|
OpenCode Go의 목표는 다음과 같습니다.
|
||||||
|
|
||||||
1. 저렴한 구독으로 더 많은 사람들이 AI 코딩에 **접근할 수 있도록** 합니다.
|
1. 저비용 구독을 통해 더 많은 사람들이 AI 코딩에 **접근 가능**하도록 합니다.
|
||||||
2. 최고의 오픈 코딩 모델에 **안정적으로** 액세스할 수 있도록 합니다.
|
2. 최고의 오픈 코딩 모델에 대한 **안정적인** 액세스를 제공합니다.
|
||||||
3. 코딩 에이전트 사용을 위해 **테스트 및 벤치마킹된** 모델을 큐레이팅합니다.
|
3. 코딩 에이전트 사용을 위해 **테스트 및 벤치마킹**된 모델을 선별합니다.
|
||||||
4. OpenCode와 함께 다른 제공자도 사용할 수 있도록 하여 **락인(lock-in)이 없도록** 합니다.
|
4. OpenCode에서 다른 제공자도 함께 사용할 수 있도록 허용하여 **종속성을 없앱니다(no lock-in)**.
|
||||||
|
|
|
||||||
|
|
@ -7,43 +7,43 @@ import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
export const console = config.console
|
||||||
export const email = `mailto:${config.email}`
|
export const email = `mailto:${config.email}`
|
||||||
|
|
||||||
OpenCode Go er et lavkostnadsabonnement til **$10/måned** som gir deg pålitelig tilgang til populære åpne kodemodeller.
|
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.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
OpenCode Go er for tiden i beta.
|
OpenCode Go er for øyeblikket i beta.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Go fungerer som enhver annen leverandør i OpenCode. Du abonnerer på OpenCode Go og
|
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 å
|
får din API-nøkkel. Det er **helt valgfritt**, og du trenger ikke å bruke det for å
|
||||||
bruke OpenCode.
|
bruke OpenCode.
|
||||||
|
|
||||||
Det er designet primært for internasjonale brukere, med modeller driftet i USA, EU og Singapore for stabil global tilgang.
|
Det er primært utformet for internasjonale brukere, med modeller driftet i USA, EU og Singapore for stabil global tilgang.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Bakgrunn
|
## Bakgrunn
|
||||||
|
|
||||||
Åpne modeller har blitt veldig bra. De når nå ytelse nær
|
Åpne modeller har blitt veldig gode. De oppnår nå ytelse nær
|
||||||
proprietære modeller for kodeoppgaver. Og fordi mange leverandører kan servere dem
|
proprietære modeller for kodeoppgaver. Og fordi mange leverandører kan tilby dem
|
||||||
konkurransedyktig, er de vanligvis mye billigere.
|
konkurransedyktig, er de vanligvis mye billigere.
|
||||||
|
|
||||||
Imidlertid kan det være vanskelig å få pålitelig tilgang med lav ventetid. Leverandører
|
Imidlertid kan det være vanskelig å få pålitelig tilgang med lav forsinkelse til dem. Leverandører
|
||||||
varierer i kvalitet og tilgjengelighet.
|
varierer i kvalitet og tilgjengelighet.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Vi testet en utvalgt gruppe modeller og leverandører som fungerer bra med OpenCode.
|
Vi testet en utvalgt gruppe modeller og leverandører som fungerer godt med OpenCode.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
For å fikse dette gjorde vi et par ting:
|
For å fikse dette, gjorde vi et par ting:
|
||||||
|
|
||||||
1. Vi testet en utvalgt gruppe åpne modeller og snakket med teamene deres om hvordan man
|
1. Vi testet en utvalgt gruppe åpne modeller og snakket med teamene deres om hvordan de
|
||||||
best kjører dem.
|
best kan kjøres.
|
||||||
2. Vi jobbet deretter med noen få leverandører for å sikre at disse ble servert
|
2. Deretter samarbeidet vi med noen få leverandører for å sikre at disse ble levert
|
||||||
riktig.
|
riktig.
|
||||||
3. Til slutt ytelsestestet vi kombinasjonen av modell/leverandør og kom opp
|
3. Til slutt utførte vi ytelsestester på kombinasjonen av modell og leverandør, og kom frem
|
||||||
med en liste som vi føler oss trygge på å anbefale.
|
til en liste som vi trygt kan anbefale.
|
||||||
|
|
||||||
OpenCode Go gir deg tilgang til disse modellene for **$10/måned**.
|
OpenCode Go gir deg tilgang til disse modellene for **$5 for din første måned**, deretter **$10/måned**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -51,14 +51,14 @@ OpenCode Go gir deg tilgang til disse modellene for **$10/måned**.
|
||||||
|
|
||||||
OpenCode Go fungerer som enhver annen leverandør i OpenCode.
|
OpenCode Go fungerer som enhver annen leverandør i OpenCode.
|
||||||
|
|
||||||
1. Du logger deg inn på **<a href={console}>OpenCode Zen</a>**, abonnerer på Go, og
|
1. Du logger inn på **<a href={console}>OpenCode Zen</a>**, abonnerer på Go, og
|
||||||
kopierer API-nøkkelen din.
|
kopierer din API-nøkkel.
|
||||||
2. Du kjører kommandoen `/connect` i TUI-en, velger `OpenCode Go`, og limer inn
|
2. Du kjører kommandoen `/connect` i TUI-en, velger `OpenCode Go`, og limer inn
|
||||||
API-nøkkelen din.
|
din API-nøkkel.
|
||||||
3. Kjør `/models` i TUI-en for å se listen over modeller tilgjengelig gjennom Go.
|
3. Kjør `/models` i TUI-en for å se listen over modeller som er tilgjengelige gjennom Go.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
Bare ett medlem per arbeidsområde kan abonnere på OpenCode Go.
|
Kun ett medlem per arbeidsområde kan abonnere på OpenCode Go.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Den nåværende listen over modeller inkluderer:
|
Den nåværende listen over modeller inkluderer:
|
||||||
|
|
@ -66,6 +66,7 @@ Den nåværende listen over modeller inkluderer:
|
||||||
- **GLM-5**
|
- **GLM-5**
|
||||||
- **Kimi K2.5**
|
- **Kimi K2.5**
|
||||||
- **MiniMax M2.5**
|
- **MiniMax M2.5**
|
||||||
|
- **MiniMax M2.7**
|
||||||
|
|
||||||
Listen over modeller kan endres etter hvert som vi tester og legger til nye.
|
Listen over modeller kan endres etter hvert som vi tester og legger til nye.
|
||||||
|
|
||||||
|
|
@ -75,53 +76,41 @@ Listen over modeller kan endres etter hvert som vi tester og legger til nye.
|
||||||
|
|
||||||
OpenCode Go inkluderer følgende grenser:
|
OpenCode Go inkluderer følgende grenser:
|
||||||
|
|
||||||
- **5 timers grense** — $12 i bruk
|
- **5-timers grense** — $12 i bruk
|
||||||
- **Ukentlig grense** — $30 i bruk
|
- **Ukentlig grense** — $30 i bruk
|
||||||
- **Månedlig grense** — $60 i bruk
|
- **Månedlig grense** — $60 i bruk
|
||||||
|
|
||||||
Grensene er definert i dollarverdi. Dette betyr at ditt faktiske antall forespørsler avhenger av modellen du bruker. Billigere modeller som MiniMax M2.5 tillater flere forespørsler, mens dyrere modeller som GLM-5 tillater færre.
|
Grensene er definert i dollarverdi. Dette betyr at ditt faktiske antall forespørsler avhenger av modellen du bruker. Billigere modeller som MiniMax M2.5 tillater flere forespørsler, mens dyrere modeller som GLM-5 tillater færre.
|
||||||
|
|
||||||
Tabellen nedenfor gir et estimert antall forespørsler basert på typiske Go-bruksmønstre:
|
Tabellen nedenfor gir et estimert antall forespørsler basert på typiske bruksmønstre for Go:
|
||||||
|
|
||||||
| | GLM-5 | Kimi K2.5 | MiniMax M2.5 |
|
| | GLM-5 | Kimi K2.5 | MiniMax M2.7 | MiniMax M2.5 |
|
||||||
| ------------------------ | ----- | --------- | ------------ |
|
| ------------------------ | ----- | --------- | ------------ | ------------ |
|
||||||
| forespørsler per 5 timer | 1,150 | 1,850 | 30,000 |
|
| forespørsler per 5 timer | 1 150 | 1 850 | 14 000 | 20 000 |
|
||||||
| forespørsler per uke | 2,880 | 4,630 | 75,000 |
|
| forespørsler per uke | 2 880 | 4 630 | 35 000 | 50 000 |
|
||||||
| forespørsler per måned | 5,750 | 9,250 | 150,000 |
|
| forespørsler per måned | 5 750 | 9 250 | 70 000 | 100 000 |
|
||||||
|
|
||||||
Estimater er basert på observerte gjennomsnittlige forespørselsmønstre:
|
Estimatene er basert på observerte gjennomsnittlige forespørselsmønstre:
|
||||||
|
|
||||||
- GLM-5 — 700 input, 52,000 cached, 150 output tokens per forespørsel
|
- GLM-5 — 700 input, 52 000 bufret, 150 output-tokens per forespørsel
|
||||||
- Kimi K2.5 — 870 input, 55,000 cached, 200 output tokens per forespørsel
|
- Kimi K2.5 — 870 input, 55 000 bufret, 200 output-tokens per forespørsel
|
||||||
- MiniMax M2.5 — 300 input, 55,000 cached, 125 output tokens per forespørsel
|
- MiniMax M2.7/M2.5 — 300 input, 55 000 bufret, 125 output-tokens per forespørsel
|
||||||
|
|
||||||
Du kan spore din nåværende bruk i **<a href={console}>konsollen</a>**.
|
Du kan spore din nåværende bruk i **<a href={console}>konsollen</a>**.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Hvis du når bruksgrensen, kan du fortsette å bruke de gratis modellene.
|
Hvis du når bruksgrensen, kan du fortsette å bruke gratismodellene.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Bruksgrenser kan endres etter hvert som vi lærer fra tidlig bruk og tilbakemeldinger.
|
Bruksgrenser kan endres etter hvert som vi lærer fra tidlig bruk og tilbakemeldinger.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Priser
|
|
||||||
|
|
||||||
OpenCode Go er et **$10/måned** abonnementsplan. Nedenfor er prisene **per 1M tokens**.
|
|
||||||
|
|
||||||
| Modell | Input | Output | Bufret lesing |
|
|
||||||
| ------------ | ----- | ------ | ------------- |
|
|
||||||
| GLM-5 | $1.00 | $3.20 | $0.20 |
|
|
||||||
| Kimi K2.5 | $0.60 | $3.00 | $0.10 |
|
|
||||||
| MiniMax M2.5 | $0.30 | $1.20 | $0.03 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Bruk utover grensene
|
### Bruk utover grensene
|
||||||
|
|
||||||
Hvis du også har kreditter på din Zen-saldo, kan du aktivere alternativet **Bruk saldo**
|
Hvis du også har kreditt på din Zen-saldo, kan du aktivere alternativet **Bruk saldo**
|
||||||
i konsollen. Når aktivert, vil Go falle tilbake til Zen-saldoen din
|
i konsollen. Når dette er aktivert, vil Go falle tilbake på din Zen-saldo
|
||||||
etter at du har nådd bruksgrensene dine i stedet for å blokkere forespørsler.
|
etter at du har nådd bruksgrensene dine, i stedet for å blokkere forespørsler.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -129,21 +118,22 @@ etter at du har nådd bruksgrensene dine i stedet for å blokkere forespørsler.
|
||||||
|
|
||||||
Du kan også få tilgang til Go-modeller gjennom følgende API-endepunkter.
|
Du kan også få tilgang til Go-modeller gjennom følgende API-endepunkter.
|
||||||
|
|
||||||
| Modell | Modell-ID | Endepunkt | AI SDK Pakke |
|
| Modell | Modell-ID | Endepunkt | AI SDK Package |
|
||||||
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
||||||
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
|
|
||||||
[Modell-ID-en](/docs/config/#models) i din OpenCode-konfigurasjon
|
[Modell-ID-en](/docs/config/#models) i din OpenCode-konfigurasjon
|
||||||
bruker formatet `opencode-go/<model-id>`. For eksempel, for Kimi K2.5, ville du
|
bruker formatet `opencode-go/<model-id>`. For eksempel, for Kimi K2.5, vil du
|
||||||
bruke `opencode-go/kimi-k2.5` i konfigurasjonen din.
|
bruke `opencode-go/kimi-k2.5` i konfigurasjonen din.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Personvern
|
## Personvern
|
||||||
|
|
||||||
Planen er designet primært for internasjonale brukere, med modeller driftet i USA, EU og Singapore for stabil global tilgang.
|
Abonnementet er primært utformet for internasjonale brukere, med modeller driftet i USA, EU og Singapore for stabil global tilgang.
|
||||||
|
|
||||||
<a href={email}>Kontakt oss</a> hvis du har noen spørsmål.
|
<a href={email}>Kontakt oss</a> hvis du har noen spørsmål.
|
||||||
|
|
||||||
|
|
@ -155,5 +145,5 @@ Vi opprettet OpenCode Go for å:
|
||||||
|
|
||||||
1. Gjøre AI-koding **tilgjengelig** for flere mennesker med et lavkostnadsabonnement.
|
1. Gjøre AI-koding **tilgjengelig** for flere mennesker med et lavkostnadsabonnement.
|
||||||
2. Gi **pålitelig** tilgang til de beste åpne kodemodellene.
|
2. Gi **pålitelig** tilgang til de beste åpne kodemodellene.
|
||||||
3. Kurere modeller som er **testet og ytelsestestet** for bruk av kodeagenter.
|
3. Kuratere modeller som er **testet og ytelsesmålt** for bruk av kodeagenter.
|
||||||
4. Ha **ingen innlåsing** ved å tillate deg å bruke hvilken som helst annen leverandør med OpenCode også.
|
4. Ha **ingen innelåsing** ved å la deg bruke en hvilken som helst annen leverandør med OpenCode også.
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,31 @@
|
||||||
---
|
---
|
||||||
title: Go
|
title: Go
|
||||||
description: Tani abonament na otwarte modele kodowania.
|
description: Niskokosztowa subskrypcja na otwarte modele do kodowania.
|
||||||
---
|
---
|
||||||
|
|
||||||
import config from "../../../../config.mjs"
|
import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
export const console = config.console
|
||||||
export const email = `mailto:${config.email}`
|
export const email = `mailto:${config.email}`
|
||||||
|
|
||||||
OpenCode Go to tania subskrypcja za **10 USD miesięcznie**, która zapewnia niezawodny dostęp do popularnych otwartych modeli kodowania.
|
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.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
OpenCode Go jest obecnie w fazie beta.
|
OpenCode Go jest obecnie w fazie beta.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
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.
|
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 głównie dla użytkowników międzynarodowych, z modelami hostowanymi w USA, UE i Singapurze dla stabilnego dostępu globalnego.
|
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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tło
|
## Tło
|
||||||
|
|
||||||
Otwarte modele stały się naprawdę dobre. Osiągają teraz wydajność zbliżoną do modeli komercyjnych w zadaniach związanych z kodowaniem. A ponieważ wielu dostawców może je obsługiwać konkurencyjnie, są zazwyczaj znacznie tańsze.
|
Otwarte modele stały się naprawdę dobre. Obecnie osiągają wydajność zbliżoną do modeli własnościowych w zadaniach związanych z kodowaniem. A ponieważ wielu dostawców może je oferować konkurencyjnie, są one zazwyczaj znacznie tańsze.
|
||||||
|
|
||||||
Jednak uzyskanie niezawodnego dostępu o niskim opóźnieniu może być trudne. Dostawcy różnią się jakością i dostępnością.
|
Jednak uzyskanie do nich niezawodnego dostępu o niskich opóźnieniach może być trudne. Dostawcy różnią się pod względem jakości i dostępności.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Przetestowaliśmy wybraną grupę modeli i dostawców, którzy dobrze współpracują z OpenCode.
|
Przetestowaliśmy wybraną grupę modeli i dostawców, którzy dobrze współpracują z OpenCode.
|
||||||
|
|
@ -31,11 +33,11 @@ Przetestowaliśmy wybraną grupę modeli i dostawców, którzy dobrze współpra
|
||||||
|
|
||||||
Aby to naprawić, zrobiliśmy kilka rzeczy:
|
Aby to naprawić, zrobiliśmy kilka rzeczy:
|
||||||
|
|
||||||
1. Przetestowaliśmy wybraną grupę otwartych modeli i rozmawialiśmy z ich zespołami o tym, jak najlepiej je uruchamiać.
|
1. Przetestowaliśmy wybraną grupę otwartych modeli i porozmawialiśmy z ich zespołami na temat najlepszych sposobów ich uruchamiania.
|
||||||
2. Następnie współpracowaliśmy z kilkoma dostawcami, aby upewnić się, że są one obsługiwane poprawnie.
|
2. Następnie nawiązaliśmy współpracę z kilkoma dostawcami, aby upewnić się, że są one obsługiwane poprawnie.
|
||||||
3. Na koniec przeprowadziliśmy testy porównawcze kombinacji modelu/dostawcy i stworzyliśmy listę, którą z czystym sumieniem polecamy.
|
3. Na koniec przetestowaliśmy kombinację modelu/dostawcy i stworzyliśmy listę, którą możemy z przekonaniem polecić.
|
||||||
|
|
||||||
OpenCode Go daje dostęp do tych modeli za **10 USD miesięcznie**.
|
OpenCode Go daje Ci dostęp do tych modeli za **5 $ za pierwszy miesiąc**, a następnie **10 $/miesiąc**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -43,12 +45,14 @@ OpenCode Go daje dostęp do tych modeli za **10 USD miesięcznie**.
|
||||||
|
|
||||||
OpenCode Go działa jak każdy inny dostawca w OpenCode.
|
OpenCode Go działa jak każdy inny dostawca w OpenCode.
|
||||||
|
|
||||||
1. Logujesz się do **<a href={console}>OpenCode Zen</a>**, subskrybujesz Go i kopiujesz swój klucz API.
|
1. Logujesz się do **<a href={console}>OpenCode Zen</a>**, subskrybujesz Go i
|
||||||
2. Uruchamiasz polecenie `/connect` w TUI, wybierasz `OpenCode Go` i wklejasz swój klucz API.
|
kopiujesz swój klucz API.
|
||||||
3. Uruchom `/models` w TUI, aby zobaczyć listę modeli dostępnych przez Go.
|
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
|
:::note
|
||||||
Tylko jeden członek na obszar roboczy może subskrybować OpenCode Go.
|
Tylko jeden członek na obszar roboczy (workspace) może zasubskrybować OpenCode Go.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Obecna lista modeli obejmuje:
|
Obecna lista modeli obejmuje:
|
||||||
|
|
@ -56,6 +60,7 @@ Obecna lista modeli obejmuje:
|
||||||
- **GLM-5**
|
- **GLM-5**
|
||||||
- **Kimi K2.5**
|
- **Kimi K2.5**
|
||||||
- **MiniMax M2.5**
|
- **MiniMax M2.5**
|
||||||
|
- **MiniMax M2.7**
|
||||||
|
|
||||||
Lista modeli może ulec zmianie w miarę testowania i dodawania nowych.
|
Lista modeli może ulec zmianie w miarę testowania i dodawania nowych.
|
||||||
|
|
||||||
|
|
@ -63,73 +68,64 @@ Lista modeli może ulec zmianie w miarę testowania i dodawania nowych.
|
||||||
|
|
||||||
## Limity użycia
|
## Limity użycia
|
||||||
|
|
||||||
OpenCode Go obejmuje następujące limity:
|
OpenCode Go zawiera następujące limity:
|
||||||
|
|
||||||
- **Limit 5-godzinny** — zużycie o wartości 12 USD
|
- **Limit 5-godzinny** — użycie o wartości 12 $
|
||||||
- **Limit tygodniowy** — zużycie o wartości 30 USD
|
- **Limit tygodniowy** — użycie o wartości 30 $
|
||||||
- **Limit miesięczny** — zużycie o wartości 60 USD
|
- **Limit miesięczny** — użycie o wartości 60 $
|
||||||
|
|
||||||
Limity są definiowane w wartości dolarowej. Oznacza to, że rzeczywista liczba żądań zależy od używanego modelu. Tańsze modele, takie jak MiniMax M2.5, pozwalają na więcej żądań, podczas gdy droższe modele, takie jak GLM-5, na mniej.
|
Limity są zdefiniowane w wartości w dolarach. Oznacza to, że rzeczywista liczba żądań zależy od używanego modelu. Tańsze modele, takie jak MiniMax M2.5, pozwalają na więcej żądań, podczas gdy modele o wyższym koszcie, takie jak GLM-5, pozwalają na mniej.
|
||||||
|
|
||||||
Poniższa tabela przedstawia szacunkową liczbę żądań w oparciu o typowe wzorce użytkowania Go:
|
Poniższa tabela przedstawia szacunkową liczbę żądań na podstawie typowych wzorców korzystania z Go:
|
||||||
|
|
||||||
| | GLM-5 | Kimi K2.5 | MiniMax M2.5 |
|
| | GLM-5 | Kimi K2.5 | MiniMax M2.7 | MiniMax M2.5 |
|
||||||
| ------------------- | ----- | --------- | ------------ |
|
| ------------------- | ----- | --------- | ------------ | ------------ |
|
||||||
| żądania na 5 godzin | 1 150 | 1 850 | 30 000 |
|
| żądania na 5 godzin | 1,150 | 1,850 | 14,000 | 20,000 |
|
||||||
| żądania na tydzień | 2 880 | 4 630 | 75 000 |
|
| żądania na tydzień | 2,880 | 4,630 | 35,000 | 50,000 |
|
||||||
| żądania na miesiąc | 5 750 | 9 250 | 150 000 |
|
| żądania na miesiąc | 5,750 | 9,250 | 70,000 | 100,000 |
|
||||||
|
|
||||||
Szacunki opierają się na zaobserwowanych średnich wzorcach żądań:
|
Szacunki opierają się na zaobserwowanych średnich wzorcach żądań:
|
||||||
|
|
||||||
- GLM-5 — 700 wejściowych, 52 000 zbuforowanych, 150 wyjściowych tokenów na żądanie
|
- GLM-5 — 700 tokenów wejściowych, 52 000 w pamięci podręcznej, 150 tokenów wyjściowych na żądanie
|
||||||
- Kimi K2.5 — 870 wejściowych, 55 000 zbuforowanych, 200 wyjściowych tokenów na żądanie
|
- Kimi K2.5 — 870 tokenów wejściowych, 55 000 w pamięci podręcznej, 200 tokenów wyjściowych na żądanie
|
||||||
- MiniMax M2.5 — 300 wejściowych, 55 000 zbuforowanych, 125 wyjściowych tokenów na żądanie
|
- MiniMax M2.7/M2.5 — 300 tokenów wejściowych, 55 000 w pamięci podręcznej, 125 tokenów wyjściowych na żądanie
|
||||||
|
|
||||||
Możesz śledzić swoje bieżące zużycie w **<a href={console}>konsoli</a>**.
|
Możesz śledzić swoje bieżące zużycie w **<a href={console}>konsoli</a>**.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Jeśli osiągniesz limit użycia, możesz kontynuować korzystanie z darmowych modeli.
|
Jeśli osiągniesz limit użycia, możesz nadal korzystać z darmowych modeli.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Limity użycia mogą ulec zmianie, gdy będziemy uczyć się na podstawie wczesnego użytkowania i opinii.
|
Limity użycia mogą ulec zmianie w miarę wyciągania wniosków z wczesnego użytkowania i opinii.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Cennik
|
### Użycie ponad limity
|
||||||
|
|
||||||
OpenCode Go to plan subskrypcji za **10 USD miesięcznie**. Poniżej znajdują się ceny **za 1 mln tokenów**.
|
Jeśli masz również środki na swoim saldzie Zen, możesz włączyć opcję **Użyj salda** (Use balance) w konsoli. Po włączeniu Go będzie korzystać z Twojego salda Zen po osiągnięciu limitów użycia zamiast blokować żądania.
|
||||||
|
|
||||||
| Model | Wejście | Wyjście | Odczyt cache |
|
|
||||||
| ------------ | ------- | ------- | ------------ |
|
|
||||||
| GLM-5 | 1,00 $ | 3,20 $ | 0,20 $ |
|
|
||||||
| Kimi K2.5 | 0,60 $ | 3,00 $ | 0,10 $ |
|
|
||||||
| MiniMax M2.5 | 0,30 $ | 1,20 $ | 0,03 $ |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Użycie poza limitami
|
|
||||||
|
|
||||||
Jeśli posiadasz również środki na swoim saldzie Zen, możesz włączyć opcję **Use balance** (Użyj salda) w konsoli. Po włączeniu, Go przełączy się na twoje saldo Zen po osiągnięciu limitów użycia, zamiast blokować żądania.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Punkty końcowe
|
## Punkty końcowe
|
||||||
|
|
||||||
Możesz również uzyskać dostęp do modeli Go poprzez następujące punkty końcowe API.
|
Możesz również uzyskać dostęp do modeli Go za pośrednictwem następujących punktów końcowych API.
|
||||||
|
|
||||||
| Model | Identyfikator modelu | Endpoint | Pakiet AI SDK |
|
| Model | ID modelu | Punkt końcowy | Pakiet AI SDK |
|
||||||
| ------------ | -------------------- | ------------------------------------------------ | --------------------------- |
|
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
||||||
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `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` |
|
||||||
|
|
||||||
[Identyfikator modelu](/docs/config/#models) w twojej konfiguracji OpenCode używa formatu `opencode-go/<model-id>`. Na przykład dla Kimi K2.5 użyłbyś `opencode-go/kimi-k2.5` w swojej konfiguracji.
|
[ID modelu](/docs/config/#models) w Twojej konfiguracji OpenCode
|
||||||
|
używa formatu `opencode-go/<model-id>`. Na przykład dla Kimi K2.5 należy użyć
|
||||||
|
`opencode-go/kimi-k2.5` w swojej konfiguracji.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Prywatność
|
## Prywatność
|
||||||
|
|
||||||
Plan jest przeznaczony głównie dla użytkowników międzynarodowych, z modelami hostowanymi w USA, UE i Singapurze dla stabilnego dostępu globalnego.
|
Plan 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.
|
||||||
|
|
||||||
<a href={email}>Skontaktuj się z nami</a>, jeśli masz jakiekolwiek pytania.
|
<a href={email}>Skontaktuj się z nami</a>, jeśli masz jakiekolwiek pytania.
|
||||||
|
|
||||||
|
|
@ -139,7 +135,7 @@ Plan jest przeznaczony głównie dla użytkowników międzynarodowych, z modelam
|
||||||
|
|
||||||
Stworzyliśmy OpenCode Go, aby:
|
Stworzyliśmy OpenCode Go, aby:
|
||||||
|
|
||||||
1. Uczynić kodowanie z AI **dostępnym** dla większej liczby osób dzięki taniej subskrypcji.
|
1. Uczynić kodowanie z pomocą sztucznej inteligencji **dostępnym** dla większej liczby osób dzięki niskokosztowej subskrypcji.
|
||||||
2. Zapewnić **niezawodny** dostęp do najlepszych otwartych modeli kodowania.
|
2. Zapewnić **niezawodny** dostęp do najlepszych otwartych modeli do kodowania.
|
||||||
3. Wyselekcjonować modele, które są **przetestowane i sprawdzone** pod kątem użycia z agentami kodującymi.
|
3. Wybierać modele, które są **przetestowane i sprawdzone w testach wydajności** do użytku przez agentów kodujących.
|
||||||
4. Nie wprowadzać **żadnych blokad (lock-in)**, pozwalając na korzystanie z dowolnego innego dostawcy w OpenCode.
|
4. Zapewnić **brak ograniczeń (no lock-in)**, pozwalając na korzystanie z dowolnego innego dostawcy wraz z OpenCode.
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,49 @@
|
||||||
---
|
---
|
||||||
title: Go
|
title: Go
|
||||||
description: Assinatura de baixo custo para modelos de codificação abertos.
|
description: Assinatura de baixo custo para modelos abertos de programação.
|
||||||
---
|
---
|
||||||
|
|
||||||
import config from "../../../../config.mjs"
|
import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
export const console = config.console
|
||||||
export const email = `mailto:${config.email}`
|
export const email = `mailto:${config.email}`
|
||||||
|
|
||||||
O OpenCode Go é uma assinatura de baixo custo de **$10/mês** que oferece acesso confiável a modelos de codificação abertos populares.
|
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.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
O OpenCode Go está atualmente em beta.
|
O OpenCode Go está atualmente em beta.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
O Go funciona como qualquer outro provedor no OpenCode. Você assina o OpenCode Go e obtém sua chave de API. É **totalmente opcional** e você não precisa usá-lo para usar o OpenCode.
|
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 é projetado principalmente para usuários internacionais, com modelos hospedados nos EUA, UE e Singapura para acesso global estável.
|
Ele foi projetado principalmente para usuários internacionais, com modelos hospedados nos EUA, na UE e em Singapura para um acesso global estável.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Contexto
|
## Contexto
|
||||||
|
|
||||||
Modelos abertos ficaram realmente bons. Eles agora alcançam desempenho próximo aos modelos proprietários para tarefas de codificação. E como muitos provedores podem servi-los competitivamente, eles geralmente são muito mais baratos.
|
Os modelos abertos ficaram muito bons. Eles agora alcançam um desempenho próximo aos
|
||||||
|
modelos proprietários para tarefas de programação. E como muitos provedores podem servi-los
|
||||||
|
de forma competitiva, eles geralmente são muito mais baratos.
|
||||||
|
|
||||||
No entanto, obter acesso confiável e de baixa latência a eles pode ser difícil. Os provedores variam em qualidade e disponibilidade.
|
No entanto, obter um acesso confiável e de baixa latência a eles pode ser difícil. Os provedores
|
||||||
|
variam em qualidade e disponibilidade.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Testamos um grupo selecionado de modelos e provedores que funcionam bem com o OpenCode.
|
Testamos um grupo selecionado de modelos e provedores que funcionam bem com o OpenCode.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Para corrigir isso, fizemos algumas coisas:
|
Para resolver isso, fizemos algumas coisas:
|
||||||
|
|
||||||
1. Testamos um grupo selecionado de modelos abertos e conversamos com suas equipes sobre a melhor forma de executá-los.
|
1. Testamos um grupo selecionado de modelos abertos e conversamos com suas equipes sobre a
|
||||||
2. Trabalhamos com alguns provedores para garantir que eles estivessem sendo servidos corretamente.
|
melhor forma de executá-los.
|
||||||
3. Finalmente, fizemos benchmarks da combinação modelo/provedor e chegamos a uma lista que nos sentimos bem em recomendar.
|
2. Em seguida, trabalhamos com alguns provedores para garantir que eles estivessem sendo servidos
|
||||||
|
corretamente.
|
||||||
|
3. Por fim, avaliamos por benchmark a combinação de modelo/provedor e elaboramos
|
||||||
|
uma lista que nos sentimos confortáveis em recomendar.
|
||||||
|
|
||||||
O OpenCode Go oferece acesso a esses modelos por **$10/mês**.
|
O OpenCode Go lhe dá acesso a esses modelos por **US$ 5 no seu primeiro mês**, depois **US$ 10/mês**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -43,8 +51,10 @@ O OpenCode Go oferece acesso a esses modelos por **$10/mês**.
|
||||||
|
|
||||||
O OpenCode Go funciona como qualquer outro provedor no OpenCode.
|
O OpenCode Go funciona como qualquer outro provedor no OpenCode.
|
||||||
|
|
||||||
1. Você faz login no **<a href={console}>OpenCode Zen</a>**, assina o Go e copia sua chave de API.
|
1. Você entra no **<a href={console}>OpenCode Zen</a>**, assina o Go e
|
||||||
2. Você executa o comando `/connect` na TUI, seleciona `OpenCode Go` e cola sua chave de API.
|
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.
|
3. Execute `/models` na TUI para ver a lista de modelos disponíveis através do Go.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
|
|
@ -56,6 +66,7 @@ A lista atual de modelos inclui:
|
||||||
- **GLM-5**
|
- **GLM-5**
|
||||||
- **Kimi K2.5**
|
- **Kimi K2.5**
|
||||||
- **MiniMax M2.5**
|
- **MiniMax M2.5**
|
||||||
|
- **MiniMax M2.7**
|
||||||
|
|
||||||
A lista de modelos pode mudar conforme testamos e adicionamos novos.
|
A lista de modelos pode mudar conforme testamos e adicionamos novos.
|
||||||
|
|
||||||
|
|
@ -65,73 +76,66 @@ A lista de modelos pode mudar conforme testamos e adicionamos novos.
|
||||||
|
|
||||||
O OpenCode Go inclui os seguintes limites:
|
O OpenCode Go inclui os seguintes limites:
|
||||||
|
|
||||||
- **Limite de 5 horas** — $12 de uso
|
- **Limite de 5 horas** — US$ 12 de uso
|
||||||
- **Limite semanal** — $30 de uso
|
- **Limite semanal** — US$ 30 de uso
|
||||||
- **Limite mensal** — $60 de uso
|
- **Limite mensal** — US$ 60 de uso
|
||||||
|
|
||||||
Os limites são definidos em valor monetário. Isso significa que sua contagem real de requisições depende do modelo que você usa. Modelos mais baratos como o MiniMax M2.5 permitem mais requisições, enquanto modelos de custo mais alto como o GLM-5 permitem menos.
|
Os limites são definidos em valor em dólares. Isso significa que a sua contagem real de requisições depende do modelo que você usa. Modelos mais baratos como o MiniMax M2.5 permitem mais requisições, enquanto modelos de custo mais alto como o GLM-5 permitem menos.
|
||||||
|
|
||||||
A tabela abaixo fornece uma estimativa de contagem de requisições baseada em padrões típicos de uso do Go:
|
A tabela abaixo fornece uma contagem estimada de requisições com base nos padrões típicos de uso do Go:
|
||||||
|
|
||||||
| | GLM-5 | Kimi K2.5 | MiniMax M2.5 |
|
| | GLM-5 | Kimi K2.5 | MiniMax M2.7 | MiniMax M2.5 |
|
||||||
| ----------------------- | ----- | --------- | ------------ |
|
| -------------------------- | ----- | --------- | ------------ | ------------ |
|
||||||
| requisições por 5 horas | 1.150 | 1.850 | 30.000 |
|
| requisições a cada 5 horas | 1.150 | 1.850 | 14.000 | 20.000 |
|
||||||
| requisições por semana | 2.880 | 4.630 | 75.000 |
|
| requisições por semana | 2.880 | 4.630 | 35.000 | 50.000 |
|
||||||
| requisições por mês | 5.750 | 9.250 | 150.000 |
|
| requisições por mês | 5.750 | 9.250 | 70.000 | 100.000 |
|
||||||
|
|
||||||
As estimativas são baseadas em padrões médios de requisição observados:
|
As estimativas baseiam-se nos padrões médios de requisições observados:
|
||||||
|
|
||||||
- GLM-5 — 700 tokens de entrada, 52.000 em cache, 150 tokens de saída por requisição
|
- GLM-5 — 700 tokens de entrada, 52.000 em cache, 150 tokens de saída por requisição
|
||||||
- Kimi K2.5 — 870 tokens de entrada, 55.000 em cache, 200 tokens de saída por requisição
|
- Kimi K2.5 — 870 tokens de entrada, 55.000 em cache, 200 tokens de saída por requisição
|
||||||
- MiniMax M2.5 — 300 tokens de entrada, 55.000 em cache, 125 tokens de saída por requisição
|
- MiniMax M2.7/M2.5 — 300 tokens de entrada, 55.000 em cache, 125 tokens de saída por requisição
|
||||||
|
|
||||||
Você pode acompanhar seu uso atual no **<a href={console}>console</a>**.
|
Você pode acompanhar o seu uso atual no **<a href={console}>console</a>**.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Se você atingir o limite de uso, pode continuar usando os modelos gratuitos.
|
Se você atingir o limite de uso, pode continuar usando os modelos gratuitos.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Os limites de uso podem mudar conforme aprendemos com o uso inicial e feedback.
|
Os limites de uso podem mudar à medida que aprendemos com o uso inicial e o feedback.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Preços
|
|
||||||
|
|
||||||
O OpenCode Go é um plano de assinatura de **$10/mês**. Abaixo estão os preços **por 1M de tokens**.
|
|
||||||
|
|
||||||
| Modelo | Entrada | Saída | Leitura em Cache |
|
|
||||||
| ------------ | ------- | ----- | ---------------- |
|
|
||||||
| GLM-5 | $1.00 | $3.20 | $0.20 |
|
|
||||||
| Kimi K2.5 | $0.60 | $3.00 | $0.10 |
|
|
||||||
| MiniMax M2.5 | $0.30 | $1.20 | $0.03 |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Uso além dos limites
|
### Uso além dos limites
|
||||||
|
|
||||||
Se você também tiver créditos em seu saldo Zen, pode ativar a opção **Use balance** (Usar saldo) no console. Quando ativada, o Go recorrerá ao seu saldo Zen depois que você atingir seus limites de uso, em vez de bloquear as requisições.
|
Se você também tiver créditos no seu saldo do Zen, pode habilitar a opção **Use balance**
|
||||||
|
no console. Quando habilitada, o Go usará o seu saldo do Zen como alternativa
|
||||||
|
após você atingir os seus limites de uso em vez de bloquear as requisições.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Endpoints
|
## Endpoints
|
||||||
|
|
||||||
Você também pode acessar os modelos Go através dos seguintes endpoints de API.
|
Você também pode acessar os modelos do Go através dos seguintes endpoints de API.
|
||||||
|
|
||||||
| Modelo | ID do Modelo | Endpoint | Pacote AI SDK |
|
| Modelo | ID do Modelo | Endpoint | Pacote do AI SDK |
|
||||||
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
||||||
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
|
|
||||||
O [model id](/docs/config/#models) (ID do modelo) na sua configuração do OpenCode usa o formato `opencode-go/<model-id>`. Por exemplo, para o Kimi K2.5, você usaria `opencode-go/kimi-k2.5` na sua configuração.
|
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 K2.5, você usaria
|
||||||
|
`opencode-go/kimi-k2.5` na sua configuração.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Privacidade
|
## Privacidade
|
||||||
|
|
||||||
O plano é projetado principalmente para usuários internacionais, com modelos hospedados nos EUA, UE e Singapura para acesso global estável.
|
O plano foi projetado principalmente para usuários internacionais, com modelos hospedados nos EUA, na UE e em Singapura para um acesso global estável.
|
||||||
|
|
||||||
<a href={email}>Entre em contato conosco</a> se tiver alguma dúvida.
|
<a href={email}>Entre em contato conosco</a> se você tiver alguma dúvida.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -139,7 +143,7 @@ O plano é projetado principalmente para usuários internacionais, com modelos h
|
||||||
|
|
||||||
Criamos o OpenCode Go para:
|
Criamos o OpenCode Go para:
|
||||||
|
|
||||||
1. Tornar a IA de codificação **acessível** a mais pessoas com uma assinatura de baixo custo.
|
1. Tornar a programação com IA **acessível** a mais pessoas com uma assinatura de baixo custo.
|
||||||
2. Fornecer acesso **confiável** aos melhores modelos de codificação abertos.
|
2. Fornecer acesso **confiável** aos melhores modelos abertos de programação.
|
||||||
3. Curar modelos que são **testados e avaliados** para uso em agentes de codificação.
|
3. Ter modelos sob curadoria que são **testados e avaliados (benchmarked)** para o uso por agentes de programação.
|
||||||
4. Não ter **nenhum bloqueio (lock-in)**, permitindo que você use qualquer outro provedor com o OpenCode também.
|
4. Não ter **nenhuma restrição de fornecedor (lock-in)**, permitindo que você use qualquer outro provedor com o OpenCode também.
|
||||||
|
|
|
||||||
|
|
@ -1,54 +1,64 @@
|
||||||
---
|
---
|
||||||
title: Go
|
title: Go
|
||||||
description: Недорогая подписка на открытые модели для кодинга.
|
description: Недорогая подписка на открытые модели для программирования.
|
||||||
---
|
---
|
||||||
|
|
||||||
import config from "../../../../config.mjs"
|
import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
export const console = config.console
|
||||||
export const email = `mailto:${config.email}`
|
export const email = `mailto:${config.email}`
|
||||||
|
|
||||||
OpenCode Go — это недорогая подписка за **$10/месяц**, которая предоставляет надежный доступ к популярным открытым моделям для кодинга.
|
OpenCode Go — это недорогая подписка (**$5 за первый месяц**, далее **$10 в месяц**), которая предоставляет надежный доступ к популярным открытым моделям для программирования.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
OpenCode Go в настоящее время находится в бета-версии.
|
OpenCode Go в настоящее время находится в бета-тестировании.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Go работает как любой другой провайдер в OpenCode. Вы подписываетесь на OpenCode Go и получаете свой API ключ. Это **полностью опционально**, и вам не нужно использовать его, чтобы пользоваться OpenCode.
|
Go работает так же, как и любой другой провайдер в OpenCode. Вы оформляете подписку на OpenCode Go и
|
||||||
|
получаете свой API-ключ. Использование Go **абсолютно необязательно**, и вам не нужно использовать его, чтобы
|
||||||
|
пользоваться OpenCode.
|
||||||
|
|
||||||
Он разработан в первую очередь для международных пользователей, с моделями, размещенными в США, ЕС и Сингапуре для стабильного глобального доступа.
|
Она предназначена в первую очередь для пользователей со всего мира, а модели размещены в США, ЕС и Сингапуре для стабильного глобального доступа.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Предыстория
|
## Предпосылки
|
||||||
|
|
||||||
Открытые модели стали действительно хорошими. Теперь они достигают производительности, близкой к проприетарным моделям для задач кодинга. И поскольку многие провайдеры могут обслуживать их на конкурентной основе, они обычно намного дешевле.
|
Открытые модели стали действительно хороши. Сейчас они достигают производительности, близкой к
|
||||||
|
проприетарным моделям для задач программирования. И поскольку многие провайдеры могут предоставлять к ним доступ
|
||||||
|
на конкурентных условиях, они, как правило, обходятся гораздо дешевле.
|
||||||
|
|
||||||
Однако получение надежного доступа к ним с низкой задержкой может быть сложным. Качество и доступность провайдеров варьируются.
|
Однако получить к ним надежный доступ с низкой задержкой может быть непросто. Провайдеры
|
||||||
|
различаются по качеству и доступности.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Мы протестировали избранную группу моделей и провайдеров, которые хорошо работают с OpenCode.
|
Мы протестировали выбранную группу моделей и провайдеров, которые хорошо работают с OpenCode.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Чтобы исправить это, мы сделали пару вещей:
|
Чтобы исправить это, мы сделали пару вещей:
|
||||||
|
|
||||||
1. Мы протестировали избранную группу открытых моделей и поговорили с их командами о том, как лучше всего их запускать.
|
1. Мы протестировали выбранную группу открытых моделей и поговорили с их командами о том, как
|
||||||
2. Затем мы работали с несколькими провайдерами, чтобы убедиться, что они обслуживаются правильно.
|
лучше всего их запускать.
|
||||||
3. Наконец, мы провели бенчмаркинг комбинации модели/провайдера и составили список, который мы можем смело рекомендовать.
|
2. Затем мы поработали с несколькими провайдерами, чтобы убедиться, что они предоставляются
|
||||||
|
корректно.
|
||||||
|
3. Наконец, мы провели бенчмаркинг комбинаций модель/провайдер и составили
|
||||||
|
список, который мы смело можем рекомендовать.
|
||||||
|
|
||||||
OpenCode Go дает вам доступ к этим моделям за **$10/месяц**.
|
OpenCode Go дает вам доступ к этим моделям за **$5 в первый месяц**, далее **$10 в месяц**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Как это работает
|
## Как это работает
|
||||||
|
|
||||||
OpenCode Go работает как любой другой провайдер в OpenCode.
|
OpenCode Go работает так же, как и любой другой провайдер в OpenCode.
|
||||||
|
|
||||||
1. Вы входите в **<a href={console}>OpenCode Zen</a>**, подписываетесь на Go и копируете свой API ключ.
|
1. Вы входите в **<a href={console}>OpenCode Zen</a>**, подписываетесь на Go и
|
||||||
2. Вы запускаете команду `/connect` в TUI, выбираете `OpenCode Go` и вставляете свой API ключ.
|
копируете свой API-ключ.
|
||||||
|
2. Вы выполняете команду `/connect` в TUI, выбираете `OpenCode Go` и вставляете
|
||||||
|
свой API-ключ.
|
||||||
3. Запустите `/models` в TUI, чтобы увидеть список моделей, доступных через Go.
|
3. Запустите `/models` в TUI, чтобы увидеть список моделей, доступных через Go.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
Только один участник рабочей области может подписаться на OpenCode Go.
|
Только один участник рабочего пространства может подписаться на OpenCode Go.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Текущий список моделей включает:
|
Текущий список моделей включает:
|
||||||
|
|
@ -56,6 +66,7 @@ OpenCode Go работает как любой другой провайдер
|
||||||
- **GLM-5**
|
- **GLM-5**
|
||||||
- **Kimi K2.5**
|
- **Kimi K2.5**
|
||||||
- **MiniMax M2.5**
|
- **MiniMax M2.5**
|
||||||
|
- **MiniMax M2.7**
|
||||||
|
|
||||||
Список моделей может меняться по мере того, как мы тестируем и добавляем новые.
|
Список моделей может меняться по мере того, как мы тестируем и добавляем новые.
|
||||||
|
|
||||||
|
|
@ -65,73 +76,66 @@ OpenCode Go работает как любой другой провайдер
|
||||||
|
|
||||||
OpenCode Go включает следующие лимиты:
|
OpenCode Go включает следующие лимиты:
|
||||||
|
|
||||||
- **5-часовой лимит** — $12 использования
|
- **Лимит на 5 часов** — $12 использования
|
||||||
- **Недельный лимит** — $30 использования
|
- **Недельный лимит** — $30 использования
|
||||||
- **Месячный лимит** — $60 использования
|
- **Месячный лимит** — $60 использования
|
||||||
|
|
||||||
Лимиты определены в денежном выражении. Это означает, что ваше фактическое количество запросов зависит от модели, которую вы используете. Более дешевые модели, такие как MiniMax M2.5, позволяют делать больше запросов, в то время как более дорогие модели, такие как GLM-5, позволяют меньше.
|
Лимиты определены в долларовом эквиваленте. Это означает, что ваше фактическое количество запросов зависит от используемой модели. Более дешевые модели, такие как MiniMax M2.5, позволяют делать больше запросов, в то время как более дорогие, такие как GLM-5, — меньше.
|
||||||
|
|
||||||
Таблица ниже предоставляет примерное количество запросов на основе типичных паттернов использования Go:
|
В таблице ниже приведено примерное количество запросов на основе типичных сценариев использования Go:
|
||||||
|
|
||||||
| | GLM-5 | Kimi K2.5 | MiniMax M2.5 |
|
| | GLM-5 | Kimi K2.5 | MiniMax M2.7 | MiniMax M2.5 |
|
||||||
| ------------------- | ----- | --------- | ------------ |
|
| ------------------- | ----- | --------- | ------------ | ------------ |
|
||||||
| запросов за 5 часов | 1,150 | 1,850 | 30,000 |
|
| запросов за 5 часов | 1,150 | 1,850 | 14,000 | 20,000 |
|
||||||
| запросов в неделю | 2,880 | 4,630 | 75,000 |
|
| запросов в неделю | 2,880 | 4,630 | 35,000 | 50,000 |
|
||||||
| запросов в месяц | 5,750 | 9,250 | 150,000 |
|
| запросов в месяц | 5,750 | 9,250 | 70,000 | 100,000 |
|
||||||
|
|
||||||
Оценки основаны на наблюдаемых средних паттернах запросов:
|
Оценки основаны на наблюдаемых средних показателях запросов:
|
||||||
|
|
||||||
- GLM-5 — 700 входных, 52,000 кэшированных, 150 выходных токенов на запрос
|
- GLM-5 — 700 входных, 52,000 кешированных, 150 выходных токенов на запрос
|
||||||
- Kimi K2.5 — 870 входных, 55,000 кэшированных, 200 выходных токенов на запрос
|
- Kimi K2.5 — 870 входных, 55,000 кешированных, 200 выходных токенов на запрос
|
||||||
- MiniMax M2.5 — 300 входных, 55,000 кэшированных, 125 выходных токенов на запрос
|
- MiniMax M2.7/M2.5 — 300 входных, 55,000 кешированных, 125 выходных токенов на запрос
|
||||||
|
|
||||||
Вы можете отслеживать свое текущее использование в **<a href={console}>консоли</a>**.
|
Вы можете отслеживать текущее использование в **<a href={console}>консоли</a>**.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Если вы достигнете лимита использования, вы можете продолжить использовать бесплатные модели.
|
Если вы достигнете лимита использования, вы можете продолжить использовать бесплатные модели.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Лимиты использования могут меняться по мере того, как мы учимся на раннем использовании и отзывах.
|
Лимиты использования могут измениться по мере того, как мы будем собирать данные о раннем использовании и отзывы.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Ценообразование
|
|
||||||
|
|
||||||
OpenCode Go — это план подписки за **$10/месяц**. Ниже приведены цены **за 1 млн токенов**.
|
|
||||||
|
|
||||||
| Модель | Ввод | Вывод | Кэшированное чтение |
|
|
||||||
| ------------ | ----- | ----- | ------------------- |
|
|
||||||
| GLM-5 | $1.00 | $3.20 | $0.20 |
|
|
||||||
| Kimi K2.5 | $0.60 | $3.00 | $0.10 |
|
|
||||||
| MiniMax M2.5 | $0.30 | $1.20 | $0.03 |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Использование сверх лимитов
|
### Использование сверх лимитов
|
||||||
|
|
||||||
Если у вас также есть кредиты на балансе Zen, вы можете включить опцию **Use balance** (Использовать баланс) в консоли. Когда она включена, Go переключится на ваш баланс Zen после того, как вы исчерпаете свои лимиты использования, вместо блокировки запросов.
|
Если у вас также есть средства на балансе Zen, вы можете включить опцию **Use balance**
|
||||||
|
в консоли. Если она включена, Go будет использовать ваш баланс Zen
|
||||||
|
после достижения лимитов использования вместо того, чтобы блокировать запросы.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Эндпоинты
|
## Эндпоинты
|
||||||
|
|
||||||
Вы также можете получить доступ к моделям Go через следующие API эндпоинты.
|
Вы также можете получить доступ к моделям Go через следующие API-эндпоинты.
|
||||||
|
|
||||||
| Модель | ID модели | Эндпоинт | Пакет AI SDK |
|
| Модель | ID модели | Эндпоинт | Пакет AI SDK |
|
||||||
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
||||||
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
|
|
||||||
[Model id](/docs/config/#models) в вашей конфигурации OpenCode использует формат `opencode-go/<model-id>`. Например, для Kimi K2.5 вы бы использовали `opencode-go/kimi-k2.5` в вашей конфигурации.
|
[ID модели](/docs/config/#models) в вашем конфиге OpenCode
|
||||||
|
использует формат `opencode-go/<model-id>`. Например, для Kimi K2.5 вам нужно
|
||||||
|
использовать `opencode-go/kimi-k2.5` в вашем конфиге.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Конфиденциальность
|
## Конфиденциальность
|
||||||
|
|
||||||
План разработан в первую очередь для международных пользователей, с моделями, размещенными в США, ЕС и Сингапуре для стабильного глобального доступа.
|
План предназначен в первую очередь для пользователей со всего мира, а модели размещены в США, ЕС и Сингапуре для стабильного глобального доступа.
|
||||||
|
|
||||||
<a href={email}>Свяжитесь с нами</a>, если у вас есть вопросы.
|
<a href={email}>Свяжитесь с нами</a>, если у вас есть какие-либо вопросы.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -139,7 +143,7 @@ OpenCode Go — это план подписки за **$10/месяц**. Ниж
|
||||||
|
|
||||||
Мы создали OpenCode Go, чтобы:
|
Мы создали OpenCode Go, чтобы:
|
||||||
|
|
||||||
1. Сделать ИИ-кодинг **доступным** большему количеству людей с недорогой подпиской.
|
1. Сделать программирование с ИИ **доступным** для большего числа людей с помощью недорогой подписки.
|
||||||
2. Обеспечить **надежный** доступ к лучшим открытым моделям для кодинга.
|
2. Обеспечить **надежный** доступ к лучшим открытым моделям для программирования.
|
||||||
3. Отобрать модели, которые **протестированы и проверены** для использования агентами кодинга.
|
3. Отбирать модели, которые **протестированы и проверены** для использования в качестве агентов-программистов.
|
||||||
4. Не иметь **привязки к поставщику** (no lock-in), позволяя вам использовать любого другого провайдера с OpenCode.
|
4. Избежать **привязки к провайдеру**, позволяя вам также использовать любого другого провайдера вместе с OpenCode.
|
||||||
|
|
|
||||||
|
|
@ -1,145 +1,135 @@
|
||||||
---
|
---
|
||||||
title: Go
|
title: Go
|
||||||
description: การสมัครสมาชิกราคาประหยัดสำหรับโมเดลการเขียนโค้ดแบบเปิด
|
description: การสมัครสมาชิกราคาประหยัดสำหรับโมเดลโอเพนซอร์สเพื่อการเขียนโค้ด
|
||||||
---
|
---
|
||||||
|
|
||||||
import config from "../../../../config.mjs"
|
import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
export const console = config.console
|
||||||
export const email = `mailto:${config.email}`
|
export const email = `mailto:${config.email}`
|
||||||
|
|
||||||
OpenCode Go คือการสมัครสมาชิกราคาประหยัดเพียง **$10/เดือน** ที่ให้คุณเข้าถึงโมเดลการเขียนโค้ดแบบเปิดยอดนิยมได้อย่างน่าเชื่อถือ
|
OpenCode Go คือการสมัครสมาชิกในราคาประหยัด — **$5 สำหรับเดือนแรก** จากนั้น **$10/เดือน** — ซึ่งให้คุณเข้าถึงโมเดลโอเพนซอร์สยอดนิยมสำหรับการเขียนโค้ดได้อย่างเสถียร
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
ขณะนี้ OpenCode Go อยู่ในช่วงเบต้า
|
OpenCode Go ขณะนี้อยู่ในช่วงเบต้า
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Go ทำงานเหมือนกับผู้ให้บริการรายอื่นใน OpenCode คุณสมัครสมาชิก OpenCode Go และรับคีย์ API ของคุณ มันเป็น**ตัวเลือกเสริมทั้งหมด** และคุณไม่จำเป็นต้องใช้มันเพื่อใช้งาน OpenCode
|
Go ทำงานเหมือนกับผู้ให้บริการ (provider) รายอื่นๆ ใน OpenCode คุณสามารถสมัครสมาชิก OpenCode Go และรับ API key ของคุณ บริการนี้เป็น**ทางเลือกเพิ่มเติม** และคุณไม่จำเป็นต้องใช้มันเพื่อใช้งาน OpenCode
|
||||||
|
|
||||||
มันถูกออกแบบมาสำหรับผู้ใช้งานระดับนานาชาติเป็นหลัก โดยมีโมเดลโฮสต์อยู่ในสหรัฐอเมริกา สหภาพยุโรป และสิงคโปร์ เพื่อการเข้าถึงที่เสถียรทั่วโลก
|
บริการนี้ออกแบบมาเพื่อผู้ใช้ในระดับสากลเป็นหลัก โดยมีโมเดลโฮสต์อยู่ในสหรัฐอเมริกา สหภาพยุโรป และสิงคโปร์ เพื่อการเข้าถึงทั่วโลกที่เสถียร
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ความเป็นมา
|
## Background
|
||||||
|
|
||||||
โมเดลแบบเปิดมีคุณภาพดีขึ้นมาก ปัจจุบันมีประสิทธิภาพใกล้เคียงกับโมเดลที่เป็นกรรมสิทธิ์สำหรับงานเขียนโค้ด และเนื่องจากผู้ให้บริการหลายรายสามารถให้บริการโมเดลเหล่านี้ได้อย่างแข่งขันกัน จึงมักจะมีราคาถูกกว่ามาก
|
โมเดลแบบเปิด (Open models) ได้รับการพัฒนาจนมีประสิทธิภาพดีมาก ตอนนี้ประสิทธิภาพในการเขียนโค้ดใกล้เคียงกับโมเดลแบบปิด (proprietary models) แล้ว และเนื่องจากมีผู้ให้บริการหลายรายสามารถให้บริการแข่งขันกันได้ จึงทำให้มีราคาถูกกว่ามาก
|
||||||
|
|
||||||
อย่างไรก็ตาม การเข้าถึงโมเดลเหล่านี้อย่างน่าเชื่อถือและมีความหน่วงต่ำอาจเป็นเรื่องยาก ผู้ให้บริการมีคุณภาพและความพร้อมใช้งานที่แตกต่างกัน
|
อย่างไรก็ตาม การเข้าถึงโมเดลเหล่านี้อย่างเสถียรและมีค่า Latency ต่ำนั้นอาจเป็นเรื่องยาก ผู้ให้บริการแต่ละรายมีคุณภาพและความพร้อมในการให้บริการแตกต่างกันไป
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
เราได้ทดสอบกลุ่มโมเดลและผู้ให้บริการที่เลือกสรรแล้วซึ่งทำงานได้ดีกับ OpenCode
|
เราได้ทดสอบกลุ่มโมเดลและผู้ให้บริการที่คัดเลือกมาเพื่อให้ทำงานร่วมกับ OpenCode ได้เป็นอย่างดี
|
||||||
:::
|
:::
|
||||||
|
|
||||||
เพื่อแก้ไขปัญหานี้ เราได้ทำสิ่งต่อไปนี้:
|
เพื่อแก้ปัญหานี้ เราได้ดำเนินการดังต่อไปนี้:
|
||||||
|
|
||||||
1. เราทดสอบกลุ่มโมเดลแบบเปิดที่เลือกสรรและพูดคุยกับทีมของพวกเขาเกี่ยวกับวิธีการรันโมเดลให้ดีที่สุด
|
1. เราทดสอบกลุ่มโมเดลแบบเปิดที่คัดเลือกมาและพูดคุยกับทีมผู้พัฒนาเกี่ยวกับวิธีการรันโมเดลเหล่านี้ให้ดีที่สุด
|
||||||
2. จากนั้นเราทำงานร่วมกับผู้ให้บริการบางรายเพื่อให้แน่ใจว่าโมเดลเหล่านี้ได้รับการให้บริการอย่างถูกต้อง
|
2. จากนั้นเราได้ทำงานร่วมกับผู้ให้บริการบางรายเพื่อให้แน่ใจว่าการให้บริการเป็นไปอย่างถูกต้อง
|
||||||
3. สุดท้าย เราทำการทดสอบประสิทธิภาพ (Benchmark) การรวมกันของโมเดล/ผู้ให้บริการ และได้รายชื่อที่เรารู้สึกดีที่จะแนะนำ
|
3. สุดท้าย เราได้ทำการวัดประสิทธิภาพ (benchmark) ของการทำงานร่วมกันระหว่างโมเดลและผู้ให้บริการ จนได้รายชื่อที่เรามั่นใจในการแนะนำ
|
||||||
|
|
||||||
OpenCode Go ให้คุณเข้าถึงโมเดลเหล่านี้ในราคา **$10/เดือน**
|
OpenCode Go ให้คุณเข้าถึงโมเดลเหล่านี้ได้ในราคา **$5 สำหรับเดือนแรก** จากนั้น **$10/เดือน**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## วิธีการทำงาน
|
## How it works
|
||||||
|
|
||||||
OpenCode Go ทำงานเหมือนกับผู้ให้บริการรายอื่นใน OpenCode
|
OpenCode Go ทำงานเหมือนกับผู้ให้บริการรายอื่นๆ ใน OpenCode
|
||||||
|
|
||||||
1. ลงชื่อเข้าใช้ **<a href={console}>OpenCode Zen</a>** สมัครสมาชิก Go และคัดลอกคีย์ API ของคุณ
|
1. ลงชื่อเข้าใช้ที่ **<a href={console}>OpenCode Zen</a>**, สมัครสมาชิก Go และคัดลอก API key ของคุณ
|
||||||
2. รันคำสั่ง `/connect` ใน TUI เลือก `OpenCode Go` และวางคีย์ API ของคุณ
|
2. รันคำสั่ง `/connect` ใน TUI, เลือก `OpenCode Go`, และวาง API key ของคุณ
|
||||||
3. รัน `/models` ใน TUI เพื่อดูรายชื่อโมเดลที่สามารถใช้งานได้ผ่าน Go
|
3. รัน `/models` ใน TUI เพื่อดูรายชื่อโมเดลที่ใช้งานได้ผ่าน Go
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
สมาชิกเพียงหนึ่งคนต่อพื้นที่ทำงาน (Workspace) เท่านั้นที่สามารถสมัครสมาชิก OpenCode Go ได้
|
มีเพียงสมาชิกหนึ่งคนต่อ workspace เท่านั้นที่สามารถสมัครสมาชิก OpenCode Go ได้
|
||||||
:::
|
:::
|
||||||
|
|
||||||
รายชื่อโมเดลปัจจุบันประกอบด้วย:
|
รายชื่อโมเดลในปัจจุบันประกอบด้วย:
|
||||||
|
|
||||||
- **GLM-5**
|
- **GLM-5**
|
||||||
- **Kimi K2.5**
|
- **Kimi K2.5**
|
||||||
- **MiniMax M2.5**
|
- **MiniMax M2.5**
|
||||||
|
- **MiniMax M2.7**
|
||||||
|
|
||||||
รายชื่อโมเดลอาจมีการเปลี่ยนแปลงเมื่อเราทดสอบและเพิ่มโมเดลใหม่
|
รายชื่อโมเดลอาจมีการเปลี่ยนแปลงเมื่อเราทำการทดสอบและเพิ่มโมเดลใหม่ๆ
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ขีดจำกัดการใช้งาน
|
## Usage limits
|
||||||
|
|
||||||
OpenCode Go มีขีดจำกัดดังต่อไปนี้:
|
OpenCode Go มีขีดจำกัดดังต่อไปนี้:
|
||||||
|
|
||||||
- **ขีดจำกัด 5 ชั่วโมง** — การใช้งานมูลค่า $12
|
- **ขีดจำกัดต่อ 5 ชั่วโมง** — การใช้งานมูลค่า $12
|
||||||
- **ขีดจำกัดรายสัปดาห์** — การใช้งานมูลค่า $30
|
- **ขีดจำกัดรายสัปดาห์** — การใช้งานมูลค่า $30
|
||||||
- **ขีดจำกัดรายเดือน** — การใช้งานมูลค่า $60
|
- **ขีดจำกัดรายเดือน** — การใช้งานมูลค่า $60
|
||||||
|
|
||||||
ขีดจำกัดถูกกำหนดเป็นมูลค่าดอลลาร์ ซึ่งหมายความว่าจำนวนคำขอจริงของคุณจะขึ้นอยู่กับโมเดลที่คุณใช้ โมเดลที่ถูกกว่าเช่น MiniMax M2.5 อนุญาตให้ส่งคำขอได้มากกว่า ในขณะที่โมเดลที่มีราคาสูงกว่าเช่น GLM-5 จะอนุญาตให้ส่งคำขอได้น้อยกว่า
|
ขีดจำกัดถูกกำหนดเป็นมูลค่าดอลลาร์ ซึ่งหมายความว่าจำนวน request จริงของคุณจะขึ้นอยู่กับโมเดลที่คุณใช้งาน โมเดลที่ราคาถูกกว่าอย่าง MiniMax M2.5 จะสามารถส่ง request ได้มากกว่า ในขณะที่โมเดลที่มีราคาสูงกว่าอย่าง GLM-5 จะส่งได้น้อยกว่า
|
||||||
|
|
||||||
ตารางด้านล่างแสดงจำนวนคำขอโดยประมาณตามรูปแบบการใช้งาน Go ทั่วไป:
|
ตารางด้านล่างแสดงจำนวน request โดยประมาณตามรูปแบบการใช้งานปกติของ Go:
|
||||||
|
|
||||||
| | GLM-5 | Kimi K2.5 | MiniMax M2.5 |
|
| | GLM-5 | Kimi K2.5 | MiniMax M2.7 | MiniMax M2.5 |
|
||||||
| ----------------- | ----- | --------- | ------------ |
|
| --------------------------- | ----- | --------- | ------------ | ------------ |
|
||||||
| คำขอต่อ 5 ชั่วโมง | 1,150 | 1,850 | 30,000 |
|
| จำนวน request ต่อ 5 ชั่วโมง | 1,150 | 1,850 | 14,000 | 20,000 |
|
||||||
| คำขอต่อสัปดาห์ | 2,880 | 4,630 | 75,000 |
|
| จำนวน request ต่อสัปดาห์ | 2,880 | 4,630 | 35,000 | 50,000 |
|
||||||
| คำขอต่อเดือน | 5,750 | 9,250 | 150,000 |
|
| จำนวน request ต่อเดือน | 5,750 | 9,250 | 70,000 | 100,000 |
|
||||||
|
|
||||||
การประมาณการขึ้นอยู่กับรูปแบบคำขอเฉลี่ยที่สังเกตได้:
|
การประมาณการอ้างอิงจากรูปแบบการใช้งาน request โดยเฉลี่ยที่สังเกตพบ:
|
||||||
|
|
||||||
- GLM-5 — 700 input, 52,000 cached, 150 output tokens ต่อคำขอ
|
- GLM-5 — 700 input, 52,000 cached, 150 output tokens ต่อ request
|
||||||
- Kimi K2.5 — 870 input, 55,000 cached, 200 output tokens ต่อคำขอ
|
- Kimi K2.5 — 870 input, 55,000 cached, 200 output tokens ต่อ request
|
||||||
- MiniMax M2.5 — 300 input, 55,000 cached, 125 output tokens ต่อคำขอ
|
- MiniMax M2.7/M2.5 — 300 input, 55,000 cached, 125 output tokens ต่อ request
|
||||||
|
|
||||||
คุณสามารถติดตามการใช้งานปัจจุบันของคุณได้ใน **<a href={console}>คอนโซล</a>**
|
คุณสามารถติดตามการใช้งานปัจจุบันของคุณได้ใน **<a href={console}>console</a>**
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
หากคุณใช้งานจนถึงขีดจำกัด คุณสามารถใช้โมเดลฟรีต่อไปได้
|
หากคุณใช้งานถึงขีดจำกัดแล้ว คุณยังสามารถใช้งานโมเดลฟรีต่อไปได้
|
||||||
:::
|
:::
|
||||||
|
|
||||||
ขีดจำกัดการใช้งานอาจมีการเปลี่ยนแปลงเมื่อเราเรียนรู้จากการใช้งานและข้อเสนอแนะในช่วงแรก
|
ขีดจำกัดการใช้งานอาจมีการเปลี่ยนแปลงเมื่อเราได้เรียนรู้จากการใช้งานในช่วงแรกและรับฟังข้อเสนอแนะ
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### ราคา
|
### Usage beyond limits
|
||||||
|
|
||||||
OpenCode Go เป็นแผนการสมัครสมาชิกราคา **$10/เดือน** ด้านล่างคือราคา**ต่อ 1 ล้านโทเค็น**
|
หากคุณมีเครดิตในยอดเงินคงเหลือของ Zen ด้วย คุณสามารถเปิดใช้งานตัวเลือก **Use balance** ใน console เมื่อเปิดใช้งาน Go จะหันไปใช้ยอดเงินคงเหลือใน Zen ของคุณหลังจากที่คุณใช้งานถึงขีดจำกัดแล้วแทนที่จะบล็อก request
|
||||||
|
|
||||||
| Model | Input | Output | Cached Read |
|
|
||||||
| ------------ | ----- | ------ | ----------- |
|
|
||||||
| GLM-5 | $1.00 | $3.20 | $0.20 |
|
|
||||||
| Kimi K2.5 | $0.60 | $3.00 | $0.10 |
|
|
||||||
| MiniMax M2.5 | $0.30 | $1.20 | $0.03 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### การใช้งานเกินขีดจำกัด
|
|
||||||
|
|
||||||
หากคุณมีเครดิตในยอดคงเหลือ Zen ของคุณ คุณสามารถเปิดใช้งานตัวเลือก **Use balance** ในคอนโซล เมื่อเปิดใช้งาน Go จะเปลี่ยนไปใช้ยอดคงเหลือ Zen ของคุณหลังจากที่คุณใช้งานถึงขีดจำกัดแล้ว แทนที่จะบล็อกคำขอ
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Endpoints
|
## Endpoints
|
||||||
|
|
||||||
คุณยังสามารถเข้าถึงโมเดล Go ผ่าน API endpoints ต่อไปนี้
|
คุณสามารถเข้าถึงโมเดลของ Go ผ่าน API endpoints ต่อไปนี้ได้เช่นกัน
|
||||||
|
|
||||||
| Model | Model ID | Endpoint | AI SDK Package |
|
| Model | Model ID | Endpoint | AI SDK Package |
|
||||||
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
||||||
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
|
|
||||||
[รหัสโมเดล](/docs/config/#models) ในการกำหนดค่า OpenCode ของคุณใช้รูปแบบ `opencode-go/<model-id>` ตัวอย่างเช่น สำหรับ Kimi K2.5 คุณจะใช้ `opencode-go/kimi-k2.5` ในการกำหนดค่าของคุณ
|
[model id](/docs/config/#models) ใน OpenCode config ของคุณจะใช้รูปแบบ `opencode-go/<model-id>` ตัวอย่างเช่น สำหรับ Kimi K2.5 คุณจะใช้ `opencode-go/kimi-k2.5` ใน config ของคุณ
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ความเป็นส่วนตัว
|
## Privacy
|
||||||
|
|
||||||
แผนนี้ออกแบบมาสำหรับผู้ใช้ระดับนานาชาติเป็นหลัก โดยมีโมเดลโฮสต์อยู่ในสหรัฐอเมริกา สหภาพยุโรป และสิงคโปร์ เพื่อการเข้าถึงที่เสถียรทั่วโลก
|
แพ็กเกจนี้ออกแบบมาเพื่อผู้ใช้ในระดับสากลเป็นหลัก โดยมีโมเดลโฮสต์อยู่ในสหรัฐอเมริกา สหภาพยุโรป และสิงคโปร์ เพื่อการเข้าถึงทั่วโลกที่เสถียร
|
||||||
|
|
||||||
<a href={email}>ติดต่อเรา</a> หากคุณมีข้อสงสัยใดๆ
|
<a href={email}>ติดต่อเรา</a> หากคุณมีคำถามใดๆ
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## เป้าหมาย
|
## Goals
|
||||||
|
|
||||||
เราสร้าง OpenCode Go เพื่อ:
|
เราสร้าง OpenCode Go เพื่อ:
|
||||||
|
|
||||||
1. ทำให้การเขียนโค้ดด้วย AI **เข้าถึงได้** สำหรับผู้คนมากขึ้นด้วยการสมัครสมาชิกราคาประหยัด
|
1. ทำให้การเขียนโค้ดด้วย AI **เข้าถึงได้** สำหรับผู้คนจำนวนมากขึ้นด้วยการสมัครสมาชิกในราคาประหยัด
|
||||||
2. ให้การเข้าถึงโมเดลการเขียนโค้ดแบบเปิดที่ดีที่สุดอย่าง **น่าเชื่อถือ**
|
2. มอบการเข้าถึงโมเดลโอเพนซอร์สสำหรับการเขียนโค้ดที่ดีที่สุดได้อย่าง**เสถียร**
|
||||||
3. คัดสรรโมเดลที่ผ่านการ **ทดสอบและวัดประสิทธิภาพ** สำหรับการใช้งานตัวแทน (Agent) เขียนโค้ด
|
3. คัดสรรโมเดลที่ผ่าน**การทดสอบและวัดประสิทธิภาพ**สำหรับการใช้งาน coding agent แล้ว
|
||||||
4. **ไม่มีการผูกมัด** โดยอนุญาตให้คุณใช้ผู้ให้บริการรายอื่นกับ OpenCode ได้เช่นกัน
|
4. **ไม่ผูกขาดการใช้งาน (no lock-in)** โดยอนุญาตให้คุณใช้งานผู้ให้บริการรายอื่นๆ ร่วมกับ OpenCode ได้เช่นกัน
|
||||||
|
|
|
||||||
|
|
@ -7,48 +7,48 @@ import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
export const console = config.console
|
||||||
export const email = `mailto:${config.email}`
|
export const email = `mailto:${config.email}`
|
||||||
|
|
||||||
OpenCode Go, popüler açık kodlama modellerine güvenilir erişim sağlayan **aylık 10$** tutarında düşük maliyetli bir aboneliktir.
|
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$**.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
OpenCode Go şu anda beta aşamasındadır.
|
OpenCode Go şu anda beta olarak mevcut.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Go, OpenCode içindeki 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 buna ihtiyacınız yoktur.
|
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.
|
||||||
|
|
||||||
Kararlı küresel erişim için ABD, AB ve Singapur'da barındırılan modellerle, öncelikli olarak uluslararası kullanıcılar için tasarlanmıştır.
|
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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Arka Plan
|
## Arka Plan
|
||||||
|
|
||||||
Açık modeller gerçekten iyi hale geldi. Artık kodlama görevleri için tescilli modellere yakın performans sunuyorlar. Ve birçok sağlayıcı bunları rekabetçi bir şekilde sunabildiği için genellikle çok daha ucuzlar.
|
Açık modeller gerçekten çok iyi hale geldi. Artık kodlama görevleri için özel mülk modellere yakın bir performansa ulaşıyorlar. Ve birçok sağlayıcı onlara rekabetçi bir şekilde hizmet verebildiği için genellikle çok daha ucuzdurlar.
|
||||||
|
|
||||||
Ancak, bunlara güvenilir ve düşük gecikmeli erişim sağlamak zor olabilir. Sağlayıcılar kalite ve kullanılabilirlik açısından farklılık gösterir.
|
Ancak, bu modellere güvenilir, düşük gecikmeli erişim sağlamak zor olabilir. Sağlayıcılar kalite ve erişilebilirlik açısından farklılık gösterir.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
OpenCode ile iyi çalışan seçkin bir model ve sağlayıcı grubunu test ettik.
|
OpenCode ile iyi çalışan seçili bir model ve sağlayıcı grubunu test ettik.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Bunu düzeltmek için birkaç şey yaptık:
|
Bunu çözmek için birkaç şey yaptık:
|
||||||
|
|
||||||
1. Seçkin bir açık model grubunu test ettik ve bunları en iyi nasıl çalıştıracakları konusunda ekipleriyle görüştük.
|
1. Seçili bir grup açık modeli test ettik ve bu modelleri en iyi nasıl çalıştırabileceğimizi öğrenmek için ekipleriyle görüştük.
|
||||||
2. Daha sonra bunların doğru şekilde sunulduğundan emin olmak için birkaç sağlayıcıyla çalıştık.
|
2. Ardından, bunların doğru şekilde sunulduğundan emin olmak için birkaç sağlayıcıyla birlikte çalıştık.
|
||||||
3. Son olarak, model/sağlayıcı kombinasyonunu kıyasladık ve önermekten memnuniyet duyduğumuz bir liste oluşturduk.
|
3. Son olarak, model/sağlayıcı kombinasyonunu kıyasladık (benchmark) ve gönül rahatlığıyla önerebileceğimiz bir liste oluşturduk.
|
||||||
|
|
||||||
OpenCode Go, bu modellere **aylık 10$** karşılığında erişmenizi sağlar.
|
OpenCode Go, bu modellere **ilk ayınız için 5$**, ardından **aylık 10$** karşılığında erişmenizi sağlar.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Nasıl çalışır
|
## Nasıl çalışır?
|
||||||
|
|
||||||
OpenCode Go, OpenCode'daki diğer herhangi bir sağlayıcı gibi çalışır.
|
OpenCode Go, OpenCode'daki diğer sağlayıcılar gibi çalışır.
|
||||||
|
|
||||||
1. **<a href={console}>OpenCode Zen</a>**'de oturum açın, Go'ya abone olun ve API anahtarınızı kopyalayın.
|
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.
|
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 kullanılabilen modellerin listesini görmek için TUI'de `/models` komutunu çalıştırın.
|
3. Go üzerinden kullanabileceğiniz modellerin listesini görmek için TUI'de `/models` komutunu çalıştırın.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
Çalışma alanı başına yalnızca bir üye OpenCode Go'ya abone olabilir.
|
Her çalışma alanından yalnızca bir üye OpenCode Go'ya abone olabilir.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Mevcut model listesi şunları içerir:
|
Mevcut model listesi şunları içerir:
|
||||||
|
|
@ -56,34 +56,35 @@ Mevcut model listesi şunları içerir:
|
||||||
- **GLM-5**
|
- **GLM-5**
|
||||||
- **Kimi K2.5**
|
- **Kimi K2.5**
|
||||||
- **MiniMax M2.5**
|
- **MiniMax M2.5**
|
||||||
|
- **MiniMax M2.7**
|
||||||
|
|
||||||
Test ettikçe ve yenilerini ekledikçe model listesi değişebilir.
|
Test edip yenilerini ekledikçe model listesi değişebilir.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Kullanım sınırları
|
## Kullanım limitleri
|
||||||
|
|
||||||
OpenCode Go aşağıdaki sınırları içerir:
|
OpenCode Go aşağıdaki limitleri içerir:
|
||||||
|
|
||||||
- **5 saatlik sınır** — 12$ kullanım
|
- **5 saatlik limit** — 12$ kullanım
|
||||||
- **Haftalık sınır** — 30$ kullanım
|
- **Haftalık limit** — 30$ kullanım
|
||||||
- **Aylık sınır** — 60$ kullanım
|
- **Aylık limit** — 60$ kullanım
|
||||||
|
|
||||||
Sınırlar dolar değeri üzerinden tanımlanmıştır. Bu, gerçek istek sayınızın kullandığınız modele bağlı olduğu anlamına gelir. MiniMax M2.5 gibi daha ucuz modeller daha fazla isteğe izin verirken, GLM-5 gibi daha yüksek maliyetli modeller daha azına izin verir.
|
Limitler dolar değeri üzerinden belirlenmiştir. Bu, gerçek istek sayınızın kullandığınız modele bağlı olduğu anlamına gelir. MiniMax M2.5 gibi daha ucuz modeller daha fazla isteğe izin verirken, GLM-5 gibi yüksek maliyetli modeller daha azına izin verir.
|
||||||
|
|
||||||
Aşağıdaki tablo, tipik Go kullanım modellerine dayalı tahmini bir istek sayısı sunmaktadır:
|
Aşağıdaki tablo, tipik Go kullanım modellerine dayalı tahmini bir istek sayısı sunmaktadır:
|
||||||
|
|
||||||
| | GLM-5 | Kimi K2.5 | MiniMax M2.5 |
|
| | GLM-5 | Kimi K2.5 | MiniMax M2.7 | MiniMax M2.5 |
|
||||||
| ------------------- | ----- | --------- | ------------ |
|
| ------------------ | ----- | --------- | ------------ | ------------ |
|
||||||
| 5 saat başına istek | 1.150 | 1.850 | 30.000 |
|
| 5 saatte bir istek | 1.150 | 1.850 | 14.000 | 20.000 |
|
||||||
| haftalık istek | 2.880 | 4.630 | 75.000 |
|
| haftalık istek | 2.880 | 4.630 | 35.000 | 50.000 |
|
||||||
| aylık istek | 5.750 | 9.250 | 150.000 |
|
| aylık istek | 5.750 | 9.250 | 70.000 | 100.000 |
|
||||||
|
|
||||||
Tahminler gözlemlenen ortalama istek modellerine dayanmaktadır:
|
Tahminler, gözlemlenen ortalama istek modellerine dayanmaktadır:
|
||||||
|
|
||||||
- GLM-5 — İstek başına 700 girdi, 52.000 önbelleğe alınmış, 150 çıktı token'ı
|
- GLM-5 — İstek başına 700 girdi, 52.000 önbelleğe alınmış, 150 çıktı token'ı
|
||||||
- Kimi K2.5 — İstek başına 870 girdi, 55.000 önbelleğe alınmış, 200 çıktı token'ı
|
- Kimi K2.5 — İstek başına 870 girdi, 55.000 önbelleğe alınmış, 200 çıktı token'ı
|
||||||
- MiniMax M2.5 — İstek başına 300 girdi, 55.000 önbelleğe alınmış, 125 çıktı token'ı
|
- MiniMax M2.7/M2.5 — İstek başına 300 girdi, 55.000 önbelleğe alınmış, 125 çıktı token'ı
|
||||||
|
|
||||||
Mevcut kullanımınızı **<a href={console}>konsoldan</a>** takip edebilirsiniz.
|
Mevcut kullanımınızı **<a href={console}>konsoldan</a>** takip edebilirsiniz.
|
||||||
|
|
||||||
|
|
@ -91,45 +92,34 @@ Mevcut kullanımınızı **<a href={console}>konsoldan</a>** takip edebilirsiniz
|
||||||
Kullanım sınırına ulaşırsanız, ücretsiz modelleri kullanmaya devam edebilirsiniz.
|
Kullanım sınırına ulaşırsanız, ücretsiz modelleri kullanmaya devam edebilirsiniz.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Erken kullanım ve geri bildirimlerden öğrendiklerimize göre kullanım sınırları değişebilir.
|
Erken kullanımlardan ve geri bildirimlerden edindiğimiz deneyimlere bağlı olarak kullanım limitleri değişebilir.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Fiyatlandırma
|
### Limit dışı kullanım
|
||||||
|
|
||||||
OpenCode Go, **aylık 10$** tutarında bir abonelik planıdır. Aşağıda **1M token başına** fiyatlar yer almaktadır.
|
Eğer Zen bakiyenizde kredileriniz varsa, konsoldan **Bakiye kullan (Use balance)** seçeneğini etkinleştirebilirsiniz. Bu özellik etkinleştirildiğinde, kullanım limitlerinize ulaştıktan sonra Go, istekleri engellemek yerine Zen bakiyenizi kullanmaya devam edecektir.
|
||||||
|
|
||||||
| Model | Girdi | Çıktı | Önbelleğe Alınmış Okuma |
|
|
||||||
| ------------ | ----- | ----- | ----------------------- |
|
|
||||||
| GLM-5 | $1.00 | $3.20 | $0.20 |
|
|
||||||
| Kimi K2.5 | $0.60 | $3.00 | $0.10 |
|
|
||||||
| MiniMax M2.5 | $0.30 | $1.20 | $0.03 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Sınırların ötesinde kullanım
|
|
||||||
|
|
||||||
Zen bakiyenizde krediniz de varsa, konsoldaki **Bakiyeyi kullan** (Use balance) seçeneğini etkinleştirebilirsiniz. Etkinleştirildiğinde, kullanım sınırlarınıza ulaştıktan sonra Go, istekleri engellemek yerine Zen bakiyenize geri dönecektir.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Uç Noktalar
|
## Uç Noktalar
|
||||||
|
|
||||||
Go modellerine aşağıdaki API uç noktaları üzerinden de erişebilirsiniz.
|
Go modellerine aşağıdaki API uç noktaları aracılığıyla da erişebilirsiniz.
|
||||||
|
|
||||||
| Model | Model ID | Endpoint | AI SDK Paketi |
|
| Model | Model ID | Uç Nokta | AI SDK Paketi |
|
||||||
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
||||||
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
|
|
||||||
OpenCode yapılandırmanızdaki [model kimliği](/docs/config/#models), `opencode-go/<model-id>` biçimini kullanır. Örneğin, Kimi K2.5 için yapılandırmanızda `opencode-go/kimi-k2.5` kullanırsınız.
|
OpenCode yapılandırmanızdaki [model id](/docs/config/#models) formatı `opencode-go/<model-id>` şeklindedir. Örneğin, Kimi K2.5 için yapılandırmanızda `opencode-go/kimi-k2.5` kullanmalısınız.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Gizlilik
|
## Gizlilik
|
||||||
|
|
||||||
Plan öncelikli olarak uluslararası kullanıcılar için tasarlanmıştır; modeller kararlı küresel erişim için ABD, AB ve Singapur'da barındırılmaktadır.
|
Plan, 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.
|
||||||
|
|
||||||
Herhangi bir sorunuz varsa <a href={email}>bizimle iletişime geçin</a>.
|
Herhangi bir sorunuz varsa <a href={email}>bizimle iletişime geçin</a>.
|
||||||
|
|
||||||
|
|
@ -139,7 +129,7 @@ Herhangi bir sorunuz varsa <a href={email}>bizimle iletişime geçin</a>.
|
||||||
|
|
||||||
OpenCode Go'yu şu amaçlarla oluşturduk:
|
OpenCode Go'yu şu amaçlarla oluşturduk:
|
||||||
|
|
||||||
1. Düşük maliyetli bir abonelikle yapay zeka kodlamasını daha fazla insan için **erişilebilir** kılmak.
|
1. Düşük maliyetli bir abonelik ile yapay zeka destekli kodlamayı daha fazla kişi için **erişilebilir** kılmak.
|
||||||
2. En iyi açık kodlama modellerine **güvenilir** erişim sağlamak.
|
2. En iyi açık kodlama modellerine **güvenilir** erişim sağlamak.
|
||||||
3. Kodlama ajanı kullanımı için **test edilmiş ve kıyaslanmış** modelleri seçmek.
|
3. Kodlama aracısı (agent) kullanımı için **test edilmiş ve kıyaslanmış** modelleri bir araya getirmek.
|
||||||
4. OpenCode ile başka herhangi bir sağlayıcıyı kullanmanıza da izin vererek **kilitlenmeyi önlemek**.
|
4. OpenCode ile diğer sağlayıcıları da kullanmanıza olanak tanıyarak **kilitlenme (vendor lock-in) olmamasını** sağlamak.
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,8 @@ You can also access our models through the following API endpoints.
|
||||||
| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| MiMo V2 Flash Free | mimo-v2-flash-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| MiMo V2 Pro Free | mimo-v2-pro-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
| MiMo V2 Omni Free | mimo-v2-omni-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Nemotron 3 Super Free | nemotron-3-super-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
|
||||||
The [model id](/docs/config/#models) in your OpenCode config
|
The [model id](/docs/config/#models) in your OpenCode config
|
||||||
|
|
@ -120,7 +121,8 @@ We support a pay-as-you-go model. Below are the prices **per 1M tokens**.
|
||||||
| Model | Input | Output | Cached Read | Cached Write |
|
| Model | Input | Output | Cached Read | Cached Write |
|
||||||
| --------------------------------- | ------ | ------- | ----------- | ------------ |
|
| --------------------------------- | ------ | ------- | ----------- | ------------ |
|
||||||
| Big Pickle | Free | Free | Free | - |
|
| Big Pickle | Free | Free | Free | - |
|
||||||
| MiMo V2 Flash Free | Free | Free | Free | - |
|
| MiMo V2 Pro Free | Free | Free | Free | - |
|
||||||
|
| MiMo V2 Omni Free | Free | Free | Free | - |
|
||||||
| Nemotron 3 Super Free | Free | Free | Free | - |
|
| Nemotron 3 Super Free | Free | Free | Free | - |
|
||||||
| MiniMax M2.5 Free | Free | Free | Free | - |
|
| MiniMax M2.5 Free | Free | Free | Free | - |
|
||||||
| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 |
|
| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 |
|
||||||
|
|
@ -165,7 +167,8 @@ Credit card fees are passed along at cost (4.4% + $0.30 per transaction); we don
|
||||||
The free models:
|
The free models:
|
||||||
|
|
||||||
- MiniMax M2.5 Free is available on OpenCode for a limited time. The team is using this time to collect feedback and improve the model.
|
- MiniMax M2.5 Free is available on OpenCode for a limited time. The team is using this time to collect feedback and improve the model.
|
||||||
- MiMo V2 Flash Free is available on OpenCode for a limited time. The team is using this time to collect feedback and improve the model.
|
- MiMo V2 Pro Free is available on OpenCode for a limited time. The team is using this time to collect feedback and improve the model.
|
||||||
|
- MiMo V2 Omni Free is available on OpenCode for a limited time. The team is using this time to collect feedback and improve the model.
|
||||||
- Nemotron 3 Super Free is available on OpenCode for a limited time. The team is using this time to collect feedback and improve the model.
|
- Nemotron 3 Super Free is available on OpenCode for a limited time. The team is using this time to collect feedback and improve the model.
|
||||||
- Big Pickle is a stealth model that's free on OpenCode for a limited time. The team is using this time to collect feedback and improve the model.
|
- Big Pickle is a stealth model that's free on OpenCode for a limited time. The team is using this time to collect feedback and improve the model.
|
||||||
|
|
||||||
|
|
@ -212,7 +215,8 @@ All our models are hosted in the US. Our providers follow a zero-retention polic
|
||||||
|
|
||||||
- Big Pickle: During its free period, collected data may be used to improve the model.
|
- Big Pickle: During its free period, collected data may be used to improve the model.
|
||||||
- MiniMax M2.5 Free: During its free period, collected data may be used to improve the model.
|
- MiniMax M2.5 Free: During its free period, collected data may be used to improve the model.
|
||||||
- MiniMax M2.5 Free: During its free period, collected data may be used to improve the model.
|
- MiMo V2 Pro Free: During its free period, collected data may be used to improve the model.
|
||||||
|
- MiMo V2 Omni Free: During its free period, collected data may be used to improve the model.
|
||||||
- Nemotron 3 Super Free: During its free period, collected data may be used to improve the model.
|
- Nemotron 3 Super Free: During its free period, collected data may be used to improve the model.
|
||||||
- OpenAI APIs: Requests are retained for 30 days in accordance with [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data).
|
- OpenAI APIs: Requests are retained for 30 days in accordance with [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data).
|
||||||
- Anthropic APIs: Requests are retained for 30 days in accordance with [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage).
|
- Anthropic APIs: Requests are retained for 30 days in accordance with [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage).
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,13 @@ import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
export const console = config.console
|
||||||
export const email = `mailto:${config.email}`
|
export const email = `mailto:${config.email}`
|
||||||
|
|
||||||
OpenCode Go 是一项低成本的订阅服务(**$10/月**),为您提供对流行开源编程模型的可靠访问。
|
OpenCode Go 是一项低成本的订阅服务 —— **首月 5 美元**,之后 **每月 10 美元** —— 让你能够稳定地访问流行的开源编程模型。
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
OpenCode Go 目前处于测试阶段。
|
OpenCode Go 目前处于 beta 测试阶段。
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Go 的工作方式与 OpenCode 中的其他提供商一样。您订阅 OpenCode Go 并获取 API 密钥。这是**完全可选的**,您不需要它也能使用 OpenCode。
|
Go 的工作方式与 OpenCode 中的任何其他提供商(provider)一样。订阅 OpenCode Go 后你将获得 API 密钥。它是 **完全可选** 的,并非使用 OpenCode 所必需的条件。
|
||||||
|
|
||||||
它主要为国际用户设计,模型托管在美国、欧盟和新加坡,以确保稳定的全球访问。
|
它主要为国际用户设计,模型托管在美国、欧盟和新加坡,以确保稳定的全球访问。
|
||||||
|
|
||||||
|
|
@ -21,21 +21,21 @@ Go 的工作方式与 OpenCode 中的其他提供商一样。您订阅 OpenCode
|
||||||
|
|
||||||
## 背景
|
## 背景
|
||||||
|
|
||||||
开源模型已经变得非常出色。它们现在在编程任务上的表现接近专有模型。而且因为许多提供商可以竞争性地提供服务,它们通常要便宜得多。
|
开源模型现在变得非常强大。在编程任务中,它们的性能已接近专有模型。由于许多提供商都可以提供具有竞争力的服务,它们通常要便宜得多。
|
||||||
|
|
||||||
然而,获得可靠、低延迟的访问可能很困难。提供商的质量和可用性各不相同。
|
然而,获得可靠、低延迟的访问可能很困难。各提供商在质量和可用性方面参差不齐。
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
我们测试了一组精选的模型和提供商,它们与 OpenCode 配合良好。
|
我们测试了一组经过精选且与 OpenCode 配合良好的模型和提供商。
|
||||||
:::
|
:::
|
||||||
|
|
||||||
为了解决这个问题,我们做了一些事情:
|
为了解决这个问题,我们做了以下几件事:
|
||||||
|
|
||||||
1. 我们测试了一组精选的开源模型,并与他们的团队讨论了如何最好地运行它们。
|
1. 我们测试了一组精选的开源模型,并与他们的团队探讨了如何以最佳方式运行它们。
|
||||||
2. 然后,我们与几家提供商合作,确保这些模型得到正确的服务。
|
2. 随后我们与一些提供商合作,以确保正确提供这些服务。
|
||||||
3. 最后,我们对模型/提供商的组合进行了基准测试,并得出了一个我们乐于推荐的列表。
|
3. 最后,我们对模型和提供商的组合进行了基准测试(benchmark),得出了一份我们乐于推荐的列表。
|
||||||
|
|
||||||
OpenCode Go 让您可以以 **$10/月** 的价格访问这些模型。
|
OpenCode Go 让你能够访问这些模型,**首月只需 5 美元**,之后 **每月 10 美元**。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -43,21 +43,22 @@ OpenCode Go 让您可以以 **$10/月** 的价格访问这些模型。
|
||||||
|
|
||||||
OpenCode Go 的工作方式与 OpenCode 中的其他提供商一样。
|
OpenCode Go 的工作方式与 OpenCode 中的其他提供商一样。
|
||||||
|
|
||||||
1. 登录 **<a href={console}>OpenCode Zen</a>**,订阅 Go,并复制您的 API 密钥。
|
1. 登录 **<a href={console}>OpenCode Zen</a>**,订阅 Go,然后复制你的 API 密钥。
|
||||||
2. 在 TUI 中运行 `/connect` 命令,选择 `OpenCode Go`,然后粘贴您的 API 密钥。
|
2. 在 TUI 中运行 `/connect` 命令,选择 `OpenCode Go`,然后粘贴你的 API 密钥。
|
||||||
3. 在 TUI 中运行 `/models` 以查看通过 Go 可用的模型列表。
|
3. 在 TUI 中运行 `/models` 以查看通过 Go 可用的模型列表。
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
每个工作区只有一名成员可以订阅 OpenCode Go。
|
每个工作空间只能有一名成员订阅 OpenCode Go。
|
||||||
:::
|
:::
|
||||||
|
|
||||||
目前的模型列表包括:
|
当前支持的模型列表包括:
|
||||||
|
|
||||||
- **GLM-5**
|
- **GLM-5**
|
||||||
- **Kimi K2.5**
|
- **Kimi K2.5**
|
||||||
- **MiniMax M2.5**
|
- **MiniMax M2.5**
|
||||||
|
- **MiniMax M2.7**
|
||||||
|
|
||||||
随着我们测试和添加新模型,模型列表可能会发生变化。
|
随着我们进行测试和添加新模型,该列表可能会发生变化。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -65,69 +66,58 @@ OpenCode Go 的工作方式与 OpenCode 中的其他提供商一样。
|
||||||
|
|
||||||
OpenCode Go 包含以下限制:
|
OpenCode Go 包含以下限制:
|
||||||
|
|
||||||
- **5 小时限制** — $12 的使用量
|
- **5 小时限制** — 12 美元使用额度
|
||||||
- **每周限制** — $30 的使用量
|
- **每周限制** — 30 美元使用额度
|
||||||
- **每月限制** — $60 的使用量
|
- **每月限制** — 60 美元使用额度
|
||||||
|
|
||||||
限制是以美元价值定义的。这意味着您的实际请求数量取决于您使用的模型。像 MiniMax M2.5 这样更便宜的模型允许更多的请求,而像 GLM-5 这样成本更高的模型允许的请求较少。
|
限制以美元价值定义。这意味着你的实际请求数取决于你所使用的模型。较便宜的模型(如 MiniMax M2.5)允许更多请求,而较高成本的模型(如 GLM-5)允许较少请求。
|
||||||
|
|
||||||
下表提供了基于典型 Go 使用模式的估计请求数:
|
下表提供了基于典型 Go 使用模式的预估请求数:
|
||||||
|
|
||||||
| | GLM-5 | Kimi K2.5 | MiniMax M2.5 |
|
| | GLM-5 | Kimi K2.5 | MiniMax M2.7 | MiniMax M2.5 |
|
||||||
| --------------- | ----- | --------- | ------------ |
|
| --------------- | ----- | --------- | ------------ | ------------ |
|
||||||
| 每 5 小时请求数 | 1,150 | 1,850 | 30,000 |
|
| 每 5 小时请求数 | 1,150 | 1,850 | 14,000 | 20,000 |
|
||||||
| 每周请求数 | 2,880 | 4,630 | 75,000 |
|
| 每周请求数 | 2,880 | 4,630 | 35,000 | 50,000 |
|
||||||
| 每月请求数 | 5,750 | 9,250 | 150,000 |
|
| 每月请求数 | 5,750 | 9,250 | 70,000 | 100,000 |
|
||||||
|
|
||||||
估计值基于观察到的平均请求模式:
|
预估值基于观察到的平均请求模式:
|
||||||
|
|
||||||
- GLM-5 — 每次请求 700 输入,52,000 缓存,150 输出 token
|
- GLM-5 — 每次请求 700 个输入 token,52,000 个缓存 token,150 个输出 token
|
||||||
- Kimi K2.5 — 每次请求 870 输入,55,000 缓存,200 输出 token
|
- Kimi K2.5 — 每次请求 870 个输入 token,55,000 个缓存 token,200 个输出 token
|
||||||
- MiniMax M2.5 — 每次请求 300 输入,55,000 缓存,125 输出 token
|
- MiniMax M2.7/M2.5 — 每次请求 300 个输入 token,55,000 个缓存 token,125 个输出 token
|
||||||
|
|
||||||
您可以在 **<a href={console}>console</a>** 中跟踪当前的用量。
|
你可以在 **<a href={console}>控制台</a>** 中跟踪你当前的使用情况。
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
如果您达到使用限制,您可以继续使用免费模型。
|
如果你达到了使用限制,你可以继续使用免费模型。
|
||||||
:::
|
:::
|
||||||
|
|
||||||
随着我们从早期使用和反馈中学习,使用限制可能会发生变化。
|
使用限制可能会随着我们从早期使用和反馈中学习而发生变化。
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 定价
|
|
||||||
|
|
||||||
OpenCode Go 是一个 **$10/月** 的订阅计划。以下是**每 1M token** 的价格。
|
|
||||||
|
|
||||||
| Model | Input | Output | Cached Read |
|
|
||||||
| ------------ | ----- | ------ | ----------- |
|
|
||||||
| GLM-5 | $1.00 | $3.20 | $0.20 |
|
|
||||||
| Kimi K2.5 | $0.60 | $3.00 | $0.10 |
|
|
||||||
| MiniMax M2.5 | $0.30 | $1.20 | $0.03 |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 超出限制的使用
|
### 超出限制的使用
|
||||||
|
|
||||||
如果您的 Zen 余额中还有信用点数,您可以在控制台中启用 **Use balance**(使用余额)选项。启用后,当您达到使用限制时,Go 将回退到您的 Zen 余额,而不是阻止请求。
|
如果你的 Zen 余额中还有积分,可以在控制台中启用 **使用余额(Use balance)** 选项。启用后,当你达到使用限制时,Go 会回退使用你的 Zen 余额,而不是拦截请求。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 端点
|
## API 端点
|
||||||
|
|
||||||
您也可以通过以下 API 端点访问 Go 模型。
|
你也可以通过以下 API 端点访问 Go 模型。
|
||||||
|
|
||||||
| Model | Model ID | Endpoint | AI SDK Package |
|
| 模型 | 模型 ID | 端点 | AI SDK 包 |
|
||||||
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
||||||
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
|
|
||||||
OpenCode 配置中的 [model id](/docs/config/#models) 使用 `opencode-go/<model-id>` 格式。例如,对于 Kimi K2.5,您将在配置中使用 `opencode-go/kimi-k2.5`。
|
你 OpenCode 配置中的 [模型 ID](/docs/config/#models) 使用 `opencode-go/<model-id>` 格式。例如,对于 Kimi K2.5,你将在配置中使用 `opencode-go/kimi-k2.5`。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 隐私
|
## 隐私保护
|
||||||
|
|
||||||
该计划主要为国际用户设计,模型托管在美国、欧盟和新加坡,以确保稳定的全球访问。
|
该计划主要为国际用户设计,模型托管在美国、欧盟和新加坡,以确保稳定的全球访问。
|
||||||
|
|
||||||
|
|
@ -137,9 +127,9 @@ OpenCode 配置中的 [model id](/docs/config/#models) 使用 `opencode-go/<mode
|
||||||
|
|
||||||
## 目标
|
## 目标
|
||||||
|
|
||||||
我们要创建 OpenCode Go 以:
|
我们创建 OpenCode Go 的目的是:
|
||||||
|
|
||||||
1. 通过低成本订阅让更多人**获得** AI 编程能力。
|
1. 通过低成本订阅让更多人能够 **无门槛地** 使用 AI 编程。
|
||||||
2. 提供对最佳开源编程模型的**可靠**访问。
|
2. 为最佳开源编程模型提供 **可靠的** 访问。
|
||||||
3. 策划经过**测试和基准测试**的、适合编程代理使用的模型。
|
3. 精选经过 **测试和基准评估**,适合编程 Agent 使用的模型。
|
||||||
4. **无锁定**,允许您在 OpenCode 中使用任何其他提供商。
|
4. **无锁定(no lock-in)**,允许你与 OpenCode 一起使用任何其他提供商。
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,29 @@
|
||||||
---
|
---
|
||||||
title: Go
|
title: Go
|
||||||
description: 針對開放原始碼程式設計模型的低成本訂閱服務。
|
description: 專為開源寫程式模型提供的低成本訂閱服務。
|
||||||
---
|
---
|
||||||
|
|
||||||
import config from "../../../../config.mjs"
|
import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
export const console = config.console
|
||||||
export const email = `mailto:${config.email}`
|
export const email = `mailto:${config.email}`
|
||||||
|
|
||||||
OpenCode Go 是一項低成本的 **每月 10 美元** 訂閱服務,讓您可以穩定存取熱門的開放原始碼程式設計模型。
|
OpenCode Go 是一項低成本的訂閱服務——**首月 $5 美元**,之後**每月 $10 美元**——讓您能穩定使用受歡迎的開源寫程式模型。
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
OpenCode Go 目前處於測試階段 (Beta)。
|
OpenCode Go 目前處於 beta 測試階段。
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Go 的運作方式就像 OpenCode 中的任何其他供應商一樣。您訂閱 OpenCode Go 並取得您的 API key。這是**完全選用**的,您不需要使用它也能使用 OpenCode。
|
Go 的運作方式與 OpenCode 中的任何其他供應商相同。您訂閱 OpenCode Go 並取得您的 API key。這是**完全可選的**,您不需要使用它也能使用 OpenCode。
|
||||||
|
|
||||||
主要是為國際使用者設計,模型託管在美國、歐盟和新加坡,以提供穩定的全球存取。
|
它主要為國際使用者設計,模型託管於美國、歐盟和新加坡,以提供全球穩定的存取。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 背景
|
## 背景
|
||||||
|
|
||||||
開放模型已經變得非常優秀。它們現在在程式設計任務上的表現已接近專有模型。而且因為許多供應商都能以具競爭力的方式提供服務,它們通常便宜得多。
|
開源模型已經變得非常強大。它們在寫程式任務上的表現,現在已經接近專有模型。而且因為有許多供應商競爭提供服務,它們通常便宜得多。
|
||||||
|
|
||||||
然而,要獲得穩定且低延遲的存取可能會很困難。供應商的品質和可用性各不相同。
|
然而,要獲得穩定、低延遲的存取可能很困難。各家供應商的品質和可用性不一。
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
我們測試了一組精選的模型和供應商,它們與 OpenCode 搭配運作良好。
|
我們測試了一組精選的模型和供應商,它們與 OpenCode 搭配運作良好。
|
||||||
|
|
@ -31,21 +31,21 @@ Go 的運作方式就像 OpenCode 中的任何其他供應商一樣。您訂閱
|
||||||
|
|
||||||
為了解決這個問題,我們做了幾件事:
|
為了解決這個問題,我們做了幾件事:
|
||||||
|
|
||||||
1. 我們測試了一組精選的開放模型,並與他們的團隊討論如何最好地運行它們。
|
1. 我們測試了一組精選的開源模型,並與它們的團隊討論如何最佳化運行。
|
||||||
2. 接著我們與幾家供應商合作,確保這些模型能正確地提供服務。
|
2. 接著我們與幾家供應商合作,確保這些模型被正確地提供服務。
|
||||||
3. 最後,我們對模型/供應商的組合進行基準測試,並提出了一份我們覺得值得推薦的清單。
|
3. 最後,我們對模型與供應商的組合進行了基準測試,並整理出一份我們樂於推薦的清單。
|
||||||
|
|
||||||
OpenCode Go 讓您能以 **每月 10 美元** 的價格存取這些模型。
|
OpenCode Go 讓您可以存取這些模型,**首月只需 $5 美元**,之後**每月 $10 美元**。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 運作方式
|
## 運作方式
|
||||||
|
|
||||||
OpenCode Go 的運作方式就像 OpenCode 中的任何其他供應商一樣。
|
OpenCode Go 的運作方式與 OpenCode 中的任何其他供應商相同。
|
||||||
|
|
||||||
1. 您登入 **<a href={console}>OpenCode Zen</a>**,訂閱 Go,並複製您的 API key。
|
1. 您登入 **<a href={console}>OpenCode Zen</a>**,訂閱 Go,然後複製您的 API key。
|
||||||
2. 您在 TUI 中執行 `/connect` 指令,選擇 `OpenCode Go`,並貼上您的 API key。
|
2. 您在 TUI 中執行 `/connect` 命令,選擇 `OpenCode Go`,然後貼上您的 API key。
|
||||||
3. 在 TUI 中執行 `/models` 以查看透過 Go 可用的模型清單。
|
3. 在 TUI 中執行 `/models` 即可查看透過 Go 可用的模型清單。
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
每個工作區只能有一位成員訂閱 OpenCode Go。
|
每個工作區只能有一位成員訂閱 OpenCode Go。
|
||||||
|
|
@ -56,8 +56,9 @@ OpenCode Go 的運作方式就像 OpenCode 中的任何其他供應商一樣。
|
||||||
- **GLM-5**
|
- **GLM-5**
|
||||||
- **Kimi K2.5**
|
- **Kimi K2.5**
|
||||||
- **MiniMax M2.5**
|
- **MiniMax M2.5**
|
||||||
|
- **MiniMax M2.7**
|
||||||
|
|
||||||
模型清單可能會隨著我們測試和新增模型而變動。
|
隨著我們測試並加入新模型,模型清單可能會有所變動。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -65,51 +66,39 @@ OpenCode Go 的運作方式就像 OpenCode 中的任何其他供應商一樣。
|
||||||
|
|
||||||
OpenCode Go 包含以下限制:
|
OpenCode Go 包含以下限制:
|
||||||
|
|
||||||
- **5 小時限制** — 12 美元的使用量
|
- **5 小時限制** — $12 美元的使用量
|
||||||
- **每週限制** — 30 美元的使用量
|
- **每週限制** — $30 美元的使用量
|
||||||
- **每月限制** — 60 美元的使用量
|
- **每月限制** — $60 美元的使用量
|
||||||
|
|
||||||
限制是以美元價值定義的。這意味著您的實際請求次數取決於您使用的模型。較便宜的模型(如 MiniMax M2.5)允許更多請求,而較高成本的模型(如 GLM-5)允許較少請求。
|
限制是以美元價值來定義。這意味著您的實際請求次數取決於您使用的模型。像 MiniMax M2.5 這樣較便宜的模型允許更多的請求次數,而像 GLM-5 這樣成本較高的模型則允許較少次數。
|
||||||
|
|
||||||
下表根據典型的 Go 使用模式提供估計的請求次數:
|
下表提供了基於典型 Go 使用模式的預估請求次數:
|
||||||
|
|
||||||
| | GLM-5 | Kimi K2.5 | MiniMax M2.5 |
|
| | GLM-5 | Kimi K2.5 | MiniMax M2.7 | MiniMax M2.5 |
|
||||||
| --------------- | ----- | --------- | ------------ |
|
| --------------- | ----- | --------- | ------------ | ------------ |
|
||||||
| 每 5 小時請求數 | 1,150 | 1,850 | 30,000 |
|
| 每 5 小時請求數 | 1,150 | 1,850 | 14,000 | 20,000 |
|
||||||
| 每週請求數 | 2,880 | 4,630 | 75,000 |
|
| 每週請求數 | 2,880 | 4,630 | 35,000 | 50,000 |
|
||||||
| 每月請求數 | 5,750 | 9,250 | 150,000 |
|
| 每月請求數 | 5,750 | 9,250 | 70,000 | 100,000 |
|
||||||
|
|
||||||
估計值是根據觀察到的平均請求模式:
|
預估值是基於觀察到的平均請求模式:
|
||||||
|
|
||||||
- GLM-5 — 700 輸入, 52,000 快取, 150 輸出 token (每個請求)
|
- GLM-5 — 每次請求 700 個輸入 token、52,000 個快取 token、150 個輸出 token
|
||||||
- Kimi K2.5 — 870 輸入, 55,000 快取, 200 輸出 token (每個請求)
|
- Kimi K2.5 — 每次請求 870 個輸入 token、55,000 個快取 token、200 個輸出 token
|
||||||
- MiniMax M2.5 — 300 輸入, 55,000 快取, 125 輸出 token (每個請求)
|
- MiniMax M2.7/M2.5 — 每次請求 300 個輸入 token、55,000 個快取 token、125 個輸出 token
|
||||||
|
|
||||||
您可以在 **<a href={console}>console</a>** 中追蹤目前的使用量。
|
您可以在 **<a href={console}>console</a>** 中追蹤您目前的使用量。
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
如果您達到使用限制,您可以繼續使用免費模型。
|
如果您達到了使用限制,您可以繼續使用免費模型。
|
||||||
:::
|
:::
|
||||||
|
|
||||||
使用限制可能會隨著我們從早期使用和回饋中學習而變動。
|
使用限制可能會隨著我們從早期使用情況和回饋中學習而有所調整。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 定價
|
### 超出限制的使用量
|
||||||
|
|
||||||
OpenCode Go 是一個 **每月 10 美元** 的訂閱方案。以下是 **每 100 萬 token** 的價格。
|
如果您在您的 Zen 餘額中也有額度,您可以在 console 中啟用 **Use balance** 選項。啟用後,當您達到使用限制時,Go 將會改用您的 Zen 餘額,而不是阻擋請求。
|
||||||
|
|
||||||
| 模型 | 輸入 | 輸出 | 快取讀取 |
|
|
||||||
| ------------ | ----- | ----- | -------- |
|
|
||||||
| GLM-5 | $1.00 | $3.20 | $0.20 |
|
|
||||||
| Kimi K2.5 | $0.60 | $3.00 | $0.10 |
|
|
||||||
| MiniMax M2.5 | $0.30 | $1.20 | $0.03 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 超出限制的使用
|
|
||||||
|
|
||||||
如果您的 Zen 餘額中也有點數,您可以在 console 中啟用 **Use balance** 選項。啟用後,當您達到使用限制時,Go 將會改用您的 Zen 餘額,而不是封鎖請求。
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -117,29 +106,30 @@ OpenCode Go 是一個 **每月 10 美元** 的訂閱方案。以下是 **每 100
|
||||||
|
|
||||||
您也可以透過以下 API 端點存取 Go 模型。
|
您也可以透過以下 API 端點存取 Go 模型。
|
||||||
|
|
||||||
| 模型 | Model ID | 端點 | AI SDK 套件 |
|
| 模型 | 模型 ID | 端點 | AI SDK 套件 |
|
||||||
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
| ------------ | ------------ | ------------------------------------------------ | --------------------------- |
|
||||||
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||||
|
| MiniMax M2.7 | minimax-m2.7 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
|
||||||
|
|
||||||
您 OpenCode 設定中的 [model id](/docs/config/#models) 使用 `opencode-go/<model-id>` 格式。例如,對於 Kimi K2.5,您會在設定中使用 `opencode-go/kimi-k2.5`。
|
您的 OpenCode 設定中的 [模型 ID](/docs/config/#models) 使用 `opencode-go/<model-id>` 的格式。例如,對於 Kimi K2.5,您應該在您的設定中使用 `opencode-go/kimi-k2.5`。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 隱私權
|
## 隱私權
|
||||||
|
|
||||||
此方案主要是為國際使用者設計,模型託管在美國、歐盟和新加坡,以提供穩定的全球存取。
|
此方案主要為國際使用者設計,模型託管於美國、歐盟和新加坡,以提供全球穩定的存取。
|
||||||
|
|
||||||
如果您有任何問題,請 <a href={email}>聯絡我們</a>。
|
如果您有任何問題,請<a href={email}>與我們聯絡</a>。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 目標
|
## 目標
|
||||||
|
|
||||||
我們建立 OpenCode Go 是為了:
|
我們建立 OpenCode Go 的目的是:
|
||||||
|
|
||||||
1. 透過低成本訂閱,讓更多人能 **輕易取得** AI 程式設計資源。
|
1. 透過低成本的訂閱服務,讓更多人能**輕鬆獲得** AI 寫程式的協助。
|
||||||
2. 提供對最佳開放程式設計模型的 **可靠** 存取。
|
2. 提供**穩定可靠**的途徑來存取最好的開源寫程式模型。
|
||||||
3. 策劃經過 **測試和基準測試** 的模型,以供程式設計代理使用。
|
3. 精選經過**測試與效能評估**、適合寫程式代理使用的模型。
|
||||||
4. **沒有鎖定**,允許您在 OpenCode 中同時使用任何其他供應商。
|
4. 允許您在 OpenCode 中同時使用任何其他供應商,確保**不被單一廠商綁定**。
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue