fix: detect Xum client in aibridge after Mux rename (#28448)

This commit is contained in:
Atif Ali
2026-08-24 16:20:57 +05:00
committed by GitHub
parent c275327fb7
commit 54d4ae9aca
14 changed files with 59 additions and 35 deletions
+4 -3
View File
@@ -18,7 +18,7 @@ const (
ClientKilo Client = "Kilo Code"
ClientCoderAgents Client = "Coder Agents"
ClientCrush Client = "Charm Crush"
ClientMux Client = "Mux"
ClientXum Client = "Xum"
ClientRoo Client = "Roo Code"
ClientCursor Client = "Cursor"
ClientOpenCode Client = "OpenCode"
@@ -35,8 +35,9 @@ func GuessClient(r *http.Request) Client {
// Must be kept in sync with documentation: https://github.com/coder/coder/blob/3cf867f84aa32d2febf7a26dc7e52be6beb8a2ac/docs/ai-coder/ai-gateway/monitoring.md?plain=1#L47-L57
switch {
case strings.HasPrefix(userAgent, "mux/"):
return ClientMux
case strings.HasPrefix(userAgent, "xum/") || strings.HasPrefix(userAgent, "mux/"):
// Mux was renamed to Xum; "mux/" is kept for older, unupgraded clients.
return ClientXum
case strings.HasPrefix(userAgent, "claude"):
return ClientClaudeCode
case strings.HasPrefix(userAgent, "codex"):
+7 -2
View File
@@ -19,9 +19,14 @@ func TestGuessClient(t *testing.T) {
wantClient aibridge.Client
}{
{
name: "mux",
name: "xum",
userAgent: "xum/0.20.0 ai-sdk/openai/3.0.36 ai-sdk/provider-utils/4.0.15 runtime/node.js/22",
wantClient: aibridge.ClientXum,
},
{
name: "xum_legacy_mux_user_agent",
userAgent: "mux/0.19.0-next.2.gcceff159 ai-sdk/openai/3.0.36 ai-sdk/provider-utils/4.0.15 runtime/node.js/22",
wantClient: aibridge.ClientMux,
wantClient: aibridge.ClientXum,
},
{
name: "claude_code",
@@ -1172,13 +1172,13 @@ func TestSessionIDTracking(t *testing.T) {
}{
// Session in header.
{
name: "mux",
name: "xum",
fixture: fixtures.AntSimple,
expectedClient: aibridge.ClientMux,
expectSessionID: "mux-workspace-321",
expectedClient: aibridge.ClientXum,
expectSessionID: "xum-workspace-321",
header: http.Header{
"User-Agent": []string{"mux/1.0.0"},
"X-Mux-Workspace-Id": []string{"mux-workspace-321"},
"User-Agent": []string{"xum/1.0.0"},
"X-Mux-Workspace-Id": []string{"xum-workspace-321"},
},
},
// Session in body.
+3 -1
View File
@@ -62,7 +62,9 @@ func GuessSessionID(client Client, r *http.Request) *string {
return sid
}
return cleanRef(r.Header.Get("session_id"))
case ClientMux:
case ClientXum:
// Header name is intentionally still "X-Mux-Workspace-Id"; Xum keeps the
// wire value from before the Mux rename.
return cleanRef(r.Header.Get("X-Mux-Workspace-Id"))
case ClientZed:
return nil // Zed does not send a session ID from Zed Agent or Text Thread.
+5 -5
View File
@@ -139,16 +139,16 @@ func TestGuessSessionID(t *testing.T) {
headers: map[string]string{"session_id": "zed-session"},
body: `{"metadata":{"user_id":"user_abc_account_456_session_some-id"}}`,
},
// Mux.
// Xum.
{
name: "mux_with_workspace_header",
client: aibridge.ClientMux,
name: "xum_with_workspace_header",
client: aibridge.ClientXum,
headers: map[string]string{"X-Mux-Workspace-Id": "ws-abc-123"},
sessionID: utils.PtrTo("ws-abc-123"),
},
{
name: "mux_without_workspace_header",
client: aibridge.ClientMux,
name: "xum_without_workspace_header",
client: aibridge.ClientXum,
},
// Copilot VS Code.
{
+1 -1
View File
@@ -38,7 +38,7 @@ The table below shows tested AI clients and their compatibility with AI Gateway.
| Client | OpenAI | Anthropic | BYOK | Notes |
|-----------------------------------|--------|-----------|------|--------------------------------------------------------------------------------------------------------------------------------------------------------|
| [Mux](./mux.md) | ✅ | ✅ | - | |
| [Xum](./xum.md) | ✅ | ✅ | - | |
| [Claude Code](./claude-code.md) | - | ✅ | ✅ | |
| [Codex CLI](./codex.md) | ✅ | - | ✅ | |
| [OpenCode](./opencode.md) | ✅ | ✅ | ✅ | |
@@ -1,12 +1,12 @@
# Mux
# Xum
> [!NOTE]
> AI Gateway is part of [AI Governance](../../ai-governance.md), which is
> included with a Premium license.
Mux makes it easy to run parallel coding agents, each with its own isolated workspace, from your browser or desktop; it is open source and provider-agnostic.
Xum (formerly Mux) makes it easy to run parallel coding agents, each with its own isolated workspace, from your browser or desktop; it is open source and provider-agnostic.
Mux can be configured to route OpenAI- and Anthropic-compatible traffic through AI Gateway by setting a custom provider base URL and using a Coder-issued token for authentication.
Xum can be configured to route OpenAI- and Anthropic-compatible traffic through AI Gateway by setting a custom provider base URL and using a Coder-issued token for authentication.
## Prerequisites
@@ -19,14 +19,14 @@ Mux can be configured to route OpenAI- and Anthropic-compatible traffic through
### OpenAI
1. Open Mux settings (`Cmd+,` / `Ctrl+,`).
1. Open Xum settings (`Cmd+,` / `Ctrl+,`).
2. Go to **Providers** → **OpenAI**.
3. Set **API Key** to your Coder API token.
4. Set **Base URL** to `https://coder.example.com/api/v2/ai-gateway/openai/v1`.
### Anthropic
1. Open Mux settings (`Cmd+,` / `Ctrl+,`).
1. Open Xum settings (`Cmd+,` / `Ctrl+,`).
2. Go to **Providers** → **Anthropic**.
3. Set **API Key** to your Coder API token.
4. Set **Base URL** to `https://coder.example.com/api/v2/ai-gateway/anthropic`.
@@ -37,11 +37,11 @@ _Replace `coder.example.com` with your Coder deployment URL._
## Environment variables
Mux reads provider configuration from its settings UI and also from environment variables.
Environment variables are useful in CI or when running Mux inside a Coder workspace.
Xum reads provider configuration from its settings UI and also from environment variables.
Environment variables are useful in CI or when running Xum inside a Coder workspace.
> [!NOTE]
> Mux treats environment variables as a fallback when a provider is not configured in settings.
> Xum treats environment variables as a fallback when a provider is not configured in settings.
> If you have already configured a provider in the UI, clear it (or update it) for env vars to take effect.
```sh
@@ -54,9 +54,9 @@ export ANTHROPIC_API_KEY="<your-coder-api-token>"
export ANTHROPIC_BASE_URL="https://coder.example.com/api/v2/ai-gateway/anthropic"
```
## Run Mux in a Coder workspace
## Run Xum in a Coder workspace
To run Mux inside a Coder workspace (for example, as a Coder app), you can install it with the [Mux module](https://registry.coder.com/modules/coder/mux) and pre-configure AI Gateway via environment variables on the agent:
To run Xum inside a Coder workspace (for example, as a Coder app), you can install it with the [`mux` module](https://registry.coder.com/modules/coder/mux) (still published under its pre-rename name) and pre-configure AI Gateway via environment variables on the agent:
```tf
data "coder_workspace" "me" {}
@@ -82,7 +82,7 @@ module "mux" {
## Advanced: providers.jsonc
If you prefer a file-based config, edit `~/.mux/providers.jsonc`:
If you prefer a file-based config, edit `~/.xum/providers.jsonc`:
```json
{
@@ -97,4 +97,4 @@ If you prefer a file-based config, edit `~/.mux/providers.jsonc`:
}
```
**References:** [Mux provider environment variables](https://mux.coder.com/config/providers#environment-variables)
**References:** [Xum provider environment variables](https://xum.coder.com/config/providers#environment-variables)
+1 -1
View File
@@ -220,7 +220,7 @@ Available query filters:
- `Kilo Code`
- `Roo Code`
- `Coder Agents`
- `Mux`
- `Xum`
- `Cursor`
- `OpenCode`
- `Charm Crush`
+3 -3
View File
@@ -1226,9 +1226,9 @@
"state": ["premium"]
},
{
"title": "Mux",
"description": "Configure Mux, the parallel coding agent tool, to route requests through AI Gateway.",
"path": "./ai-coder/ai-gateway/clients/mux.md",
"title": "Xum",
"description": "Configure Xum, the parallel coding agent tool, to route requests through AI Gateway.",
"path": "./ai-coder/ai-gateway/clients/xum.md",
"state": ["premium"]
},
{
@@ -49,6 +49,14 @@ export const AIBridgeClientIcon = ({
className={cn(iconClassName, className)}
/>
);
case "Xum":
return (
<ExternalImage
src="/icon/xum.svg"
className={cn(iconClassName, className)}
/>
);
// Legacy label for interceptions recorded before the Mux -> Xum rename.
case "Mux":
return (
<ExternalImage
+2 -2
View File
@@ -5611,10 +5611,10 @@ export const MockSession: TypesGen.AIBridgeSession = {
},
providers: ["anthropic", "openai"],
models: ["claude-opus-4-6", "gpt-5.4"],
client: "Mux",
client: "Xum",
metadata: {
request_user_agent:
"mux/0.20.1-next.8.g0f494106 ai-sdk/anthropic/3.0.58 ai-sdk/provider-utils/4.0.19 runtime/node.js/22",
"xum/0.20.1-next.8.g0f494106 ai-sdk/anthropic/3.0.58 ai-sdk/provider-utils/4.0.19 runtime/node.js/22",
},
started_at: "2026-03-09T09:28:15.03152Z",
ended_at: "2026-03-09T10:28:17.294897Z",
+1
View File
@@ -187,6 +187,7 @@ export const defaultParametersForBuiltinIcons = new Map<string, string>([
["/icon/terminal.svg", "monochrome"],
["/icon/vercel.svg", "whiteWithColor"],
["/icon/widgets.svg", "monochrome"],
["/icon/xum.svg", "monochrome"],
["/icon/windsurf.svg", "monochrome"],
["/icon/zed.svg", "monochrome"],
]);
+1
View File
@@ -151,5 +151,6 @@
"widgets.svg",
"windows.svg",
"windsurf.svg",
"xum.svg",
"zed.svg"
]
+6
View File
@@ -0,0 +1,6 @@
<svg width="256" height="256" viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(5.595628 0 0 5.595628 -73.442623 -73.442623)">
<path d="M13.125 47.5 20.9101 36.4133 13.3288 25.6526H19.8096L24.497 32.6634L29.0214 25.6526H35.6652L28.1246 36.454L35.869 47.5H29.3882L24.5785 40.0817L19.7281 47.5H13.125Z" fill="black"/>
<rect x="38.875" y="24.5" width="20" height="23" fill="black"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 433 B