Skip to content

feat(web): dev backend switcher and engine badge for dual-engine debugging - #1592

Merged
wbxl2000 merged 1 commit into
mainfrom
feat/web-backend-switcher
Jul 13, 2026
Merged

feat(web): dev backend switcher and engine badge for dual-engine debugging#1592
wbxl2000 merged 1 commit into
mainfrom
feat/web-backend-switcher

Conversation

@wbxl2000

Copy link
Copy Markdown
Collaborator

Related Issue

No linked issue — this came from a maintainer request; the problem is explained below.

Problem

Debugging kimi-web against the two backend engines (v1 @moonshot-ai/server, v2 @moonshot-ai/kap-server) had three frictions:

  1. No way to tell which engine the dev server was talking to. Both default to the same port, and the sidebar only showed host:port.
  2. Switching engines meant restarting the Vite dev server with a different KIMI_SERVER_URL.
  3. Once pointed at v1, the WebSocket failed in a reconnect loop. The dev proxy rewrites Host (changeOrigin) but leaks the browser's Origin (the Vite origin); v1's WS upgrade path rejects that Origin-vs-Host mismatch with 403. kap-server doesn't enforce this, which is why v2 appeared to work — the failure only showed up when targeting v1.

What changed

  • Root pnpm dev:v1 / pnpm dev:v2 scripts. v2 boots kap-server with KIMI_CODE_EXPERIMENTAL_MULTI_SERVER=1 on a fixed port (58628; v1 keeps 58627), so both engines can run side by side — v2 registers in the instance registry instead of taking the single-instance lock.
  • Dev-proxy backend switcher (apps/kimi-web/vite.config.ts, dev only): GET/POST /__kimi-dev/backend reads/repoints the /api/v1 proxy target at runtime, for both HTTP and WS. Note: vite's vendored http-proxy has no router support (verified in the bundled source), so the plugin captures the live proxy-options object via configure and mutates target on it, which vite consults per HTTP request (shallow copy) and per WS upgrade (direct reference). Presets default to 58627/58628, overridable via KIMI_BACKEND_V1_URL / KIMI_BACKEND_V2_URL.
  • Sidebar backend pill (dev only) next to the brand: shows v1/v2 + endpoint sourced from GET /api/v1/meta's backend field (absent ⇒ v1), with a one-click menu that switches the proxy and reloads. Responsive: the endpoint collapses below 320px sidebar width, the product name below 250px.
  • Settings → Advanced shows the backend engine — visible in the production (server-hosted) web UI too.
  • /meta is re-fetched on every WS (re)connect, so version/backend can never go stale across backend restarts or proxy switches.
  • The shared dev/preview proxy strips the browser Origin header on forwarded requests (proxyReq + proxyReqWs). An Origin-less request is treated as a non-browser client by both engines, and the browser needs no CORS in same-origin mode. This fixes the v1 WS 403 without weakening any server-side check — the proxy was the layer creating the mismatch.
  • Tests: workspace-state coverage for the backend mapping (incl. absent ⇒ v1) and the reconnect meta refresh.

Verification: vue-tsc, vitest (458 passed), check:style (no new findings), oxlint (0 errors). Functionally verified against live v1/v2 servers: switcher endpoints, proxy retargeting for HTTP and WS (dead-port probe proves the target actually moved), and the 403→401 fix with a browser Origin header. Visually verified light/dark pill, the switcher menu, and the Settings row via headless Chrome.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update — contributor-facing dev tooling plus one Settings label; no CLI/user documentation impact.

…gging

Add the plumbing to debug kimi-web against the v1 (server) and v2
(kap-server) engines side by side:

- root dev:v1 / dev:v2 scripts; v2 boots kap-server with the
  multi_server flag on a fixed port so both engines can run at once
- dev-proxy backend switcher: GET/POST /__kimi-dev/backend repoints
  the /api/v1 proxy at runtime (HTTP + WS) without a Vite restart
- dev-only sidebar backend pill reading /meta's backend field, with a
  one-click switcher menu; Settings shows the backend engine too
- re-fetch /meta on every WS (re)connect so the badge stays truthful
  across backend restarts and switches
- strip the browser Origin header on proxied requests: v1's WS upgrade
  path rejected the Vite-origin vs server-Host mismatch with 403
@changeset-bot

changeset-bot Bot commented Jul 13, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 308a5c1

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jul 13, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@308a5c1
npx https://pkg.pr.new/@moonshot-ai/kimi-code@308a5c1

commit: 308a5c1

@wbxl2000
wbxl2000 merged commit 924d5c9 into main Jul 13, 2026
11 checks passed
@wbxl2000
wbxl2000 deleted the feat/web-backend-switcher branch July 13, 2026 07:22
@github-actions github-actions Bot mentioned this pull request Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant