test: test all the tool calls

Kujtim Hoxha created

Change summary

internal/agent/agent.go                                                            |   2 
internal/agent/agent_test.go                                                       | 520 
internal/agent/common_test.go                                                      |   8 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/bash_tool.yaml             |  72 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/download_tool.yaml         |  66 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/fetch_tool.yaml            |  72 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/glob_tool.yaml             |  66 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/grep_tool.yaml             |  66 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/ls_tool.yaml               |  66 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/multiedit_tool.yaml        |  78 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/parallel_tool_calls.yaml   |  69 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/read_a_file.yaml           |  46 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/simple_test.yaml           |  42 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/sourcegraph_tool.yaml      |  72 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/update_a_file.yaml         |  69 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/write_tool.yaml            |  75 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/bash_tool.yaml                 |  59 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/download_tool.yaml             |  61 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/fetch_tool.yaml                |  69 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/glob_tool.yaml                 |  65 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/grep_tool.yaml                 |  65 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/ls_tool.yaml                   |  59 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/multiedit_tool.yaml            |  65 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/parallel_tool_calls.yaml       |  67 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/read_a_file.yaml               |  76 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/simple_test.yaml               |  44 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/sourcegraph_tool.yaml          |  69 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/update_a_file.yaml             |  67 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/write_tool.yaml                |  59 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/bash_tool.yaml           |  63 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/download_tool.yaml       |  55 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/fetch_tool.yaml          |  57 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/glob_tool.yaml           |  55 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/grep_tool.yaml           |  53 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/ls_tool.yaml             |  53 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/multiedit_tool.yaml      |  73 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/parallel_tool_calls.yaml |  10 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/read_a_file.yaml         |   2 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/simple_test.yaml         |  22 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/sourcegraph_tool.yaml    |  59 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/update_a_file.yaml       |  10 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/write_tool.yaml          |  59 
internal/agent/tools/download.go                                                   |  18 
internal/agent/tools/fetch.go                                                      |  18 
internal/agent/tools/sourcegraph.go                                                |  18 
internal/shell/persistent.go                                                       |   6 
46 files changed, 2,694 insertions(+), 151 deletions(-)

Detailed changes

internal/agent/agent.go 🔗

@@ -11,8 +11,8 @@ import (
 	"time"
 
 	"github.com/charmbracelet/catwalk/pkg/catwalk"
+	"github.com/charmbracelet/crush/internal/agent/tools"
 	"github.com/charmbracelet/crush/internal/csync"
-	"github.com/charmbracelet/crush/internal/llm/tools"
 	"github.com/charmbracelet/crush/internal/message"
 	"github.com/charmbracelet/crush/internal/permission"
 	"github.com/charmbracelet/crush/internal/session"

internal/agent/agent_test.go 🔗

@@ -1,16 +1,18 @@
 package agent
 
 import (
-	"encoding/json"
-	"fmt"
+	"os"
+	"path/filepath"
 	"strings"
 	"testing"
 
 	"github.com/charmbracelet/crush/internal/agent/tools"
 	"github.com/charmbracelet/crush/internal/message"
+	"github.com/charmbracelet/crush/internal/shell"
 	"github.com/charmbracelet/fantasy/ai"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
+	"gopkg.in/dnaeon/go-vcr.v4/pkg/recorder"
 
 	_ "github.com/joho/godotenv/autoload"
 )
@@ -21,8 +23,7 @@ var modelPairs = []modelPair{
 	{"openrouter-kimi-k2", openRouterBuilder("moonshotai/kimi-k2-0905"), openRouterBuilder("qwen/qwen3-next-80b-a3b-instruct")},
 }
 
-func getModels(t *testing.T, pair modelPair) (ai.LanguageModel, ai.LanguageModel) {
-	r := newRecorder(t)
+func getModels(t *testing.T, r *recorder.Recorder, pair modelPair) (ai.LanguageModel, ai.LanguageModel) {
 	large, err := pair.largeModel(t, r)
 	require.NoError(t, err)
 	small, err := pair.smallModel(t, r)
@@ -31,11 +32,13 @@ func getModels(t *testing.T, pair modelPair) (ai.LanguageModel, ai.LanguageModel
 }
 
 func setupAgent(t *testing.T, pair modelPair) (SessionAgent, env) {
-	large, small := getModels(t, pair)
+	r := newRecorder(t)
+	large, small := getModels(t, r, pair)
 	env := testEnv(t)
 
 	createSimpleGoProject(t, env.workingDir)
-	agent, err := coderAgent(env, large, small)
+	agent, err := coderAgent(r, env, large, small)
+	shell.Reset(env.workingDir)
 	require.NoError(t, err)
 	return agent, env
 }
@@ -82,8 +85,6 @@ func TestCoderAgent(t *testing.T) {
 				var tcID string
 			out:
 				for _, msg := range msgs {
-					data, _ := json.Marshal(msg)
-					fmt.Println(string(data))
 					if msg.Role == message.Assistant {
 						for _, tc := range msg.ToolCalls() {
 							if tc.Name == tools.ViewToolName {
@@ -104,6 +105,509 @@ func TestCoderAgent(t *testing.T) {
 				}
 				require.True(t, foundFile)
 			})
+			t.Run("update a file", func(t *testing.T) {
+				agent, env := setupAgent(t, pair)
+
+				session, err := env.sessions.Create(t.Context(), "New Session")
+				require.NoError(t, err)
+
+				res, err := agent.Run(t.Context(), SessionAgentCall{
+					Prompt:          "update the main.go file by changing the print to say hello from crush",
+					SessionID:       session.ID,
+					MaxOutputTokens: 10000,
+				})
+				require.NoError(t, err)
+				assert.NotNil(t, res)
+
+				msgs, err := env.messages.List(t.Context(), session.ID)
+				require.NoError(t, err)
+
+				foundRead := false
+				foundWrite := false
+				var readTCID, writeTCID string
+
+				for _, msg := range msgs {
+					if msg.Role == message.Assistant {
+						for _, tc := range msg.ToolCalls() {
+							if tc.Name == tools.ViewToolName {
+								readTCID = tc.ID
+							}
+							if tc.Name == tools.EditToolName || tc.Name == tools.WriteToolName {
+								writeTCID = tc.ID
+							}
+						}
+					}
+					if msg.Role == message.Tool {
+						for _, tr := range msg.ToolResults() {
+							if tr.ToolCallID == readTCID {
+								foundRead = true
+							}
+							if tr.ToolCallID == writeTCID {
+								foundWrite = true
+							}
+						}
+					}
+				}
+
+				require.True(t, foundRead, "Expected to find a read operation")
+				require.True(t, foundWrite, "Expected to find a write operation")
+
+				mainGoPath := filepath.Join(env.workingDir, "main.go")
+				content, err := os.ReadFile(mainGoPath)
+				require.NoError(t, err)
+				require.Contains(t, strings.ToLower(string(content)), "hello from crush")
+			})
+			t.Run("bash tool", func(t *testing.T) {
+				agent, env := setupAgent(t, pair)
+
+				session, err := env.sessions.Create(t.Context(), "New Session")
+				require.NoError(t, err)
+
+				res, err := agent.Run(t.Context(), SessionAgentCall{
+					Prompt:          "use bash to create a file named test.txt with content 'hello bash'",
+					SessionID:       session.ID,
+					MaxOutputTokens: 10000,
+				})
+				require.NoError(t, err)
+				assert.NotNil(t, res)
+
+				msgs, err := env.messages.List(t.Context(), session.ID)
+				require.NoError(t, err)
+
+				foundBash := false
+				var bashTCID string
+
+				for _, msg := range msgs {
+					if msg.Role == message.Assistant {
+						for _, tc := range msg.ToolCalls() {
+							if tc.Name == tools.BashToolName {
+								bashTCID = tc.ID
+							}
+						}
+					}
+					if msg.Role == message.Tool {
+						for _, tr := range msg.ToolResults() {
+							if tr.ToolCallID == bashTCID {
+								foundBash = true
+							}
+						}
+					}
+				}
+
+				require.True(t, foundBash, "Expected to find a bash operation")
+
+				testFilePath := filepath.Join(env.workingDir, "test.txt")
+				content, err := os.ReadFile(testFilePath)
+				require.NoError(t, err)
+				require.Contains(t, string(content), "hello bash")
+			})
+			t.Run("download tool", func(t *testing.T) {
+				agent, env := setupAgent(t, pair)
+
+				session, err := env.sessions.Create(t.Context(), "New Session")
+				require.NoError(t, err)
+
+				res, err := agent.Run(t.Context(), SessionAgentCall{
+					Prompt:          "download the file from https://httpbin.org/robots.txt and save it as robots.txt",
+					SessionID:       session.ID,
+					MaxOutputTokens: 10000,
+				})
+				require.NoError(t, err)
+				assert.NotNil(t, res)
+
+				msgs, err := env.messages.List(t.Context(), session.ID)
+				require.NoError(t, err)
+
+				foundDownload := false
+				var downloadTCID string
+
+				for _, msg := range msgs {
+					if msg.Role == message.Assistant {
+						for _, tc := range msg.ToolCalls() {
+							if tc.Name == tools.DownloadToolName {
+								downloadTCID = tc.ID
+							}
+						}
+					}
+					if msg.Role == message.Tool {
+						for _, tr := range msg.ToolResults() {
+							if tr.ToolCallID == downloadTCID {
+								foundDownload = true
+							}
+						}
+					}
+				}
+
+				require.True(t, foundDownload, "Expected to find a download operation")
+
+				robotsPath := filepath.Join(env.workingDir, "robots.txt")
+				_, err = os.Stat(robotsPath)
+				require.NoError(t, err, "Expected robots.txt file to exist")
+			})
+			t.Run("fetch tool", func(t *testing.T) {
+				agent, env := setupAgent(t, pair)
+
+				session, err := env.sessions.Create(t.Context(), "New Session")
+				require.NoError(t, err)
+
+				res, err := agent.Run(t.Context(), SessionAgentCall{
+					Prompt:          "fetch the content from https://httpbin.org/html and tell me if it contains the word 'Herman'",
+					SessionID:       session.ID,
+					MaxOutputTokens: 10000,
+				})
+				require.NoError(t, err)
+				assert.NotNil(t, res)
+
+				msgs, err := env.messages.List(t.Context(), session.ID)
+				require.NoError(t, err)
+
+				foundFetch := false
+				var fetchTCID string
+
+				for _, msg := range msgs {
+					if msg.Role == message.Assistant {
+						for _, tc := range msg.ToolCalls() {
+							if tc.Name == tools.FetchToolName {
+								fetchTCID = tc.ID
+							}
+						}
+					}
+					if msg.Role == message.Tool {
+						for _, tr := range msg.ToolResults() {
+							if tr.ToolCallID == fetchTCID {
+								foundFetch = true
+							}
+						}
+					}
+				}
+
+				require.True(t, foundFetch, "Expected to find a fetch operation")
+			})
+			t.Run("glob tool", func(t *testing.T) {
+				agent, env := setupAgent(t, pair)
+
+				session, err := env.sessions.Create(t.Context(), "New Session")
+				require.NoError(t, err)
+
+				res, err := agent.Run(t.Context(), SessionAgentCall{
+					Prompt:          "use glob to find all .go files in the current directory",
+					SessionID:       session.ID,
+					MaxOutputTokens: 10000,
+				})
+				require.NoError(t, err)
+				assert.NotNil(t, res)
+
+				msgs, err := env.messages.List(t.Context(), session.ID)
+				require.NoError(t, err)
+
+				foundGlob := false
+				var globTCID string
+
+				for _, msg := range msgs {
+					if msg.Role == message.Assistant {
+						for _, tc := range msg.ToolCalls() {
+							if tc.Name == tools.GlobToolName {
+								globTCID = tc.ID
+							}
+						}
+					}
+					if msg.Role == message.Tool {
+						for _, tr := range msg.ToolResults() {
+							if tr.ToolCallID == globTCID {
+								foundGlob = true
+								require.Contains(t, tr.Content, "main.go", "Expected glob to find main.go")
+							}
+						}
+					}
+				}
+
+				require.True(t, foundGlob, "Expected to find a glob operation")
+			})
+			t.Run("grep tool", func(t *testing.T) {
+				agent, env := setupAgent(t, pair)
+
+				session, err := env.sessions.Create(t.Context(), "New Session")
+				require.NoError(t, err)
+
+				res, err := agent.Run(t.Context(), SessionAgentCall{
+					Prompt:          "use grep to search for the word 'package' in go files",
+					SessionID:       session.ID,
+					MaxOutputTokens: 10000,
+				})
+				require.NoError(t, err)
+				assert.NotNil(t, res)
+
+				msgs, err := env.messages.List(t.Context(), session.ID)
+				require.NoError(t, err)
+
+				foundGrep := false
+				var grepTCID string
+
+				for _, msg := range msgs {
+					if msg.Role == message.Assistant {
+						for _, tc := range msg.ToolCalls() {
+							if tc.Name == tools.GrepToolName {
+								grepTCID = tc.ID
+							}
+						}
+					}
+					if msg.Role == message.Tool {
+						for _, tr := range msg.ToolResults() {
+							if tr.ToolCallID == grepTCID {
+								foundGrep = true
+								require.Contains(t, tr.Content, "main.go", "Expected grep to find main.go")
+							}
+						}
+					}
+				}
+
+				require.True(t, foundGrep, "Expected to find a grep operation")
+			})
+			t.Run("ls tool", func(t *testing.T) {
+				agent, env := setupAgent(t, pair)
+
+				session, err := env.sessions.Create(t.Context(), "New Session")
+				require.NoError(t, err)
+
+				res, err := agent.Run(t.Context(), SessionAgentCall{
+					Prompt:          "use ls to list the files in the current directory",
+					SessionID:       session.ID,
+					MaxOutputTokens: 10000,
+				})
+				require.NoError(t, err)
+				assert.NotNil(t, res)
+
+				msgs, err := env.messages.List(t.Context(), session.ID)
+				require.NoError(t, err)
+
+				foundLS := false
+				var lsTCID string
+
+				for _, msg := range msgs {
+					if msg.Role == message.Assistant {
+						for _, tc := range msg.ToolCalls() {
+							if tc.Name == tools.LSToolName {
+								lsTCID = tc.ID
+							}
+						}
+					}
+					if msg.Role == message.Tool {
+						for _, tr := range msg.ToolResults() {
+							if tr.ToolCallID == lsTCID {
+								foundLS = true
+								require.Contains(t, tr.Content, "main.go", "Expected ls to list main.go")
+								require.Contains(t, tr.Content, "go.mod", "Expected ls to list go.mod")
+							}
+						}
+					}
+				}
+
+				require.True(t, foundLS, "Expected to find an ls operation")
+			})
+			t.Run("multiedit tool", func(t *testing.T) {
+				agent, env := setupAgent(t, pair)
+
+				session, err := env.sessions.Create(t.Context(), "New Session")
+				require.NoError(t, err)
+
+				res, err := agent.Run(t.Context(), SessionAgentCall{
+					Prompt:          "use multiedit to change 'Hello, World!' to 'Hello, Crush!' and add a comment '// Greeting' above the fmt.Println line in main.go",
+					SessionID:       session.ID,
+					MaxOutputTokens: 10000,
+				})
+				require.NoError(t, err)
+				assert.NotNil(t, res)
+
+				msgs, err := env.messages.List(t.Context(), session.ID)
+				require.NoError(t, err)
+
+				foundMultiEdit := false
+				var multiEditTCID string
+
+				for _, msg := range msgs {
+					if msg.Role == message.Assistant {
+						for _, tc := range msg.ToolCalls() {
+							if tc.Name == tools.MultiEditToolName {
+								multiEditTCID = tc.ID
+							}
+						}
+					}
+					if msg.Role == message.Tool {
+						for _, tr := range msg.ToolResults() {
+							if tr.ToolCallID == multiEditTCID {
+								foundMultiEdit = true
+							}
+						}
+					}
+				}
+
+				require.True(t, foundMultiEdit, "Expected to find a multiedit operation")
+
+				mainGoPath := filepath.Join(env.workingDir, "main.go")
+				content, err := os.ReadFile(mainGoPath)
+				require.NoError(t, err)
+				require.Contains(t, string(content), "Hello, Crush!", "Expected file to contain 'Hello, Crush!'")
+			})
+			t.Run("sourcegraph tool", func(t *testing.T) {
+				agent, env := setupAgent(t, pair)
+
+				session, err := env.sessions.Create(t.Context(), "New Session")
+				require.NoError(t, err)
+
+				res, err := agent.Run(t.Context(), SessionAgentCall{
+					Prompt:          "use sourcegraph to search for 'func main' in Go repositories",
+					SessionID:       session.ID,
+					MaxOutputTokens: 10000,
+				})
+				require.NoError(t, err)
+				assert.NotNil(t, res)
+
+				msgs, err := env.messages.List(t.Context(), session.ID)
+				require.NoError(t, err)
+
+				foundSourcegraph := false
+				var sourcegraphTCID string
+
+				for _, msg := range msgs {
+					if msg.Role == message.Assistant {
+						for _, tc := range msg.ToolCalls() {
+							if tc.Name == tools.SourcegraphToolName {
+								sourcegraphTCID = tc.ID
+							}
+						}
+					}
+					if msg.Role == message.Tool {
+						for _, tr := range msg.ToolResults() {
+							if tr.ToolCallID == sourcegraphTCID {
+								foundSourcegraph = true
+							}
+						}
+					}
+				}
+
+				require.True(t, foundSourcegraph, "Expected to find a sourcegraph operation")
+			})
+			t.Run("write tool", func(t *testing.T) {
+				agent, env := setupAgent(t, pair)
+
+				session, err := env.sessions.Create(t.Context(), "New Session")
+				require.NoError(t, err)
+
+				res, err := agent.Run(t.Context(), SessionAgentCall{
+					Prompt:          "use write to create a new file called config.json with content '{\"name\": \"test\", \"version\": \"1.0.0\"}'",
+					SessionID:       session.ID,
+					MaxOutputTokens: 10000,
+				})
+				require.NoError(t, err)
+				assert.NotNil(t, res)
+
+				msgs, err := env.messages.List(t.Context(), session.ID)
+				require.NoError(t, err)
+
+				foundWrite := false
+				var writeTCID string
+
+				for _, msg := range msgs {
+					if msg.Role == message.Assistant {
+						for _, tc := range msg.ToolCalls() {
+							if tc.Name == tools.WriteToolName {
+								writeTCID = tc.ID
+							}
+						}
+					}
+					if msg.Role == message.Tool {
+						for _, tr := range msg.ToolResults() {
+							if tr.ToolCallID == writeTCID {
+								foundWrite = true
+							}
+						}
+					}
+				}
+
+				require.True(t, foundWrite, "Expected to find a write operation")
+
+				configPath := filepath.Join(env.workingDir, "config.json")
+				content, err := os.ReadFile(configPath)
+				require.NoError(t, err)
+				require.Contains(t, string(content), "test", "Expected config.json to contain 'test'")
+				require.Contains(t, string(content), "1.0.0", "Expected config.json to contain '1.0.0'")
+			})
+			t.Run("parallel tool calls", func(t *testing.T) {
+				agent, env := setupAgent(t, pair)
+
+				session, err := env.sessions.Create(t.Context(), "New Session")
+				require.NoError(t, err)
+
+				res, err := agent.Run(t.Context(), SessionAgentCall{
+					Prompt:          "use glob to find all .go files and use ls to list the current directory, it is very important that you run both tool calls in parallel",
+					SessionID:       session.ID,
+					MaxOutputTokens: 10000,
+				})
+				require.NoError(t, err)
+				assert.NotNil(t, res)
+
+				msgs, err := env.messages.List(t.Context(), session.ID)
+				require.NoError(t, err)
+
+				var assistantMsg *message.Message
+				var toolMsgs []message.Message
+
+				for _, msg := range msgs {
+					if msg.Role == message.Assistant && len(msg.ToolCalls()) > 0 {
+						assistantMsg = &msg
+					}
+					if msg.Role == message.Tool {
+						toolMsgs = append(toolMsgs, msg)
+					}
+				}
+
+				require.NotNil(t, assistantMsg, "Expected to find an assistant message with tool calls")
+				require.NotNil(t, toolMsgs, "Expected to find a tool message")
+
+				toolCalls := assistantMsg.ToolCalls()
+				require.GreaterOrEqual(t, len(toolCalls), 2, "Expected at least 2 tool calls in parallel")
+
+				foundGlob := false
+				foundLS := false
+				var globTCID, lsTCID string
+
+				for _, tc := range toolCalls {
+					if tc.Name == tools.GlobToolName {
+						foundGlob = true
+						globTCID = tc.ID
+					}
+					if tc.Name == tools.LSToolName {
+						foundLS = true
+						lsTCID = tc.ID
+					}
+				}
+
+				require.True(t, foundGlob, "Expected to find a glob tool call")
+				require.True(t, foundLS, "Expected to find an ls tool call")
+
+				require.GreaterOrEqual(t, len(toolMsgs), 2, "Expected at least 2 tool results in the same message")
+
+				foundGlobResult := false
+				foundLSResult := false
+
+				for _, msg := range toolMsgs {
+					for _, tr := range msg.ToolResults() {
+						if tr.ToolCallID == globTCID {
+							foundGlobResult = true
+							require.Contains(t, tr.Content, "main.go", "Expected glob result to contain main.go")
+							require.False(t, tr.IsError, "Expected glob result to not be an error")
+						}
+						if tr.ToolCallID == lsTCID {
+							foundLSResult = true
+							require.Contains(t, tr.Content, "main.go", "Expected ls result to contain main.go")
+							require.False(t, tr.IsError, "Expected ls result to not be an error")
+						}
+					}
+				}
+
+				require.True(t, foundGlobResult, "Expected to find glob tool result")
+				require.True(t, foundLSResult, "Expected to find ls tool result")
+			})
 		})
 	}
 }

internal/agent/common_test.go 🔗

@@ -129,7 +129,7 @@ func testSessionAgent(env env, large, small ai.LanguageModel, systemPrompt strin
 	return agent
 }
 
-func coderAgent(env env, large, small ai.LanguageModel) (SessionAgent, error) {
+func coderAgent(r *recorder.Recorder, env env, large, small ai.LanguageModel) (SessionAgent, error) {
 	fixedTime := func() time.Time {
 		t, _ := time.Parse("1/2/2006", "1/1/2025")
 		return t
@@ -149,14 +149,14 @@ func coderAgent(env env, large, small ai.LanguageModel) (SessionAgent, error) {
 	}
 	allTools := []ai.AgentTool{
 		tools.NewBashTool(env.permissions, env.workingDir, cfg.Options.Attribution),
-		tools.NewDownloadTool(env.permissions, env.workingDir),
+		tools.NewDownloadTool(env.permissions, env.workingDir, r.GetDefaultClient()),
 		tools.NewEditTool(env.lspClients, env.permissions, env.history, env.workingDir),
 		tools.NewMultiEditTool(env.lspClients, env.permissions, env.history, env.workingDir),
-		tools.NewFetchTool(env.permissions, env.workingDir),
+		tools.NewFetchTool(env.permissions, env.workingDir, r.GetDefaultClient()),
 		tools.NewGlobTool(env.workingDir),
 		tools.NewGrepTool(env.workingDir),
 		tools.NewLsTool(env.permissions, env.workingDir),
-		tools.NewSourcegraphTool(),
+		tools.NewSourcegraphTool(r.GetDefaultClient()),
 		tools.NewViewTool(env.lspClients, env.permissions, env.workingDir),
 		tools.NewWriteTool(env.lspClients, env.permissions, env.history, env.workingDir),
 	}

internal/agent/testdata/TestCoderAgent/anthropic-sonnet/bash_tool.yaml 🔗

@@ -0,0 +1,210 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 681
+    host: ""
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse bash to create a file named test.txt with content ''hello bash''","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","type":"text"}],"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - Anthropic/Go 1.12.0
+    url: https://api.anthropic.com/v1/messages
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      event: message_start
+      data: {"type":"message_start","message":{"id":"msg_01QzWSMWaFuRgJiu1L3Z9Hdb","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":124,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":2,"service_tier":"standard"}}      }
+
+      event: content_block_start
+      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}               }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Bash"}          }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" File"}}
+
+      event: ping
+      data: {"type": "ping"}
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Creation"}         }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Comman"}  }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"d"}              }
+
+      event: content_block_stop
+      data: {"type":"content_block_stop","index":0          }
+
+      event: message_delta
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":124,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":8}  }
+
+      event: message_stop
+      data: {"type":"message_stop"   }
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 599.662167ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 31962
+    host: ""

internal/agent/testdata/TestCoderAgent/anthropic-sonnet/download_tool.yaml 🔗

@@ -0,0 +1,224 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 694
+    host: ""
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\ndownload the file from https://httpbin.org/robots.txt and save it as robots.txt","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","type":"text"}],"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - Anthropic/Go 1.12.0
+    url: https://api.anthropic.com/v1/messages
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      event: message_start
+      data: {"type":"message_start","message":{"id":"msg_01NnjK5tLEiEwApinNWddYUP","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":128,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":2,"service_tier":"standard"}}          }
+
+      event: content_block_start
+      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}              }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Download robots"}           }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":".txt from"}             }
+
+      event: ping
+      data: {"type": "ping"}
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" URL"}   }
+
+      event: content_block_stop
+      data: {"type":"content_block_stop","index":0      }
+
+      event: message_delta
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":128,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":9}             }
+
+      event: message_stop
+      data: {"type":"message_stop"     }
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 604.190791ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 31979
+    host: ""

internal/agent/testdata/TestCoderAgent/anthropic-sonnet/fetch_tool.yaml 🔗

@@ -0,0 +1,239 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 707
+    host: ""
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nfetch the content from https://httpbin.org/html and tell me if it contains the word ''Herman''","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","type":"text"}],"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - Anthropic/Go 1.12.0
+    url: https://api.anthropic.com/v1/messages
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      event: message_start
+      data: {"type":"message_start","message":{"id":"msg_013MFwdf3Gw2NahRrEvZCRh5","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":131,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard"}}         }
+
+      event: content_block_start
+      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}    }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Web"}               }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Page"}               }
+
+      event: ping
+      data: {"type": "ping"}
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Content Check"}   }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" for"}               }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Herman"}          }
+
+      event: content_block_stop
+      data: {"type":"content_block_stop","index":0 }
+
+      event: message_delta
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":131,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":9}             }
+
+      event: message_stop
+      data: {"type":"message_stop"   }
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 605.181708ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 31989
+    host: ""

internal/agent/testdata/TestCoderAgent/anthropic-sonnet/glob_tool.yaml 🔗

@@ -0,0 +1,177 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 670
+    host: ""
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse glob to find all .go files in the current directory","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","type":"text"}],"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - Anthropic/Go 1.12.0
+    url: https://api.anthropic.com/v1/messages
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      event: message_start
+      data: {"type":"message_start","message":{"id":"msg_01BzJrW3i8S6Q8NBkzCJnzWx","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":119,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard"}}            }
+
+      event: content_block_start
+      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}              }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Fin"}      }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"d Go"}  }
+
+      event: ping
+      data: {"type": "ping"}
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" files in current directory"}  }
+
+      event: content_block_stop
+      data: {"type":"content_block_stop","index":0          }
+
+      event: message_delta
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":119,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":9}     }
+
+      event: message_stop
+      data: {"type":"message_stop"    }
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 655.657583ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 31951
+    host: ""

internal/agent/testdata/TestCoderAgent/anthropic-sonnet/grep_tool.yaml 🔗

@@ -0,0 +1,183 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 668
+    host: ""
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse grep to search for the word ''package'' in go files","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","type":"text"}],"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - Anthropic/Go 1.12.0
+    url: https://api.anthropic.com/v1/messages
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      event: message_start
+      data: {"type":"message_start","message":{"id":"msg_01NLe4eaXKvYXxkz6JGpS1zn","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":121,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":2,"service_tier":"standard"}}        }
+
+      event: content_block_start
+      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}            }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Grep"}             }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" for 'package'"}              }
+
+      event: ping
+      data: {"type": "ping"}
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" in Go Files"}  }
+
+      event: content_block_stop
+      data: {"type":"content_block_stop","index":0  }
+
+      event: message_delta
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":121,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":13}}
+
+      event: message_stop
+      data: {"type":"message_stop"  }
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 629.556417ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 31949
+    host: ""

internal/agent/testdata/TestCoderAgent/anthropic-sonnet/ls_tool.yaml 🔗

@@ -0,0 +1,171 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 664
+    host: ""
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse ls to list the files in the current directory","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","type":"text"}],"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - Anthropic/Go 1.12.0
+    url: https://api.anthropic.com/v1/messages
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      event: message_start
+      data: {"type":"message_start","message":{"id":"msg_01TWV6WCFaUugY2ckiR39tRe","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":117,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard"}}   }
+
+      event: content_block_start
+      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}       }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"List"}            }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Files"}   }
+
+      event: ping
+      data: {"type": "ping"}
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" in Current Directory"}             }
+
+      event: content_block_stop
+      data: {"type":"content_block_stop","index":0               }
+
+      event: message_delta
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":117,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":8}       }
+
+      event: message_stop
+      data: {"type":"message_stop"  }
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 723.497791ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 31943
+    host: ""

internal/agent/testdata/TestCoderAgent/anthropic-sonnet/multiedit_tool.yaml 🔗

@@ -0,0 +1,389 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 743
+    host: ""
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse multiedit to change ''Hello, World!'' to ''Hello, Crush!'' and add a comment ''// Greeting'' above the fmt.Println line in main.go","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","type":"text"}],"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - Anthropic/Go 1.12.0
+    url: https://api.anthropic.com/v1/messages
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      event: message_start
+      data: {"type":"message_start","message":{"id":"msg_0186hQ5FUzms1HhHfBaWNzEG","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":147,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":2,"service_tier":"standard"}}               }
+
+      event: content_block_start
+      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}             }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Modify"}}
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Hello"}         }
+
+      event: ping
+      data: {"type": "ping"}
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Worl"}  }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"d greeting"}     }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" in"}        }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Go"}             }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" file"}}
+
+      event: content_block_stop
+      data: {"type":"content_block_stop","index":0   }
+
+      event: message_delta
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":147,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":11}     }
+
+      event: message_stop
+      data: {"type":"message_stop"              }
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 637.583375ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 32029
+    host: ""

internal/agent/testdata/TestCoderAgent/anthropic-sonnet/parallel_tool_calls.yaml 🔗

@@ -0,0 +1,192 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 749
+    host: ""
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse glob to find all .go files and use ls to list the current directory, it is very important that you run both tool calls in parallel","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","type":"text"}],"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - Anthropic/Go 1.12.0
+    url: https://api.anthropic.com/v1/messages
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      event: message_start
+      data: {"type":"message_start","message":{"id":"msg_01XwN3GAPxs7Gk6g4dsMGvCr","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":136,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":2,"service_tier":"standard"}}           }
+
+      event: content_block_start
+      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}        }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Parallel"}     }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Go File"}       }
+
+      event: ping
+      data: {"type": "ping"}
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Discovery"}           }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" and Listing"}    }
+
+      event: content_block_stop
+      data: {"type":"content_block_stop","index":0             }
+
+      event: message_delta
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":136,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":11}               }
+
+      event: message_stop
+      data: {"type":"message_stop"}
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 812.748291ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 32040
+    host: ""

internal/agent/testdata/TestCoderAgent/anthropic-sonnet/read_a_file.yaml 🔗

@@ -25,41 +25,41 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"id":"msg_01E1ouMmiDmjBTmxBzKbijL9","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":111,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard"}}           }
+      data: {"type":"message_start","message":{"id":"msg_01QeBDeyfws24WCYGL7WX2eh","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":111,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":2,"service_tier":"standard"}}  }
 
       event: content_block_start
-      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""} }
+      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}              }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Review"}}
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Checking"}    }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Go"}            }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Go"} }
 
       event: ping
       data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Module"}             }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Module"}  }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Dependencies"}         }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Dependencies"}    }
 
       event: content_block_stop
-      data: {"type":"content_block_stop","index":0           }
+      data: {"type":"content_block_stop","index":0  }
 
       event: message_delta
-      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":111,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":7}             }
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":111,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":8}              }
 
       event: message_stop
-      data: {"type":"message_stop"          }
+      data: {"type":"message_stop"             }
 
     headers:
       Content-Type:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 581.664125ms
+    duration: 706.473875ms
 - id: 1
   request:
     proto: HTTP/1.1
@@ -84,38 +84,44 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"id":"msg_01QubLD2omumch7oHi9Wd9pU","type":"message","role":"assistant","model":"claude-sonnet-4-5-20250929","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":3,"cache_creation_input_tokens":1766,"cache_read_input_tokens":6884,"cache_creation":{"ephemeral_5m_input_tokens":1766,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard"}}           }
+      data: {"type":"message_start","message":{"id":"msg_01VptiRLmS6XLkbLuAtQfaov","type":"message","role":"assistant","model":"claude-sonnet-4-5-20250929","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":3,"cache_creation_input_tokens":1766,"cache_read_input_tokens":6884,"cache_creation":{"ephemeral_5m_input_tokens":1766,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard"}}     }
 
       event: content_block_start
-      data: {"type":"content_block_start","index":0,"content_block":{"type":"tool_use","id":"toolu_01WqFKgUkEDCi8o8fVCJyz97","name":"view","input":{}}            }
+      data: {"type":"content_block_start","index":0,"content_block":{"type":"tool_use","id":"toolu_01Mx1r2b2z7dDoUd61HDrAEN","name":"view","input":{}}    }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":""}        }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":""}         }
+
+      event: ping
+      data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"{\"file_pat"}      }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"{\"fil"}            }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"h\": \"go.m"}              }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"e_path"}            }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"od\"}"}        }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"\":"}            }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":" \"go.mod\"}"} }
 
       event: content_block_stop
-      data: {"type":"content_block_stop","index":0           }
+      data: {"type":"content_block_stop","index":0              }
 
       event: message_delta
-      data: {"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"input_tokens":3,"cache_creation_input_tokens":1766,"cache_read_input_tokens":6884,"output_tokens":55} }
+      data: {"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"input_tokens":3,"cache_creation_input_tokens":1766,"cache_read_input_tokens":6884,"output_tokens":55}    }
 
       event: message_stop
-      data: {"type":"message_stop"             }
+      data: {"type":"message_stop"        }
 
     headers:
       Content-Type:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 2.520332333s
+    duration: 2.565954792s
 - id: 2
   request:
     proto: HTTP/1.1
@@ -123,7 +129,7 @@ interactions:
     proto_minor: 1
     content_length: 32323
     host: ""

internal/agent/testdata/TestCoderAgent/anthropic-sonnet/simple_test.yaml 🔗

@@ -25,29 +25,41 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"id":"msg_01EA1yHe2hGWqG98PVSSf5s8","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":108,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":2,"service_tier":"standard"}} }
+      data: {"type":"message_start","message":{"id":"msg_01Pn5WLdGCLP5aKCti1Y47pz","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":108,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard"}}       }
 
       event: content_block_start
-      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}           }
+      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}      }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Greeting"}               }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"First"}           }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Contact"}         }
+
+      event: ping
+      data: {"type": "ping"}
 
       event: content_block_stop
-      data: {"type":"content_block_stop","index":0    }
+      data: {"type":"content_block_stop","index":0               }
+
+      event: ping
+      data: {"type": "ping"}
+
+      event: ping
+      data: {"type": "ping"}
 
       event: message_delta
-      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":108,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":5}              }
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":108,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":5}               }
 
       event: message_stop
-      data: {"type":"message_stop"      }
+      data: {"type":"message_stop"       }
 
     headers:
       Content-Type:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 642.344708ms
+    duration: 692.799334ms
 - id: 1
   request:
     proto: HTTP/1.1
@@ -72,22 +84,22 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"id":"msg_01S99d6CmzZeEvf987aG9ksX","type":"message","role":"assistant","model":"claude-sonnet-4-5-20250929","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":3,"cache_creation_input_tokens":8645,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":8645,"ephemeral_1h_input_tokens":0},"output_tokens":3,"service_tier":"standard"}}   }
+      data: {"type":"message_start","message":{"id":"msg_015DTCS4wTuYNBhwJXZtLJLm","type":"message","role":"assistant","model":"claude-sonnet-4-5-20250929","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":3,"cache_creation_input_tokens":8645,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":8645,"ephemeral_1h_input_tokens":0},"output_tokens":3,"service_tier":"standard"}}              }
 
       event: content_block_start
-      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}   }
+      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}     }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello! How"}   }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello! How"}}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" can I help you today?"}}
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" can I help you today?"}           }
 
       event: ping
       data: {"type": "ping"}
 
       event: content_block_stop
-      data: {"type":"content_block_stop","index":0          }
+      data: {"type":"content_block_stop","index":0         }
 
       event: ping
       data: {"type": "ping"}
@@ -96,14 +108,14 @@ interactions:
       data: {"type": "ping"}
 
       event: message_delta
-      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":3,"cache_creation_input_tokens":8645,"cache_read_input_tokens":0,"output_tokens":12}}
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":3,"cache_creation_input_tokens":8645,"cache_read_input_tokens":0,"output_tokens":12}            }
 
       event: message_stop
-      data: {"type":"message_stop"      }
+      data: {"type":"message_stop"             }
 
     headers:
       Content-Type:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 2.390267667s
+    duration: 3.558943042s

internal/agent/testdata/TestCoderAgent/anthropic-sonnet/sourcegraph_tool.yaml 🔗

@@ -0,0 +1,256 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 675
+    host: ""
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse sourcegraph to search for ''func main'' in Go repositories","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","type":"text"}],"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - Anthropic/Go 1.12.0
+    url: https://api.anthropic.com/v1/messages
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      event: message_start
+      data: {"type":"message_start","message":{"id":"msg_01VSrXVJhnLArjQ7Xkq11P8X","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":122,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard"}}         }
+
+      event: content_block_start
+      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}  }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Search"}         }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Go"}          }
+
+      event: ping
+      data: {"type": "ping"}
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Repos"}      }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" for Main"} }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Functions"}  }
+
+      event: content_block_stop
+      data: {"type":"content_block_stop","index":0  }
+
+      event: message_delta
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":122,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":10}}
+
+      event: message_stop
+      data: {"type":"message_stop"     }
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 731.217333ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 31963
+    host: ""

internal/agent/testdata/TestCoderAgent/anthropic-sonnet/update_a_file.yaml 🔗

@@ -0,0 +1,302 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 684
+    host: ""
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nupdate the main.go file by changing the print to say hello from crush","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","type":"text"}],"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - Anthropic/Go 1.12.0
+    url: https://api.anthropic.com/v1/messages
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      event: message_start
+      data: {"type":"message_start","message":{"id":"msg_019orHc6gvEQdk3nKQns2MLh","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":122,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard"}}  }
+
+      event: content_block_start
+      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}               }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Update"}        }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" main"}       }
+
+      event: ping
+      data: {"type": "ping"}
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":".go print"}  }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" statement"}     }
+
+      event: content_block_stop
+      data: {"type":"content_block_stop","index":0          }
+
+      event: message_delta
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":122,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":9}      }
+
+      event: message_stop
+      data: {"type":"message_stop"       }
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 586.543833ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 31969
+    host: ""

internal/agent/testdata/TestCoderAgent/anthropic-sonnet/write_tool.yaml 🔗

@@ -0,0 +1,201 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 724
+    host: ""
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse write to create a new file called config.json with content ''{\"name\": \"test\", \"version\": \"1.0.0\"}''","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","type":"text"}],"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - Anthropic/Go 1.12.0
+    url: https://api.anthropic.com/v1/messages
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      event: message_start
+      data: {"type":"message_start","message":{"id":"msg_01FV2WLbbqWdo6g1LB3tmsN2","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":138,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":2,"service_tier":"standard"}}      }
+
+      event: content_block_start
+      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}    }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Create config"}   }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":".json with JSON"}  }
+
+      event: ping
+      data: {"type": "ping"}
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" data"}    }
+
+      event: ping
+      data: {"type": "ping"}
+
+      event: content_block_stop
+      data: {"type":"content_block_stop","index":0         }
+
+      event: ping
+      data: {"type": "ping"}
+
+      event: ping
+      data: {"type": "ping"}
+
+      event: message_delta
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":138,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":10}  }
+
+      event: message_stop
+      data: {"type":"message_stop"}
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 743.054792ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 32006
+    host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/bash_tool.yaml 🔗

@@ -0,0 +1,194 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 671
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse bash to create a file named test.txt with content ''hello bash''","role":"user"}],"model":"gpt-4o","max_tokens":40,"stream_options":{"include_usage":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://api.openai.com/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"chatcmpl-CLqSzNT48qPypS7n1ZTWrPR2mOUt8","object":"chat.completion.chunk","created":1759322605,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"1TxwY53leO98Ex"}
+
+      data: {"id":"chatcmpl-CLqSzNT48qPypS7n1ZTWrPR2mOUt8","object":"chat.completion.chunk","created":1759322605,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":"Create"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ZPOmrvsedn"}
+
+      data: {"id":"chatcmpl-CLqSzNT48qPypS7n1ZTWrPR2mOUt8","object":"chat.completion.chunk","created":1759322605,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"vphUd0AWtZO"}
+
+      data: {"id":"chatcmpl-CLqSzNT48qPypS7n1ZTWrPR2mOUt8","object":"chat.completion.chunk","created":1759322605,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"NqNBlHlutaT"}
+
+      data: {"id":"chatcmpl-CLqSzNT48qPypS7n1ZTWrPR2mOUt8","object":"chat.completion.chunk","created":1759322605,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Content"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"PO5HnCau"}
+
+      data: {"id":"chatcmpl-CLqSzNT48qPypS7n1ZTWrPR2mOUt8","object":"chat.completion.chunk","created":1759322605,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Using"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"TaokMgX5bv"}
+
+      data: {"id":"chatcmpl-CLqSzNT48qPypS7n1ZTWrPR2mOUt8","object":"chat.completion.chunk","created":1759322605,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Bash"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"es3dYxkeybX"}
+
+      data: {"id":"chatcmpl-CLqSzNT48qPypS7n1ZTWrPR2mOUt8","object":"chat.completion.chunk","created":1759322605,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"1xRoCYfGub"}
+
+      data: {"id":"chatcmpl-CLqSzNT48qPypS7n1ZTWrPR2mOUt8","object":"chat.completion.chunk","created":1759322605,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[],"usage":{"prompt_tokens":123,"completion_tokens":6,"total_tokens":129,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"CofnmIRzaJWBkd"}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 550.053458ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30582
+    host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/download_tool.yaml 🔗

@@ -0,0 +1,200 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 684
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\ndownload the file from https://httpbin.org/robots.txt and save it as robots.txt","role":"user"}],"model":"gpt-4o","max_tokens":40,"stream_options":{"include_usage":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://api.openai.com/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"chatcmpl-CLqfueSzbOcmAPbTW2g1hEuMsyq4H","object":"chat.completion.chunk","created":1759323406,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"0VcDmQE07bsMsM"}
+
+      data: {"id":"chatcmpl-CLqfueSzbOcmAPbTW2g1hEuMsyq4H","object":"chat.completion.chunk","created":1759323406,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":"Download"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"JXeR95k0"}
+
+      data: {"id":"chatcmpl-CLqfueSzbOcmAPbTW2g1hEuMsyq4H","object":"chat.completion.chunk","created":1759323406,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"yg6I7KW5hRRe"}
+
+      data: {"id":"chatcmpl-CLqfueSzbOcmAPbTW2g1hEuMsyq4H","object":"chat.completion.chunk","created":1759323406,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Save"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ThmZZVmdxyl"}
+
+      data: {"id":"chatcmpl-CLqfueSzbOcmAPbTW2g1hEuMsyq4H","object":"chat.completion.chunk","created":1759323406,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Robots"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ji53R00EP"}
+
+      data: {"id":"chatcmpl-CLqfueSzbOcmAPbTW2g1hEuMsyq4H","object":"chat.completion.chunk","created":1759323406,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":".txt"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"adHsEhEYJ1gi"}
+
+      data: {"id":"chatcmpl-CLqfueSzbOcmAPbTW2g1hEuMsyq4H","object":"chat.completion.chunk","created":1759323406,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" from"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"9OTPvkUyl1J"}
+
+      data: {"id":"chatcmpl-CLqfueSzbOcmAPbTW2g1hEuMsyq4H","object":"chat.completion.chunk","created":1759323406,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" URL"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"CGWzI77dm6bL"}
+
+      data: {"id":"chatcmpl-CLqfueSzbOcmAPbTW2g1hEuMsyq4H","object":"chat.completion.chunk","created":1759323406,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"48xNEgOuNZ"}
+
+      data: {"id":"chatcmpl-CLqfueSzbOcmAPbTW2g1hEuMsyq4H","object":"chat.completion.chunk","created":1759323406,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[],"usage":{"prompt_tokens":126,"completion_tokens":7,"total_tokens":133,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"e4YP3fNwUYl4mY"}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 708.007ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30599
+    host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/fetch_tool.yaml 🔗

@@ -0,0 +1,214 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 697
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nfetch the content from https://httpbin.org/html and tell me if it contains the word ''Herman''","role":"user"}],"model":"gpt-4o","max_tokens":40,"stream_options":{"include_usage":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://api.openai.com/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"chatcmpl-CLqeRoaMRC5eXV8LOfpW1Z9AKesHE","object":"chat.completion.chunk","created":1759323315,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"rl63whrmQwXJBG"}
+
+      data: {"id":"chatcmpl-CLqeRoaMRC5eXV8LOfpW1Z9AKesHE","object":"chat.completion.chunk","created":1759323315,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":"Check"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"BydBTWOroVA"}
+
+      data: {"id":"chatcmpl-CLqeRoaMRC5eXV8LOfpW1Z9AKesHE","object":"chat.completion.chunk","created":1759323315,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":" for"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"eLsM4vvoVxMN"}
+
+      data: {"id":"chatcmpl-CLqeRoaMRC5eXV8LOfpW1Z9AKesHE","object":"chat.completion.chunk","created":1759323315,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"iGq54v6lu2vR87"}
+
+      data: {"id":"chatcmpl-CLqeRoaMRC5eXV8LOfpW1Z9AKesHE","object":"chat.completion.chunk","created":1759323315,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":"H"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"UgU4MRVWpLCdXUV"}
+
+      data: {"id":"chatcmpl-CLqeRoaMRC5eXV8LOfpW1Z9AKesHE","object":"chat.completion.chunk","created":1759323315,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":"erman"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"PciYud5cbts"}
+
+      data: {"id":"chatcmpl-CLqeRoaMRC5eXV8LOfpW1Z9AKesHE","object":"chat.completion.chunk","created":1759323315,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"6HmCEQqYKvzLWqO"}
+
+      data: {"id":"chatcmpl-CLqeRoaMRC5eXV8LOfpW1Z9AKesHE","object":"chat.completion.chunk","created":1759323315,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"PXbQMtNNEJYiY"}
+
+      data: {"id":"chatcmpl-CLqeRoaMRC5eXV8LOfpW1Z9AKesHE","object":"chat.completion.chunk","created":1759323315,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":" HTTP"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"KZocX9Qmj07"}
+
+      data: {"id":"chatcmpl-CLqeRoaMRC5eXV8LOfpW1Z9AKesHE","object":"chat.completion.chunk","created":1759323315,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":"Bin"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"9L6WZMHofxMi2"}
+
+      data: {"id":"chatcmpl-CLqeRoaMRC5eXV8LOfpW1Z9AKesHE","object":"chat.completion.chunk","created":1759323315,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":" HTML"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"AOElDfAEncO"}
+
+      data: {"id":"chatcmpl-CLqeRoaMRC5eXV8LOfpW1Z9AKesHE","object":"chat.completion.chunk","created":1759323315,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":" Content"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"BBpGdYB0"}
+
+      data: {"id":"chatcmpl-CLqeRoaMRC5eXV8LOfpW1Z9AKesHE","object":"chat.completion.chunk","created":1759323315,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"HdCmoFMec4"}
+
+      data: {"id":"chatcmpl-CLqeRoaMRC5eXV8LOfpW1Z9AKesHE","object":"chat.completion.chunk","created":1759323315,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[],"usage":{"prompt_tokens":130,"completion_tokens":11,"total_tokens":141,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"trSMiVfLxCqfI"}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 1.425811834s
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30609
+    host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/glob_tool.yaml 🔗

@@ -0,0 +1,182 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 660
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse glob to find all .go files in the current directory","role":"user"}],"model":"gpt-4o","max_tokens":40,"stream_options":{"include_usage":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://api.openai.com/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"chatcmpl-CLqi7jrUgqiO30roa88DYi2HWVEct","object":"chat.completion.chunk","created":1759323543,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"9DFhz6iBTg0chb"}
+
+      data: {"id":"chatcmpl-CLqi7jrUgqiO30roa88DYi2HWVEct","object":"chat.completion.chunk","created":1759323543,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":"Finding"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"9t2uJy5CW"}
+
+      data: {"id":"chatcmpl-CLqi7jrUgqiO30roa88DYi2HWVEct","object":"chat.completion.chunk","created":1759323543,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" ."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"gpCMLZfzQLDebZ"}
+
+      data: {"id":"chatcmpl-CLqi7jrUgqiO30roa88DYi2HWVEct","object":"chat.completion.chunk","created":1759323543,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":"go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"l0fPByc6lJYqab"}
+
+      data: {"id":"chatcmpl-CLqi7jrUgqiO30roa88DYi2HWVEct","object":"chat.completion.chunk","created":1759323543,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"xSYBHbUgHz"}
+
+      data: {"id":"chatcmpl-CLqi7jrUgqiO30roa88DYi2HWVEct","object":"chat.completion.chunk","created":1759323543,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"AjtQK6H9zAJ"}
+
+      data: {"id":"chatcmpl-CLqi7jrUgqiO30roa88DYi2HWVEct","object":"chat.completion.chunk","created":1759323543,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Glob"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"4XVCWxMxsRo"}
+
+      data: {"id":"chatcmpl-CLqi7jrUgqiO30roa88DYi2HWVEct","object":"chat.completion.chunk","created":1759323543,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"yGguzRzK6cBDb"}
+
+      data: {"id":"chatcmpl-CLqi7jrUgqiO30roa88DYi2HWVEct","object":"chat.completion.chunk","created":1759323543,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Current"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"SNKwvpeX"}
+
+      data: {"id":"chatcmpl-CLqi7jrUgqiO30roa88DYi2HWVEct","object":"chat.completion.chunk","created":1759323543,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Directory"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"u9GYd1"}
+
+      data: {"id":"chatcmpl-CLqi7jrUgqiO30roa88DYi2HWVEct","object":"chat.completion.chunk","created":1759323543,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"ILIrAymb6o"}
+
+      data: {"id":"chatcmpl-CLqi7jrUgqiO30roa88DYi2HWVEct","object":"chat.completion.chunk","created":1759323543,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[],"usage":{"prompt_tokens":120,"completion_tokens":9,"total_tokens":129,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"8zq9ainuGg9f8i"}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 481.804458ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30571
+    host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/grep_tool.yaml 🔗

@@ -0,0 +1,186 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 658
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse grep to search for the word ''package'' in go files","role":"user"}],"model":"gpt-4o","max_tokens":40,"stream_options":{"include_usage":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://api.openai.com/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"chatcmpl-CLqjYvneCZnV7XudaITZKQO8TLZ0K","object":"chat.completion.chunk","created":1759323632,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"cVYQyJUavJ2xpg"}
+
+      data: {"id":"chatcmpl-CLqjYvneCZnV7XudaITZKQO8TLZ0K","object":"chat.completion.chunk","created":1759323632,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":"Search"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"HODnzE4OZ3"}
+
+      data: {"id":"chatcmpl-CLqjYvneCZnV7XudaITZKQO8TLZ0K","object":"chat.completion.chunk","created":1759323632,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"pdhK54EZmRaVVu"}
+
+      data: {"id":"chatcmpl-CLqjYvneCZnV7XudaITZKQO8TLZ0K","object":"chat.completion.chunk","created":1759323632,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":"package"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"5VeflBSUf"}
+
+      data: {"id":"chatcmpl-CLqjYvneCZnV7XudaITZKQO8TLZ0K","object":"chat.completion.chunk","created":1759323632,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"yFsUnv2WYzGNujp"}
+
+      data: {"id":"chatcmpl-CLqjYvneCZnV7XudaITZKQO8TLZ0K","object":"chat.completion.chunk","created":1759323632,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"7Jhm9fQu2LQHz"}
+
+      data: {"id":"chatcmpl-CLqjYvneCZnV7XudaITZKQO8TLZ0K","object":"chat.completion.chunk","created":1759323632,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"VVeaVVJrYxk5B"}
+
+      data: {"id":"chatcmpl-CLqjYvneCZnV7XudaITZKQO8TLZ0K","object":"chat.completion.chunk","created":1759323632,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"iYtDiWlWBE"}
+
+      data: {"id":"chatcmpl-CLqjYvneCZnV7XudaITZKQO8TLZ0K","object":"chat.completion.chunk","created":1759323632,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" Using"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"pSNkhaAI2c"}
+
+      data: {"id":"chatcmpl-CLqjYvneCZnV7XudaITZKQO8TLZ0K","object":"chat.completion.chunk","created":1759323632,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" grep"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"upz2Vg4Wzrd"}
+
+      data: {"id":"chatcmpl-CLqjYvneCZnV7XudaITZKQO8TLZ0K","object":"chat.completion.chunk","created":1759323632,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"etvSxhAa8V"}
+
+      data: {"id":"chatcmpl-CLqjYvneCZnV7XudaITZKQO8TLZ0K","object":"chat.completion.chunk","created":1759323632,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[],"usage":{"prompt_tokens":121,"completion_tokens":9,"total_tokens":130,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"1BwqV8IqAh8peC"}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 615.042833ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30569
+    host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/ls_tool.yaml 🔗

@@ -0,0 +1,182 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 654
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse ls to list the files in the current directory","role":"user"}],"model":"gpt-4o","max_tokens":40,"stream_options":{"include_usage":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://api.openai.com/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"chatcmpl-CLqmJ90g17us8SdrlwJyTc5VUUKyh","object":"chat.completion.chunk","created":1759323803,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"c1Ki3rK0aPKtpG"}
+
+      data: {"id":"chatcmpl-CLqmJ90g17us8SdrlwJyTc5VUUKyh","object":"chat.completion.chunk","created":1759323803,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":"Listing"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"4gDcRItj7"}
+
+      data: {"id":"chatcmpl-CLqmJ90g17us8SdrlwJyTc5VUUKyh","object":"chat.completion.chunk","created":1759323803,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"QZEnXvc55e"}
+
+      data: {"id":"chatcmpl-CLqmJ90g17us8SdrlwJyTc5VUUKyh","object":"chat.completion.chunk","created":1759323803,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"5kdd1OXG3h4"}
+
+      data: {"id":"chatcmpl-CLqmJ90g17us8SdrlwJyTc5VUUKyh","object":"chat.completion.chunk","created":1759323803,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"KwvfAwRmOrLS"}
+
+      data: {"id":"chatcmpl-CLqmJ90g17us8SdrlwJyTc5VUUKyh","object":"chat.completion.chunk","created":1759323803,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" ls"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Gj8GX1ZR2s7Wf"}
+
+      data: {"id":"chatcmpl-CLqmJ90g17us8SdrlwJyTc5VUUKyh","object":"chat.completion.chunk","created":1759323803,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" Command"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Ok2hK4pJ"}
+
+      data: {"id":"chatcmpl-CLqmJ90g17us8SdrlwJyTc5VUUKyh","object":"chat.completion.chunk","created":1759323803,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"Zv1PcDIS1T"}
+
+      data: {"id":"chatcmpl-CLqmJ90g17us8SdrlwJyTc5VUUKyh","object":"chat.completion.chunk","created":1759323803,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[],"usage":{"prompt_tokens":118,"completion_tokens":6,"total_tokens":124,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"0Qepco7oIqBuv4"}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 432.019916ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30563
+    host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/multiedit_tool.yaml 🔗

@@ -0,0 +1,516 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 733
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse multiedit to change ''Hello, World!'' to ''Hello, Crush!'' and add a comment ''// Greeting'' above the fmt.Println line in main.go","role":"user"}],"model":"gpt-4o","max_tokens":40,"stream_options":{"include_usage":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://api.openai.com/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"chatcmpl-CLqnYH9vX8hsgieA6oBgscmNX8RbW","object":"chat.completion.chunk","created":1759323880,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"UM30vfmFCl3gLU"}
+
+      data: {"id":"chatcmpl-CLqnYH9vX8hsgieA6oBgscmNX8RbW","object":"chat.completion.chunk","created":1759323880,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":"Mult"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ekNvzS2aB4JT"}
+
+      data: {"id":"chatcmpl-CLqnYH9vX8hsgieA6oBgscmNX8RbW","object":"chat.completion.chunk","created":1759323880,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":"ied"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"k8heFTUsZdBNE"}
+
+      data: {"id":"chatcmpl-CLqnYH9vX8hsgieA6oBgscmNX8RbW","object":"chat.completion.chunk","created":1759323880,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":"it"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"kkhLAdvCGVeoA3"}
+
+      data: {"id":"chatcmpl-CLqnYH9vX8hsgieA6oBgscmNX8RbW","object":"chat.completion.chunk","created":1759323880,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Command"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Cmbv6c6o"}
+
+      data: {"id":"chatcmpl-CLqnYH9vX8hsgieA6oBgscmNX8RbW","object":"chat.completion.chunk","created":1759323880,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" for"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"VNzA0npsSKlv"}
+
+      data: {"id":"chatcmpl-CLqnYH9vX8hsgieA6oBgscmNX8RbW","object":"chat.completion.chunk","created":1759323880,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Text"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ApUOidpKsbC"}
+
+      data: {"id":"chatcmpl-CLqnYH9vX8hsgieA6oBgscmNX8RbW","object":"chat.completion.chunk","created":1759323880,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Replacement"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ZivH"}
+
+      data: {"id":"chatcmpl-CLqnYH9vX8hsgieA6oBgscmNX8RbW","object":"chat.completion.chunk","created":1759323880,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"76123RVObx5G"}
+
+      data: {"id":"chatcmpl-CLqnYH9vX8hsgieA6oBgscmNX8RbW","object":"chat.completion.chunk","created":1759323880,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Comment"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"DTUI7oUa"}
+
+      data: {"id":"chatcmpl-CLqnYH9vX8hsgieA6oBgscmNX8RbW","object":"chat.completion.chunk","created":1759323880,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"V9pHhsJJBF"}
+
+      data: {"id":"chatcmpl-CLqnYH9vX8hsgieA6oBgscmNX8RbW","object":"chat.completion.chunk","created":1759323880,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[],"usage":{"prompt_tokens":140,"completion_tokens":9,"total_tokens":149,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"TDInfLBxhC9Zce"}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 583.795208ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30649
+    host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/parallel_tool_calls.yaml 🔗

@@ -0,0 +1,236 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 739
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse glob to find all .go files and use ls to list the current directory, it is very important that you run both tool calls in parallel","role":"user"}],"model":"gpt-4o","max_tokens":40,"stream_options":{"include_usage":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://api.openai.com/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"chatcmpl-CLrMEJZxTpYnQZmdFfXnn9gPPdCwk","object":"chat.completion.chunk","created":1759326030,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"RepZi9uEBVvAeE"}
+
+      data: {"id":"chatcmpl-CLrMEJZxTpYnQZmdFfXnn9gPPdCwk","object":"chat.completion.chunk","created":1759326030,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":"Running"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"OD5Hw4Fbx"}
+
+      data: {"id":"chatcmpl-CLrMEJZxTpYnQZmdFfXnn9gPPdCwk","object":"chat.completion.chunk","created":1759326030,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" ls"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Or47PhsyiPEN8"}
+
+      data: {"id":"chatcmpl-CLrMEJZxTpYnQZmdFfXnn9gPPdCwk","object":"chat.completion.chunk","created":1759326030,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"DAVINozhqrOh"}
+
+      data: {"id":"chatcmpl-CLrMEJZxTpYnQZmdFfXnn9gPPdCwk","object":"chat.completion.chunk","created":1759326030,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" glob"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ZSdIvd8LLId"}
+
+      data: {"id":"chatcmpl-CLrMEJZxTpYnQZmdFfXnn9gPPdCwk","object":"chat.completion.chunk","created":1759326030,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"p3Vu6TE7AFvU7"}
+
+      data: {"id":"chatcmpl-CLrMEJZxTpYnQZmdFfXnn9gPPdCwk","object":"chat.completion.chunk","created":1759326030,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Parallel"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"OY9hCw3"}
+
+      data: {"id":"chatcmpl-CLrMEJZxTpYnQZmdFfXnn9gPPdCwk","object":"chat.completion.chunk","created":1759326030,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" for"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"FXdTvF2oyPkE"}
+
+      data: {"id":"chatcmpl-CLrMEJZxTpYnQZmdFfXnn9gPPdCwk","object":"chat.completion.chunk","created":1759326030,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" ."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"7eynPXXaxI6Xaj"}
+
+      data: {"id":"chatcmpl-CLrMEJZxTpYnQZmdFfXnn9gPPdCwk","object":"chat.completion.chunk","created":1759326030,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":"go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"AJl3rpuhdCypJY"}
+
+      data: {"id":"chatcmpl-CLrMEJZxTpYnQZmdFfXnn9gPPdCwk","object":"chat.completion.chunk","created":1759326030,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"MzH1z8oX79"}
+
+      data: {"id":"chatcmpl-CLrMEJZxTpYnQZmdFfXnn9gPPdCwk","object":"chat.completion.chunk","created":1759326030,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"KtAqvrfGP1"}
+
+      data: {"id":"chatcmpl-CLrMEJZxTpYnQZmdFfXnn9gPPdCwk","object":"chat.completion.chunk","created":1759326030,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[],"usage":{"prompt_tokens":137,"completion_tokens":10,"total_tokens":147,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"WGHBq9nN8MTmo"}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 834.772958ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30660
+    host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/read_a_file.yaml 🔗

@@ -24,21 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-CLnydQKroNZFqVZIZi19ouB0wEbNO","object":"chat.completion.chunk","created":1759313035,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"1sl8OkqH6sCvFZ"}
+      data: {"id":"chatcmpl-CLqSTmKKMBfHyfMfR4liWxdWpGQBX","object":"chat.completion.chunk","created":1759322573,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"OhM1CD7NU7Ap7K"}
 
-      data: {"id":"chatcmpl-CLnydQKroNZFqVZIZi19ouB0wEbNO","object":"chat.completion.chunk","created":1759313035,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":"Understanding"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"l13"}
+      data: {"id":"chatcmpl-CLqSTmKKMBfHyfMfR4liWxdWpGQBX","object":"chat.completion.chunk","created":1759322573,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":"Understanding"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"LEl"}
 
-      data: {"id":"chatcmpl-CLnydQKroNZFqVZIZi19ouB0wEbNO","object":"chat.completion.chunk","created":1759313035,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"1Vo2490BdRxb"}
+      data: {"id":"chatcmpl-CLqSTmKKMBfHyfMfR4liWxdWpGQBX","object":"chat.completion.chunk","created":1759322573,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"zOaagIrSrOKe"}
 
-      data: {"id":"chatcmpl-CLnydQKroNZFqVZIZi19ouB0wEbNO","object":"chat.completion.chunk","created":1759313035,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"aBaqSx7ueCbH0"}
+      data: {"id":"chatcmpl-CLqSTmKKMBfHyfMfR4liWxdWpGQBX","object":"chat.completion.chunk","created":1759322573,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"MJhPCSdpNob8v"}
 
-      data: {"id":"chatcmpl-CLnydQKroNZFqVZIZi19ouB0wEbNO","object":"chat.completion.chunk","created":1759313035,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Module"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"jT2j800IA"}
+      data: {"id":"chatcmpl-CLqSTmKKMBfHyfMfR4liWxdWpGQBX","object":"chat.completion.chunk","created":1759322573,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" Module"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"E0kEvtxgz"}
 
-      data: {"id":"chatcmpl-CLnydQKroNZFqVZIZi19ouB0wEbNO","object":"chat.completion.chunk","created":1759313035,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"xq2s7jupXFD"}
+      data: {"id":"chatcmpl-CLqSTmKKMBfHyfMfR4liWxdWpGQBX","object":"chat.completion.chunk","created":1759322573,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" System"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"YAIpzyOrF"}
 
-      data: {"id":"chatcmpl-CLnydQKroNZFqVZIZi19ouB0wEbNO","object":"chat.completion.chunk","created":1759313035,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"XAJrr1rC3o"}
+      data: {"id":"chatcmpl-CLqSTmKKMBfHyfMfR4liWxdWpGQBX","object":"chat.completion.chunk","created":1759322573,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"h3Slp8bxva"}
 
-      data: {"id":"chatcmpl-CLnydQKroNZFqVZIZi19ouB0wEbNO","object":"chat.completion.chunk","created":1759313035,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[],"usage":{"prompt_tokens":112,"completion_tokens":5,"total_tokens":117,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"4dZAIDY5siwB84"}
+      data: {"id":"chatcmpl-CLqSTmKKMBfHyfMfR4liWxdWpGQBX","object":"chat.completion.chunk","created":1759322573,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[],"usage":{"prompt_tokens":112,"completion_tokens":5,"total_tokens":117,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"rqabkwbF9Q4CY2"}
 
       data: [DONE]
 
@@ -47,7 +47,7 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 694.339416ms
+    duration: 606.662708ms
 - id: 1
   request:
     proto: HTTP/1.1
@@ -71,53 +71,59 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"role":"assistant","content":null,"tool_calls":[{"index":0,"id":"call_h2ypC8aQEh70kS5aRxA5OP0L","type":"function","function":{"name":"ls","arguments":""}}],"refusal":null},"finish_reason":null}],"usage":null,"obfuscation":"udCj5sEwdgRZO8"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"role":"assistant","content":null,"tool_calls":[{"index":0,"id":"call_HXwBerJGP9q6ZiWB1wA9n0dN","type":"function","function":{"name":"view","arguments":""}}],"refusal":null},"finish_reason":null}],"usage":null,"obfuscation":"QNRubaXSQuzz"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\""}}]},"finish_reason":null}],"usage":null,"obfuscation":"pEWlsz1UmVwR5T0"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\""}}]},"finish_reason":null}],"usage":null,"obfuscation":"zvydynC4b2voJ2J"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"path"}}]},"finish_reason":null}],"usage":null,"obfuscation":"4rvBDvsbKhkfUW"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"file"}}]},"finish_reason":null}],"usage":null,"obfuscation":"HKLBCf0f7S34UF"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":"}}]},"finish_reason":null}],"usage":null,"obfuscation":"lDRaVdb6w6HY4bB"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"_path"}}]},"finish_reason":null}],"usage":null,"obfuscation":"aDlENCL0hTz5b"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" \"/"}}]},"finish_reason":null}],"usage":null,"obfuscation":"86uDBqxbwrhKcG"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":"}}]},"finish_reason":null}],"usage":null,"obfuscation":"IcNLo4HErFrqOum"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"tmp"}}]},"finish_reason":null}],"usage":null,"obfuscation":"XJwFlPi1cJN4gSW"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"/"}}]},"finish_reason":null}],"usage":null,"obfuscation":"m5t7YOgNMBMjKky"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/cr"}}]},"finish_reason":null}],"usage":null,"obfuscation":"Yd0vutWvMyGysaX"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"tmp"}}]},"finish_reason":null}],"usage":null,"obfuscation":"Vr9hJGQwszXFSzK"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"ush"}}]},"finish_reason":null}],"usage":null,"obfuscation":"HS6RdJ6PqkBZxIk"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/cr"}}]},"finish_reason":null}],"usage":null,"obfuscation":"Pli9f7CLZoeKGkS"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"-test"}}]},"finish_reason":null}],"usage":null,"obfuscation":"X0rCWcu5UCHJd"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"ush"}}]},"finish_reason":null}],"usage":null,"obfuscation":"bNIu30KFlNCghAp"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/Test"}}]},"finish_reason":null}],"usage":null,"obfuscation":"Bwd86hIdF8fGi"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"-test"}}]},"finish_reason":null}],"usage":null,"obfuscation":"fSXzeFOJscj97"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"Coder"}}]},"finish_reason":null}],"usage":null,"obfuscation":"MqT0iEfzDuiqo"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/Test"}}]},"finish_reason":null}],"usage":null,"obfuscation":"22J3eDWqCkolE"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"Agent"}}]},"finish_reason":null}],"usage":null,"obfuscation":"RSdaRiSacYd5l"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"Coder"}}]},"finish_reason":null}],"usage":null,"obfuscation":"K8ntuhexLYb2S"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/open"}}]},"finish_reason":null}],"usage":null,"obfuscation":"jub295DEMeN8b"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"Agent"}}]},"finish_reason":null}],"usage":null,"obfuscation":"Bf5KwEFgtkZrU"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"ai"}}]},"finish_reason":null}],"usage":null,"obfuscation":""}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/open"}}]},"finish_reason":null}],"usage":null,"obfuscation":"Eow8kAM7GpptB"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"-g"}}]},"finish_reason":null}],"usage":null,"obfuscation":""}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"ai"}}]},"finish_reason":null}],"usage":null,"obfuscation":""}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"pt"}}]},"finish_reason":null}],"usage":null,"obfuscation":""}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"-g"}}]},"finish_reason":null}],"usage":null,"obfuscation":""}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"-"}}]},"finish_reason":null}],"usage":null,"obfuscation":"3"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"pt"}}]},"finish_reason":null}],"usage":null,"obfuscation":""}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"5"}}]},"finish_reason":null}],"usage":null,"obfuscation":"b"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"-"}}]},"finish_reason":null}],"usage":null,"obfuscation":"m"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/read"}}]},"finish_reason":null}],"usage":null,"obfuscation":"GXN4JIYrXKzYf"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"5"}}]},"finish_reason":null}],"usage":null,"obfuscation":"Q"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"_a"}}]},"finish_reason":null}],"usage":null,"obfuscation":""}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/read"}}]},"finish_reason":null}],"usage":null,"obfuscation":"W09rK3NiuTBpP"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"_file"}}]},"finish_reason":null}],"usage":null,"obfuscation":"SrjFhA7dxPbiC"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"_a"}}]},"finish_reason":null}],"usage":null,"obfuscation":""}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"}"}}]},"finish_reason":null}],"usage":null,"obfuscation":"sMFHQf4veT84RRE"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"_file"}}]},"finish_reason":null}],"usage":null,"obfuscation":"HSppD1QO9xVmB"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{},"finish_reason":"tool_calls"}],"usage":null,"obfuscation":""}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/go"}}]},"finish_reason":null}],"usage":null,"obfuscation":"TcHr4hmFBiyIEat"}
 
-      data: {"id":"chatcmpl-CLnyeFgIfZUhkmsmw9CIOV7zdKiCz","object":"chat.completion.chunk","created":1759313036,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[],"usage":{"prompt_tokens":6546,"completion_tokens":103,"total_tokens":6649,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":64,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"43XgN"}
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":".mod"}}]},"finish_reason":null}],"usage":null,"obfuscation":"1gFl0w0KUxFNDJ"}
+
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"}"}}]},"finish_reason":null}],"usage":null,"obfuscation":"S3DzQXEBzDSJGSz"}
+
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{},"finish_reason":"tool_calls"}],"usage":null,"obfuscation":""}
+
+      data: {"id":"chatcmpl-CLqSTJUdml88aOvbticbuarcvvHuE","object":"chat.completion.chunk","created":1759322573,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[],"usage":{"prompt_tokens":6546,"completion_tokens":105,"total_tokens":6651,"prompt_tokens_details":{"cached_tokens":6528,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":64,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"lm"}
 
       data: [DONE]
 
@@ -126,15 +132,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 6.020108959s
+    duration: 4.70024825s
 - id: 2
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 30898
+    content_length: 30907
     host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/simple_test.yaml 🔗

@@ -24,25 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-CLnyZUC3HECSNiCyPUyFNYk3jkToU","object":"chat.completion.chunk","created":1759313031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"FQ2C1HyimwsSIJ"}
+      data: {"id":"chatcmpl-CLqSPM5xEBAzlWvxt8DMeqRGaDv9l","object":"chat.completion.chunk","created":1759322569,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"2jyVpvWydcoDzR"}
 
-      data: {"id":"chatcmpl-CLnyZUC3HECSNiCyPUyFNYk3jkToU","object":"chat.completion.chunk","created":1759313031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":"User"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"LIC7mLokOZ9E"}
+      data: {"id":"chatcmpl-CLqSPM5xEBAzlWvxt8DMeqRGaDv9l","object":"chat.completion.chunk","created":1759322569,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":"User"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"BchqB0J32Wsd"}
 
-      data: {"id":"chatcmpl-CLnyZUC3HECSNiCyPUyFNYk3jkToU","object":"chat.completion.chunk","created":1759313031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" Gre"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"r7SBrJb3ou5J"}
+      data: {"id":"chatcmpl-CLqSPM5xEBAzlWvxt8DMeqRGaDv9l","object":"chat.completion.chunk","created":1759322569,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":"'s"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"9vvcSlmIx5o9qW"}
 
-      data: {"id":"chatcmpl-CLnyZUC3HECSNiCyPUyFNYk3jkToU","object":"chat.completion.chunk","created":1759313031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":"ets"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"zUr2uM9B9K3ob"}
+      data: {"id":"chatcmpl-CLqSPM5xEBAzlWvxt8DMeqRGaDv9l","object":"chat.completion.chunk","created":1759322569,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Initial"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"GzmBljPi"}
 
-      data: {"id":"chatcmpl-CLnyZUC3HECSNiCyPUyFNYk3jkToU","object":"chat.completion.chunk","created":1759313031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"csC49xwKSOL"}
+      data: {"id":"chatcmpl-CLqSPM5xEBAzlWvxt8DMeqRGaDv9l","object":"chat.completion.chunk","created":1759322569,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Greeting"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"BmT9dMg"}
 
-      data: {"id":"chatcmpl-CLnyZUC3HECSNiCyPUyFNYk3jkToU","object":"chat.completion.chunk","created":1759313031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"U2SfAZTiySGrTd"}
+      data: {"id":"chatcmpl-CLqSPM5xEBAzlWvxt8DMeqRGaDv9l","object":"chat.completion.chunk","created":1759322569,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"kMj5pI727f"}
 
-      data: {"id":"chatcmpl-CLnyZUC3HECSNiCyPUyFNYk3jkToU","object":"chat.completion.chunk","created":1759313031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" Simple"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"kF2mXsyQE"}
-
-      data: {"id":"chatcmpl-CLnyZUC3HECSNiCyPUyFNYk3jkToU","object":"chat.completion.chunk","created":1759313031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" Hello"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"2Ffvui00sv"}
-
-      data: {"id":"chatcmpl-CLnyZUC3HECSNiCyPUyFNYk3jkToU","object":"chat.completion.chunk","created":1759313031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"wj1wg1XKPv"}
-
-      data: {"id":"chatcmpl-CLnyZUC3HECSNiCyPUyFNYk3jkToU","object":"chat.completion.chunk","created":1759313031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[],"usage":{"prompt_tokens":109,"completion_tokens":7,"total_tokens":116,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"hss1b1Nj1zXerq"}
+      data: {"id":"chatcmpl-CLqSPM5xEBAzlWvxt8DMeqRGaDv9l","object":"chat.completion.chunk","created":1759322569,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[],"usage":{"prompt_tokens":109,"completion_tokens":4,"total_tokens":113,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"CZWaBIXTMZPzE4"}
 
       data: [DONE]
 
@@ -51,7 +45,7 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 1.173388541s
+    duration: 589.427875ms
 - id: 1
   request:
     proto: HTTP/1.1
@@ -75,25 +69,13 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-CLnyZweXlaWIhQPdgTTMjKH0ieg43","object":"chat.completion.chunk","created":1759313031,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"finish_reason":null}],"usage":null,"obfuscation":"BlAf6hXt5L"}
-
-      data: {"id":"chatcmpl-CLnyZweXlaWIhQPdgTTMjKH0ieg43","object":"chat.completion.chunk","created":1759313031,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"Hi"},"finish_reason":null}],"usage":null,"obfuscation":"lmC5EDku3L"}
-
-      data: {"id":"chatcmpl-CLnyZweXlaWIhQPdgTTMjKH0ieg43","object":"chat.completion.chunk","created":1759313031,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"!"},"finish_reason":null}],"usage":null,"obfuscation":"R4SN5zRlnTY"}
-
-      data: {"id":"chatcmpl-CLnyZweXlaWIhQPdgTTMjKH0ieg43","object":"chat.completion.chunk","created":1759313031,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":" How"},"finish_reason":null}],"usage":null,"obfuscation":"YoJvJi1Y"}
-
-      data: {"id":"chatcmpl-CLnyZweXlaWIhQPdgTTMjKH0ieg43","object":"chat.completion.chunk","created":1759313031,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":" can"},"finish_reason":null}],"usage":null,"obfuscation":"EHjiUEMv"}
-
-      data: {"id":"chatcmpl-CLnyZweXlaWIhQPdgTTMjKH0ieg43","object":"chat.completion.chunk","created":1759313031,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":" I"},"finish_reason":null}],"usage":null,"obfuscation":"tk00iUY5TP"}
-
-      data: {"id":"chatcmpl-CLnyZweXlaWIhQPdgTTMjKH0ieg43","object":"chat.completion.chunk","created":1759313031,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":" help"},"finish_reason":null}],"usage":null,"obfuscation":"8tE8LXF"}
+      data: {"id":"chatcmpl-CLqSPD68gpvvHjIs88ayEM0SmTCLC","object":"chat.completion.chunk","created":1759322569,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"finish_reason":null}],"usage":null,"obfuscation":"F6FsxCnM3u"}
 
-      data: {"id":"chatcmpl-CLnyZweXlaWIhQPdgTTMjKH0ieg43","object":"chat.completion.chunk","created":1759313031,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"?"},"finish_reason":null}],"usage":null,"obfuscation":"NukrNEtVmmp"}
+      data: {"id":"chatcmpl-CLqSPD68gpvvHjIs88ayEM0SmTCLC","object":"chat.completion.chunk","created":1759322569,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"Hi"},"finish_reason":null}],"usage":null,"obfuscation":"bOfHSbC8pG"}
 
-      data: {"id":"chatcmpl-CLnyZweXlaWIhQPdgTTMjKH0ieg43","object":"chat.completion.chunk","created":1759313031,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":null,"obfuscation":"RSH2sU"}
+      data: {"id":"chatcmpl-CLqSPD68gpvvHjIs88ayEM0SmTCLC","object":"chat.completion.chunk","created":1759322569,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":null,"obfuscation":"xuyCQb"}
 
-      data: {"id":"chatcmpl-CLnyZweXlaWIhQPdgTTMjKH0ieg43","object":"chat.completion.chunk","created":1759313031,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[],"usage":{"prompt_tokens":6542,"completion_tokens":80,"total_tokens":6622,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":64,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"hmNsuX"}
+      data: {"id":"chatcmpl-CLqSPD68gpvvHjIs88ayEM0SmTCLC","object":"chat.completion.chunk","created":1759322569,"model":"gpt-5-2025-08-07","service_tier":"default","system_fingerprint":null,"choices":[],"usage":{"prompt_tokens":6542,"completion_tokens":74,"total_tokens":6616,"prompt_tokens_details":{"cached_tokens":6528,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":64,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"LmL"}
 
       data: [DONE]
 
@@ -102,4 +84,4 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 4.041598333s
+    duration: 3.666814459s

internal/agent/testdata/TestCoderAgent/openai-gpt-5/sourcegraph_tool.yaml 🔗

@@ -0,0 +1,442 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 665
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse sourcegraph to search for ''func main'' in Go repositories","role":"user"}],"model":"gpt-4o","max_tokens":40,"stream_options":{"include_usage":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://api.openai.com/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"chatcmpl-CLqrJJBa8ZMtZi42hKuTTfdL7aW55","object":"chat.completion.chunk","created":1759324113,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"R0kKOnuAIO67g1"}
+
+      data: {"id":"chatcmpl-CLqrJJBa8ZMtZi42hKuTTfdL7aW55","object":"chat.completion.chunk","created":1759324113,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":"Searching"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ptEpuoc"}
+
+      data: {"id":"chatcmpl-CLqrJJBa8ZMtZi42hKuTTfdL7aW55","object":"chat.completion.chunk","created":1759324113,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":" for"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"p7ec2hX6G1pN"}
+
+      data: {"id":"chatcmpl-CLqrJJBa8ZMtZi42hKuTTfdL7aW55","object":"chat.completion.chunk","created":1759324113,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"44eLiVjPfptbG7"}
+
+      data: {"id":"chatcmpl-CLqrJJBa8ZMtZi42hKuTTfdL7aW55","object":"chat.completion.chunk","created":1759324113,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":"func"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"DE8Ucn0eBwYa"}
+
+      data: {"id":"chatcmpl-CLqrJJBa8ZMtZi42hKuTTfdL7aW55","object":"chat.completion.chunk","created":1759324113,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":" main"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"xmPdGE5MCrY"}
+
+      data: {"id":"chatcmpl-CLqrJJBa8ZMtZi42hKuTTfdL7aW55","object":"chat.completion.chunk","created":1759324113,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"nUBRrpjQ8MlnZcG"}
+
+      data: {"id":"chatcmpl-CLqrJJBa8ZMtZi42hKuTTfdL7aW55","object":"chat.completion.chunk","created":1759324113,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"e1Oo8VPkltyj6"}
+
+      data: {"id":"chatcmpl-CLqrJJBa8ZMtZi42hKuTTfdL7aW55","object":"chat.completion.chunk","created":1759324113,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"hhUCIoLRzmoDD"}
+
+      data: {"id":"chatcmpl-CLqrJJBa8ZMtZi42hKuTTfdL7aW55","object":"chat.completion.chunk","created":1759324113,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"lLbSjTjDHyu"}
+
+      data: {"id":"chatcmpl-CLqrJJBa8ZMtZi42hKuTTfdL7aW55","object":"chat.completion.chunk","created":1759324113,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":" Source"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"le8qaaddN"}
+
+      data: {"id":"chatcmpl-CLqrJJBa8ZMtZi42hKuTTfdL7aW55","object":"chat.completion.chunk","created":1759324113,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{"content":"graph"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ArW62fuTYKC"}
+
+      data: {"id":"chatcmpl-CLqrJJBa8ZMtZi42hKuTTfdL7aW55","object":"chat.completion.chunk","created":1759324113,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"564zv6Hufz"}
+
+      data: {"id":"chatcmpl-CLqrJJBa8ZMtZi42hKuTTfdL7aW55","object":"chat.completion.chunk","created":1759324113,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_1827dd0c55","choices":[],"usage":{"prompt_tokens":121,"completion_tokens":11,"total_tokens":132,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"MrjMoFfH77bAa"}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 1.114136375s
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30583
+    host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/update_a_file.yaml 🔗

@@ -0,0 +1,462 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 674
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nupdate the main.go file by changing the print to say hello from crush","role":"user"}],"model":"gpt-4o","max_tokens":40,"stream_options":{"include_usage":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://api.openai.com/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"chatcmpl-CLqSeBGZUw93AsqGUuwhQtteRhJ8z","object":"chat.completion.chunk","created":1759322584,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Z0WzX13B73cyI2"}
+
+      data: {"id":"chatcmpl-CLqSeBGZUw93AsqGUuwhQtteRhJ8z","object":"chat.completion.chunk","created":1759322584,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":"Modify"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"9dGxIijFHA"}
+
+      data: {"id":"chatcmpl-CLqSeBGZUw93AsqGUuwhQtteRhJ8z","object":"chat.completion.chunk","created":1759322584,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" main"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"sCNoMdUuiak"}
+
+      data: {"id":"chatcmpl-CLqSeBGZUw93AsqGUuwhQtteRhJ8z","object":"chat.completion.chunk","created":1759322584,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":".go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"aaqSLBfgDY6tj"}
+
+      data: {"id":"chatcmpl-CLqSeBGZUw93AsqGUuwhQtteRhJ8z","object":"chat.completion.chunk","created":1759322584,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"krEcnkkvEixyJ"}
+
+      data: {"id":"chatcmpl-CLqSeBGZUw93AsqGUuwhQtteRhJ8z","object":"chat.completion.chunk","created":1759322584,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" Print"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"aDhqWYzBgs"}
+
+      data: {"id":"chatcmpl-CLqSeBGZUw93AsqGUuwhQtteRhJ8z","object":"chat.completion.chunk","created":1759322584,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"YDFm0tPaHxc5q"}
+
+      data: {"id":"chatcmpl-CLqSeBGZUw93AsqGUuwhQtteRhJ8z","object":"chat.completion.chunk","created":1759322584,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":"Hello"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"4jeqQIjAOpZ"}
+
+      data: {"id":"chatcmpl-CLqSeBGZUw93AsqGUuwhQtteRhJ8z","object":"chat.completion.chunk","created":1759322584,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" from"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"sjtAKuBO4Ih"}
+
+      data: {"id":"chatcmpl-CLqSeBGZUw93AsqGUuwhQtteRhJ8z","object":"chat.completion.chunk","created":1759322584,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" Crush"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"deYqAN4dzH"}
+
+      data: {"id":"chatcmpl-CLqSeBGZUw93AsqGUuwhQtteRhJ8z","object":"chat.completion.chunk","created":1759322584,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":"\""},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"zIYd6azg7e4Gk5"}
+
+      data: {"id":"chatcmpl-CLqSeBGZUw93AsqGUuwhQtteRhJ8z","object":"chat.completion.chunk","created":1759322584,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"mYWEUU4k28"}
+
+      data: {"id":"chatcmpl-CLqSeBGZUw93AsqGUuwhQtteRhJ8z","object":"chat.completion.chunk","created":1759322584,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[],"usage":{"prompt_tokens":122,"completion_tokens":10,"total_tokens":132,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"i17JCPlr9vXHW"}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 826.612292ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30589
+    host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/write_tool.yaml 🔗

@@ -0,0 +1,214 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 714
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse write to create a new file called config.json with content ''{\"name\": \"test\", \"version\": \"1.0.0\"}''","role":"user"}],"model":"gpt-4o","max_tokens":40,"stream_options":{"include_usage":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://api.openai.com/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"chatcmpl-CLqt4FXyZyPQkIUDP7PZUE7Qsq1i3","object":"chat.completion.chunk","created":1759324222,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"lYlPGTaYLIXWn5"}
+
+      data: {"id":"chatcmpl-CLqt4FXyZyPQkIUDP7PZUE7Qsq1i3","object":"chat.completion.chunk","created":1759324222,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":"Creating"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"JzuegLEB"}
+
+      data: {"id":"chatcmpl-CLqt4FXyZyPQkIUDP7PZUE7Qsq1i3","object":"chat.completion.chunk","created":1759324222,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" config"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"2OgRAIGxz"}
+
+      data: {"id":"chatcmpl-CLqt4FXyZyPQkIUDP7PZUE7Qsq1i3","object":"chat.completion.chunk","created":1759324222,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":".json"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"I1rJOoIxVRG"}
+
+      data: {"id":"chatcmpl-CLqt4FXyZyPQkIUDP7PZUE7Qsq1i3","object":"chat.completion.chunk","created":1759324222,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"FhnIgNrHooV"}
+
+      data: {"id":"chatcmpl-CLqt4FXyZyPQkIUDP7PZUE7Qsq1i3","object":"chat.completion.chunk","created":1759324222,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" JSON"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"FPu6z2bkv2c"}
+
+      data: {"id":"chatcmpl-CLqt4FXyZyPQkIUDP7PZUE7Qsq1i3","object":"chat.completion.chunk","created":1759324222,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{"content":" Content"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"FpYmLP9h"}
+
+      data: {"id":"chatcmpl-CLqt4FXyZyPQkIUDP7PZUE7Qsq1i3","object":"chat.completion.chunk","created":1759324222,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"5McOf2NcB6"}
+
+      data: {"id":"chatcmpl-CLqt4FXyZyPQkIUDP7PZUE7Qsq1i3","object":"chat.completion.chunk","created":1759324222,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_f33640a400","choices":[],"usage":{"prompt_tokens":137,"completion_tokens":6,"total_tokens":143,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"zZ6btDmBK9OIYG"}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream; charset=utf-8
+    status: 200 OK
+    code: 200
+    duration: 805.907084ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30626
+    host: ""

internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/bash_tool.yaml 🔗

@@ -0,0 +1,204 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 722
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse bash to create a file named test.txt with content ''hello bash''","role":"user"}],"model":"qwen/qwen3-next-80b-a3b-instruct","max_tokens":40,"stream_options":{"include_usage":true},"usage":{"include":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://openrouter.ai/api/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"gen-1759322635-TppkWLzjmz9zZIUM3yuA","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759322635,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759322635-TppkWLzjmz9zZIUM3yuA","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759322635,"choices":[{"index":0,"delta":{"role":"assistant","content":"Create"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759322635-TppkWLzjmz9zZIUM3yuA","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759322635,"choices":[{"index":0,"delta":{"role":"assistant","content":" test"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759322635-TppkWLzjmz9zZIUM3yuA","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759322635,"choices":[{"index":0,"delta":{"role":"assistant","content":".txt"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759322635-TppkWLzjmz9zZIUM3yuA","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759322635,"choices":[{"index":0,"delta":{"role":"assistant","content":" with"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759322635-TppkWLzjmz9zZIUM3yuA","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759322635,"choices":[{"index":0,"delta":{"role":"assistant","content":" hello"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759322635-TppkWLzjmz9zZIUM3yuA","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759322635,"choices":[{"index":0,"delta":{"role":"assistant","content":" bash"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759322635-TppkWLzjmz9zZIUM3yuA","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759322635,"choices":[{"index":0,"delta":{"role":"assistant","content":" using"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759322635-TppkWLzjmz9zZIUM3yuA","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759322635,"choices":[{"index":0,"delta":{"role":"assistant","content":" bash"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759322635-TppkWLzjmz9zZIUM3yuA","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759322635,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
+
+      data: {"id":"gen-1759322635-TppkWLzjmz9zZIUM3yuA","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759322635,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":127,"completion_tokens":9,"total_tokens":136,"cost":0.0000199,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000127,"upstream_inference_completions_cost":0.0000072},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream
+    status: 200 OK
+    code: 200
+    duration: 1.365781417s
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30620
+    host: ""

internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/download_tool.yaml 🔗

@@ -0,0 +1,252 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 735
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\ndownload the file from https://httpbin.org/robots.txt and save it as robots.txt","role":"user"}],"model":"qwen/qwen3-next-80b-a3b-instruct","max_tokens":40,"stream_options":{"include_usage":true},"usage":{"include":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://openrouter.ai/api/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"gen-1759323412-yoIjWFg9z9HVZLNX3BRG","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323412,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323412-yoIjWFg9z9HVZLNX3BRG","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323412,"choices":[{"index":0,"delta":{"role":"assistant","content":"Download"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323412-yoIjWFg9z9HVZLNX3BRG","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323412,"choices":[{"index":0,"delta":{"role":"assistant","content":" robots"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323412-yoIjWFg9z9HVZLNX3BRG","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323412,"choices":[{"index":0,"delta":{"role":"assistant","content":".txt from httpbin"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323412-yoIjWFg9z9HVZLNX3BRG","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323412,"choices":[{"index":0,"delta":{"role":"assistant","content":".org"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323412-yoIjWFg9z9HVZLNX3BRG","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323412,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
+
+      data: {"id":"gen-1759323412-yoIjWFg9z9HVZLNX3BRG","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323412,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":130,"completion_tokens":8,"total_tokens":138,"cost":0.0000315,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000195,"upstream_inference_completions_cost":0.000012},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream
+    status: 200 OK
+    code: 200
+    duration: 1.117266s
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30637
+    host: ""

internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/fetch_tool.yaml 🔗

@@ -0,0 +1,244 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 748
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nfetch the content from https://httpbin.org/html and tell me if it contains the word ''Herman''","role":"user"}],"model":"qwen/qwen3-next-80b-a3b-instruct","max_tokens":40,"stream_options":{"include_usage":true},"usage":{"include":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://openrouter.ai/api/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"gen-1759323329-oZ5YAFmW4RWi4jG2tSFM","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323329,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323329-oZ5YAFmW4RWi4jG2tSFM","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323329,"choices":[{"index":0,"delta":{"role":"assistant","content":"Check"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323329-oZ5YAFmW4RWi4jG2tSFM","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323329,"choices":[{"index":0,"delta":{"role":"assistant","content":" if https"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323329-oZ5YAFmW4RWi4jG2tSFM","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323329,"choices":[{"index":0,"delta":{"role":"assistant","content":"://httpbin.org"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323329-oZ5YAFmW4RWi4jG2tSFM","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323329,"choices":[{"index":0,"delta":{"role":"assistant","content":"/html contains the word"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323329-oZ5YAFmW4RWi4jG2tSFM","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323329,"choices":[{"index":0,"delta":{"role":"assistant","content":" Herman"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323329-oZ5YAFmW4RWi4jG2tSFM","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323329,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
+
+      data: {"id":"gen-1759323329-oZ5YAFmW4RWi4jG2tSFM","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323329,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":134,"completion_tokens":13,"total_tokens":147,"cost":0.0000357,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000201,"upstream_inference_completions_cost":0.0000156},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream
+    status: 200 OK
+    code: 200
+    duration: 1.107577291s
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30647
+    host: ""

internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/glob_tool.yaml 🔗

@@ -0,0 +1,158 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 711
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse glob to find all .go files in the current directory","role":"user"}],"model":"qwen/qwen3-next-80b-a3b-instruct","max_tokens":40,"stream_options":{"include_usage":true},"usage":{"include":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://openrouter.ai/api/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"gen-1759323552-YE7xA0iP4oXg1mnhL1Rn","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323552,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323552-YE7xA0iP4oXg1mnhL1Rn","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323552,"choices":[{"index":0,"delta":{"role":"assistant","content":"Find"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323552-YE7xA0iP4oXg1mnhL1Rn","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323552,"choices":[{"index":0,"delta":{"role":"assistant","content":" all .go files"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323552-YE7xA0iP4oXg1mnhL1Rn","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323552,"choices":[{"index":0,"delta":{"role":"assistant","content":" in current directory using"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323552-YE7xA0iP4oXg1mnhL1Rn","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323552,"choices":[{"index":0,"delta":{"role":"assistant","content":" glob"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323552-YE7xA0iP4oXg1mnhL1Rn","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323552,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
+
+      data: {"id":"gen-1759323552-YE7xA0iP4oXg1mnhL1Rn","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323552,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":124,"completion_tokens":11,"total_tokens":135,"cost":0.0000318,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000186,"upstream_inference_completions_cost":0.0000132},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream
+    status: 200 OK
+    code: 200
+    duration: 1.093133708s
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30609
+    host: ""

internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/grep_tool.yaml 🔗

@@ -0,0 +1,180 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 709
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse grep to search for the word ''package'' in go files","role":"user"}],"model":"qwen/qwen3-next-80b-a3b-instruct","max_tokens":40,"stream_options":{"include_usage":true},"usage":{"include":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://openrouter.ai/api/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"gen-1759323648-CQo1FDMLUkmMiUjswfD3","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323648,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323648-CQo1FDMLUkmMiUjswfD3","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323648,"choices":[{"index":0,"delta":{"role":"assistant","content":"Search"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323648-CQo1FDMLUkmMiUjswfD3","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323648,"choices":[{"index":0,"delta":{"role":"assistant","content":" for package in Go"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323648-CQo1FDMLUkmMiUjswfD3","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323648,"choices":[{"index":0,"delta":{"role":"assistant","content":" files using grep"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323648-CQo1FDMLUkmMiUjswfD3","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323648,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
+
+      data: {"id":"gen-1759323648-CQo1FDMLUkmMiUjswfD3","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323648,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":125,"completion_tokens":9,"total_tokens":134,"cost":0.00002955,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.00001875,"upstream_inference_completions_cost":0.0000108},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream
+    status: 200 OK
+    code: 200
+    duration: 790.255959ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30607
+    host: ""

internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/ls_tool.yaml 🔗

@@ -0,0 +1,182 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 705
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse ls to list the files in the current directory","role":"user"}],"model":"qwen/qwen3-next-80b-a3b-instruct","max_tokens":40,"stream_options":{"include_usage":true},"usage":{"include":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://openrouter.ai/api/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"gen-1759323819-7Qc4Shy009BbR8hMLBHq","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323819,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323819-7Qc4Shy009BbR8hMLBHq","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323819,"choices":[{"index":0,"delta":{"role":"assistant","content":"List"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323819-7Qc4Shy009BbR8hMLBHq","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323819,"choices":[{"index":0,"delta":{"role":"assistant","content":" files in current directory"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323819-7Qc4Shy009BbR8hMLBHq","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323819,"choices":[{"index":0,"delta":{"role":"assistant","content":" using ls"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323819-7Qc4Shy009BbR8hMLBHq","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323819,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
+
+      data: {"id":"gen-1759323819-7Qc4Shy009BbR8hMLBHq","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323819,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":122,"completion_tokens":8,"total_tokens":130,"cost":0.0000303,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000183,"upstream_inference_completions_cost":0.000012},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream
+    status: 200 OK
+    code: 200
+    duration: 1.071837291s
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30601
+    host: ""

internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/multiedit_tool.yaml 🔗

@@ -0,0 +1,673 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 784
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse multiedit to change ''Hello, World!'' to ''Hello, Crush!'' and add a comment ''// Greeting'' above the fmt.Println line in main.go","role":"user"}],"model":"qwen/qwen3-next-80b-a3b-instruct","max_tokens":40,"stream_options":{"include_usage":true},"usage":{"include":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://openrouter.ai/api/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"gen-1759323944-SGxhAadWpT4VK6lfYEaS","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323944,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323944-SGxhAadWpT4VK6lfYEaS","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323944,"choices":[{"index":0,"delta":{"role":"assistant","content":"Use"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323944-SGxhAadWpT4VK6lfYEaS","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323944,"choices":[{"index":0,"delta":{"role":"assistant","content":" mult"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323944-SGxhAadWpT4VK6lfYEaS","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323944,"choices":[{"index":0,"delta":{"role":"assistant","content":"ied"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323944-SGxhAadWpT4VK6lfYEaS","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323944,"choices":[{"index":0,"delta":{"role":"assistant","content":"it"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323944-SGxhAadWpT4VK6lfYEaS","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323944,"choices":[{"index":0,"delta":{"role":"assistant","content":" to"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323944-SGxhAadWpT4VK6lfYEaS","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323944,"choices":[{"index":0,"delta":{"role":"assistant","content":" update"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323944-SGxhAadWpT4VK6lfYEaS","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323944,"choices":[{"index":0,"delta":{"role":"assistant","content":" greeting"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323944-SGxhAadWpT4VK6lfYEaS","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323944,"choices":[{"index":0,"delta":{"role":"assistant","content":" and"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323944-SGxhAadWpT4VK6lfYEaS","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323944,"choices":[{"index":0,"delta":{"role":"assistant","content":" add"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323944-SGxhAadWpT4VK6lfYEaS","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323944,"choices":[{"index":0,"delta":{"role":"assistant","content":" comment"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323944-SGxhAadWpT4VK6lfYEaS","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323944,"choices":[{"index":0,"delta":{"role":"assistant","content":" in"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323944-SGxhAadWpT4VK6lfYEaS","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323944,"choices":[{"index":0,"delta":{"role":"assistant","content":" main"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323944-SGxhAadWpT4VK6lfYEaS","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323944,"choices":[{"index":0,"delta":{"role":"assistant","content":".go"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759323944-SGxhAadWpT4VK6lfYEaS","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323944,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
+
+      data: {"id":"gen-1759323944-SGxhAadWpT4VK6lfYEaS","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759323944,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":145,"completion_tokens":14,"total_tokens":159,"cost":0.0000257,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000145,"upstream_inference_completions_cost":0.0000112},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream
+    status: 200 OK
+    code: 200
+    duration: 1.250544792s
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30687
+    host: ""

internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/simple_test.yaml 🔗

@@ -24,13 +24,13 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1759316452-zjAj0sEKiIFFAKMkb9ry","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759316452,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1759322621-088y2ZDJ2qWERmy5LEKL","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759322621,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1759316452-zjAj0sEKiIFFAKMkb9ry","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759316452,"choices":[{"index":0,"delta":{"role":"assistant","content":"Hello"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1759322621-088y2ZDJ2qWERmy5LEKL","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759322621,"choices":[{"index":0,"delta":{"role":"assistant","content":"Hello"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1759316452-zjAj0sEKiIFFAKMkb9ry","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759316452,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
+      data: {"id":"gen-1759322621-088y2ZDJ2qWERmy5LEKL","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759322621,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
 
-      data: {"id":"gen-1759316452-zjAj0sEKiIFFAKMkb9ry","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759316452,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":113,"completion_tokens":2,"total_tokens":115,"cost":0.0000129,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000113,"upstream_inference_completions_cost":0.0000016},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      data: {"id":"gen-1759322621-088y2ZDJ2qWERmy5LEKL","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759322621,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":113,"completion_tokens":2,"total_tokens":115,"cost":0.0000129,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000113,"upstream_inference_completions_cost":0.0000016},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
 
       data: [DONE]
 
@@ -39,7 +39,7 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 1.246887958s
+    duration: 1.105230416s
 - id: 1
   request:
     proto: HTTP/1.1
@@ -63,15 +63,13 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1759316452-0gJYswImYao5Of0iy7j1","provider":"Moonshot AI","model":"moonshotai/kimi-k2-0905","object":"chat.completion.chunk","created":1759316452,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":"fpv0_ef28f882"}
+      data: {"id":"gen-1759322621-TFyRE7QqvCi8A7vVSHKy","provider":"Novita","model":"moonshotai/kimi-k2-0905","object":"chat.completion.chunk","created":1759322621,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":"fpv0_ef28f882"}
 
-      data: {"id":"gen-1759316452-0gJYswImYao5Of0iy7j1","provider":"Moonshot AI","model":"moonshotai/kimi-k2-0905","object":"chat.completion.chunk","created":1759316452,"choices":[{"index":0,"delta":{"role":"assistant","content":"Hello"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":"fpv0_ef28f882"}
+      data: {"id":"gen-1759322621-TFyRE7QqvCi8A7vVSHKy","provider":"Novita","model":"moonshotai/kimi-k2-0905","object":"chat.completion.chunk","created":1759322621,"choices":[{"index":0,"delta":{"role":"assistant","content":"Hello"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":"fpv0_ef28f882"}
 
-      data: {"id":"gen-1759316452-0gJYswImYao5Of0iy7j1","provider":"Moonshot AI","model":"moonshotai/kimi-k2-0905","object":"chat.completion.chunk","created":1759316452,"choices":[{"index":0,"delta":{"role":"assistant","content":"."},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":"fpv0_ef28f882"}
+      data: {"id":"gen-1759322621-TFyRE7QqvCi8A7vVSHKy","provider":"Novita","model":"moonshotai/kimi-k2-0905","object":"chat.completion.chunk","created":1759322621,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}],"system_fingerprint":"fpv0_ef28f882"}
 
-      data: {"id":"gen-1759316452-0gJYswImYao5Of0iy7j1","provider":"Moonshot AI","model":"moonshotai/kimi-k2-0905","object":"chat.completion.chunk","created":1759316452,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}],"system_fingerprint":"fpv0_ef28f882"}
-
-      data: {"id":"gen-1759316452-0gJYswImYao5Of0iy7j1","provider":"Moonshot AI","model":"moonshotai/kimi-k2-0905","object":"chat.completion.chunk","created":1759316452,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":7552,"completion_tokens":3,"total_tokens":7555,"cost":0.0045387,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0045312,"upstream_inference_completions_cost":0.0000075},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      data: {"id":"gen-1759322621-TFyRE7QqvCi8A7vVSHKy","provider":"Novita","model":"moonshotai/kimi-k2-0905","object":"chat.completion.chunk","created":1759322621,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":7552,"completion_tokens":2,"total_tokens":7554,"cost":0.0045362,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0045312,"upstream_inference_completions_cost":0.000005},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
 
       data: [DONE]
 
@@ -80,4 +78,4 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 4.667991458s
+    duration: 2.331369875s

internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/sourcegraph_tool.yaml 🔗

@@ -0,0 +1,322 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 716
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse sourcegraph to search for ''func main'' in Go repositories","role":"user"}],"model":"qwen/qwen3-next-80b-a3b-instruct","max_tokens":40,"stream_options":{"include_usage":true},"usage":{"include":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://openrouter.ai/api/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"gen-1759324078-x7ZcQt0aUZGcghnMwFjT","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324078,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759324078-x7ZcQt0aUZGcghnMwFjT","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324078,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759324078-x7ZcQt0aUZGcghnMwFjT","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324078,"choices":[{"index":0,"delta":{"role":"assistant","content":"Search"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759324078-x7ZcQt0aUZGcghnMwFjT","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324078,"choices":[{"index":0,"delta":{"role":"assistant","content":" for func"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759324078-x7ZcQt0aUZGcghnMwFjT","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324078,"choices":[{"index":0,"delta":{"role":"assistant","content":" main in Go repositories"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759324078-x7ZcQt0aUZGcghnMwFjT","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324078,"choices":[{"index":0,"delta":{"role":"assistant","content":" using Source"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759324078-x7ZcQt0aUZGcghnMwFjT","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324078,"choices":[{"index":0,"delta":{"role":"assistant","content":"graph"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759324078-x7ZcQt0aUZGcghnMwFjT","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324078,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
+
+      data: {"id":"gen-1759324078-x7ZcQt0aUZGcghnMwFjT","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324078,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":125,"completion_tokens":11,"total_tokens":136,"cost":0.0000329,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000175,"upstream_inference_completions_cost":0.0000154},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream
+    status: 200 OK
+    code: 200
+    duration: 564.385416ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30621
+    host: ""

internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/write_tool.yaml 🔗

@@ -0,0 +1,230 @@
+---
+version: 2
+interactions:
+- id: 0
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 765
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse write to create a new file called config.json with content ''{\"name\": \"test\", \"version\": \"1.0.0\"}''","role":"user"}],"model":"qwen/qwen3-next-80b-a3b-instruct","max_tokens":40,"stream_options":{"include_usage":true},"usage":{"include":true},"stream":true}'
+    headers:
+      Accept:
+      - application/json
+      Content-Type:
+      - application/json
+      User-Agent:
+      - OpenAI/Go 2.3.0
+    url: https://openrouter.ai/api/v1/chat/completions
+    method: POST
+  response:
+    proto: HTTP/2.0
+    proto_major: 2
+    proto_minor: 0
+    content_length: -1
+    body: |+
+      data: {"id":"gen-1759324239-kCtpYE5oZ0djYufAfuoA","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324239,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759324239-kCtpYE5oZ0djYufAfuoA","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324239,"choices":[{"index":0,"delta":{"role":"assistant","content":"Create"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759324239-kCtpYE5oZ0djYufAfuoA","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324239,"choices":[{"index":0,"delta":{"role":"assistant","content":" config"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759324239-kCtpYE5oZ0djYufAfuoA","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324239,"choices":[{"index":0,"delta":{"role":"assistant","content":".json"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759324239-kCtpYE5oZ0djYufAfuoA","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324239,"choices":[{"index":0,"delta":{"role":"assistant","content":" with"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759324239-kCtpYE5oZ0djYufAfuoA","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324239,"choices":[{"index":0,"delta":{"role":"assistant","content":" test"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759324239-kCtpYE5oZ0djYufAfuoA","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324239,"choices":[{"index":0,"delta":{"role":"assistant","content":" data"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1759324239-kCtpYE5oZ0djYufAfuoA","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324239,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
+
+      data: {"id":"gen-1759324239-kCtpYE5oZ0djYufAfuoA","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1759324239,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":141,"completion_tokens":7,"total_tokens":148,"cost":0.00003165,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.00002115,"upstream_inference_completions_cost":0.0000105},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream
+    status: 200 OK
+    code: 200
+    duration: 1.025030083s
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 30664
+    host: ""

internal/agent/tools/download.go 🔗

@@ -32,14 +32,16 @@ const DownloadToolName = "download"
 //go:embed download.md
 var downloadDescription []byte
 
-func NewDownloadTool(permissions permission.Service, workingDir string) ai.AgentTool {
-	client := &http.Client{
-		Timeout: 5 * time.Minute, // Default 5 minute timeout for downloads
-		Transport: &http.Transport{
-			MaxIdleConns:        100,
-			MaxIdleConnsPerHost: 10,
-			IdleConnTimeout:     90 * time.Second,
-		},
+func NewDownloadTool(permissions permission.Service, workingDir string, client *http.Client) ai.AgentTool {
+	if client == nil {
+		client = &http.Client{
+			Timeout: 5 * time.Minute, // Default 5 minute timeout for downloads
+			Transport: &http.Transport{
+				MaxIdleConns:        100,
+				MaxIdleConnsPerHost: 10,
+				IdleConnTimeout:     90 * time.Second,
+			},
+		}
 	}
 	return ai.NewAgentTool(
 		DownloadToolName,

internal/agent/tools/fetch.go 🔗

@@ -39,14 +39,16 @@ const FetchToolName = "fetch"
 //go:embed fetch.md
 var fetchDescription []byte
 
-func NewFetchTool(permissions permission.Service, workingDir string) ai.AgentTool {
-	client := &http.Client{
-		Timeout: 30 * time.Second,
-		Transport: &http.Transport{
-			MaxIdleConns:        100,
-			MaxIdleConnsPerHost: 10,
-			IdleConnTimeout:     90 * time.Second,
-		},
+func NewFetchTool(permissions permission.Service, workingDir string, client *http.Client) ai.AgentTool {
+	if client == nil {
+		client = &http.Client{
+			Timeout: 30 * time.Second,
+			Transport: &http.Transport{
+				MaxIdleConns:        100,
+				MaxIdleConnsPerHost: 10,
+				IdleConnTimeout:     90 * time.Second,
+			},
+		}
 	}
 
 	return ai.NewAgentTool(

internal/agent/tools/sourcegraph.go 🔗

@@ -31,14 +31,16 @@ const SourcegraphToolName = "sourcegraph"
 //go:embed sourcegraph.md
 var sourcegraphDescription []byte
 
-func NewSourcegraphTool() ai.AgentTool {
-	client := &http.Client{
-		Timeout: 30 * time.Second,
-		Transport: &http.Transport{
-			MaxIdleConns:        100,
-			MaxIdleConnsPerHost: 10,
-			IdleConnTimeout:     90 * time.Second,
-		},
+func NewSourcegraphTool(client *http.Client) ai.AgentTool {
+	if client == nil {
+		client = &http.Client{
+			Timeout: 30 * time.Second,
+			Transport: &http.Transport{
+				MaxIdleConns:        100,
+				MaxIdleConnsPerHost: 10,
+				IdleConnTimeout:     90 * time.Second,
+			},
+		}
 	}
 	return ai.NewAgentTool(
 		SourcegraphToolName,

internal/shell/persistent.go 🔗

@@ -29,6 +29,12 @@ func GetPersistentShell(cwd string) *PersistentShell {
 	return shellInstance
 }
 
+// INFO: only used for tests
+func Reset(cwd string) {
+	once = sync.Once{}
+	_ = GetPersistentShell(cwd)
+}
+
 // slog.dapter adapts the internal slog.package to the Logger interface
 type loggingAdapter struct{}