feat: add Claude Code channel support with OAuth integration#1445
Conversation
|
""" WalkthroughThis 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
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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Possibly related PRs
Poem
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (2)
✅ Files skipped from review due to trivial changes (2)
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
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 routesservice/claude_token_refresh.go (2)
31-31: Consider adding index for better query performance.The query filters on both
typeandstatusfields. 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
nilwithout 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
⛔ Files ignored due to path filters (1)
go.sumis 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 forgolang.org/x/oauth2 v0.30.0security statusgovulncheck 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.0by 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 Codeproperly groups the new channel type with other Claude variants (14, 33) and maintains visual consistency by using the sameClaude.Coloricon.constant/api_type.go (1)
34-34: LGTM! Proper constant enumeration addition.The
APITypeClaudeCodeconstant is correctly positioned before theAPITypeDummysentinel value, maintaining the iota enumeration pattern and following established conventions.constant/channel.go (2)
53-53: LGTM! Consistent channel type constant addition.The
ChannelTypeClaudeCode = 53constant follows the established naming convention and enumeration pattern.
112-112: Confirmed: Claude Code and Standard Anthropic Share the Same Base URLThe 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, callscommon.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.SysErrorfor 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
Inputcomponent 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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
| // 特殊处理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.
There was a problem hiding this comment.
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
📒 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_PROMPTaddresses 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_PROMPTconstant, 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.
There was a problem hiding this comment.
🛠️ 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.
| // 特殊处理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.
334b2f1 to
bca78be
Compare
There was a problem hiding this comment.
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.BaseUrlto ensure it doesn't have trailing slashes.
63-102: Header setup needs minor improvements.Issues to address:
- Chinese comments on lines 77, 83, and 89 should be in English for consistency
- The
anthropic-dangerous-direct-browser-accessheader (line 97) has security implicationsThe 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-codePlease verify the security implications of setting
anthropic-dangerous-direct-browser-access: true.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis 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:
ModelListandChannelNameconstants are defined elsewhere (likely inconstants.go).
| func (a *Adaptor) ConvertRerankRequest(c *gin.Context, relayMode int, request dto.RerankRequest) (any, error) { | ||
| return nil, nil | ||
| } | ||
|
|
There was a problem hiding this comment.
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.
|
解决一下冲突 |
# Conflicts: # web/src/components/table/channels/modals/EditChannelModal.jsx
…date placeholder in EditChannelModal
feat: add Claude Code channel support with OAuth integration
Summary by CodeRabbit
New Features
Chores