feat(anthropic): add configurable prompt count for system blocks#390
feat(anthropic): add configurable prompt count for system blocks#390Kindness-Kismet wants to merge 2 commits intotbphp:mainfrom
Conversation
WalkthroughThe PR adds an Anthropic-specific system prompt count feature: new model fields and constants, request normalization and enforcement in the proxy, service-level normalization, handler plumbing, tests, frontend form/display/localizations, and integration of the normalization into the request pipeline. Changes
Sequence DiagramsequenceDiagram
actor Client
participant Handler as "HTTP Handler"
participant Service as "Group Service"
participant Server as "Proxy Server"
participant Upstream as "Upstream API"
Client->>Handler: Create/Update Group (anthropic_system_prompt_count)
Handler->>Service: CreateGroup/UpdateGroup(params with count)
Service->>Service: normalizeAnthropicSystemPromptCount(channelType, count)
Service-->>Handler: Group (with normalized count)
Handler-->>Client: GroupResponse (includes count)
Client->>Server: Forward request (uses Group)
Server->>Server: applyAnthropicSystemPromptCount(body, group)
Server->>Upstream: Modified request (merged/padded system prompts)
Upstream-->>Server: Response
Server-->>Client: Response
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/proxy/server.go (1)
110-114:⚠️ Potential issue | 🟠 MajorUse the transformed request body for stream detection.
After Line [110] mutates the payload, Line [112] still checks
IsStreamRequestagainstbodyBytes. That can select the wrong execution path when payload-level overrides affectstream.💡 Suggested fix
- isStream := channelHandler.IsStreamRequest(c, bodyBytes) + isStream := channelHandler.IsStreamRequest(c, finalBodyBytes)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/proxy/server.go` around lines 110 - 114, The code calls channelHandler.IsStreamRequest(c, bodyBytes) before passing the mutated payload to ps.executeRequestWithRetry, which can mis-detect streaming when payload-level changes were applied by applyAnthropicSystemPromptCount; change the IsStreamRequest call to use finalBodyBytes (the transformed request) so stream detection uses the actual payload sent to executeRequestWithRetry (update the call site that invokes IsStreamRequest and ensure the isStream boolean is derived from finalBodyBytes).
🧹 Nitpick comments (1)
internal/services/group_service_anthropic_test.go (1)
16-20: Add explicit boundary test cases (0and exact max).Coverage is good overall; adding exact boundary assertions will make normalization intent fully explicit.
✅ Suggested test additions
tests := []struct { name string channelType string count int want int }{ {name: "non-anthropic forced zero", channelType: "openai", count: 5, want: 0}, + {name: "anthropic zero kept", channelType: "anthropic", count: 0, want: 0}, {name: "negative clamped to zero", channelType: "anthropic", count: -1, want: 0}, {name: "within range kept", channelType: "anthropic", count: 2, want: 2}, + {name: "exact max kept", channelType: "anthropic", count: models.MaxAnthropicSystemPromptCount, want: models.MaxAnthropicSystemPromptCount}, {name: "upper bound clamped", channelType: "anthropic", count: models.MaxAnthropicSystemPromptCount + 1, want: models.MaxAnthropicSystemPromptCount}, }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/services/group_service_anthropic_test.go` around lines 16 - 20, Add two explicit boundary table-driven tests in the same test slice used in group_service_anthropic_test.go: one where channelType == "anthropic" and count == 0 expecting want == 0, and another where channelType == "anthropic" and count == models.MaxAnthropicSystemPromptCount expecting want == models.MaxAnthropicSystemPromptCount; ensure the new entries follow the existing test entry shape (fields name, channelType, count, want) so the normalization logic in the test exercises the exact lower and upper boundaries.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@internal/proxy/request_helpers.go`:
- Around line 53-58: systemBlocks is being polluted with raw strings (via
asAnyArray branch and setSystemText) which yields invalid Claude payloads;
normalize any string system blocks into structured text objects before appending
or returning. Update the asAnyArray handling in request_helpers.go so that when
a system item is a string you convert it to an object like {type: "text", text:
"<string>"} before appending to systemBlocks, and modify setSystemText to return
structured text objects instead of raw strings; ensure both single-string and
array-of-string paths produce only structured text objects so merged system
arrays contain no raw strings.
In `@internal/services/group_service.go`:
- Around line 990-993: The channel type check in
normalizeAnthropicSystemPromptCount is case-sensitive; update it to perform a
case-insensitive comparison (e.g., use strings.EqualFold(channelType,
"anthropic") or compare strings.ToLower(channelType) == "anthropic") so inputs
like "Anthropic" or "ANTHROPIC" are treated the same; remember to add the
strings import if using strings.EqualFold or ToLower.
In `@web/src/components/keys/GroupFormModal.vue`:
- Around line 342-343: The submit handler in GroupFormModal.vue currently only
enforces the lower bound for anthropic_system_prompt_count and can send values
>100; update the submit logic that builds the payload to clamp
anthropic_system_prompt_count to the 0–100 range (e.g., Math.min(Math.max(value,
0), 100)) wherever the form value is serialized (the lines setting
anthropic_system_prompt_count from props.group and the duplicate occurrences
around lines 531-534), so the payload uses the same upper-bound enforcement as
the UI/backend and avoid drift.
---
Outside diff comments:
In `@internal/proxy/server.go`:
- Around line 110-114: The code calls channelHandler.IsStreamRequest(c,
bodyBytes) before passing the mutated payload to ps.executeRequestWithRetry,
which can mis-detect streaming when payload-level changes were applied by
applyAnthropicSystemPromptCount; change the IsStreamRequest call to use
finalBodyBytes (the transformed request) so stream detection uses the actual
payload sent to executeRequestWithRetry (update the call site that invokes
IsStreamRequest and ensure the isStream boolean is derived from finalBodyBytes).
---
Nitpick comments:
In `@internal/services/group_service_anthropic_test.go`:
- Around line 16-20: Add two explicit boundary table-driven tests in the same
test slice used in group_service_anthropic_test.go: one where channelType ==
"anthropic" and count == 0 expecting want == 0, and another where channelType ==
"anthropic" and count == models.MaxAnthropicSystemPromptCount expecting want ==
models.MaxAnthropicSystemPromptCount; ensure the new entries follow the existing
test entry shape (fields name, channelType, count, want) so the normalization
logic in the test exercises the exact lower and upper boundaries.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5e53a3bd-5c87-434d-9417-95bad4bff1be
📒 Files selected for processing (13)
internal/handler/group_handler.gointernal/models/types.gointernal/proxy/request_helpers.gointernal/proxy/request_helpers_test.gointernal/proxy/server.gointernal/services/group_service.gointernal/services/group_service_anthropic_test.goweb/src/components/keys/GroupFormModal.vueweb/src/components/keys/GroupInfoCard.vueweb/src/locales/en-US.tsweb/src/locales/ja-JP.tsweb/src/locales/zh-CN.tsweb/src/types/models.ts
There was a problem hiding this comment.
🧹 Nitpick comments (2)
web/src/components/keys/GroupFormModal.vue (1)
55-55: Use the existing max constant in the template to avoid drift.
Line 711hardcodes100whileLine 55already definesMAX_ANTHROPIC_SYSTEM_PROMPT_COUNT. Reusing the constant keeps UI and normalization limits aligned.♻️ Proposed refactor
<n-input-number v-model:value="formData.anthropic_system_prompt_count" :min="0" - :max="100" + :max="MAX_ANTHROPIC_SYSTEM_PROMPT_COUNT" :placeholder="t('keys.anthropicSystemPromptCountPlaceholder')" style="width: 100%" />Also applies to: 711-711
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/components/keys/GroupFormModal.vue` at line 55, The template currently hardcodes the value 100 (at the UI max on Line 711) which can drift from the constant defined as MAX_ANTHROPIC_SYSTEM_PROMPT_COUNT; update the template to reference that constant instead of the literal so the UI max stays in sync with the normalization limit—use the MAX_ANTHROPIC_SYSTEM_PROMPT_COUNT symbol from the script section (exported/defined at top) in the template binding or computed property that supplies the max value for the input control.internal/proxy/request_helpers.go (1)
35-35: Consider trimming channel type in the Anthropics guard.Line 35 uses case-insensitive matching but not whitespace normalization; trimming here would make the guard more defensive against legacy or malformed persisted values.
♻️ Proposed tweak
-func applyAnthropicSystemPromptCount(bodyBytes []byte, group *models.Group) []byte { - if group == nil || !strings.EqualFold(group.ChannelType, "anthropic") { +func applyAnthropicSystemPromptCount(bodyBytes []byte, group *models.Group) []byte { + if group == nil || !strings.EqualFold(strings.TrimSpace(group.ChannelType), "anthropic") { return bodyBytes }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/proxy/request_helpers.go` at line 35, The guard that checks the group's channel type uses strings.EqualFold but doesn't normalize whitespace, so update the condition around "group" and "group.ChannelType" to compare strings.TrimSpace(group.ChannelType) with "anthropic" (still using strings.EqualFold) to defensively handle leading/trailing whitespace; keep the nil check for "group" and ensure you import or reference strings.TrimSpace alongside strings.EqualFold where the comparison is done.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@internal/proxy/request_helpers.go`:
- Line 35: The guard that checks the group's channel type uses strings.EqualFold
but doesn't normalize whitespace, so update the condition around "group" and
"group.ChannelType" to compare strings.TrimSpace(group.ChannelType) with
"anthropic" (still using strings.EqualFold) to defensively handle
leading/trailing whitespace; keep the nil check for "group" and ensure you
import or reference strings.TrimSpace alongside strings.EqualFold where the
comparison is done.
In `@web/src/components/keys/GroupFormModal.vue`:
- Line 55: The template currently hardcodes the value 100 (at the UI max on Line
711) which can drift from the constant defined as
MAX_ANTHROPIC_SYSTEM_PROMPT_COUNT; update the template to reference that
constant instead of the literal so the UI max stays in sync with the
normalization limit—use the MAX_ANTHROPIC_SYSTEM_PROMPT_COUNT symbol from the
script section (exported/defined at top) in the template binding or computed
property that supplies the max value for the input control.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: dcf63ea3-5d5a-4580-be2c-007f6957b64d
📒 Files selected for processing (6)
internal/proxy/request_helpers.gointernal/proxy/request_helpers_test.gointernal/proxy/server.gointernal/services/group_service.gointernal/services/group_service_anthropic_test.goweb/src/components/keys/GroupFormModal.vue
🚧 Files skipped from review as they are similar to previous changes (3)
- internal/services/group_service_anthropic_test.go
- internal/proxy/server.go
- internal/proxy/request_helpers_test.go
变更内容 / Change Content
自查清单 / Checklist
Summary by CodeRabbit
New Features
Behavior
Tests