Skip to content

feat(proxy,ui): add Moyai to the view switcher with quick connect - #45196

Merged
ishaan-berri merged 10 commits into
mainfrom
litellm_moyai_view_switcher
Oct 8, 2026
Merged

ishaan-berri merged 10 commits into
mainfrom
litellm_moyai_view_switcher

Conversation

@ishaan-berri

@ishaan-berri ishaan-berri commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

TLDR

Adds Moyai (Cloud Coding Agent) to the dashboard product switcher, above Chat. When no deployment is connected, it opens a /moyai launch page styled after the Moyai launch post, with GitHub and demo CTAs and a Quick connect button. An admin who already runs Moyai can quick connect it: the gateway issues a scoped virtual key to Moyai server to server, and from then on the switcher opens that deployment directly.

User Flow

Before: the switcher had only AI Gateway and Chat

After: picking Moyai with nothing connected opens /moyai. From there, Quick connect takes a Moyai URL, calls POST /moyai/connect/start, and redirects to <moyai>/connect/litellm?gateway_url&code&return_to. The Moyai admin confirms. Moyai's server calls POST /moyai/connect/exchange, gets a virtual key, checks it against /v1/models, and sends the user back to the "Moyai connected" view (workspace, key alias, model count). After that, picking Moyai goes straight to the deployment. UI Settings shows the connection and has a Disconnect button

Protocol

start    (PROXY_ADMIN)  -> code = b64url(payload) + "." + b64url(HMAC_SHA256(sha256(master_key), payload))
                           payload = {moyai_origin, user_id, exp: now+600, nonce}
exchange (public route) -> verify sig (compare_digest), exp, origin == moyai_url origin
                        -> claim nonce: LiteLLM_Config.create(param_name="moyai_connect_nonce:<nonce>")
                             UniqueViolationError -> 400   (atomic across workers and concurrent requests)
                        -> generate_key_helper_fn(key_alias="moyai-<host>", no user_id,
                             allowed_routes=["openai_routes","anthropic_routes","/model/info"],
                             metadata={created_via: "moyai_quick_connect", moyai_url, connected_by})
                        -> persist UISettings.moyai_url, return {api_key, key_alias, api_base}

The key only ever travels server to server and is never logged. All exchange failures return the same generic 400. moyai_url is a new allowlisted UISettings field, validated by normalize_moyai_url (http/https only, host required, no credentials). Disconnect clears moyai_url but does not revoke the key. The Moyai side lives in a separate BerriAI/moyai branch

The five localStorage hooks now get () => false server snapshots so /moyai prerenders during build-ui

Pre-Submission checklist

  • Unit tests: tests/unit/proxy/test_moyai_endpoints.py (including sequential, concurrent and cross-worker replay), test_proxy_setting_endpoints.py, and vitest for ViewSwitcher, MoyaiLanding, MoyaiConnected, moyaiConnect, UISettings
  • Typecheck and eslint clean on changed dashboard files
  • Verified end to end against a live proxy and a local Moyai: key issued, 40 models listed, /key/generate rejects the key with 403
  • Live replay check: 2 parallel + 1 serial exchanges of one code return 200, 400, 400 with exactly one key minted

Screenshots / Proof

Moyai connected

Link to Devin session: https://app.devin.ai/sessions/4b60e9642bca44a89c1fdf8050ef0467
Open in Devin Desktop: https://app.devin.ai/desktop/session/4b60e9642bca44a89c1fdf8050ef0467?variant=devin
Requested by: @ishaan-berri

devin-ai-integration Bot and others added 2 commits October 7, 2026 23:26
Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>
Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@greptile-apps

greptile-apps Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 1/5

[Medium risk] Adds Moyai integration UI and quick-connect endpoints.

Fix the exposed connect code, missing gateway path prefix, and stale settings overwrite before merging

Findings

  1. P1 Security Connect code can be stolen ▶
  2. P1 Gateway URL loses its prefix ▶
  3. P1 Connecting restores old settings ▶
  4. P2 Gateway button returns to plugin ▶
  5. P2 Viewers get a failing form ▶
  6. P2 Accepted URLs cannot connect ▶
  7. P2 Helper inputs lack required types ▶
  8. P2 Save helper reassigns settings ▶

Summary

Adds Moyai to the product switcher, an admin quick-connect flow, a connected view, and a Disconnect control in UI Settings

  • The previous provider, reduced-motion resize, offscreen drawing, and routing-comment findings are addressed. Those threads were supplied without comment numbers
  • Remote HTTP connections can expose the connect code. Root-path deployments and replica-backed settings writes also need fixes
  • Disconnect intentionally clears the saved URL without revoking the key, as described by ishaan-berri

Reviews (2) · Last reviewed commit: "fix(proxy,ui): drop redundant auth depen..." · Reviewed by Greptile

Comment thread ui/litellm-dashboard/src/app/moyai/page.tsx Outdated
Comment thread ui/litellm-dashboard/src/components/moyai/MoyaiLanding.tsx Outdated
Comment thread ui/litellm-dashboard/src/components/moyai/moyaiSky.ts
Comment thread ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.tsx Outdated
@ishaan-berri
ishaan-berri enabled auto-merge (squash) October 7, 2026 23:34
…tual key

Adds POST /moyai/connect/start (admin only) minting a short-lived HMAC
signed connect code, and POST /moyai/connect/exchange (public route)
that verifies the code, mints a LiteLLM virtual key, and stores the
moyai_url UI setting server side. The dashboard view switcher lists
Moyai above Chat and navigates straight to a connected deployment, the
/moyai page gains a quick connect dialog, a redirect state, and a
connected success view, and UI Settings gets a Moyai disconnect row.

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>
…cate error state

The exchanged key is minted without an owning user so it cannot inherit
admin rights, records the connecting admin in metadata, and is limited
to openai_routes, anthropic_routes and /model/info. Exchange now fails
early when the proxy has no database, gateway URL resolution is shared,
and the Moyai landing relies on the dialog's own error region.

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>
The useState initializer touched window.location during static
prerender of /moyai, crashing the production build. Parse the callback
params in an effect and render nothing until they are read.

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>
@codecov

codecov Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.81579% with 17 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
litellm/proxy/moyai_endpoints.py 87.87% 16 Missing ⚠️
...proxy/ui_crud_endpoints/proxy_setting_endpoints.py 94.44% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

Comment thread litellm/proxy/moyai_endpoints.py Outdated
@veria-ai

veria-ai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

PR overview

All previously flagged issues have been addressed. No open security concerns remain on this pull request.

Security review

No open security issues remain on this pull request.

Fixed/addressed: 1 · PR risk: 0/10

…n moyai key alias lookup

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>
@devin-ai-integration devin-ai-integration Bot changed the title feat(ui): add Moyai cloud coding agent to the view switcher feat(proxy,ui): add Moyai to the view switcher with quick connect Oct 8, 2026
… without setState in effect

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>
@codspeed

codspeed Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_moyai_view_switcher (977af55) with main (6498bef)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (e638540) during the generation of this report, so 6498bef was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>
Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>
…back

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

@greptile review

raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Only proxy admins can connect Moyai")

try:
moyai_url: Final = normalize_moyai_url(body.moyai_url)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Connect code can be stolen

If an admin connects a remote HTTP deployment, the browser sends the signed code without encryption. A network observer can redeem it first at /moyai/connect/exchange, receive a working gateway key, and block the intended connection. Require HTTPS for remote quick-connect URLs, with a separate localhost exception if needed

How this was verified: The browser sends code in an HTTP URL, and the public exchange returns an API key using that code without another credential

Rule Used: What: Fail any PR which may contains a security incident on litellm's authentication layer Why: Do not cause security incidents Bad: ```python # Check cache first cache_key = ( f"oidc_userinfo_{token[:20]}" # Use fi... (source)

Comment on lines +82 to +84
if os.environ.get("PROXY_BASE_URL"):
return os.environ["PROXY_BASE_URL"].rstrip("/")
return str(request.base_url).rstrip("/")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Gateway URL loses its prefix

If PROXY_BASE_URL is set and the proxy runs under SERVER_ROOT_PATH, _gateway_url drops the path prefix. Moyai sends its exchange request to the wrong URL, so quick connect fails. The returned api_base also lacks the prefix. Use get_custom_url(str(request.base_url)), which already joins the public base URL and the current root path

Knowledge Base Used: Dashboard and enterprise UI

Comment on lines +196 to +198
db_existing: Final = await _ui_settings_db(UISettingsRepository(prisma_client)).find_unique(
where={"id": "ui_settings"}
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Connecting restores old settings

If a read replica is configured, _persist_moyai_url reads settings from it and then replaces the entire settings value on the writer. An admin's recent changes can disappear if the replica has not caught up. Read from the writer and make the merge safe against concurrent updates

Comment on lines +73 to +74
<a
href={uiHref("")}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Gateway button returns to plugin

After connecting from an enterprise plugin, “Back to AI Gateway” opens that plugin again because the link keeps the saved plugin mode. Users must use the switcher to reach the gateway. Call setMode("ai-gateway") before navigating, as ViewSwitcher does

Knowledge Base Used: Dashboard and enterprise UI

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

</div>
);
} else {
content = <MoyaiLanding canQuickConnect={isProxyAdminRole(userRole ?? "")} onQuickConnect={onQuickConnect} />;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Viewers get a failing form

View-only admins see Quick connect because useAuthorized().userRole maps proxy_admin_viewer to "Admin". They can fill out the form, but every attempt fails the backend's write-admin check. Also require !isViewOnly when showing this control

Comment on lines +159 to +161
connect_url: Final = f"{moyai_url}/connect/litellm?" + urlencode(
{"gateway_url": _gateway_url(request), "code": code, "return_to": body.return_to}
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Accepted URLs cannot connect

Both URL validators accept queries and fragments, but connect_url appends its path to the raw URL. For https://moyai.example.com/#dashboard, the connection path and code stay in the fragment and never reach the server. An admin can pass the form checks but land at the wrong page. Reject queries and fragments for deployment base URLs, or build the URL from parsed parts

return f"{_b64url(payload)}.{_b64url(signature)}"


def _decode_connect_code(master_key: str, code: str) -> dict:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Helper inputs lack required types

_decode_connect_code returns a bare dict, while _moyai_key_alias and _persist_moyai_url leave prisma_client untyped. AGENTS.md requires strongly typed parameters and forbids coarse types such as bare dict. Add the database type and a typed model for the decoded payload. This repository requirement must be satisfied before merging

Context Used: AGENTS.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +195 to +201
existing: dict = {}
db_existing: Final = await _ui_settings_db(UISettingsRepository(prisma_client)).find_unique(
where={"id": "ui_settings"}
)
if db_existing and db_existing.ui_settings:
raw: Final = db_existing.ui_settings
existing = json.loads(raw) if isinstance(raw, str) else dict(raw)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Save helper reassigns settings

_persist_moyai_url initializes existing and later reassigns it. AGENTS.md forbids reassignment and requires every variable to use Final. Build existing once from the database row instead. This repository requirement must be satisfied before merging

Context Used: AGENTS.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@ishaan-berri
ishaan-berri merged commit 5531169 into main Oct 8, 2026
108 of 111 checks passed
@ishaan-berri
ishaan-berri deleted the litellm_moyai_view_switcher branch October 8, 2026 00:41

This branch is waiting to be deployed

1 waiting deployment
e2e-changed — 977af554 Waiting Oct 8, 2026 by devin-ai-integration[bot] via oauth #3676
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.

4 participants