Skip to content
This repository was archived by the owner on Sep 13, 2026. It is now read-only.

Commit 3955c3b

Browse files
committed
feat(tool_call): implement tool call logging and improve format handling
1 parent 5e25714 commit 3955c3b

7 files changed

Lines changed: 100 additions & 60 deletions

File tree

‎lib/httpapi/server.go‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,10 @@ func NewServer(ctx context.Context, config ServerConfig) (*Server, error) {
233233
return mf.IsAgentReadyForInitialPrompt(config.AgentType, message)
234234
}
235235

236+
formatToolCall := func(message string) (string, []string) {
237+
return mf.FormatToolCall(config.AgentType, message)
238+
}
239+
236240
conversation := st.NewConversation(ctx, st.ConversationConfig{
237241
AgentType: config.AgentType,
238242
AgentIO: config.Process,
@@ -243,6 +247,8 @@ func NewServer(ctx context.Context, config ServerConfig) (*Server, error) {
243247
ScreenStabilityLength: 2 * time.Second,
244248
FormatMessage: formatMessage,
245249
ReadyForInitialPrompt: isAgentReadyForInitialPrompt,
250+
FormatToolCall: formatToolCall,
251+
Logger: logger,
246252
}, config.InitialPrompt)
247253
emitter := NewEventEmitter(1024)
248254

‎lib/msgfmt/format_tool_call.go‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package msgfmt
2+
3+
import (
4+
"strings"
5+
)
6+
7+
func removeClaudeReportTaskToolCall(msg string) (string, []string) {
8+
// Remove all tool calls that start with `● coder - coder_report_task (MCP)` till we encounter the next line starting with ●
9+
lines := strings.Split(msg, "\n")
10+
11+
toolCallStartIdx := -1
12+
13+
// Store all tool call start and end indices [[start, end], ...]
14+
var toolCallIdxs [][]int
15+
16+
for i := 1; i < len(lines)-1; i++ {
17+
prevLine := strings.TrimSpace(lines[i-1])
18+
line := strings.TrimSpace(lines[i])
19+
nextLine := strings.TrimSpace(lines[i+1])
20+
21+
if strings.HasPrefix(line, "● coder - coder_report_task (MCP)") {
22+
toolCallStartIdx = i
23+
} else if toolCallStartIdx != -1 && line == "\"message\": \"Thanks for reporting!\"" && nextLine == "}" && strings.Replace(prevLine, " ", "", -1) == "⎿{" {
24+
// Store [start, end] pair
25+
toolCallIdxs = append(toolCallIdxs, []int{toolCallStartIdx, min(len(lines), i+2)})
26+
27+
// Reset to find the next tool call
28+
toolCallStartIdx = -1
29+
}
30+
}
31+
32+
// If no tool calls found, return original message
33+
if len(toolCallIdxs) == 0 {
34+
return strings.TrimSuffix(msg, "\n"), []string{}
35+
}
36+
37+
toolCallMessages := make([]string, 0)
38+
39+
// Remove tool calls from the message
40+
for i := len(toolCallIdxs) - 1; i >= 0; i-- {
41+
idxPair := toolCallIdxs[i]
42+
start, end := idxPair[0], idxPair[1]
43+
44+
toolCallMessages = append(toolCallMessages, strings.Join(lines[start:end], "\n"))
45+
46+
lines = append(lines[:start], lines[end:]...)
47+
}
48+
return strings.TrimSuffix(strings.Join(lines, "\n"), "\n\n"), toolCallMessages
49+
}
50+
51+
func FormatToolCall(agentType AgentType, message string) (string, []string) {
52+
switch agentType {
53+
case AgentTypeClaude:
54+
return removeClaudeReportTaskToolCall(message)
55+
default:
56+
return message, []string{}
57+
}
58+
}

‎lib/msgfmt/message_box.go‎

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -100,53 +100,3 @@ func removeAmpMessageBox(msg string) string {
100100
}
101101
return formattedMsg
102102
}
103-
104-
func removeClaudeReportTaskToolCall(msg string) string {
105-
// Remove all tool calls that start with `● coder - coder_report_task (MCP)` till we encounter the next line starting with ●
106-
lines := strings.Split(msg, "\n")
107-
108-
toolCallStartIdx := -1
109-
newLineAfterToolCallIdx := -1
110-
111-
// Store all tool call start and end indices [[start, end], ...]
112-
var toolCallIdxs [][]int
113-
114-
for i := 0; i < len(lines); i++ {
115-
line := strings.TrimSpace(lines[i])
116-
117-
if strings.HasPrefix(line, "● coder - coder_report_task (MCP)") {
118-
toolCallStartIdx = i
119-
} else if toolCallStartIdx != -1 && strings.HasPrefix(line, "●") {
120-
// Store [start, end] pair
121-
toolCallIdxs = append(toolCallIdxs, []int{toolCallStartIdx, i})
122-
123-
// Reset to find the next tool call
124-
toolCallStartIdx = -1
125-
newLineAfterToolCallIdx = -1
126-
}
127-
if len(line) == 0 && toolCallStartIdx != -1 && newLineAfterToolCallIdx == -1 {
128-
newLineAfterToolCallIdx = i
129-
}
130-
}
131-
132-
// Handle the case where the last tool call goes till the end of the message
133-
// And a failsafe when the next message is not prefixed with ●
134-
if toolCallStartIdx != -1 && newLineAfterToolCallIdx != -1 {
135-
toolCallIdxs = append(toolCallIdxs, []int{toolCallStartIdx, newLineAfterToolCallIdx})
136-
}
137-
138-
// If no tool calls found, return original message
139-
if len(toolCallIdxs) == 0 {
140-
return msg
141-
}
142-
143-
// Remove tool calls from the message
144-
for i := len(toolCallIdxs) - 1; i >= 0; i-- {
145-
idxPair := toolCallIdxs[i]
146-
start, end := idxPair[0], idxPair[1]
147-
148-
lines = append(lines[:start], lines[end:]...)
149-
}
150-
151-
return strings.Join(lines, "\n")
152-
}

‎lib/msgfmt/msgfmt.go‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -254,13 +254,13 @@ func formatGenericMessage(message string, userInput string, agentType AgentType)
254254
return message
255255
}
256256

257-
func formatClaudeMessage(message string, userInput string) string {
258-
message = RemoveUserInput(message, userInput, AgentTypeClaude)
259-
message = removeMessageBox(message)
260-
message = removeClaudeReportTaskToolCall(message)
261-
message = trimEmptyLines(message)
262-
return message
263-
}
257+
//func formatClaudeMessage(message string, userInput string) string {
258+
// message = RemoveUserInput(message, userInput, AgentTypeClaude)
259+
// message = removeMessageBox(message)
260+
// message = removeClaudeReportTaskToolCall(message)
261+
// message = trimEmptyLines(message)
262+
// return message
263+
//}
264264

265265
func formatCodexMessage(message string, userInput string) string {
266266
message = RemoveUserInput(message, userInput, AgentTypeCodex)
@@ -286,7 +286,7 @@ func formatAmpMessage(message string, userInput string) string {
286286
func FormatAgentMessage(agentType AgentType, message string, userInput string) string {
287287
switch agentType {
288288
case AgentTypeClaude:
289-
return formatClaudeMessage(message, userInput)
289+
return formatGenericMessage(message, userInput, agentType)
290290
case AgentTypeGoose:
291291
return formatGenericMessage(message, userInput, agentType)
292292
case AgentTypeAider:

‎lib/msgfmt/msgfmt_test.go‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,8 @@ func TestFormatAgentMessage(t *testing.T) {
233233
assert.NoError(t, err)
234234
expected, err := testdataDir.ReadFile(path.Join(dir, string(agentType), c.Name(), "expected.txt"))
235235
assert.NoError(t, err)
236-
assert.Equal(t, string(expected), FormatAgentMessage(agentType, string(msg), string(userInput)))
236+
output, _ := FormatToolCall(agentType, FormatAgentMessage(agentType, string(msg), string(userInput)))
237+
assert.Equal(t, string(expected), output)
237238
})
238239
}
239240
})

‎lib/msgfmt/testdata/format/claude/remove-task-tool-call/expected.txt‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
● I'll build a snake game for you. Let me start by reporting my
22
progress and creating a task list.
33

4+
45
● Now I'll create a complete snake game with HTML, CSS, and
56
JavaScript:
67

@@ -19,6 +20,8 @@
1920
padding: 0;
2021
… +334 lines (ctrl+o to expand)
2122

23+
24+
2225
● I've built a complete snake game for you! The game is saved
2326
at /home/coder/snake-game.html.
2427

@@ -36,4 +39,4 @@
3639
How to play:
3740
Open the HTML file in your web browser and use the arrow keys
3841
to move the snake. Collect the red food to grow and increase
39-
your score!
42+
your score!

‎lib/screentracker/conversation.go‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package screentracker
33
import (
44
"context"
55
"fmt"
6+
"log/slog"
67
"strings"
78
"sync"
89
"time"
@@ -43,6 +44,9 @@ type ConversationConfig struct {
4344
SkipSendMessageStatusCheck bool
4445
// ReadyForInitialPrompt detects whether the agent has initialized and is ready to accept the initial prompt
4546
ReadyForInitialPrompt func(message string) bool
47+
FormatToolCall func(message string) (string, []string)
48+
// Logger for logging tool calls and other events
49+
Logger *slog.Logger
4650
}
4751

4852
type ConversationRole string
@@ -82,6 +86,8 @@ type Conversation struct {
8286
InitialPromptSent bool
8387
// ReadyForInitialPrompt keeps track if the agent is ready to accept the initial prompt
8488
ReadyForInitialPrompt bool
89+
//
90+
toolCallMessageSet map[string]bool
8591
}
8692

8793
type ConversationStatus string
@@ -205,9 +211,18 @@ func (c *Conversation) lastMessage(role ConversationRole) ConversationMessage {
205211
func (c *Conversation) updateLastAgentMessage(screen string, timestamp time.Time) {
206212
agentMessage := FindNewMessage(c.screenBeforeLastUserMessage, screen, c.cfg.AgentType)
207213
lastUserMessage := c.lastMessage(ConversationRoleUser)
214+
var toolCalls []string
208215
if c.cfg.FormatMessage != nil {
209216
agentMessage = c.cfg.FormatMessage(agentMessage, lastUserMessage.Message)
210217
}
218+
if c.cfg.FormatToolCall != nil {
219+
agentMessage, toolCalls = c.cfg.FormatToolCall(agentMessage)
220+
}
221+
for _, toolCall := range toolCalls {
222+
if c.toolCallMessageSet[toolCall] == false {
223+
c.toolCallMessageSet[toolCall] = true
224+
}
225+
}
211226
shouldCreateNewMessage := len(c.messages) == 0 || c.messages[len(c.messages)-1].Role == ConversationRoleUser
212227
lastAgentMessage := c.lastMessage(ConversationRoleAgent)
213228
if lastAgentMessage.Message == agentMessage {
@@ -220,6 +235,13 @@ func (c *Conversation) updateLastAgentMessage(screen string, timestamp time.Time
220235
}
221236
if shouldCreateNewMessage {
222237
c.messages = append(c.messages, conversationMessage)
238+
// Logging all the tool calls till now
239+
for toolCall := range c.toolCallMessageSet {
240+
c.cfg.Logger.Info("Tool call detected", "toolCall", toolCall)
241+
}
242+
// Cleanup
243+
c.toolCallMessageSet = make(map[string]bool)
244+
223245
} else {
224246
c.messages[len(c.messages)-1] = conversationMessage
225247
}

0 commit comments

Comments
 (0)