feat(messages): enforce 2000 character message length limit#324
Conversation
Add MaxMessageLength constant (2000 chars) and validate message content before dispatch to any integration, returning a clear error suggesting the sender split into multiple messages.
There was a problem hiding this comment.
Code Review
This pull request introduces a 2000-character limit (MaxMessageLength) for messages, implementing validation checks in both the agent messaging handler and the structured message validation logic, along with corresponding unit tests. The review feedback highlights two main areas for improvement: first, using utf8.RuneCountInString instead of len([]rune(...)) to avoid inefficient memory allocations; second, conditionally applying the character limit validation only to outbound agent messages rather than unconditionally to all messages, which could otherwise block valid inbound user messages.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| if len([]rune(m.Msg)) > MaxMessageLength { | ||
| return fmt.Errorf("message exceeds %d character limit (current: %d chars). Consider splitting into multiple messages using multiple scion message invocations", MaxMessageLength, len([]rune(m.Msg))) | ||
| } |
There was a problem hiding this comment.
The comment for MaxMessageLength on line 28 states:
// Maximum length of the Msg field in characters for outbound messages.
However, StructuredMessage.Validate() enforces this 2000-character limit unconditionally on all messages. This includes inbound user-to-agent messages (e.g., instructions from user:alice to agent:backend-dev). Since user prompts, code snippets, or logs can easily exceed 2000 characters, this unconditional limit will block valid inbound messages.
If the limit is indeed only intended for outbound messages (agent-to-user or agent-to-agent), we should conditionally apply this check in Validate(), for example by checking if the sender is an agent using SenderPrefix(m.Sender) == "agent".
Additionally, converting the string to []rune twice (once for the check and once for the error message) is inefficient and causes redundant memory allocations. We should use utf8.RuneCountInString(m.Msg) and store the result in a variable.
Note: You will need to import "unicode/utf8" in this file. Also, since validMsg() in types_test.go uses Sender: "user:alice", you will need to update the test cases ("msg exceeds character limit" and "msg at character limit") to set m.Sender = "agent:some-agent" so that the validation is triggered during the tests.
if SenderPrefix(m.Sender) == "agent" {
if msgLen := utf8.RuneCountInString(m.Msg); msgLen > MaxMessageLength {
return fmt.Errorf("message exceeds %d character limit (current: %d chars). Consider splitting into multiple messages using multiple scion message invocations", MaxMessageLength, msgLen)
}
}| if msgLen := len([]rune(req.Msg)); msgLen > messages.MaxMessageLength { | ||
| ValidationError(w, fmt.Sprintf("message exceeds %d character limit (current: %d chars). Consider splitting into multiple messages using multiple scion message invocations", messages.MaxMessageLength, msgLen), nil) | ||
| return | ||
| } |
There was a problem hiding this comment.
Using len([]rune(req.Msg)) to count characters in Go allocates a new slice of runes, which is inefficient and causes unnecessary memory allocations and garbage collection pressure.
Instead, use utf8.RuneCountInString(req.Msg) from the unicode/utf8 package, which counts the runes in-place with
Note: You will need to import "unicode/utf8" in this file.
| if msgLen := len([]rune(req.Msg)); msgLen > messages.MaxMessageLength { | |
| ValidationError(w, fmt.Sprintf("message exceeds %d character limit (current: %d chars). Consider splitting into multiple messages using multiple scion message invocations", messages.MaxMessageLength, msgLen), nil) | |
| return | |
| } | |
| if msgLen := utf8.RuneCountInString(req.Msg); msgLen > messages.MaxMessageLength { | |
| ValidationError(w, fmt.Sprintf("message exceeds %d character limit (current: %d chars). Consider splitting into multiple messages using multiple scion message invocations", messages.MaxMessageLength, msgLen), nil) | |
| return | |
| } |
Replace len([]rune(req.Msg)) with utf8.RuneCountInString(req.Msg) to avoid allocating a temporary []rune slice. Addresses Gemini PR GoogleCloudPlatform#524 MEDIUM finding.
Summary
MaxMessageLength = 2000constant inpkg/messages/types.goStructuredMessage.Validate()before dispatch to any integrationhandleAgentOutboundMessagehandler for agent outbound messagesTest plan
go build ./...passes