Skip to content

Add a system-prompt-count option for some Claude providers to pass validation#1838

Closed
Kindness-Kismet wants to merge 3 commits intorouter-for-me:mainfrom
Kindness-Kismet:main
Closed

Add a system-prompt-count option for some Claude providers to pass validation#1838
Kindness-Kismet wants to merge 3 commits intorouter-for-me:mainfrom
Kindness-Kismet:main

Conversation

@Kindness-Kismet
Copy link
Copy Markdown

Some Claude providers verify the number of prompts, so this option has been added.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a validation requirement from certain Claude providers by introducing a configurable system-prompt-count for Claude API keys. The change allows the system to automatically normalize the number of system prompt blocks in outgoing requests, ensuring compliance with provider-specific constraints without manual intervention. This enhances the flexibility and compatibility of the Claude integration.

Highlights

  • New Configuration Option: Introduced a new system-prompt-count option for Claude API keys, allowing users to specify a desired number of system prompt blocks for validation purposes.
  • System Prompt Enforcement Logic: Implemented logic to automatically adjust the number of system prompt blocks in Claude API requests. This involves merging extra blocks into the last one or padding with empty blocks to meet the configured system-prompt-count.
  • API and Configuration Integration: Integrated the new system-prompt-count into the API for patching Claude keys, updated the main configuration structure, and added sanitization and diff tracking for this setting.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • config.example.yaml
    • Added a commented example for the new system-prompt-count option under Claude key configurations.
  • internal/api/handlers/management/config_lists.go
    • Added SystemPromptCount field to the claudeKeyPatch struct to enable patching this new setting.
    • Included logic to apply the SystemPromptCount from a patch to an existing Claude key entry.
    • Added validation to ensure SystemPromptCount is not negative, defaulting it to 0 if it is.
  • internal/config/config.go
    • Added SystemPromptCount field to the ClaudeKey struct, including YAML and JSON tags and documentation.
    • Incorporated sanitization logic for SystemPromptCount within SanitizeClaudeKeys to ensure it's not negative.
  • internal/runtime/executor/claude_executor.go
    • Introduced applyClaudeSystemPromptCountPolicy function to handle the enforcement of the system prompt count.
    • Called applyClaudeSystemPromptCountPolicy in Execute, ExecuteStream, and CountTokens methods to modify the request payload.
    • Refactored resolveClaudeKeyCloakConfig into a more general resolveClaudeKeyConfig to retrieve the full ClaudeKey configuration.
    • Implemented enforceSystemPromptCount function to merge or pad system prompt blocks based on the target count.
  • internal/runtime/executor/claude_executor_test.go
    • Added TestEnforceSystemPromptCount_MergeExtrasIntoSecond to verify correct merging of multiple system prompt blocks.
    • Added TestEnforceSystemPromptCount_PadsEmptyWhenMissing to confirm proper padding with empty blocks when fewer are present.
  • internal/watcher/diff/config_diff.go
    • Added logic to detect and report changes in the system-prompt-count for Claude keys when generating configuration diffs.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a system-prompt-count option for Claude providers to enforce a specific number of system prompt blocks, useful for compatibility with certain Claude-like APIs. However, a critical security vulnerability has been identified: the lack of input validation for the maximum allowed system-prompt-count creates a potential Denial of Service (DoS) vector, as a large value can lead to excessive memory allocation and server crashes. Additionally, a high-severity bug was found where non-text system prompt blocks (like cache_control) are discarded, and there's a medium-severity issue with redundant code in configuration handling.

Comment on lines +1147 to 1203
func enforceSystemPromptCount(payload []byte, targetCount int) []byte {
if targetCount <= 0 {
return payload
}
root, ok := parsePayloadObject(payload)
if !ok {
return payload
}

texts := make([]string, 0, targetCount)
appendText := func(value any) {
switch v := value.(type) {
case string:
texts = append(texts, v)
case map[string]any:
if blockType, ok := v["type"].(string); ok && blockType != "" && !strings.EqualFold(blockType, "text") {
return
}
return entry.Cloak
text, ok := v["text"].(string)
if !ok {
return
}
texts = append(texts, text)
}
}

return nil
if system, exists := root["system"]; exists {
if items, ok := asArray(system); ok {
for _, item := range items {
appendText(item)
}
} else {
appendText(system)
}
}

normalized := make([]string, 0, targetCount)
if len(texts) >= targetCount {
normalized = append(normalized, texts[:targetCount-1]...)
normalized = append(normalized, strings.Join(texts[targetCount-1:], "\n\n"))
} else {
normalized = append(normalized, texts...)
for len(normalized) < targetCount {
normalized = append(normalized, "")
}
}

blocks := make([]any, 0, targetCount)
for _, text := range normalized {
blocks = append(blocks, map[string]any{
"type": "text",
"text": text,
})
}
root["system"] = blocks
return marshalPayloadObject(payload, root)
}
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.

high

The function enforceSystemPromptCount incorrectly handles system prompts containing non-text blocks. It extracts only the text content from the system array and then reconstructs it using only text blocks. This causes any non-text blocks, such as cache_control blocks, to be discarded from the request payload. This can lead to incorrect behavior, for example, by breaking prompt caching.

The logic should be updated to preserve non-text blocks while adjusting the number of text blocks.

Comment on lines +981 to +983
if entry.SystemPromptCount < 0 {
entry.SystemPromptCount = 0
}
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.

security-medium medium

The system-prompt-count parameter lacks upper bound validation. An attacker with access to the management API could set this value to an extremely large number, leading to an Out-Of-Memory (OOM) crash of the server when enforceSystemPromptCount attempts to allocate large slices. It is recommended to enforce a reasonable upper limit (e.g., 100) for SystemPromptCount. Additionally, the existing if entry.SystemPromptCount < 0 { entry.SystemPromptCount = 0 } validation might be redundant here, as SanitizeClaudeKeys performs this exact sanitization; consider consolidating sanitization logic to avoid duplication.

if entry.SystemPromptCount < 0 {
		entry.SystemPromptCount = 0
	} else if entry.SystemPromptCount > 100 {
		entry.SystemPromptCount = 100
	}

Comment thread internal/config/config.go
Comment on lines +803 to +805
if entry.SystemPromptCount < 0 {
entry.SystemPromptCount = 0
}
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.

security-medium medium

Similar to the management API handler, the configuration sanitization logic for Claude keys lacks an upper bound check on SystemPromptCount. This could allow a maliciously crafted configuration file to cause a Denial of Service via memory exhaustion when requests are processed.

Recommendation: Enforce a reasonable upper limit (e.g., 100) for SystemPromptCount.

		if entry.SystemPromptCount < 0 {
			entry.SystemPromptCount = 0
		} else if entry.SystemPromptCount > 100 {
			entry.SystemPromptCount = 100
		}

Copy link
Copy Markdown
Collaborator

@luispater luispater left a comment

Choose a reason for hiding this comment

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

Summary:
This PR adds system-prompt-count to Claude provider config, threads it through the management API and config diff output, and enforces it in the Claude executor. I ran the targeted package tests plus a server build, and they passed. I still found two blocking correctness issues in the executor path.

Key findings:

  • Blocking: shrinking the system array can reorder text around intervening non-text system blocks.
  • Blocking: the new policy runs after cloaking, so it rewrites the Claude Code billing/agent blocks when cloak and system-prompt-count are enabled together.

Test plan:

  • go test ./internal/runtime/executor ./internal/config ./internal/watcher/diff ./internal/api/handlers/management
  • go build -o test-output ./cmd/server

Follow-ups:

  • Apply the count policy before cloaking, or explicitly exclude cloaking-injected blocks from the count.
  • Add a regression test for a mixed sequence such as [text, text, non-text, text] when shrinking to 2.

Kindness added 3 commits March 15, 2026 14:31
…s non-text blocks

- Merge adjacent text blocks from the end first, avoiding text
  content crossing non-text block boundaries.
- Fall back to cross-boundary merge only when adjacent merge
  cannot reach the target count.
- Move system-prompt-count policy before cloaking so
  cloaking-injected system blocks are excluded from the count.
- Add regression tests for mixed text/non-text sequences and
  exact-count no-op.
@Kindness-Kismet
Copy link
Copy Markdown
Author

Summary: This PR adds system-prompt-count to Claude provider config, threads it through the management API and config diff output, and enforces it in the Claude executor. I ran the targeted package tests plus a server build, and they passed. I still found two blocking correctness issues in the executor path.

Key findings:

* Blocking: shrinking the `system` array can reorder text around intervening non-text system blocks.

* Blocking: the new policy runs after cloaking, so it rewrites the Claude Code billing/agent blocks when `cloak` and `system-prompt-count` are enabled together.

Test plan:

* `go test ./internal/runtime/executor ./internal/config ./internal/watcher/diff ./internal/api/handlers/management`

* `go build -o test-output ./cmd/server`

Follow-ups:

* Apply the count policy before cloaking, or explicitly exclude cloaking-injected blocks from the count.

* Add a regression test for a mixed sequence such as `[text, text, non-text, text]` when shrinking to `2`.

Thanks! All issues have been addressed

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