diff --git a/.github/TEAM_MEMBERS b/.github/TEAM_MEMBERS index 5268ff59ddc8..866d466a8b4c 100644 --- a/.github/TEAM_MEMBERS +++ b/.github/TEAM_MEMBERS @@ -20,3 +20,4 @@ Slickstef11 usrnk1 vimtor StarpTech +vaprdev diff --git a/bun.lock b/bun.lock index a8774d3aa2bd..338f7f02342e 100644 --- a/bun.lock +++ b/bun.lock @@ -29,7 +29,7 @@ }, "packages/app": { "name": "@opencode-ai/app", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@corvu/drawer": "catalog:", "@dnd-kit/abstract": "0.5.0", @@ -96,7 +96,7 @@ }, "packages/cli": { "name": "@opencode-ai/cli", - "version": "1.18.30", + "version": "1.18.31", "bin": { "lildax": "./bin/lildax.cjs", }, @@ -144,7 +144,7 @@ }, "packages/codemode": { "name": "@opencode-ai/codemode", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "acorn": "8.15.0", "effect": "catalog:", @@ -158,7 +158,7 @@ }, "packages/console/app": { "name": "@opencode-ai/console-app", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@cloudflare/vite-plugin": "1.15.2", "@ibm/plex": "6.4.1", @@ -195,7 +195,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -222,7 +222,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@ai-sdk/anthropic": "3.0.82", "@ai-sdk/openai": "3.0.48", @@ -245,7 +245,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -269,7 +269,7 @@ }, "packages/console/support": { "name": "@opencode-ai/console-support", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@cloudflare/vite-plugin": "1.15.2", "@opencode-ai/console-core": "workspace:*", @@ -289,7 +289,7 @@ }, "packages/core": { "name": "@opencode-ai/core", - "version": "1.18.30", + "version": "1.18.31", "bin": { "opencode": "./bin/opencode", }, @@ -383,7 +383,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@zip.js/zip.js": "2.7.62", "drizzle-orm": "catalog:", @@ -437,7 +437,7 @@ }, "packages/effect-drizzle-sqlite": { "name": "@opencode-ai/effect-drizzle-sqlite", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "drizzle-orm": "catalog:", "effect": "catalog:", @@ -451,7 +451,7 @@ }, "packages/effect-sqlite-node": { "name": "@opencode-ai/effect-sqlite-node", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "effect": "catalog:", }, @@ -463,7 +463,7 @@ }, "packages/enterprise": { "name": "@opencode-ai/enterprise", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@hono/standard-validator": "catalog:", "@opencode-ai/core": "workspace:*", @@ -495,7 +495,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "catalog:", @@ -511,7 +511,7 @@ }, "packages/http-recorder": { "name": "@opencode-ai/http-recorder", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@effect/platform-node": "4.0.0-beta.83", "@effect/platform-node-shared": "4.0.0-beta.83", @@ -542,7 +542,7 @@ }, "packages/llm": { "name": "@opencode-ai/llm", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@opencode-ai/schema": "workspace:*", "@smithy/eventstream-codec": "4.2.14", @@ -561,7 +561,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.18.30", + "version": "1.18.31", "bin": { "opencode": "./bin/opencode", }, @@ -692,7 +692,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@ai-sdk/provider": "3.0.8", "@opencode-ai/sdk": "workspace:*", @@ -768,7 +768,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "cross-spawn": "catalog:", }, @@ -783,7 +783,7 @@ }, "packages/server": { "name": "@opencode-ai/server", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@opencode-ai/core": "workspace:*", "@opencode-ai/protocol": "workspace:*", @@ -798,7 +798,7 @@ }, "packages/session-ui": { "name": "@opencode-ai/session-ui", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/client": "file:../app/vendor/opencode-ai-client-1.17.13-v2.tgz", @@ -838,7 +838,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -851,7 +851,7 @@ }, "packages/stats/app": { "name": "@opencode-ai/stats-app", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@ibm/plex": "6.4.1", "@kobalte/core": "catalog:", @@ -878,7 +878,7 @@ }, "packages/stats/core": { "name": "@opencode-ai/stats-core", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@aws-sdk/client-athena": "3.933.0", "@planetscale/database": "1.19.0", @@ -897,7 +897,7 @@ }, "packages/stats/server": { "name": "@opencode-ai/stats-server", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@aws-sdk/client-firehose": "3.933.0", "@effect/platform-node": "catalog:", @@ -939,7 +939,7 @@ }, "packages/tui": { "name": "@opencode-ai/tui", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@opencode-ai/core": "workspace:*", "@opencode-ai/plugin": "workspace:*", @@ -966,7 +966,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@kobalte/core": "catalog:", "@pierre/diffs": "catalog:", @@ -1017,7 +1017,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.18.30", + "version": "1.18.31", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/app/e2e/regression/legacy-new-session.spec.ts b/packages/app/e2e/regression/legacy-new-session.spec.ts deleted file mode 100644 index 45cd64adcc69..000000000000 --- a/packages/app/e2e/regression/legacy-new-session.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { expect, test } from "@playwright/test" -import { base64Encode } from "@opencode-ai/core/util/encode" -import { mockOpenCodeServer } from "../utils/mock-server" - -const draftID = "draft_legacy_new_session" -const directory = "C:/OpenCode/LegacyNewSession" -const server = `http://${process.env.PLAYWRIGHT_SERVER_HOST ?? "127.0.0.1"}:${process.env.PLAYWRIGHT_SERVER_PORT ?? "4096"}` - -test("redirects a draft to the legacy new-session route", async ({ page }) => { - await mockOpenCodeServer(page, { - directory, - project: { - id: "proj_legacy_new_session", - worktree: directory, - vcs: "git", - name: "legacy-new-session", - time: { created: 1700000000000, updated: 1700000000000 }, - sandboxes: [], - }, - provider: { all: [], connected: [], default: {} }, - sessions: [], - pageMessages: () => ({ items: [] }), - }) - await page.addInitScript( - ({ directory, draftID, server }) => { - localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: false } })) - localStorage.setItem("app-version.v1", JSON.stringify({ version: "1.17.20" })) - localStorage.setItem( - "opencode.window.browser.dat:tabs", - JSON.stringify([{ type: "draft", draftID, server, directory }]), - ) - }, - { directory, draftID, server }, - ) - - await page.goto(`/new-session?draftId=${draftID}`) - - await expect(page).toHaveURL(`/${base64Encode(directory)}/session`) - await expect(page.locator("header[data-tauri-drag-region]")).toBeVisible() - await expect(page.locator('[data-component="prompt-input"]')).toBeVisible() -}) diff --git a/packages/app/e2e/regression/session-timeline-projection.spec.ts b/packages/app/e2e/regression/session-timeline-projection.spec.ts index b1aabcc32ca9..54c84a2bea5d 100644 --- a/packages/app/e2e/regression/session-timeline-projection.spec.ts +++ b/packages/app/e2e/regression/session-timeline-projection.spec.ts @@ -128,7 +128,7 @@ test.describe("session timeline projection", () => { await expect(page.locator('[data-timeline-row="TurnGap"]')).toBeVisible() }) - test("renders comment strips and historical diff summary overflow", async ({ page }) => { + test("renders inline comments and historical diff summary overflow", async ({ page }) => { const user = userMessage( [ userText("The user made the following comment regarding lines 4 through 8 of src/a.ts: Keep this stable", { @@ -152,14 +152,10 @@ test.describe("session timeline projection", () => { parentID: "msg_2000_diff_next_user", created: 1700000011000, }) - await setupTimeline(page, { - messages: [user, assistantMessage(), nextUser, nextAssistant], - settings: { newLayoutDesigns: false }, - }) + await setupTimeline(page, { messages: [user, assistantMessage(), nextUser, nextAssistant] }) const scroller = page.locator(".scroll-view__viewport", { has: page.locator("[data-timeline-row]") }) await scroller.evaluate((element) => (element.scrollTop = 0)) - await expect(page.locator('[data-timeline-row="CommentStrip"]')).toBeVisible() await expect(page.getByText("Keep this stable", { exact: true })).toBeVisible() await expect(page.locator('[data-timeline-row="DiffSummary"]')).toBeVisible() await expect(page.getByText(/show all/i)).toBeVisible() diff --git a/packages/app/package.json b/packages/app/package.json index 17b356ed6087..97c98e9fc3f2 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "1.18.30", + "version": "1.18.31", "description": "", "type": "module", "exports": { diff --git a/packages/cli/package.json b/packages/cli/package.json index f6dd6bf831f3..7e94b2310840 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/cli", - "version": "1.18.30", + "version": "1.18.31", "type": "module", "license": "MIT", "bin": { diff --git a/packages/codemode/package.json b/packages/codemode/package.json index c516b3a98589..8a14b5769d16 100644 --- a/packages/codemode/package.json +++ b/packages/codemode/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/codemode", - "version": "1.18.30", + "version": "1.18.31", "description": "Effect-native confined code execution over schema-described tools", "private": true, "type": "module", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 3651594fd764..b89e19a72ba2 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-app", - "version": "1.18.30", + "version": "1.18.31", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/console/app/src/component/go-models.ts b/packages/console/app/src/component/go-models.ts index 6df79f4a3921..5c86d66b5a60 100644 --- a/packages/console/app/src/component/go-models.ts +++ b/packages/console/app/src/component/go-models.ts @@ -50,4 +50,13 @@ export const goModels = [ allowance: 60, regions: true, }, + { + id: "union-alpha", + name: "Union Alpha Free", + requests: Infinity, + allowance: Infinity, + featured: true, + fresh: true, + unlimited: true, + }, ].sort((a, b) => a.requests - b.requests) diff --git a/packages/console/app/src/component/limits-graph.css b/packages/console/app/src/component/limits-graph.css index ddcf2dfece52..88b13199d4fa 100644 --- a/packages/console/app/src/component/limits-graph.css +++ b/packages/console/app/src/component/limits-graph.css @@ -144,6 +144,11 @@ } } + [data-slot="model-row"][data-unlimited] :is([data-slot="requests"], [data-slot="allowance"]) bdi { + font-size: 1.5rem; + line-height: 1; + } + [data-slot="currency"] { color: var(--color-text-weak); } diff --git a/packages/console/app/src/component/limits-graph.tsx b/packages/console/app/src/component/limits-graph.tsx index 410fd48e4392..59c736fdf801 100644 --- a/packages/console/app/src/component/limits-graph.tsx +++ b/packages/console/app/src/component/limits-graph.tsx @@ -5,9 +5,11 @@ import { useLanguage } from "~/context/language" import { goModels } from "./go-models" // Compress the request range, with the same domain in both views. -const max = Math.max(...goModels.map((model) => model.requests)) +const max = Math.max(...goModels.filter((model) => Number.isFinite(model.requests)).map((model) => model.requests)) const position = (requests: number) => - 4 + Math.pow(Math.log10(Math.max(requests / 100, 1)) / Math.log10(max / 100), 2.2) * 96 + Number.isFinite(requests) + ? 4 + Math.pow(Math.log10(Math.max(requests / 100, 1)) / Math.log10(max / 100), 2.2) * 88 + : 100 const ticks = [100, 1000, 10000, 40000] export function LimitsGraph(props: { href: string }) { @@ -74,7 +76,13 @@ export function LimitsGraph(props: { href: string }) {
{(model, index) => ( -
+
{model.name} @@ -83,6 +91,9 @@ export function LimitsGraph(props: { href: string }) { {i18n.t("go.graph.bonus", { count: model.bonus! })} + + {i18n.t("go.graph.limitedTime")} +
-
+
-
= 60 ? "" : undefined}> - - {currency().format(model.baseAllowance!)}{" "} +
= 60 ? "" : undefined} + aria-label={model.unlimited ? i18n.t("go.graph.unlimited") : undefined} + > + - - - {(part) => ( - {part.value} - )} - -
)} diff --git a/packages/console/app/src/i18n/ar.ts b/packages/console/app/src/i18n/ar.ts index fac1d6475833..80cb9a9c63db 100644 --- a/packages/console/app/src/i18n/ar.ts +++ b/packages/console/app/src/i18n/ar.ts @@ -3,7 +3,7 @@ import { dict as en } from "./en" export const dict = { ...en, - "go.promo.deepseek": "يحصل DeepSeek V4.1 Flash على حدود استخدام مضاعفة 4 مرات لفترة محدودة", + "go.promo.unionAlpha": "يتوفر Union Alpha مجانًا لفترة محدودة", "go.graph.bonus": "استخدام مضاعف {{count}} مرات", "nav.github": "GitHub", "nav.docs": "الوثائق", @@ -282,6 +282,7 @@ export const dict = { "go.graph.showLess": "عرض نماذج أقل", "go.graph.limitedRegions": "مناطق محدودة", "go.graph.limitedTime": "لفترة محدودة", + "go.graph.unlimited": "غير محدود", "go.graph.usageLimits": "حدود الاستخدام", "go.graph.aria": "الطلبات كل 5 ساعات: {{free}} مقابل {{go}}", diff --git a/packages/console/app/src/i18n/br.ts b/packages/console/app/src/i18n/br.ts index a2e5867a63dc..c0fa12fcb00d 100644 --- a/packages/console/app/src/i18n/br.ts +++ b/packages/console/app/src/i18n/br.ts @@ -3,7 +3,7 @@ import { dict as en } from "./en" export const dict = { ...en, - "go.promo.deepseek": "DeepSeek V4.1 Flash tem limites de uso 4x maiores por tempo limitado", + "go.promo.unionAlpha": "O Union Alpha está grátis por tempo limitado", "go.graph.bonus": "{{count}}× mais uso", "nav.github": "GitHub", "nav.docs": "Documentação", @@ -288,6 +288,7 @@ export const dict = { "go.graph.showLess": "Mostrar menos modelos", "go.graph.limitedRegions": "regiões limitadas", "go.graph.limitedTime": "tempo limitado", + "go.graph.unlimited": "ilimitado", "go.graph.usageLimits": "Limites de uso", "go.graph.aria": "Requisições por 5h: {{free}} vs {{go}}", diff --git a/packages/console/app/src/i18n/da.ts b/packages/console/app/src/i18n/da.ts index d2787bb611eb..5d310d74c147 100644 --- a/packages/console/app/src/i18n/da.ts +++ b/packages/console/app/src/i18n/da.ts @@ -3,7 +3,7 @@ import { dict as en } from "./en" export const dict = { ...en, - "go.promo.deepseek": "DeepSeek V4.1 Flash får firedoblet brugsgrænse i en begrænset periode", + "go.promo.unionAlpha": "Union Alpha er gratis i en begrænset periode", "go.graph.bonus": "{{count}}× forbrug", "nav.github": "GitHub", "nav.docs": "Dokumentation", @@ -285,6 +285,7 @@ export const dict = { "go.graph.showLess": "Vis færre modeller", "go.graph.limitedRegions": "begrænsede regioner", "go.graph.limitedTime": "begrænset periode", + "go.graph.unlimited": "ubegrænset", "go.graph.usageLimits": "Forbrugsgrænser", "go.graph.aria": "Forespørgsler pr. 5t: {{free}} vs {{go}}", diff --git a/packages/console/app/src/i18n/de.ts b/packages/console/app/src/i18n/de.ts index 8fb78e76e611..2dfbd2830b38 100644 --- a/packages/console/app/src/i18n/de.ts +++ b/packages/console/app/src/i18n/de.ts @@ -3,7 +3,7 @@ import { dict as en } from "./en" export const dict = { ...en, - "go.promo.deepseek": "DeepSeek V4.1 Flash erhält für begrenzte Zeit 4x Nutzungslimits", + "go.promo.unionAlpha": "Union Alpha ist für begrenzte Zeit kostenlos", "go.graph.bonus": "{{count}}× Nutzung", "nav.github": "GitHub", "nav.docs": "Dokumentation", @@ -287,6 +287,7 @@ export const dict = { "go.graph.showLess": "Weniger Modelle anzeigen", "go.graph.limitedRegions": "begrenzte Regionen", "go.graph.limitedTime": "begrenzte Zeit", + "go.graph.unlimited": "unbegrenzt", "go.graph.usageLimits": "Nutzungslimits", "go.graph.aria": "Anfragen pro 5h: {{free}} vs {{go}}", diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index 4469c3353c51..33664e8eed0d 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -1,5 +1,5 @@ export const dict = { - "go.promo.deepseek": "DeepSeek V4.1 Flash gets 4× usage limits for a limited time", + "go.promo.unionAlpha": "Union Alpha is free for a limited time", "go.graph.bonus": "{{count}}× usage", "nav.github": "GitHub", "nav.docs": "Docs", @@ -282,6 +282,7 @@ export const dict = { "go.graph.showLess": "Show fewer models", "go.graph.limitedRegions": "limited regions", "go.graph.limitedTime": "limited time", + "go.graph.unlimited": "unlimited", "go.graph.tick": "{{n}}x", "go.graph.usageLimits": "Usage limits", "go.graph.aria": "Requests per 5h: {{free}} vs {{go}}", diff --git a/packages/console/app/src/i18n/es.ts b/packages/console/app/src/i18n/es.ts index 9750bc584e27..58c3279f7e54 100644 --- a/packages/console/app/src/i18n/es.ts +++ b/packages/console/app/src/i18n/es.ts @@ -3,7 +3,7 @@ import { dict as en } from "./en" export const dict = { ...en, - "go.promo.deepseek": "DeepSeek V4.1 Flash tiene límites de uso 4x mayores por tiempo limitado", + "go.promo.unionAlpha": "Union Alpha es gratis por tiempo limitado", "go.graph.bonus": "{{count}}× de uso", "nav.github": "GitHub", "nav.docs": "Documentación", @@ -289,6 +289,7 @@ export const dict = { "go.graph.showLess": "Mostrar menos modelos", "go.graph.limitedRegions": "regiones limitadas", "go.graph.limitedTime": "tiempo limitado", + "go.graph.unlimited": "ilimitado", "go.graph.usageLimits": "Límites de uso", "go.graph.aria": "Solicitudes por 5h: {{free}} vs {{go}}", diff --git a/packages/console/app/src/i18n/fr.ts b/packages/console/app/src/i18n/fr.ts index 5281b6b3e54f..ba63215ffd40 100644 --- a/packages/console/app/src/i18n/fr.ts +++ b/packages/console/app/src/i18n/fr.ts @@ -3,7 +3,7 @@ import { dict as en } from "./en" export const dict = { ...en, - "go.promo.deepseek": "DeepSeek V4.1 Flash bénéficie de limites d’utilisation 4x supérieures pour une durée limitée", + "go.promo.unionAlpha": "Union Alpha est gratuit pendant une durée limitée", "go.graph.bonus": "{{count}}× d’utilisation", "app.meta.description": "OpenCode - L'agent de code open source.", "nav.github": "GitHub", @@ -290,6 +290,7 @@ export const dict = { "go.graph.showLess": "Afficher moins de modèles", "go.graph.limitedRegions": "régions limitées", "go.graph.limitedTime": "durée limitée", + "go.graph.unlimited": "illimité", "go.graph.usageLimits": "Limites d’utilisation", "go.graph.aria": "Requêtes par 5h : {{free}} vs {{go}}", diff --git a/packages/console/app/src/i18n/it.ts b/packages/console/app/src/i18n/it.ts index cb2f3d7d7a83..d84600279552 100644 --- a/packages/console/app/src/i18n/it.ts +++ b/packages/console/app/src/i18n/it.ts @@ -3,7 +3,7 @@ import { dict as en } from "./en" export const dict = { ...en, - "go.promo.deepseek": "DeepSeek V4.1 Flash offre limiti di utilizzo 4x superiori per un periodo limitato", + "go.promo.unionAlpha": "Union Alpha è gratuito per un periodo limitato", "go.graph.bonus": "Utilizzo {{count}}×", "nav.github": "GitHub", "nav.docs": "Documentazione", @@ -286,6 +286,7 @@ export const dict = { "go.graph.showLess": "Mostra meno modelli", "go.graph.limitedRegions": "regioni limitate", "go.graph.limitedTime": "periodo limitato", + "go.graph.unlimited": "illimitato", "go.graph.usageLimits": "Limiti di utilizzo", "go.graph.aria": "Richieste ogni 5h: {{free}} vs {{go}}", diff --git a/packages/console/app/src/i18n/ja.ts b/packages/console/app/src/i18n/ja.ts index 2ae754c47d90..b1b0b49a41e7 100644 --- a/packages/console/app/src/i18n/ja.ts +++ b/packages/console/app/src/i18n/ja.ts @@ -3,7 +3,7 @@ import { dict as en } from "./en" export const dict = { ...en, - "go.promo.deepseek": "DeepSeek V4.1 Flashの利用上限が期間限定で4倍に", + "go.promo.unionAlpha": "Union Alphaは期間限定で無料です", "go.graph.bonus": "利用枠{{count}}倍", "nav.github": "GitHub", "nav.docs": "ドキュメント", @@ -285,6 +285,7 @@ export const dict = { "go.graph.showLess": "折りたたむ", "go.graph.limitedRegions": "一部の地域に限定", "go.graph.limitedTime": "期間限定", + "go.graph.unlimited": "無制限", "go.graph.usageLimits": "利用制限", "go.graph.aria": "5時間あたりのリクエスト数: {{free}} 対 {{go}}", diff --git a/packages/console/app/src/i18n/ko.ts b/packages/console/app/src/i18n/ko.ts index e9b5c92071c4..18f2b2dca5b8 100644 --- a/packages/console/app/src/i18n/ko.ts +++ b/packages/console/app/src/i18n/ko.ts @@ -3,7 +3,7 @@ import { dict as en } from "./en" export const dict = { ...en, - "go.promo.deepseek": "DeepSeek V4.1 Flash 사용 한도가 한시적으로 4배 확대됩니다", + "go.promo.unionAlpha": "Union Alpha는 한정 기간 동안 무료로 이용할 수 있습니다", "go.graph.bonus": "사용량 {{count}}배", "nav.github": "GitHub", "nav.docs": "문서", @@ -281,6 +281,7 @@ export const dict = { "go.graph.showLess": "접기", "go.graph.limitedRegions": "일부 지역에서만 제공", "go.graph.limitedTime": "한정된 기간", + "go.graph.unlimited": "무제한", "go.graph.usageLimits": "사용 한도", "go.graph.aria": "5시간당 요청 수: {{free}} 대 {{go}}", diff --git a/packages/console/app/src/i18n/no.ts b/packages/console/app/src/i18n/no.ts index fc2636a30057..64f75c648670 100644 --- a/packages/console/app/src/i18n/no.ts +++ b/packages/console/app/src/i18n/no.ts @@ -3,7 +3,7 @@ import { dict as en } from "./en" export const dict = { ...en, - "go.promo.deepseek": "DeepSeek V4.1 Flash får 4x bruksgrense i en begrenset periode", + "go.promo.unionAlpha": "Union Alpha er gratis i en begrenset periode", "go.graph.bonus": "{{count}}× bruk", "nav.github": "GitHub", "nav.docs": "Dokumentasjon", @@ -285,6 +285,7 @@ export const dict = { "go.graph.showLess": "Vis færre modeller", "go.graph.limitedRegions": "begrensede regioner", "go.graph.limitedTime": "begrenset periode", + "go.graph.unlimited": "ubegrenset", "go.graph.usageLimits": "Bruksgrenser", "go.graph.aria": "Forespørsler per 5t: {{free}} vs {{go}}", diff --git a/packages/console/app/src/i18n/pl.ts b/packages/console/app/src/i18n/pl.ts index 4a4e1ba724a6..996d421bc8a0 100644 --- a/packages/console/app/src/i18n/pl.ts +++ b/packages/console/app/src/i18n/pl.ts @@ -2,7 +2,7 @@ import { dict as en } from "./en" export const dict = { ...en, - "go.promo.deepseek": "DeepSeek V4.1 Flash oferuje 4x wyższe limity użycia przez ograniczony czas", + "go.promo.unionAlpha": "Union Alpha jest dostępny bezpłatnie przez ograniczony czas", "go.graph.bonus": "{{count}}× większy limit", "nav.github": "GitHub", "nav.docs": "Dokumentacja", @@ -287,6 +287,7 @@ export const dict = { "go.graph.showLess": "Pokaż mniej modeli", "go.graph.limitedRegions": "ograniczone regiony", "go.graph.limitedTime": "ograniczony czas", + "go.graph.unlimited": "bez limitu", "go.graph.usageLimits": "Limity użycia", "go.graph.aria": "Żądania na 5h: {{free}} vs {{go}}", diff --git a/packages/console/app/src/i18n/ru.ts b/packages/console/app/src/i18n/ru.ts index 37f6e43b06d6..fc4e4dc2b040 100644 --- a/packages/console/app/src/i18n/ru.ts +++ b/packages/console/app/src/i18n/ru.ts @@ -3,7 +3,7 @@ import { dict as en } from "./en" export const dict = { ...en, - "go.promo.deepseek": "DeepSeek V4.1 Flash получает 4x лимиты использования на ограниченное время", + "go.promo.unionAlpha": "Union Alpha можно использовать бесплатно в течение ограниченного времени", "go.graph.bonus": "Лимит ×{{count}}", "nav.github": "GitHub", "nav.docs": "Документация", @@ -290,6 +290,7 @@ export const dict = { "go.graph.showLess": "Показать меньше моделей", "go.graph.limitedRegions": "доступно в отдельных регионах", "go.graph.limitedTime": "ограниченное время", + "go.graph.unlimited": "без ограничений", "go.graph.usageLimits": "Лимиты использования", "go.graph.aria": "Запросов за 5ч: {{free}} против {{go}}", diff --git a/packages/console/app/src/i18n/th.ts b/packages/console/app/src/i18n/th.ts index 97a80f039418..860f3c595d74 100644 --- a/packages/console/app/src/i18n/th.ts +++ b/packages/console/app/src/i18n/th.ts @@ -3,7 +3,7 @@ import { dict as en } from "./en" export const dict = { ...en, - "go.promo.deepseek": "DeepSeek V4.1 Flash เพิ่มโควตาการใช้งานเป็น 4 เท่าในช่วงเวลาจำกัด", + "go.promo.unionAlpha": "ใช้ Union Alpha ฟรีในช่วงเวลาจำกัด", "go.graph.bonus": "ใช้งาน {{count}} เท่า", "nav.github": "GitHub", "nav.docs": "เอกสาร", @@ -284,6 +284,7 @@ export const dict = { "go.graph.showLess": "แสดงโมเดลน้อยลง", "go.graph.limitedRegions": "เฉพาะบางภูมิภาค", "go.graph.limitedTime": "ช่วงเวลาจำกัด", + "go.graph.unlimited": "ไม่จำกัด", "go.graph.usageLimits": "ขีดจำกัดการใช้งาน", "go.graph.aria": "คำขอต่อ 5 ชม.: {{free}} vs {{go}}", diff --git a/packages/console/app/src/i18n/tr.ts b/packages/console/app/src/i18n/tr.ts index 4289706cc66e..390ce8eccfd6 100644 --- a/packages/console/app/src/i18n/tr.ts +++ b/packages/console/app/src/i18n/tr.ts @@ -3,7 +3,7 @@ import { dict as en } from "./en" export const dict = { ...en, - "go.promo.deepseek": "DeepSeek V4.1 Flash sınırlı bir süre için 4x kullanım limiti sunuyor", + "go.promo.unionAlpha": "Union Alpha sınırlı bir süre boyunca ücretsiz", "go.graph.bonus": "{{count}}× kullanım", "nav.github": "GitHub", "nav.docs": "Dokümantasyon", @@ -287,6 +287,7 @@ export const dict = { "go.graph.showLess": "Daha az model göster", "go.graph.limitedRegions": "sınırlı bölgeler", "go.graph.limitedTime": "sınırlı süre", + "go.graph.unlimited": "sınırsız", "go.graph.usageLimits": "Kullanım limitleri", "go.graph.aria": "5 saatlik istekler: {{free}} vs {{go}}", diff --git a/packages/console/app/src/i18n/uk.ts b/packages/console/app/src/i18n/uk.ts index 4efac1d76762..f9338c587c78 100644 --- a/packages/console/app/src/i18n/uk.ts +++ b/packages/console/app/src/i18n/uk.ts @@ -2,7 +2,7 @@ import { dict as en } from "./en" export const dict = { ...en, - "go.promo.deepseek": "DeepSeek V4.1 Flash отримує 4x ліміти використання протягом обмеженого часу", + "go.promo.unionAlpha": "Union Alpha можна використовувати безкоштовно протягом обмеженого часу", "go.graph.bonus": "Ліміт ×{{count}}", "nav.github": "GitHub", "nav.docs": "Документація", @@ -285,6 +285,7 @@ export const dict = { "go.graph.showLess": "Показати менше моделей", "go.graph.limitedRegions": "обмежені регіони", "go.graph.limitedTime": "обмежений час", + "go.graph.unlimited": "без обмежень", "go.graph.usageLimits": "Ліміти використання", "go.graph.aria": "Запитів за 5 год: {{free}} vs {{go}}", diff --git a/packages/console/app/src/i18n/zh.ts b/packages/console/app/src/i18n/zh.ts index 8c1aff6f6083..76bc605d6c6b 100644 --- a/packages/console/app/src/i18n/zh.ts +++ b/packages/console/app/src/i18n/zh.ts @@ -3,7 +3,7 @@ import { dict as en } from "./en" export const dict = { ...en, - "go.promo.deepseek": "DeepSeek V4.1 Flash 限时享受 4 倍使用额度", + "go.promo.unionAlpha": "Union Alpha 限时免费", "go.graph.bonus": "{{count}} 倍用量", "nav.github": "GitHub", "nav.docs": "文档", @@ -274,6 +274,7 @@ export const dict = { "go.graph.showLess": "收起模型", "go.graph.limitedRegions": "仅限部分地区", "go.graph.limitedTime": "限时", + "go.graph.unlimited": "无限制", "go.graph.usageLimits": "使用限制", "go.graph.aria": "每 5 小时请求数: {{free}} vs {{go}}", diff --git a/packages/console/app/src/i18n/zht.ts b/packages/console/app/src/i18n/zht.ts index a4a5f4bd4a73..50bfb1cac458 100644 --- a/packages/console/app/src/i18n/zht.ts +++ b/packages/console/app/src/i18n/zht.ts @@ -3,7 +3,7 @@ import { dict as en } from "./en" export const dict = { ...en, - "go.promo.deepseek": "DeepSeek V4.1 Flash 限時享有 4 倍使用額度", + "go.promo.unionAlpha": "Union Alpha 限時免費", "go.graph.bonus": "{{count}} 倍用量", "nav.github": "GitHub", "nav.docs": "文件", @@ -273,6 +273,7 @@ export const dict = { "go.graph.showLess": "收起模型", "go.graph.limitedRegions": "僅限部分地區", "go.graph.limitedTime": "限時", + "go.graph.unlimited": "無限制", "go.graph.usageLimits": "使用限制", "go.graph.aria": "每 5 小時請求數:{{free}} vs {{go}}", diff --git a/packages/console/app/src/lib/inference-proxy.ts b/packages/console/app/src/lib/inference-proxy.ts index b572c361b655..1eade3ff8fee 100644 --- a/packages/console/app/src/lib/inference-proxy.ts +++ b/packages/console/app/src/lib/inference-proxy.ts @@ -1,5 +1,5 @@ import { Resource } from "@opencode-ai/console-resource" -import { and, Database, eq, isNull, sql } from "@opencode-ai/console-core/drizzle/index.js" +import { and, Database, eq, isNotNull, isNull, sql } from "@opencode-ai/console-core/drizzle/index.js" import { KeyTable } from "@opencode-ai/console-core/schema/key.sql.js" import { ProviderTable } from "@opencode-ai/console-core/schema/provider.sql.js" import { WorkspaceTable } from "@opencode-ai/console-core/schema/workspace.sql.js" @@ -34,7 +34,6 @@ export async function proxyInference( : undefined) if (!path) return undefined - const go = url.pathname.startsWith("/zen/go/") const key = url.pathname.endsWith("/messages") ? request.headers.get("x-api-key") : path.startsWith("/google/") @@ -42,44 +41,23 @@ export async function proxyInference( : request.headers.get("authorization")?.split(" ")[1] if (!key || key === "public") return undefined - // Routing only; the destination owns authentication and revocation after cutover. - const workspace = await Database.use((tx) => - tx - .select({ - id: WorkspaceTable.id, - migratedAt: WorkspaceTable.migrated_at, - provider: ProviderTable.provider, - }) - .from(KeyTable) - .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID)) - .leftJoin( - ProviderTable, - !go && generation?.provider - ? and( - eq(ProviderTable.workspaceID, KeyTable.workspaceID), - eq(ProviderTable.provider, generation.provider), - isNull(ProviderTable.timeDeleted), - sql`length(${ProviderTable.credentials}) > 0`, - ) - : sql`false`, - ) - .where(eq(KeyTable.key, key)) - .limit(1) - .then((rows) => rows[0]), - ) - if (!workspace?.migratedAt) return undefined - const model = workspace.provider ? generation?.model : undefined - if (workspace.provider && !model) throw new Error("Legacy BYOK model mapping is unavailable") + // New Console keys are never in the legacy key table; every legacy key is `sk-`. + const legacy = !key.startsWith("oc_sk_") + const workspace = legacy ? await migratedWorkspace(key, generation?.provider) : undefined + if (legacy && !workspace) return undefined + const model = workspace?.provider ? generation?.model : undefined + if (workspace?.provider && !model) throw new Error("Legacy BYOK model mapping is unavailable") const destination = new URL(Resource.ConsoleMigration.inferenceUrl) // Imported connections must use this same workspace/provider-derived ID. - const target = model - ? `/custom/conn_${workspace.id.slice(4)}_${workspace.provider}${ - path.startsWith("/google/") - ? `/models/${encodeURIComponent(model)}${url.pathname.slice(url.pathname.lastIndexOf(":"))}` - : url.pathname.slice("/zen/v1".length) - }` - : path + const target = + model && workspace + ? `/custom/conn_${workspace.id.slice(4)}_${workspace.provider}${ + path.startsWith("/google/") + ? `/models/${encodeURIComponent(model)}${url.pathname.slice(url.pathname.lastIndexOf(":"))}` + : url.pathname.slice("/zen/v1".length) + }` + : path destination.pathname = `${destination.pathname.replace(/\/$/, "")}${target}` destination.search = url.search destination.hash = "" @@ -109,6 +87,30 @@ export async function proxyInference( return fetch(forwarded, { redirect: "manual" }) } +// Routing only; the destination owns authentication and revocation after cutover. +function migratedWorkspace(key: string, provider?: string) { + return Database.use((tx) => + tx + .select({ id: WorkspaceTable.id, provider: ProviderTable.provider }) + .from(KeyTable) + .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID)) + .leftJoin( + ProviderTable, + provider + ? and( + eq(ProviderTable.workspaceID, KeyTable.workspaceID), + eq(ProviderTable.provider, provider), + isNull(ProviderTable.timeDeleted), + sql`length(${ProviderTable.credentials}) > 0`, + ) + : sql`false`, + ) + .where(and(eq(KeyTable.key, key), isNotNull(WorkspaceTable.migrated_at))) + .limit(1) + .then((rows) => rows[0]), + ) +} + export function inferenceUnavailable() { return Response.json( { error: { type: "api_error", message: "Inference routing is unavailable. Please retry later." } }, diff --git a/packages/console/app/src/routes/auth/index.ts b/packages/console/app/src/routes/auth/index.ts index 0fefb98933ea..3840d653e13b 100644 --- a/packages/console/app/src/routes/auth/index.ts +++ b/packages/console/app/src/routes/auth/index.ts @@ -1,4 +1,5 @@ import { redirect } from "@solidjs/router" +import { Resource } from "@opencode-ai/console-resource" import type { APIEvent } from "@solidjs/start/server" import { getLastSeenWorkspaceID } from "../workspace/common" import { localeFromRequest, route } from "~/lib/language" @@ -7,6 +8,11 @@ export async function GET(input: APIEvent) { const locale = localeFromRequest(input.request) try { const workspaceID = await getLastSeenWorkspaceID() + if (!workspaceID) { + const destination = Resource.ConsoleMigration.consoleUrl + if (!destination) throw new Error("New Console URL is not configured") + return redirect(`${destination}/login`, { headers: { "Cache-Control": "no-store" } }) + } return redirect(route(locale, `/workspace/${workspaceID}`)) } catch { return redirect("/auth/authorize") diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index 95f0e338947a..a0df753a18a1 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -52,6 +52,7 @@ const models = [ { name: "DeepSeek V4 Flash Vision Exp", training: "go.faq.a5.notUsed", retention: "go.faq.a5.retention0" }, { name: "Hy4 preview", training: "go.faq.a5.notUsed", retention: "go.faq.a5.retention0" }, { name: "Hy3", training: "go.faq.a5.notUsed", retention: "go.faq.a5.retention0" }, + { name: "Union Alpha Free", training: "go.faq.a5.notUsed", retention: "go.faq.a5.retention0" }, ] as const export default function Home() { @@ -84,7 +85,7 @@ export default function Home() {
{i18n.t("home.banner.badge")}
- {i18n.t("go.promo.deepseek")} + {i18n.t("go.promo.unionAlpha")}
diff --git a/packages/console/app/src/routes/workspace-picker.tsx b/packages/console/app/src/routes/workspace-picker.tsx index 83f5582ebe09..1bd5fa2f8f5c 100644 --- a/packages/console/app/src/routes/workspace-picker.tsx +++ b/packages/console/app/src/routes/workspace-picker.tsx @@ -27,6 +27,7 @@ const getWorkspaces = query(async () => { and( eq(UserTable.accountID, Actor.account()), isNull(WorkspaceTable.timeDeleted), + isNull(WorkspaceTable.migrated_at), isNull(UserTable.timeDeleted), ), ), diff --git a/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx b/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx index ed3c4d740676..e004603e82fb 100644 --- a/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx @@ -667,8 +667,9 @@ export function LiteSection(props: { lite: LiteSubscription | undefined }) {
  • MiMo-V2.5-Pro
  • Hy4 preview
  • Hy3
  • +
  • Union Alpha Free
  • -

    {i18n.t("go.promo.deepseek")}

    +

    {i18n.t("go.promo.unionAlpha")}

    {i18n.t("workspace.lite.promo.footer")}