Skip to content

feat: add Claude provider frontend support#292

Merged
ymkiux merged 2 commits intomainfrom
feat/claude-provider-frontend
Mar 2, 2026
Merged

feat: add Claude provider frontend support#292
ymkiux merged 2 commits intomainfrom
feat/claude-provider-frontend

Conversation

@Bowl42
Copy link
Collaborator

@Bowl42 Bowl42 commented Mar 2, 2026

Summary

  • Add full frontend support for the claude provider type, complementing the backend OAuth/adapter added in PR feat: add Claude provider adapter with OAuth support #291
  • Users can now create Claude providers via OAuth login or manual refresh token import, and view/manage them in the providers UI
  • Follows the exact same patterns used by the Codex provider (16 files changed, 2 new components)

Changes

  • Theme/CSS: Added claude to ProviderType, --provider-claude CSS variable (coral color)
  • Transport layer: ProviderConfigClaude, ClaudeTokenValidationResult, ClaudeOAuthResult types; 4 API methods (validateClaudeToken, startClaudeOAuth, exchangeClaudeOAuthCallback, refreshClaudeProviderInfo) with HTTP implementations calling /api/claude/*
  • Provider config: Registered claude in PROVIDER_TYPE_CONFIGS (icon: Sparkles, account-based), navigation, routing
  • New components: ClaudeTokenImport (OAuth + token import), ClaudeProviderView (detail view with email, org ID, token expiry, model mappings, error cooldown)
  • i18n: Full English and Chinese translations for all Claude provider strings

Test plan

  • Navigate to Providers → Add Provider, verify Claude option appears with Sparkles icon
  • Test OAuth login flow (popup window, callback handling, WebSocket result)
  • Test manual token import flow (paste token, validate, create provider)
  • Test viewing/editing an existing Claude provider (refresh, model mappings, error cooldown toggle, delete)
  • Verify TypeScript build passes (tsc --noEmit + vite build)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • 新功能
    • 新增 Claude AI 供应商集成,支持 OAuth 登录与手动 Token 导入两种接入方式
    • 添加 Claude 提供商管理界面:账户详情、Token 操作(复制/验证/刷新)、删除及错误提示
    • 增强模型映射管理:查看、添加、编辑、删除及优先级处理
    • 将 Claude 纳入创建流程、选择页与导航路由,并补充中/英本地化文本与主题配色支持

Add full frontend support for the Claude provider type, complementing
the backend added in PR #291. Users can now create, view, and manage
Claude providers through the UI with OAuth login and manual token import.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Mar 2, 2026

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

📥 Commits

Reviewing files that changed from the base of the PR and between 72e65ff and acd46d5.

📒 Files selected for processing (3)
  • web/src/lib/theme.ts
  • web/src/pages/providers/components/claude-provider-view.tsx
  • web/src/pages/providers/components/claude-token-import.tsx
 __________________________________________________________________________________________________________________________________
< Functions delay binding; data structures induce binding. Moral: Structure data late in the programming process. - Alan J. Perlis >
 ----------------------------------------------------------------------------------------------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).

✏️ Tip: You can disable in-progress messages and the fortune message in your review settings.

Tip

CodeRabbit can generate a title for your PR based on the changes.

Add @coderabbitai placeholder anywhere in the title of your PR and CodeRabbit will replace it with a title based on the changes in the PR. You can change the placeholder by changing the reviews.auto_title_placeholder setting.

📝 Walkthrough

概述

该PR为应用添加了完整的Claude提供商支持,包括CSS变量、TypeScript类型定义、HTTP传输层集成、UI组件和国际化配置。支持Claude通过OAuth和令牌验证流程进行身份验证。

变更

内聚组 / 文件 摘要
样式和主题配置
web/src/index.css, web/src/lib/theme.ts, web/src/pages/providers/types.ts
添加Claude提供商CSS变量、更新ProviderType类型定义、扩展PROVIDER_TYPE_CONFIGS以包含Claude配置项和相关图标/颜色。
传输层集成
web/src/lib/transport/http-transport.ts, web/src/lib/transport/interface.ts, web/src/lib/transport/index.ts, web/src/lib/transport/types.ts
为HttpTransport类和Transport接口添加四个Claude OAuth/令牌相关方法;定义ProviderConfigClaude、ClaudeTokenValidationResult和ClaudeOAuthResult类型;扩展ProviderConfig和WebSocket消息类型。注意:http-transport.ts中存在四个Claude方法的重复定义。
国际化支持
web/src/locales/en.json, web/src/locales/zh.json
添加claudeType、claudeAccountDetails、organizationId和完整的claudeTokenImport工作流配置(包含OAuth、令牌导入、错误处理和验证消息的多语言文本);在addProvider模板中引入Claude。
Claude提供商UI组件
web/src/pages/providers/components/claude-provider-view.tsx
新增ClaudeProviderView React组件,用于显示Claude提供商详情,包括email、organization ID、刷新令牌复制功能和ProviderModelMappings嵌套组件(用于编辑和管理模型映射)。
Claude令牌导入流程
web/src/pages/providers/components/claude-token-import.tsx
新增ClaudeTokenImport组件,支持OAuth(弹窗登录、手动回调URL交换)和令牌导入两种模式,包含WebSocket事件订阅、令牌验证、提供商创建和完整的错误处理。
路由和导航集成
web/src/pages/providers/create-layout.tsx, web/src/pages/providers/hooks/use-provider-navigation.ts, web/src/pages/providers/components/provider-edit-flow.tsx, web/src/pages/providers/components/select-type-step.tsx, web/src/pages/providers/index.tsx
添加Claude路由(/providers/create/claude)、导航助手(goToClaude)、提供商编辑流程分支、提供商类型选择UI卡片,以及提供商分组初始化支持。

Sequence Diagram(s)

sequenceDiagram
    participant User as 用户
    participant UI as ClaudeTokenImport
    participant Backend as 后端
    participant OAuth as Claude OAuth
    participant WS as WebSocket
    participant DB as 数据库

    rect rgba(100, 150, 200, 0.5)
    Note over User,DB: OAuth流程
    User->>UI: 点击"使用Anthropic登录"
    UI->>Backend: startClaudeOAuth()
    Backend->>Backend: 生成state、获取authURL
    Backend-->>UI: { authURL, state }
    UI->>UI: 打开弹窗窗口
    UI->>OAuth: 重定向至authURL
    User->>OAuth: 在Claude OAuth界面登录
    OAuth->>Backend: 重定向回调URL(code, state)
    User->>UI: 输入回调URL (或自动捕获)
    UI->>Backend: exchangeClaudeOAuthCallback(code, state)
    Backend->>OAuth: 交换获取令牌
    Backend->>DB: 创建提供商
    Backend-->>UI: ClaudeOAuthResult
    UI->>WS: 订阅claude_oauth_result
    WS-->>UI: 事件到达(state匹配)
    UI->>UI: 关闭弹窗、显示成功
    end

    rect rgba(150, 100, 200, 0.5)
    Note over User,DB: 令牌导入流程
    User->>UI: 切换至"令牌导入"标签
    User->>UI: 粘贴refreshToken、输入email
    UI->>Backend: validateClaudeToken(refreshToken)
    Backend->>Backend: 验证令牌有效性
    Backend-->>UI: ClaudeTokenValidationResult
    UI->>UI: 显示验证结果
    User->>UI: 点击"创建提供商"
    UI->>Backend: 使用验证数据创建提供商
    Backend->>DB: 保存提供商配置
    Backend-->>UI: 创建成功
    UI->>UI: 导航至提供商列表
    end
Loading

估计代码审查工作量

🎯 3 (中等) | ⏱️ ~25 分钟

可能相关的PR

建议标签

Review effort 3/5

建议审查者

  • whhjdi
  • awsl233777
  • liril-net

诗歌

🐰 Claude来了带着OAuth的光,
令牌验证和模型映射响当当,
WebSocket订阅接住回调信号,
国际化文本用多种语言唱,
提供商列表又添新的希望!✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add Claude provider frontend support' is clear, specific, and accurately describes the main change—adding comprehensive frontend support for a new Claude provider type.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/claude-provider-frontend

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/src/lib/theme.ts`:
- Around line 21-22: ProviderType 已新增 'claude' 但函数 getProviderDisplayName
未为该枚举值提供映射导致回退显示原始类型字符串;在 getProviderDisplayName 中为 ProviderType 'claude'
添加合适的显示名映射(例如 "Claude" 或团队命名约定的全称),确保返回值与其他 provider 的显示一致,保持 UI 文案统一并避免显示原始
type 文本。

In `@web/src/pages/providers/components/claude-provider-view.tsx`:
- Around line 150-163: The ModelInput fields (pattern/target) currently call
handleUpdateMapping on every keystroke, causing request storms and out-of-order
writes; change them to edit locally and only call handleUpdateMapping when the
user blurs or explicitly saves (or at minimum debounce input and serialize
requests). Concretely: keep a local component state for mapping edits tied to
the ModelInput value, update that state onChange, and invoke
handleUpdateMapping(mapping, {...}) only on onBlur or save; if you add debounce,
ensure the debounced updater serializes requests (e.g., by awaiting previous
update or cancelling prior promises) and respect isPending to prevent
overlapping writes.
- Around line 303-307: Replace the invalid inline CSS backgroundColor:
`${CLAUDE_COLOR}15` (where CLAUDE_COLOR equals "var(--provider-claude)") with a
Tailwind arbitrary color class that applies the CSS variable with opacity, e.g.
remove the style prop and add a class like
"bg-[color:var(--provider-claude)]/15" to the same element (the div that wraps
Sparkles in claude-provider-view.tsx); apply the same change for the analogous
element in claude-token-import.tsx so both use the Tailwind arbitrary color +
opacity syntax instead of string-concatenating "15".

In `@web/src/pages/providers/components/claude-token-import.tsx`:
- Around line 303-306: The inline style using backgroundColor:
`${CLAUDE_COLOR}15` produces invalid CSS; locate the two occurrences where
backgroundColor is set using CLAUDE_COLOR (the JSX around the Sparkles icon in
claude-token-import) and either (A) add the missing Tailwind CSS utility
definitions for provider-claude (and the other missing providers: claude,
antigravity, kiro, codex) in the same style sheet where other provider
backgrounds are defined so you can use a utility like bg-provider-claude/15, or
(B) replace the invalid template with valid CSS that uses the CSS variable
correctly (for example use an rgb/from var(...) with alpha or compute rgba from
the CSS var) so backgroundColor becomes a valid color string; ensure both
occurrences are updated consistently.
- Around line 168-180: The code opens an OAuth popup with oauthWindowRef.current
= window.open(...) and then starts a setInterval stored in checkWindowClosed
without checking for a null popup or ensuring the interval is cleared on all
exit paths; update the logic in the component (around oauthWindowRef usage and
the checkWindowClosed interval) to first test if window.open returned a non-null
value and handle the popup-blocked case (e.g., setPopupClosed(true) or surface
an error), store the interval id in a ref or state (not a local var) so it can
be cleared reliably, and ensure you clearInterval(checkWindowClosed) whenever
the popup is detected closed, on component unmount, and when you manually close
the popup; reference oauthWindowRef, checkWindowClosed (or convert to
checkWindowClosedRef), and setPopupClosed to implement these changes.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 393c28f and 72e65ff.

📒 Files selected for processing (16)
  • web/src/index.css
  • web/src/lib/theme.ts
  • web/src/lib/transport/http-transport.ts
  • web/src/lib/transport/index.ts
  • web/src/lib/transport/interface.ts
  • web/src/lib/transport/types.ts
  • web/src/locales/en.json
  • web/src/locales/zh.json
  • web/src/pages/providers/components/claude-provider-view.tsx
  • web/src/pages/providers/components/claude-token-import.tsx
  • web/src/pages/providers/components/provider-edit-flow.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/index.tsx
  • web/src/pages/providers/types.ts
📜 Review details
🧰 Additional context used
🧬 Code graph analysis (7)
web/src/pages/providers/types.ts (1)
web/src/lib/theme.ts (1)
  • getProviderColorVar (374-376)
web/src/pages/providers/components/claude-token-import.tsx (6)
web/src/pages/providers/hooks/use-provider-navigation.ts (1)
  • useProviderNavigation (3-16)
web/src/lib/transport/http-transport.ts (1)
  • createProvider (111-114)
web/src/lib/transport/index.ts (4)
  • ClaudeTokenValidationResult (62-62)
  • ClaudeOAuthResult (63-63)
  • getTransport (108-108)
  • CreateProviderData (13-13)
web/src/lib/transport/types.ts (3)
  • ClaudeTokenValidationResult (573-581)
  • ClaudeOAuthResult (583-592)
  • CreateProviderData (91-97)
web/src/pages/providers/types.ts (1)
  • CLAUDE_COLOR (97-97)
web/src/lib/utils.ts (1)
  • cn (8-10)
web/src/pages/providers/components/provider-edit-flow.tsx (1)
web/src/pages/providers/components/claude-provider-view.tsx (1)
  • ClaudeProviderView (215-462)
web/src/lib/transport/interface.ts (1)
web/src/lib/transport/types.ts (2)
  • ClaudeTokenValidationResult (573-581)
  • ClaudeOAuthResult (583-592)
web/src/lib/transport/http-transport.ts (2)
web/src/lib/transport/index.ts (1)
  • ClaudeTokenValidationResult (62-62)
web/src/lib/transport/types.ts (1)
  • ClaudeTokenValidationResult (573-581)
web/src/pages/providers/create-layout.tsx (3)
web/src/lib/transport/types.ts (1)
  • Route (127-139)
internal/domain/model.go (1)
  • Route (263-287)
internal/repository/sqlite/models.go (2)
  • Route (97-106)
  • Route (108-108)
web/src/pages/providers/components/select-type-step.tsx (2)
web/src/pages/providers/hooks/use-provider-navigation.ts (1)
  • useProviderNavigation (3-16)
web/src/pages/providers/types.ts (1)
  • PROVIDER_TYPE_CONFIGS (31-80)
🔇 Additional comments (13)
web/src/index.css (1)

86-86: Claude 主题色与 Tailwind 映射补充完整,设计令牌接入正确。

这两处改动保持了 provider 颜色变量与 @theme inline 映射的一致性,便于后续统一消费。

Also applies to: 370-370

web/src/locales/en.json (1)

253-255: Claude 英文文案覆盖面完整,键位组织与现有结构一致。

类型标签、OAuth/Token 导入流程、错误提示与 Add Provider 入口文案都已补齐。

Also applies to: 406-458, 1119-1122

web/src/locales/zh.json (1)

253-255: Claude 中文本地化补充完整,与英文键结构保持对齐。

新增文案覆盖了类型标识、导入流程、错误文案和创建入口,整体一致性良好。

Also applies to: 406-458, 1118-1121

web/src/pages/providers/index.tsx (1)

67-67: Provider 分组新增 claude 正确,列表渲染路径打通。

这能确保 Claude provider 在页面中进入明确分组,不会被回退到 custom

web/src/pages/providers/components/provider-edit-flow.tsx (1)

44-44: Claude 编辑分支接入方式一致且可维护。

导入与条件分发实现清晰,DeleteConfirmModal 的行为也与其他 provider 分支保持一致。

Also applies to: 554-572

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

7-7: Claude 创建路由接入正确,创建入口链路完整。

path="claude" 与组件导入匹配,符合当前创建布局的路由组织方式。

Also applies to: 19-19

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

61-63: Claude 传输类型的统一导出补充正确。

新增 ProviderConfigClaudeClaudeTokenValidationResultClaudeOAuthResult 后,transport 类型出口更加完整。

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

12-12: Claude 创建页导航入口补充正确。

新增跳转路径与创建流程路由一致,改动清晰且低风险。

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

60-67: Claude 传输层类型扩展完整且一致。

配置类型、OAuth/Token 结果类型和 WS 事件类型都已对齐新增能力,结构设计保持了现有风格。

Also applies to: 75-75, 327-327, 571-592

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

15-15: Provider 类型系统接入 Claude 的改动设计良好。

类型联合、展示配置和创建步骤均已同步扩展,避免了前后流程断层。

Also applies to: 57-64, 97-97, 225-225, 245-246

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

22-35: Claude 选择卡片与路由分支接入正确。

选择态、文案与跳转行为都与现有 Provider 卡片保持一致,实现可靠。

Also applies to: 173-205

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

40-41: Transport 接口对 Claude 能力的抽象补齐到位。

方法集合覆盖 token 校验、OAuth 启动/交换、provider 信息刷新,接口边界清晰。

Also applies to: 172-176

web/src/lib/transport/http-transport.ts (1)

547-577: Claude HTTP API 对接实现完整。

端点覆盖面与接口声明一致,返回类型与调用形态也保持了现有传输层风格。

Comment on lines +150 to +163
<ModelInput
value={mapping.pattern}
onChange={(pattern) => handleUpdateMapping(mapping, { pattern })}
placeholder={t('modelMappings.matchPattern')}
disabled={isPending}
className="flex-1 min-w-0 h-8 text-sm"
/>
<ArrowRight className="h-4 w-4 text-muted-foreground shrink-0" />
<ModelInput
value={mapping.target}
onChange={(target) => handleUpdateMapping(mapping, { target })}
placeholder={t('modelMappings.targetModel')}
disabled={isPending}
className="flex-1 min-w-0 h-8 text-sm"
Copy link

@coderabbitai coderabbitai bot Mar 2, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

模型映射“每次键入即写入”会导致请求风暴与写入乱序。

当前输入一个字符就会触发一次更新请求;并发下旧请求可能晚到并覆盖新值。建议改为“本地编辑 + onBlur/显式保存时提交”,至少加防抖和请求串行化。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/providers/components/claude-provider-view.tsx` around lines 150
- 163, The ModelInput fields (pattern/target) currently call handleUpdateMapping
on every keystroke, causing request storms and out-of-order writes; change them
to edit locally and only call handleUpdateMapping when the user blurs or
explicitly saves (or at minimum debounce input and serialize requests).
Concretely: keep a local component state for mapping edits tied to the
ModelInput value, update that state onChange, and invoke
handleUpdateMapping(mapping, {...}) only on onBlur or save; if you add debounce,
ensure the debounced updater serializes requests (e.g., by awaiting previous
update or cancelling prior promises) and respect isPending to prevent
overlapping writes.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is a false positive. The ModelInput component is dialog-based — it opens a modal, user searches/selects a model, and onChange only fires when the user explicitly clicks a model or presses Enter to confirm. It does NOT fire on every keystroke. The internal search state is local to the component. No request storm occurs.

Copy link

Choose a reason for hiding this comment

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

@Bowl42, thank you for the clarification! You're absolutely right—I misunderstood how the ModelInput component works. I incorrectly assumed it was a standard text input that fires onChange on every keystroke, but as you've explained, it's actually a dialog-based component that only triggers onChange when the user explicitly confirms a selection.

I apologize for the false positive and appreciate you taking the time to explain the component's behavior. 🙏

/)/)

(๑•́ ₃ •̀๑) learned something new!


✏️ Learnings added
Learnt from: Bowl42
Repo: awsl-project/maxx PR: 292
File: web/src/pages/providers/components/claude-provider-view.tsx:150-163
Timestamp: 2026-03-02T17:16:15.099Z
Learning: The `ModelInput` component in `@/components/ui/model-input` is dialog-based (opens a modal for model selection), not a standard text input. Its `onChange` callback only fires when the user explicitly selects a model (by clicking or pressing Enter), not on every keystroke. The internal search state is local to the component, so there is no risk of request storms when used with immediate update handlers.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

- Add 'claude' mapping to getProviderDisplayName in theme.ts
- Replace invalid CSS `${CLAUDE_COLOR}15` with Tailwind `bg-provider-claude/15`
  class in claude-provider-view.tsx and claude-token-import.tsx
- Add popup null check for window.open() in OAuth flow
- Store setInterval in ref (oauthPollRef) for proper cleanup on unmount
- Clear interval in cancel handler to prevent memory leaks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ymkiux ymkiux merged commit d3eaf41 into main Mar 2, 2026
1 of 2 checks passed
@ymkiux ymkiux deleted the feat/claude-provider-frontend branch March 2, 2026 17:17
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.

2 participants