Compare commits

..
Author SHA1 Message Date
LukeParkerDev 21197e4e6f perf(desktop): enable the V8 code cache for the renderer scheme
Chromium only persists compiled bytecode for schemes that opt in, so
every launch re-parsed and re-compiled the whole renderer bundle. With
the codeCache privilege on oc:// the third launch onwards loads from the
Code Cache directory.

Packaged build, warm service, renderer main-thread task time until idle
481 -> 447 ms (script 110 -> 83 ms); shell visible 450 -> 405 ms after
the renderer process starts.
2026-09-18 23:00:28 +10:00
Shoubhit Dash db80806651 refactor(core): move native compaction mechanisms into a plugin (#49575) 2026-09-18 17:15:44 +05:30
Luke Parker 47f66de8dd perf(app): load draft image bytes on demand (#49703) 2026-09-18 19:32:15 +10:00
opencode c076066c33 sync release versions for v2.0.8 2026-09-18 09:12:33 +00:00
opencode-agent[bot] 5c09d051e5 chore: update nix node_modules hashes 2026-09-18 08:45:27 +00:00
Luke Parker 0a6111291e refactor(desktop): send IPC messages by structured clone (#49701) 2026-09-18 18:28:20 +10:00
Luke Parker 609044ef0a feat(app): scan pairing QR code from add server dialog (#49699) 2026-09-18 17:36:30 +10:00
Luke Parker 4f32bfca57 fix(desktop): copy IPC payloads out of the shared msgpack buffer (#49696) 2026-09-18 17:14:29 +10:00
Luke Parker 90112f52db fix(app): deliver text and oversized attachments by path (#49682) 2026-09-18 06:30:57 +00:00
Luke Parker d4303a9ca5 feat(app): show provider metrics in debug bar (#49674) 2026-09-18 15:51:08 +10:00
Kit Langton 735556eab8 fix(tui): open completed subagent sessions (#49675) 2026-09-18 05:42:40 +00:00
Kit Langton 10cac9ab5d fix(tui): show update installation progress (#49676) 2026-09-17 22:33:43 -07:00
Kit Langton 2d0ce64111 fix(client): reconcile stale tools at settlement (#49672) 2026-09-17 22:23:45 -07:00
Luke Parker 3355c93efd fix(app): create local sessions in project root (#49668) 2026-09-18 14:12:18 +10:00
Luke Parker 469e1c035e feat(app): stream large attachments to the server with progress (#49647) 2026-09-18 14:05:30 +10:00
opencode-agent[bot]andrekram1-node b2e3569add test(codemode): isolate OpenAPI fixtures (#49667)
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
2026-09-17 23:01:36 -05:00
James Long 0ac458b3b3 refactor(theme): rename surface tokens to raised (#49655) 2026-09-17 22:05:42 -04:00
Brendan DukeandAiden Cline b278ef6b82 fix(tui): include reasoning tokens in throughput (#48689)
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
2026-09-17 20:12:06 -05:00
Dax 3e3a4ae46b feat(tui): add /btw side question command (#49646) 2026-09-17 21:03:09 -04:00
Dax Raad fe0d9579a7 fix(tui): preserve block tool spacing 2026-09-17 20:18:52 -04:00
Aiden Cline a2594ddefb fix(tui): sync model preferences across clients (#49611) 2026-09-17 14:54:34 -05:00
Aiden Cline 3555cef1c8 chore(client): regenerate policy types (#49613) 2026-09-17 14:38:09 -05:00
opencode 0fa881efd0 sync release versions for v2.0.7 2026-09-17 19:29:59 +00:00
opencode-agent[bot]andrekram1-node 37ff501cc6 fix(cli): keep updates client-owned (#49577)
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
2026-09-17 12:47:49 -04:00
Dax fa126d68e8 feat(core): enforce permission policies 2026-09-17 12:39:20 -04:00
opencode-agent[bot]andJames Long a0571a8b14 fix(tui): keep upgrade as a search keyword (#49567)
Co-authored-by: James Long <17031+jlongster@users.noreply.github.com>
2026-09-17 11:32:16 -04:00
Dax Raad cae475df37 sync 2026-09-17 10:47:52 -04:00
Shoubhit Dash 19781a4447 fix(acp): propagate request cancellation and close sessions cleanly (#49563) 2026-09-17 20:16:07 +05:30
Brendan Allan e32de90d88 fix(app): prevent settings project cache reload loop (#49564) 2026-09-17 14:45:03 +00:00
Kit Langton 0ee5ef6c43 fix(tui): keep spinner glyph from shrinking beside long labels (#49395) 2026-09-17 07:43:07 -07:00
a72f988c90 fix(tui): switch vertical tabs sooner (#49440)
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2026-09-17 09:43:02 -05:00
Dax Raad 2a132d6f50 fix(tui): include provider latency in TPS 2026-09-17 10:40:12 -04:00
Dax Raad 23418b3885 docs: reorder sidebar navigation 2026-09-17 10:20:57 -04:00
Dax Raad b4ac938c3d docs: improve installation guide 2026-09-17 10:10:20 -04:00
Dax Raad 4b25739e93 docs(cli): drop command-name leads in command descriptions 2026-09-17 09:44:31 -04:00
Dax Raad 2f97e1324f fix(www): restore OpenTUI Mono docs font 2026-09-17 09:31:40 -04:00
Dax Raad 0018f08832 feat(cli): add reload command 2026-09-17 09:21:41 -04:00
Dax Raad b52f241294 feat(location): reload configuration 2026-09-17 09:18:51 -04:00
Dax Raad 254ace8594 docs: add CLI settings reference 2026-09-17 09:17:14 -04:00
usrnk1 657f700f5d feat(desktop): disable security code autofill (#49531) 2026-09-17 20:35:14 +08:00
Victor Navarro 7e1d28b549 feat(cli): support custom Console logins (#49542) 2026-09-17 13:50:32 +02:00
opencode 040d2ffb48 sync release versions for v2.0.6 2026-09-17 11:17:33 +00:00
usrnk1 0675975f98 feat(desktop): remove pointer cursor from non-link elements (#49323) 2026-09-17 20:41:24 +10:00
opencode-agent[bot]andiamdavidhill 130232feb6 chore(desktop): update bundled themes (#48713)
Co-authored-by: iamdavidhill <iamdavidhill@users.noreply.github.com>
2026-09-17 20:40:07 +10:00
opencode-agent[bot]andiamdavidhill 54f2356166 fix(app): remove Anthropic Pro and Max copy (#49369)
Co-authored-by: iamdavidhill <1879069+iamdavidhill@users.noreply.github.com>
2026-09-17 20:39:39 +10:00
David Hill ac0dd75c6a fix(app): hide browser when the right panel closes (#49425) 2026-09-17 20:39:02 +10:00
David Hill 430886142b fix(app): center start screen beside summary panels (#49429) 2026-09-17 20:38:36 +10:00
David Hill 5a02ec776e fix(app): use muted worktree icon in session timeline (#49459) 2026-09-17 20:37:37 +10:00
David Hill c303a11725 fix(app): mute session tab hover and active backgrounds (#49465) 2026-09-17 20:37:13 +10:00
David Hill dfceca8de7 fix(app): refine start-screen logo (#49475) 2026-09-17 20:36:45 +10:00
Luke Parker f04c3fd82b feat(app): attach any file and deliver unsupported ones by path (#49467) 2026-09-17 20:35:00 +10:00
Luke Parker 1685e70c4b feat(server): add fs.write endpoint (#49466) 2026-09-17 20:17:14 +10:00
Chris Yang 73e7b7bc79 fix(app): derive directory names from listed paths (#49122) 2026-09-17 18:46:07 +10:00
David Hill a5b3802ca3 fix(app): keep compact tab icons visible (#49460) 2026-09-17 14:48:47 +08:00
Dax Raad f28d1b44e3 fix(core): serialize MCP endpoint startup 2026-09-17 00:52:34 -04:00
Dax Raad b81be469c8 fix(client): preserve state during location reload 2026-09-17 00:52:34 -04:00
opencode-agent[bot]andkitlangton fca4a8fa3b feat(tui): show explicit subagent model (#49388)
Co-authored-by: kitlangton <7587245+kitlangton@users.noreply.github.com>
2026-09-16 22:50:28 -05:00
Aiden Cline 8520617ca8 fix(core): retry provider failures for about 84s with 10s gap cap (#49441) 2026-09-16 20:59:16 -05:00
319 changed files with 4583 additions and 1780 deletions
+1
View File
@@ -184,6 +184,7 @@ const table = sqliteTable("session", {
- Keep `SessionRunner`, model resolution, tool registry, permissions, and filesystem Location-scoped. Omitted `Location.workspaceID` means implicit-local placement; explicit workspace identity remains reserved for future placement semantics.
- Preserve one explicit `llm.stream(request)` call per Physical Attempt and reload projected history before durable continuation. A logical Step may use generic pre-output retries, one full-context retry after continuation rejection, incomplete-stream continuation, or one overflow-compaction rebuild. Generic retries retain the logical step number and do not consume another agent-step allowance. Do not delegate orchestration to an in-memory tool loop.
- Keep local Session drains process-local until clustering is implemented. `SessionRunCoordinator` joins explicit same-Session resumes, coalesces prompt wakeups, and allows different Sessions to run concurrently. A write-ahead execution claim marks a process-local busy period for restart recovery: terminal completion, failure, or user interruption releases it, while shutdown interruption and process death preserve it. Startup recovery resumes claimed top-level Sessions with durable per-execution attempt accounting. The claim is a recovery marker, not clustered ownership, fencing, or an exactly-once guarantee.
- Keep native compaction mechanisms out of `SessionCompaction`. Plugins register `native` strategies through the `SessionCompaction` editor that turn a prepared request into a replacement window (the built-in `NativeCompactionPlugin` handles `@opencode/ai` compaction operations); later registrations win. Core owns the provider-mode decision, route provenance, the retry policy, overflow recovery, interruption, usage accounting, and checkpoint persistence.
- Keep delivery vocabulary explicit. Prompts steer by default. At safe step boundaries, steered compaction takes priority up to the first steered move control; other steers retain enqueue order. At an idle boundary, steers take priority; otherwise exactly one queued item delivers before the runner reevaluates continuation. Inbox items may be cancelled or changed between queue and steer before delivery. Promoting new user input resets the selected agent's step allowance; a batch of steers resets it once.
- One step is one logical LLM call; its durable record covers only the model-visible span. Do not write "provider turn", and do not use bare "turn" for a single call: "turn" is reserved for the future assistant-turn unit containing all steps from prompt promotion until the session would go idle.
- Keep event replay ownership separate from clustered Session execution ownership.
+35 -36
View File
@@ -32,7 +32,7 @@
},
"packages/ai": {
"name": "@opencode/ai",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@aws-sdk/credential-providers": "3.1057.0",
"@opencode/schema": "workspace:*",
@@ -54,7 +54,7 @@
},
"packages/app": {
"name": "@opencode/app",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@corvu/drawer": "catalog:",
"@dnd-kit/abstract": "0.5.0",
@@ -113,7 +113,7 @@
},
"packages/cli": {
"name": "@opencode/cli",
"version": "2.0.5",
"version": "2.0.8",
"bin": {
"opencode2": "./bin/opencode2.cjs",
},
@@ -177,7 +177,7 @@
},
"packages/client": {
"name": "@opencode/client",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@opencode/protocol": "workspace:*",
"@opencode/schema": "workspace:*",
@@ -203,7 +203,7 @@
},
"packages/codemode": {
"name": "@opencode/codemode",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"acorn": "8.15.0",
"effect": "catalog:",
@@ -217,7 +217,7 @@
},
"packages/console/app": {
"name": "@opencode/console-app",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@ibm/plex": "6.4.1",
@@ -253,7 +253,7 @@
},
"packages/console/core": {
"name": "@opencode/console-core",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1",
@@ -280,7 +280,7 @@
},
"packages/console/function": {
"name": "@opencode/console-function",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@openauthjs/openauth": "0.0.0-20250322224806",
"@opencode/console-core": "workspace:*",
@@ -297,7 +297,7 @@
},
"packages/console/mail": {
"name": "@opencode/console-mail",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
@@ -321,7 +321,7 @@
},
"packages/console/support": {
"name": "@opencode/console-support",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@opencode/console-core": "workspace:*",
@@ -341,7 +341,7 @@
},
"packages/core": {
"name": "@opencode/core",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@ai-sdk/cohere": "3.0.27",
"@ai-sdk/gateway": "3.0.104",
@@ -409,7 +409,7 @@
},
"packages/desktop": {
"name": "@opencode/desktop",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@zip.js/zip.js": "2.7.62",
"electron-context-menu": "4.1.2",
@@ -456,12 +456,11 @@
"@lydell/node-pty-linux-x64": "1.2.0-beta.12",
"@lydell/node-pty-win32-arm64": "1.2.0-beta.12",
"@lydell/node-pty-win32-x64": "1.2.0-beta.12",
"msgpackr-extract": "3.0.4",
},
},
"packages/enterprise": {
"name": "@opencode/enterprise",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@hono/standard-validator": "catalog:",
"@opencode-ai/sdk": "1.18.21",
@@ -498,7 +497,7 @@
},
"packages/function": {
"name": "@opencode/function",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "catalog:",
@@ -514,7 +513,7 @@
},
"packages/http-recorder": {
"name": "@opencode/http-recorder",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@effect/platform-node-shared": "4.0.0-rc.112",
},
@@ -533,7 +532,7 @@
},
"packages/httpapi-codegen": {
"name": "@opencode/httpapi-codegen",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"effect": "catalog:",
"prettier": "3.6.2",
@@ -546,7 +545,7 @@
},
"packages/latex": {
"name": "@opencode/latex",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@opencode/plugin": "workspace:*",
"@opentui/core": "catalog:",
@@ -560,7 +559,7 @@
},
"packages/merman": {
"name": "@opencode/merman",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@opencode/plugin": "workspace:*",
"@opentui/core": "catalog:",
@@ -575,7 +574,7 @@
},
"packages/plugin": {
"name": "@opencode/plugin",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@ai-sdk/provider": "3.0.8",
"@opencode/ai": "workspace:*",
@@ -614,7 +613,7 @@
},
"packages/plugin-browser": {
"name": "@opencode/plugin-browser",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@opencode/plugin": "workspace:*",
"@opencode/schema": "workspace:*",
@@ -644,7 +643,7 @@
},
"packages/protocol": {
"name": "@opencode/protocol",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@opencode/schema": "workspace:*",
"effect": "catalog:",
@@ -659,7 +658,7 @@
},
"packages/schema": {
"name": "@opencode/schema",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@standard-schema/spec": "catalog:",
"effect": "catalog:",
@@ -683,7 +682,7 @@
},
"packages/sdk": {
"name": "@opencode/sdk",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@opencode/client": "workspace:*",
"@opencode/core": "workspace:*",
@@ -704,7 +703,7 @@
},
"packages/server": {
"name": "@opencode/server",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@effect/platform-node": "catalog:",
"@effect/platform-node-shared": "catalog:",
@@ -726,7 +725,7 @@
},
"packages/session-ui": {
"name": "@opencode/session-ui",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode/client": "workspace:*",
@@ -761,7 +760,7 @@
},
"packages/simulation": {
"name": "@opencode/simulation",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@opencode/ai": "workspace:*",
"@opencode/core": "workspace:*",
@@ -781,7 +780,7 @@
},
"packages/stats/app": {
"name": "@opencode/stats-app",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@ibm/plex": "6.4.1",
"@kobalte/core": "catalog:",
@@ -815,7 +814,7 @@
},
"packages/stats/core": {
"name": "@opencode/stats-core",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@aws-sdk/client-athena": "3.933.0",
"@planetscale/database": "1.19.0",
@@ -834,7 +833,7 @@
},
"packages/stats/server": {
"name": "@opencode/stats-server",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@aws-sdk/client-firehose": "3.933.0",
"@effect/platform-node": "catalog:",
@@ -880,7 +879,7 @@
},
"packages/theme": {
"name": "@opencode/theme",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@opentui/core": "catalog:",
"effect": "catalog:",
@@ -894,7 +893,7 @@
},
"packages/tui": {
"name": "@opencode/tui",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@opencode/client": "workspace:*",
"@opencode/core": "workspace:*",
@@ -929,7 +928,7 @@
},
"packages/ui": {
"name": "@opencode/ui",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@kobalte/core": "catalog:",
"@pierre/diffs": "catalog:",
@@ -964,7 +963,7 @@
},
"packages/util": {
"name": "@opencode/util",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@effect/opentelemetry": "catalog:",
"@effect/platform-node": "catalog:",
@@ -997,7 +996,7 @@
},
"packages/web": {
"name": "@opencode/web",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",
@@ -1038,7 +1037,7 @@
},
"services/update": {
"name": "@opencode/update",
"version": "2.0.5",
"version": "2.0.8",
"dependencies": {
"jose": "6.0.11",
"semver": "catalog:",
+4 -4
View File
@@ -1,8 +1,8 @@
{
"nodeModules": {
"x86_64-linux": "sha256-U9IuP/ev6w4urvogOwQyl3rdumY6W4YaY18NkFaOVHU=",
"aarch64-linux": "sha256-Wc8OT2DRZpVo56KaoGE0Hsj1NDknakbWXO9w2qy6j+0=",
"aarch64-darwin": "sha256-wAea8+jajnMDxZ6XJL+Hsrf0621hwtBtWyD1+dS45dE=",
"x86_64-darwin": "sha256-g8PCNBSV6rO+VQjKU9AtYqj+r18o+fhLDXEQq+X2EZ4="
"x86_64-linux": "sha256-TlCPtuIvTNF01fLI0yHCLzVkx53yF9xxvAObDMGeo8M=",
"aarch64-linux": "sha256-aEjyPIXHeA5w1iZXbPKJAOIJQBfXg+LAx/y7C5uFz4g=",
"aarch64-darwin": "sha256-lthMTio2qNy+H2tL9cAPmqC41O+wdSADI61cnW4dIb0=",
"x86_64-darwin": "sha256-ONFbRQnwzOYHo0Pyh327QfJG2uzqzNEn/SS2vbYYMdM="
}
}
+1 -1
View File
@@ -2,7 +2,7 @@
"$schema": "https://json.schemastore.org/package.json",
"name": "opencode",
"description": "AI-powered development tool",
"version": "2.0.5",
"version": "2.0.8",
"private": true,
"type": "module",
"packageManager": "bun@1.4.2",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "2.0.5",
"version": "2.0.8",
"name": "@opencode/ai",
"type": "module",
"license": "MIT",
@@ -42,3 +42,18 @@ story("hides and restores the same registration for Review tabs and unmount", as
await root.getByRole("button", { name: "Unmount pane", exact: true }).click()
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "false")
})
story("hides the native view immediately while the pane stays mounted", async ({ page }) => {
const root = page.getByTestId("browser-pane-fixture")
const toggle = root.getByRole("button", { name: "Toggle Review tab", exact: true })
await expect(toggle).toBeEnabled()
// Read in the same task as the click so a deferred animation-frame hide cannot pass.
const visible = await toggle.evaluate((element) => {
element.dispatchEvent(new MouseEvent("click", { bubbles: true }))
return document.querySelector('[data-testid="native-Alpha"]')?.getAttribute("data-visible")
})
expect(visible).toBe("false")
await expect(root.locator("#browser-panel")).toHaveCount(1)
await toggle.click()
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
})
@@ -9,12 +9,17 @@ for (const theme of ["light", "dark"]) {
const reveal = logo.locator('[data-slot="wordmark-reveal"]')
const shimmer = logo.locator(".wordmark-shimmer")
const base = logo.locator("svg").first()
await expect(base).toHaveCSS("opacity", theme === "dark" ? "0.5" : "0.6")
await expect(base).toHaveCSS("opacity", "0.16")
await expect(shimmer).toHaveCSS("animation-iteration-count", "1")
await expect(logo.locator("g[mask]")).toHaveCount(0)
await expect(shimmer).toHaveCSS("color", "rgb(255, 255, 255)")
await expect(shimmer).toHaveCSS("mix-blend-mode", "screen")
await expect(base.locator("g[fill]")).toHaveAttribute("fill", "currentColor")
await expect(base.locator("path").nth(1)).toHaveAttribute("fill", "var(--icon-base)")
await expect(base.locator("path").nth(9)).toHaveCSS(
"fill",
await base.locator("path").nth(1).evaluate((element) => getComputedStyle(element).fill),
)
await expect(base.locator('path[fill="var(--icon-weak-base)"]')).toHaveCount(8)
await logo.evaluate((element) => {
element.getAnimations({ subtree: true }).forEach((animation) => {
@@ -77,7 +82,7 @@ for (const theme of ["light", "dark"]) {
await page.setViewportSize({ width: 360, height: 640 })
const component = await mount("app-new-session-wordmark--reveal", { globals: { theme } })
const logo = component.locator('[data-component="new-session-wordmark"]')
await expect(logo.locator("svg").first()).toHaveCSS("opacity", theme === "dark" ? "0.5" : "0.6")
await expect(logo.locator("svg").first()).toHaveCSS("opacity", "0.16")
await expect(logo.locator('[data-slot="wordmark-reveal"]')).toHaveCSS("opacity", "1")
await expect(logo.locator(".wordmark-shimmer")).toHaveCSS("opacity", "0")
expect(await logo.evaluate((element) => element.getAnimations({ subtree: true }).length)).toBe(0)
@@ -485,6 +485,7 @@ export function stepStarted(message: SessionMessageAssistant) {
assistantMessageID: message.id,
agent: message.agent,
model: message.model,
started: message.time.created,
})
}
@@ -108,6 +108,15 @@ test("non-Git folders show their status without offering worktree actions", asyn
).toBeEnabled()
})
test("submits locally after changing a new worktree draft to Local", async ({ page }) => {
const mock = await openDraft(page, "create", { currentDirectory: workspace })
await page.getByRole("button", { name: "New worktree", exact: true }).click()
await page.getByRole("menuitem", { name: "Local repository", exact: true }).click()
await page.locator('[data-component="composer-editor"]').fill("Run locally")
await page.locator('[data-action="composer-submit"]').click()
await expect.poll(() => mock.calls.find((call) => call.type === "session")?.directory).toBe(directory)
})
test("new worktree MCP choices persist per draft and apply before the first prompt", async ({ page }, testInfo) => {
const mock = await openDraft(page, "create")
await page.locator('[data-component="composer-editor"]').fill("Use my selected MCPs")
@@ -296,7 +305,12 @@ test("new worktree sign-in completes before the draft can send", async ({ page,
expect(attempts).toHaveLength(1)
})
async function openDraft(page: Page, worktree = "main", options: { git?: boolean; direction?: "ltr" | "rtl" } = {}) {
async function openDraft(
page: Page,
worktree = "main",
options: { git?: boolean; direction?: "ltr" | "rtl"; currentDirectory?: string } = {},
) {
const currentDirectory = options.currentDirectory ?? directory
const project = {
id: "proj_new_summary",
worktree: directory,
@@ -315,7 +329,7 @@ async function openDraft(page: Page, worktree = "main", options: { git?: boolean
const prompts: { sessionID: string; body: Record<string, unknown> }[] = []
const state: { fail: boolean; hold?: Promise<void>; holdDirectory?: string } = { fail: false }
await mockOpenCodeServer(page, {
directory,
directory: currentDirectory,
project,
sessions,
provider: {
@@ -442,7 +456,7 @@ async function openDraft(page: Page, worktree = "main", options: { git?: boolean
},
)
await page.addInitScript(
({ directory, server, draftID, secondDraftID, worktree }) => {
({ directory, currentDirectory, server, draftID, secondDraftID, worktree }) => {
if (!localStorage.getItem("opencode.global.dat:server"))
localStorage.setItem(
"opencode.global.dat:server",
@@ -455,12 +469,12 @@ async function openDraft(page: Page, worktree = "main", options: { git?: boolean
localStorage.setItem(
"opencode.window.browser.dat:tabs",
JSON.stringify([
{ type: "draft", draftID, server, directory, worktree },
{ type: "draft", draftID: secondDraftID, server, directory, worktree },
{ type: "draft", draftID, server, directory: currentDirectory, worktree },
{ type: "draft", draftID: secondDraftID, server, directory: currentDirectory, worktree },
]),
)
},
{ directory, server, draftID, secondDraftID, worktree },
{ directory, currentDirectory, server, draftID, secondDraftID, worktree },
)
if (options.direction) await openWithDirection(page, draftPath, options.direction)
if (!options.direction) await page.goto(draftPath)
@@ -284,7 +284,7 @@ for (const delivery of ["steer", "queue"] as const) {
await expect(thinking).toHaveCount(0)
// The next assistant step still belongs to U1: U2 has been admitted, not delivered.
mock.emit("session.step.started", { sessionID, assistantMessageID: assistantID, agent: "build", model })
mock.emit("session.step.started", { sessionID, assistantMessageID: assistantID, agent: "build", model, started: Date.now() })
for (const tool of [
{ id: "tool_queue_read", name: "read", input: { path: "src/queue.ts" } },
{ id: "tool_queue_grep", name: "grep", input: { pattern: "retry", path: "src" } },
@@ -341,7 +341,7 @@ for (const delivery of ["steer", "queue"] as const) {
)
const later = { sessionID, assistantMessageID: "msg_queue_follow_up_assistant" }
mock.emit("session.step.started", { ...later, agent: "build", model })
mock.emit("session.step.started", { ...later, agent: "build", model, started: Date.now() })
mock.emit("session.text.started", { ...later, ordinal: 0 })
mock.emit("session.text.ended", { ...later, ordinal: 0, text: "A3: Now checking the retry path for U2." })
const response = transcript
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode/app",
"version": "2.0.5",
"version": "2.0.8",
"description": "",
"type": "module",
"exports": {
@@ -16,6 +16,86 @@
}
}
[data-component="upload-row"] {
display: flex;
flex-direction: column;
gap: 4px;
& + & {
margin-top: 8px;
}
[data-slot="upload-row-label"] {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 8px;
font-size: 13px;
line-height: var(--line-height-base);
letter-spacing: -0.04px;
}
[data-slot="upload-row-name"] {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--v2-text-text-base);
font-weight: 530;
}
[data-slot="upload-row-percent"] {
flex-shrink: 0;
color: var(--v2-text-text-muted);
font-variant-numeric: tabular-nums;
}
[data-slot="upload-row-track"] {
display: flex;
align-items: center;
gap: 8px;
}
[data-component="upload-progress"] {
flex: 1;
height: 4px;
overflow: hidden;
border-radius: 999px;
background: var(--v2-background-bg-layer-02);
}
[data-slot="upload-progress-bar"] {
height: 100%;
border-radius: inherit;
background: var(--v2-icon-icon-base);
transition: width 160ms ease-out;
}
[data-slot="upload-row-cancel"] {
display: inline-flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
padding: 0;
border: 0;
border-radius: 4px;
background: transparent;
color: var(--v2-icon-icon-muted);
cursor: pointer;
&:hover {
background: var(--v2-overlay-simple-overlay-hover);
color: var(--v2-icon-icon-base);
}
svg {
width: 12px;
height: 12px;
}
}
}
[data-component="composer-attachments"] {
timeline-scope: --composer-attachments-scroll;
@@ -1,66 +1,12 @@
import { onCleanup, onMount } from "solid-js"
import { createStore } from "solid-js/store"
import { makeEventListener } from "@solid-primitives/event-listener"
import { createBlobReference } from "@/runtime/persistence/drafts"
import { uuid } from "@/runtime/persistence/uuid"
import type { ComposerAttachment, ComposerPrompt } from "../types"
const accepted = [
"image/png",
"image/jpeg",
"image/gif",
"image/webp",
"application/pdf",
"text/*",
"application/json",
"application/ld+json",
"application/toml",
"application/x-toml",
"application/x-yaml",
"application/xml",
"application/yaml",
".c",
".cc",
".cjs",
".conf",
".cpp",
".css",
".csv",
".cts",
".env",
".go",
".gql",
".graphql",
".h",
".hh",
".hpp",
".htm",
".html",
".ini",
".java",
".js",
".json",
".jsx",
".log",
".md",
".mdx",
".mjs",
".mts",
".py",
".rb",
".rs",
".sass",
".scss",
".sh",
".sql",
".toml",
".ts",
".tsx",
".txt",
".xml",
".yaml",
".yml",
".zsh",
]
import type { ComposerPrompt } from "../types"
import type { ImageAttachmentPart, PathAttachmentPart } from "../state"
import type { AttachmentDestination } from "./destination"
import { uploads } from "./uploads"
type PromptTarget = {
current: () => ComposerPrompt
@@ -74,10 +20,11 @@ export type ComposerAttachmentConfig = {
onFile: (file: File) => Promise<unknown>,
) => Promise<void>
directory: () => string
destination: () => AttachmentDestination
isDialogActive: () => boolean
warn: () => void
duplicate: () => void
onError: (error: unknown) => void
onUploadError: (error: unknown) => void
readClipboardImage?: () => Promise<File | null>
getPathForFile?: (file: File) => string
onDragCancel?: (callback: () => void) => () => void
@@ -102,13 +49,23 @@ export function createComposerAttachments(
if (!editor) return
return { prompt, cursor: prompt.cursor() ?? cursorPosition(editor) }
}
const add = async (file: File, toast = true, target = capture(), clipboard = false) => {
// Uploads this composer started; they finish (or fail) even if the composer unmounts.
const [pending, setPending] = createStore<{ ids: string[] }>({ ids: [] })
// Media the model reads natively travels inline with the prompt, so its bytes live in the draft
// store. Everything else, including text, reaches the model as a path on the server that its
// tools open; those bytes never enter the store, and never get base64-encoded into the request.
const add = async (file: File, target = capture(), clipboard = false) => {
if (!target) return false
const mime = await attachmentMime(file)
if (!mime) {
if (toast) input.warn()
return false
}
const destination = input.destination()
if (native(mime, destination.input) && file.size <= MAX_INLINE_BYTES) return addInline(file, mime, target, clipboard)
const sourcePath = input.getPathForFile?.(file) || undefined
if (destination.local && sourcePath) return addPath(target, { filename: file.name, mime, path: sourcePath })
void stage(file, mime, target, destination)
return true
}
const addInline = async (file: File, mime: string, target: NonNullable<ReturnType<typeof capture>>, clipboard: boolean) => {
const blob = input.store ? await input.store(file) : await createBlobReference(file)
const sourcePath = input.getPathForFile?.(file) || undefined
// Native clipboard images arrive with a fresh timestamped filename on every paste, so identical
@@ -127,24 +84,45 @@ export function createComposerAttachments(
input.duplicate()
return true
}
const attachment: ComposerAttachment = {
type: "image",
id: uuid(),
filename: file.name,
sourcePath,
mime,
blob,
}
const attachment: ImageAttachmentPart = { type: "image", id: uuid(), filename: file.name, sourcePath, mime, blob }
target.prompt.set([...target.prompt.current(), attachment], target.cursor)
return true
}
const addAttachments = async (files: File[], toast = true, target = capture()) => {
const found = await files.reduce(async (result, file) => {
const addPath = (
target: NonNullable<ReturnType<typeof capture>>,
attachment: Pick<PathAttachmentPart, "filename" | "mime" | "path">,
) => {
if (target.prompt.current().some((part) => part.type === "path" && part.path === attachment.path)) {
input.duplicate()
return true
}
target.prompt.set([...target.prompt.current(), { type: "path", id: uuid(), ...attachment }], target.prompt.cursor())
return true
}
const stage = async (
file: File,
mime: string,
target: NonNullable<ReturnType<typeof capture>>,
destination: AttachmentDestination,
) => {
const id = uuid()
setPending("ids", (ids) => [...ids, id])
const path = await uploads
.track({ id, filename: file.name, mime, size: file.size }, (report, signal) =>
destination.upload(file, report, signal),
)
.catch((error: unknown) => {
input.onUploadError(error)
return undefined
})
.finally(() => setPending("ids", (ids) => ids.filter((item) => item !== id)))
if (path) addPath(target, { filename: file.name, mime, path })
}
const addAttachments = async (files: File[], target = capture()) => {
return files.reduce(async (result, file) => {
const previous = await result
return (await add(file, false, target)) || previous
return (await add(file, target)) || previous
}, Promise.resolve(false))
if (!found && files.length > 0 && toast) input.warn()
return found
}
const handlePaste = async (event: ClipboardEvent) => {
const clipboardData = event.clipboardData
@@ -159,13 +137,13 @@ export function createComposerAttachments(
return file ? [file] : []
})
if (files.length > 0) {
await addAttachments(files, true, target)
await addAttachments(files, target)
return
}
const plainText = clipboardData.getData("text/plain") ?? ""
if (input.readClipboardImage && !plainText) {
const file = await input.readClipboardImage()
if (file && (await add(file, true, target, true))) return
if (file && (await add(file, target, true))) return
}
if (!plainText) return
const text = plainText.includes("\r") ? plainText.replace(/\r\n?/g, "\n") : plainText
@@ -218,20 +196,33 @@ export function createComposerAttachments(
addAttachments,
handlePaste,
handleDrop,
/** Uploads still in flight for this composer; sending waits for them. */
pending: () => uploads.items().filter((item) => pending.ids.includes(item.id)),
cancel(id: string) {
uploads.items().find((item) => item.id === id)?.cancel()
},
pick(fallback: () => void) {
if (!input.picker) {
fallback()
return
}
void input
.picker({ defaultPath: input.directory(), multiple: true, accept: accepted }, (file) => add(file))
.catch(input.onError)
void input.picker({ defaultPath: input.directory(), multiple: true }, (file) => add(file)).catch(input.onError)
},
}
}
const imageMimes = new Set(["image/png", "image/jpeg", "image/gif", "image/webp"])
// The server rejects inline attachments above this size, so larger media takes the path route.
const MAX_INLINE_BYTES = 20 * 1024 * 1024
// Mirrors the media the server forwards to the model as message content.
function native(mime: string, input: AttachmentDestination["input"]) {
if (imageMimes.has(mime)) return input.image
if (mime === "application/pdf") return input.pdf
return false
}
const imageExtensions = new Map([
["gif", "image/gif"],
["jpeg", "image/jpeg"],
@@ -249,6 +240,8 @@ const textMimes = new Set([
"application/yaml",
])
// Text-like files normalize to text/plain so the chip labels them as text; every other file keeps
// a binary type. Delivery is decided separately: native media inline, everything else by path.
async function attachmentMime(file: File) {
const type = file.type.split(";", 1)[0]?.trim().toLowerCase() ?? ""
if (imageMimes.has(type) || type === "application/pdf") return type
@@ -259,10 +252,11 @@ async function attachmentMime(file: File) {
if (type.startsWith("text/") || textMimes.has(type) || type.endsWith("+json") || type.endsWith("+xml")) {
return "text/plain"
}
const binary = type || "application/octet-stream"
const bytes = new Uint8Array(await file.slice(0, 4096).arrayBuffer())
if (bytes.some((byte) => byte === 0)) return
if (bytes.some((byte) => byte === 0)) return binary
const control = bytes.filter((byte) => byte < 9 || (byte > 13 && byte < 32)).length
if (bytes.length > 0 && control / bytes.length > 0.3) return
if (bytes.length > 0 && control / bytes.length > 0.3) return binary
return "text/plain"
}
@@ -0,0 +1,57 @@
import type { Accessor } from "solid-js"
import { useServer } from "@/runtime/server/current"
import { useServerSDK } from "@/runtime/server/client"
import { authTokenFromCredentials } from "@/runtime/server/api"
import { useWorkspaceLocation } from "@/workspaces/location"
import type { ComposerControls } from "../adapter"
// Where a prompt is headed: the model that reads it and the server that runs its tools.
export type AttachmentDestination = {
/** Input modalities the selected model reads natively. */
input: { image: boolean; pdf: boolean }
/** The server shares the client's filesystem, so an attachment's source path resolves as-is. */
local: boolean
/** Streams a file into the server's temporary directory and returns its absolute path there. */
upload: (file: File, report: (loaded: number) => void, signal: AbortSignal) => Promise<string>
}
export function useAttachmentDestination(controls: Accessor<ComposerControls>) {
const server = useServer()
const sdk = useServerSDK()
const location = useWorkspaceLocation()
return (): AttachmentDestination => ({
input: controls().model.selection.current()?.capabilities.input ?? { image: false, pdf: false },
local: server.isLocal,
upload: async (file, report, signal) => {
const info = await sdk.api.server.info({ signal })
// One directory per upload keeps the original filename without collisions; the server
// normalizes the separators and returns the resolved path.
const url = new URL("/api/experimental/fs/write", server.conn.http.url)
url.searchParams.set("location[directory]", location().directory)
url.searchParams.set("path", `${info.paths.tmp}/uploads/${crypto.randomUUID()}/${file.name}`)
return write(url, file, server.conn.http.password, report, signal)
},
})
}
// fetch cannot report upload progress and Chromium only streams request bodies over HTTP/2, so
// the one request that needs both goes through XMLHttpRequest. The browser streams the File
// from disk; nothing is buffered in the renderer.
function write(url: URL, file: File, password: string | undefined, report: (loaded: number) => void, signal: AbortSignal) {
return new Promise<string>((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open("POST", url)
xhr.responseType = "json"
xhr.setRequestHeader("content-type", "application/octet-stream")
if (password) xhr.setRequestHeader("authorization", `Basic ${authTokenFromCredentials({ password })}`)
xhr.upload.addEventListener("progress", (event) => report(event.loaded))
xhr.addEventListener("load", () => {
if (xhr.status !== 200) return reject(new Error(`Upload failed with status ${xhr.status}`))
resolve((xhr.response as { data: { path: string } }).data.path)
})
xhr.addEventListener("error", () => reject(new Error("Upload failed")))
xhr.addEventListener("abort", () => reject(new DOMException("Upload aborted", "AbortError")))
signal.addEventListener("abort", () => xhr.abort(), { once: true })
xhr.send(file)
})
}
@@ -0,0 +1,116 @@
import { createEffect, createRoot, For, on, onCleanup } from "solid-js"
import { createStore } from "solid-js/store"
import { Icon } from "@opencode/ui/icon"
import { Toast, toaster } from "@opencode/ui/toast"
import { useLanguage } from "@/runtime/i18n/language"
export type Upload = {
id: string
filename: string
mime: string
size: number
loaded: number
cancel: () => void
}
// Uploads outlive the composer that started them, so one process-wide list feeds every chip
// and the single progress toast.
const [state, setState] = createStore<{ items: Upload[] }>({ items: [] })
export const uploads = {
items: () => state.items,
/** Runs `work` while the upload is listed. Resolves to undefined when the user cancels it. */
async track<T>(
input: Pick<Upload, "id" | "filename" | "mime" | "size">,
work: (report: (loaded: number) => void, signal: AbortSignal) => Promise<T>,
): Promise<T | undefined> {
const controller = new AbortController()
setState("items", (items) => [...items, { ...input, loaded: 0, cancel: () => controller.abort() }])
try {
return await work((loaded) => setState("items", (item) => item.id === input.id, "loaded", loaded), controller.signal)
} catch (error) {
if (controller.signal.aborted) return undefined
throw error
} finally {
setState("items", (items) => items.filter((item) => item.id !== input.id))
}
},
}
// Sonner builds toast content outside the app's Solid tree: no context and no owner. This host
// lives inside the providers, lends the toast its language instance, and gives the content a
// root of its own so progress stays reactive.
export function UploadToastHost() {
const language = useLanguage()
let active: { id: number; dispose: () => void } | undefined
const dismiss = () => {
if (!active) return
toaster.dismiss(active.id)
active.dispose()
active = undefined
}
createEffect(
on(
() => state.items.length > 0,
(uploading) => {
if (!uploading) return dismiss()
if (active) return
const id = toaster.show(
(props) =>
createRoot((dispose) => {
active = { id: props.toastId, dispose }
return <UploadToast toastId={props.toastId} language={language} />
}),
{ persistent: true, resize: () => state.items.length },
)
active ??= { id, dispose: () => {} }
},
),
)
onCleanup(dismiss)
return null
}
function UploadToast(props: { toastId: number; language: ReturnType<typeof useLanguage> }) {
const percent = (item: Upload) => (item.size === 0 ? 100 : Math.floor((item.loaded / item.size) * 100))
return (
<Toast toastId={props.toastId}>
<Toast.Content>
<For each={state.items}>
{(item) => (
<div data-component="upload-row">
<div data-slot="upload-row-label">
<span data-slot="upload-row-name" title={item.filename}>
{item.filename}
</span>
<span data-slot="upload-row-percent">
{props.language.t("prompt.toast.uploading.percent", { percent: percent(item) })}
</span>
</div>
<div data-slot="upload-row-track">
<div
data-component="upload-progress"
role="progressbar"
aria-label={item.filename}
aria-valuemin={0}
aria-valuemax={100}
aria-valuenow={percent(item)}
>
<div data-slot="upload-progress-bar" style={{ width: `${percent(item)}%` }} />
</div>
<button
type="button"
data-slot="upload-row-cancel"
aria-label={props.language.t("prompt.toast.uploading.cancel")}
onClick={() => item.cancel()}
>
<Icon name="outline-xmark" />
</button>
</div>
</div>
)}
</For>
</Toast.Content>
</Toast>
)
}
+20
View File
@@ -8,6 +8,13 @@ export type PromptComment = {
origin?: "review" | "file"
}
/** An attachment the model receives as a path on the server rather than inline bytes. */
export type PromptAttachmentReference = {
name: string
mime: string
path: string
}
function selection(selection: unknown) {
if (!selection || typeof selection !== "object") return undefined
const startLine = Number((selection as FileSelection).startLine)
@@ -58,8 +65,17 @@ export function readPromptPresentation(value: unknown) {
const displayText = (value as { displayText?: unknown }).displayText
const comments = (value as { comments?: unknown }).comments
if (typeof displayText !== "string" || !Array.isArray(comments)) return
const attachments = (value as { attachments?: unknown }).attachments
return {
displayText,
attachments: (Array.isArray(attachments) ? attachments : []).flatMap((item): PromptAttachmentReference[] => {
if (!item || typeof item !== "object") return []
const name = (item as { name?: unknown }).name
const mime = (item as { mime?: unknown }).mime
const path = (item as { path?: unknown }).path
if (typeof name !== "string" || typeof mime !== "string" || typeof path !== "string") return []
return [{ name, mime, path }]
}),
comments: comments.flatMap((item): PromptComment[] => {
if (!item || typeof item !== "object") return []
const path = (item as { path?: unknown }).path
@@ -80,6 +96,10 @@ export function readPromptPresentation(value: unknown) {
}
}
export function formatAttachmentReference(input: PromptAttachmentReference) {
return `Attached file: \`${input.path}\``
}
export function formatCommentNote(input: { path: string; selection?: FileSelection; comment: string }) {
const start = input.selection ? Math.min(input.selection.startLine, input.selection.endLine) : undefined
const end = input.selection ? Math.max(input.selection.startLine, input.selection.endLine) : undefined
+6 -6
View File
@@ -7,7 +7,7 @@ import type {
ComposerPersistedState,
ComposerPrompt,
} from "../types"
import { promptLength } from "../prompt-parts"
import { isAttachment, promptLength } from "../prompt-parts"
export type ComposerStateStore = [
Store<ComposerPersistedState> | Accessor<Store<ComposerPersistedState>>,
@@ -48,7 +48,7 @@ export function createComposerEditorActions(input: ComposerStateStoreInput) {
setStore()((state) => ({
prompt: [
{ type: "text", content, start: 0, end: content.length },
...state.prompt.filter((part) => part.type === "image"),
...state.prompt.filter(isAttachment),
],
cursor: content.length,
retry: undefined,
@@ -83,7 +83,7 @@ export function createComposerEditorActions(input: ComposerStateStoreInput) {
clearRetry()
},
removeAttachment(id: string) {
setStore()("prompt", (parts) => parts.filter((part) => part.type !== "image" || part.id !== id))
setStore()("prompt", (parts) => parts.filter((part) => !isAttachment(part) || part.id !== id))
clearRetry()
},
}
@@ -93,7 +93,7 @@ function insertText(prompt: ComposerPrompt, cursor: number, content: string): Co
let position = 0
let inserted = false
const parts = prompt.flatMap<ComposerPrompt[number]>((part) => {
if (part.type === "image") return [part]
if (isAttachment(part)) return [part]
const start = position
position += part.content.length
if (inserted) return [part]
@@ -121,7 +121,7 @@ function insertMention(
}
let position = 0
const parts = prompt.flatMap<ComposerPrompt[number]>((part) => {
if (part.type === "image") return [part]
if (isAttachment(part)) return [part]
const partStart = position
position += part.content.length
if (part.type !== "text" || start < partStart || end > position) return [part]
@@ -139,7 +139,7 @@ function insertMention(
function withOffsets(prompt: ComposerPrompt): ComposerPrompt {
let offset = 0
return prompt.map((part) => {
if (part.type === "image") return part
if (isAttachment(part)) return part
const next = { ...part, start: offset, end: offset + part.content.length }
offset = next.end
return next
+59 -15
View File
@@ -1,9 +1,10 @@
import { createEffect, createMemo, createSignal, For, onCleanup, onMount, Show, type JSX } from "solid-js"
import { createEffect, createMemo, createResource, createSignal, For, onCleanup, onMount, Show, type JSX } from "solid-js"
import { createStore } from "solid-js/store"
import { FileIcon } from "@opencode/ui/file-icon"
import { Icon } from "@opencode/ui/icon"
import { IconButton } from "@opencode/ui/icon-button"
import { createAnimatedPresence } from "@/runtime/animated-presence"
import { resolveBlobUrl } from "@/runtime/persistence/drafts"
import { ProviderIcon } from "@opencode/ui/provider-icon"
import { useI18n } from "@opencode/ui/context/i18n"
import { Button } from "@opencode/ui/button"
@@ -12,6 +13,8 @@ import { Menu } from "@opencode/ui/menu"
import { Tooltip } from "@opencode/ui/tooltip"
import { ScrollView } from "@opencode/ui/scroll-view"
import { AttachmentCard } from "@opencode/session-ui/attachment-card"
import { ProgressCircle } from "@opencode/ui/progress-circle"
import type { Upload } from "../attachments/uploads"
import { CommentCard } from "@opencode/session-ui/comment-card"
import { typeLabel } from "@opencode/session-ui/message-file"
import { Skill } from "@opencode/schema/skill"
@@ -24,6 +27,7 @@ import type {
ComposerSuggestion,
} from "../types"
import type { ComposerEditorModel, ComposerSelectControl } from "./interaction"
import { isAttachment } from "../prompt-parts"
import "../attachments/attachments.css"
import "./editor.css"
@@ -102,7 +106,6 @@ export function ComposerEditor(props: ComposerEditorProps) {
ref={props.controller.setFileInput}
type="file"
multiple
accept="image/png,image/jpeg,image/gif,image/webp,application/pdf,text/*,application/json,application/ld+json,application/toml,application/x-toml,application/x-yaml,application/xml,application/yaml,.c,.cc,.cjs,.conf,.cpp,.css,.csv,.cts,.env,.go,.gql,.graphql,.h,.hh,.hpp,.htm,.html,.ini,.java,.js,.json,.jsx,.log,.md,.mdx,.mjs,.mts,.py,.rb,.rs,.sass,.scss,.sh,.sql,.toml,.ts,.tsx,.txt,.xml,.yaml,.yml,.zsh"
class="hidden"
onChange={(event) => {
const list = event.currentTarget.files
@@ -149,11 +152,13 @@ export function ComposerEditor(props: ComposerEditorProps) {
<Show when={state.mode === "normal"}>
<ComposerAttachments
attachments={props.controller.attachments()}
uploads={props.controller.uploads()}
comments={props.controller.comments()}
activeCommentID={state.activeContextID}
removeLabel={i18n.t("ui.promptInput.removeAttachment")}
onAttachmentClick={props.controller.openAttachment}
onAttachmentRemove={(attachment) => props.controller.removeAttachment(attachment.id)}
onUploadCancel={(upload) => props.controller.cancelUpload(upload.id)}
onCommentClick={(comment) => props.controller.toggleContext(comment.key)}
onCommentRemove={(comment) => props.controller.removeContext(comment.key)}
/>
@@ -192,9 +197,9 @@ export function ComposerEditor(props: ComposerEditorProps) {
onInput={(event) => {
const cursor = composerCursor(event.currentTarget)
const prompt = parseComposerEditor(event.currentTarget)
const images = props.controller.parts().filter((part) => part.type === "image")
const attachments = props.controller.parts().filter(isAttachment)
localInput = true
props.controller.onInput(prompt.map((part) => part.content).join(""), [...prompt, ...images], cursor)
props.controller.onInput(prompt.map((part) => part.content).join(""), [...prompt, ...attachments], cursor)
}}
onKeyDown={(event) => {
if (!view.draftOnly && props.controller.onKeyDown(event)) return
@@ -349,7 +354,7 @@ function renderComposerEditor(editor: HTMLDivElement, prompt: ComposerPrompt) {
const active = document.activeElement === editor
editor.replaceChildren(
...prompt.flatMap<Node>((part) => {
if (part.type === "image") return []
if (isAttachment(part)) return []
if (part.type === "text") return [document.createTextNode(part.content)]
const mention = document.createElement("span")
mentionParts.set(mention, part)
@@ -476,17 +481,22 @@ function composerCursor(editor: HTMLDivElement) {
export function ComposerAttachments(props: {
attachments: ComposerAttachment[]
uploads?: Upload[]
comments?: ComposerComment[]
activeCommentID?: string
removeLabel: string
onAttachmentClick?: (attachment: ComposerAttachment) => void
onAttachmentRemove: (attachment: ComposerAttachment) => void
onUploadCancel?: (upload: Upload) => void
onCommentClick?: (comment: ComposerComment) => void
onCommentRemove?: (comment: ComposerComment) => void
}) {
const i18n = useI18n()
const percent = (upload: Upload) => (upload.size === 0 ? 100 : Math.floor((upload.loaded / upload.size) * 100))
return (
<Show when={props.attachments.length > 0 || (props.comments?.length ?? 0) > 0}>
<Show
when={props.attachments.length > 0 || (props.uploads?.length ?? 0) > 0 || (props.comments?.length ?? 0) > 0}
>
<div data-component="composer-attachments" data-slot="composer-attachments" class="relative">
<div
data-slot="composer-attachments-scroll"
@@ -523,22 +533,34 @@ export function ComposerAttachments(props: {
<For each={props.attachments}>
{(attachment) => (
<div class="relative group shrink-0">
<Tooltip value={attachment.filename} placement="top" contentClass="break-all">
<Tooltip
value={attachment.type === "path" ? attachment.path : attachment.filename}
placement="top"
contentClass="break-all"
>
<Show
when={attachment.mime.startsWith("image/")}
when={attachment.type === "image" && attachment.mime.startsWith("image/") ? attachment : undefined}
fallback={
<AttachmentCard title={attachment.filename}>
{typeLabel(attachment.filename, attachment.mime, i18n.t("ui.common.file"))}
</AttachmentCard>
}
>
<img
src={attachment.blob.url}
alt={attachment.filename}
class="w-[58px] h-[46px] rounded-[6px] object-cover"
onClick={() => props.onAttachmentClick?.(attachment)}
/>
<div class="absolute inset-0 rounded-[6px] shadow-[inset_0_0_0_0.5px_var(--v2-border-border-base)] pointer-events-none" />
{(image) => {
// Restored drafts and history carry image ids only; bytes load when shown.
const [url] = createResource(() => image().blob, resolveBlobUrl)
return (
<>
<img
src={url() ?? ""}
alt={attachment.filename}
class="w-[58px] h-[46px] rounded-[6px] object-cover"
onClick={() => props.onAttachmentClick?.(attachment)}
/>
<div class="absolute inset-0 rounded-[6px] shadow-[inset_0_0_0_0.5px_var(--v2-border-border-base)] pointer-events-none" />
</>
)
}}
</Show>
</Tooltip>
<button
@@ -552,6 +574,28 @@ export function ComposerAttachments(props: {
</div>
)}
</For>
<For each={props.uploads ?? []}>
{(upload) => (
<div class="relative group shrink-0" data-slot="composer-upload">
<Tooltip value={upload.filename} placement="top" contentClass="break-all">
<AttachmentCard title={upload.filename}>
<span class="inline-flex items-center gap-1">
<ProgressCircle percentage={percent(upload)} />
{i18n.t("ui.promptInput.uploading", { percent: percent(upload) })}
</span>
</AttachmentCard>
</Tooltip>
<button
type="button"
onClick={() => props.onUploadCancel?.(upload)}
class="absolute -top-1 -end-1 size-4 rounded-full bg-v2-icon-icon-muted outline-solid outline-1 outline-v2-icon-icon-contrast flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity"
aria-label={i18n.t("ui.promptInput.cancelUpload")}
>
<Icon name="outline-xmark" class="text-v2-icon-icon-contrast" />
</button>
</div>
)}
</For>
</div>
<div
data-slot="composer-attachments-fade-left"
@@ -2,6 +2,7 @@ import { createEffect, type Accessor } from "solid-js"
import { createStore, reconcile } from "solid-js/store"
import { useFilteredList } from "@opencode/ui/hooks"
import { createComposerAttachments, type ComposerAttachmentConfig } from "../attachments/attachments"
import type { Upload } from "../attachments/uploads"
import { createComposerEditorActions, type ComposerStateStoreInput } from "./actions"
import type {
ComposerAttachment,
@@ -18,7 +19,7 @@ import {
type ComposerInteractionCommand,
type ComposerInteractionEvent,
} from "../suggestions/machine"
import { clonePrompt, promptLength } from "../prompt-parts"
import { clonePrompt, isAttachment, promptLength } from "../prompt-parts"
import type { ComposerQueue } from "../adapter"
export type ComposerSelectControl = {
@@ -74,7 +75,7 @@ export function createComposerEditor(input: {
const draft = createComposerEditorActions(input.store)
const [state, setState] = input.state ?? createComposerEditorState(draft.state.mode)
function addPart(part: ComposerPersistedState["prompt"][number]) {
if (part.type === "image") return false
if (isAttachment(part)) return false
if (part.type === "file" || part.type === "agent") {
draft.addMention(part)
return true
@@ -169,7 +170,7 @@ export function createComposerEditor(input: {
if (!action || state.popover.type !== "command-menu") result.commands.forEach(execute)
if (action && event.item.kind === "command" && state.popover.type !== "command-menu") {
draft.setPrompt(
draft.state.prompt.filter((part): part is ComposerAttachment => part.type === "image"),
draft.state.prompt.filter(isAttachment),
0,
)
}
@@ -315,7 +316,13 @@ export function createComposerEditor(input: {
return draft.state.context.items.filter((item) => !!item.comment?.trim())
},
attachments(): ComposerAttachment[] {
return draft.state.prompt.filter((part): part is ComposerAttachment => part.type === "image")
return draft.state.prompt.filter(isAttachment)
},
uploads(): Upload[] {
return attachments?.pending() ?? []
},
cancelUpload(id: string) {
attachments?.cancel(id)
},
toggleContext(id: string) {
dispatch({ type: "context.active", id })
@@ -336,11 +343,12 @@ export function createComposerEditor(input: {
canSubmit() {
if (input.view.submit.available?.() === false) return false
if (input.view.draftOnly) return false
if (attachments?.pending().length) return false
const persisted = draft.state
if (state.mode === "shell") {
return persisted.prompt.some((part) => "content" in part && !!part.content.trim())
}
if (persisted.prompt.some((part) => part.type === "image")) return true
if (persisted.prompt.some(isAttachment)) return true
if (persisted.context.items.some((item) => !!item.comment?.trim())) return true
return persisted.prompt.some((part) => "content" in part && !!part.content.trim())
},
@@ -369,6 +377,7 @@ export function createComposerEditor(input: {
submit(options?: { alternate?: boolean }) {
if (input.view.submit.available?.() === false) return
if (input.view.draftOnly) return
if (attachments?.pending().length) return
input.view.submit.onSubmit(options)
dispatch({ type: "popover.close" })
},
+4 -4
View File
@@ -1,6 +1,6 @@
import type { Prompt } from "@/composer/state"
import type { SelectedLineRange } from "@/workspaces/files/model"
import { clonePrompt } from "../prompt-parts"
import { clonePrompt, isAttachment } from "../prompt-parts"
import type { PromptHistoryComment, PromptHistoryEntry } from "../schema"
export type { PromptHistoryComment, PromptHistoryEntry } from "../schema"
@@ -35,9 +35,9 @@ export function prependHistoryEntry(
.map((part) => ("content" in part ? part.content : ""))
.join("")
.trim()
const hasImages = prompt.some((part) => part.type === "image")
const hasAttachments = prompt.some(isAttachment)
const hasComments = comments.some((comment) => !!comment.comment.trim())
if (!text && !hasImages && !hasComments) return entries
if (!text && !hasAttachments && !hasComments) return entries
const entry = {
prompt: clonePrompt(prompt),
@@ -86,7 +86,7 @@ function isPromptEqual(entryA: PromptHistoryStoredEntry, entryB: PromptHistorySt
if (partA.type === "skill") {
if (partB.type !== "skill" || partA.id !== partB.id || partA.name !== partB.name) return false
}
if (partA.type === "image" && partA.id !== (partB.type === "image" ? partB.id : "")) return false
if (isAttachment(partA) && partA.id !== (isAttachment(partB) ? partB.id : "")) return false
}
if (entryA.comments.length !== entryB.comments.length) return false
for (let i = 0; i < entryA.comments.length; i++) {
+17 -9
View File
@@ -11,17 +11,19 @@ import { useLanguage } from "@/runtime/i18n/language"
import { useLayout } from "@/shell/state/layout"
import { usePlatform } from "@/runtime/platform/platform"
import { useWorkspaceLocation } from "@/workspaces/location"
import { resolveBlobUrl } from "@/runtime/persistence/drafts"
import { useData, useServer } from "@/runtime/server/current"
import { createSessionTabs } from "@/session/helpers"
import { showToast } from "@/shell/notifications/toast"
import { formatServerError } from "@/runtime/server/errors"
import { Skill } from "@opencode/schema/skill"
import type { ComposerAdapter, ComposerControls, ComposerQueue } from "./adapter"
import type { ImageAttachmentPart } from "./state"
import { isAttachment } from "./prompt-parts"
import type { PromptHistoryComment } from "./history/entry"
import { createComposerHistory } from "./history/store"
import { composerPlaceholder } from "./placeholder"
import { createComposerSubmit } from "./submit"
import { useAttachmentDestination } from "./attachments/destination"
export type ComposerModel = ComposerEditorModel & {
readonly model: ComposerControls["model"]
@@ -72,7 +74,7 @@ export function createComposerModel(adapter: ComposerAdapter, options?: { queue?
}, [])
})
const attachments = createMemo(() =>
prompt.current().filter((part): part is ImageAttachmentPart => part.type === "image"),
prompt.current().filter(isAttachment),
)
const commentCount = createMemo(() => {
if (mode() === "shell") return 0
@@ -319,8 +321,12 @@ export function createComposerModel(adapter: ComposerAdapter, options?: { queue?
onContextRemove(item) {
if (item?.commentID) comments.remove(item.path, item.commentID)
},
openAttachment: (attachment) =>
dialog.show(() => createComponent(ImagePreview, { src: attachment.blob.url, alt: attachment.filename })),
openAttachment: (attachment) => {
if (attachment.type !== "image") return
void resolveBlobUrl(attachment.blob).then((src) => {
if (src) dialog.show(() => createComponent(ImagePreview, { src, alt: attachment.filename }))
})
},
openContext(key) {
const item = controller.contextItem(key)
if (item) openComment(item, adapter.controls(), layout, files, comments)
@@ -338,13 +344,15 @@ export function createComposerModel(adapter: ComposerAdapter, options?: { queue?
attachments: {
picker: platform.openAttachmentPickerDialog,
directory: () => sdk().directory,
destination: useAttachmentDestination(adapter.controls),
isDialogActive: () => !!dialog.active,
warn: () =>
showToast({
title: language.t("prompt.toast.pasteUnsupported.title"),
description: language.t("prompt.toast.pasteUnsupported.description"),
}),
duplicate: () => showToast({ title: language.t("prompt.toast.attachmentDuplicate.title") }),
onUploadError: (error) =>
showToast({
variant: "error",
title: language.t("prompt.toast.uploadFailed.title"),
description: composerErrorMessage(language, error),
}),
onError: (error) =>
showToast({
variant: "error",
+7 -2
View File
@@ -1,4 +1,9 @@
import type { Prompt } from "./state"
import type { ContentPart, ImageAttachmentPart, PathAttachmentPart, Prompt } from "./state"
/** Parts that sit beside the text rather than inside it. */
export function isAttachment(part: ContentPart): part is ImageAttachmentPart | PathAttachmentPart {
return part.type === "image" || part.type === "path"
}
export function clonePrompt(prompt: Prompt): Prompt {
return prompt.map((part) =>
@@ -17,7 +22,7 @@ export function appendPrompt(prompt: Prompt, following: Prompt): Prompt {
...clonePrompt(prompt),
{ type: "text", content: "\n\n", start, end: offset },
...clonePrompt(following).map((part) =>
part.type === "image" ? part : { ...part, start: part.start + offset, end: part.end + offset },
isAttachment(part) ? part : { ...part, start: part.start + offset, end: part.end + offset },
),
]
}
+9 -21
View File
@@ -1,8 +1,12 @@
import { describe, expect, test } from "bun:test"
import { Skill } from "@opencode/schema/skill"
import type { Prompt } from "@/composer/state"
import type { ImageAttachmentPart, Prompt } from "@/composer/state"
import { buildPromptRequest } from "./request"
function inline(filename: string, mime: string, extra?: Partial<ImageAttachmentPart>) {
return { type: "image" as const, id: `img_${filename}`, filename, mime, dataUrl: `data:${mime};base64,AAA`, ...extra }
}
describe("buildPromptRequest", () => {
test("builds text, files, and agents from the prompt", () => {
const prompt: Prompt = [
@@ -21,9 +25,7 @@ describe("buildPromptRequest", () => {
const result = buildPromptRequest({
prompt,
context: [{ key: "ctx:1", type: "file", path: "src/bar.ts", comment: "check this" }],
images: [
{ type: "image", id: "img_1", filename: "a.png", mime: "image/png", dataUrl: "data:image/png;base64,AAA" },
],
images: [inline("a.png", "image/png")],
text: "hello @src/foo.ts @planner",
sessionDirectory: "/repo",
})
@@ -45,16 +47,7 @@ describe("buildPromptRequest", () => {
const result = buildPromptRequest({
prompt: [{ type: "text", content: "check these", start: 0, end: 11 }],
context: [],
images: [
{ type: "image", id: "img_1", filename: "a.png", mime: "image/png", dataUrl: "data:image/png;base64,AAA" },
{
type: "image",
id: "img_2",
filename: "b.pdf",
mime: "application/pdf",
dataUrl: "data:application/pdf;base64,BBB",
},
],
images: [inline("a.png", "image/png"), inline("b.pdf", "application/pdf")],
text: "check these",
sessionDirectory: "/repo",
})
@@ -70,14 +63,9 @@ describe("buildPromptRequest", () => {
prompt: [],
context: [],
images: [
{
type: "image",
id: "img_external",
filename: "opencode.global.dat",
inline("opencode.global.dat", "text/plain", {
sourcePath: "C:\\Users\\Luke\\AppData\\Roaming\\ai.opencode.desktop.beta\\opencode.global.dat",
mime: "text/plain",
dataUrl: "data:text/plain;base64,AAA",
},
}),
],
text: "inspect this",
sessionDirectory: "C:\\Repos\\sst\\opencode",
+21 -5
View File
@@ -1,8 +1,13 @@
import { getFilename } from "@opencode/util/path"
import type { FileSelection } from "@/workspaces/files/model"
import { encodeFilePath } from "@/workspaces/files/path"
import type { AgentPart, FileAttachmentPart, ImageAttachmentPart, Prompt, SkillPart } from "@/composer/state"
import { formatCommentNote, type PromptComment } from "@/composer/comment-note"
import type { AgentPart, FileAttachmentPart, ImageAttachmentPart, PathAttachmentPart, Prompt, SkillPart } from "@/composer/state"
import {
formatAttachmentReference,
formatCommentNote,
type PromptAttachmentReference,
type PromptComment,
} from "@/composer/comment-note"
// Network fields feed both boundaries; display fields keep desktop-only rendering details in the local echo.
type PromptRequest = {
@@ -12,6 +17,7 @@ type PromptRequest = {
agents: { name: string; mention?: { start: number; end: number; text: string } }[]
skills: { id: string; name: string; mention?: { start: number; end: number; text: string } }[]
comments: PromptComment[]
attachments: PromptAttachmentReference[]
}
type ContextFile = {
@@ -56,6 +62,7 @@ const parseCommentMentions = (comment: string) => {
const isFileAttachment = (part: Prompt[number]): part is FileAttachmentPart => part.type === "file"
const isAgentAttachment = (part: Prompt[number]): part is AgentPart => part.type === "agent"
const isSkillAttachment = (part: Prompt[number]): part is SkillPart => part.type === "skill"
const isPathAttachment = (part: Prompt[number]): part is PathAttachmentPart => part.type === "path"
export function buildPromptRequest(input: BuildPromptRequestInput): PromptRequest {
const skills = input.prompt.filter(isSkillAttachment).map((attachment) => ({
@@ -106,18 +113,27 @@ export function buildPromptRequest(input: BuildPromptRequestInput): PromptReques
return [file, ...mentions]
})
const images = input.images.map((attachment) => ({
const inline = input.images.map((attachment) => ({
uri: attachment.dataUrl,
mime: attachment.mime,
name: attachment.sourcePath ?? attachment.filename,
}))
// Like comments, path references reach the model as text and the message UI through metadata.
const attachments = input.prompt
.filter(isPathAttachment)
.map((part) => ({ name: part.filename, mime: part.mime, path: part.path }))
return {
text: [...(input.text.trim() ? [input.text] : []), ...comments.map(formatCommentNote)].join("\n"),
text: [
...(input.text.trim() ? [input.text] : []),
...attachments.map(formatAttachmentReference),
...comments.map(formatCommentNote),
].join("\n"),
displayText: input.text,
files: [...files, ...context, ...images],
files: [...files, ...context, ...inline],
agents,
skills,
comments,
attachments,
}
}
+6 -2
View File
@@ -136,7 +136,7 @@ describe("composer persistence schemas", () => {
).toEqual(value)
})
test("migrates inline images but never encodes dataUrl or unresolved references", () => {
test("migrates inline images, keeps store references without a URL, and never encodes dataUrl", () => {
const value = Schema.decodeUnknownSync(
Persistence.withInitial(ComposerStore, { prompt: DEFAULT_PROMPT, context: { items: [] } }),
)({
@@ -149,12 +149,16 @@ describe("composer persistence schemas", () => {
{ ...image, blob: { id: "missing" }, dataUrl: "data:image/png;base64,YQ==" },
],
})
expect(value.prompt).toHaveLength(3)
expect(value.prompt).toHaveLength(6)
expect(value.prompt[0]).toEqual({
...image,
sourcePath: "/image.png",
blob: { id: "data:image/png;base64,YQ==", url: "data:image/png;base64,YQ==" },
})
// Bytes still in the draft store resolve on use; a non-blob URL is discarded in favour of the id.
expect(value.prompt[3]).toEqual({ ...image, blob: { id: "missing", url: "" } })
expect(value.prompt[4]).toEqual({ ...image, blob: { id: "bad", url: "" } })
expect(value.prompt[5]).toEqual({ ...image, blob: { id: "missing", url: "" } })
const encoded = Schema.encodeSync(ComposerStore)(value)
expect(JSON.stringify(encoded)).not.toContain("dataUrl")
expect(
+22 -4
View File
@@ -61,11 +61,12 @@ const ImageFields = {
}
const Image = Persistence.struct({
...ImageFields,
blob: Schema.Struct({ id: Schema.NonEmptyString, url: Schema.String.check(Schema.isPattern(/^(blob:|data:)/)) }),
// An empty URL is an image whose bytes are still in the draft store; see `resolveBlobUrl`.
blob: Schema.Struct({ id: Schema.NonEmptyString, url: Schema.String.check(Schema.isPattern(/^(blob:|data:|$)/)) }),
})
// Draft storage hydrates content-addressed blobs before this codec runs. Legacy
// inline data remains usable, but unresolved references are not renderable.
// Draft storage keeps content-addressed blobs in the store until an image is shown or sent; a
// reference without a URL resolves through `resolveBlobUrl`. Legacy inline data remains usable.
export const ImageAttachmentPart = Schema.Struct({
...ImageFields,
blob: Persistence.optional(
@@ -94,7 +95,24 @@ export const ImageAttachmentPart = Schema.Struct({
)
export type ImageAttachmentPart = typeof ImageAttachmentPart.Type
export const ContentPart = Schema.Union([TextPart, FileAttachmentPart, AgentPart, SkillPart, ImageAttachmentPart])
// A file the model receives as a path on the server: its bytes never enter the draft store.
export const PathAttachmentPart = Persistence.struct({
type: Schema.Literal("path"),
id: Schema.String,
filename: Schema.String,
mime: Schema.String,
path: Schema.String,
})
export type PathAttachmentPart = typeof PathAttachmentPart.Type
export const ContentPart = Schema.Union([
TextPart,
FileAttachmentPart,
AgentPart,
SkillPart,
ImageAttachmentPart,
PathAttachmentPart,
])
export type ContentPart = typeof ContentPart.Type
export const Prompt = Persistence.array(ContentPart)
export type Prompt = typeof Prompt.Type
+9
View File
@@ -88,6 +88,15 @@ describe("prompt state initialization", () => {
start: 5,
end: 12,
},
// A reference without a usable URL keeps its id; the bytes resolve from the draft store on use.
{
type: "image",
id: "missing-blob",
filename: "missing.png",
mime: "image/png",
blob: { id: "content-hash-without-a-url", url: "" },
},
{ type: "image", id: "invalid-url", filename: "invalid.png", mime: "image/png", blob: { id: "hash", url: "" } },
{
type: "image",
id: "legacy",
+1
View File
@@ -23,6 +23,7 @@ export type {
FileAttachmentPart,
FileContextItem,
ImageAttachmentPart,
PathAttachmentPart,
Prompt,
PromptModel,
SkillPart,
@@ -1,5 +1,5 @@
import type { ComposerState, ContextItem, Prompt } from "./state"
import { appendPrompt, clonePrompt } from "./prompt-parts"
import { appendPrompt, clonePrompt, isAttachment } from "./prompt-parts"
export type ComposerStateTarget = ReturnType<ComposerState["capture"]>
@@ -22,7 +22,7 @@ export function createComposerSubmission(input: {
if (initial !== target) {
initial.reset()
// A preparing session may already have an unsent follow-up in its promoted composer.
if (preserveDraft && target.current().some((part) => part.type === "image" || part.content.length > 0))
if (preserveDraft && target.current().some((part) => isAttachment(part) || part.content.length > 0))
following = clonePrompt(target.current())
}
if (!following) target.reset()
+21 -10
View File
@@ -8,7 +8,8 @@ import type { ComposerAdapter, ComposerDelivery, ComposerSelection, ComposerSess
import { createComposerSubmission } from "./submission-state"
import { buildPromptRequest } from "./request"
import { setCursorPosition } from "./editor/dom"
import { blobDataUrl } from "@/runtime/persistence/drafts"
import { blobDataUrl, resolveBlobUrl } from "@/runtime/persistence/drafts"
import { isAttachment } from "./prompt-parts"
import type { ModelSelection } from "@/providers/models/selection"
const submitting = new WeakSet<object>()
@@ -58,12 +59,22 @@ export function createComposerSubmit(input: ComposerSubmitInput) {
selection: item.selection ? { ...item.selection } : undefined,
})),
})
const value = readSubmission(input, submission.prompt, submission.context, options?.alternate ?? false)
if (!value) {
const read = readSubmission(input, submission.prompt, submission.context, options?.alternate ?? false)
if (!read) {
if (input.adapter.working() && input.adapter.kind === "active-session") void input.adapter.interrupt()
return
}
if (submitting.has(input.adapter.state)) return
// Images restored from a draft or history carry ids only; the optimistic message shows their URLs.
const value = {
...read,
images: await Promise.all(
read.images.map(async (image) => ({
...image,
blob: { ...image.blob, url: (await resolveBlobUrl(image.blob)) ?? image.blob.url },
})),
),
}
submitting.add(input.adapter.state)
const comments = input.comments.capture()
// Capture command intent before starting a session in a worktree whose catalog has not loaded.
@@ -151,6 +162,9 @@ function handoffMessage(value: ComposerSubmission): SessionMessageUser {
})),
metadata: {
displayText: value.text,
attachments: value.prompt.flatMap((part) =>
part.type === "path" ? [{ name: part.filename, mime: part.mime, path: part.path }] : [],
),
comments: value.context.flatMap((item) =>
item.comment?.trim()
? [
@@ -185,7 +199,7 @@ function readSubmission(
if (mode === "shell" && !text.trim()) return
const images = prompt.filter((part): part is ImageAttachmentPart => part.type === "image")
const comments = context.filter((item) => !!item.comment?.trim()).length
if (!text.trim() && images.length === 0 && comments === 0) return
if (!text.trim() && !prompt.some(isAttachment) && comments === 0) return
const controls = input.adapter.controls()
const model = controls.model.selection.current()
@@ -358,6 +372,7 @@ async function sendPrompt(
metadata: {
displayText: request.displayText,
comments: request.comments,
attachments: request.attachments,
agent: value.selection.agent,
model: {
...value.selection.model,
@@ -372,19 +387,15 @@ async function sendPrompt(
async function buildSubmissionRequest(session: ComposerSession, value: ComposerSubmission) {
const images = await Promise.all(
value.images.map(async (attachment) => ({
...attachment,
dataUrl: await blobDataUrl(attachment.blob, attachment.mime),
})),
value.images.map(async (attachment) => ({ ...attachment, dataUrl: await blobDataUrl(attachment.blob, attachment.mime) })),
)
const request = buildPromptRequest({
return buildPromptRequest({
prompt: value.prompt,
context: value.context,
images,
text: value.text,
sessionDirectory: session.directory,
})
return request
}
function failSubmission(
@@ -1,4 +1,5 @@
import type { ComposerHistoryEntry, ComposerPersistedState, ComposerSuggestion } from "../types"
import { isAttachment } from "../prompt-parts"
export type ComposerInteractionState = {
mode: "normal" | "shell"
@@ -236,7 +237,7 @@ function populated(persisted: ComposerPersistedState) {
return (
!!promptText(persisted).trim() ||
persisted.context.items.length > 0 ||
persisted.prompt.some((part) => part.type === "file" || part.type === "image")
persisted.prompt.some((part) => part.type === "file" || isAttachment(part))
)
}
+10 -2
View File
@@ -1,9 +1,17 @@
import type { AgentPart, ComposerStore, FileAttachmentPart, ImageAttachmentPart, Prompt, SkillPart } from "./state"
import type {
AgentPart,
ComposerStore,
FileAttachmentPart,
ImageAttachmentPart,
PathAttachmentPart,
Prompt,
SkillPart,
} from "./state"
export type ComposerFilePart = FileAttachmentPart
export type ComposerAgentPart = AgentPart
export type ComposerSkillPart = SkillPart
export type ComposerAttachment = ImageAttachmentPart
export type ComposerAttachment = ImageAttachmentPart | PathAttachmentPart
export type ComposerPrompt = Prompt
export type ComposerComment = ComposerStore["context"]["items"][number]
export type ComposerPersistedState = ComposerStore
-1
View File
@@ -1,5 +1,4 @@
export { AppBaseProviders, AppInterface, preloadRoute } from "./app"
export { ACCEPTED_FILE_EXTENSIONS } from "./runtime/platform/file-picker"
export { useCommand } from "./shell/commands/command"
export { currentRoute, type LayoutRoute, useCurrentRoute } from "./shell/state/layout"
export { loadLocaleDict, normalizeLocale, type Locale, useLanguage } from "./runtime/i18n/language"
+21 -2
View File
@@ -42,8 +42,14 @@
container-name: session-chat;
}
[data-component="new-session"] {
container-type: inline-size;
container-name: new-session;
}
[data-slot="session-chat-panel"]
:is([data-timeline-virtual-content], [data-component="session-composer-dock"] > div) {
:is([data-timeline-virtual-content], [data-component="session-composer-dock"] > div),
[data-slot="new-session-content"] {
translate: var(--session-summary-resize-translate, var(--session-summary-translate, none));
transition: translate 240ms cubic-bezier(0.4, 0, 0.2, 1);
@@ -53,7 +59,8 @@
}
[data-slot="session-chat-panel"][data-summary-resizing="true"]
:is([data-timeline-virtual-content], [data-component="session-composer-dock"] > div) {
:is([data-timeline-virtual-content], [data-component="session-composer-dock"] > div),
[data-component="new-session"][data-summary-resizing="true"] [data-slot="new-session-content"] {
transition: none;
}
@@ -70,6 +77,18 @@
}
}
/* Shift only while centered content overlaps the 280px summary cards and their 16px edge inset:
880px + 2 * (280px + 16px) = 1472px. Center it in the remaining space, reserving 320px. */
@container new-session (min-width: 1200px) and (width < 1472px) {
[data-component="new-session"][data-summary-open="true"] [data-slot="new-session-content"] {
--session-summary-translate: -160px;
&:dir(rtl) {
--session-summary-translate: 160px;
}
}
}
[data-slot="session-chat-panel"][data-scrollbar-hidden="true"]
[data-slot="session-timeline-scroll"]
> .scroll-view__thumb {
@@ -48,7 +48,8 @@ export function createNewSessionComposerAdapter(props: {
submitted: props.submitted,
async start(selection, submission, message) {
const draftID = props.draftID
const projectDirectory = location().directory
const currentDirectory = location().directory
const projectDirectory = data.location.info({ directory: currentDirectory })?.project.canonical ?? currentDirectory
const worktree = props.worktree()
const branch = props.branch()
const mcp = props.mcp.capture()
+26 -3
View File
@@ -1,8 +1,10 @@
import { useDialog } from "@opencode/ui/context/dialog"
import { Tooltip } from "@opencode/ui/tooltip"
import { Icon } from "@opencode/ui/icon"
import { Show, Suspense, createMemo, createSignal, lazy } from "solid-js"
import { Show, Suspense, createMemo, createSignal, lazy, onMount } from "solid-js"
import { createStore } from "solid-js/store"
import { makeEventListener } from "@solid-primitives/event-listener"
import { debounce } from "@solid-primitives/scheduled"
import { Schema } from "effect"
import createPresence from "solid-presence"
import { Composer } from "@/composer/composer"
@@ -48,7 +50,21 @@ export function NewSessionView(props: {
workspace: NewSessionWorkspaceController
mcp: DraftMcpControls
}) {
const [store, setStore] = createStore({ summary: false })
const [store, setStore] = createStore({
summary: false,
content: undefined as HTMLDivElement | undefined,
summaryResizeTranslate: undefined as string | undefined,
})
const finishWindowResize = debounce(() => setStore("summaryResizeTranslate", undefined), 150)
onMount(() => {
makeEventListener(window, "resize", () => {
if (store.summaryResizeTranslate === undefined) {
// Freeze the painted offset, including an in-flight slide, until resizing settles.
setStore("summaryResizeTranslate", store.content ? getComputedStyle(store.content).translate : "none")
}
finishWindowResize()
})
})
const [onboarding, setOnboarding, , onboardingReady] = persisted(
Persist.global("workspace-onboarding"),
WorkspaceOnboardingSchema,
@@ -63,6 +79,9 @@ export function NewSessionView(props: {
<div class="@container relative flex flex-col min-h-0 h-full flex-1">
<div
data-component="new-session"
data-summary-open={store.summary}
data-summary-resizing={store.summaryResizeTranslate !== undefined}
style={{ "--session-summary-resize-translate": store.summaryResizeTranslate }}
class="relative flex-1 min-h-0 overflow-hidden rounded-[10px] bg-v2-background-bg-base shadow-[var(--v2-elevation-raised)]"
>
<ComposerDropzone
@@ -89,7 +108,11 @@ export function NewSessionView(props: {
</SummaryPopover>
</div>
<div class="absolute inset-x-0 top-[25.375%] flex justify-center px-6">
<div class={NEW_SESSION_CONTENT_WIDTH}>
<div
ref={(element) => setStore("content", element)}
data-slot="new-session-content"
class={NEW_SESSION_CONTENT_WIDTH}
>
<NewSessionWordmark />
<div class="mt-8 flex flex-col gap-8">
<Composer model={props.composer} />
@@ -1,7 +1,12 @@
[data-component="new-session-wordmark"] {
--icon-strong-base: var(--icon-base);
--wordmark-shimmer-opacity: 0.45;
.wordmark-shimmer {
--icon-base: white;
--icon-strong-base: white;
--icon-weak-base: transparent;
/* Blend above the base logo's opacity so the sweep only adds light in either theme. */
color: white;
mix-blend-mode: screen;
@@ -13,6 +18,10 @@
}
}
[data-color-scheme="light"] [data-component="new-session-wordmark"] {
--icon-weak-base: color-mix(in srgb, var(--icon-base) 30%, transparent);
}
[data-color-scheme="dark"] [data-component="new-session-wordmark"] {
/* Preserve the previous dark highlight strength: 0.16 × 0.7 × 0.6. */
--wordmark-shimmer-opacity: 0.0672;
+4 -4
View File
@@ -1,4 +1,4 @@
import { Wordmark } from "@opencode/ui/wordmark"
import { Logo } from "@opencode/ui/logo"
import "./wordmark.css"
export function NewSessionWordmark() {
@@ -8,9 +8,9 @@ export function NewSessionWordmark() {
aria-hidden="true"
class="pointer-events-none mx-auto w-full max-w-[720px] text-v2-background-bg-inverse"
>
<div data-slot="wordmark-reveal" class="relative">
<Wordmark fade={false} class="block h-auto w-full opacity-60 [[data-color-scheme=dark]_&]:opacity-50" />
<Wordmark fade={false} muted={false} class="wordmark-shimmer absolute inset-0 h-auto w-full" />
<div data-slot="wordmark-reveal" class="relative mx-auto w-4/5">
<Logo class="block aspect-[720/129] w-full opacity-[0.16]" />
<Logo class="wordmark-shimmer absolute inset-0 aspect-[720/129] w-full" />
</div>
</div>
)
-4
View File
@@ -191,7 +191,6 @@ export const dict = {
"dialog.provider.opencode.note": "Claude፣ GPT፣ Gemini እና ሌሎችንም ጨምሮ የተስተካከሉ ሞዴሎች",
"dialog.provider.opencode.tagline": "ታማኝ የተመቻቹ ሞዴሎች",
"dialog.provider.opencodeGo.tagline": "ዝቅተኛ ወጪ ለሁሉም ሰው",
"dialog.provider.anthropic.note": "የቀጥታ የClaude ሞዴሎች፣ ፕሮ እና ማክስን ጨምሮ",
"dialog.provider.copilot.note": "AI ሞዴሎች በGitHub Copilot] በኩል ኮድ ለማድረግ እገዛ",
"dialog.provider.openai.note": "GPT ሞዴሎች ለፈጣን እና ችሎታ ላለው አጠቃላይ AI ተግባራት",
"dialog.provider.google.note": "Gemini ለፈጣን፣ የተዋቀሩ ምላሾች ሞዴሎች",
@@ -208,7 +207,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "ከ70+ በላይ አቅራቢዎችን ይመልከቱ",
"dialog.provider.viewAll": "ተጨማሪ አቅራቢዎችን አሳይ",
"provider.connect.title": "{{provider}} አገናኝ",
"provider.connect.title.anthropicProMax": "በClaude Pro/Max ይግቡ",
"provider.connect.selectMethod": "የመግቢያ ዘዴን ለ{{provider}} ምረጥ።",
"provider.connect.method.apiKey": "API ቁልፍ",
"provider.connect.method.browser": "አሳሽ",
@@ -371,8 +369,6 @@ export const dict = {
"prompt.attachment.remove": "ዓባሪን አስወግድ",
"prompt.action.send": "ላክ",
"prompt.action.stop": "አቁም",
"prompt.toast.pasteUnsupported.title": "የማይደገፍ ዓባሪ",
"prompt.toast.pasteUnsupported.description": "ምስሎች፣ ፒዲኤፎች ወይም የጽሑፍ ፋይሎች ብቻ እዚህ ጋር ሊጣመሩ ይችላሉ።",
"prompt.toast.attachmentDuplicate.title": "ይህ ፋይል አስቀድሞ ተሰቅሏል",
"prompt.toast.modelAgentRequired.title": "ወኪል እና ሞዴል ይምረጡ",
"prompt.toast.modelAgentRequired.description": "ፕሮምፕት ከመላክዎ በፊት ወኪል እና ሞዴል ይምረጡ።",
-4
View File
@@ -198,7 +198,6 @@ export const dict = {
"dialog.provider.opencode.note": "نماذج مختارة تتضمن Claude و GPT و Gemini والمزيد",
"dialog.provider.opencode.tagline": "نماذج موثوقة ومحسنة",
"dialog.provider.opencodeGo.tagline": "اشتراك منخفض التكلفة للجميع",
"dialog.provider.anthropic.note": "وصول مباشر إلى نماذج Claude، بما فيها Pro و Max",
"dialog.provider.copilot.note": "نماذج ذكاء اصطناعي للمساعدة في البرمجة عبر GitHub Copilot",
"dialog.provider.openai.note": "نماذج GPT لمهام الذكاء الاصطناعي العامة السريعة والمتقدمة",
"dialog.provider.google.note": "نماذج Gemini لاستجابات سريعة ومنظمة",
@@ -215,7 +214,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "عرض أكثر من 70 موفرًا إضافيًا",
"dialog.provider.viewAll": "عرض المزيد من الموفرين",
"provider.connect.title": "الاتصال بـ {{provider}}",
"provider.connect.title.anthropicProMax": "تسجيل الدخول باستخدام Claude Pro/Max",
"provider.connect.selectMethod": "حدد طريقة تسجيل الدخول لـ {{provider}}.",
"provider.connect.method.apiKey": "مفتاح API",
"provider.connect.method.browser": "المتصفح",
@@ -380,9 +378,7 @@ export const dict = {
"prompt.attachment.remove": "إزالة المرفق",
"prompt.action.send": "إرسال",
"prompt.action.stop": "إيقاف",
"prompt.toast.pasteUnsupported.title": "مرفق غير مدعوم",
"prompt.toast.attachmentDuplicate.title": "تم تحميل هذا الملف بالفعل",
"prompt.toast.pasteUnsupported.description": "يمكن إرفاق الصور أو ملفات PDF أو الملفات النصية فقط هنا.",
"prompt.toast.modelAgentRequired.title": "حدد وكيلاً ونموذجاً",
"prompt.toast.modelAgentRequired.description": "اختر وكيلاً ونموذجاً قبل إرسال الموجه.",
"prompt.toast.worktreeCreateFailed.title": "فشل إنشاء شجرة العمل",
-4
View File
@@ -194,7 +194,6 @@ export const dict = {
"dialog.provider.opencode.note": "Claude, GPT, Gemini və daha çoxu daxil olmaqla seçilmiş modellər",
"dialog.provider.opencode.tagline": "Etibarlı optimallaşdırılmış modellər",
"dialog.provider.opencodeGo.tagline": "Hamı üçün aşağı qiymətli abunəlik",
"dialog.provider.anthropic.note": "Pro və Max daxil olmaqla Claude modellərinə birbaşa giriş",
"dialog.provider.copilot.note": "GitHub Copilot vasitəsilə kodlaşdırma yardımı üçün AI modelləri",
"dialog.provider.openai.note": "Sürətli və bacarıqlı ümumi AI tapşırıqları üçün GPT modelləri",
"dialog.provider.google.note": "Sürətli, strukturlaşdırılmış cavablar üçün Gemini modelləri",
@@ -211,7 +210,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Daha 70+ provayderə baxın",
"dialog.provider.viewAll": "Daha çox provayder göstər",
"provider.connect.title": "{{provider}} provayderini qoş",
"provider.connect.title.anthropicProMax": "Claude Pro/Max ilə daxil ol",
"provider.connect.selectMethod": "{{provider}} üçün giriş üsulunu seçin.",
"provider.connect.method.apiKey": "API açarı",
"provider.connect.method.browser": "Brauzer",
@@ -378,8 +376,6 @@ export const dict = {
"prompt.attachment.remove": "Əlavəni sil",
"prompt.action.send": "Göndər",
"prompt.action.stop": "Dayandır",
"prompt.toast.pasteUnsupported.title": "Dəstəklənməyən əlavə",
"prompt.toast.pasteUnsupported.description": "Buraya yalnız şəkillər, PDF-lər və ya mətn faylları əlavə edilə bilər.",
"prompt.toast.attachmentDuplicate.title": "Bu fayl artıq yüklənib",
"prompt.toast.modelAgentRequired.title": "Agent və model seçin",
"prompt.toast.modelAgentRequired.description": "Prompt göndərməzdən əvvəl agent və model seçin.",
-4
View File
@@ -194,7 +194,6 @@ export const dict = {
"dialog.provider.opencode.note": "Подбрани модели, включително Claude, GPT, Gemini и други",
"dialog.provider.opencode.tagline": "Надеждни оптимизирани модели",
"dialog.provider.opencodeGo.tagline": "Абонамент на ниска цена за всеки",
"dialog.provider.anthropic.note": "Директен достъп до Claude модели, включително Pro и Max",
"dialog.provider.copilot.note": "AI модели за помощ при кодиране чрез GitHub Copilot",
"dialog.provider.openai.note": "GPT модели за бързи, способни общи задачи с изкуствен интелект",
"dialog.provider.google.note": "Gemini модели за бързи, структурирани отговори",
@@ -211,7 +210,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Вижте още 70+ доставчици",
"dialog.provider.viewAll": "Показване на още доставчици",
"provider.connect.title": "Свържете {{provider}}",
"provider.connect.title.anthropicProMax": "Влезте с Claude Pro/Max",
"provider.connect.selectMethod": "Изберете метод за влизане за {{provider}}.",
"provider.connect.method.apiKey": "API ключ",
"provider.connect.method.browser": "Браузър",
@@ -378,8 +376,6 @@ export const dict = {
"prompt.attachment.remove": "Премахване на прикачения файл",
"prompt.action.send": "Изпратете",
"prompt.action.stop": "Спрете",
"prompt.toast.pasteUnsupported.title": "Неподдържан прикачен файл",
"prompt.toast.pasteUnsupported.description": "Тук могат да се прикачват само изображения, PDF или текстови файлове.",
"prompt.toast.attachmentDuplicate.title": "Този файл вече е качен",
"prompt.toast.modelAgentRequired.title": "Изберете агент и модел",
"prompt.toast.modelAgentRequired.description": "Изберете агент и модел, преди да изпратите подкана.",
-4
View File
@@ -192,7 +192,6 @@ export const dict: Record<string, string> = {
"dialog.provider.opencode.note": "Claude, GPT, Gemini এবং আরও অনেক কিছু সহ কিউরেট করা মডেল",
"dialog.provider.opencode.tagline": "নির্ভরযোগ্য অপ্টিমাইজ করা মডেল",
"dialog.provider.opencodeGo.tagline": "সবার জন্য কম খরচে সাবস্ক্রিপশন",
"dialog.provider.anthropic.note": "প্রো এবং ম্যাক্স সহ Claude মডেলগুলিতে সরাসরি অ্যাক্সেস",
"dialog.provider.copilot.note": "GitHub Copilot এর মাধ্যমে কোডিং সহায়তার জন্য AI মডেল",
"dialog.provider.openai.note": "দ্রুত, সক্ষম সাধারণ AI কার্যগুলির জন্য GPT মডেল",
"dialog.provider.google.note": "দ্রুত, কাঠামোগত প্রতিক্রিয়ার জন্য Gemini মডেল",
@@ -209,7 +208,6 @@ export const dict: Record<string, string> = {
"dialog.model.unpaid.viewMoreProviders": "আরও 70+ প্রদানকারী দেখুন",
"dialog.provider.viewAll": "আরো প্রদানকারী দেখান",
"provider.connect.title": "{{provider}} সংযোগ করুন",
"provider.connect.title.anthropicProMax": "Claude Pro/Max দিয়ে লগইন করুন",
"provider.connect.selectMethod": "{{provider}} এর জন্য লগইন পদ্ধতি নির্বাচন করুন।",
"provider.connect.method.apiKey": "API কী",
"provider.connect.method.browser": "ব্রাউজার",
@@ -375,8 +373,6 @@ export const dict: Record<string, string> = {
"prompt.attachment.remove": "সংযুক্তি সরান",
"prompt.action.send": "পাঠান",
"prompt.action.stop": "থামো",
"prompt.toast.pasteUnsupported.title": "অসমর্থিত সংযুক্তি",
"prompt.toast.pasteUnsupported.description": "এখানে শুধুমাত্র ছবি, পিডিএফ বা টেক্সট ফাইল সংযুক্ত করা যাবে।",
"prompt.toast.attachmentDuplicate.title": "এই ফাইল ইতিমধ্যে আপলোড করা হয়েছে",
"prompt.toast.modelAgentRequired.title": "একটি এজেন্ট এবং মডেল নির্বাচন করুন",
"prompt.toast.modelAgentRequired.description": "প্রম্পট পাঠানোর আগে একটি এজেন্ট এবং মডেল বেছে নিন।",
-4
View File
@@ -200,7 +200,6 @@ export const dict = {
"dialog.provider.opencode.note": "Modelos selecionados incluindo Claude, GPT, Gemini e mais",
"dialog.provider.opencode.tagline": "Modelos otimizados e confiáveis",
"dialog.provider.opencodeGo.tagline": "Assinatura de baixo custo para todos",
"dialog.provider.anthropic.note": "Acesso direto aos modelos Claude, incluindo Pro e Max",
"dialog.provider.copilot.note": "Modelos de IA para auxílio à programação pelo GitHub Copilot",
"dialog.provider.openai.note": "Modelos GPT rápidos e avançados para tarefas gerais de IA",
"dialog.provider.google.note": "Modelos Gemini para respostas rápidas e estruturadas",
@@ -217,7 +216,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Ver mais de 70 provedores",
"dialog.provider.viewAll": "Ver mais provedores",
"provider.connect.title": "Conectar {{provider}}",
"provider.connect.title.anthropicProMax": "Entrar com Claude Pro/Max",
"provider.connect.selectMethod": "Selecionar método de login para {{provider}}.",
"provider.connect.method.apiKey": "Chave de API",
"provider.connect.method.browser": "Navegador",
@@ -382,9 +380,7 @@ export const dict = {
"prompt.attachment.remove": "Remover anexo",
"prompt.action.send": "Enviar",
"prompt.action.stop": "Parar",
"prompt.toast.pasteUnsupported.title": "Anexo não suportado",
"prompt.toast.attachmentDuplicate.title": "Este arquivo já foi enviado",
"prompt.toast.pasteUnsupported.description": "Apenas imagens, PDFs ou arquivos de texto podem ser anexados aqui.",
"prompt.toast.modelAgentRequired.title": "Selecione um agente e modelo",
"prompt.toast.modelAgentRequired.description": "Escolha um agente e modelo antes de enviar um prompt.",
"prompt.toast.worktreeCreateFailed.title": "Falha ao criar worktree",
-4
View File
@@ -208,7 +208,6 @@ export const dict = {
"dialog.provider.opencode.note": "Kurirani modeli uključujući Claude, GPT, Gemini i druge",
"dialog.provider.opencode.tagline": "Pouzdani optimizovani modeli",
"dialog.provider.opencodeGo.tagline": "Povoljna pretplata za sve",
"dialog.provider.anthropic.note": "Direktan pristup Claude modelima, uključujući Pro i Max",
"dialog.provider.copilot.note": "AI modeli za pomoć pri kodiranju putem GitHub Copilot",
"dialog.provider.openai.note": "GPT modeli za brze, sposobne opšte AI zadatke",
"dialog.provider.google.note": "Gemini modeli za brze, strukturirane odgovore",
@@ -229,7 +228,6 @@ export const dict = {
"dialog.provider.viewAll": "Prikaži više provajdera",
"provider.connect.title": "Poveži {{provider}}",
"provider.connect.title.anthropicProMax": "Prijavi se putem Claude Pro/Max",
"provider.connect.selectMethod": "Odaberi način prijave za {{provider}}.",
"provider.connect.method.apiKey": "API ključ",
"provider.connect.method.browser": "Preglednik",
@@ -403,9 +401,7 @@ export const dict = {
"prompt.action.send": "Pošalji",
"prompt.action.stop": "Zaustavi",
"prompt.toast.pasteUnsupported.title": "Nepodržan prilog",
"prompt.toast.attachmentDuplicate.title": "Ova datoteka je već učitana",
"prompt.toast.pasteUnsupported.description": "Ovdje se mogu priložiti samo slike, PDF-ovi ili tekstualne datoteke.",
"prompt.toast.modelAgentRequired.title": "Odaberi agenta i model",
"prompt.toast.modelAgentRequired.description": "Odaberi agenta i model prije slanja upita.",
"prompt.toast.worktreeCreateFailed.title": "Neuspješno kreiranje worktree-a",
-4
View File
@@ -193,7 +193,6 @@ export const dict = {
"dialog.provider.opencode.note": "Models seleccionats que inclouen Claude, GPT, Gemini i més",
"dialog.provider.opencode.tagline": "Models optimitzats fiables",
"dialog.provider.opencodeGo.tagline": "Subscripció de baix cost per a tothom",
"dialog.provider.anthropic.note": "Accés directe a Claude models, inclosos Pro i Max",
"dialog.provider.copilot.note": "Models d'IA per a l'assistència de codificació mitjançant GitHub Copilot",
"dialog.provider.openai.note": "GPT models per a tasques d'IA generals ràpides i capaces",
"dialog.provider.google.note": "Gemini models per a respostes ràpides i estructurades",
@@ -210,7 +209,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Consulta més de 70 proveïdors més",
"dialog.provider.viewAll": "Mostra més proveïdors",
"provider.connect.title": "Connecta {{provider}}",
"provider.connect.title.anthropicProMax": "Inicieu sessió amb Claude Pro/Max",
"provider.connect.selectMethod": "Seleccioneu el mètode d'inici de sessió per a {{provider}}.",
"provider.connect.method.apiKey": "tecla API.",
"provider.connect.method.browser": "Navegador",
@@ -377,8 +375,6 @@ export const dict = {
"prompt.attachment.remove": "Elimina el fitxer adjunt",
"prompt.action.send": "Enviar",
"prompt.action.stop": "Atureu-vos",
"prompt.toast.pasteUnsupported.title": "Fitxer adjunt no compatible",
"prompt.toast.pasteUnsupported.description": "Aquí només es poden adjuntar imatges, PDFs o fitxers de text.",
"prompt.toast.attachmentDuplicate.title": "Aquest fitxer ja s'ha penjat",
"prompt.toast.modelAgentRequired.title": "Seleccioneu un agent i un model",
"prompt.toast.modelAgentRequired.description": "Trieu un agent i un model abans d'enviar una sol·licitud.",
-4
View File
@@ -191,7 +191,6 @@ export const dict = {
"dialog.provider.opencode.note": "Vybrané modely včetně Claude, GPT, Gemini a dalších",
"dialog.provider.opencode.tagline": "Spolehlivé optimalizované modely",
"dialog.provider.opencodeGo.tagline": "Nízkonákladové předplatné pro každého",
"dialog.provider.anthropic.note": "Přímý přístup k modelům Claude, včetně modelů Pro a Max",
"dialog.provider.copilot.note": "Modely umělé inteligence pro pomoc s kódováním prostřednictvím GitHub Copilot",
"dialog.provider.openai.note": "GPT modely pro rychlé a schopné obecné úlohy umělé inteligence",
"dialog.provider.google.note": "Gemini modely pro rychlé, strukturované odpovědi",
@@ -208,7 +207,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Zobrazit více než 70 dalších poskytovatelů",
"dialog.provider.viewAll": "Zobrazit další poskytovatele",
"provider.connect.title": "Připojit {{provider}}",
"provider.connect.title.anthropicProMax": "Přihlaste se pomocí Claude Pro/Max",
"provider.connect.selectMethod": "Vyberte způsob přihlášení pro {{provider}}.",
"provider.connect.method.apiKey": "API klíč",
"provider.connect.method.browser": "Prohlížeč",
@@ -375,8 +373,6 @@ export const dict = {
"prompt.attachment.remove": "Odstraňte přílohu",
"prompt.action.send": "Odeslat",
"prompt.action.stop": "Přestaň",
"prompt.toast.pasteUnsupported.title": "Nepodporovaná příloha",
"prompt.toast.pasteUnsupported.description": "Zde lze připojit pouze obrázky, PDFs nebo textové soubory.",
"prompt.toast.attachmentDuplicate.title": "Tento soubor již byl nahrán",
"prompt.toast.modelAgentRequired.title": "Vyberte agenta a model",
"prompt.toast.modelAgentRequired.description": "Před odesláním výzvy vyberte zástupce a model.",
-4
View File
@@ -107,7 +107,6 @@ export const dict = {
"dialog.provider.opencode.note": "Udvalgte modeller inklusive Claude, GPT, Gemini og flere",
"dialog.provider.opencode.tagline": "Pålidelige optimerede modeller",
"dialog.provider.opencodeGo.tagline": "Billigt abonnement for alle",
"dialog.provider.anthropic.note": "Direkte adgang til Claude-modeller, inklusive Pro og Max",
"dialog.provider.copilot.note": "AI-modeller til kodningsassistance via GitHub Copilot",
"dialog.provider.openai.note": "GPT-modeller til hurtige, kompetente generelle AI-opgaver",
"dialog.provider.google.note": "Gemini-modeller til hurtige, strukturerede svar",
@@ -128,7 +127,6 @@ export const dict = {
"dialog.provider.viewAll": "Vis flere udbydere",
"provider.connect.title": "Forbind {{provider}}",
"provider.connect.title.anthropicProMax": "Log ind med Claude Pro/Max",
"provider.connect.selectMethod": "Vælg loginmetode for {{provider}}.",
"provider.connect.method.apiKey": "API-nøgle",
"provider.connect.method.browser": "Browser",
@@ -300,9 +298,7 @@ export const dict = {
"prompt.action.send": "Send",
"prompt.action.stop": "Stop",
"prompt.toast.pasteUnsupported.title": "Ikke understøttet vedhæftning",
"prompt.toast.attachmentDuplicate.title": "Denne fil er allerede uploadet",
"prompt.toast.pasteUnsupported.description": "Kun billeder, PDF'er eller tekstfiler kan vedhæftes her.",
"prompt.toast.modelAgentRequired.title": "Vælg en agent og model",
"prompt.toast.modelAgentRequired.description": "Vælg en agent og model før du sender en forespørgsel.",
"prompt.toast.worktreeCreateFailed.title": "Kunne ikke oprette worktree",
-4
View File
@@ -103,7 +103,6 @@ export const dict = {
"dialog.provider.opencode.note": "Kuratierte Modelle inklusive Claude, GPT, Gemini und mehr",
"dialog.provider.opencode.tagline": "Zuverlässige, optimierte Modelle",
"dialog.provider.opencodeGo.tagline": "Kostengünstiges Abo für alle",
"dialog.provider.anthropic.note": "Direkter Zugriff auf Claude-Modelle, einschließlich Pro und Max",
"dialog.provider.copilot.note": "KI-Modelle zur Programmierunterstützung über GitHub Copilot",
"dialog.provider.openai.note": "GPT-Modelle für schnelle, leistungsfähige allgemeine KI-Aufgaben",
"dialog.provider.google.note": "Gemini-Modelle für schnelle, strukturierte Antworten",
@@ -120,7 +119,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Über 70 weitere Anbieter anzeigen",
"dialog.provider.viewAll": "Mehr Anbieter anzeigen",
"provider.connect.title": "{{provider}} verbinden",
"provider.connect.title.anthropicProMax": "Mit Claude Pro/Max anmelden",
"provider.connect.selectMethod": "Anmeldemethode für {{provider}} auswählen.",
"provider.connect.method.apiKey": "API-Schlüssel",
"provider.connect.method.browser": "Browser",
@@ -286,9 +284,7 @@ export const dict = {
"prompt.attachment.remove": "Anhang entfernen",
"prompt.action.send": "Senden",
"prompt.action.stop": "Stoppen",
"prompt.toast.pasteUnsupported.title": "Nicht unterstützter Anhang",
"prompt.toast.attachmentDuplicate.title": "Diese Datei wurde bereits hochgeladen",
"prompt.toast.pasteUnsupported.description": "Hier können nur Bilder, PDFs oder Textdateien angehängt werden.",
"prompt.toast.modelAgentRequired.title": "Wählen Sie einen Agenten und ein Modell",
"prompt.toast.modelAgentRequired.description":
"Wählen Sie einen Agenten und ein Modell, bevor Sie eine Eingabe senden.",
-5
View File
@@ -195,7 +195,6 @@ export const dict = {
"ކިއުރެޓް ކުރެވިފައިވާ މޮޑެލްތަކުގެ ތެރޭގައި Claude، GPT، Gemini އަދި އެހެނިހެން މޮޑެލްތައް ހިމެނެއެވެ",
"dialog.provider.opencode.tagline": "އިތުބާރު ހުރި އޮޕްޓިމައިޒްޑް މޮޑެލްތަކެވެ",
"dialog.provider.opencodeGo.tagline": "އެންމެންނަށް ކުޑަ އަގެއްގައި ސަބްސްކްރިޕްޝަން ދިނުމެވެ",
"dialog.provider.anthropic.note": "ޕްރޯ އަދި މެކްސް ހިމެނޭ ގޮތަށް Claude މޮޑެލްތަކަށް ސީދާ އެކްސެސް ލިބޭނެ އެވެ",
"dialog.provider.copilot.note": "GitHub Copilot މެދުވެރިކޮށް ކޯޑިންގ އެހީތެރިވުމަށް AI މޮޑެލްތައް",
"dialog.provider.openai.note": "އަވަސް، ގާބިލް އާންމު AI ޓާސްކްތަކަށް GPT މޮޑެލްތަކެވެ",
"dialog.provider.google.note": "އަވަސް، ސްޓްރަކްޗަރޑް ރެސްޕޮންސްތަކަށް Gemini މޮޑެލްތަކެވެ",
@@ -212,7 +211,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "އިތުރު 70+ ޕްރޮވައިޑަރުން ބައްލަވާށެވެ",
"dialog.provider.viewAll": "އިތުރު ޕްރޮވައިޑަރުން ދައްކާށެވެ",
"provider.connect.title": "{{provider}} ގުޅުވާށެވެ",
"provider.connect.title.anthropicProMax": "Claude ޕްރޯ/މެކްސް އިން ލޮގިން ވާނެއެވެ",
"provider.connect.selectMethod": "{{provider}} އަށް ލޮގިން މެތޯޑް ހޮވާށެވެ.",
"provider.connect.method.apiKey": "API ކީ އެވެ",
"provider.connect.method.browser": "ބްރައުޒާ އެވެ",
@@ -380,9 +378,6 @@ export const dict = {
"prompt.attachment.remove": "އެޓޭޗްމަންޓް ނަގާށެވެ",
"prompt.action.send": "ފޮނުވުން",
"prompt.action.stop": "ހުއްޓުން",
"prompt.toast.pasteUnsupported.title": "ސަޕޯޓް ނުކުރާ އެޓޭޗްމަންޓެވެ",
"prompt.toast.pasteUnsupported.description":
"މިތަނުގައި އެޓޭޗް ކުރެވޭނީ ހަމައެކަނި ތަސްވީރު، PDFs، ނުވަތަ ޓެކްސްޓް ފައިލްތަކެވެ.",
"prompt.toast.attachmentDuplicate.title": "މި ފައިލް މިހާރު ވަނީ އަޕްލޯޑްކޮށްފައެވެ",
"prompt.toast.modelAgentRequired.title": "އޭޖެންޓަކާއި މޮޑެލްއެއް ހޮވުން",
"prompt.toast.modelAgentRequired.description": "ޕްރޮމްޕްޓެއް ފޮނުވުމުގެ ކުރިން އޭޖެންޓަކާއި މޮޑެލްއެއް ހޮވުން.",
-5
View File
@@ -194,7 +194,6 @@ export const dict: Record<string, string> = {
"dialog.provider.opencode.note": "Claude དང་ GPT དེ་ལས་ Gemini དང་དེ་ལས་ལྷག་སྟེ་ བཀོད་སྒྲིག་འབད་ཡོད་པའི་དཔེ་ཚད།",
"dialog.provider.opencode.tagline": "བློ་གཏད་ཅན་གྱི་ཡར་རྒྱས་ཅན་གྱི་དཔེ་ཚད་ཚུ།",
"dialog.provider.opencodeGo.tagline": "མི་ཚང་མའི་དོན་ལུ་ གོང་ཚད་དམའ་བའི་ མཁོ་མངགས་འབད་ནི།",
"dialog.provider.anthropic.note": "པྲོ་དང་མེགསི་ཚུ་རྩིས་ཏེ་ Claudeདཔེ་ཚད་ཚུ་ལུ་ཐད་ཀར་དུ་འཛུལ་སྤྱོད།",
"dialog.provider.copilot.note": "GitHub Copilot བརྒྱུད་དེ་ ཀོ་ཌིང་གྲོགས་རམ་གྱི་དོན་ལུ་ AI དཔེ་ཚད།",
"dialog.provider.openai.note": "GPT མགྱོགས་དྲགས་དང་ལྕོགས་གྲུབ་ཅན་གྱི་སྤྱིར་བཏང་ཨེ་ཨའི་ལས་འགན་ཚུ་གི་དོན་ལུ་དཔེ་ཚད།",
"dialog.provider.google.note": "Gemini མགྱོགས་དྲགས་དང་སྒྲིག་བཀོད་ཅན་གྱི་ལན་འདེབས་ཀྱི་དཔེ་ཚད།",
@@ -212,7 +211,6 @@ export const dict: Record<string, string> = {
"dialog.model.unpaid.viewMoreProviders": "70+ མཁོ་སྤྲོད་འབད་མི་ཚུ་བལྟ།",
"dialog.provider.viewAll": "བྱིན་མི་མངམ་སྟོན།",
"provider.connect.title": "{{provider}}མཐུད།",
"provider.connect.title.anthropicProMax": "Claude Pro/Max དང་ཅིག་ཁར་ནང་བསྐྱོན།",
"provider.connect.selectMethod": "{{provider}}གི་དོན་ལུ་ ནང་བསྐྱོད་ཐབས་ལམ་སེལ་འཐུ་འབད།",
"provider.connect.method.apiKey": "APIལྡེ་མིག།",
"provider.connect.method.browser": "བརའུ་ཟར།",
@@ -379,9 +377,6 @@ export const dict: Record<string, string> = {
"prompt.attachment.remove": "མཉམ་སྦྲགས་རྩ་བསྐྲད་གཏང་།",
"prompt.action.send": "བཏང༌ནི",
"prompt.action.stop": "བཀག་པ",
"prompt.toast.pasteUnsupported.title": "རྒྱབ་སྐྱོར་མེད་པའི་མཉམ་སྦྲགས།",
"prompt.toast.pasteUnsupported.description":
"པར་རིས་དང་པི་ཌི་ཨེཕ་ ཡང་ན་ ཚིག་ཡིག་ཡིག་སྣོད་ཚུ་རྐྱངམ་ཅིག་ ནཱ་ལུ་མཉམ་སྦྲགས་འབད་བཏུབ།",
"prompt.toast.attachmentDuplicate.title": "ཡིག་སྣོད་འདི་ཧེ་མ་ལས་སྐྱེལ་བཙུགས་འབད་ཡི།",
"prompt.toast.modelAgentRequired.title": "ལས་ཚབ་དང་དཔེ་ཚད་ཅིག་སེལ་འཐུ་འབད།",
"prompt.toast.modelAgentRequired.description": "བརྡ་སྟོན་མ་གཏང་པའི་ཧེ་མ་ ལས་ཚབ་དང་དཔེ་ཚད་གདམ་ཁ་རྐྱབས།",
-4
View File
@@ -192,7 +192,6 @@ export const dict = {
"dialog.provider.opencode.note": "Επιμελημένα μοντέλα συμπεριλαμβανομένων των Claude, GPT, Gemini και άλλων",
"dialog.provider.opencode.tagline": "Αξιόπιστα βελτιστοποιημένα μοντέλα",
"dialog.provider.opencodeGo.tagline": "Συνδρομή χαμηλού κόστους για όλους",
"dialog.provider.anthropic.note": "Άμεση πρόσβαση σε Claude μοντέλα, συμπεριλαμβανομένων των Pro και Max",
"dialog.provider.copilot.note": "Μοντέλα AI για βοήθεια κωδικοποίησης μέσω GitHub Copilot",
"dialog.provider.openai.note": "GPT μοντέλα για γρήγορες, ικανές εργασίες γενικής τεχνητής νοημοσύνης",
"dialog.provider.google.note": "Gemini μοντέλα για γρήγορες, δομημένες απαντήσεις",
@@ -209,7 +208,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Δείτε 70+ ακόμη παρόχους",
"dialog.provider.viewAll": "Εμφάνιση περισσότερων παρόχων",
"provider.connect.title": "Σύνδεση {{provider}}",
"provider.connect.title.anthropicProMax": "Σύνδεση με Claude Pro/Max",
"provider.connect.selectMethod": "Επιλογή μεθόδου σύνδεσης για {{provider}}.",
"provider.connect.method.apiKey": "API κλειδί",
"provider.connect.method.browser": "Πρόγραμμα περιήγησης",
@@ -376,8 +374,6 @@ export const dict = {
"prompt.attachment.remove": "Κατάργηση συνημμένου",
"prompt.action.send": "Αποστολή",
"prompt.action.stop": "Διακοπή",
"prompt.toast.pasteUnsupported.title": "Μη υποστηριζόμενο συνημμένο",
"prompt.toast.pasteUnsupported.description": "Εδώ επισυνάπτονται μόνο εικόνες, αρχεία PDF ή αρχεία κειμένου.",
"prompt.toast.attachmentDuplicate.title": "Αυτό το αρχείο έχει ήδη μεταφορτωθεί",
"prompt.toast.modelAgentRequired.title": "Επιλέξτε έναν πράκτορα και μοντέλο",
"prompt.toast.modelAgentRequired.description":
+15 -4
View File
@@ -74,6 +74,7 @@ export const dict = {
"command.category.workspace": "Worktree",
"command.category.settings": "Settings",
"command.logs.export": "Export logs",
"command.debugBar.toggle": "Toggle debug bar",
"theme.scheme.system": "System",
"theme.scheme.light": "Light",
@@ -170,7 +171,7 @@ export const dict = {
"dialog.provider.opencode.note": "Curated models including Claude, GPT, Gemini and more",
"dialog.provider.opencode.tagline": "Reliable optimized models",
"dialog.provider.opencodeGo.tagline": "Low cost subscription for everyone",
"dialog.provider.anthropic.note": "Direct access to Claude models, including Pro and Max",
"dialog.provider.anthropic.note": "Direct access to Claude models via API key",
"dialog.provider.copilot.note": "AI models for coding assistance via GitHub Copilot",
"dialog.provider.openai.note": "GPT models for fast, capable general AI tasks",
"dialog.provider.google.note": "Gemini models for fast, structured responses",
@@ -191,7 +192,7 @@ export const dict = {
"dialog.provider.viewAll": "Show more providers",
"provider.connect.title": "Connect {{provider}}",
"provider.connect.title.anthropicProMax": "Login with Claude Pro/Max",
"provider.connect.title.anthropicProMax": "Login with Anthropic",
"provider.connect.selectMethod": "Select login method for {{provider}}.",
"provider.connect.method.apiKey": "API key",
"provider.connect.method.browser": "Browser",
@@ -365,9 +366,10 @@ export const dict = {
"prompt.action.send": "Send",
"prompt.action.stop": "Stop",
"prompt.toast.pasteUnsupported.title": "Unsupported attachment",
"prompt.toast.pasteUnsupported.description": "Only images, PDFs, or text files can be attached here.",
"prompt.toast.attachmentDuplicate.title": "This file has already been uploaded",
"prompt.toast.uploading.percent": "{{percent}}%",
"prompt.toast.uploading.cancel": "Cancel upload",
"prompt.toast.uploadFailed.title": "Upload failed",
"prompt.toast.modelAgentRequired.title": "Select an agent and model",
"prompt.toast.modelAgentRequired.description": "Choose an agent and model before sending a prompt.",
"prompt.toast.worktreeCreateFailed.title": "Failed to create worktree",
@@ -965,7 +967,16 @@ export const dict = {
"sidebar.empty.description": "Open a project to get started",
"debugBar.ariaLabel": "Development performance diagnostics",
"debugBar.providerAriaLabel": "Provider performance diagnostics",
"debugBar.na": "n/a",
"debugBar.ttft.label": "TTFT",
"debugBar.ttft.tip": "Time from provider request dispatch to the first model output.",
"debugBar.ttfa.label": "TTFA",
"debugBar.ttfa.tip": "Time from provider request dispatch to the first answer text.",
"debugBar.tps.label": "TPS",
"debugBar.tps.tip": "Output tokens per second after the first model output.",
"debugBar.e2e.label": "E2E",
"debugBar.e2e.tip": "Time from provider request dispatch until its response stream ended.",
"debugBar.nav.label": "NAV",
"debugBar.nav.tip":
"Last completed route transition touching a session page, measured from router start until the first paint after it settles.",
-5
View File
@@ -208,7 +208,6 @@ export const dict = {
"dialog.provider.opencode.note": "Selección de modelos como Claude, GPT, Gemini y otros",
"dialog.provider.opencode.tagline": "Modelos optimizados y fiables",
"dialog.provider.opencodeGo.tagline": "Suscripción económica para todos",
"dialog.provider.anthropic.note": "Acceso directo a modelos Claude, incluidos Pro y Max",
"dialog.provider.copilot.note": "Modelos de IA para asistencia de codificación a través de GitHub Copilot",
"dialog.provider.openai.note": "Modelos GPT para tareas de IA generales rápidas y capaces",
"dialog.provider.google.note": "Modelos Gemini para respuestas rápidas y estructuradas",
@@ -229,7 +228,6 @@ export const dict = {
"dialog.provider.viewAll": "Ver más proveedores",
"provider.connect.title": "Conectar {{provider}}",
"provider.connect.title.anthropicProMax": "Iniciar sesión con Claude Pro/Max",
"provider.connect.selectMethod": "Seleccionar método de inicio de sesión para {{provider}}.",
"provider.connect.method.apiKey": "Clave API",
"provider.connect.method.browser": "Navegador",
@@ -403,10 +401,7 @@ export const dict = {
"prompt.action.send": "Enviar",
"prompt.action.stop": "Detener",
"prompt.toast.pasteUnsupported.title": "Adjunto no compatible",
"prompt.toast.attachmentDuplicate.title": "Este archivo ya se ha subido",
"prompt.toast.pasteUnsupported.description":
"Aquí solo se pueden adjuntar imágenes, archivos PDF o archivos de texto.",
"prompt.toast.modelAgentRequired.title": "Selecciona un agente y modelo",
"prompt.toast.modelAgentRequired.description": "Elige un agente y modelo antes de enviar un prompt.",
"prompt.toast.worktreeCreateFailed.title": "Fallo al crear el árbol de trabajo",
-4
View File
@@ -191,7 +191,6 @@ export const dict = {
"dialog.provider.opencode.note": "Kureeritud mudelid, sealhulgas Claude, GPT, Gemini ja palju muud",
"dialog.provider.opencode.tagline": "Usaldusväärsed optimeeritud mudelid",
"dialog.provider.opencodeGo.tagline": "Madala hinnaga tellimus kõigile",
"dialog.provider.anthropic.note": "Otsene juurdepääs Claude mudelile, sealhulgas Pro ja Max",
"dialog.provider.copilot.note": "AI mudelid kodeerimisabiks GitHub Copilot kaudu",
"dialog.provider.openai.note": "GPT mudelid kiirete ja võimekate üldiste AI-ülesannete jaoks",
"dialog.provider.google.note": "Gemini mudelid kiirete ja struktureeritud vastuste jaoks",
@@ -208,7 +207,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Vaadake veel 70+ pakkujat",
"dialog.provider.viewAll": "Kuva rohkem teenusepakkujaid",
"provider.connect.title": "Ühenda {{provider}}",
"provider.connect.title.anthropicProMax": "Logi sisse Claude Pro/Max",
"provider.connect.selectMethod": "Valige {{provider}} jaoks sisselogimisviis.",
"provider.connect.method.apiKey": "API klahv",
"provider.connect.method.browser": "Brauser",
@@ -374,8 +372,6 @@ export const dict = {
"prompt.attachment.remove": "Eemalda manus",
"prompt.action.send": "Saada",
"prompt.action.stop": "Peatus",
"prompt.toast.pasteUnsupported.title": "Toetamata manus",
"prompt.toast.pasteUnsupported.description": "Siia saab lisada ainult pilte, PDFs või tekstifaile.",
"prompt.toast.attachmentDuplicate.title": "See fail on juba üles laaditud",
"prompt.toast.modelAgentRequired.title": "Valige agent ja mudel",
"prompt.toast.modelAgentRequired.description": "Enne viipa saatmist valige agent ja mudel.",
-4
View File
@@ -192,7 +192,6 @@ export const dict = {
"dialog.provider.opencode.note": "مدل های انتخاب شده از جمله Claude، GPT، Gemini و موارد دیگر",
"dialog.provider.opencode.tagline": "مدل های بهینه شده قابل اعتماد",
"dialog.provider.opencodeGo.tagline": "اشتراک کم هزینه برای همه",
"dialog.provider.anthropic.note": "دسترسی مستقیم به مدل های Claude، از جمله Pro و Max",
"dialog.provider.copilot.note": "مدل های AI برای کمک به کدنویسی از طریق GitHub Copilot",
"dialog.provider.openai.note": "مدل های GPT برای کارهای عمومی سریع و با قابلیت AI",
"dialog.provider.google.note": "مدل های Gemini برای پاسخ های سریع و ساختاریافته",
@@ -209,7 +208,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "70+ ارائه‌دهنده دیگر را ببینید",
"dialog.provider.viewAll": "نمایش ارائه دهندگان بیشتر",
"provider.connect.title": "{{provider}} را وصل کنید",
"provider.connect.title.anthropicProMax": "با Claude Pro/Max وارد شوید",
"provider.connect.selectMethod": "روش ورود برای {{provider}} را انتخاب کنید.",
"provider.connect.method.apiKey": "کلید API",
"provider.connect.method.browser": "مرورگر",
@@ -375,8 +373,6 @@ export const dict = {
"prompt.attachment.remove": "حذف پیوست",
"prompt.action.send": "ارسال کنید",
"prompt.action.stop": "توقف کنید",
"prompt.toast.pasteUnsupported.title": "پیوست پشتیبانی نشده است",
"prompt.toast.pasteUnsupported.description": "فقط تصاویر، PDFs، یا فایل های متنی را می توان در اینجا پیوست کرد.",
"prompt.toast.attachmentDuplicate.title": "این فایل قبلا آپلود شده است",
"prompt.toast.modelAgentRequired.title": "یک عامل و مدل را انتخاب کنید",
"prompt.toast.modelAgentRequired.description": "قبل از ارسال درخواست، یک عامل و مدل را انتخاب کنید.",
-4
View File
@@ -99,7 +99,6 @@ export const dict = {
"dialog.provider.opencode.note": "Kuratoituja malleja, kuten Claude, GPT, Gemini ja muita",
"dialog.provider.opencode.tagline": "Luotettavat optimoidut mallit",
"dialog.provider.opencodeGo.tagline": "Edullinen tilaus kaikille",
"dialog.provider.anthropic.note": "Suora pääsy Claude-malleihin, mukaan lukien Pro ja Max",
"dialog.provider.copilot.note": "AI-malleja koodausapuun GitHub Copilotin kautta",
"dialog.provider.openai.note": "GPT-mallit nopeisiin, suorituskykyisiin yleisiin tekoälytehtäviin",
"dialog.provider.google.note": "Gemini-mallit nopeisiin, jäsenneltyihin vastauksiin",
@@ -116,7 +115,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Katso yli 70 muuta palveluntarjoajaa",
"dialog.provider.viewAll": "Näytä lisää palveluntarjoajia",
"provider.connect.title": "Yhdistä {{provider}}",
"provider.connect.title.anthropicProMax": "Kirjaudu sisään Claude Pro/Maxilla",
"provider.connect.selectMethod": "Valitse kirjautumistapa palvelulle {{provider}}.",
"provider.connect.method.apiKey": "API-avain",
"provider.connect.method.browser": "Selain",
@@ -282,8 +280,6 @@ export const dict = {
"prompt.attachment.remove": "Poista liite",
"prompt.action.send": "Lähetä",
"prompt.action.stop": "Pysäytä",
"prompt.toast.pasteUnsupported.title": "Liitettä ei tueta",
"prompt.toast.pasteUnsupported.description": "Vain kuvia, PDF-tiedostoja tai tekstitiedostoja voi liittää tähän.",
"prompt.toast.attachmentDuplicate.title": "Tämä tiedosto on jo ladattu",
"prompt.toast.modelAgentRequired.title": "Valitse agentti ja malli",
"prompt.toast.modelAgentRequired.description": "Valitse agentti ja malli ennen kehotteen lähettämistä.",
-4
View File
@@ -191,7 +191,6 @@ export const dict = {
"dialog.provider.opencode.note": "Kuraterað modell íroknað Claude, GPT, Gemini og fleiri",
"dialog.provider.opencode.tagline": "Álítandi optimerað modell",
"dialog.provider.opencodeGo.tagline": "Lágkostnaðarhald fyri øll",
"dialog.provider.anthropic.note": "Beinleiðis atgongd til Claude modellir, eisini Pro og Max .",
"dialog.provider.copilot.note": "AI modellir til koduhjálp umvegis GitHub Copilot",
"dialog.provider.openai.note": "GPT modellir til skjótar, førar almennar AI uppgávur",
"dialog.provider.google.note": "Gemini modellir til skjót, strukturerað svar",
@@ -208,7 +207,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Sí 70+ fleiri veitarar",
"dialog.provider.viewAll": "Vís fleiri veitarar",
"provider.connect.title": "Samband {{provider}}",
"provider.connect.title.anthropicProMax": "Rita inn við Claude Pro/Max",
"provider.connect.selectMethod": "Vel innritanarhátt til {{provider}}.",
"provider.connect.method.apiKey": "API lykil",
"provider.connect.method.browser": "Kagari",
@@ -374,8 +372,6 @@ export const dict = {
"prompt.attachment.remove": "Strika viðheftið",
"prompt.action.send": "Send",
"prompt.action.stop": "Steðga",
"prompt.toast.pasteUnsupported.title": "Óstuðlað viðhefti",
"prompt.toast.pasteUnsupported.description": "Bert myndir, PDFs, ella tekstfílur kunnu viðheftast her.",
"prompt.toast.attachmentDuplicate.title": "Hendan fílan er longu løgd upp.",
"prompt.toast.modelAgentRequired.title": "Vel agent og modell",
"prompt.toast.modelAgentRequired.description": "Vel agent og modell, áðrenn tú sendir ein prompt.",
-5
View File
@@ -200,7 +200,6 @@ export const dict = {
"dialog.provider.opencode.note": "Modèles sélectionnés incluant Claude, GPT, Gemini et plus",
"dialog.provider.opencode.tagline": "Modèles optimisés et fiables",
"dialog.provider.opencodeGo.tagline": "Abonnement abordable pour tous",
"dialog.provider.anthropic.note": "Connectez-vous avec Claude Pro/Max ou une clé API",
"dialog.provider.copilot.note": "Connectez-vous avec Copilot ou une clé API",
"dialog.provider.openai.note": "Connectez-vous avec ChatGPT Pro/Plus ou une clé API",
"dialog.provider.google.note": "Modèles Gemini pour des réponses rapides et structurées",
@@ -217,7 +216,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Voir plus de 70 autres fournisseurs",
"dialog.provider.viewAll": "Voir plus de fournisseurs",
"provider.connect.title": "Connecter {{provider}}",
"provider.connect.title.anthropicProMax": "Connexion avec Claude Pro/Max",
"provider.connect.selectMethod": "Sélectionnez la méthode de connexion pour {{provider}}.",
"provider.connect.method.apiKey": "Clé API",
"provider.connect.method.browser": "Navigateur",
@@ -385,10 +383,7 @@ export const dict = {
"prompt.attachment.remove": "Supprimer la pièce jointe",
"prompt.action.send": "Envoyer",
"prompt.action.stop": "Arrêter",
"prompt.toast.pasteUnsupported.title": "Pièce jointe non prise en charge",
"prompt.toast.attachmentDuplicate.title": "Ce fichier a déjà été téléversé",
"prompt.toast.pasteUnsupported.description":
"Seules les images, les PDF ou les fichiers texte peuvent être joints ici.",
"prompt.toast.modelAgentRequired.title": "Sélectionnez un agent et un modèle",
"prompt.toast.modelAgentRequired.description": "Choisissez un agent et un modèle avant d'envoyer une invite.",
"prompt.toast.worktreeCreateFailed.title": "Échec de la création de l'arbre de travail",
-4
View File
@@ -192,7 +192,6 @@ export const dict = {
"dialog.provider.opencode.note": "מבחר מודלים, בהם Claude, GPT, Gemini ועוד",
"dialog.provider.opencode.tagline": "מודלים אמינים שעברו אופטימיזציה",
"dialog.provider.opencodeGo.tagline": "מנוי בעלות נמוכה לכולם",
"dialog.provider.anthropic.note": "גישה ישירה למודלי Claude, כולל Pro ו-Max",
"dialog.provider.copilot.note": "מודלי AI לסיוע בכתיבת קוד באמצעות GitHub Copilot",
"dialog.provider.openai.note": "מודלי GPT למשימות AI כלליות, מהירות ומתקדמות",
"dialog.provider.google.note": "מודלי Gemini לתגובות מהירות ומובנות",
@@ -209,7 +208,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "הצגת יותר מ-70 ספקים נוספים",
"dialog.provider.viewAll": "הצג עוד ספקים",
"provider.connect.title": "חבר את {{provider}}",
"provider.connect.title.anthropicProMax": "התחבר עם Claude Pro/Max",
"provider.connect.selectMethod": "בחר שיטת התחברות עבור {{provider}}.",
"provider.connect.method.apiKey": "מפתח API",
"provider.connect.method.browser": "דפדפן",
@@ -373,8 +371,6 @@ export const dict = {
"prompt.attachment.remove": "הסר את הקובץ המצורף",
"prompt.action.send": "שלח",
"prompt.action.stop": "עצור",
"prompt.toast.pasteUnsupported.title": "קובץ מצורף לא נתמך",
"prompt.toast.pasteUnsupported.description": "ניתן לצרף כאן רק תמונות, קובצי PDF או קבצי טקסט.",
"prompt.toast.attachmentDuplicate.title": "הקובץ הזה כבר הועלה",
"prompt.toast.modelAgentRequired.title": "בחר סוכן ומודל",
"prompt.toast.modelAgentRequired.description": "יש לבחור סוכן ומודל לפני שליחת פרומפט.",
-4
View File
@@ -199,7 +199,6 @@ export const dict = {
"dialog.provider.opencode.note": "Claude, GPT, Gemini और अधिक सहित क्यूरेटेड मॉडल",
"dialog.provider.opencode.tagline": "विश्वसनीय अनुकूलित मॉडल",
"dialog.provider.opencodeGo.tagline": "सभी के लिए कम लागत वाली सदस्यता",
"dialog.provider.anthropic.note": "प्रो और मैक्स सहित Claude मॉडल तक सीधी पहुँच",
"dialog.provider.copilot.note": "GitHub Copilot के माध्यम से कोडिंग सहायता के लिए AI मॉडल",
"dialog.provider.openai.note": "तेज़, सक्षम सामान्य AI कार्यों के लिए GPT मॉडल",
"dialog.provider.google.note": "तेज़, संरचित प्रतिक्रियाओं के लिए Gemini मॉडल",
@@ -216,7 +215,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "70+ अधिक प्रोवाइडर देखें",
"dialog.provider.viewAll": "और प्रोवाइडर दिखाएँ",
"provider.connect.title": "{{provider}} कनेक्ट करें",
"provider.connect.title.anthropicProMax": "Claude प्रो/मैक्स के साथ लॉगिन करें",
"provider.connect.selectMethod": "{{provider}} के लिए लॉगिन विधि चुनें।",
"provider.connect.method.apiKey": "API कुंजी",
"provider.connect.method.browser": "ब्राउज़र",
@@ -382,8 +380,6 @@ export const dict = {
"prompt.attachment.remove": "अनुलग्नक हटाएँ",
"prompt.action.send": "भेजें",
"prompt.action.stop": "रोकें",
"prompt.toast.pasteUnsupported.title": "असमर्थित अनुलग्नक",
"prompt.toast.pasteUnsupported.description": "यहां केवल छवियां, PDFs, या टेक्स्ट फ़ाइलें संलग्न की जा सकती हैं।",
"prompt.toast.attachmentDuplicate.title": "यह फ़ाइल पहले ही अपलोड की जा चुकी है",
"prompt.toast.modelAgentRequired.title": "एक एजेंट और मॉडल चुनें",
"prompt.toast.modelAgentRequired.description": "प्रॉम्प्ट भेजने से पहले एक एजेंट और मॉडल चुनें।",
-4
View File
@@ -195,7 +195,6 @@ export const dict = {
"dialog.provider.opencode.note": "Odabrani modeli uključujući Claude, GPT, Gemini i druge",
"dialog.provider.opencode.tagline": "Pouzdani optimizirani modeli",
"dialog.provider.opencodeGo.tagline": "Niska cijena pretplate za sve",
"dialog.provider.anthropic.note": "Izravan pristup Claude modelima, uključujući Pro i Max",
"dialog.provider.copilot.note": "AI modeli za pomoć kodiranja putem GitHub Copilot",
"dialog.provider.openai.note": "GPT modeli za brze, sposobne opće AI zadatke",
"dialog.provider.google.note": "Gemini modeli za brze, strukturirane odgovore",
@@ -212,7 +211,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Pogledajte više od 70 pružatelja usluga",
"dialog.provider.viewAll": "Prikaži više pružatelja usluga",
"provider.connect.title": "Povežite {{provider}}",
"provider.connect.title.anthropicProMax": "Prijavite se sa Claude Pro/Max",
"provider.connect.selectMethod": "Odaberite način prijave za {{provider}}.",
"provider.connect.method.apiKey": "Ključ API",
"provider.connect.method.browser": "preglednik",
@@ -379,8 +377,6 @@ export const dict = {
"prompt.attachment.remove": "Ukloni privitak",
"prompt.action.send": "Poslati",
"prompt.action.stop": "Zaustavi",
"prompt.toast.pasteUnsupported.title": "Nepodržani privitak",
"prompt.toast.pasteUnsupported.description": "Ovdje se mogu priložiti samo slike, PDF-ovi ili tekstualne datoteke.",
"prompt.toast.attachmentDuplicate.title": "Ova datoteka je već učitana",
"prompt.toast.modelAgentRequired.title": "Odaberite agenta i model",
"prompt.toast.modelAgentRequired.description": "Odaberite agenta i model prije slanja upita.",
-4
View File
@@ -195,7 +195,6 @@ export const dict = {
"dialog.provider.opencode.note": "Összeválogatott modellek, köztük Claude, GPT, Gemini és még sok más",
"dialog.provider.opencode.tagline": "Megbízható optimalizált modellek",
"dialog.provider.opencodeGo.tagline": "Olcsó előfizetés mindenki számára",
"dialog.provider.anthropic.note": "Közvetlen hozzáférés a Claude modellekhez, beleértve a Pro és Max modelleket",
"dialog.provider.copilot.note": "AI modellek a kódoláshoz a GitHub Copilot segítségével",
"dialog.provider.openai.note": "GPT modellek a gyors, általános AI-feladatokhoz",
"dialog.provider.google.note": "Gemini modellek a gyors, strukturált válaszokhoz",
@@ -212,7 +211,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "További 70+ szolgáltató megtekintése",
"dialog.provider.viewAll": "További szolgáltatók megjelenítése",
"provider.connect.title": "Csatlakoztassa a {{provider}}-t",
"provider.connect.title.anthropicProMax": "Jelentkezzen be a Claude Pro/Max",
"provider.connect.selectMethod": "Válassza ki a {{provider}} bejelentkezési módját.",
"provider.connect.method.apiKey": "API kulcs",
"provider.connect.method.browser": "Böngésző",
@@ -379,8 +377,6 @@ export const dict = {
"prompt.attachment.remove": "Távolítsa el a mellékletet",
"prompt.action.send": "Elküld",
"prompt.action.stop": "Leállítás",
"prompt.toast.pasteUnsupported.title": "Nem támogatott melléklet",
"prompt.toast.pasteUnsupported.description": "Ide csak képeket, PDF-eket vagy szöveges fájlokat lehet csatolni.",
"prompt.toast.attachmentDuplicate.title": "Ezt a fájlt már feltöltötték",
"prompt.toast.modelAgentRequired.title": "Válasszon egy ügynököt és modellt",
"prompt.toast.modelAgentRequired.description": "A felszólítás elküldése előtt válasszon ügynököt és modellt.",
-4
View File
@@ -193,7 +193,6 @@ export const dict = {
"dialog.provider.opencode.note": "Ընտրված մոդելներ, ներառյալ՝ Claude, GPT, Gemini և ավելին",
"dialog.provider.opencode.tagline": "Վստահելի օպտիմիզացված մոդելներ",
"dialog.provider.opencodeGo.tagline": "Ցածր գնով բաժանորդագրություն բոլորի համար",
"dialog.provider.anthropic.note": "Ուղիղ մուտք դեպի Claude մոդելներ, ներառյալ Pro և Max",
"dialog.provider.copilot.note": "AI մոդելներ կոդավորման օգնության համար՝ GitHub Copilot",
"dialog.provider.openai.note": "GPT մոդելներ արագ, ունակ ընդհանուր AI առաջադրանքների համար",
"dialog.provider.google.note": "Gemini մոդելներ արագ, կառուցվածքային պատասխանների համար",
@@ -210,7 +209,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Տես 70+ այլ մատակարարներ",
"dialog.provider.viewAll": "Ցույց տալ ավելի շատ մատակարարներ",
"provider.connect.title": "Միացեք {{provider}}",
"provider.connect.title.anthropicProMax": "Մուտք գործեք Claude Pro/Max-ով",
"provider.connect.selectMethod": "Ընտրեք մուտքի եղանակը {{provider}}-ի համար։",
"provider.connect.method.apiKey": "API բանալի",
"provider.connect.method.browser": "Դիտարկիչ",
@@ -377,8 +375,6 @@ export const dict = {
"prompt.attachment.remove": "Հեռացնել հավելվածը",
"prompt.action.send": "Ուղարկել",
"prompt.action.stop": "Կանգնեցնել",
"prompt.toast.pasteUnsupported.title": "Չաջակցվող հավելված",
"prompt.toast.pasteUnsupported.description": "Այստեղ կարող են կցվել միայն պատկերներ, PDF կամ տեքստային ֆայլեր։",
"prompt.toast.attachmentDuplicate.title": "Այս ֆայլն արդեն վերբեռնվել է",
"prompt.toast.modelAgentRequired.title": "Ընտրեք գործակալ և մոդել",
"prompt.toast.modelAgentRequired.description": "Ընտրեք գործակալ և մոդել՝ նախքան հուշում ուղարկելը։",
-4
View File
@@ -208,7 +208,6 @@ export const dict = {
"dialog.provider.opencode.note": "Model pilihan, termasuk Claude, GPT, Gemini, dan lainnya",
"dialog.provider.opencode.tagline": "Model andal yang dioptimalkan",
"dialog.provider.opencodeGo.tagline": "Langganan terjangkau untuk semua orang",
"dialog.provider.anthropic.note": "Akses langsung ke model Claude, termasuk Pro dan Max",
"dialog.provider.copilot.note": "Model AI untuk bantuan pengodean melalui GitHub Copilot",
"dialog.provider.openai.note": "Model GPT untuk tugas AI umum yang cepat dan mumpuni",
"dialog.provider.google.note": "Model Gemini untuk respons cepat dan terstruktur",
@@ -229,7 +228,6 @@ export const dict = {
"dialog.provider.viewAll": "Tampilkan lebih banyak penyedia",
"provider.connect.title": "Hubungkan {{provider}}",
"provider.connect.title.anthropicProMax": "Masuk dengan Claude Pro/Max",
"provider.connect.selectMethod": "Pilih metode masuk untuk {{provider}}.",
"provider.connect.method.apiKey": "Kunci API",
"provider.connect.method.browser": "Peramban",
@@ -403,8 +401,6 @@ export const dict = {
"prompt.action.send": "Kirim",
"prompt.action.stop": "Hentikan",
"prompt.toast.pasteUnsupported.title": "Lampiran tidak didukung",
"prompt.toast.pasteUnsupported.description": "Hanya gambar, PDF, atau berkas teks yang dapat dilampirkan di sini.",
"prompt.toast.attachmentDuplicate.title": "Berkas ini sudah diunggah",
"prompt.toast.modelAgentRequired.title": "Pilih agen dan model",
"prompt.toast.modelAgentRequired.description": "Pilih agen dan model sebelum mengirim prompt.",
-4
View File
@@ -195,7 +195,6 @@ export const dict = {
"dialog.provider.opencode.note": "Sýndar gerðir þar á meðal Claude, GPT, Gemini og fleira",
"dialog.provider.opencode.tagline": "Áreiðanleg bjartsýni módel",
"dialog.provider.opencodeGo.tagline": "Lággjaldaáskrift fyrir alla",
"dialog.provider.anthropic.note": "Beinn aðgangur að Claude gerðum, þar á meðal Pro og Max",
"dialog.provider.copilot.note": "AI módel fyrir kóðaaðstoð í gegnum GitHub Copilot",
"dialog.provider.openai.note": "GPT gerðir fyrir hröð, fær almenn gervigreind verkefni",
"dialog.provider.google.note": "Gemini módel fyrir hröð, skipulögð viðbrögð",
@@ -212,7 +211,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Sjáðu 70+ þjónustuveitendur í viðbót",
"dialog.provider.viewAll": "Sýna fleiri veitendur",
"provider.connect.title": "Tengdu {{provider}}",
"provider.connect.title.anthropicProMax": "Skráðu þig inn með Claude Pro/Max",
"provider.connect.selectMethod": "Veldu innskráningaraðferð fyrir {{provider}}.",
"provider.connect.method.apiKey": "API lykill",
"provider.connect.method.browser": "Vafri",
@@ -379,8 +377,6 @@ export const dict = {
"prompt.attachment.remove": "Fjarlægðu viðhengi",
"prompt.action.send": "Senda",
"prompt.action.stop": "Stöðva",
"prompt.toast.pasteUnsupported.title": "Óstudd viðhengi",
"prompt.toast.pasteUnsupported.description": "Aðeins er hægt að hengja myndir, PDF-skjöl eða textaskrár hér við.",
"prompt.toast.attachmentDuplicate.title": "Þessari skrá hefur þegar verið hlaðið upp",
"prompt.toast.modelAgentRequired.title": "Veldu fulltrúa og líkan",
"prompt.toast.modelAgentRequired.description": "Veldu fulltrúa og líkan áður en þú sendir kvaðningu.",
-4
View File
@@ -100,7 +100,6 @@ export const dict = {
"dialog.provider.opencode.note": "Modelli selezionati tra cui Claude, GPT, Gemini e altri",
"dialog.provider.opencode.tagline": "Modelli affidabili e ottimizzati",
"dialog.provider.opencodeGo.tagline": "Abbonamento economico per tutti",
"dialog.provider.anthropic.note": "Accesso diretto ai modelli Claude, inclusi Pro e Max",
"dialog.provider.copilot.note": "Modelli di IA per assistere nella programmazione tramite GitHub Copilot",
"dialog.provider.openai.note": "Modelli GPT veloci e potenti per attività generiche di IA",
"dialog.provider.google.note": "Modelli Gemini per risposte rapide e strutturate",
@@ -117,7 +116,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Scopri oltre 70 provider",
"dialog.provider.viewAll": "Mostra altri provider",
"provider.connect.title": "Connetti {{provider}}",
"provider.connect.title.anthropicProMax": "Accedi con Claude Pro/Max",
"provider.connect.selectMethod": "Seleziona il metodo di accesso per {{provider}}.",
"provider.connect.method.apiKey": "Chiave API",
"provider.connect.method.browser": "Browser",
@@ -284,8 +282,6 @@ export const dict = {
"prompt.attachment.remove": "Rimuovi l'allegato",
"prompt.action.send": "Invia",
"prompt.action.stop": "Interrompi",
"prompt.toast.pasteUnsupported.title": "Allegato non supportato",
"prompt.toast.pasteUnsupported.description": "Qui è possibile allegare solo immagini, PDF o file di testo.",
"prompt.toast.attachmentDuplicate.title": "Questo file è già stato caricato",
"prompt.toast.modelAgentRequired.title": "Seleziona un agente e un modello",
"prompt.toast.modelAgentRequired.description": "Scegli un agente e un modello prima di inviare un prompt.",
-4
View File
@@ -198,7 +198,6 @@ export const dict = {
"dialog.provider.opencode.note": "Claude, GPT, Geminiなどを含む厳選されたモデル",
"dialog.provider.opencode.tagline": "信頼性の高い最適化モデル",
"dialog.provider.opencodeGo.tagline": "すべての人に低価格のサブスクリプション",
"dialog.provider.anthropic.note": "ProやMaxを含むClaudeモデルに直接アクセス",
"dialog.provider.copilot.note": "GitHub Copilotを通じてコーディングを支援するAIモデル",
"dialog.provider.openai.note": "高速で高性能な汎用AIタスク向けのGPTモデル",
"dialog.provider.google.note": "高速で構造化された応答のためのGeminiモデル",
@@ -215,7 +214,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "その他70以上のプロバイダーを見る",
"dialog.provider.viewAll": "さらにプロバイダーを表示",
"provider.connect.title": "{{provider}}を接続",
"provider.connect.title.anthropicProMax": "Claude Pro/Maxでログイン",
"provider.connect.selectMethod": "{{provider}}のログイン方法を選択してください。",
"provider.connect.method.apiKey": "APIキー",
"provider.connect.method.browser": "ブラウザ",
@@ -379,9 +377,7 @@ export const dict = {
"prompt.attachment.remove": "添付ファイルを削除",
"prompt.action.send": "送信",
"prompt.action.stop": "停止",
"prompt.toast.pasteUnsupported.title": "サポートされていない添付ファイル",
"prompt.toast.attachmentDuplicate.title": "このファイルはすでにアップロードされています",
"prompt.toast.pasteUnsupported.description": "画像、PDF、またはテキストファイルのみ添付できます。",
"prompt.toast.modelAgentRequired.title": "エージェントとモデルを選択",
"prompt.toast.modelAgentRequired.description": "プロンプトを送信する前にエージェントとモデルを選択してください。",
"prompt.toast.worktreeCreateFailed.title": "ワークツリーの作成に失敗しました",
-4
View File
@@ -191,7 +191,6 @@ export const dict = {
"dialog.provider.opencode.note": "კურირებული მოდელები, მათ შორის Claude, GPT, Gemini და სხვა",
"dialog.provider.opencode.tagline": "სანდო ოპტიმიზებული მოდელები",
"dialog.provider.opencodeGo.tagline": "დაბალფასიანი გამოწერა ყველასთვის",
"dialog.provider.anthropic.note": "პირდაპირი წვდომა Claude მოდელზე, მათ შორის Pro და Max",
"dialog.provider.copilot.note": "AI მოდელები კოდირების დახმარებისთვის GitHub Copilot",
"dialog.provider.openai.note": "GPT მოდელები სწრაფი, ზოგადი AI ამოცანების შესასრულებლად",
"dialog.provider.google.note": "Gemini მოდელები სწრაფი, სტრუქტურირებული პასუხებისთვის",
@@ -208,7 +207,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "იხილეთ 70+ სხვა პროვაიდერი",
"dialog.provider.viewAll": "აჩვენე მეტი პროვაიდერი",
"provider.connect.title": "დაკავშირება {{provider}}",
"provider.connect.title.anthropicProMax": "შესვლა Claude Pro/Max-ით",
"provider.connect.selectMethod": "აირჩიეთ შესვლის მეთოდი {{provider}}-ისთვის.",
"provider.connect.method.apiKey": "API გასაღები",
"provider.connect.method.browser": "ბრაუზერი",
@@ -375,8 +373,6 @@ export const dict = {
"prompt.attachment.remove": "დანართის წაშლა",
"prompt.action.send": "გაგზავნა",
"prompt.action.stop": "შეჩერება",
"prompt.toast.pasteUnsupported.title": "მხარდაუჭერელი დანართი",
"prompt.toast.pasteUnsupported.description": "აქ შეიძლება დაერთოს მხოლოდ სურათები, PDF ან ტექსტური ფაილები.",
"prompt.toast.attachmentDuplicate.title": "ეს ფაილი უკვე ატვირთულია",
"prompt.toast.modelAgentRequired.title": "აირჩიეთ აგენტი და მოდელი",
"prompt.toast.modelAgentRequired.description": "აირჩიეთ აგენტი და მოდელი მოთხოვნის გაგზავნამდე.",
-4
View File
@@ -191,7 +191,6 @@ export const dict = {
"dialog.provider.opencode.note": "ម៉ូដែលដែលបានជ្រើសរើសរួមមាន Claude, GPT, Gemini និងច្រើនទៀត",
"dialog.provider.opencode.tagline": "ម៉ូដែលដែលបានកែលម្អដែលអាចទុកចិត្តបាន។",
"dialog.provider.opencodeGo.tagline": "ការជាវតម្លៃទាបសម្រាប់អ្នករាល់គ្នា",
"dialog.provider.anthropic.note": "ការចូលប្រើដោយផ្ទាល់ទៅកាន់ម៉ូដែល Claude រួមទាំង Pro និង Max",
"dialog.provider.copilot.note": "ម៉ូដែល AI សម្រាប់ជំនួយការសរសេរកូដតាមរយៈ GitHub Copilot",
"dialog.provider.openai.note": "ម៉ូដែល GPT សម្រាប់កិច្ចការ AI ទូទៅដែលមានល្បឿនលឿន និងមានសមត្ថភាព",
"dialog.provider.google.note": "ម៉ូដែល Gemini សម្រាប់ការឆ្លើយតបរហ័ស និងមានរចនាសម្ព័ន្ធ",
@@ -208,7 +207,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "មើលអ្នកផ្តល់សេវា 70+ ទៀត។",
"dialog.provider.viewAll": "បង្ហាញអ្នកផ្តល់សេវាបន្ថែម",
"provider.connect.title": "ភ្ជាប់ {{provider}}",
"provider.connect.title.anthropicProMax": "ចូលដោយប្រើ Claude Pro/Max",
"provider.connect.selectMethod": "ជ្រើសរើសវិធីសាស្ត្រចូលសម្រាប់ {{provider}} ។",
"provider.connect.method.apiKey": "សោ API",
"provider.connect.method.browser": "កម្មវិធីរុករក",
@@ -374,8 +372,6 @@ export const dict = {
"prompt.attachment.remove": "លុបឯកសារភ្ជាប់ចេញ",
"prompt.action.send": "ផ្ញើ",
"prompt.action.stop": "ឈប់",
"prompt.toast.pasteUnsupported.title": "ឯកសារភ្ជាប់ដែលមិនគាំទ្រ",
"prompt.toast.pasteUnsupported.description": "មានតែរូបភាព PDF ឬឯកសារអត្ថបទប៉ុណ្ណោះដែលអាចភ្ជាប់មកទីនេះបាន។",
"prompt.toast.attachmentDuplicate.title": "ឯកសារនេះត្រូវបានផ្ទុកឡើងរួចហើយ",
"prompt.toast.modelAgentRequired.title": "ជ្រើសរើសភ្នាក់ងារ និងម៉ូដែល",
"prompt.toast.modelAgentRequired.description": "ជ្រើសរើសភ្នាក់ងារ និងម៉ូដែលមុនពេលផ្ញើប្រអប់បញ្ចូល។",
-4
View File
@@ -95,7 +95,6 @@ export const dict = {
"dialog.provider.opencode.note": "Claude, GPT, Gemini 등을 포함한 엄선된 모델",
"dialog.provider.opencode.tagline": "신뢰할 수 있는 최적화 모델",
"dialog.provider.opencodeGo.tagline": "모두를 위한 저렴한 구독",
"dialog.provider.anthropic.note": "Pro 및 Max를 포함한 Claude 모델에 직접 액세스",
"dialog.provider.copilot.note": "GitHub Copilot을 통한 코딩 지원용 AI 모델",
"dialog.provider.openai.note": "빠르고 강력한 범용 AI 작업을 위한 GPT 모델",
"dialog.provider.google.note": "빠르고 구조화된 응답을 위한 Gemini 모델",
@@ -112,7 +111,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "70개 이상의 공급자 더 보기",
"dialog.provider.viewAll": "더 많은 공급자 보기",
"provider.connect.title": "{{provider}} 연결",
"provider.connect.title.anthropicProMax": "Claude Pro/Max로 로그인",
"provider.connect.selectMethod": "{{provider}} 로그인 방법 선택",
"provider.connect.method.apiKey": "API 키",
"provider.connect.method.browser": "브라우저",
@@ -268,9 +266,7 @@ export const dict = {
"prompt.attachment.remove": "첨부 파일 제거",
"prompt.action.send": "전송",
"prompt.action.stop": "중지",
"prompt.toast.pasteUnsupported.title": "지원되지 않는 첨부 파일",
"prompt.toast.attachmentDuplicate.title": "이 파일은 이미 업로드되었습니다",
"prompt.toast.pasteUnsupported.description": "이미지, PDF 또는 텍스트 파일만 첨부할 수 있습니다.",
"prompt.toast.modelAgentRequired.title": "에이전트 및 모델 선택",
"prompt.toast.modelAgentRequired.description": "프롬프트를 보내기 전에 에이전트와 모델을 선택하세요.",
"prompt.toast.worktreeCreateFailed.title": "작업 트리 생성 실패",
-4
View File
@@ -191,7 +191,6 @@ export const dict = {
"dialog.provider.opencode.note": "ແບບທີ່ຄັດສັນມາລວມທັງ Claude, GPT, Gemini ແລະອື່ນໆ",
"dialog.provider.opencode.tagline": "ຮູບແບບການເພີ່ມປະສິດທິພາບທີ່ເຊື່ອຖືໄດ້",
"dialog.provider.opencodeGo.tagline": "ການສະໝັກໃຊ້ລາຄາຕໍ່າສຳລັບທຸກຄົນ",
"dialog.provider.anthropic.note": "ເຂົ້າເຖິງຕົວແບບ Claude ໂດຍກົງ, ລວມທັງ Pro ແລະ Max",
"dialog.provider.copilot.note": "ຮູບແບບ AI ສໍາລັບການຊ່ວຍເຫຼືອການເຂົ້າລະຫັດຜ່ານ GitHub Copilot",
"dialog.provider.openai.note": "ແບບ GPT ສໍາລັບວຽກງານ AI ທົ່ວໄປທີ່ໄວ, ມີຄວາມສາມາດ",
"dialog.provider.google.note": "ແບບ Gemini ສໍາລັບການຕອບສະຫນອງໄວ, ມີໂຄງສ້າງ",
@@ -208,7 +207,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "ເບິ່ງ 70+ ຜູ້ໃຫ້ບໍລິການເພີ່ມເຕີມ",
"dialog.provider.viewAll": "ສະແດງຜູ້ໃຫ້ບໍລິການເພີ່ມເຕີມ",
"provider.connect.title": "ເຊື່ອມຕໍ່ {{provider}}",
"provider.connect.title.anthropicProMax": "ເຂົ້າສູ່ລະບົບດ້ວຍ Claude Pro/Max",
"provider.connect.selectMethod": "ເລືອກວິທີການເຂົ້າສູ່ລະບົບສໍາລັບ {{provider}}.",
"provider.connect.method.apiKey": "ລະຫັດ API",
"provider.connect.method.browser": "ຕົວທ່ອງເວັບ",
@@ -374,8 +372,6 @@ export const dict = {
"prompt.attachment.remove": "ເອົາໄຟລ໌ແນບອອກ",
"prompt.action.send": "ສົ່ງ",
"prompt.action.stop": "ຢຸດ",
"prompt.toast.pasteUnsupported.title": "ບໍ່ຮອງຮັບໄຟລ໌ແນບ",
"prompt.toast.pasteUnsupported.description": "ພຽງແຕ່ຮູບພາບ, PDFs, ຫຼືໄຟລ໌ຂໍ້ຄວາມສາມາດຕິດຢູ່ນີ້.",
"prompt.toast.attachmentDuplicate.title": "ໄຟລ໌ນີ້ໄດ້ຖືກອັບໂຫລດໄປກ່ອນແລ້ວ",
"prompt.toast.modelAgentRequired.title": "ເລືອກຕົວແທນ ແລະຕົວແບບ",
"prompt.toast.modelAgentRequired.description": "ເລືອກຕົວແທນ ແລະຕົວແບບກ່ອນສົ່ງ prompt.",
-4
View File
@@ -195,7 +195,6 @@ export const dict = {
"dialog.provider.opencode.note": "Kuruojami modeliai, įskaitant Claude, GPT, Gemini ir kt.",
"dialog.provider.opencode.tagline": "Patikimi optimizuoti modeliai",
"dialog.provider.opencodeGo.tagline": "Mažos kainos abonementas visiems",
"dialog.provider.anthropic.note": "Tiesioginė prieiga prie Claude modelių, įskaitant Pro ir Max",
"dialog.provider.copilot.note": "AI modeliai, skirti kodavimo pagalbai per GitHub Copilot",
"dialog.provider.openai.note": "GPT modeliai, skirti greitoms, bendroms AI užduotims atlikti",
"dialog.provider.google.note": "Gemini modeliai greitiems, struktūriniams atsakymams",
@@ -212,7 +211,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Žr. daugiau nei 70 tiekėjų",
"dialog.provider.viewAll": "Rodyti daugiau teikėjų",
"provider.connect.title": "Prijunkite {{provider}}",
"provider.connect.title.anthropicProMax": "Prisijunkite naudodami Claude Pro/Max",
"provider.connect.selectMethod": "Pasirinkite {{provider}} prisijungimo būdą.",
"provider.connect.method.apiKey": "API raktas",
"provider.connect.method.browser": "Naršyklė",
@@ -380,8 +378,6 @@ export const dict = {
"prompt.attachment.remove": "Pašalinti priedą",
"prompt.action.send": "Siųsti",
"prompt.action.stop": "Stabdyti",
"prompt.toast.pasteUnsupported.title": "Nepalaikomas priedas",
"prompt.toast.pasteUnsupported.description": "Čia galima pridėti tik vaizdus, PDF arba tekstinius failus.",
"prompt.toast.attachmentDuplicate.title": "Šis failas jau buvo įkeltas",
"prompt.toast.modelAgentRequired.title": "Pasirinkite agentą ir modelį",
"prompt.toast.modelAgentRequired.description": "Prieš siųsdami raginimą, pasirinkite agentą ir modelį.",
-4
View File
@@ -191,7 +191,6 @@ export const dict = {
"dialog.provider.opencode.note": "Atlasīti modeļi, tostarp Claude, GPT, Gemini un citi",
"dialog.provider.opencode.tagline": "Uzticami optimizēti modeļi",
"dialog.provider.opencodeGo.tagline": "Zemas cenas abonements visiem",
"dialog.provider.anthropic.note": "Tieša piekļuve Claude modeļiem, tostarp Pro un Max",
"dialog.provider.copilot.note": "AI modeļi programmēšanas atbalstam ar GitHub Copilot",
"dialog.provider.openai.note": "GPT modeļi ātriem, spējīgiem vispārējiem AI uzdevumiem",
"dialog.provider.google.note": "Gemini modeļi ātrām, strukturētām atbildēm",
@@ -208,7 +207,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Skatīt vēl 70+ nodrošinātājus",
"dialog.provider.viewAll": "Rādīt vairāk nodrošinātāju",
"provider.connect.title": "Savienot {{provider}}",
"provider.connect.title.anthropicProMax": "Pieteikties ar Claude Pro/Max",
"provider.connect.selectMethod": "Izvēlieties pieteikšanās metodi pakalpojumam {{provider}}.",
"provider.connect.method.apiKey": "API atslēga",
"provider.connect.method.browser": "Pārlūks",
@@ -375,8 +373,6 @@ export const dict = {
"prompt.attachment.remove": "Noņemt pielikumu",
"prompt.action.send": "Sūtīt",
"prompt.action.stop": "Apturēt",
"prompt.toast.pasteUnsupported.title": "Neatbalstīts pielikums",
"prompt.toast.pasteUnsupported.description": "Šeit var pievienot tikai attēlus, PDF vai teksta failus.",
"prompt.toast.attachmentDuplicate.title": "Šis fails jau ir augšupielādēts",
"prompt.toast.modelAgentRequired.title": "Izvēlieties aģentu un modeli",
"prompt.toast.modelAgentRequired.description": "Pirms nosūtīšanas izvēlieties aģentu un modeli.",
-4
View File
@@ -192,7 +192,6 @@ export const dict = {
"dialog.provider.opencode.note": "Курирани модели вклучувајќи Claude, GPT, Gemini и повеќе",
"dialog.provider.opencode.tagline": "Сигурни оптимизирани модели",
"dialog.provider.opencodeGo.tagline": "Ниска цена претплата за секого",
"dialog.provider.anthropic.note": "Директен пристап до Claude модели, вклучувајќи ги Pro и Max",
"dialog.provider.copilot.note": "Модели со вештачка интелигенција за помош за кодирање преку GitHub Copilot",
"dialog.provider.openai.note": "GPT модели за брзи, способни општи задачи со вештачка интелигенција",
"dialog.provider.google.note": "Gemini модели за брзи, структурирани одговори",
@@ -209,7 +208,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Видете повеќе од 70 провајдери",
"dialog.provider.viewAll": "Прикажи повеќе провајдери",
"provider.connect.title": "Поврзете се {{provider}}",
"provider.connect.title.anthropicProMax": "Најавете се со Claude Pro/Max",
"provider.connect.selectMethod": "Изберете метод за најавување за {{provider}}.",
"provider.connect.method.apiKey": "клуч API",
"provider.connect.method.browser": "Прелистувач",
@@ -376,8 +374,6 @@ export const dict = {
"prompt.attachment.remove": "Отстранете го прилогот",
"prompt.action.send": "Испрати",
"prompt.action.stop": "Стоп",
"prompt.toast.pasteUnsupported.title": "Неподдржан прилог",
"prompt.toast.pasteUnsupported.description": "Овде може да се прикачат само слики, PDFs или текстуални датотеки.",
"prompt.toast.attachmentDuplicate.title": "Оваа датотека е веќе поставена",
"prompt.toast.modelAgentRequired.title": "Изберете агент и модел",
"prompt.toast.modelAgentRequired.description": "Изберете агент и модел пред да испратите известување.",
-4
View File
@@ -194,7 +194,6 @@ export const dict = {
"dialog.provider.opencode.note": "Claude, GPT, Gemini болон бусад загваруудыг сонгон шалгаруулсан",
"dialog.provider.opencode.tagline": "Найдвартай оновчтой загварууд",
"dialog.provider.opencodeGo.tagline": "Хүн бүрт зориулсан хямд өртөгтэй захиалга",
"dialog.provider.anthropic.note": "Pro болон Max зэрэг Claude загварт шууд хандах",
"dialog.provider.copilot.note": "GitHub Copilot-ээр дамжуулан кодлоход туслах хиймэл оюун ухааны загварууд",
"dialog.provider.openai.note": "GPT AI-ийн хурдан, чадвартай ерөнхий ажлуудад зориулсан загварууд",
"dialog.provider.google.note": "Gemini хурдан, бүтэцтэй хариулт өгөх загварууд",
@@ -211,7 +210,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Өөр 70 гаруй үйлчилгээ үзүүлэгчийг харна уу",
"dialog.provider.viewAll": "Илүү олон үйлчилгээ үзүүлэгчийг харуулах",
"provider.connect.title": "Холбох {{provider}}",
"provider.connect.title.anthropicProMax": "Claude Pro/Max-аар нэвтэрнэ үү",
"provider.connect.selectMethod": "{{provider}}-д нэвтрэх аргыг сонгоно уу.",
"provider.connect.method.apiKey": "API түлхүүр",
"provider.connect.method.browser": "Хөтөч",
@@ -378,8 +376,6 @@ export const dict = {
"prompt.attachment.remove": "Хавсралтыг устгана уу",
"prompt.action.send": "Илгээх",
"prompt.action.stop": "Зогс",
"prompt.toast.pasteUnsupported.title": "Дэмжигдээгүй хавсралт",
"prompt.toast.pasteUnsupported.description": "Энд зөвхөн зураг, PDFс, эсвэл текст файлыг хавсаргах боломжтой.",
"prompt.toast.attachmentDuplicate.title": "Энэ файлыг аль хэдийн байршуулсан байна",
"prompt.toast.modelAgentRequired.title": "Агент болон загварыг сонгоно уу",
"prompt.toast.modelAgentRequired.description": "Промпт илгээхээсээ өмнө агент болон загварыг сонгоно уу.",
-4
View File
@@ -191,7 +191,6 @@ export const dict = {
"dialog.provider.opencode.note": "Model terpilih termasuk Claude, GPT, Gemini dan banyak lagi",
"dialog.provider.opencode.tagline": "Model dioptimumkan yang boleh dipercayai",
"dialog.provider.opencodeGo.tagline": "Langganan kos rendah untuk semua",
"dialog.provider.anthropic.note": "Akses terus ke model Claude, termasuk Pro dan Max",
"dialog.provider.copilot.note": "Model AI untuk bantuan pengekodan melalui GitHub Copilot",
"dialog.provider.openai.note": "Model GPT untuk tugasan AI umum yang pantas dan berkeupayaan",
"dialog.provider.google.note": "Model Gemini untuk respons pantas dan berstruktur",
@@ -208,7 +207,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Lihat 70+ lagi penyedia",
"dialog.provider.viewAll": "Tunjukkan lebih banyak penyedia",
"provider.connect.title": "Sambungkan {{provider}}",
"provider.connect.title.anthropicProMax": "Log masuk dengan Claude Pro/Max",
"provider.connect.selectMethod": "Pilih kaedah log masuk untuk {{provider}}.",
"provider.connect.method.apiKey": "Kunci API",
"provider.connect.method.browser": "Pelayar",
@@ -375,8 +373,6 @@ export const dict = {
"prompt.attachment.remove": "Buang lampiran",
"prompt.action.send": "Hantar",
"prompt.action.stop": "Henti",
"prompt.toast.pasteUnsupported.title": "Lampiran tidak disokong",
"prompt.toast.pasteUnsupported.description": "Hanya imej, PDF, atau fail teks boleh dilampirkan di sini.",
"prompt.toast.attachmentDuplicate.title": "Fail ini telah dimuat naik",
"prompt.toast.modelAgentRequired.title": "Pilih ejen dan model",
"prompt.toast.modelAgentRequired.description": "Pilih ejen dan model sebelum menghantar prompt.",
-5
View File
@@ -193,7 +193,6 @@ export const dict = {
"dialog.provider.opencode.note": "Claude၊ GPT၊ Gemini နှင့် အခြားအရာများ အပါအဝင် ရွေးချယ်ထားသော မော်ဒယ်များ",
"dialog.provider.opencode.tagline": "ယုံကြည်စိတ်ချရသော အကောင်းဆုံးပြင်ဆင်ထားသော မော်ဒယ်များ",
"dialog.provider.opencodeGo.tagline": "လူတိုင်းအတွက် ကုန်ကျစရိတ်သက်သာသော စာရင်းသွင်းမှု",
"dialog.provider.anthropic.note": "Pro နှင့် Max အပါအဝင် Claude မော်ဒယ်များသို့ တိုက်ရိုက်ဝင်ရောက်ခွင့်",
"dialog.provider.copilot.note": "GitHub Copilot မှတစ်ဆင့် ကုဒ်ရေးနည်းအကူအညီအတွက် AI မော်ဒယ်များ",
"dialog.provider.openai.note": "လျင်မြန်ပြီး လုပ်ဆောင်နိုင်သော အထွေထွေ AI လုပ်ဆောင်ချက်များအတွက် GPT မော်ဒယ်များ",
"dialog.provider.google.note": "မြန်ဆန်ပြီး ဖွဲ့စည်းတည်ဆောက်ထားသော တုံ့ပြန်မှုများအတွက် Gemini မော်ဒယ်များ",
@@ -210,7 +209,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "နောက်ထပ်ပံ့ပိုးပေးသူ 70+ ကိုကြည့်ပါ။",
"dialog.provider.viewAll": "နောက်ထပ်ဝန်ဆောင်မှုပေးသူများကို ပြပါ။",
"provider.connect.title": "{{provider}} ကို ချိတ်ဆက်ပါ။",
"provider.connect.title.anthropicProMax": "Claude Pro/Max ဖြင့် ဝင်ရောက်ပါ။",
"provider.connect.selectMethod": "{{provider}} အတွက် အကောင့်ဝင်နည်းလမ်းကို ရွေးပါ။",
"provider.connect.method.apiKey": "API သော့",
"provider.connect.method.browser": "ဘရောက်ဆာ",
@@ -378,9 +376,6 @@ export const dict = {
"prompt.attachment.remove": "ပူးတွဲပါဖိုင်ကို ဖယ်ရှားပါ။",
"prompt.action.send": "ပို့ပါ။",
"prompt.action.stop": "ရပ်ပါ။",
"prompt.toast.pasteUnsupported.title": "ပူးတွဲပါဖိုင်ကို ပံ့ပိုးမထားပါ။",
"prompt.toast.pasteUnsupported.description":
"ရုပ်ပုံများ၊ PDF များ သို့မဟုတ် စာသားဖိုင်များကိုသာ ဤနေရာတွင် ပူးတွဲနိုင်ပါသည်။",
"prompt.toast.attachmentDuplicate.title": "ဤဖိုင်ကို အပ်လုဒ်လုပ်ပြီးပါပြီ။",
"prompt.toast.modelAgentRequired.title": "အေးဂျင့်နှင့် မော်ဒယ်ကို ရွေးပါ။",
"prompt.toast.modelAgentRequired.description": "Prompt မပို့မီ အေးဂျင့်နှင့် မော်ဒယ်ကို ရွေးပါ။",
-4
View File
@@ -192,7 +192,6 @@ export const dict: Record<string, string> = {
"dialog.provider.opencode.note": "Claude, GPT, Gemini र थप सहित क्युरेट गरिएका मोडेलहरू",
"dialog.provider.opencode.tagline": "भरपर्दो अनुकूलित मोडेलहरू",
"dialog.provider.opencodeGo.tagline": "सबैको लागि कम लागत सदस्यता",
"dialog.provider.anthropic.note": "प्रो र म्याक्स सहित Claude मोडेलहरूमा प्रत्यक्ष पहुँच",
"dialog.provider.copilot.note": "GitHub Copilot मार्फत कोडिङ सहायताका लागि AI मोडेलहरू",
"dialog.provider.openai.note": "छिटो, सक्षम सामान्य AI कार्यहरूको लागि GPT मोडेलहरू",
"dialog.provider.google.note": "छिटो, संरचित प्रतिक्रियाहरूको लागि Gemini मोडेलहरू",
@@ -209,7 +208,6 @@ export const dict: Record<string, string> = {
"dialog.model.unpaid.viewMoreProviders": "70+ थप प्रदायकहरू हेर्नुहोस्",
"dialog.provider.viewAll": "थप प्रदायकहरू देखाउनुहोस्",
"provider.connect.title": "जडान गर्नुहोस् {{provider}}",
"provider.connect.title.anthropicProMax": "Claude Pro/Max सँग लगइन गर्नुहोस्",
"provider.connect.selectMethod": "{{provider}} का लागि लगइन विधि चयन गर्नुहोस्।",
"provider.connect.method.apiKey": "API कुञ्जी",
"provider.connect.method.browser": "ब्राउजर",
@@ -376,8 +374,6 @@ export const dict: Record<string, string> = {
"prompt.attachment.remove": "संलग्नक हटाउनुहोस्",
"prompt.action.send": "पठाउनुहोस्",
"prompt.action.stop": "रोक्नुहोस्",
"prompt.toast.pasteUnsupported.title": "असमर्थित संलग्नक",
"prompt.toast.pasteUnsupported.description": "केवल छविहरू, PDF हरू, वा पाठ फाइलहरू यहाँ संलग्न गर्न सकिन्छ।",
"prompt.toast.attachmentDuplicate.title": "यो फाइल पहिले नै अपलोड गरिएको छ",
"prompt.toast.modelAgentRequired.title": "एक एजेन्ट र मोडेल चयन गर्नुहोस्",
"prompt.toast.modelAgentRequired.description": "प्रम्प्ट पठाउनु अघि एजेन्ट र मोडेल छान्नुहोस्।",
-5
View File
@@ -192,7 +192,6 @@ export const dict = {
"dialog.provider.opencode.note": "Samengestelde modellen, waaronder Claude, GPT, Gemini en meer",
"dialog.provider.opencode.tagline": "Betrouwbare geoptimaliseerde modellen",
"dialog.provider.opencodeGo.tagline": "Goedkoop abonnement voor iedereen",
"dialog.provider.anthropic.note": "Directe toegang tot Claude-modellen, inclusief Pro en Max",
"dialog.provider.copilot.note": "AI-modellen voor codeerondersteuning via GitHub Copilot",
"dialog.provider.openai.note": "GPT-modellen voor snelle, capabele algemene AI-taken",
"dialog.provider.google.note": "Gemini-modellen voor snelle, gestructureerde reacties",
@@ -209,7 +208,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Bekijk nog 70+ aanbieders",
"dialog.provider.viewAll": "Toon meer aanbieders",
"provider.connect.title": "Verbinding maken met {{provider}}",
"provider.connect.title.anthropicProMax": "Inloggen met Claude Pro/Max",
"provider.connect.selectMethod": "Selecteer de aanmeldingsmethode voor {{provider}}.",
"provider.connect.method.apiKey": "API-sleutel",
"provider.connect.method.browser": "Browser",
@@ -375,9 +373,6 @@ export const dict = {
"prompt.attachment.remove": "Bijlage verwijderen",
"prompt.action.send": "Verzenden",
"prompt.action.stop": "Stop",
"prompt.toast.pasteUnsupported.title": "Niet-ondersteunde bijlage",
"prompt.toast.pasteUnsupported.description":
"Hier kunnen alleen afbeeldingen, pdf's of tekstbestanden worden bijgevoegd.",
"prompt.toast.attachmentDuplicate.title": "Dit bestand is al geüpload",
"prompt.toast.modelAgentRequired.title": "Selecteer een agent en model",
"prompt.toast.modelAgentRequired.description": "Kies een agent en model voordat je een prompt verzendt.",
-4
View File
@@ -206,7 +206,6 @@ export const dict = {
"dialog.provider.opencode.note": "Utvalgte modeller inkludert Claude, GPT, Gemini og mer",
"dialog.provider.opencode.tagline": "Pålitelige, optimaliserte modeller",
"dialog.provider.opencodeGo.tagline": "Rimelig abonnement for alle",
"dialog.provider.anthropic.note": "Direkte tilgang til Claude-modeller, inkludert Pro og Max",
"dialog.provider.copilot.note": "AI-modeller for kodeassistanse via GitHub Copilot",
"dialog.provider.openai.note": "GPT-modeller for raske, dyktige generelle AI-oppgaver",
"dialog.provider.google.note": "Gemini-modeller for raske, strukturerte svar",
@@ -227,7 +226,6 @@ export const dict = {
"dialog.provider.viewAll": "Vis flere leverandører",
"provider.connect.title": "Koble til {{provider}}",
"provider.connect.title.anthropicProMax": "Logg inn med Claude Pro/Max",
"provider.connect.selectMethod": "Velg innloggingsmetode for {{provider}}.",
"provider.connect.method.apiKey": "API-nøkkel",
"provider.connect.method.browser": "Nettleser",
@@ -393,9 +391,7 @@ export const dict = {
"prompt.action.send": "Send",
"prompt.action.stop": "Stopp",
"prompt.toast.pasteUnsupported.title": "Ikke støttet vedlegg",
"prompt.toast.attachmentDuplicate.title": "Denne filen er allerede lastet opp",
"prompt.toast.pasteUnsupported.description": "Kun bilder, PDF-er eller tekstfiler kan legges ved her.",
"prompt.toast.modelAgentRequired.title": "Velg en agent og modell",
"prompt.toast.modelAgentRequired.description": "Velg en agent og modell før du sender en forespørsel.",
"prompt.toast.worktreeCreateFailed.title": "Kunne ikke opprette worktree",
-5
View File
@@ -198,7 +198,6 @@ export const dict = {
"dialog.provider.opencode.note": "Claude، GPT، Gemini تے ہور سمیت کیوریٹڈ ماڈل",
"dialog.provider.opencode.tagline": "قابل اعتماد اصلاح شدہ ماڈل",
"dialog.provider.opencodeGo.tagline": "ہر اک لئی گھٹ قیمت دی رکنیت",
"dialog.provider.anthropic.note": "پرو تے میکس سمیت Claude ماڈل تک براہ راست رسائی",
"dialog.provider.copilot.note": "GitHub Copilot دے ذریعے کوڈنگ دی مدد لئی اے آئی ماڈل",
"dialog.provider.openai.note": "تیز تے صلاحیت والے عام AI کماں لئی GPT ماڈل",
"dialog.provider.google.note": "تیز تے منظم جواباں لئی Gemini ماڈل",
@@ -215,7 +214,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "70+ ہور پرووائیڈر ویکھو",
"dialog.provider.viewAll": "ہور پرووائیڈر وکھاؤ",
"provider.connect.title": "{{provider}} نال جڑو",
"provider.connect.title.anthropicProMax": "Claude پرو/میکس دے نال لاگ ان کرو",
"provider.connect.selectMethod": "{{provider}} لئی لاگ ان دا طریقہ منتخب کرو۔",
"provider.connect.method.apiKey": "API کلید",
"provider.connect.method.browser": "براؤزر",
@@ -381,9 +379,6 @@ export const dict = {
"prompt.attachment.remove": "منسلکہ ہٹا دیو",
"prompt.action.send": "گھلو",
"prompt.action.stop": "روکو",
"prompt.toast.pasteUnsupported.title": "غیر تعاون یافتہ منسلکہ",
"prompt.toast.pasteUnsupported.description":
"ایتھے صرف تصویراں، پی ڈی ایف، یا ٹیکسٹ فائلاں منسلک کیتیاں جا سکدیاں نیں۔",
"prompt.toast.attachmentDuplicate.title": "ایہہ فائل پہلے ای اپ لوڈ ہو چکی اے",
"prompt.toast.modelAgentRequired.title": "اک ایجنٹ تے ماڈل چنو",
"prompt.toast.modelAgentRequired.description": "پرامپٹ بھیجن توں پہلاں اک ایجنٹ تے ماڈل دا انتخاب کرو۔",
-4
View File
@@ -199,7 +199,6 @@ export const dict = {
"dialog.provider.opencode.note": "Starannie dobrane modele, w tym Claude, GPT, Gemini i inne",
"dialog.provider.opencode.tagline": "Niezawodne, zoptymalizowane modele",
"dialog.provider.opencodeGo.tagline": "Niedroga subskrypcja dla każdego",
"dialog.provider.anthropic.note": "Bezpośredni dostęp do modeli Claude, w tym Pro i Max",
"dialog.provider.copilot.note": "Modele AI do pomocy w kodowaniu przez GitHub Copilot",
"dialog.provider.openai.note": "Modele GPT do szybkich i wszechstronnych zadań AI",
"dialog.provider.google.note": "Modele Gemini do szybkich i ustrukturyzowanych odpowiedzi",
@@ -216,7 +215,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Zobacz ponad 70 innych dostawców",
"dialog.provider.viewAll": "Zobacz więcej dostawców",
"provider.connect.title": "Połącz {{provider}}",
"provider.connect.title.anthropicProMax": "Zaloguj się za pomocą konta Claude Pro/Max",
"provider.connect.selectMethod": "Wybierz metodę logowania dla {{provider}}.",
"provider.connect.method.apiKey": "Klucz API",
"provider.connect.method.browser": "Przeglądarka",
@@ -382,9 +380,7 @@ export const dict = {
"prompt.attachment.remove": "Usuń załącznik",
"prompt.action.send": "Wyślij",
"prompt.action.stop": "Zatrzymaj",
"prompt.toast.pasteUnsupported.title": "Nieobsługiwany załącznik",
"prompt.toast.attachmentDuplicate.title": "Ten plik został już przesłany",
"prompt.toast.pasteUnsupported.description": "Można tutaj załączać tylko obrazy, pliki PDF lub pliki tekstowe.",
"prompt.toast.modelAgentRequired.title": "Wybierz agenta i model",
"prompt.toast.modelAgentRequired.description": "Wybierz agenta i model przed wysłaniem zapytania.",
"prompt.toast.worktreeCreateFailed.title": "Nie udało się utworzyć drzewa roboczego",
-4
View File
@@ -191,7 +191,6 @@ export const dict = {
"dialog.provider.opencode.note": "Modele selectate, inclusiv Claude, GPT, Gemini și altele",
"dialog.provider.opencode.tagline": "Modele optimizate, fiabile",
"dialog.provider.opencodeGo.tagline": "Abonament accesibil pentru toți",
"dialog.provider.anthropic.note": "Acces direct la modelele Claude, inclusiv Pro și Max",
"dialog.provider.copilot.note": "Modele AI pentru asistență la programare prin GitHub Copilot",
"dialog.provider.openai.note": "Modele GPT pentru sarcini AI generale rapide și performante",
"dialog.provider.google.note": "Modele Gemini pentru răspunsuri rapide și structurate",
@@ -208,7 +207,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Vezi peste 70 de furnizori",
"dialog.provider.viewAll": "Afișează mai mulți furnizori",
"provider.connect.title": "Conectează {{provider}}",
"provider.connect.title.anthropicProMax": "Autentificare cu Claude Pro/Max",
"provider.connect.selectMethod": "Selectează metoda de autentificare pentru {{provider}}.",
"provider.connect.method.apiKey": "Cheie API",
"provider.connect.method.browser": "Navigator",
@@ -374,8 +372,6 @@ export const dict = {
"prompt.attachment.remove": "Elimină atașamentul",
"prompt.action.send": "Trimite",
"prompt.action.stop": "Oprește",
"prompt.toast.pasteUnsupported.title": "Atașament neacceptat",
"prompt.toast.pasteUnsupported.description": "Poți atașa doar imagini, PDF-uri sau fișiere text aici.",
"prompt.toast.attachmentDuplicate.title": "Acest fișier a fost deja încărcat",
"prompt.toast.modelAgentRequired.title": "Selectează un agent și un model",
"prompt.toast.modelAgentRequired.description": "Alege un agent și un model înainte de a trimite un prompt.",
-4
View File
@@ -207,7 +207,6 @@ export const dict = {
"dialog.provider.opencode.note": "Отобранные модели, включая Claude, GPT, Gemini и другие",
"dialog.provider.opencode.tagline": "Надёжные оптимизированные модели",
"dialog.provider.opencodeGo.tagline": "Доступная подписка для всех",
"dialog.provider.anthropic.note": "Прямой доступ к моделям Claude, включая Pro и Max",
"dialog.provider.copilot.note": "ИИ-модели для помощи в кодировании через GitHub Copilot",
"dialog.provider.openai.note": "Модели GPT для быстрых и мощных задач общего ИИ",
"dialog.provider.google.note": "Модели Gemini для быстрых и структурированных ответов",
@@ -228,7 +227,6 @@ export const dict = {
"dialog.provider.viewAll": "Показать больше провайдеров",
"provider.connect.title": "Подключить {{provider}}",
"provider.connect.title.anthropicProMax": "Войти с помощью Claude Pro/Max",
"provider.connect.selectMethod": "Выберите способ входа для {{provider}}.",
"provider.connect.method.apiKey": "Ключ API",
"provider.connect.method.browser": "Браузер",
@@ -401,9 +399,7 @@ export const dict = {
"prompt.action.send": "Отправить",
"prompt.action.stop": "Остановить",
"prompt.toast.pasteUnsupported.title": "Неподдерживаемое вложение",
"prompt.toast.attachmentDuplicate.title": "Этот файл уже загружен",
"prompt.toast.pasteUnsupported.description": "Здесь можно прикрепить только изображения, PDF или текстовые файлы.",
"prompt.toast.modelAgentRequired.title": "Выберите агента и модель",
"prompt.toast.modelAgentRequired.description": "Выберите агента и модель перед отправкой запроса.",
"prompt.toast.worktreeCreateFailed.title": "Не удалось создать worktree",
-4
View File
@@ -191,7 +191,6 @@ export const dict: Record<string, string> = {
"dialog.provider.opencode.note": "Claude, GPT, Gemini සහ තවත් දේ ඇතුළුව සංවෘත ආකෘති",
"dialog.provider.opencode.tagline": "විශ්වසනීය ප්රශස්ත මාදිලි",
"dialog.provider.opencodeGo.tagline": "සෑම කෙනෙකුටම අඩු වියදම් දායකත්වයක්",
"dialog.provider.anthropic.note": "Pro සහ Max ඇතුළුව Claude මාදිලි වෙත සෘජු ප්‍රවේශය",
"dialog.provider.copilot.note": "GitHub Copilot හරහා කේතීකරණ සහාය සඳහා AI ආකෘති",
"dialog.provider.openai.note": "වේගවත්, හැකියාව ඇති සාමාන්‍ය AI කාර්යයන් සඳහා GPT මාදිලි",
"dialog.provider.google.note": "වේගවත්, ව්‍යුහගත ප්‍රතිචාර සඳහා Gemini ආකෘති",
@@ -208,7 +207,6 @@ export const dict: Record<string, string> = {
"dialog.model.unpaid.viewMoreProviders": "තවත් සපයන්නන් 70+ බලන්න",
"dialog.provider.viewAll": "තවත් සපයන්නන් පෙන්වන්න",
"provider.connect.title": "{{provider}} සම්බන්ධ කරන්න",
"provider.connect.title.anthropicProMax": "Claude Pro/Max සමඟින් පුරනය වන්න",
"provider.connect.selectMethod": "{{provider}} සඳහා පිවිසුම් ක්‍රමය තෝරන්න.",
"provider.connect.method.apiKey": "API යතුර",
"provider.connect.method.browser": "බ්රවුසරය",
@@ -374,8 +372,6 @@ export const dict: Record<string, string> = {
"prompt.attachment.remove": "ඇමුණුම ඉවත් කරන්න",
"prompt.action.send": "යවන්න",
"prompt.action.stop": "නවත්වන්න",
"prompt.toast.pasteUnsupported.title": "සහාය නොදක්වන ඇමුණුම",
"prompt.toast.pasteUnsupported.description": "පින්තූර, PDF හෝ පෙළ ගොනු පමණක් මෙහි ඇමිණිය හැක.",
"prompt.toast.attachmentDuplicate.title": "මෙම ගොනුව දැනටමත් උඩුගත කර ඇත",
"prompt.toast.modelAgentRequired.title": "නියෝජිතයෙකු සහ ආකෘතියක් තෝරන්න",
"prompt.toast.modelAgentRequired.description": "ප්‍රොම්ප්ට් එකක් යැවීමට පෙර නියෝජිතයෙකු සහ ආකෘතියක් තෝරන්න.",
-4
View File
@@ -191,7 +191,6 @@ export const dict = {
"dialog.provider.opencode.note": "Vybrané modely vrátane Claude, GPT, Gemini a ďalších",
"dialog.provider.opencode.tagline": "Spoľahlivé optimalizované modely",
"dialog.provider.opencodeGo.tagline": "Nízkonákladové predplatné pre každého",
"dialog.provider.anthropic.note": "Priamy prístup k modelom Claude vrátane Pro a Max",
"dialog.provider.copilot.note": "AI modely na asistenciu pri kódovaní cez GitHub Copilot",
"dialog.provider.openai.note": "GPT modely na rýchle a výkonné všeobecné AI úlohy",
"dialog.provider.google.note": "Gemini modely na rýchle, štruktúrované odpovede",
@@ -208,7 +207,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Zobraziť viac ako 70 ďalších poskytovateľov",
"dialog.provider.viewAll": "Zobraziť viac poskytovateľov",
"provider.connect.title": "Pripojiť {{provider}}",
"provider.connect.title.anthropicProMax": "Prihlásiť sa cez Claude Pro/Max",
"provider.connect.selectMethod": "Vyberte spôsob prihlásenia pre {{provider}}.",
"provider.connect.method.apiKey": "API kľúč",
"provider.connect.method.browser": "Prehliadač",
@@ -374,8 +372,6 @@ export const dict = {
"prompt.attachment.remove": "Odstrániť prílohu",
"prompt.action.send": "Odoslať",
"prompt.action.stop": "Zastaviť",
"prompt.toast.pasteUnsupported.title": "Nepodporovaná príloha",
"prompt.toast.pasteUnsupported.description": "Pripojiť možno len obrázky, PDF alebo textové súbory.",
"prompt.toast.attachmentDuplicate.title": "Tento súbor už bol nahraný",
"prompt.toast.modelAgentRequired.title": "Vyberte agenta a model",
"prompt.toast.modelAgentRequired.description": "Pred odoslaním výzvy vyberte agenta a model.",
-4
View File
@@ -191,7 +191,6 @@ export const dict = {
"dialog.provider.opencode.note": "Izbrani modeli, vključno z Claude, GPT, Gemini in drugimi",
"dialog.provider.opencode.tagline": "Zanesljivi optimizirani modeli",
"dialog.provider.opencodeGo.tagline": "Poceni naročnina za vsakogar",
"dialog.provider.anthropic.note": "Neposreden dostop do modelov Claude, vključno s Pro in Max",
"dialog.provider.copilot.note": "Modeli AI za pomoč pri kodiranju prek GitHub Copilot",
"dialog.provider.openai.note": "Modeli GPT za hitre in zmogljive splošne naloge z umetno inteligenco",
"dialog.provider.google.note": "Modeli Gemini za hitre, strukturirane odzive",
@@ -208,7 +207,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Oglejte si več kot 70 ponudnikov",
"dialog.provider.viewAll": "Pokaži več ponudnikov",
"provider.connect.title": "Povežite {{provider}}",
"provider.connect.title.anthropicProMax": "Prijavite se z Claude Pro/Max",
"provider.connect.selectMethod": "Izberite način prijave za {{provider}}.",
"provider.connect.method.apiKey": "Ključ API",
"provider.connect.method.browser": "Brskalnik",
@@ -374,8 +372,6 @@ export const dict = {
"prompt.attachment.remove": "Odstrani prilogo",
"prompt.action.send": "Pošlji",
"prompt.action.stop": "Ustavi",
"prompt.toast.pasteUnsupported.title": "Nepodprta priloga",
"prompt.toast.pasteUnsupported.description": "Sem lahko priložite samo slike, datoteke PDF ali besedilne datoteke.",
"prompt.toast.attachmentDuplicate.title": "Ta datoteka je že naložena",
"prompt.toast.modelAgentRequired.title": "Izberite agenta in model",
"prompt.toast.modelAgentRequired.description": "Preden pošljete poziv, izberite agenta in model.",
-5
View File
@@ -192,7 +192,6 @@ export const dict = {
"dialog.provider.opencode.note": "Modele të kuruara duke përfshirë Claude, GPT, Gemini dhe më shumë",
"dialog.provider.opencode.tagline": "Modele të besueshme të optimizuara",
"dialog.provider.opencodeGo.tagline": "Abonim me kosto të ulët për të gjithë",
"dialog.provider.anthropic.note": "Qasje e drejtpërdrejtë në modelet Claude, duke përfshirë Pro dhe Max",
"dialog.provider.copilot.note": "Modele të AI për ndihmë kodimi përmes GitHub Copilot",
"dialog.provider.openai.note": "Modelet GPT për detyra të shpejta dhe të afta të përgjithshme të AI",
"dialog.provider.google.note": "Modele Gemini për përgjigje të shpejta dhe të strukturuara",
@@ -209,7 +208,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Shiko mbi 70 ofrues të tjerë",
"dialog.provider.viewAll": "Shfaq më shumë ofrues",
"provider.connect.title": "Lidhni {{provider}}",
"provider.connect.title.anthropicProMax": "Hyni me Claude Pro/Max",
"provider.connect.selectMethod": "Zgjidhni metodën e hyrjes për {{provider}}.",
"provider.connect.method.apiKey": "Tasti API",
"provider.connect.method.browser": "Shfletuesi",
@@ -375,9 +373,6 @@ export const dict = {
"prompt.attachment.remove": "Hiq shtojcën",
"prompt.action.send": "Dërgo",
"prompt.action.stop": "Ndalo",
"prompt.toast.pasteUnsupported.title": "Bashkëngjitje e pambështetur",
"prompt.toast.pasteUnsupported.description":
"Këtu mund të bashkëngjiten vetëm imazhe, skedarë PDF ose skedarë teksti.",
"prompt.toast.attachmentDuplicate.title": "Ky skedar tashmë është ngarkuar",
"prompt.toast.modelAgentRequired.title": "Zgjidhni një agjent dhe model",
"prompt.toast.modelAgentRequired.description": "Zgjidhni një agjent dhe model përpara se të dërgoni një kërkesë.",
-4
View File
@@ -192,7 +192,6 @@ export const dict = {
"dialog.provider.opencode.note": "одабрани модели укључујући Claude, GPT, Gemini и више",
"dialog.provider.opencode.tagline": "Поуздани оптимизовани модели",
"dialog.provider.opencodeGo.tagline": "Ниска цена претплате за све",
"dialog.provider.anthropic.note": "Директан приступ Claude моделима, укључујући Про и Мак",
"dialog.provider.copilot.note": "АИ модели за помоћ код кодирања преко GitHub Copilot",
"dialog.provider.openai.note": "GPT модела за брзе, способне опште задатке вештачке интелигенције",
"dialog.provider.google.note": "Gemini модела за брзе, структуриране одговоре",
@@ -209,7 +208,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Погледајте више од 70 провајдера",
"dialog.provider.viewAll": "Прикажи више добављача",
"provider.connect.title": "Повежи {{provider}}",
"provider.connect.title.anthropicProMax": "Пријавите се са Claude Про/Мак",
"provider.connect.selectMethod": "Изаберите метод пријаве за {{provider}}.",
"provider.connect.method.apiKey": "API кључ",
"provider.connect.method.browser": "Прегледач",
@@ -375,8 +373,6 @@ export const dict = {
"prompt.attachment.remove": "Уклоните прилог",
"prompt.action.send": "Пошаљи",
"prompt.action.stop": "Стоп",
"prompt.toast.pasteUnsupported.title": "Неподржани прилог",
"prompt.toast.pasteUnsupported.description": "Овде се могу приложити само слике, PDFс или текстуалне датотеке.",
"prompt.toast.attachmentDuplicate.title": "Ова датотека је већ отпремљена",
"prompt.toast.modelAgentRequired.title": "Изаберите агента и модел",
"prompt.toast.modelAgentRequired.description": "Одаберите агента и модел пре него што пошаљете упит.",
-4
View File
@@ -193,7 +193,6 @@ export const dict = {
"dialog.provider.opencode.note": "Kurerade modeller inklusive Claude, GPT, Gemini och mer",
"dialog.provider.opencode.tagline": "Pålitliga optimerade modeller",
"dialog.provider.opencodeGo.tagline": "Lågprisprenumeration för alla",
"dialog.provider.anthropic.note": "Direkt tillgång till Claude-modeller, inklusive Pro och Max",
"dialog.provider.copilot.note": "AI-modeller för kodningshjälp via GitHub Copilot",
"dialog.provider.openai.note": "GPT-modeller för snabba, kapabla allmänna AI-uppgifter",
"dialog.provider.google.note": "Gemini-modeller för snabba, strukturerade svar",
@@ -210,7 +209,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Se fler än 70 leverantörer",
"dialog.provider.viewAll": "Visa fler leverantörer",
"provider.connect.title": "Anslut {{provider}}",
"provider.connect.title.anthropicProMax": "Logga in med Claude Pro/Max",
"provider.connect.selectMethod": "Välj inloggningsmetod för {{provider}}.",
"provider.connect.method.apiKey": "API-nyckel",
"provider.connect.method.browser": "Webbläsare",
@@ -376,8 +374,6 @@ export const dict = {
"prompt.attachment.remove": "Ta bort bilagan",
"prompt.action.send": "Skicka",
"prompt.action.stop": "Stoppa",
"prompt.toast.pasteUnsupported.title": "Bilaga som inte stöds",
"prompt.toast.pasteUnsupported.description": "Endast bilder, PDF-filer eller textfiler kan bifogas här.",
"prompt.toast.attachmentDuplicate.title": "Den här filen har redan laddats upp",
"prompt.toast.modelAgentRequired.title": "Välj en agent och modell",
"prompt.toast.modelAgentRequired.description": "Välj en agent och modell innan du skickar en prompt.",
-5
View File
@@ -192,7 +192,6 @@ export const dict = {
"dialog.provider.opencode.note": "Моделҳои интихобшуда, аз ҷумла Claude, GPT, Gemini ва ғайра",
"dialog.provider.opencode.tagline": "Моделҳои боэътимоди оптимизатсияшуда",
"dialog.provider.opencodeGo.tagline": "Обунаи арзон барои ҳама",
"dialog.provider.anthropic.note": "Дастрасии мустақим ба моделҳои Claude, аз ҷумла Pro ва Max",
"dialog.provider.copilot.note": "Моделҳои AI барои кӯмаки рамзгузорӣ тавассути GitHub Copilot",
"dialog.provider.openai.note": "GPT моделҳо барои вазифаҳои зуд ва тавонои умумии AI",
"dialog.provider.google.note": "Gemini моделҳо барои посухҳои зуд ва сохторӣ",
@@ -209,7 +208,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Ба 70+ провайдерҳои дигар нигаред",
"dialog.provider.viewAll": "Провайдерҳои бештарро нишон диҳед",
"provider.connect.title": "Пайвастшавӣ {{provider}}",
"provider.connect.title.anthropicProMax": "Воридшавӣ бо Claude Pro/Max",
"provider.connect.selectMethod": "Усули воридшавиро барои {{provider}} интихоб кунед.",
"provider.connect.method.apiKey": "API калид",
"provider.connect.method.browser": "Браузер",
@@ -376,9 +374,6 @@ export const dict = {
"prompt.attachment.remove": "Замимаро хориҷ кунед",
"prompt.action.send": "Фиристодан",
"prompt.action.stop": "Ист",
"prompt.toast.pasteUnsupported.title": "Замимаи дастгирӣнашаванда",
"prompt.toast.pasteUnsupported.description":
"Дар ин ҷо танҳо тасвирҳо, PDFс ё файлҳои матнӣ замима кардан мумкин аст.",
"prompt.toast.attachmentDuplicate.title": "Ин файл аллакай бор карда шудааст",
"prompt.toast.modelAgentRequired.title": "Агент ва моделро интихоб кунед",
"prompt.toast.modelAgentRequired.description": "Пеш аз фиристодани промпт агент ва моделро интихоб кунед.",
-4
View File
@@ -206,7 +206,6 @@ export const dict = {
"dialog.provider.opencode.note": "โมเดลที่คัดสรร รวมถึง Claude, GPT, Gemini และอื่น ๆ",
"dialog.provider.opencode.tagline": "โมเดลที่เชื่อถือได้และปรับให้เหมาะสม",
"dialog.provider.opencodeGo.tagline": "การสมัครสมาชิกราคาประหยัดสำหรับทุกคน",
"dialog.provider.anthropic.note": "เข้าถึงโมเดล Claude โดยตรง รวมถึง Pro และ Max",
"dialog.provider.copilot.note": "โมเดล AI สำหรับการช่วยเหลือในการเขียนโค้ดผ่าน GitHub Copilot",
"dialog.provider.openai.note": "โมเดล GPT สำหรับงาน AI ทั่วไปที่รวดเร็วและมีความสามารถ",
"dialog.provider.google.note": "โมเดล Gemini สำหรับการตอบสนองที่รวดเร็วและมีโครงสร้าง",
@@ -227,7 +226,6 @@ export const dict = {
"dialog.provider.viewAll": "แสดงผู้ให้บริการเพิ่มเติม",
"provider.connect.title": "เชื่อมต่อ {{provider}}",
"provider.connect.title.anthropicProMax": "เข้าสู่ระบบด้วย Claude Pro/Max",
"provider.connect.selectMethod": "เลือกวิธีการเข้าสู่ระบบสำหรับ {{provider}}",
"provider.connect.method.apiKey": "คีย์ API",
"provider.connect.method.browser": "เบราว์เซอร์",
@@ -400,9 +398,7 @@ export const dict = {
"prompt.action.send": "ส่ง",
"prompt.action.stop": "หยุด",
"prompt.toast.pasteUnsupported.title": "ไฟล์แนบที่ไม่รองรับ",
"prompt.toast.attachmentDuplicate.title": "ไฟล์นี้ถูกอัปโหลดแล้ว",
"prompt.toast.pasteUnsupported.description": "แนบได้เฉพาะรูปภาพ PDF หรือไฟล์ข้อความเท่านั้น",
"prompt.toast.modelAgentRequired.title": "เลือกเอเจนต์และโมเดล",
"prompt.toast.modelAgentRequired.description": "เลือกเอเจนต์และโมเดลก่อนส่งพรอมต์",
"prompt.toast.worktreeCreateFailed.title": "ไม่สามารถสร้าง worktree",
-4
View File
@@ -192,7 +192,6 @@ export const dict = {
"dialog.provider.opencode.note": "Claude, GPT, Gemini we ş.m.",
"dialog.provider.opencode.tagline": "Ygtybarly optimal modeller",
"dialog.provider.opencodeGo.tagline": "Hemmeler üçin arzan bahaly abuna",
"dialog.provider.anthropic.note": "Pro we Max ýaly Claude modellerine göni giriş",
"dialog.provider.copilot.note": "GitHub Copilot arkaly kodlaşdyrmak üçin AI modelleri",
"dialog.provider.openai.note": "Çalt, başarnykly umumy AI meseleleri üçin GPT modelleri",
"dialog.provider.google.note": "Çalt, gurluşly jogaplar üçin Gemini modelleri",
@@ -209,7 +208,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Moreene-de 70+ üpjün edijä serediň",
"dialog.provider.viewAll": "Has köp üpjün edijini görkeziň",
"provider.connect.title": "{{provider}} birikdiriň",
"provider.connect.title.anthropicProMax": "Claude Pro / Maks bilen giriň",
"provider.connect.selectMethod": "{{provider}} üçin giriş usulyny saýlaň.",
"provider.connect.method.apiKey": "API açary",
"provider.connect.method.browser": "Brauzer",
@@ -375,8 +373,6 @@ export const dict = {
"prompt.attachment.remove": "Goşundyny aýyryň",
"prompt.action.send": "Iber",
"prompt.action.stop": "Dur",
"prompt.toast.pasteUnsupported.title": "Goldaw berilmeýän goşundy",
"prompt.toast.pasteUnsupported.description": "Bu ýerde diňe suratlar, PDF ýa-da tekst faýllary birikdirilip bilner.",
"prompt.toast.attachmentDuplicate.title": "Bu faýl eýýäm ýüklendi",
"prompt.toast.modelAgentRequired.title": "Agent we model saýlaň",
"prompt.toast.modelAgentRequired.description": "Sorag ibermezden ozal agent we model saýlaň.",
-4
View File
@@ -212,7 +212,6 @@ export const dict = {
"dialog.provider.opencode.note": "Claude, GPT, Gemini ve daha fazlasını içeren seçilmiş modeller",
"dialog.provider.opencode.tagline": "Güvenilir, optimize edilmiş modeller",
"dialog.provider.opencodeGo.tagline": "Herkes için düşük maliyetli abonelik",
"dialog.provider.anthropic.note": "Pro ve Max dahil Claude modellerine doğrudan erişim",
"dialog.provider.copilot.note": "GitHub Copilot üzerinden kodlama yardımı için yapay zekâ modelleri",
"dialog.provider.openai.note": "Hızlı ve yetenekli genel yapay zekâ görevleri için GPT modelleri",
"dialog.provider.google.note": "Hızlı ve yapılandırılmış yanıtlar için Gemini modelleri",
@@ -233,7 +232,6 @@ export const dict = {
"dialog.provider.viewAll": "Daha fazla sağlayıcı göster",
"provider.connect.title": "{{provider}} bağla",
"provider.connect.title.anthropicProMax": "Claude Pro/Max ile giriş yap",
"provider.connect.selectMethod": "{{provider}} için giriş yöntemini seçin.",
"provider.connect.method.apiKey": "API anahtarı",
"provider.connect.method.browser": "Tarayıcı",
@@ -407,9 +405,7 @@ export const dict = {
"prompt.action.send": "Gönder",
"prompt.action.stop": "Durdur",
"prompt.toast.pasteUnsupported.title": "Desteklenmeyen ek",
"prompt.toast.attachmentDuplicate.title": "Bu dosya zaten yüklendi",
"prompt.toast.pasteUnsupported.description": "Buraya yalnızca resimler, PDF'ler veya metin dosyaları eklenebilir.",
"prompt.toast.modelAgentRequired.title": "Bir ajan ve model seçin",
"prompt.toast.modelAgentRequired.description": "İstem göndermeden önce bir ajan ve model seçin.",
"prompt.toast.worktreeCreateFailed.title": "Çalışma ağacı oluşturulamadı",
-4
View File
@@ -208,7 +208,6 @@ export const dict = {
"dialog.provider.opencode.note": "Відібрані моделі, включаючи Claude, GPT, Gemini та інші",
"dialog.provider.opencode.tagline": "Надійні оптимізовані моделі",
"dialog.provider.opencodeGo.tagline": "Недорога підписка для всіх",
"dialog.provider.anthropic.note": "Прямий доступ до моделей Claude, включаючи Pro та Max",
"dialog.provider.copilot.note": "Моделі ШІ для допомоги в кодуванні через GitHub Copilot",
"dialog.provider.openai.note": "Моделі GPT для швидких і універсальних завдань ШІ",
"dialog.provider.google.note": "Моделі Gemini для швидких структурованих відповідей",
@@ -229,7 +228,6 @@ export const dict = {
"dialog.provider.viewAll": "Показати більше провайдерів",
"provider.connect.title": "Підключити {{provider}}",
"provider.connect.title.anthropicProMax": "Увійти з Claude Pro/Max",
"provider.connect.selectMethod": "Виберіть спосіб входу для {{provider}}.",
"provider.connect.method.apiKey": "Ключ API",
"provider.connect.method.browser": "Браузер",
@@ -404,9 +402,7 @@ export const dict = {
"prompt.action.send": "Надіслати",
"prompt.action.stop": "Зупинити",
"prompt.toast.pasteUnsupported.title": "Непідтримуване вкладення",
"prompt.toast.attachmentDuplicate.title": "Цей файл уже завантажено",
"prompt.toast.pasteUnsupported.description": "Сюди можна прикріплювати лише зображення, PDF або текстові файли.",
"prompt.toast.modelAgentRequired.title": "Виберіть агента та модель",
"prompt.toast.modelAgentRequired.description": "Виберіть агента та модель перед надсиланням запиту.",
"prompt.toast.worktreeCreateFailed.title": "Не вдалося створити робоче дерево",
-4
View File
@@ -200,7 +200,6 @@ export const dict = {
"dialog.provider.opencode.note": "کیوریٹ شدہ ماڈلز بشمول Claude، GPT، Gemini اور مزید",
"dialog.provider.opencode.tagline": "قابل اعتماد آپٹمائزڈ ماڈلز",
"dialog.provider.opencodeGo.tagline": "سب کے لیے کم لاگت کی رکنیت",
"dialog.provider.anthropic.note": "پرو اور میکس سمیت Claude ماڈلز تک براہ راست رسائی",
"dialog.provider.copilot.note": "GitHub Copilot کے ذریعے کوڈنگ امداد کے لیے AI ماڈلز",
"dialog.provider.openai.note": "تیز رفتار اور مؤثر عمومی AI کاموں کے لیے GPT ماڈلز",
"dialog.provider.google.note": "تیز، منظم جوابات کے لیے Gemini ماڈل",
@@ -217,7 +216,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "مزید 70 فراہم کنندگان دیکھیں",
"dialog.provider.viewAll": "مزید فراہم کنندگان دکھائیں۔",
"provider.connect.title": "{{provider}} سے منسلک ہوں",
"provider.connect.title.anthropicProMax": "Claude Pro/Max کے ساتھ لاگ ان کریں۔",
"provider.connect.selectMethod": "{{provider}} کے لیے لاگ ان کا طریقہ منتخب کریں۔",
"provider.connect.method.apiKey": "API کلید",
"provider.connect.method.browser": "براؤزر",
@@ -384,8 +382,6 @@ export const dict = {
"prompt.attachment.remove": "منسلکہ کو ہٹا دیں۔",
"prompt.action.send": "بھیجیں۔",
"prompt.action.stop": "روکیں",
"prompt.toast.pasteUnsupported.title": "غیر تعاون یافتہ منسلکہ",
"prompt.toast.pasteUnsupported.description": "یہاں صرف تصاویر، PDFs، یا ٹیکسٹ فائلیں منسلک کی جا سکتی ہیں۔",
"prompt.toast.attachmentDuplicate.title": "یہ فائل پہلے ہی اپ لوڈ ہو چکی ہے",
"prompt.toast.modelAgentRequired.title": "ایک ایجنٹ اور ماڈل منتخب کریں۔",
"prompt.toast.modelAgentRequired.description": "پرامپٹ بھیجنے سے پہلے ایک ایجنٹ اور ماڈل کا انتخاب کریں۔",
-4
View File
@@ -193,7 +193,6 @@ export const dict = {
"dialog.provider.opencode.note": "Tanlangan modellar, jumladan Claude, GPT, Gemini va boshqalar",
"dialog.provider.opencode.tagline": "Ishonchli optimallashtirilgan modellar",
"dialog.provider.opencodeGo.tagline": "Hamma uchun arzon obuna",
"dialog.provider.anthropic.note": "Claude modellariga, jumladan Pro va Maksga to'g'ridan-to'g'ri kirish",
"dialog.provider.copilot.note": "GitHub Copilot orqali kodlash yordami uchun AI modellari",
"dialog.provider.openai.note": "Tez, qobiliyatli umumiy AI vazifalari uchun GPT modellari",
"dialog.provider.google.note": "Tez, tuzilgan javoblar uchun Gemini modellari",
@@ -210,7 +209,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Yana 70 dan ortiq provayderlarni koʻring",
"dialog.provider.viewAll": "Ko'proq provayderlarni ko'rsatish",
"provider.connect.title": "{{provider}} ni ulang",
"provider.connect.title.anthropicProMax": "Claude Pro/Maks bilan tizimga kiring",
"provider.connect.selectMethod": "{{provider}} uchun kirish usulini tanlang.",
"provider.connect.method.apiKey": "API kaliti",
"provider.connect.method.browser": "Brauzer",
@@ -377,8 +375,6 @@ export const dict = {
"prompt.attachment.remove": "Qo'shimchani olib tashlang",
"prompt.action.send": "Yuborish",
"prompt.action.stop": "To'xtang",
"prompt.toast.pasteUnsupported.title": "Qoʻllab-quvvatlanmaydigan biriktirma",
"prompt.toast.pasteUnsupported.description": "Bu yerda faqat rasmlar, PDF yoki matnli fayllar biriktirilishi mumkin.",
"prompt.toast.attachmentDuplicate.title": "Bu fayl allaqachon yuklangan",
"prompt.toast.modelAgentRequired.title": "Agent va modelni tanlang",
"prompt.toast.modelAgentRequired.description": "So'rov yuborishdan oldin agent va modelni tanlang.",
-4
View File
@@ -199,7 +199,6 @@ export const dict = {
"dialog.provider.opencode.note": "Các mô hình được tuyển chọn, gồm Claude, GPT, Gemini và nhiều mô hình khác",
"dialog.provider.opencode.tagline": "Các mô hình tối ưu hóa đáng tin cậy",
"dialog.provider.opencodeGo.tagline": "Đăng ký chi phí thấp cho mọi người",
"dialog.provider.anthropic.note": "Truy cập trực tiếp các mô hình Claude, bao gồm Pro và Max",
"dialog.provider.copilot.note": "Các mô hình AI hỗ trợ lập trình qua GitHub Copilot",
"dialog.provider.openai.note": "Các mô hình GPT nhanh và mạnh mẽ cho tác vụ AI đa dụng",
"dialog.provider.google.note": "Các mô hình Gemini cho phản hồi nhanh, có cấu trúc",
@@ -216,7 +215,6 @@ export const dict = {
"dialog.model.unpaid.viewMoreProviders": "Xem hơn 70 nhà cung cấp khác",
"dialog.provider.viewAll": "Hiển thị thêm nhà cung cấp",
"provider.connect.title": "Kết nối {{provider}}",
"provider.connect.title.anthropicProMax": "Đăng nhập bằng Claude Pro/Max",
"provider.connect.selectMethod": "Chọn phương thức đăng nhập cho {{provider}}.",
"provider.connect.method.apiKey": "Khóa API",
"provider.connect.method.browser": "Trình duyệt",
@@ -382,8 +380,6 @@ export const dict = {
"prompt.attachment.remove": "Xóa tệp đính kèm",
"prompt.action.send": "Gửi",
"prompt.action.stop": "Dừng",
"prompt.toast.pasteUnsupported.title": "Tệp đính kèm không được hỗ trợ",
"prompt.toast.pasteUnsupported.description": "Chỉ có thể đính kèm hình ảnh, tệp PDF hoặc tệp văn bản ở đây.",
"prompt.toast.attachmentDuplicate.title": "Tệp này đã được tải lên",
"prompt.toast.modelAgentRequired.title": "Chọn tác nhân và mô hình",
"prompt.toast.modelAgentRequired.description": "Chọn một tác nhân và mô hình trước khi gửi lời nhắc.",
-4
View File
@@ -233,7 +233,6 @@ export const dict = {
"dialog.provider.opencode.note": "精选模型,包括 Claude、GPT、Gemini 等",
"dialog.provider.opencode.tagline": "可靠的优化模型",
"dialog.provider.opencodeGo.tagline": "适合所有人的低成本订阅",
"dialog.provider.anthropic.note": "直接使用 Claude 模型,包括 Pro 和 Max",
"dialog.provider.copilot.note": "通过 GitHub Copilot 使用辅助编程 AI 模型",
"dialog.provider.openai.note": "适合快速处理各类 AI 任务的 GPT 模型",
"dialog.provider.google.note": "可快速生成结构化回复的 Gemini 模型",
@@ -253,7 +252,6 @@ export const dict = {
"dialog.provider.viewAll": "查看更多提供商",
"provider.connect.title": "连接 {{provider}}",
"provider.connect.title.anthropicProMax": "使用 Claude Pro/Max 登录",
"provider.connect.selectMethod": "选择 {{provider}} 的登录方式。",
"provider.connect.method.apiKey": "API 密钥",
"provider.connect.method.browser": "浏览器",
@@ -419,9 +417,7 @@ export const dict = {
"prompt.attachment.remove": "移除附件",
"prompt.action.send": "发送",
"prompt.action.stop": "停止",
"prompt.toast.pasteUnsupported.title": "不支持的附件",
"prompt.toast.attachmentDuplicate.title": "此文件已上传",
"prompt.toast.pasteUnsupported.description": "此处仅能附加图片、PDF 或文本文件。",
"prompt.toast.modelAgentRequired.title": "请选择智能体和模型",
"prompt.toast.modelAgentRequired.description": "发送提示前请先选择智能体和模型。",
"prompt.toast.worktreeCreateFailed.title": "创建工作区失败",

Some files were not shown because too many files have changed in this diff Show More