fix(monitor): inbox API returns {data:[...]} not {messages:[...]}
Some checks failed
CI / test (push) Failing after 3s

The MCP agent_inbox tool wraps the response as {messages:[...]},
but the raw API returns {data:[...]}. The monitor calls the raw
API directly, so it needs to parse {data:[...]}.

Verified with curl against live API. Removed debug channel events.

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Snider 2026-03-21 19:17:53 +00:00
parent 62b9ee7729
commit b5dcdd1261
2 changed files with 25 additions and 7 deletions

View file

@ -68,6 +68,12 @@ func New(opts ...Options) *Subsystem {
if len(opts) > 0 && opts[0].Interval > 0 {
interval = opts[0].Interval
}
// Override via env for debugging
if envInterval := os.Getenv("MONITOR_INTERVAL"); envInterval != "" {
if d, err := time.ParseDuration(envInterval); err == nil {
interval = d
}
}
return &Subsystem{
interval: interval,
poke: make(chan struct{}, 1),
@ -75,6 +81,13 @@ func New(opts ...Options) *Subsystem {
}
}
// debugChannel sends a debug message via the notifier so it arrives as a channel event.
func (m *Subsystem) debugChannel(msg string) {
if m.notifier != nil {
m.notifier.ChannelSend(context.Background(), "monitor.debug", map[string]any{"msg": msg})
}
}
func (m *Subsystem) Name() string { return "monitor" }
func (m *Subsystem) RegisterTools(server *mcp.Server) {
@ -95,6 +108,8 @@ func (m *Subsystem) Start(ctx context.Context) {
monCtx, cancel := context.WithCancel(ctx)
m.cancel = cancel
fmt.Fprintf(os.Stderr, "monitor: started (interval=%s, notifier=%v)\n", m.interval, m.notifier != nil)
m.wg.Add(1)
go func() {
defer m.wg.Done()
@ -150,6 +165,7 @@ func (m *Subsystem) loop(ctx context.Context) {
}
func (m *Subsystem) check(ctx context.Context) {
fmt.Fprintf(os.Stderr, "monitor: check cycle running\n")
var messages []string
// Check agent completions
@ -270,6 +286,7 @@ func (m *Subsystem) checkInbox() string {
keyFile := filepath.Join(home, ".claude", "brain.key")
data, err := coreio.Local.Read(keyFile)
if err != nil {
fmt.Fprintf(os.Stderr, "monitor: checkInbox: no API key (env=%v, file err=%v)\n", apiKeyStr == "", err)
return ""
}
apiKeyStr = data
@ -298,11 +315,11 @@ func (m *Subsystem) checkInbox() string {
}
var resp struct {
Messages []struct {
Data []struct {
Read bool `json:"read"`
From string `json:"from"`
Subject string `json:"subject"`
} `json:"messages"`
} `json:"data"`
}
if json.NewDecoder(httpResp.Body).Decode(&resp) != nil {
return ""
@ -311,7 +328,7 @@ func (m *Subsystem) checkInbox() string {
unread := 0
senders := make(map[string]int)
latestSubject := ""
for _, msg := range resp.Messages {
for _, msg := range resp.Data {
if !msg.Read {
unread++
if msg.From != "" {
@ -343,6 +360,7 @@ func (m *Subsystem) checkInbox() string {
}
// Push channel event for new messages
if m.notifier != nil {
fmt.Fprintf(os.Stderr, "monitor: pushing inbox.message channel event (new=%d)\n", unread-prevInbox)
m.notifier.ChannelSend(context.Background(), "inbox.message", map[string]any{
"new": unread - prevInbox,
"total": unread,

View file

@ -228,7 +228,7 @@ func TestCheckInbox_Good_UnreadMessages(t *testing.T) {
assert.NotEmpty(t, r.URL.Query().Get("agent"))
resp := map[string]any{
"messages": []map[string]any{
"data": []map[string]any{
{"read": false, "from": "clotho", "subject": "task done"},
{"read": false, "from": "gemini", "subject": "review ready"},
{"read": true, "from": "clotho", "subject": "old msg"},
@ -262,7 +262,7 @@ func TestCheckInbox_Good_UnreadMessages(t *testing.T) {
func TestCheckInbox_Good_NoUnread(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
resp := map[string]any{
"messages": []map[string]any{
"data": []map[string]any{
{"read": true, "from": "clotho", "subject": "old"},
},
}
@ -281,7 +281,7 @@ func TestCheckInbox_Good_NoUnread(t *testing.T) {
func TestCheckInbox_Good_SameCountNoRepeat(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
resp := map[string]any{
"messages": []map[string]any{
"data": []map[string]any{
{"read": false, "from": "clotho", "subject": "msg"},
},
}
@ -338,7 +338,7 @@ func TestCheckInbox_Bad_InvalidJSON(t *testing.T) {
func TestCheckInbox_Good_MultipleSameSender(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
resp := map[string]any{
"messages": []map[string]any{
"data": []map[string]any{
{"read": false, "from": "clotho", "subject": "msg1"},
{"read": false, "from": "clotho", "subject": "msg2"},
{"read": false, "from": "gemini", "subject": "msg3"},