feat: add pagination + body truncation to list_by_state
Prevents 181K+ responses when channels have many messages with long bodies. New params: limit (default 20, max 100), offset (default 0), max_body_length (default 500 chars when include_messages=true). Response now includes total count alongside paginated results. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
faab0f7f17
commit
91a1f2adcb
@@ -512,21 +512,24 @@ func allActions() []Action {
|
||||
{
|
||||
Name: "list_by_state",
|
||||
Category: "reactions",
|
||||
Description: "List messages in a channel filtered by workflow state. Use to find actionable work: list_by_state with state='approved' finds work ready to be claimed. States: proposed (new, awaiting approval), approved (ready for work), in_progress (claimed by agent), rejected, done, published.",
|
||||
Description: "List messages in a channel filtered by workflow state. Paginated — use limit and offset for large channels. States: proposed (new), approved (ready for work), in_progress (claimed), rejected, done, published.",
|
||||
Params: []Param{
|
||||
{Name: "channel", Type: "string", Description: "Channel name", Required: true},
|
||||
{Name: "state", Type: "string", Description: "Workflow state to filter by: proposed, approved, in_progress, rejected, done, published", Required: true},
|
||||
{Name: "include_messages", Type: "boolean", Description: "If true, include full message bodies in the response (default: false)"},
|
||||
{Name: "limit", Type: "number", Description: "Max messages to return (default 20, max 100)"},
|
||||
{Name: "offset", Type: "number", Description: "Skip first N messages for pagination (default 0)"},
|
||||
{Name: "include_messages", Type: "boolean", Description: "Include message bodies (default false). Bodies truncated to max_body_length chars."},
|
||||
{Name: "max_body_length", Type: "number", Description: "Max chars per message body when include_messages=true (default 500). Use lower values for channels with long messages."},
|
||||
},
|
||||
Returns: "JSON with message_ids array, count, and optionally messages array with id, from_agent, body, priority, created_at, reply_to",
|
||||
Returns: "JSON with message_ids, count (this page), total (all matching), limit, offset, and optionally messages array",
|
||||
Examples: []Example{
|
||||
{
|
||||
Description: "List approved messages in a channel",
|
||||
Code: `call("list_by_state", {"channel": "approvals", "state": "approved"})`,
|
||||
Description: "List first 10 approved messages with content",
|
||||
Code: `call("list_by_state", {"channel": "approvals", "state": "approved", "limit": 10, "include_messages": true})`,
|
||||
},
|
||||
{
|
||||
Description: "List approved messages with full content",
|
||||
Code: `call("list_by_state", {"channel": "approvals", "state": "approved", "include_messages": true})`,
|
||||
Description: "Paginate — get next page",
|
||||
Code: `call("list_by_state", {"channel": "approvals", "state": "proposed", "limit": 10, "offset": 10})`,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
+40
-6
@@ -1080,25 +1080,59 @@ func (b *ServiceBridge) callListByState(ctx context.Context, args map[string]any
|
||||
messageIDs = []int64{}
|
||||
}
|
||||
|
||||
totalCount := len(messageIDs)
|
||||
|
||||
// Apply limit and offset for pagination
|
||||
limit := getInt(args, "limit", 20)
|
||||
if limit <= 0 {
|
||||
limit = 20
|
||||
}
|
||||
if limit > 100 {
|
||||
limit = 100
|
||||
}
|
||||
offset := getInt(args, "offset", 0)
|
||||
if offset < 0 {
|
||||
offset = 0
|
||||
}
|
||||
if offset > len(messageIDs) {
|
||||
offset = len(messageIDs)
|
||||
}
|
||||
end := offset + limit
|
||||
if end > len(messageIDs) {
|
||||
end = len(messageIDs)
|
||||
}
|
||||
pageIDs := messageIDs[offset:end]
|
||||
|
||||
resp := map[string]any{
|
||||
"message_ids": messageIDs,
|
||||
"count": len(messageIDs),
|
||||
"message_ids": pageIDs,
|
||||
"count": len(pageIDs),
|
||||
"total": totalCount,
|
||||
"channel": channelName,
|
||||
"state": state,
|
||||
"limit": limit,
|
||||
"offset": offset,
|
||||
}
|
||||
|
||||
includeMessages := getBool(args, "include_messages", false)
|
||||
if includeMessages && len(messageIDs) > 0 && b.msgService != nil {
|
||||
if includeMessages && len(pageIDs) > 0 && b.msgService != nil {
|
||||
maxBodyLen := getInt(args, "max_body_length", 500)
|
||||
if maxBodyLen <= 0 {
|
||||
maxBodyLen = 500
|
||||
}
|
||||
var messages []map[string]any
|
||||
for _, id := range messageIDs {
|
||||
for _, id := range pageIDs {
|
||||
msg, err := b.msgService.GetMessageByID(ctx, id)
|
||||
if err != nil {
|
||||
continue // skip messages that can't be fetched
|
||||
continue
|
||||
}
|
||||
body := msg.Body
|
||||
if len(body) > maxBodyLen {
|
||||
body = body[:maxBodyLen] + "..."
|
||||
}
|
||||
messages = append(messages, map[string]any{
|
||||
"id": msg.ID,
|
||||
"from_agent": msg.FromAgent,
|
||||
"body": msg.Body,
|
||||
"body": body,
|
||||
"priority": msg.Priority,
|
||||
"created_at": msg.CreatedAt,
|
||||
"reply_to": msg.ReplyTo,
|
||||
|
||||
Reference in New Issue
Block a user