Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions pkg/hub/handlers_agent_messaging.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"net/http"
"strings"
"time"
"unicode/utf8"

"github.com/GoogleCloudPlatform/scion/pkg/agent/state"
"github.com/GoogleCloudPlatform/scion/pkg/api"
Expand Down Expand Up @@ -68,6 +69,10 @@ func (s *Server) handleAgentOutboundMessage(w http.ResponseWriter, r *http.Reque
ValidationError(w, "msg is required", 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
}
if req.Type == "" {
req.Type = "input-needed"
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/messages/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import (
// Schema version for the structured message format.
const Version = 1

// Maximum length of the Msg field in characters for outbound messages.
const MaxMessageLength = 2000

// Maximum size of the Msg field in bytes.
const MaxMsgSize = 64 * 1024 // 64KB

Expand Down Expand Up @@ -127,6 +130,9 @@ func (m *StructuredMessage) Validate() error {
if m.Msg == "" {
return fmt.Errorf("msg field is required")
}
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)))
}
Comment on lines +133 to +135

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

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 len(m.Msg) > MaxMsgSize {
return fmt.Errorf("msg exceeds maximum size of %d bytes", MaxMsgSize)
}
Expand Down
19 changes: 19 additions & 0 deletions pkg/messages/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,25 @@ func TestStructuredMessage_Validate(t *testing.T) {
}
})

t.Run("msg exceeds character limit", func(t *testing.T) {
m := validMsg()
m.Msg = strings.Repeat("x", MaxMessageLength+1)
err := m.Validate()
if err == nil {
t.Error("expected error for msg exceeding character limit")
} else if !strings.Contains(err.Error(), "character limit") {
t.Errorf("error should mention character limit, got: %v", err)
}
})

t.Run("msg at character limit", func(t *testing.T) {
m := validMsg()
m.Msg = strings.Repeat("x", MaxMessageLength)
if err := m.Validate(); err != nil {
t.Errorf("unexpected error for msg at character limit: %v", err)
}
})

t.Run("msg too large", func(t *testing.T) {
m := validMsg()
m.Msg = strings.Repeat("x", MaxMsgSize+1)
Expand Down
Loading