diff --git a/pyproject.toml b/pyproject.toml index 0323d620..adb9490e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ dependencies = [ "langchain-openai>=1.2.2", "langchain-fireworks>=1.4.2", # langchain-fireworks 1.4.2 pins a pre-release fireworks-ai; opt in explicitly so uv resolves it. - "fireworks-ai>=1.2.0a71", + "fireworks-ai>=1.2.0a85", "langchain-daytona>=0.0.5", "langchain-modal>=0.0.3", "langchain-runloop>=0.0.4", diff --git a/tests/e2e/package-lock.json b/tests/e2e/package-lock.json index 24a2c9bf..653ef271 100644 --- a/tests/e2e/package-lock.json +++ b/tests/e2e/package-lock.json @@ -6,17 +6,17 @@ "": { "name": "open-swe-e2e", "devDependencies": { - "@playwright/test": "1.61.0" + "@playwright/test": "1.61.1" } }, "node_modules/@playwright/test": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.61.0.tgz", - "integrity": "sha512-cKA5B6lpFEMyMGjxF54QihfYpB4FkEGH+qZhtArDEG+wezQAJY8Pq6C7T1SjWz+FFzt3TbyoXBQYk/0292TdJA==", + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.61.1.tgz", + "integrity": "sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.61.0" + "playwright": "1.61.1" }, "bin": { "playwright": "cli.js" @@ -41,13 +41,13 @@ } }, "node_modules/playwright": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.0.tgz", - "integrity": "sha512-Z+7BeeqQPRRzklHsVFP4KTGIyMxKUmfeRA4WisM6G3/XW6nwGeX6fX9qYaDa+CiUqpOkb2f6X3nar05R3kSuJQ==", + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.1.tgz", + "integrity": "sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.61.0" + "playwright-core": "1.61.1" }, "bin": { "playwright": "cli.js" @@ -60,9 +60,9 @@ } }, "node_modules/playwright-core": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.0.tgz", - "integrity": "sha512-caX7TrY3Ml6egyDX0WUcTHDxodl/b51y5wJOdCEA36QviK/s2g081hvmGs8eaE3DWb6NYZQ6BjO/QkNRPenoPA==", + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.1.tgz", + "integrity": "sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/tests/e2e/package.json b/tests/e2e/package.json index 1cd31b38..50baf798 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -8,6 +8,6 @@ "report": "playwright show-report" }, "devDependencies": { - "@playwright/test": "1.61.0" + "@playwright/test": "1.61.1" } } diff --git a/ui/package.json b/ui/package.json index 130f02be..48eeaacc 100644 --- a/ui/package.json +++ b/ui/package.json @@ -5,7 +5,6 @@ "scripts": { "dev": "vite dev --port 3000", "build": "vite build", - "vercel-build": "vite build && node scripts/build-vercel-output.mjs", "preview": "vite preview", "test": "vitest run", "lint": "eslint", @@ -34,7 +33,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^1.16.0", - "monaco-editor": "^0.52.2", + "monaco-editor": "^0.55.1", "nitro": "latest", "react": "^19.2.4", "react-dom": "^19.2.4", @@ -48,7 +47,7 @@ "vite-tsconfig-paths": "^5.1.4" }, "devDependencies": { - "@tanstack/devtools-vite": "^0.6.0", + "@tanstack/devtools-vite": "^0.8.1", "@tanstack/eslint-config": "^0.4.0", "@testing-library/dom": "^10.4.1", "@testing-library/react": "^16.3.2", @@ -58,7 +57,7 @@ "@vitejs/plugin-react": "^5.2.0", "jsdom": "^27.4.0", "prettier": "^3.8.1", - "prettier-plugin-tailwindcss": "^0.7.2", + "prettier-plugin-tailwindcss": "^0.8.0", "typescript": "^5.9.3", "vite": "^7.3.5", "vite-plugin-pwa": "^1.3.0", diff --git a/ui/scripts/build-vercel-output.mjs b/ui/scripts/build-vercel-output.mjs deleted file mode 100644 index 0bb2c1fb..00000000 --- a/ui/scripts/build-vercel-output.mjs +++ /dev/null @@ -1,47 +0,0 @@ -// Repackage the static Vite/TanStack-Start build (.output/public) into the Vercel -// Build Output API layout (.vercel/output), generating the /dashboard/api/* proxy -// destination from a per-project env var. -// -// Why this exists: prod deploys via a fast-forward-only promotion, so the `dev` and -// `main` branches are byte-identical and a committed vercel.json CANNOT differ between -// them. The app is same-origin only (no backend CORS), so the per-environment backend -// must be the PROXY DESTINATION, supplied per Vercel project as LANGGRAPH_BACKEND_URL. -// Vercel reads vercel.json BEFORE the build and never interpolates env into it, so the -// routes are emitted here (read AFTER the build) where process.env is available. -import { cp, mkdir, writeFile, rm } from "node:fs/promises" - -const backend = process.env.LANGGRAPH_BACKEND_URL -if (!backend) { - throw new Error( - "LANGGRAPH_BACKEND_URL is required at build time (set it per Vercel project: " + - "dev project -> dev langgraph URL, prod project -> prod langgraph URL).", - ) -} -const base = backend.replace(/\/$/, "") - -await rm(".vercel/output", { recursive: true, force: true }) -await mkdir(".vercel/output/static", { recursive: true }) -await cp(".output/public", ".vercel/output/static", { recursive: true }) - -await writeFile( - ".vercel/output/config.json", - JSON.stringify( - { - version: 3, - routes: [ - // Same-origin proxy to this project's backend (proxy, not redirect, so the - // osw_session cookie stays first-party on the Vercel origin). - { src: "^/dashboard/api/(.*)$", dest: `${base}/dashboard/api/$1` }, - // Serve hashed assets, the PWA manifest/service worker, and _shell.html itself - // BEFORE the SPA catch-all, or static files get swallowed by the fallback. - { handle: "filesystem" }, - // SPA fallback (replaces the old vercel.json /(.*) -> /_shell.html rewrite). - { src: "^/.*$", dest: "/_shell.html" }, - ], - }, - null, - 2, - ) + "\n", -) - -console.log(`[build-vercel-output] wrote .vercel/output/config.json (backend: ${base})`) diff --git a/ui/vercel.json b/ui/vercel.json index 46980c33..7a3c56cc 100644 --- a/ui/vercel.json +++ b/ui/vercel.json @@ -1,4 +1,5 @@ { + "$schema": "https://openapi.vercel.sh/vercel.json", "framework": null, - "buildCommand": "bun run vercel-build" + "buildCommand": "bun run build" } diff --git a/ui/vite.config.ts b/ui/vite.config.ts index 3d30de8d..14c5d307 100644 --- a/ui/vite.config.ts +++ b/ui/vite.config.ts @@ -74,13 +74,44 @@ function mockHarnessProxy(): Plugin | null { } } +// Same-origin proxy for the dashboard API. Vercel reads vercel.json BEFORE the build +// and never interpolates env into it, and prod promotes by fast-forward (so `dev` and +// `main` ship a byte-identical vercel.json that cannot encode a per-project backend). +// So the per-project backend is driven through Nitro instead: this `routeRules` proxy +// is compiled by Nitro's Vercel preset into a CDN-level rewrite in +// `.vercel/output/config.json` at build time, reading LANGGRAPH_BACKEND_URL from the +// per-project Vercel env var. Proxy (not redirect) keeps the osw_session cookie +// first-party on the Vercel origin. The `**` wildcard maps 1:1 to the destination. +function backendProxyRouteRules(): + | Record + | undefined { + const backend = process.env.LANGGRAPH_BACKEND_URL?.replace(/\/$/, "") + // Nitro's Vercel preset auto-activates from the VERCEL env var; NITRO_PRESET=vercel + // forces it locally. On Vercel the backend is mandatory — fail loudly rather than + // ship a build whose API calls 404, which is exactly how the previous approach broke. + const onVercel = + !!process.env.VERCEL || process.env.NITRO_PRESET === "vercel" + if (!backend) { + if (onVercel) { + throw new Error( + "LANGGRAPH_BACKEND_URL is required for Vercel builds (set it per Vercel " + + "project: dev project -> dev langgraph URL, prod project -> prod langgraph URL).", + ) + } + // Off Vercel with no backend configured (plain local `vite build`, tests): omit the + // proxy. Local dev gets its API via the E2E_HARNESS mock proxy above instead. + return undefined + } + return { "/dashboard/api/**": { proxy: `${backend}/dashboard/api/**` } } +} + const config = defineConfig({ optimizeDeps: { include: ["workbox-window"] }, worker: { format: "es" }, plugins: [ mockHarnessProxy(), devtools(), - nitro(), + nitro({ routeRules: backendProxyRouteRules() }), viteTsConfigPaths({ projects: ["./tsconfig.json"], }), diff --git a/uv.lock b/uv.lock index 3a325ca1..cf23658e 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.11" resolution-markers = [ "python_full_version >= '3.14'", @@ -784,7 +784,7 @@ wheels = [ [[package]] name = "fireworks-ai" -version = "1.2.0a75" +version = "1.2.0a85" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, @@ -796,9 +796,9 @@ dependencies = [ { name = "sniffio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f9/e8/3ce01c9802810f476a7d4273ff937584ba5941da9f06a0f3a4c10d0335c5/fireworks_ai-1.2.0a75.tar.gz", hash = "sha256:b7ccb914f2a64037fd8ab93b219565e94cd3a072fe60d0349707ab67210ba9aa", size = 416496, upload-time = "2026-06-03T18:45:34.846Z" } +sdist = { url = "https://files.pythonhosted.org/packages/65/94/fb75cf9c769a09de31e550ba99a279e5f83a05cfcf49cd0cbb8ad586ab35/fireworks_ai-1.2.0a85.tar.gz", hash = "sha256:33abbeddd9a6bd9993bca6cb9e16afe9799b2cd674d6b7c04a601cd4e412f2a7", size = 448217, upload-time = "2026-06-26T08:06:57.286Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/53/49/d799dcabfb65b50423dae7d2d4715058b848be7d4d9bb8248850b8aa1d18/fireworks_ai-1.2.0a75-py3-none-any.whl", hash = "sha256:6f2dfe15ceee2a700e21f775cad5776b2726ff475095e33a10ab8cd3c3d5b5aa", size = 495789, upload-time = "2026-06-03T18:45:33.328Z" }, + { url = "https://files.pythonhosted.org/packages/3f/5b/0b10d0afb633b45f234f6728cc680851f136b9f75903b4387049537a6cd6/fireworks_ai-1.2.0a85-py3-none-any.whl", hash = "sha256:80a4b13bda8e28ca9064c8339d0afe47cbbdb7c61a88eeebc173ccb58129f19a", size = 528844, upload-time = "2026-06-26T08:06:55.927Z" }, ] [[package]] @@ -2220,7 +2220,7 @@ requires-dist = [ { name = "deepagents", specifier = "==0.6.8" }, { name = "exa-py", specifier = ">=2.13.0" }, { name = "fastapi", specifier = ">=0.136.3" }, - { name = "fireworks-ai", specifier = ">=1.2.0a71" }, + { name = "fireworks-ai", specifier = ">=1.2.0a85" }, { name = "httpx", specifier = ">=0.28.1" }, { name = "langchain", specifier = ">=1.3.9" }, { name = "langchain-anthropic", specifier = ">=1.4.6" },