Date: 2026-02-11
Task: P0 - Fix message API returning ALL messages
Issue: Agents hitting 200+ message inboxes, wasting tokens every heartbeat
The /chat/messages and /inbox/:agent endpoints were returning ALL messages by default, causing:
- Agents loading 200+ messages per heartbeat
- Token waste (130k+ tokens/day per Rhythm's analysis)
- Context window exhaustion
- Slow API responses
Added proper pagination with sensible defaults:
// Before: returned ALL messages if no limit specified
getMessages(options?: { limit?: number })
// After: default to 20 if no limit specified
const limit = options?.limit !== undefined ? options.limit : 20Added before and after params for timestamp-based pagination:
getMessages(options?: {
limit?: number // Default: 20
before?: number // Get messages before this timestamp
after?: number // Get messages after this timestamp
since?: number // Existing: minimum timestamp filter
// ... other filters
})The inbox endpoint needs to scan more messages to find @mentions/DMs, but still capped:
// Get last 100 messages for inbox scanning (vs 20 default)
const allMessages = chatManager.getMessages({ limit: 100 })Query Params:
limit(number, default: 20) - Max messages to returnbefore(timestamp) - Get messages before this timeafter(timestamp) - Get messages after this timesince(timestamp) - Get messages since this time (existing)from,to,channel(existing filters)
Examples:
# Get last 20 messages (default)
curl 'http://localhost:4445/chat/messages'
# Get last 50 messages
curl 'http://localhost:4445/chat/messages?limit=50'
# Get messages before timestamp (pagination backwards)
curl 'http://localhost:4445/chat/messages?before=1770825000000&limit=20'
# Get messages after timestamp (pagination forwards)
curl 'http://localhost:4445/chat/messages?after=1770825000000&limit=20'
# Get all messages (use with caution!)
curl 'http://localhost:4445/chat/messages?limit=0'Query Params:
limit(number, default: no limit on inbox results) - Max inbox messages to returnpriority(high|medium|low) - Filter by prioritysince(timestamp) - Only messages after this time
Note: Inbox internally fetches last 100 messages to scan for @mentions/DMs, then filters and sorts. The limit param only affects the final returned count.
Examples:
# Get inbox (returns all relevant messages found in last 100)
curl 'http://localhost:4445/inbox/link'
# Get only high-priority inbox items
curl 'http://localhost:4445/inbox/link?priority=high'
# Get last 10 inbox items
curl 'http://localhost:4445/inbox/link?limit=10'✅ Fully backwards compatible:
- Existing code that specifies
limitworks unchanged - Existing code that uses
sinceworks unchanged - New default limit only applies when NO limit is specified
- Setting
limit=0bypasses the default (returns all messages)
Before:
/chat/messages→ returned ~200 messages/inbox/:agent→ scanned ~200 messages- Agent heartbeat: ~3000 tokens/call
After:
/chat/messages→ returns 20 messages (default)/inbox/:agent→ scans 100 messages, returns relevant subset- Agent heartbeat: ~500 tokens/call (est.)
Estimated savings: ~80% token reduction for typical heartbeat patterns
# Test default limit
curl 'http://localhost:4445/chat/messages' | jq '.messages | length'
# Should return 20 (or fewer if less than 20 messages exist)
# Test custom limit
curl 'http://localhost:4445/chat/messages?limit=5' | jq '.messages | length'
# Should return 5
# Test cursor pagination
curl 'http://localhost:4445/chat/messages?limit=10' | jq '.messages[-1].timestamp'
# Copy last timestamp, then:
curl 'http://localhost:4445/chat/messages?before=<timestamp>&limit=10'
# Should return previous 10 messages
# Test inbox still works
curl 'http://localhost:4445/inbox/link?limit=10' | jq '.count'
# Should return count of inbox messages (max 10)src/
chat.ts [MODIFIED] - Added default limit, before/after params
server.ts [MODIFIED] - Pass before/after params, limit inbox scan to 100
Total changes: ~20 lines modified, 0 breaking changes
No migration required - this is a performance optimization that's fully backwards compatible.
Agents that were relying on getting ALL messages without specifying a limit will now get the last 20. To restore old behavior: add ?limit=0 to API calls.
- ✅ Deploy this fix
- Monitor token usage reduction
- Consider adding response headers with pagination cursors:
X-Next-Before: <timestamp>(for next page backwards)X-Next-After: <timestamp>(for next page forwards)
- Add rate limiting if needed
Implementation: Link 🔗
Reported by: Ryan
Priority: P0 (context window crisis)