fix(deploy): map grok/xai models to the xai provider for credential matching

Merged
WI
4mo ago
+60-0

Problem

Deploying a grok persona to cloud fails to recognize a connected xAI credential. Even after relay cloud connect xai succeeds, the deploy reports:

grok credentials are not connected. Choose harness source (plan/byok/oauth) [plan]

…and accepting the default plan then fails on workspaces without relay-managed grok:

cloud managed provider credentials failed: 403 {"error":"Forbidden"}

Choosing oauth doesn't help either — it re-launches a browser connect and polls for a credential row that never matches, so the deploy loops.

Root cause

deriveModelProvider special-cases anthropic/openai/google/openrouter via token matching, but has no grok/xai case. A grok persona declares model: "grok-build", which falls through to the generic model.split(/[/:]/) and resolves to the literal provider key "grok-build".

The credential relay cloud connect xai stores is keyed harness: "grok" (modelProvider "xai"):

{ "harness": "grok", "modelProvider": "xai", "authType": "provider_oauth", "status": "connected", "isActive": true }

"grok-build" matches neither "grok" nor "xai", so hasConnectedHarness returns false → the probe says "not connected" → re-prompt / loop.

Fix

Mirror the existing provider/alias pattern (anthropic→claude, openai→codex, openrouter→opencode):

  • deriveModelProvider: map grok/xai/x-ai models → provider "xai"
  • harnessAliasForModelProvider: alias "xai" → "grok"

So deriveModelProvider("grok-build") → "xai", the match targets become {"xai", "grok"}, and the connected harness: "grok" entry is recognized. The oauth deploy then proceeds without a browser reconnect or the plan-path 403.

Grok remains harness-only for ctx.llm (same as codex/opencode subscriptions) — the persona runs through the grok harness via harness.run, so no ctx.llm credential selection is stamped, which is expected.

Test

Adds a regression test: a grok persona (model: "grok-build") with a credential connected under harness: "grok" resolves silently and deploys, with no browser reconnect. Verified it fails without the fix (grok OAuth credentials are not connected) and passes with it.

# tests 188
# pass 188
# fail 0

🤖 Generated with Claude Code