mirror of
https://github.com/anomalyco/opencode.git
synced 2026-09-03 07:26:20 +00:00
Compare commits
7
Commits
attach-output
..
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b578b7261f | ||
|
|
bbe4c952d7 | ||
|
|
3a9d4e78b6 | ||
|
|
8d1f8916d3 | ||
|
|
05028334b2 | ||
|
|
b04697366f | ||
|
|
4eb29a64f0 |
@@ -29,7 +29,7 @@
|
||||
},
|
||||
"packages/app": {
|
||||
"name": "@opencode-ai/app",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@corvu/drawer": "catalog:",
|
||||
"@dnd-kit/abstract": "0.5.0",
|
||||
@@ -96,7 +96,7 @@
|
||||
},
|
||||
"packages/cli": {
|
||||
"name": "@opencode-ai/cli",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"bin": {
|
||||
"lildax": "./bin/lildax.cjs",
|
||||
},
|
||||
@@ -144,7 +144,7 @@
|
||||
},
|
||||
"packages/codemode": {
|
||||
"name": "@opencode-ai/codemode",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"acorn": "8.15.0",
|
||||
"effect": "catalog:",
|
||||
@@ -158,7 +158,7 @@
|
||||
},
|
||||
"packages/console/app": {
|
||||
"name": "@opencode-ai/console-app",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@cloudflare/vite-plugin": "1.15.2",
|
||||
"@ibm/plex": "6.4.1",
|
||||
@@ -195,7 +195,7 @@
|
||||
},
|
||||
"packages/console/core": {
|
||||
"name": "@opencode-ai/console-core",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-sts": "3.782.0",
|
||||
"@jsx-email/render": "1.1.1",
|
||||
@@ -222,7 +222,7 @@
|
||||
},
|
||||
"packages/console/function": {
|
||||
"name": "@opencode-ai/console-function",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "3.0.82",
|
||||
"@ai-sdk/openai": "3.0.48",
|
||||
@@ -245,7 +245,7 @@
|
||||
},
|
||||
"packages/console/mail": {
|
||||
"name": "@opencode-ai/console-mail",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@jsx-email/all": "2.2.3",
|
||||
"@jsx-email/cli": "1.4.3",
|
||||
@@ -269,7 +269,7 @@
|
||||
},
|
||||
"packages/console/support": {
|
||||
"name": "@opencode-ai/console-support",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@cloudflare/vite-plugin": "1.15.2",
|
||||
"@opencode-ai/console-core": "workspace:*",
|
||||
@@ -289,7 +289,7 @@
|
||||
},
|
||||
"packages/core": {
|
||||
"name": "@opencode-ai/core",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode",
|
||||
},
|
||||
@@ -341,7 +341,7 @@
|
||||
"drizzle-orm": "catalog:",
|
||||
"effect": "catalog:",
|
||||
"fuzzysort": "3.1.0",
|
||||
"gitlab-ai-provider": "6.12.1",
|
||||
"gitlab-ai-provider": "6.13.0",
|
||||
"glob": "13.0.5",
|
||||
"google-auth-library": "10.5.0",
|
||||
"gray-matter": "4.0.3",
|
||||
@@ -383,7 +383,7 @@
|
||||
},
|
||||
"packages/desktop": {
|
||||
"name": "@opencode-ai/desktop",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@zip.js/zip.js": "2.7.62",
|
||||
"drizzle-orm": "catalog:",
|
||||
@@ -437,7 +437,7 @@
|
||||
},
|
||||
"packages/effect-drizzle-sqlite": {
|
||||
"name": "@opencode-ai/effect-drizzle-sqlite",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"drizzle-orm": "catalog:",
|
||||
"effect": "catalog:",
|
||||
@@ -451,7 +451,7 @@
|
||||
},
|
||||
"packages/effect-sqlite-node": {
|
||||
"name": "@opencode-ai/effect-sqlite-node",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"effect": "catalog:",
|
||||
},
|
||||
@@ -463,7 +463,7 @@
|
||||
},
|
||||
"packages/enterprise": {
|
||||
"name": "@opencode-ai/enterprise",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@hono/standard-validator": "catalog:",
|
||||
"@opencode-ai/core": "workspace:*",
|
||||
@@ -495,7 +495,7 @@
|
||||
},
|
||||
"packages/function": {
|
||||
"name": "@opencode-ai/function",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@octokit/auth-app": "8.0.1",
|
||||
"@octokit/rest": "catalog:",
|
||||
@@ -511,7 +511,7 @@
|
||||
},
|
||||
"packages/http-recorder": {
|
||||
"name": "@opencode-ai/http-recorder",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@effect/platform-node": "4.0.0-beta.83",
|
||||
"@effect/platform-node-shared": "4.0.0-beta.83",
|
||||
@@ -542,7 +542,7 @@
|
||||
},
|
||||
"packages/llm": {
|
||||
"name": "@opencode-ai/llm",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@opencode-ai/schema": "workspace:*",
|
||||
"@smithy/eventstream-codec": "4.2.14",
|
||||
@@ -561,7 +561,7 @@
|
||||
},
|
||||
"packages/opencode": {
|
||||
"name": "opencode",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode",
|
||||
},
|
||||
@@ -634,7 +634,7 @@
|
||||
"drizzle-orm": "catalog:",
|
||||
"effect": "catalog:",
|
||||
"fuzzysort": "3.1.0",
|
||||
"gitlab-ai-provider": "6.12.1",
|
||||
"gitlab-ai-provider": "6.13.0",
|
||||
"glob": "13.0.5",
|
||||
"google-auth-library": "10.5.0",
|
||||
"gray-matter": "4.0.3",
|
||||
@@ -692,7 +692,7 @@
|
||||
},
|
||||
"packages/plugin": {
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@ai-sdk/provider": "3.0.8",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
@@ -768,7 +768,7 @@
|
||||
},
|
||||
"packages/sdk/js": {
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"cross-spawn": "catalog:",
|
||||
},
|
||||
@@ -783,7 +783,7 @@
|
||||
},
|
||||
"packages/server": {
|
||||
"name": "@opencode-ai/server",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@opencode-ai/core": "workspace:*",
|
||||
"@opencode-ai/protocol": "workspace:*",
|
||||
@@ -798,7 +798,7 @@
|
||||
},
|
||||
"packages/session-ui": {
|
||||
"name": "@opencode-ai/session-ui",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@kobalte/core": "catalog:",
|
||||
"@opencode-ai/client": "file:../app/vendor/opencode-ai-client-1.17.13-v2.tgz",
|
||||
@@ -838,7 +838,7 @@
|
||||
},
|
||||
"packages/slack": {
|
||||
"name": "@opencode-ai/slack",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@slack/bolt": "^3.17.1",
|
||||
@@ -851,7 +851,7 @@
|
||||
},
|
||||
"packages/stats/app": {
|
||||
"name": "@opencode-ai/stats-app",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@ibm/plex": "6.4.1",
|
||||
"@kobalte/core": "catalog:",
|
||||
@@ -878,7 +878,7 @@
|
||||
},
|
||||
"packages/stats/core": {
|
||||
"name": "@opencode-ai/stats-core",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-athena": "3.933.0",
|
||||
"@planetscale/database": "1.19.0",
|
||||
@@ -897,7 +897,7 @@
|
||||
},
|
||||
"packages/stats/server": {
|
||||
"name": "@opencode-ai/stats-server",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-firehose": "3.933.0",
|
||||
"@effect/platform-node": "catalog:",
|
||||
@@ -939,7 +939,7 @@
|
||||
},
|
||||
"packages/tui": {
|
||||
"name": "@opencode-ai/tui",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@opencode-ai/core": "workspace:*",
|
||||
"@opencode-ai/plugin": "workspace:*",
|
||||
@@ -966,7 +966,7 @@
|
||||
},
|
||||
"packages/ui": {
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@kobalte/core": "catalog:",
|
||||
"@pierre/diffs": "catalog:",
|
||||
@@ -1017,7 +1017,7 @@
|
||||
},
|
||||
"packages/web": {
|
||||
"name": "@opencode-ai/web",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@astrojs/cloudflare": "12.6.3",
|
||||
"@astrojs/markdown-remark": "6.3.1",
|
||||
@@ -3845,7 +3845,7 @@
|
||||
|
||||
"github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="],
|
||||
|
||||
"gitlab-ai-provider": ["gitlab-ai-provider@6.12.1", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=3.0.0", "@ai-sdk/provider-utils": ">=4.0.0" } }, "sha512-Qn5iHqvjG8yktI5MWaUgdRR94l7O4WtYW0CAbhsCh1Tj0Fei/DeprOYPVyf4Nht1Ix6U2PXSYM32QOHI6Z2TDw=="],
|
||||
"gitlab-ai-provider": ["gitlab-ai-provider@6.13.0", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=3.0.0", "@ai-sdk/provider-utils": ">=4.0.0" } }, "sha512-JDZhNjvoiB7xBfesNegXNDg6ItKf9M2l8/DifuIyuvYmGgaZnDDbl89QrOKSoIzAOpo/+3Om0qviBPm84nGEbg=="],
|
||||
|
||||
"glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="],
|
||||
|
||||
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"nodeModules": {
|
||||
"x86_64-linux": "sha256-SVvFPO+KuS67+6XGPhaB3cIuc3XUyM0XVccy5v8afS4=",
|
||||
"aarch64-linux": "sha256-HJRrSu5u0TEg214d2RAbM1C+nmrxvIR/d7JlSBOGb9I=",
|
||||
"aarch64-darwin": "sha256-ytmHSdC0PVGAJSbpt/+YwL5ySF3w6r/9uZpZACPppkI=",
|
||||
"x86_64-darwin": "sha256-ma7K4K+xn7Jz3+YPA/n8ly1o308UNoM/DO9Z8yZSAKE="
|
||||
"x86_64-linux": "sha256-2kzFIn42mD7ZDu/+6lWctqjZ/lIVZZfjZhmF/ymhF54=",
|
||||
"aarch64-linux": "sha256-4HlReGD3gYfyyfnY/FQ46Ov+g3ZGV3sBYQ9p1bS9YAY=",
|
||||
"aarch64-darwin": "sha256-dkfCoH/sW9XBPZ7XhnUoE54TY1lcfNvZ5wQQLr7gKiQ=",
|
||||
"x86_64-darwin": "sha256-32t1JEcibZ4OrornIgfWOGQA87FOXjrxrxlDrflh7Ss="
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/app",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
|
||||
@@ -31,7 +31,10 @@ export function OpenInAppV2(props: { directory: () => string }) {
|
||||
disabled={state.opening()}
|
||||
aria-label={language.t("session.header.open.ariaLabel", { app: state.current().label })}
|
||||
>
|
||||
<Show when={state.opening()} fallback={<AppIcon id={state.current().icon} class="size-[18px]" />}>
|
||||
<Show
|
||||
when={state.opening()}
|
||||
fallback={<AppIcon id={state.current().icon} style={{ width: "20px", height: "20px" }} />}
|
||||
>
|
||||
<Spinner class="size-3.5" />
|
||||
</Show>
|
||||
</SplitButtonV2Action>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/cli",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/codemode",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"description": "Effect-native confined code execution over schema-described tools",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-app",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/console-core",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-function",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-mail",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"dependencies": {
|
||||
"@jsx-email/all": "2.2.3",
|
||||
"@jsx-email/cli": "1.4.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-support",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"name": "@opencode-ai/core",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
@@ -108,7 +108,7 @@
|
||||
"drizzle-orm": "catalog:",
|
||||
"effect": "catalog:",
|
||||
"fuzzysort": "3.1.0",
|
||||
"gitlab-ai-provider": "6.12.1",
|
||||
"gitlab-ai-provider": "6.13.0",
|
||||
"glob": "13.0.5",
|
||||
"google-auth-library": "10.5.0",
|
||||
"gray-matter": "4.0.3",
|
||||
|
||||
@@ -108,15 +108,20 @@ export const Info = Schema.Struct({
|
||||
headerTimeout: Schema.optional(
|
||||
Schema.Union([PositiveInt, Schema.Literal(false)]).annotate({
|
||||
description:
|
||||
"Timeout in milliseconds to wait for response headers. Provider integrations may set defaults. Set to false to disable timeout.",
|
||||
"Timeout in milliseconds to wait for response headers (default: 300000). Set to false to disable timeout.",
|
||||
}),
|
||||
).annotate({
|
||||
description:
|
||||
"Timeout in milliseconds to wait for response headers. Provider integrations may set defaults. Set to false to disable timeout.",
|
||||
"Timeout in milliseconds to wait for response headers (default: 300000). Set to false to disable timeout.",
|
||||
}),
|
||||
chunkTimeout: Schema.optional(PositiveInt).annotate({
|
||||
chunkTimeout: Schema.optional(
|
||||
Schema.Union([PositiveInt, Schema.Literal(false)]).annotate({
|
||||
description:
|
||||
"Timeout in milliseconds between streamed SSE chunks for this provider (default: 300000). If no chunk arrives within this window, the request is aborted. Set to false to disable timeout.",
|
||||
}),
|
||||
).annotate({
|
||||
description:
|
||||
"Timeout in milliseconds between streamed SSE chunks for this provider. If no chunk arrives within this window, the request is aborted.",
|
||||
"Timeout in milliseconds between streamed SSE chunks for this provider (default: 300000). If no chunk arrives within this window, the request is aborted. Set to false to disable timeout.",
|
||||
}),
|
||||
}),
|
||||
[Schema.Record(Schema.String, Schema.Any)],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@opencode-ai/desktop",
|
||||
"private": true,
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"homepage": "https://opencode.ai",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"name": "@opencode-ai/effect-drizzle-sqlite",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"name": "@opencode-ai/effect-sqlite-node",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/enterprise",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/function",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"name": "@opencode-ai/http-recorder",
|
||||
"description": "Record and replay Effect HTTP client traffic with deterministic cassettes",
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"name": "@opencode-ai/llm",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"name": "opencode",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
@@ -120,7 +120,7 @@
|
||||
"drizzle-orm": "catalog:",
|
||||
"effect": "catalog:",
|
||||
"fuzzysort": "3.1.0",
|
||||
"gitlab-ai-provider": "6.12.1",
|
||||
"gitlab-ai-provider": "6.13.0",
|
||||
"glob": "13.0.5",
|
||||
"google-auth-library": "10.5.0",
|
||||
"gray-matter": "4.0.3",
|
||||
|
||||
@@ -22,7 +22,7 @@ import { UI } from "../ui"
|
||||
import { effectCmd } from "../effect-cmd"
|
||||
import { EOL } from "os"
|
||||
import { Filesystem } from "@/util/filesystem"
|
||||
import { createOpencodeClient, type Event, type OpencodeClient, type ToolPart } from "@opencode-ai/sdk/v2"
|
||||
import { createOpencodeClient, type OpencodeClient, type ToolPart } from "@opencode-ai/sdk/v2"
|
||||
import { FormatError, FormatUnknownError } from "../error"
|
||||
import { INTERACTIVE_INPUT_ERROR, resolveInteractiveStdin } from "./run/runtime.stdin"
|
||||
|
||||
@@ -690,14 +690,12 @@ export const RunCommand = effectCmd({
|
||||
return false
|
||||
}
|
||||
|
||||
const toggles = new Map<string, boolean>()
|
||||
const printed = new Set<string>()
|
||||
|
||||
// Consume one subscribed event stream for the active session and mirror it
|
||||
// to stdout/UI. `client` is passed explicitly because attach mode may
|
||||
// rebind the SDK to the session's directory after the subscription is
|
||||
// created, and replies issued from inside the loop must use that client.
|
||||
async function loop(client: OpencodeClient, events: Awaited<ReturnType<typeof sdk.event.subscribe>>) {
|
||||
const toggles = new Map<string, boolean>()
|
||||
const sessions = new Set([sessionID])
|
||||
let error: string | undefined
|
||||
|
||||
@@ -722,16 +720,6 @@ export const RunCommand = effectCmd({
|
||||
if (event.type === "message.part.updated") {
|
||||
const part = event.properties.part
|
||||
if (part.sessionID !== sessionID) continue
|
||||
if (
|
||||
args.attach &&
|
||||
(part.type === "step-start" ||
|
||||
part.type === "step-finish" ||
|
||||
((part.type === "text" || part.type === "reasoning") && part.time?.end) ||
|
||||
(part.type === "tool" && (part.state.status === "completed" || part.state.status === "error")))
|
||||
) {
|
||||
if (printed.has(part.id)) continue
|
||||
printed.add(part.id)
|
||||
}
|
||||
|
||||
if (part.type === "tool" && (part.state.status === "completed" || part.state.status === "error")) {
|
||||
if (emit("tool_use", { part })) continue
|
||||
@@ -843,41 +831,15 @@ export const RunCommand = effectCmd({
|
||||
await share(client, sessionID)
|
||||
|
||||
if (!interactive) {
|
||||
const controller = new AbortController()
|
||||
const events = await client.event.subscribe(undefined, { signal: controller.signal })
|
||||
const events = await client.event.subscribe()
|
||||
const completed = loop(client, events).catch((e) => {
|
||||
console.error(e)
|
||||
process.exitCode = 1
|
||||
})
|
||||
async function finish(parentID?: string) {
|
||||
if (args.attach) controller.abort()
|
||||
async function finish() {
|
||||
if (args.attach) return
|
||||
const error = await completed
|
||||
if (error) process.exitCode = 1
|
||||
if (!args.attach || !parentID) return
|
||||
|
||||
// The request has completed, but remote events may still be buffered
|
||||
// or missing. Recover this prompt's output without waiting for idle.
|
||||
const messages = await client.session.messages({ sessionID }, { throwOnError: true })
|
||||
async function* replay(): AsyncGenerator<Event> {
|
||||
for (const message of messages.data) {
|
||||
if (message.info.role !== "assistant" || message.info.parentID !== parentID) continue
|
||||
yield { id: message.info.id, type: "message.updated", properties: { sessionID, info: message.info } }
|
||||
for (const part of message.parts)
|
||||
yield {
|
||||
id: part.id,
|
||||
type: "message.part.updated",
|
||||
properties: { sessionID, part, time: message.info.time.completed ?? message.info.time.created },
|
||||
}
|
||||
if (message.info.error && !error)
|
||||
yield {
|
||||
id: message.info.id,
|
||||
type: "session.error",
|
||||
properties: { sessionID, error: message.info.error },
|
||||
}
|
||||
}
|
||||
}
|
||||
const replayError = await loop(client, { stream: replay() })
|
||||
if (replayError) process.exitCode = 1
|
||||
}
|
||||
|
||||
if (args.command) {
|
||||
@@ -894,7 +856,7 @@ export const RunCommand = effectCmd({
|
||||
process.exitCode = 1
|
||||
return
|
||||
}
|
||||
await finish(result.data?.info.parentID)
|
||||
await finish()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -911,7 +873,7 @@ export const RunCommand = effectCmd({
|
||||
process.exitCode = 1
|
||||
return
|
||||
}
|
||||
await finish(result.data?.info.parentID)
|
||||
await finish()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -1792,8 +1792,8 @@ const layer = Layer.effect(
|
||||
if (existing) return existing
|
||||
|
||||
const customFetch = options["fetch"]
|
||||
const chunkTimeout = options["chunkTimeout"]
|
||||
const headerTimeout = options["headerTimeout"]
|
||||
const chunkTimeout = options["chunkTimeout"] ?? 300_000
|
||||
const headerTimeout = options["headerTimeout"] ?? 300_000
|
||||
delete options["chunkTimeout"]
|
||||
delete options["headerTimeout"]
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import { describe, expect } from "bun:test"
|
||||
import { Effect } from "effect"
|
||||
import { reply } from "../../lib/llm-server"
|
||||
import { cliIt } from "../../lib/cli-process"
|
||||
import { testProviderConfig } from "../../lib/test-provider"
|
||||
|
||||
describe("opencode run (non-interactive subprocess)", () => {
|
||||
// Happy path: prompt completes, output reaches stdout, process exits 0.
|
||||
@@ -300,7 +299,6 @@ describe("opencode run (non-interactive subprocess)", () => {
|
||||
})
|
||||
|
||||
opencode.expectExit(result, 0)
|
||||
expect(result.stdout).toBe("attachment received\n")
|
||||
const input = JSON.stringify(yield* llm.inputs)
|
||||
expect(input).toContain(sentinel)
|
||||
expect(input).not.toContain(`file://${source}`)
|
||||
@@ -308,104 +306,6 @@ describe("opencode run (non-interactive subprocess)", () => {
|
||||
60_000,
|
||||
)
|
||||
|
||||
for (const mode of ["stream", "missing-idle", "command"]) {
|
||||
cliIt.live(
|
||||
`attach preserves completed output (${mode})`,
|
||||
({ llm, opencode }) =>
|
||||
Effect.gen(function* () {
|
||||
yield* llm.push(
|
||||
reply().reason("thinking").text("before").tool("bash", {
|
||||
command: "printf tool-output",
|
||||
description: "Print deterministic output",
|
||||
}),
|
||||
)
|
||||
yield* llm.text("after")
|
||||
const server = yield* opencode.serve({
|
||||
env: {
|
||||
OPENCODE_CONFIG_CONTENT: JSON.stringify({
|
||||
...testProviderConfig(llm.url),
|
||||
command: { probe: { template: "exercise output" } },
|
||||
}),
|
||||
},
|
||||
})
|
||||
// Keep SSE connected but withhold its events, including session idle.
|
||||
const proxy = yield* Effect.acquireRelease(
|
||||
Effect.sync(() =>
|
||||
Bun.serve({
|
||||
hostname: "127.0.0.1",
|
||||
port: 0,
|
||||
fetch(request) {
|
||||
const url = new URL(request.url)
|
||||
if (url.pathname === "/event" && mode !== "stream") {
|
||||
return new Response(
|
||||
new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(
|
||||
new TextEncoder().encode('data: {"type":"server.connected","properties":{}}\n\n'),
|
||||
)
|
||||
},
|
||||
}),
|
||||
{ headers: { "Content-Type": "text/event-stream" } },
|
||||
)
|
||||
}
|
||||
const forwarded = new Request(new URL(url.pathname + url.search, server.url), request)
|
||||
forwarded.headers.set("Accept-Encoding", "identity")
|
||||
return fetch(forwarded)
|
||||
},
|
||||
}),
|
||||
),
|
||||
(proxy) => Effect.sync(() => proxy.stop(true)),
|
||||
)
|
||||
const result = yield* opencode.run("exercise output", {
|
||||
command: mode === "command" ? "probe" : undefined,
|
||||
format: "json",
|
||||
extraArgs: ["--attach", proxy.url.origin, "--thinking", "--dangerously-skip-permissions"],
|
||||
})
|
||||
opencode.expectExit(result, 0)
|
||||
const events = opencode.parseJsonEvents(result.stdout)
|
||||
expect(events.map((event) => event.type)).toEqual([
|
||||
"step_start",
|
||||
"reasoning",
|
||||
"text",
|
||||
"tool_use",
|
||||
"step_finish",
|
||||
"step_start",
|
||||
"text",
|
||||
"step_finish",
|
||||
])
|
||||
expect(events.filter((event) => event.type === "text").map((event) => event.part)).toEqual([
|
||||
expect.objectContaining({ text: "before" }),
|
||||
expect.objectContaining({ text: "after" }),
|
||||
])
|
||||
|
||||
yield* llm.text("next turn")
|
||||
const resumed = yield* opencode.run("continue", {
|
||||
format: "json",
|
||||
extraArgs: ["--attach", proxy.url.origin, "--session", String(events[0].sessionID)],
|
||||
})
|
||||
opencode.expectExit(resumed, 0)
|
||||
expect(opencode.parseJsonEvents(resumed.stdout).map((event) => event.type)).toEqual([
|
||||
"step_start",
|
||||
"text",
|
||||
"step_finish",
|
||||
])
|
||||
expect(resumed.stdout).toContain("next turn")
|
||||
expect(resumed.stdout).not.toContain('"before"')
|
||||
|
||||
const rejected = yield* opencode.run("unknown model", {
|
||||
model: "test/nonexistent-model",
|
||||
format: "json",
|
||||
extraArgs: ["--attach", proxy.url.origin],
|
||||
})
|
||||
expect(rejected.exitCode).not.toBe(0)
|
||||
const errors = opencode.parseJsonEvents(rejected.stdout)
|
||||
expect(errors.length).toBeGreaterThan(0)
|
||||
expect(errors.every((event) => event.type === "error")).toBe(true)
|
||||
}),
|
||||
60_000,
|
||||
)
|
||||
}
|
||||
|
||||
cliIt.concurrent(
|
||||
"attach mode rejects local directories before prompt admission",
|
||||
({ home, opencode }) =>
|
||||
|
||||
@@ -13,6 +13,8 @@ import { Env } from "@/env"
|
||||
import { Plugin } from "@/plugin"
|
||||
import { Provider } from "@/provider/provider"
|
||||
import { ProviderError } from "@/provider/error"
|
||||
import { MessageV2 } from "@/session/message-v2"
|
||||
import { SessionRetry } from "@/session/retry"
|
||||
|
||||
afterEach(async () => {
|
||||
await disposeAllInstances()
|
||||
@@ -46,7 +48,48 @@ it.live("headerTimeout does not abort delayed SSE body after headers arrive", ()
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("chunkTimeout raises a response stream error when SSE body stalls", () =>
|
||||
for (const timeout of ["chunkTimeout", "headerTimeout"] as const) {
|
||||
it.live(`default ${timeout} is applied at fetch without changing provider options`, () =>
|
||||
Effect.gen(function* () {
|
||||
const server = yield* Effect.acquireRelease(
|
||||
Effect.promise(() => delayedBodyServer(250)),
|
||||
(server) => Effect.sync(() => server.server.close()),
|
||||
)
|
||||
|
||||
yield* provideTmpdirInstance(
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
const provider = yield* Provider.Service
|
||||
const configured = yield* provider.getProvider(ProviderV2.ID.make("test"))
|
||||
const signals: (AbortSignal | null | undefined)[] = []
|
||||
configured.options.fetch = (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
signals.push(init?.signal)
|
||||
return fetch(input, init)
|
||||
}
|
||||
const model = yield* provider.getModel(ProviderV2.ID.make("test"), ModelV2.ID.make("test-model"))
|
||||
const language = yield* provider.getLanguage(model)
|
||||
yield* Effect.acquireRelease(
|
||||
Effect.promise(() =>
|
||||
language.doStream({ prompt: [{ role: "user", content: [{ type: "text", text: "hello" }] }] }),
|
||||
),
|
||||
(result) => Effect.promise(() => result.stream.cancel()),
|
||||
)
|
||||
|
||||
expect(signals).toHaveLength(1)
|
||||
expect(signals[0]).toBeInstanceOf(AbortSignal)
|
||||
expect(configured.options[timeout]).toBeUndefined()
|
||||
}),
|
||||
{
|
||||
config: providerConfig(server.url, {
|
||||
[timeout === "chunkTimeout" ? "headerTimeout" : "chunkTimeout"]: false,
|
||||
}),
|
||||
},
|
||||
)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
it.live("configured chunkTimeout raises a retryable response stream error when SSE body stalls", () =>
|
||||
Effect.gen(function* () {
|
||||
const server = yield* Effect.acquireRelease(
|
||||
Effect.promise(() => delayedBodyServer(250)),
|
||||
@@ -74,12 +117,41 @@ it.live("chunkTimeout raises a response stream error when SSE body stalls", () =
|
||||
}
|
||||
})
|
||||
expect(error).toBeInstanceOf(ProviderError.ResponseStreamError)
|
||||
expect(
|
||||
SessionRetry.retryable(MessageV2.fromError(error, { providerID: model.providerID }), model.providerID),
|
||||
).toEqual({ message: "SSE read timed out" })
|
||||
}),
|
||||
{ config: providerConfig(server.url, { chunkTimeout: 50 }) },
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("chunkTimeout can be disabled with false", () =>
|
||||
Effect.gen(function* () {
|
||||
const server = yield* Effect.acquireRelease(
|
||||
Effect.promise(() => delayedBodyServer(250)),
|
||||
(server) => Effect.sync(() => server.server.close()),
|
||||
)
|
||||
|
||||
yield* provideTmpdirInstance(
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
const provider = yield* Provider.Service
|
||||
const configured = yield* provider.getProvider(ProviderV2.ID.make("test"))
|
||||
expect(configured.options.chunkTimeout).toBe(false)
|
||||
const model = yield* provider.getModel(ProviderV2.ID.make("test"), ModelV2.ID.make("test-model"))
|
||||
const result = streamText({
|
||||
model: yield* provider.getLanguage(model),
|
||||
messages: [{ role: "user", content: "hello" }],
|
||||
})
|
||||
|
||||
expect(yield* Effect.promise(() => result.text)).toBe("late")
|
||||
}),
|
||||
{ config: providerConfig(server.url, { chunkTimeout: false }) },
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("headerTimeout aborts when response headers do not arrive", () =>
|
||||
Effect.gen(function* () {
|
||||
const server = yield* Effect.acquireRelease(
|
||||
@@ -112,7 +184,7 @@ it.live("headerTimeout aborts when response headers do not arrive", () =>
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("headerTimeout is opt-in for non-OpenAI providers", () =>
|
||||
it.live("headerTimeout can be disabled with false for non-OpenAI providers", () =>
|
||||
Effect.gen(function* () {
|
||||
const server = yield* Effect.acquireRelease(
|
||||
Effect.promise(() => delayedHeaderServer(100)),
|
||||
@@ -131,12 +203,12 @@ it.live("headerTimeout is opt-in for non-OpenAI providers", () =>
|
||||
|
||||
expect(yield* Effect.promise(() => result.text)).toBe("ok")
|
||||
}),
|
||||
{ config: providerConfig(server.url) },
|
||||
{ config: providerConfig(server.url, { headerTimeout: false }) },
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("OpenAI Codex headerTimeout default can be disabled by config", () =>
|
||||
it.live("OpenAI Codex header and chunk timeout defaults can be disabled by config", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* withAuthContent(
|
||||
Effect.gen(function* () {
|
||||
@@ -146,8 +218,9 @@ it.live("OpenAI Codex headerTimeout default can be disabled by config", () =>
|
||||
const provider = yield* Provider.Service
|
||||
const openai = yield* provider.getProvider(ProviderV2.ID.openai)
|
||||
expect(openai.options.headerTimeout).toBe(false)
|
||||
expect(openai.options.chunkTimeout).toBe(false)
|
||||
}),
|
||||
{ config: { provider: { openai: { options: { headerTimeout: false } } } } },
|
||||
{ config: { provider: { openai: { options: { headerTimeout: false, chunkTimeout: false } } } } },
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1751,11 +1751,14 @@ export type ProviderConfig = {
|
||||
*/
|
||||
timeout?: number | false
|
||||
/**
|
||||
* Timeout in milliseconds to wait for response headers. Provider integrations may set defaults. Set to false to disable timeout.
|
||||
* Timeout in milliseconds to wait for response headers (default: 300000). Set to false to disable timeout.
|
||||
*/
|
||||
headerTimeout?: number | false
|
||||
chunkTimeout?: number
|
||||
[key: string]: unknown | string | boolean | number | false | number | false | number | undefined
|
||||
/**
|
||||
* Timeout in milliseconds between streamed SSE chunks for this provider (default: 300000). If no chunk arrives within this window, the request is aborted. Set to false to disable timeout.
|
||||
*/
|
||||
chunkTimeout?: number | false
|
||||
[key: string]: unknown | string | boolean | number | false | number | false | number | false | undefined
|
||||
}
|
||||
models?: {
|
||||
[key: string]: {
|
||||
|
||||
@@ -20780,11 +20780,20 @@
|
||||
"enum": [false]
|
||||
}
|
||||
],
|
||||
"description": "Timeout in milliseconds to wait for response headers. Provider integrations may set defaults. Set to false to disable timeout."
|
||||
"description": "Timeout in milliseconds to wait for response headers (default: 300000). Set to false to disable timeout."
|
||||
},
|
||||
"chunkTimeout": {
|
||||
"type": "integer",
|
||||
"exclusiveMinimum": 0
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer",
|
||||
"exclusiveMinimum": 0
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"enum": [false]
|
||||
}
|
||||
],
|
||||
"description": "Timeout in milliseconds between streamed SSE chunks for this provider (default: 300000). If no chunk arrives within this window, the request is aborted. Set to false to disable timeout."
|
||||
}
|
||||
},
|
||||
"additionalProperties": {}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/server",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/session-ui",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/slack",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/stats-app",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/stats-core",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/stats-server",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/tui",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@opencode-ai/web",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
|
||||
|
||||
@@ -374,7 +374,7 @@ You can configure the providers and models you want to use in your OpenCode conf
|
||||
|
||||
The `small_model` option configures a separate model for lightweight tasks like title generation. By default, OpenCode tries to use a cheaper model if one is available from your provider, otherwise it falls back to your main model.
|
||||
|
||||
Provider options can include `timeout`, `chunkTimeout`, and `setCacheKey`:
|
||||
Provider options can include `timeout`, `headerTimeout`, `chunkTimeout`, and `setCacheKey`:
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -392,7 +392,8 @@ Provider options can include `timeout`, `chunkTimeout`, and `setCacheKey`:
|
||||
```
|
||||
|
||||
- `timeout` - Request timeout in milliseconds (default: 300000). Set to `false` to disable.
|
||||
- `chunkTimeout` - Timeout in milliseconds between streamed response chunks. If no chunk arrives in time, the request is aborted.
|
||||
- `headerTimeout` - Timeout in milliseconds to wait for response headers (default: 300000, or 5 minutes). This timer stops once headers arrive and does not limit the streamed response body. Set to `false` to disable.
|
||||
- `chunkTimeout` - Timeout in milliseconds between streamed response chunks (default: 300000, or 5 minutes). If no chunk arrives in time, the request is aborted. Set to `false` to disable.
|
||||
- `setCacheKey` - Ensure a cache key is always set for designated provider.
|
||||
|
||||
You can also configure [local models](/docs/models#local). [Learn more](/docs/models).
|
||||
|
||||
@@ -874,6 +874,54 @@ Selecting a router model is a drop-in replacement for any other model — OpenCo
|
||||
|
||||
---
|
||||
|
||||
### Eden AI
|
||||
|
||||
[Eden AI](https://www.edenai.co/) is an EU-based gateway that serves models from many vendors over a single OpenAI-compatible API, with a separate EU endpoint for teams that need inference to stay in the EU.
|
||||
|
||||
1. Head over to the [Eden AI platform](https://app.edenai.run/user/register) to create an account and generate an API key.
|
||||
|
||||
2. Run the `/connect` command and search for **Eden AI**.
|
||||
|
||||
```txt
|
||||
/connect
|
||||
```
|
||||
|
||||
3. Enter your Eden AI API key.
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
│
|
||||
│
|
||||
└ enter
|
||||
```
|
||||
|
||||
4. Run the `/models` command to select a model like _Mistral Large 3_ or _Claude Sonnet 5_.
|
||||
|
||||
```txt
|
||||
/models
|
||||
```
|
||||
|
||||
Eden AI model ids are themselves in `vendor/model` form, so a full reference has three segments, for example `edenai/anthropic/claude-sonnet-5`.
|
||||
|
||||
5. To keep requests on Eden AI's EU gateway, set its base URL.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"provider": {
|
||||
"edenai": {
|
||||
"options": {
|
||||
"baseURL": "https://api.eu.edenai.run/v3"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The default is `https://api.edenai.run/v3`, so this swaps the global endpoint for the EU one. The EU endpoint serves the subset of the catalog that is available in the EU, so a model chosen in step 4 may not be reachable through it.
|
||||
|
||||
---
|
||||
|
||||
### FrogBot
|
||||
|
||||
1. Head over to the [FrogBot dashboard](https://app.frogbot.ai/signup), create an account, and generate an API key.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "opencode",
|
||||
"displayName": "opencode",
|
||||
"description": "opencode for VS Code",
|
||||
"version": "1.18.26",
|
||||
"version": "1.18.27",
|
||||
"publisher": "sst-dev",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
Reference in New Issue
Block a user