Skip to content

feat: add Claude Code channel support with OAuth integration#1445

Merged
Calcium-Ion merged 4 commits into
QuantumNous:alphafrom
seefs001:feature/claude-code
Jul 31, 2025
Merged

feat: add Claude Code channel support with OAuth integration#1445
Calcium-Ion merged 4 commits into
QuantumNous:alphafrom
seefs001:feature/claude-code

Conversation

@seefs001
Copy link
Copy Markdown
Collaborator

@seefs001 seefs001 commented Jul 26, 2025

  • Introduced Claude Code as a new channel type with ID 53.
  • Implemented OAuth authorization flow for Claude Code, including URL generation and code exchange.
  • Updated UI components to handle access and refresh tokens specific to Claude Code.
  • Enhanced the EditChannelModal to support OAuth token management and fixed system prompt for Claude Code.

Summary by CodeRabbit

  • New Features

    • Added support for the "Claude Code" channel type, including OAuth-based authentication with access and refresh tokens.
    • Introduced UI for generating OAuth authorization URLs and exchanging authorization codes for tokens when configuring Claude Code channels.
    • Enforced a fixed system prompt for Claude Code channels.
    • Added "Claude Code" as a selectable channel type with appropriate icon and color in the interface.
  • Chores

    • Added background scheduler to automatically refresh Claude Code tokens.
    • Updated dependencies to include OAuth2 support.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jul 26, 2025

"""

Walkthrough

This update introduces support for a new channel type, "Claude Code" (ID 53), including backend API type and channel constants, OAuth2 authentication flow, token refresh scheduling, and a new relay adaptor. The frontend is updated to support the new channel type, including OAuth-based token management and UI adjustments for editing and creating such channels.

Changes

File(s) Change Summary
constant/api_type.go, constant/channel.go Added APITypeClaudeCode and ChannelTypeClaudeCode constants; updated base URLs.
common/api_type.go, relay/relay_adaptor.go Updated mapping and adaptor logic to support the new Claude Code API/channel type.
relay/channel/claude_code/adaptor.go
relay/channel/claude_code/constants.go
relay/channel/claude_code/dto.go
Introduced new Claude Code relay adaptor, model list, channel name, and DTO placeholder.
controller/claude_oauth.go
service/claude_oauth.go
Added Claude OAuth controller and service for OAuth2 flow, including endpoints and token exchange logic.
service/claude_token_refresh.go
main.go
Implemented scheduled token refresh for Claude Code channels and started the scheduler in main.
router/api-router.go Registered new admin routes for Claude OAuth URL generation and code exchange.
go.mod Added golang.org/x/oauth2 as an indirect dependency.
web/src/components/table/channels/modals/EditChannelModal.jsx Enhanced channel modal to support Claude Code (type 53) with OAuth flow, token split, and fixed prompt.
web/src/constants/channel.constants.js Added "Claude Code" to channel options and defined default system prompt.
web/src/helpers/render.js Added icon support for Claude Code channel type.
setting/operation_setting/operation_setting.go Added new automatic disable keywords related to OAuth and bearer token errors for Claude Code.

Sequence Diagram(s)

sequenceDiagram
    participant AdminUser as Admin User
    participant Frontend as Web Frontend
    participant Backend as Backend API
    participant Claude as Claude OAuth Server

    AdminUser->>Frontend: Open Edit Channel Modal (Claude Code)
    Frontend->>Backend: GET /channel/claude/oauth/url
    Backend->>Claude: (generates OAuth2 URL)
    Backend-->>Frontend: Returns OAuth2 URL and PKCE params
    AdminUser->>Frontend: Completes OAuth in browser, gets code
    AdminUser->>Frontend: Inputs code/callback URL
    Frontend->>Backend: POST /channel/claude/oauth/exchange (code, verifier, state)
    Backend->>Claude: Exchanges code for tokens
    Claude-->>Backend: Returns access & refresh tokens
    Backend-->>Frontend: Returns tokens
    Frontend->>Frontend: Populates token fields in modal
Loading
sequenceDiagram
    participant Scheduler as Token Refresh Scheduler
    participant DB as Database
    participant Claude as Claude OAuth Server

    loop Every 5 minutes
        Scheduler->>DB: Query Claude Code channels
        Scheduler->>Claude: Refresh tokens for each channel
        Claude-->>Scheduler: Returns new tokens
        Scheduler->>DB: Update channel keys with new tokens
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Poem

In fields of code where channels grow,
A rabbit hops where Claude winds blow.
OAuth tokens, fresh and bright,
Renew themselves by day and night.
With prompts set firm and icons new,
Claude Code hops in—how do you do?
🐇✨
"""

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bca78be and fe9acb6.

📒 Files selected for processing (2)
  • relay/channel/claude_code/constants.go (1 hunks)
  • setting/operation_setting/operation_setting.go (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • setting/operation_setting/operation_setting.go
  • relay/channel/claude_code/constants.go
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

@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: 4

🧹 Nitpick comments (8)
relay/channel/claude_code/dto.go (1)

1-4: Placeholder DTO file is acceptable but consider future maintainability.

The approach of reusing Claude DTOs makes sense for initial implementation. However, consider whether a more explicit approach (like importing Claude DTOs or using type aliases) might be clearer for future maintainers if Claude Code-specific modifications are needed.

router/api-router.go (1)

123-125: OAuth routes implemented correctly but consider comment consistency.

The OAuth routes are properly implemented with appropriate admin authentication and follow RESTful patterns. However, the comment is in Chinese while the rest of the codebase uses English comments for consistency.

Consider updating the comment to English for consistency:

-			// Claude OAuth路由
+			// Claude OAuth routes
service/claude_token_refresh.go (2)

31-31: Consider adding index for better query performance.

The query filters on both type and status fields. Ensure there's a composite index on these columns for optimal performance when dealing with many channels.

CREATE INDEX idx_channels_type_status ON channels(type, status);

86-90: Consider using database transactions for atomic updates.

The channel update operation should be wrapped in a transaction to ensure consistency, especially if there are concurrent operations on the same channel.

+// Consider wrapping in a transaction
+tx := model.DB.Begin()
+defer func() {
+	if r := recover(); r != nil {
+		tx.Rollback()
+	}
+}()
+
-err = model.DB.Model(channel).Update("key", newKey).Error
+err = tx.Model(channel).Update("key", newKey).Error
+if err != nil {
+	tx.Rollback()
+	// ... existing error handling
+	return false
+}
+
+if err = tx.Commit().Error; err != nil {
+	// Handle commit error
+	return false
+}
controller/claude_oauth.go (1)

24-24: Consider internationalization for error messages.

The error messages are in Chinese, which may limit the API's usability in international contexts. Consider using message keys or supporting multiple languages.

-"message": "生成OAuth授权URL失败: " + err.Error(),
+"message": "Failed to generate OAuth authorization URL: " + err.Error(),

Also applies to: 42-42, 52-52, 63-63

service/claude_oauth.go (1)

88-98: Authorization code validation could be more robust.

The current validation only checks for empty strings and URLs. Consider adding more comprehensive validation for OAuth authorization codes.

func ParseAuthorizationCode(input string) (string, error) {
	if input == "" {
		return "", fmt.Errorf("please provide a valid authorization code")
	}
	// URLs are not allowed
	if strings.Contains(input, "http") || strings.Contains(input, "https") {
		return "", fmt.Errorf("authorization code cannot contain URLs")
	}
+
+	// Trim whitespace
+	code := strings.TrimSpace(input)
+	
+	// Basic format validation (OAuth codes are typically alphanumeric with some special chars)
+	if len(code) < 10 || len(code) > 512 {
+		return "", fmt.Errorf("authorization code has invalid length")
+	}
+	
+	// Check for suspicious patterns
+	if strings.ContainsAny(code, "<>\"'") {
+		return "", fmt.Errorf("authorization code contains invalid characters")
+	}

-	return input, nil
+	return code, nil
}
relay/channel/claude_code/adaptor.go (1)

107-109: Consider implementing rerank and responses functionality.

The rerank function returns nil without error, which might cause confusion. Consider returning an explicit "not implemented" error for consistency.

func (a *Adaptor) ConvertRerankRequest(c *gin.Context, relayMode int, request dto.RerankRequest) (any, error) {
-	return nil, nil
+	return nil, errors.New("not implemented")
}

Also applies to: 115-117

web/src/components/table/channels/modals/EditChannelModal.jsx (1)

512-557: Consider extracting the key concatenation logic.

The logic for combining access token and refresh token is duplicated. Consider creating a helper function.

Add a helper function to reduce duplication:

+  // Helper function to create Claude Code key
+  const createClaudeCodeKey = (accessToken, refreshToken) => {
+    return `${accessToken || ''}|${refreshToken || ''}`;
+  };

   // 交换授权码
   const handleExchangeCode = async () => {
     // ... existing validation code ...

     try {
       setIsExchangingCode(true);
       const res = await API.post('/api/channel/claude/oauth/exchange', {
         authorization_code: authorizationCode,
         code_verifier: oauthParams.code_verifier,
         state: oauthParams.state,
       });

       if (res.data.success) {
         const tokenData = res.data.data;
         // 自动填充access token和refresh token
         handleInputChange('access_token', tokenData.access_token);
         handleInputChange('refresh_token', tokenData.refresh_token);
-        handleInputChange('key', `${tokenData.access_token}|${tokenData.refresh_token}`);
+        handleInputChange('key', createClaudeCodeKey(tokenData.access_token, tokenData.refresh_token));

Then use it in the form inputs as well (lines 1218 and 1244).

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e7524c8 and 41856e8.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (16)
  • common/api_type.go (1 hunks)
  • constant/api_type.go (1 hunks)
  • constant/channel.go (2 hunks)
  • controller/claude_oauth.go (1 hunks)
  • go.mod (1 hunks)
  • main.go (1 hunks)
  • relay/channel/claude_code/adaptor.go (1 hunks)
  • relay/channel/claude_code/constants.go (1 hunks)
  • relay/channel/claude_code/dto.go (1 hunks)
  • relay/relay_adaptor.go (2 hunks)
  • router/api-router.go (1 hunks)
  • service/claude_oauth.go (1 hunks)
  • service/claude_token_refresh.go (1 hunks)
  • web/src/components/table/channels/modals/EditChannelModal.jsx (9 hunks)
  • web/src/constants/channel.constants.js (1 hunks)
  • web/src/helpers/render.js (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (6)
main.go (1)
service/claude_token_refresh.go (1)
  • StartClaudeTokenRefreshScheduler (15-24)
common/api_type.go (2)
constant/channel.go (1)
  • ChannelTypeClaudeCode (53-53)
constant/api_type.go (1)
  • APITypeClaudeCode (34-34)
relay/relay_adaptor.go (3)
constant/api_type.go (1)
  • APITypeClaudeCode (34-34)
relay/channel/claude_code/adaptor.go (1)
  • Adaptor (23-25)
relay/channel/adapter.go (1)
  • Adaptor (13-29)
router/api-router.go (1)
controller/claude_oauth.go (2)
  • GenerateClaudeOAuthURL (19-34)
  • ExchangeClaudeOAuthCode (37-73)
service/claude_token_refresh.go (6)
common/logger.go (2)
  • SysLog (50-53)
  • SysError (55-58)
model/channel.go (1)
  • Channel (19-49)
model/main.go (1)
  • DB (63-63)
constant/channel.go (1)
  • ChannelTypeClaudeCode (53-53)
common/constants.go (1)
  • ChannelStatusEnabled (192-192)
service/claude_oauth.go (1)
  • RefreshClaudeToken (108-130)
web/src/components/table/channels/modals/EditChannelModal.jsx (3)
web/src/helpers/utils.js (2)
  • showSuccess (148-150)
  • showError (113-142)
web/src/components/table/channels/modals/EditTagModal.jsx (3)
  • handleInputChange (77-129)
  • formApiRef (74-74)
  • inputs (73-73)
web/src/components/table/tokens/modals/EditTokenModal.jsx (2)
  • formApiRef (62-62)
  • isEdit (65-65)
🔇 Additional comments (34)
go.mod (1)

90-90: Manual verification required for golang.org/x/oauth2 v0.30.0 security status

govulncheck failed to run in this sandbox (invalid mode flag, telemetry errors). Please verify there are no known vulnerabilities for golang.org/x/oauth2 v0.30.0 by running govulncheck locally (e.g. govulncheck -mode=source golang.org/x/oauth2@v0.30.0) or consulting the Go vulnerability database.

web/src/helpers/render.js (1)

361-361: LGTM! Consistent icon mapping for Claude Code channel.

The addition of case 53: // Claude Code properly groups the new channel type with other Claude variants (14, 33) and maintains visual consistency by using the same Claude.Color icon.

constant/api_type.go (1)

34-34: LGTM! Proper constant enumeration addition.

The APITypeClaudeCode constant is correctly positioned before the APITypeDummy sentinel value, maintaining the iota enumeration pattern and following established conventions.

constant/channel.go (2)

53-53: LGTM! Consistent channel type constant addition.

The ChannelTypeClaudeCode = 53 constant follows the established naming convention and enumeration pattern.


112-112: Confirmed: Claude Code and Standard Anthropic Share the Same Base URL

The entry at index 14 (Anthropic) and index 53 (Claude Code) in constant/channel.go both point to https://api.anthropic.com. No change is needed here—using the same endpoint for Claude Code is intentional.

main.go (1)

89-91: Scheduler startup and token refresh errors are handled safely

  • StartClaudeTokenRefreshScheduler() (service/claude_token_refresh.go:15–24) always succeeds in creating the ticker and spawning a goroutine—it does not return an error.
  • Inside that goroutine, RefreshClaudeCodeTokens() catches any database errors, calls common.SysError(...), and returns without panicking or affecting the main application.

No further action required here.

web/src/constants/channel.constants.js (1)

162-166: LGTM! Consistent channel option addition.

The new Claude Code channel option follows the established pattern with appropriate value (53), consistent color scheme ('indigo' matching other Claude variants), and proper labeling.

relay/relay_adaptor.go (2)

12-12: LGTM! Proper import addition.

The import for the claude_code package is correctly added following the existing import organization.


102-103: LGTM! Consistent adaptor factory pattern.

The new case for Claude Code follows the established factory pattern correctly, returning a properly instantiated adaptor instance.

common/api_type.go (1)

68-69: LGTM! Correct channel-to-API type mapping.

The new mapping case correctly associates the Claude Code channel type with its corresponding API type, following the established pattern consistently.

relay/channel/claude_code/constants.go (2)

3-13: Model list looks comprehensive and well-structured.

The model identifiers follow Claude's naming conventions with proper version dates and variant suffixes (haiku, sonnet, thinking). The list covers a good range of available models.


15-15: Channel name constant is appropriate.

The channel name "claude_code" properly identifies this specific channel type.

service/claude_token_refresh.go (2)

15-24: Token refresh scheduler implementation looks good.

The scheduler uses a proper ticker with cleanup and goroutine pool management. The 5-minute interval seems reasonable for token refresh operations.


52-61: Token key format validation is thorough.

Good validation of the expected "accesstoken|refreshtoken" format with proper error messages including channel ID for debugging.

controller/claude_oauth.go (3)

12-16: Request struct is well-defined with proper validation tags.

The struct includes all necessary OAuth2 PKCE parameters with required validation, which ensures proper request handling.


19-34: OAuth URL generation endpoint is properly implemented.

Good error handling with appropriate HTTP status codes and structured JSON responses. The delegation to the service layer follows good separation of concerns.


37-73: OAuth code exchange endpoint handles the flow correctly.

The implementation properly validates input, calls service functions in the correct order, and handles errors appropriately. The use of common.SysError for logging exchange failures is good for debugging.

service/claude_oauth.go (4)

47-66: PKCE implementation is correct and secure.

The use of oauth2.GenerateVerifier() for both code verifier and state generation follows OAuth2 PKCE best practices. The S256 challenge method is properly implemented.


69-86: Token exchange implementation follows OAuth2 standards.

The code exchange properly uses the PKCE verifier and includes state parameter. Error wrapping provides good context for debugging.


101-105: HTTP client configuration is appropriate.

The 30-second timeout is reasonable for OAuth operations and prevents hanging requests.


108-130: Token refresh implementation is correct.

The refresh token flow properly constructs the token object and uses the OAuth2 TokenSource for automatic refresh. Error wrapping provides good context.

relay/channel/claude_code/adaptor.go (6)

31-37: Correctly returns errors for unsupported request types.

The explicit rejection of audio, image, embedding, and rerank requests with "not implemented" errors is appropriate for the Claude Code channel.


40-45: Request mode determination logic is clear.

The prefix-based detection for legacy Claude models (claude-2, claude-instant) vs. message mode for newer models follows a logical pattern.


58-65: Token parsing handles the composite key format correctly.

The code properly extracts the access token from the "accesstoken|refreshtoken" format, with safe handling when the separator is missing.


68-87: Header setup is comprehensive and follows Claude Code requirements.

The implementation correctly sets Claude-specific headers including authorization, API version, content-type, user-agent, and beta features. The conditional header setting prevents overriding existing values when appropriate.


102-102: System prompt override is appropriate for Claude Code.

Setting the system prompt to identify as "Claude Code, Anthropic's official CLI" helps maintain consistency with the expected behavior of the Claude Code channel.


123-130: Response handling properly delegates to existing Claude handlers.

The implementation correctly chooses between streaming and non-streaming handlers based on the request configuration and passes the appropriate request mode.

web/src/components/table/channels/modals/EditChannelModal.jsx (7)

48-49: LGTM! Import addition is appropriate.

The Input component import is correctly added for use in the OAuth authorization modal.


93-94: LGTM! Consistent format prompt for Claude Code.

The prompt format follows the established pattern for multi-part keys.


147-150: LGTM! Well-structured OAuth state management.

The state variables are properly organized for managing the OAuth flow lifecycle.


493-510: LGTM! Clean OAuth URL generation implementation.

The function properly handles loading states, errors, and success scenarios with appropriate user feedback.


871-871: LGTM! Appropriate restriction for OAuth-based channel.

Disabling batch creation for Claude Code channels is correct since OAuth tokens are unique per authorization.


1207-1249: Form implementation looks good.

The Claude Code form inputs provide a good user experience with integrated OAuth flow. The duplication of key concatenation logic was already mentioned in a previous comment.


1790-1850: LGTM! Well-designed OAuth authorization modal.

The modal provides excellent user experience with clear instructions, copy functionality, and proper state management.

Comment thread service/claude_oauth.go Outdated
Comment thread service/claude_token_refresh.go Outdated
Comment on lines 96 to 99
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.

⚠️ Potential issue

Critical: Implement proper token expiry checking.

The shouldRefreshToken function always returns true, which will cause unnecessary token refresh operations. This could lead to rate limiting or quota exhaustion.

Implement proper token expiry validation:

-func shouldRefreshToken(_ string) bool {
-	// TODO: Implement token refresh logic
-	return true
-}
+func shouldRefreshToken(accessToken string) bool {
+	// Parse JWT token to check expiry
+	// Refresh if token expires within 30 minutes
+	
+	// For now, implement a basic time-based check
+	// You might want to decode the JWT token to get actual expiry
+	parts := strings.Split(accessToken, ".")
+	if len(parts) != 3 {
+		return true // Invalid JWT format, refresh anyway
+	}
+	
+	// TODO: Decode JWT payload and check 'exp' claim
+	// For now, refresh every hour to be safe
+	return time.Now().Unix()%3600 < 300 // Refresh in last 5 minutes of hour
+}
🤖 Prompt for AI Agents
In service/claude_token_refresh.go around lines 96 to 99, the shouldRefreshToken
function currently always returns true, causing unnecessary token refreshes.
Modify this function to accept the token or its expiry information as input,
parse the token expiry time, compare it with the current time, and return true
only if the token is close to or past expiry. This will prevent redundant
refresh operations and avoid rate limiting or quota issues.

Comment on lines 357 to 374
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.

⚠️ Potential issue

Add validation for key format when loading Claude Code channel.

The code should validate that the key contains exactly two parts before accessing them to prevent potential undefined values.

      // 特殊处理Claude Code渠道的密钥拆分和系统提示词
      if (data.type === 53) {
        // 拆分密钥
        if (data.key) {
          const keyParts = data.key.split('|');
-         if (keyParts.length === 2) {
+         if (keyParts.length === 2) {
            data.access_token = keyParts[0];
            data.refresh_token = keyParts[1];
+         } else {
+           console.error('Invalid Claude Code key format');
+           showError(t('Claude Code密钥格式无效'));
          }
        }
        // 强制设置固定系统提示词
        data.system_prompt = "You are Claude Code, Anthropic's official CLI for Claude.";
      }
📝 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
// 特殊处理Claude Code渠道的密钥拆分和系统提示词
if (data.type === 53) {
// 拆分密钥
if (data.key) {
const keyParts = data.key.split('|');
if (keyParts.length === 2) {
data.access_token = keyParts[0];
data.refresh_token = keyParts[1];
}
}
// 强制设置固定系统提示词
data.system_prompt = "You are Claude Code, Anthropic's official CLI for Claude.";
}
// 特殊处理Claude Code渠道的密钥拆分和系统提示词
if (data.type === 53) {
// 拆分密钥
if (data.key) {
const keyParts = data.key.split('|');
if (keyParts.length === 2) {
data.access_token = keyParts[0];
data.refresh_token = keyParts[1];
} else {
console.error('Invalid Claude Code key format');
showError(t('Claude Code密钥格式无效'));
}
}
// 强制设置固定系统提示词
data.system_prompt = "You are Claude Code, Anthropic's official CLI for Claude.";
}
🤖 Prompt for AI Agents
In web/src/components/table/channels/modals/EditChannelModal.jsx around lines
357 to 369, the code splits the key for Claude Code channel but does not
validate the key format before accessing parts. Add a check to ensure the key
contains exactly two parts after splitting by '|' before assigning access_token
and refresh_token to avoid undefined values.

Comment thread web/src/components/table/channels/modals/EditChannelModal.jsx Outdated
@seefs001 seefs001 marked this pull request as ready for review July 26, 2025 08:53
Copy link
Copy Markdown
Contributor

@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: 1

♻️ Duplicate comments (1)
service/claude_token_refresh.go (1)

71-74: Critical: Token expiry checking is disabled.

The token expiry validation logic is commented out, causing all tokens to be refreshed regardless of their actual expiry status. This could lead to unnecessary API calls and potential rate limiting.

🧹 Nitpick comments (2)
relay/channel/claude_code/adaptor.go (2)

77-77: Consider using English comments for consistency.

The comment is in Chinese while the rest of the codebase uses English. Consider translating for consistency:

-	// 只有在没有设置的情况下才设置 anthropic-version
+	// Only set anthropic-version if not already set

83-89: Consider using English comments for consistency.

The comments are in Chinese while the rest of the codebase uses English. Consider translating for consistency:

-	// 只有在 user-agent 不包含 claude-cli 时才设置
+	// Only set user-agent if it doesn't already contain claude-cli
-	// 只有在 anthropic-beta 不包含 claude-code 时才设置
+	// Only set anthropic-beta if it doesn't already contain claude-code
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 46bbcc4 and 334b2f1.

📒 Files selected for processing (5)
  • relay/channel/claude_code/adaptor.go (1 hunks)
  • service/claude_oauth.go (1 hunks)
  • service/claude_token_refresh.go (1 hunks)
  • web/src/components/table/channels/modals/EditChannelModal.jsx (9 hunks)
  • web/src/constants/channel.constants.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/src/constants/channel.constants.js
🧰 Additional context used
🧬 Code Graph Analysis (2)
relay/channel/claude_code/adaptor.go (7)
relay/common/relay_info.go (1)
  • RelayInfo (62-112)
dto/claude.go (1)
  • ClaudeRequest (183-199)
relay/channel/api_request.go (1)
  • DoApiRequest (37-58)
dto/openai_request.go (1)
  • GeneralOpenAIRequest (21-67)
relay/channel/claude/relay-claude.go (3)
  • RequestOpenAI2ClaudeComplete (42-71)
  • ClaudeStreamHandler (677-699)
  • ClaudeHandler (743-765)
types/error.go (1)
  • NewAPIError (77-83)
relay/channel/claude_code/constants.go (2)
  • ModelList (3-13)
  • ChannelName (15-15)
web/src/components/table/channels/modals/EditChannelModal.jsx (4)
web/src/constants/channel.constants.js (2)
  • CLAUDE_CODE_DEFAULT_SYSTEM_PROMPT (172-172)
  • CLAUDE_CODE_DEFAULT_SYSTEM_PROMPT (172-172)
web/src/helpers/utils.js (2)
  • showSuccess (148-150)
  • showError (113-142)
web/src/components/table/channels/modals/EditTagModal.jsx (3)
  • handleInputChange (77-129)
  • formApiRef (74-74)
  • inputs (73-73)
web/src/components/table/tokens/modals/EditTokenModal.jsx (2)
  • formApiRef (62-62)
  • isEdit (65-65)
🔇 Additional comments (22)
service/claude_token_refresh.go (4)

14-24: LGTM: Well-structured scheduler implementation.

The scheduler properly uses a ticker with goroutine pool and includes proper cleanup with defer ticker.Stop(). The 5-minute interval is reasonable for token refresh operations.


26-47: LGTM: Robust batch refresh implementation.

The function correctly queries active Claude Code channels, handles database errors appropriately, and provides useful logging for successful refreshes.


49-70: LGTM: Comprehensive key validation logic.

The function properly validates the channel key format, ensures both access and refresh tokens are present, and provides clear error messages for invalid formats.


76-94: LGTM: Robust token refresh and database update.

The token refresh logic properly calls the shared RefreshClaudeToken function, updates the channel with new tokens, and provides comprehensive error handling and logging throughout the process.

service/claude_oauth.go (4)

14-78: LGTM: Excellent improvement addressing security concerns.

The implementation now properly uses environment variables with sensible defaults, addressing the previous security concern about hardcoded OAuth credentials. The configuration function correctly splits scopes and creates a proper OAuth2 config.


80-100: LGTM: Proper PKCE implementation with security best practices.

The OAuth parameter generation correctly implements PKCE with S256 challenge, includes state for CSRF protection, and properly handles Claude-specific parameters.


102-132: LGTM: Secure token exchange with proper validation.

The token exchange implementation correctly handles PKCE verification, state validation, and includes security measures to prevent URL injection in authorization codes. Error handling is comprehensive with proper error wrapping.


134-164: LGTM: Well-implemented token refresh with proper timeout handling.

The HTTP client configuration uses a reasonable timeout, and the token refresh implementation properly leverages OAuth2's TokenSource for automatic refresh handling with comprehensive error reporting.

relay/channel/claude_code/adaptor.go (5)

18-37: LGTM: Well-structured adaptor with proper system prompt handling.

The adaptor correctly implements request mode constants and system prompt logic, properly using channel settings with a sensible default that matches the frontend implementation.


39-45: LGTM: Appropriate handling of unsupported features.

The methods correctly return "not implemented" errors for audio and image requests, which is appropriate for the Claude Code channel's capabilities.


47-61: LGTM: Correct model-based request mode determination.

The initialization logic properly determines request mode based on model prefixes, and URL generation correctly maps to the appropriate Claude API endpoints for each mode.


63-96: LGTM: Comprehensive header setup with proper token handling.

The header setup correctly parses the composite API key format, sets appropriate Claude Code headers, and uses conditional logic to avoid overriding existing headers. The authorization setup properly extracts and uses the access token.


98-153: LGTM: Well-implemented request conversion and delegation.

The OpenAI request conversion properly handles both request modes and applies system prompts correctly. The response handling appropriately delegates to existing Claude handlers, and the model/channel name methods correctly use the defined constants.

web/src/components/table/channels/modals/EditChannelModal.jsx (9)

46-46: LGTM: Proper constant import addressing previous feedback.

The import of CLAUDE_CODE_DEFAULT_SYSTEM_PROMPT addresses the previous review comment about centralizing the system prompt definition, improving maintainability.


94-95: LGTM: Appropriate key format prompt for Claude Code.

The prompt correctly describes the expected format for Claude Code authentication tokens (AccessToken|RefreshToken).


148-151: LGTM: Well-named state variables for OAuth functionality.

The state variables are appropriately named and necessary for implementing the OAuth authorization flow for Claude Code channels.


498-515: LGTM: Well-implemented OAuth URL generation.

The function properly handles the asynchronous API call, manages loading states, provides comprehensive error handling, and sets up the modal state for user interaction.


517-562: LGTM: Comprehensive OAuth code exchange implementation.

The function includes proper input validation, handles the token exchange API call correctly, updates all relevant form fields (individual tokens and composite key), and provides excellent user feedback throughout the process.


876-876: LGTM: Appropriate disabling of batch creation for Claude Code.

Correctly disables batch creation for Claude Code channels since OAuth-based authentication doesn't support batch operations.


1212-1254: LGTM: Well-designed OAuth token input interface.

The separate access token and refresh token fields provide excellent UX while properly maintaining the composite key format. The integration of the OAuth generation button directly in the access token field is intuitive and user-friendly.


1769-1782: LGTM: Excellent system prompt handling addressing previous feedback.

The implementation now uses the centralized CLAUDE_CODE_DEFAULT_SYSTEM_PROMPT constant, properly disables editing for Claude Code channels, and provides clear explanatory text. This fully addresses the previous review comment about centralizing the system prompt definition.


1795-1855: LGTM: Well-designed OAuth authorization modal.

The OAuth modal provides excellent UX with a clickable authorization URL, copy functionality, clear instructions for users, and proper form handling for the authorization code input. The modal state management and user feedback are comprehensive.

Comment on lines 358 to 374
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.

🛠️ Refactor suggestion

Improvement made but error handling still missing.

The code now handles the case where there's no "|" separator, which is an improvement. However, the past review comment about validating the exact format and showing error messages for invalid keys is still not fully addressed.

Consider adding validation:

      if (data.type === 53) {
        if (data.key) {
          const keyParts = data.key.split('|');
-         if (keyParts.length === 2) {
+         if (keyParts.length === 2) {
            data.access_token = keyParts[0];
            data.refresh_token = keyParts[1];
+         } else if (keyParts.length === 1) {
+           data.access_token = data.key;
+           data.refresh_token = '';
          } else {
-           // 如果没有 | 分隔符,表示只有access token
-           data.access_token = data.key;
-           data.refresh_token = '';
+           console.error('Invalid Claude Code key format');
+           showError(t('Claude Code密钥格式无效'));
+           data.access_token = '';
+           data.refresh_token = '';
          }
        }
📝 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
// 特殊处理Claude Code渠道的密钥拆分和系统提示词
if (data.type === 53) {
// 拆分密钥
if (data.key) {
const keyParts = data.key.split('|');
if (keyParts.length === 2) {
data.access_token = keyParts[0];
data.refresh_token = keyParts[1];
} else {
// 如果没有 | 分隔符,表示只有access token
data.access_token = data.key;
data.refresh_token = '';
}
}
// 强制设置固定系统提示词
data.system_prompt = CLAUDE_CODE_DEFAULT_SYSTEM_PROMPT;
}
// 特殊处理Claude Code渠道的密钥拆分和系统提示词
if (data.type === 53) {
// 拆分密钥
if (data.key) {
const keyParts = data.key.split('|');
if (keyParts.length === 2) {
data.access_token = keyParts[0];
data.refresh_token = keyParts[1];
} else if (keyParts.length === 1) {
data.access_token = data.key;
data.refresh_token = '';
} else {
console.error('Invalid Claude Code key format');
showError(t('Claude Code密钥格式无效'));
data.access_token = '';
data.refresh_token = '';
}
}
// 强制设置固定系统提示词
data.system_prompt = CLAUDE_CODE_DEFAULT_SYSTEM_PROMPT;
}
🤖 Prompt for AI Agents
In web/src/components/table/channels/modals/EditChannelModal.jsx around lines
358 to 374, the code splits the key for type 53 but lacks validation for the key
format and error handling. Add validation to check if the key is either a single
token or two tokens separated by '|'; if the format is invalid, set an error
state or display an error message to inform the user. This ensures invalid keys
are caught early and users receive clear feedback.

@seefs001 seefs001 force-pushed the feature/claude-code branch from 334b2f1 to bca78be Compare July 26, 2025 10:06
Copy link
Copy Markdown
Contributor

@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: 1

🧹 Nitpick comments (2)
relay/channel/claude_code/adaptor.go (2)

47-62: Model detection and URL routing look correct.

The logic properly differentiates between completion and message endpoints based on model prefixes. Consider adding URL validation for info.BaseUrl to ensure it doesn't have trailing slashes.


63-102: Header setup needs minor improvements.

Issues to address:

  1. Chinese comments on lines 77, 83, and 89 should be in English for consistency
  2. The anthropic-dangerous-direct-browser-access header (line 97) has security implications

The token parsing logic correctly handles the composite key format.

Replace Chinese comments with English:

  • Line 77: // 只有在没有设置的情况下才设置 anthropic-version// Only set anthropic-version if not already set
  • Line 83: // 只有在 user-agent 不包含 claude-cli 时才设置// Only set user-agent if it doesn't contain claude-cli
  • Line 89: // 只有在 anthropic-beta 不包含 claude-code 时才设置// Only set anthropic-beta if it doesn't contain claude-code

Please verify the security implications of setting anthropic-dangerous-direct-browser-access: true.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 334b2f1 and bca78be.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (16)
  • common/api_type.go (1 hunks)
  • constant/api_type.go (1 hunks)
  • constant/channel.go (2 hunks)
  • controller/claude_oauth.go (1 hunks)
  • go.mod (1 hunks)
  • main.go (1 hunks)
  • relay/channel/claude_code/adaptor.go (1 hunks)
  • relay/channel/claude_code/constants.go (1 hunks)
  • relay/channel/claude_code/dto.go (1 hunks)
  • relay/relay_adaptor.go (2 hunks)
  • router/api-router.go (1 hunks)
  • service/claude_oauth.go (1 hunks)
  • service/claude_token_refresh.go (1 hunks)
  • web/src/components/table/channels/modals/EditChannelModal.jsx (9 hunks)
  • web/src/constants/channel.constants.js (1 hunks)
  • web/src/helpers/render.js (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • go.mod
🚧 Files skipped from review as they are similar to previous changes (13)
  • main.go
  • constant/api_type.go
  • web/src/helpers/render.js
  • relay/channel/claude_code/dto.go
  • constant/channel.go
  • relay/relay_adaptor.go
  • common/api_type.go
  • router/api-router.go
  • relay/channel/claude_code/constants.go
  • web/src/constants/channel.constants.js
  • service/claude_token_refresh.go
  • controller/claude_oauth.go
  • web/src/components/table/channels/modals/EditChannelModal.jsx
🔇 Additional comments (12)
service/claude_oauth.go (7)

1-13: Imports look good.

The package declaration and imports are appropriate for implementing OAuth2 functionality.


14-22: Good implementation of configurable OAuth constants.

The use of default values that can be overridden via environment variables addresses the previous security concerns about hardcoded credentials. This approach provides flexibility while maintaining ease of deployment.


23-52: Well-structured configuration retrieval.

The function properly handles environment variable retrieval with appropriate fallbacks to default values. The consistent pattern and named return values enhance readability.


53-79: Clean OAuth configuration setup.

Good design choices:

  • Appropriate struct for OAuth credentials
  • Maintaining backward compatibility with getOAuthConfig
  • Proper handling of scopes string splitting

80-101: PKCE implementation looks secure.

The OAuth flow correctly implements PKCE with proper verifier and challenge generation. Good reuse of the verifier generator for state parameter.

Note: Line 91 adds a Claude-specific parameter code=true. Please verify this is required by Claude's OAuth implementation.


122-133: Basic authorization code validation.

The function provides minimal but reasonable validation. The URL check is an interesting security measure to prevent potential injection attacks.


134-165: Proper HTTP client configuration and token refresh implementation.

Good practices observed:

  • Reasonable 30-second timeout for OAuth operations
  • Correct usage of oauth2.TokenSource for token refresh
  • Proper error wrapping with context
relay/channel/claude_code/adaptor.go (5)

1-23: Well-structured package setup.

Good organization with clear constants for request modes and appropriate default system prompt.


24-38: Clean system prompt handling.

Good implementation that respects channel-specific system prompts while providing a sensible default.


39-46: Clear handling of unsupported request types.

Appropriate "not implemented" errors for audio and image requests.


103-126: Robust OpenAI request conversion.

Good implementation with:

  • Proper nil checking
  • Consistent system prompt handling
  • Appropriate delegation to the claude package

139-159: Proper request/response handling and utility methods.

The implementation correctly:

  • Delegates request handling to the channel package
  • Differentiates between streaming and non-streaming responses
  • Provides model list and channel name accessors

Note: ModelList and ChannelName constants are defined elsewhere (likely in constants.go).

Comment on lines +127 to +130
func (a *Adaptor) ConvertRerankRequest(c *gin.Context, relayMode int, request dto.RerankRequest) (any, error) {
return nil, 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.

⚠️ Potential issue

Inconsistent error handling for unimplemented method.

ConvertRerankRequest returns nil, nil while other unimplemented methods return proper "not implemented" errors. This inconsistency could cause confusion.

Consider returning an error for consistency:

 func (a *Adaptor) ConvertRerankRequest(c *gin.Context, relayMode int, request dto.RerankRequest) (any, error) {
-	return nil, nil
+	return nil, errors.New("not implemented")
 }
🤖 Prompt for AI Agents
In relay/channel/claude_code/adaptor.go around lines 127 to 130, the
ConvertRerankRequest method currently returns nil, nil which is inconsistent
with other unimplemented methods that return a "not implemented" error. Update
this method to return a proper "not implemented" error instead of nil, nil to
maintain consistent error handling across unimplemented methods.

@Calcium-Ion
Copy link
Copy Markdown
Collaborator

解决一下冲突

seefs001 added 2 commits July 31, 2025 21:19
# Conflicts:
#	web/src/components/table/channels/modals/EditChannelModal.jsx
@Calcium-Ion Calcium-Ion merged commit 9758a9e into QuantumNous:alpha Jul 31, 2025
1 check passed
This was referenced Sep 8, 2025
This was referenced Sep 22, 2025
@coderabbitai coderabbitai Bot mentioned this pull request Sep 30, 2025
@coderabbitai coderabbitai Bot mentioned this pull request Oct 18, 2025
This was referenced Jan 12, 2026
x22x22 pushed a commit to x22x22/new-api that referenced this pull request Apr 24, 2026
feat: add Claude Code channel support with OAuth integration
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