fix: claude & gemini endpoint system prompt overwrite - #1850
Conversation
WalkthroughAdds logic in relay/claude_handler.go to automatically inject or prepend a channel-level system prompt into Claude requests when SystemPromptOverride is enabled, handling both string and structured system content, setting a context key for the override, and running this before building the upstream request payload. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Client
participant Handler as Claude Handler
participant Chan as ChannelSettings
participant Ctx as Context
participant Claude as Upstream Claude API
Client->>Handler: Send request (messages incl. system)
Handler->>Chan: Read SystemPrompt & Override flag
alt Override enabled
opt No system content
Handler->>Handler: Set system = ChannelSetting.SystemPrompt
end
opt String system content
Handler->>Handler: Prepend ChannelPrompt (+ newline if needed)
end
opt Structured system content
Handler->>Handler: Create text media message with ChannelPrompt and prepend
end
Handler->>Ctx: Set ContextKeySystemPromptOverride
end
Handler->>Claude: Send modified payload
Claude-->>Handler: Response
Handler-->>Client: Response
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
relay/claude_handler.go (3)
73-96: Always set the context flag when overriding; simplify redundant condition.The override flag is only set when
request.System != nil. Ifrequest.System == nil, you still override but don’t mark it in context. Also, the nestedelse if info.ChannelSetting.SystemPromptOverrideis redundant given the outer condition.Apply this minimal diff:
- if info.ChannelSetting.SystemPrompt != "" && info.ChannelSetting.SystemPromptOverride { - if request.System == nil { - request.SetStringSystem(info.ChannelSetting.SystemPrompt) - } else if info.ChannelSetting.SystemPromptOverride { - common.SetContextKey(c, constant.ContextKeySystemPromptOverride, true) + if info.ChannelSetting.SystemPrompt != "" && info.ChannelSetting.SystemPromptOverride { + // Mark override for downstream logging/handlers in all cases. + common.SetContextKey(c, constant.ContextKeySystemPromptOverride, true) + if request.System == nil { + request.SetStringSystem(info.ChannelSetting.SystemPrompt) + } else { if request.IsStringSystem() { existing := strings.TrimSpace(request.GetStringSystem()) if existing == "" { request.SetStringSystem(info.ChannelSetting.SystemPrompt) } else { request.SetStringSystem(info.ChannelSetting.SystemPrompt + "\n" + existing) } } else { systemContents := request.ParseSystem() newSystem := dto.ClaudeMediaMessage{Type: dto.ContentTypeText} newSystem.SetText(info.ChannelSetting.SystemPrompt) if len(systemContents) == 0 { request.System = []dto.ClaudeMediaMessage{newSystem} } else { request.System = append([]dto.ClaudeMediaMessage{newSystem}, systemContents...) } } } }
78-85: De-duplicate to avoid double-prepending in string system case.If the channel prompt is already present (e.g., on retries or upstream already included it), this will prepend it again.
- if request.IsStringSystem() { - existing := strings.TrimSpace(request.GetStringSystem()) + if request.IsStringSystem() { + existing := strings.TrimSpace(request.GetStringSystem()) + channel := strings.TrimSpace(info.ChannelSetting.SystemPrompt) if existing == "" { - request.SetStringSystem(info.ChannelSetting.SystemPrompt) - } else { - request.SetStringSystem(info.ChannelSetting.SystemPrompt + "\n" + existing) + request.SetStringSystem(channel) + } else if !strings.HasPrefix(existing, channel) { + request.SetStringSystem(channel + "\n" + existing) }
86-94: De-duplicate in structured system case.Skip prepend when the first block already equals the channel prompt (type=text, same text).
- } else { + } else { systemContents := request.ParseSystem() - newSystem := dto.ClaudeMediaMessage{Type: dto.ContentTypeText} - newSystem.SetText(info.ChannelSetting.SystemPrompt) + channel := strings.TrimSpace(info.ChannelSetting.SystemPrompt) + newSystem := dto.ClaudeMediaMessage{Type: dto.ContentTypeText} + newSystem.SetText(channel) if len(systemContents) == 0 { request.System = []dto.ClaudeMediaMessage{newSystem} } else { - request.System = append([]dto.ClaudeMediaMessage{newSystem}, systemContents...) + dup := systemContents[0].Type == dto.ContentTypeText && + systemContents[0].Text != nil && + strings.TrimSpace(*systemContents[0].Text) == channel + if !dup { + request.System = append([]dto.ClaudeMediaMessage{newSystem}, systemContents...) + } } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
relay/claude_handler.go(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
relay/claude_handler.go (4)
common/gin.go (1)
SetContextKey(53-55)constant/context_key.go (1)
ContextKeySystemPromptOverride(49-49)dto/claude.go (1)
ClaudeMediaMessage(17-36)dto/openai_request.go (1)
ContentTypeText(374-374)
🔇 Additional comments (2)
relay/claude_handler.go (2)
9-9: Import looks correct.Package name matches usage (
constant.ContextKeySystemPromptOverride). No action needed.
73-97: Pass‑through bypasses SystemPromptOverride — confirm intended behaviorPass-through (global or channel PassThroughBodyEnabled) reads/forwards the original request body (relay/claude_handler.go:99-106; relay/responses_handler.go:44-47), so the earlier mutation that sets/appends SystemPrompt on the request struct (relay/claude_handler.go:73-97) will not be sent upstream. The ContextKeySystemPromptOverride is set (relay/claude_handler.go:77) but appears only used for logging (service/log_info_generate.go:32-35). Confirm intent: either apply the override to the raw request body when pass-through is enabled, or skip mutating/setting the override when pass-through is in effect.
…rompt-overwrite fix: claude & gemini endpoint system prompt overwrite
…ghts feat(monitor): channel monitor with available channels & feature flags
Summary by CodeRabbit