Skip to content

feat(grok): import CPA xAI OAuth provider - #676

Merged
awsl233777 merged 4 commits into
mainfrom
feat/grok-cpa-import
Jul 15, 2026
Merged

feat(grok): import CPA xAI OAuth provider#676
awsl233777 merged 4 commits into
mainfrom
feat/grok-cpa-import

Conversation

@awsl233777

@awsl233777 awsl233777 commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add a Grok provider that accepts CLIProxyAPI xAI OAuth JSON exports
  • route Grok requests through CLIProxyAPI's native xAI executor instead of an OpenAI-compatible fallback
  • add the Grok provider creation UI and transport/domain config types

Dependency

Validation

  • go test ./internal/adapter/provider/cliproxyapi_grok ./internal/adapter/provider/grok
  • go test ./...
  • go build -o /tmp/maxx-grok-build ./cmd/maxx
  • pnpm --dir web typecheck
  • pnpm --dir web build

Notes

  • used the CPA xAI OAuth JSON shape supplied in chat for adapter normalization coverage; token values are not included in this PR description

Summary by CodeRabbit

  • 新功能

    • 新增 Grok(xAI)提供方支持,可通过 OAuth 配置调用相关模型。
    • 支持从粘贴内容或 JSON 文件批量导入 Grok 凭据。
    • 提供方创建流程新增 Grok 选项、导入页面及品牌样式。
    • 支持流式与非流式请求,并显示相应模型与响应信息。
  • 界面优化

    • 优化密码输入框在不同浏览器中的显示效果。
    • 新增 Grok 提供方配色。

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@awsl233777, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 23 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e7f71524-4a5a-416e-ae35-9777bc74f7c5

📥 Commits

Reviewing files that changed from the base of the PR and between c184e7a and 1724718.

📒 Files selected for processing (1)
  • web/src/pages/providers/components/grok-token-import.tsx
📝 Walkthrough

Walkthrough

新增 Grok provider 支持:后端适配 CLIProxyAPI 的 xAI OAuth 请求,前端提供 JSON/文件凭据导入、provider 创建、类型选择、路由及主题展示。

Changes

Grok provider integration

Layer / File(s) Summary
Grok configuration contracts
internal/domain/model.go, web/src/lib/transport/types.ts, web/src/lib/theme.ts, web/src/pages/providers/types.ts, web/src/index.css
新增 Grok OAuth 配置结构、provider 类型、显示配置及主题颜色。
CLIProxyAPI Grok adapter
internal/adapter/provider/cliproxyapi_grok/adapter.go, internal/adapter/provider/cliproxyapi_grok/adapter_test.go
校验 xAI OAuth 配置,初始化 XAI executor,并处理模型映射、非流式响应和 SSE 流式响应。
Adapter registration and dependency wiring
internal/adapter/provider/grok/adapter.go, internal/core/database.go, cmd/maxx/main.go, go.mod
注册 grok 适配器工厂,通过空白导入启用注册,并更新相关依赖解析信息。
Grok token import flow
web/src/pages/providers/components/grok-token-import.tsx, web/src/pages/providers/components/select-type-step.tsx, web/src/pages/providers/create-layout.tsx, web/src/pages/providers/hooks/use-provider-navigation.ts
支持粘贴或选择 Grok OAuth JSON,校验并创建 provider,增加类型选择、导航和创建路由。
Provider presentation styling
web/src/index.css
隐藏密码输入框的浏览器内置控件。

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Operator
  participant ProviderSelector
  participant GrokTokenImport
  participant ProviderAPI
  participant GrokAdapter
  participant XAIExecutor
  Operator->>ProviderSelector: Select Grok
  ProviderSelector->>GrokTokenImport: Navigate to Grok import
  Operator->>GrokTokenImport: Paste or upload OAuth JSON
  GrokTokenImport->>ProviderAPI: Create grok provider
  ProviderAPI->>GrokAdapter: Resolve registered adapter
  GrokAdapter->>XAIExecutor: Execute mapped OpenAI request
  XAIExecutor-->>GrokAdapter: Return JSON or SSE response
Loading

Possibly related PRs

Suggested reviewers: bowl42

Poem

兔耳竖起,Grok 来到田野,
OAuth 小票装进篮子里。
JSON 飘过,令牌排好队,
XAI executor 踏着 SSE 起舞。
新的 provider 亮起颜色,
胡萝卜也为这次接入欢呼。

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了本次变更:新增 grok 提供方并导入 CLIProxyAPI 的 xAI OAuth 配置。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/grok-cpa-import

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/adapter/provider/cliproxyapi_grok/adapter.go`:
- Around line 224-227: 在流式响应处理逻辑中更新 w.Write
调用,检查其返回的错误;当写入失败(例如客户端断开连接)时立即退出当前上游读取循环,避免继续处理和写入后续数据。保留成功写入后的 flusher.Flush
及首个分块处理逻辑不变。
- Around line 156-163: Update updateModelInBody to parse the request with a
json.Decoder configured with UseNumber(), preserving integer values and their
original numeric representation. Serialize the updated payload with a
json.Encoder configured to disable HTML escaping, while retaining the existing
error propagation and model replacement behavior.

In `@web/src/pages/providers/components/grok-token-import.tsx`:
- Around line 180-191: 为包含 jsonText 的 Textarea 添加可访问名称,并通过关联的 label
让其具备明确语义;同时更新 error 条件渲染的错误容器,加入 role="alert" 或等效的 aria-live
属性。保持现有输入处理和错误展示内容不变。
- Around line 157-198: Move the Grok import UI strings in
web/src/pages/providers/components/grok-token-import.tsx (lines 157-198) into
the existing translation resources and render them through the component’s
established i18n helper, including the title, description, file label/status,
textarea placeholder, error-related text, buttons, and dynamic singular/plural
wording. In web/src/pages/providers/components/select-type-step.tsx (lines
309-312), replace hardcoded Grok name and description text with the existing t()
calls and corresponding translation keys.
- Around line 119-143: 更新 submit,先完成所有 fileItems/parseImportItemsFromText
项目的本地解析与 normalizeGrokConfig 校验,确认全部有效后再执行写入。优先改用原子批量创建接口,避免循环调用
createProvider.mutateAsync 产生部分持久化;若只能逐项创建,则记录成功与失败结果,并让重试仅提交失败项。
- Around line 105-117: 为文件解析流程增加递增版本号,更新 handleFilesSelected
时使当前版本失效,并仅允许与最新版本匹配的 parseImportItemsFromFiles 结果写入 fileItems 或 setError;在 JSON
文本编辑处理器中同样递增版本号,使文件读取完成后不能覆盖用户最新输入。
- Around line 196-198: Update the Cancel Button in the token import form to be
disabled while submitting, preventing navigation during the active import
request. Preserve its existing navigation behavior when submitting is false.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1381d73a-0668-4ac5-a6aa-63d96feabef4

📥 Commits

Reviewing files that changed from the base of the PR and between ae0ada8 and c184e7a.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (15)
  • cmd/maxx/main.go
  • go.mod
  • internal/adapter/provider/cliproxyapi_grok/adapter.go
  • internal/adapter/provider/cliproxyapi_grok/adapter_test.go
  • internal/adapter/provider/grok/adapter.go
  • internal/core/database.go
  • internal/domain/model.go
  • web/src/index.css
  • web/src/lib/theme.ts
  • web/src/lib/transport/types.ts
  • web/src/pages/providers/components/grok-token-import.tsx
  • web/src/pages/providers/components/select-type-step.tsx
  • web/src/pages/providers/create-layout.tsx
  • web/src/pages/providers/hooks/use-provider-navigation.ts
  • web/src/pages/providers/types.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: playwright
  • GitHub Check: multiinstance
  • GitHub Check: e2e
🔇 Additional comments (15)
internal/domain/model.go (1)

309-330: LGTM!

Also applies to: 341-341

web/src/lib/transport/types.ts (1)

117-137: LGTM!

Also applies to: 171-171

web/src/lib/theme.ts (1)

24-25: LGTM!

web/src/pages/providers/types.ts (1)

4-4: LGTM!

Also applies to: 17-17, 86-93, 301-301

web/src/index.css (1)

6-11: LGTM!

Also applies to: 13-17, 100-100, 387-387

internal/adapter/provider/cliproxyapi_grok/adapter_test.go (1)

9-56: LGTM!

web/src/pages/providers/components/grok-token-import.tsx (1)

1-104: LGTM!

Also applies to: 145-156, 199-202

web/src/pages/providers/components/select-type-step.tsx (1)

12-12: LGTM!

Also applies to: 32-50, 293-308, 313-322

web/src/pages/providers/create-layout.tsx (1)

7-7: LGTM!

Also applies to: 24-24

web/src/pages/providers/hooks/use-provider-navigation.ts (1)

15-15: LGTM!

internal/adapter/provider/grok/adapter.go (1)

1-15: LGTM!

internal/core/database.go (1)

17-17: LGTM!

cmd/maxx/main.go (1)

22-22: LGTM!

go.mod (2)

53-53: LGTM!


126-126: 🎯 Functional Correctness

请确认这个 replace 目标的模块路径与 github.com/router-for-me/CLIProxyAPI/v7 保持一致,并且包含 Grok 适配器依赖的 sdk/exec 入口;否则依赖解析或构建会失败。

Comment on lines +156 to +163
func updateModelInBody(body []byte, model string) ([]byte, error) {
var req map[string]any
if err := json.Unmarshal(body, &req); err != nil {
return nil, err
}
req["model"] = model
return json.Marshal(req)
}

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

避免 json.Unmarshal 导致的数字精度丢失和 HTML 字符转义。

使用 json.Unmarshal 解析到 map[string]any 时,会将所有数字转换为 float64,可能导致请求体中较大的整数参数(如 seed)丢失精度或格式被改变。同时,默认的 json.Marshal 会转义 HTML 字符。建议使用带有 UseNumber()json.Decoder 以及禁用 HTML 转义的 json.Encoder 进行重写,以确保负载数据的完整性。

🐛 修复建议
 func updateModelInBody(body []byte, model string) ([]byte, error) {
 	var req map[string]any
-	if err := json.Unmarshal(body, &req); err != nil {
+	dec := json.NewDecoder(bytes.NewReader(body))
+	dec.UseNumber()
+	if err := dec.Decode(&req); err != nil {
 		return nil, err
 	}
 	req["model"] = model
-	return json.Marshal(req)
+
+	var buf bytes.Buffer
+	enc := json.NewEncoder(&buf)
+	enc.SetEscapeHTML(false)
+	if err := enc.Encode(req); err != nil {
+		return nil, err
+	}
+	return buf.Bytes(), nil
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func updateModelInBody(body []byte, model string) ([]byte, error) {
var req map[string]any
if err := json.Unmarshal(body, &req); err != nil {
return nil, err
}
req["model"] = model
return json.Marshal(req)
}
func updateModelInBody(body []byte, model string) ([]byte, error) {
var req map[string]any
dec := json.NewDecoder(bytes.NewReader(body))
dec.UseNumber()
if err := dec.Decode(&req); err != nil {
return nil, err
}
req["model"] = model
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
enc.SetEscapeHTML(false)
if err := enc.Encode(req); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/adapter/provider/cliproxyapi_grok/adapter.go` around lines 156 -
163, Update updateModelInBody to parse the request with a json.Decoder
configured with UseNumber(), preserving integer values and their original
numeric representation. Serialize the updated payload with a json.Encoder
configured to disable HTML escaping, while retaining the existing error
propagation and model replacement behavior.

Comment on lines +224 to +227
sseBuffer.Write(chunk.Payload)
_, _ = w.Write(chunk.Payload)
flusher.Flush()
if !firstChunkSent && eventChan != nil {

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

检查 w.Write 的返回值以处理客户端断开连接的情况。

目前忽略了 w.Write 的错误返回值。如果客户端在流式传输过程中断开连接,代理会继续读取上游的流并尝试写入已关闭的连接,造成无谓的资源消耗。建议检查错误并在写入失败时及时退出循环。

🐛 修复建议
 		if len(chunk.Payload) > 0 {
 			sseBuffer.Write(chunk.Payload)
-			_, _ = w.Write(chunk.Payload)
+			if _, err := w.Write(chunk.Payload); err != nil {
+				break
+			}
 			flusher.Flush()
 			if !firstChunkSent && eventChan != nil {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sseBuffer.Write(chunk.Payload)
_, _ = w.Write(chunk.Payload)
flusher.Flush()
if !firstChunkSent && eventChan != nil {
sseBuffer.Write(chunk.Payload)
if _, err := w.Write(chunk.Payload); err != nil {
break
}
flusher.Flush()
if !firstChunkSent && eventChan != nil {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/adapter/provider/cliproxyapi_grok/adapter.go` around lines 224 -
227, 在流式响应处理逻辑中更新 w.Write
调用,检查其返回的错误;当写入失败(例如客户端断开连接)时立即退出当前上游读取循环,避免继续处理和写入后续数据。保留成功写入后的 flusher.Flush
及首个分块处理逻辑不变。

Comment thread web/src/pages/providers/components/grok-token-import.tsx
Comment on lines +119 to +143
const submit = async () => {
setError(null);
setSubmitting(true);
try {
const items = fileItems.length > 0 ? fileItems : parseImportItemsFromText(jsonText);
if (items.length === 0) {
throw new Error('Paste JSON or select one or more JSON files');
}
for (const item of items) {
const grok = normalizeGrokConfig(item.raw);
const data: CreateProviderData = {
type: 'grok',
name: providerName(grok, item.source),
config: { grok },
supportedClientTypes: ['openai'],
};
await createProvider.mutateAsync(data);
}
navigate('/providers');
} catch (err) {
setError(err instanceof Error ? err.message : String(err));
} finally {
setSubmitting(false);
}
};

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.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

避免批量导入留下半完成状态。

第 N 项创建失败时,前 N-1 项已持久化,但界面仅显示错误;用户重试会再次提交全部项目。应优先使用原子批量接口,或记录逐项结果并仅重试失败项,同时在首次写入前完成全部本地校验。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/pages/providers/components/grok-token-import.tsx` around lines 119 -
143, 更新 submit,先完成所有 fileItems/parseImportItemsFromText 项目的本地解析与
normalizeGrokConfig 校验,确认全部有效后再执行写入。优先改用原子批量创建接口,避免循环调用
createProvider.mutateAsync 产生部分持久化;若只能逐项创建,则记录成功与失败结果,并让重试仅提交失败项。

Comment thread web/src/pages/providers/components/grok-token-import.tsx Outdated
Comment on lines +180 to +191
<Textarea
value={jsonText}
onChange={(event) => {
setJsonText(event.target.value);
if (event.target.value.trim()) {
setFileItems([]);
}
}}
placeholder='{"type":"xai","auth_kind":"oauth",...}'
className="min-h-80 font-mono text-xs"
/>
{error && <div className="rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive">{error}</div>}

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

为 JSON 文本框和错误消息补充可访问语义。

占位符不能替代可访问名称。请为 Textarea 添加关联的 label,并为错误容器添加 role="alert"aria-live

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/pages/providers/components/grok-token-import.tsx` around lines 180 -
191, 为包含 jsonText 的 Textarea 添加可访问名称,并通过关联的 label 让其具备明确语义;同时更新 error
条件渲染的错误容器,加入 role="alert" 或等效的 aria-live 属性。保持现有输入处理和错误展示内容不变。

Comment on lines +196 to +198
<Button type="button" variant="outline" onClick={() => navigate('/providers/create')}>
Cancel
</Button>

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

提交期间禁用“取消”,或真正中止导入。

当前点击取消只会导航离开;后台创建仍会继续,成功后还会再次导航到 /providers。至少应在 submitting 时禁用按钮。

建议修改
-<Button type="button" variant="outline" onClick={() => navigate('/providers/create')}>
+<Button
+  type="button"
+  variant="outline"
+  disabled={submitting}
+  onClick={() => navigate('/providers/create')}
+>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Button type="button" variant="outline" onClick={() => navigate('/providers/create')}>
Cancel
</Button>
<Button
type="button"
variant="outline"
disabled={submitting}
onClick={() => navigate('/providers/create')}>
Cancel
</Button>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/pages/providers/components/grok-token-import.tsx` around lines 196 -
198, Update the Cancel Button in the token import form to be disabled while
submitting, preventing navigation during the active import request. Preserve its
existing navigation behavior when submitting is false.

@awsl233777

Copy link
Copy Markdown
Collaborator Author

Validation update for 17247187ee79:

  • pnpm typecheck passed
  • pnpm build passed
  • GitHub checks are passing: Backend, Frontend, e2e, multiinstance, playwright
  • CodeRabbit completed
  • Local E2E covered:
    • admin login
    • Grok JSON create page
    • multi-file CPA xAI JSON selection
    • batch import of 2 Grok providers
    • Provider list display after import
    • OpenAI route creation against the imported Grok provider
    • /v1/chat/completions request through maxx
    • upstream mock receiving /responses
    • 200 response with mock e2e ok

Current known blocker: repository review requirement. The PR author is awsl233777, so this account cannot satisfy the required independent review gate by self-review.

# Conflicts:
#	web/src/pages/providers/components/grok-token-import.tsx
@awsl233777
awsl233777 merged commit 684cf4e into main Jul 15, 2026
3 checks passed
@awsl233777
awsl233777 deleted the feat/grok-cpa-import branch July 15, 2026 08:58
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