feat(providers): add Grok CPA flow and cooldown fallback setting - #678
Conversation
📝 WalkthroughWalkthrough本次变更新增 Grok/XAI OAuth provider 的后端适配器与前端创建、编辑、导出流程,并完善密钥保留与脱敏处理。同时调整 Antigravity 限流解析及默认冷却时间配置。 ChangesGrok 后端适配与限流处理
Grok 前端流程
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant GrokTokenImport
participant ProviderAPI
participant CLIProxyAPIGrokAdapter
participant CLIProxyAPI
Client->>GrokTokenImport: submit XAI OAuth JSON
GrokTokenImport->>ProviderAPI: create Grok provider
ProviderAPI->>CLIProxyAPIGrokAdapter: initialize adapter
CLIProxyAPIGrokAdapter->>CLIProxyAPI: execute OpenAI-compatible request
CLIProxyAPI-->>CLIProxyAPIGrokAdapter: return JSON or SSE
CLIProxyAPIGrokAdapter-->>Client: write response
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (1)
internal/domain/model.go (1)
309-310: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win明确 OAuth 密钥的导出策略。
这里要求密钥在所有
export场景中脱敏,但管理导出测试明确要求保留令牌以支持重新导入。请改为仅禁止自助/UI 响应泄漏,并注明受控管理导出是例外,避免后续按错误安全契约修改实现。🤖 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/domain/model.go` around lines 309 - 310, 更新 ProviderConfigGrok 的安全注释,明确令牌仅在自助服务和 UI 响应中必须脱敏;注明受控管理导出是例外,可保留令牌以支持重新导入,避免将脱敏要求扩大到所有导出场景。
🤖 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 170-176: Update the error mapping used by executeNonStream and its
streaming counterpart to preserve executor status-code semantics: when the
wrapped error contains a status code, map Scope, Reason, Retryable, and
HTTPStatusCode consistently for authentication, quota, and rate-limit responses
instead of always assigning provider/server-error values. Centralize this
mapping in one shared helper and reuse it from both flows.
In `@web/src/pages/providers/components/grok-provider-view.tsx`:
- Around line 48-67: Update the grok submission payload so the trimmed email and
baseURL values use undefined rather than grok?.email or grok?.baseURL when
empty, allowing users to clear these fields while preserving non-empty input
values.
In `@web/src/pages/providers/components/grok-token-import.tsx`:
- Line 289: Update the back navigation in the relevant provider token import
component to wrap the ChevronLeft icon in a focusable Button with an appropriate
aria-label, and move the click handler onto the Button while preserving
navigation to /providers/create.
- Around line 238-266: Update the submit flow around createProvider.mutateAsync
and createModelMapping.mutateAsync so the entire import is atomic: prefer a
backend batch operation that creates all providers and mappings together, or
reliably delete every resource created during this submission when any request
fails. Ensure retries cannot leave partial imports or duplicate providers, while
preserving the existing item and mapping data.
- Around line 150-159: 将 normalizeGrokConfig
中直接面向用户的英文错误改为可本地化的错误码或结构化错误信息,并在导入组件使用 t(...) 将其转换为当前语言后展示;覆盖 type、auth_kind 及
access_token/refresh_token 校验路径,同时保持原有校验条件和失败行为不变。
In `@web/src/pages/providers/components/select-type-step.tsx`:
- Around line 308-313: Replace the hardcoded “Grok” title and “Import xAI OAuth
JSON from CLIProxyAPI” description in the provider card with the file’s existing
t() i18n lookup pattern. Add or reuse the corresponding translation keys while
preserving the card’s current layout and styling.
---
Nitpick comments:
In `@internal/domain/model.go`:
- Around line 309-310: 更新 ProviderConfigGrok 的安全注释,明确令牌仅在自助服务和 UI
响应中必须脱敏;注明受控管理导出是例外,可保留令牌以支持重新导入,避免将脱敏要求扩大到所有导出场景。
🪄 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: 08796aa0-d1e2-44d4-83dd-c10cd3185463
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (27)
cmd/maxx/main.gogo.modinternal/adapter/provider/antigravity/adapter.gointernal/adapter/provider/antigravity/rate_limit_info_test.gointernal/adapter/provider/cliproxyapi_grok/adapter.gointernal/adapter/provider/cliproxyapi_grok/adapter_test.gointernal/adapter/provider/grok/adapter.gointernal/core/database.gointernal/domain/model.gointernal/executor/cooldown_default_test.gointernal/executor/executor.gointernal/handler/self_service.gointernal/service/admin.gointernal/service/system_setting_validation.gotests/e2e/grok_provider_test.goweb/src/index.cssweb/src/lib/theme.tsweb/src/lib/transport/types.tsweb/src/locales/en.jsonweb/src/locales/zh.jsonweb/src/pages/providers/components/grok-provider-view.tsxweb/src/pages/providers/components/grok-token-import.tsxweb/src/pages/providers/components/provider-edit-flow.tsxweb/src/pages/providers/components/select-type-step.tsxweb/src/pages/providers/create-layout.tsxweb/src/pages/providers/hooks/use-provider-navigation.tsweb/src/pages/providers/types.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
- GitHub Check: multiinstance
- GitHub Check: playwright
- GitHub Check: e2e
🔇 Additional comments (27)
internal/adapter/provider/antigravity/adapter.go (1)
1190-1198: LGTM!Also applies to: 1236-1236, 1261-1261
internal/executor/executor.go (1)
262-273: LGTM!Also applies to: 297-314
internal/service/system_setting_validation.go (1)
5-5: LGTM!Also applies to: 19-37
internal/adapter/provider/antigravity/rate_limit_info_test.go (1)
1-151: LGTM!internal/executor/cooldown_default_test.go (1)
1-109: LGTM!web/src/lib/transport/types.ts (1)
117-137: LGTM!Also applies to: 171-171
web/src/index.css (1)
100-100: LGTM!Also applies to: 387-387
web/src/locales/en.json (1)
1881-1900: LGTM!web/src/locales/zh.json (1)
1877-1896: LGTM!web/src/pages/providers/components/grok-token-import.tsx (1)
1-149: LGTM!Also applies to: 160-237, 277-288, 290-405
web/src/pages/providers/create-layout.tsx (1)
7-7: LGTM!Also applies to: 24-24
web/src/lib/theme.ts (1)
24-25: LGTM!web/src/pages/providers/types.ts (1)
86-93: LGTM!web/src/pages/providers/hooks/use-provider-navigation.ts (1)
15-15: LGTM!web/src/pages/providers/components/provider-edit-flow.tsx (1)
671-690: LGTM!internal/domain/model.go (1)
311-329: LGTM!Also applies to: 341-341, 852-852
internal/adapter/provider/cliproxyapi_grok/adapter.go (2)
1-163: LGTM!Also applies to: 165-169, 178-190, 209-241, 248-277
193-197: 🎯 Functional Correctness这里不需要强制报错。
Flusher不可用时回退到executeNonStream与internal/adapter/provider/cliproxyapi_codex/adapter.go的处理一致;此路径会走Execute并按普通 JSON 返回,不会继续按 SSE 流式写出。> Likely an incorrect or invalid review comment.internal/adapter/provider/cliproxyapi_grok/adapter_test.go (1)
1-56: LGTM!internal/service/admin.go (1)
516-532: LGTM!Also applies to: 1340-1342
tests/e2e/grok_provider_test.go (1)
1-145: LGTM!internal/adapter/provider/grok/adapter.go (1)
9-14: 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请验证新的 CLIProxyAPI 版本与适配器契约兼容。
该
replace实际改变了运行时依赖;请确认目标提交可解析,并验证cliproxyapi_grok使用的 API、模型映射及流式响应行为仍兼容,随后运行对应的定向测试。internal/handler/self_service.go (1)
1471-1477: LGTM!
| resp, err := a.executor.Execute(ctx, a.authObj, execReq, execOpts) | ||
| if err != nil { | ||
| log.Printf("[CLIProxyAPI-Grok] executeNonStream error: model=%s, err=%v", execReq.Model, err) | ||
| proxyErr := domain.NewProxyErrorWithMessage(err, true, fmt.Sprintf("executor request failed: %v", err)) | ||
| proxyErr.Scope = domain.ScopeProvider | ||
| proxyErr.Reason = domain.CooldownReasonServerError | ||
| return proxyErr |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 查找项目已有的状态码和冷却原因映射实现。
rg -n -C5 --type go 'StatusCode\(\)|CooldownReason|errors\.As\(' internalRepository: awsl-project/maxx
Length of output: 50374
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== adapter outline =="
ast-grep outline internal/adapter/provider/cliproxyapi_grok/adapter.go --view expanded || true
echo
echo "== adapter snippets around the relevant lines =="
sed -n '140,230p' internal/adapter/provider/cliproxyapi_grok/adapter.go | cat -n
echo
echo "== executor error type references =="
sed -n '1,260p' internal/executor/types.go 2>/dev/null | cat -n || true
echo
echo "== search for executor.StatusError and status mapping =="
rg -n -C4 'type .*StatusError|StatusError|HTTPStatus|StatusCode|status code|CooldownReasonAuthFailure|CooldownReasonRateLimitExceeded|CooldownReasonQuotaExhausted' internal/executor internal/adapter/provider/cliproxyapi_grok internal/domainRepository: awsl-project/maxx
Length of output: 25546
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== executor interface / error types =="
rg -n -C4 'type .*Executor|type .*StatusError|HTTPStatusCode|StatusError|Upstream.*Error|CooldownReasonAuthFailure|CooldownReasonRateLimitExceeded|CooldownReasonQuotaExhausted' internal/executor internal/adapter/provider/cliproxyapi_grok | sed -n '1,260p'
echo
echo "== cliproxyapi_grok stream path snippet =="
sed -n '193,250p' internal/adapter/provider/cliproxyapi_grok/adapter.go | cat -n
echo
echo "== domain ProxyError fields and helpers =="
sed -n '55,130p' internal/domain/errors.go | cat -nRepository: awsl-project/maxx
Length of output: 12029
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== cliproxyapi_grok imports and surrounding logic =="
sed -n '1,120p' internal/adapter/provider/cliproxyapi_grok/adapter.go | cat -n
echo
echo "== executor package API surface =="
sed -n '1,220p' internal/executor/types.go 2>/dev/null | cat -n || true
sed -n '1,220p' internal/executor/executor.go | cat -n | sed -n '1,220p'
echo
echo "== search for 401/402/429 handling and StatusError across repo =="
rg -n -C3 '401|402|429|StatusError|HTTPStatusCode|errors\.As\(' internal | sed -n '1,260p'Repository: awsl-project/maxx
Length of output: 30074
🌐 Web query:
router-for-me/CLIProxyAPI sdk/cliproxy/executor/types.go StatusError HTTPStatusCode 401 402 429
💡 Result:
In the router-for-me/CLIProxyAPI project, StatusError is an interface defined within the sdk/cliproxy/executor package [1]. It requires types to implement an error method and a StatusCode method that returns an integer [1]. While StatusError itself is a generic interface, the CLIProxyAPI system uses it to handle specific HTTP status codes during execution and authentication workflows [2][3][4][5]. The status codes 401, 402, and 429 are frequently handled in the following ways: - 401 Unauthorized: Triggers an update to authentication state, often marking it as unauthorized and initiating a cooling-off period (e.g., 30 minutes) before the model can be retried [2][3]. - 402 Payment Required: Treated similarly to 401, this indicates billing issues and typically sets a "payment_required" status and a retry delay [2][3]. - 429 Too Many Requests: Indicates that quota has been exhausted; the system sets the status to "quota exhausted," marks the quota as exceeded, and calculates a recovery time [2][3]. These codes are checked by casting errors to the StatusError interface (or an anonymous interface with a StatusCode method) to decide how to manage backoff, model suspension, and quota tracking [2][3][4][5].
Citations:
- 1: https://pkg.go.dev/github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/executor
- 2: https://github.com/router-for-me/CLIProxyAPIPlus/commit/ab55373bc58a09482855869cca2b796c8ccdc4bc
- 3: https://github.com/router-for-me/CLIProxyAPIPlus/commit/6a27bceec0ab04aea3a34cca182f92efc0a3291d
- 4: https://github.com/router-for-me/CLIProxyAPI/blob/5afc0f1d/sdk/cliproxy/auth/conductor.go
- 5: https://github.com/router-for-me/CLIProxyAPI/blob/5b7f2361/internal/api/server.go
保留 executor 的状态码语义。
这里把所有错误都归为 ScopeProvider + CooldownReasonServerError,会丢掉 401/402/429 的鉴权、配额和限流语义。若底层错误链里带状态码,就在同一个 helper 里统一映射 Scope / Reason / Retryable / HTTPStatusCode,让流式和非流式共用。
🤖 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 170 -
176, Update the error mapping used by executeNonStream and its streaming
counterpart to preserve executor status-code semantics: when the wrapped error
contains a status code, map Scope, Reason, Retryable, and HTTPStatusCode
consistently for authentication, quota, and rate-limit responses instead of
always assigning provider/server-error values. Centralize this mapping in one
shared helper and reuse it from both flows.
| grok: { | ||
| type: 'xai', | ||
| authKind: 'oauth', | ||
| email: email.trim() || grok?.email, | ||
| sub: grok?.sub, | ||
| // Blank/omitted secrets preserve the stored tokens on the backend. | ||
| accessToken: '', | ||
| refreshToken: '', | ||
| idToken: '', | ||
| tokenType: grok?.tokenType, | ||
| expiresIn: grok?.expiresIn, | ||
| expired: grok?.expired, | ||
| lastRefresh: grok?.lastRefresh, | ||
| redirectURI: grok?.redirectURI, | ||
| tokenEndpoint: grok?.tokenEndpoint, | ||
| baseURL: baseURL.trim() || grok?.baseURL, | ||
| disabled: grok?.disabled, | ||
| headers: grok?.headers, | ||
| }, | ||
| }, |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
修复回退逻辑,允许用户清空字段。
因为状态 email 和 baseURL 已使用旧值进行了初始化,在提交表单时,如果用户故意将这些输入框清空,email.trim() 将返回 "",紧随其后的 || grok?.email 会导致原有的非空旧值被重新赋上。这会导致用户无法成功清空这些配置项。
建议将回退逻辑修改为 || undefined,以便正确处理清空操作并向后端发送 undefined 从而抹去相应配置。
🐛 建议的修复
grok: {
type: 'xai',
authKind: 'oauth',
- email: email.trim() || grok?.email,
+ email: email.trim() || undefined,
sub: grok?.sub,
// Blank/omitted secrets preserve the stored tokens on the backend.
accessToken: '',
refreshToken: '',
idToken: '',
tokenType: grok?.tokenType,
expiresIn: grok?.expiresIn,
expired: grok?.expired,
lastRefresh: grok?.lastRefresh,
redirectURI: grok?.redirectURI,
tokenEndpoint: grok?.tokenEndpoint,
- baseURL: baseURL.trim() || grok?.baseURL,
+ baseURL: baseURL.trim() || undefined,
disabled: grok?.disabled,
headers: grok?.headers,
},📝 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.
| grok: { | |
| type: 'xai', | |
| authKind: 'oauth', | |
| email: email.trim() || grok?.email, | |
| sub: grok?.sub, | |
| // Blank/omitted secrets preserve the stored tokens on the backend. | |
| accessToken: '', | |
| refreshToken: '', | |
| idToken: '', | |
| tokenType: grok?.tokenType, | |
| expiresIn: grok?.expiresIn, | |
| expired: grok?.expired, | |
| lastRefresh: grok?.lastRefresh, | |
| redirectURI: grok?.redirectURI, | |
| tokenEndpoint: grok?.tokenEndpoint, | |
| baseURL: baseURL.trim() || grok?.baseURL, | |
| disabled: grok?.disabled, | |
| headers: grok?.headers, | |
| }, | |
| }, | |
| grok: { | |
| type: 'xai', | |
| authKind: 'oauth', | |
| email: email.trim() || undefined, | |
| sub: grok?.sub, | |
| // Blank/omitted secrets preserve the stored tokens on the backend. | |
| accessToken: '', | |
| refreshToken: '', | |
| idToken: '', | |
| tokenType: grok?.tokenType, | |
| expiresIn: grok?.expiresIn, | |
| expired: grok?.expired, | |
| lastRefresh: grok?.lastRefresh, | |
| redirectURI: grok?.redirectURI, | |
| tokenEndpoint: grok?.tokenEndpoint, | |
| baseURL: baseURL.trim() || undefined, | |
| disabled: grok?.disabled, | |
| headers: grok?.headers, | |
| }, | |
| }, |
🤖 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-provider-view.tsx` around lines 48 -
67, Update the grok submission payload so the trimmed email and baseURL values
use undefined rather than grok?.email or grok?.baseURL when empty, allowing
users to clear these fields while preserving non-empty input values.
| function normalizeGrokConfig(raw: CPAxAIExportJSON): ProviderConfigGrok { | ||
| if (raw.type !== 'xai') { | ||
| throw new Error(`Expected CPA xai credential JSON, got type=${raw.type || '(empty)'}`); | ||
| } | ||
| if ((raw.auth_kind || 'oauth') !== 'oauth') { | ||
| throw new Error(`Expected oauth credential JSON, got auth_kind=${raw.auth_kind || '(empty)'}`); | ||
| } | ||
| if (!raw.access_token && !raw.refresh_token) { | ||
| throw new Error('access_token or refresh_token is required'); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
将导入错误信息纳入本地化。
这些错误会直接展示给用户,但目前固定为英文,中文界面会出现混合语言。请抛出错误码并在组件中通过 t(...) 转换,或向校验函数传入本地化文案。
Also applies to: 243-244
🤖 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 150 -
159, 将 normalizeGrokConfig 中直接面向用户的英文错误改为可本地化的错误码或结构化错误信息,并在导入组件使用 t(...)
将其转换为当前语言后展示;覆盖 type、auth_kind 及 access_token/refresh_token
校验路径,同时保持原有校验条件和失败行为不变。
| const submit = async () => { | ||
| setError(null); | ||
| setSaveStatus('idle'); | ||
| setSubmitting(true); | ||
| try { | ||
| const items = fileItems.length > 0 ? fileItems : parseImportItemsFromText(jsonText); | ||
| if (items.length === 0) throw new Error('Paste JSON or select files'); | ||
|
|
||
| const mappingEntries = Object.entries(modelMapping); | ||
| for (const item of items) { | ||
| const grok = normalizeGrokConfig(item.raw); | ||
| const data: CreateProviderData = { | ||
| type: 'grok', | ||
| name: providerName(grok, item.source), | ||
| config: { disableErrorCooldown, grok }, | ||
| supportedClientTypes: [...GROK_CLIENT_TYPES], | ||
| excludeFromExport: blackBox, | ||
| blackBox, | ||
| }; | ||
| const provider = await createProvider.mutateAsync(data); | ||
| for (const [pattern, target] of mappingEntries) { | ||
| await createModelMapping.mutateAsync({ | ||
| scope: 'provider', | ||
| providerID: provider.id, | ||
| pattern, | ||
| target, | ||
| }); | ||
| } | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
避免失败后留下部分导入结果。
Provider 创建和模型映射是多个独立写请求。任意后续请求失败时,已创建的 Provider/映射仍会保留;用户重试还可能生成重复 Provider。请使用后端原子批量接口,或在失败时可靠回滚本次已创建的资源。
🤖 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 238 -
266, Update the submit flow around createProvider.mutateAsync and
createModelMapping.mutateAsync so the entire import is atomic: prefer a backend
batch operation that creates all providers and mappings together, or reliably
delete every resource created during this submission when any request fails.
Ensure retries cannot leave partial imports or duplicate providers, while
preserving the existing item and mapping data.
| return ( | ||
| <div className="flex h-full flex-col"> | ||
| <PageHeader | ||
| icon={<ChevronLeft className="cursor-pointer" onClick={() => navigate('/providers/create')} />} |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
将返回操作改为可聚焦的按钮。
点击事件直接绑定在 SVG 上,键盘用户无法聚焦或触发该操作。请使用带 aria-label 的 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` at line 289, Update
the back navigation in the relevant provider token import component to wrap the
ChevronLeft icon in a focusable Button with an appropriate aria-label, and move
the click handler onto the Button while preserving navigation to
/providers/create.
| <div className="flex-1 min-w-0 space-y-1"> | ||
| <h3 className="text-sm sm:text-base font-semibold text-foreground leading-tight truncate">Grok</h3> | ||
| <p className="text-xs sm:text-sm text-muted-foreground leading-relaxed line-clamp-2"> | ||
| Import xAI OAuth JSON from CLIProxyAPI | ||
| </p> | ||
| </div> |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
使用 i18n 函数替换硬编码的文本。
当前卡片的标题和描述被硬编码为英文,这会破坏界面的国际化支持。建议统一使用 t() 函数来获取多语言文本(与文件中其他 Provider 卡片保持一致)。
♻️ 建议的代码修改
<div className="flex-1 min-w-0 space-y-1">
- <h3 className="text-sm sm:text-base font-semibold text-foreground leading-tight truncate">Grok</h3>
- <p className="text-xs sm:text-sm text-muted-foreground leading-relaxed line-clamp-2">
- Import xAI OAuth JSON from CLIProxyAPI
- </p>
+ <h3 className="text-sm sm:text-base font-semibold text-foreground leading-tight truncate">
+ {t('addProvider.grok.name', 'Grok')}
+ </h3>
+ <p className="text-xs sm:text-sm text-muted-foreground leading-relaxed line-clamp-2">
+ {t('addProvider.grok.description', 'Import xAI OAuth JSON from CLIProxyAPI')}
+ </p>
</div>📝 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.
| <div className="flex-1 min-w-0 space-y-1"> | |
| <h3 className="text-sm sm:text-base font-semibold text-foreground leading-tight truncate">Grok</h3> | |
| <p className="text-xs sm:text-sm text-muted-foreground leading-relaxed line-clamp-2"> | |
| Import xAI OAuth JSON from CLIProxyAPI | |
| </p> | |
| </div> | |
| <div className="flex-1 min-w-0 space-y-1"> | |
| <h3 className="text-sm sm:text-base font-semibold text-foreground leading-tight truncate"> | |
| {t('addProvider.grok.name', 'Grok')} | |
| </h3> | |
| <p className="text-xs sm:text-sm text-muted-foreground leading-relaxed line-clamp-2"> | |
| {t('addProvider.grok.description', 'Import xAI OAuth JSON from CLIProxyAPI')} | |
| </p> | |
| </div> |
🤖 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/select-type-step.tsx` around lines 308 -
313, Replace the hardcoded “Grok” title and “Import xAI OAuth JSON from
CLIProxyAPI” description in the provider card with the file’s existing t() i18n
lookup pattern. Add or reuse the corresponding translation keys while preserving
the card’s current layout and styling.
Summary
Cooldown fallback scope
ReasonRateLimitandReasonConcurrentLimitwhen no upstream retry/cooldown time is providedinternal/cooldown/policy.godefault 5s policy intact and applies the setting in executor handling only for the targeted fallback pathValidation
go test ./internal/adapter/provider/antigravity ./internal/executor ./internal/cooldown ./internal/handler ./internal/serviceSummary by CodeRabbit
新功能
问题修复