From e18e7139bd2f00bd6cb6661522b0af4b0a1336bb Mon Sep 17 00:00:00 2001 From: Philip Zeyliger Date: Mon, 5 Jan 2026 17:02:09 +0000 Subject: [PATCH] shelley: fix agentWorking to ignore gitinfo messages Prompt: in a new worktree, reset to origin/main: i was expecting this gitinfo message to be marked end of turn gitinfo messages are passive notifications about git state changes. They should not affect whether the agent is considered to be working. Previously, a gitinfo message after an agent's end-of-turn message would cause agentWorking() to return true, because it looked like there was a new non-agent message requiring agent attention. Now we skip over trailing gitinfo messages when determining the 'last' message for the agentWorking check. --- server/agent_working_test.go | 103 +++++++++++++++++++++++++++++++++++ server/server.go | 12 +++- 2 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 server/agent_working_test.go diff --git a/server/agent_working_test.go b/server/agent_working_test.go new file mode 100644 index 0000000000000000000000000000000000000000..af825efc135fb895c982e96efd245a933d31b5c6 --- /dev/null +++ b/server/agent_working_test.go @@ -0,0 +1,103 @@ +package server + +import ( + "testing" + + "shelley.exe.dev/db" +) + +func boolPtr(b bool) *bool { + return &b +} + +func TestAgentWorking(t *testing.T) { + tests := []struct { + name string + messages []APIMessage + want bool + }{ + { + name: "empty messages", + messages: []APIMessage{}, + want: false, + }, + { + name: "agent with end_of_turn true", + messages: []APIMessage{ + {Type: string(db.MessageTypeAgent), EndOfTurn: boolPtr(true)}, + }, + want: false, + }, + { + name: "agent with end_of_turn false", + messages: []APIMessage{ + {Type: string(db.MessageTypeAgent), EndOfTurn: boolPtr(false)}, + }, + want: true, + }, + { + name: "agent with end_of_turn nil", + messages: []APIMessage{ + {Type: string(db.MessageTypeAgent), EndOfTurn: nil}, + }, + want: true, + }, + { + name: "error message", + messages: []APIMessage{ + {Type: string(db.MessageTypeError)}, + }, + want: false, + }, + { + name: "agent end_of_turn then tool message means working", + messages: []APIMessage{ + {Type: string(db.MessageTypeAgent), EndOfTurn: boolPtr(true)}, + {Type: string(db.MessageTypeTool)}, + }, + want: true, + }, + { + name: "gitinfo after agent end_of_turn should NOT indicate working", + messages: []APIMessage{ + {Type: string(db.MessageTypeAgent), EndOfTurn: boolPtr(true)}, + {Type: string(db.MessageTypeGitInfo)}, + }, + want: false, + }, + { + name: "multiple gitinfo after agent end_of_turn should NOT indicate working", + messages: []APIMessage{ + {Type: string(db.MessageTypeAgent), EndOfTurn: boolPtr(true)}, + {Type: string(db.MessageTypeGitInfo)}, + {Type: string(db.MessageTypeGitInfo)}, + }, + want: false, + }, + { + name: "gitinfo after agent not end_of_turn should indicate working", + messages: []APIMessage{ + {Type: string(db.MessageTypeAgent), EndOfTurn: boolPtr(false)}, + {Type: string(db.MessageTypeGitInfo)}, + }, + want: true, + }, + { + name: "only gitinfo messages", + messages: []APIMessage{ + {Type: string(db.MessageTypeGitInfo)}, + {Type: string(db.MessageTypeGitInfo)}, + }, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := agentWorking(tt.messages) + if got != tt.want { + t.Errorf("agentWorking() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/server/server.go b/server/server.go index 410c780995057d0f0d19c8b30bfb5fd7576971fa..3c5d421e52b6819abd56999601ae03a74d6c3767 100644 --- a/server/server.go +++ b/server/server.go @@ -147,7 +147,15 @@ func agentWorking(messages []APIMessage) bool { return false } - last := messages[len(messages)-1] + // Find the last non-gitinfo message (gitinfo messages are passive notifications) + lastIdx := len(messages) - 1 + for lastIdx >= 0 && messages[lastIdx].Type == string(db.MessageTypeGitInfo) { + lastIdx-- + } + if lastIdx < 0 { + return false + } + last := messages[lastIdx] // If the last message is an error, agent is not working if last.Type == string(db.MessageTypeError) { @@ -161,7 +169,7 @@ func agentWorking(messages []APIMessage) bool { return !*last.EndOfTurn } - for i := len(messages) - 1; i >= 0; i-- { + for i := lastIdx; i >= 0; i-- { msg := messages[i] if msg.Type != string(db.MessageTypeAgent) { continue