Merge branch 'main' into ui

Ayman Bagabas created

Change summary

.github/cla-signatures.json                                                        |   8 
Taskfile.yaml                                                                      |   7 
go.mod                                                                             |  15 
go.sum                                                                             |  30 
internal/agent/agent.go                                                            |  46 
internal/agent/agent_test.go                                                       |   4 
internal/agent/agent_tool.go                                                       |   2 
internal/agent/common_test.go                                                      |   2 
internal/agent/coordinator.go                                                      |  11 
internal/agent/templates/summary.md                                                |   2 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/bash_tool.yaml             |  27 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/download_tool.yaml         |  23 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/fetch_tool.yaml            |  26 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/glob_tool.yaml             |  22 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/grep_tool.yaml             |  25 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/ls_tool.yaml               |  25 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/multiedit_tool.yaml        |  28 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/parallel_tool_calls.yaml   |  25 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/read_a_file.yaml           |  22 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/simple_test.yaml           |  16 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/sourcegraph_tool.yaml      |  22 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/update_a_file.yaml         |  20 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/write_tool.yaml            |   3 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/bash_tool.yaml                 |  38 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/download_tool.yaml             |  22 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/fetch_tool.yaml                |  28 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/glob_tool.yaml                 |  28 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/grep_tool.yaml                 |  30 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/ls_tool.yaml                   |  26 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/multiedit_tool.yaml            |  40 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/parallel_tool_calls.yaml       |  26 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/read_a_file.yaml               |  20 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/simple_test.yaml               |  14 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/sourcegraph_tool.yaml          |  36 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/update_a_file.yaml             |  30 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/write_tool.yaml                |  26 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/bash_tool.yaml           |  49 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/download_tool.yaml       |  24 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/fetch_tool.yaml          |  24 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/glob_tool.yaml           |  30 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/grep_tool.yaml           |  26 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/ls_tool.yaml             |   2 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/multiedit_tool.yaml      |  34 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/parallel_tool_calls.yaml |  22 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/read_a_file.yaml         |  18 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/simple_test.yaml         |  12 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/sourcegraph_tool.yaml    |  22 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/update_a_file.yaml       |  18 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/write_tool.yaml          |  36 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/bash_tool.yaml                   |  20 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/download_tool.yaml               |  20 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/fetch_tool.yaml                  |   3 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/glob_tool.yaml                   |  18 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/grep_tool.yaml                   |  18 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/ls_tool.yaml                     |  18 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/multiedit_tool.yaml              |  20 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/parallel_tool_calls.yaml         |  18 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/read_a_file.yaml                 |   2 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/simple_test.yaml                 |  14 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/sourcegraph_tool.yaml            |  20 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/update_a_file.yaml               |  24 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/write_tool.yaml                  |  22 
internal/agent/tools/edit.go                                                       |  13 
internal/agent/tools/ls.go                                                         |   2 
internal/agent/tools/todos.go                                                      | 134 
internal/agent/tools/todos.md                                                      |  90 
internal/app/app.go                                                                |  37 
internal/cmd/root.go                                                               |  18 
internal/cmd/run.go                                                                |   5 
internal/config/config.go                                                          |   1 
internal/config/load.go                                                            |   3 
internal/config/load_test.go                                                       |   4 
internal/db/migrations/20250812000000_add_todos_to_sessions.sql                    |   9 
internal/db/models.go                                                              |   1 
internal/db/sessions.sql.go                                                        |  17 
internal/db/sql/sessions.sql                                                       |   3 
internal/env/env.go                                                                |   8 
internal/env/env_test.go                                                           |   4 
internal/session/session.go                                                        |  53 
internal/shell/background_test.go                                                  |   5 
internal/term/term.go                                                              |  15 
internal/tui/components/chat/chat.go                                               |  50 
internal/tui/components/chat/editor/editor.go                                      |   5 
internal/tui/components/chat/messages/renderer.go                                  |  95 
internal/tui/components/chat/messages/tool.go                                      |   2 
internal/tui/components/chat/queue.go                                              |  28 
internal/tui/components/chat/todos/todos.go                                        |  67 
internal/tui/exp/list/list.go                                                      | 118 
internal/tui/page/chat/chat.go                                                     | 274 
internal/tui/page/chat/keys.go                                                     |  15 
internal/tui/page/chat/pills.go                                                    | 125 
internal/tui/styles/icons.go                                                       |  24 
92 files changed, 1,754 insertions(+), 780 deletions(-)

Detailed changes

.github/cla-signatures.json 🔗

@@ -943,6 +943,14 @@
       "created_at": "2025-12-10T12:04:50Z",
       "repoId": 987670088,
       "pullRequestNo": 1592
+    },
+    {
+      "name": "nonsleepr",
+      "id": 2337602,
+      "comment_id": 3644171671,
+      "created_at": "2025-12-11T23:09:21Z",
+      "repoId": 987670088,
+      "pullRequestNo": 1611
     }
   ]
 }

Taskfile.yaml 🔗

@@ -123,3 +123,10 @@ tasks:
     cmds:
       - git tag -d nightly || true
       - git fetch --tags
+
+  deps:
+    desc: Update Fantasy and Catwalk
+    cmds:
+      - go get charm.land/fantasy
+      - go get github.com/charmbracelet/catwalk
+      - go mod tidy

go.mod 🔗

@@ -4,8 +4,8 @@ go 1.25.5
 
 require (
 	charm.land/bubbles/v2 v2.0.0-rc.1
-	charm.land/bubbletea/v2 v2.0.0-rc.2.0.20251210233456-3f036811208b
-	charm.land/fantasy v0.5.1
+	charm.land/bubbletea/v2 v2.0.0-rc.2.0.20251212022530-7adbf082fd25
+	charm.land/fantasy v0.5.2
 	charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251205162909-7869489d8971
 	charm.land/x/vcr v0.1.1
 	github.com/JohannesKaufmann/html-to-markdown v1.6.0
@@ -16,13 +16,13 @@ require (
 	github.com/aymanbagabas/go-udiff v0.3.1
 	github.com/bmatcuk/doublestar/v4 v4.9.1
 	github.com/charlievieth/fastwalk v1.0.14
-	github.com/charmbracelet/catwalk v0.9.7-0.20251208190755-350e2a004c74
-	github.com/charmbracelet/colorprofile v0.3.3
+	github.com/charmbracelet/catwalk v0.10.1
+	github.com/charmbracelet/colorprofile v0.4.1
 	github.com/charmbracelet/fang v0.4.4
 	github.com/charmbracelet/glamour/v2 v2.0.0-20251106195642-800eb8175930
 	github.com/charmbracelet/log/v2 v2.0.0-20251106192421-eb64aaa963a0
-	github.com/charmbracelet/ultraviolet v0.0.0-20251210233322-b32b4bd64885
-	github.com/charmbracelet/x/ansi v0.11.2
+	github.com/charmbracelet/ultraviolet v0.0.0-20251211195649-3a51f4048cae
+	github.com/charmbracelet/x/ansi v0.11.3
 	github.com/charmbracelet/x/exp/charmtone v0.0.0-20250708181618-a60a724ba6c3
 	github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f
 	github.com/charmbracelet/x/exp/ordered v0.1.0
@@ -91,10 +91,11 @@ require (
 	github.com/bahlo/generic-list-go v0.2.0 // indirect
 	github.com/buger/jsonparser v1.1.1 // indirect
 	github.com/charmbracelet/anthropic-sdk-go v0.0.0-20251024181547-21d6f3d9a904 // indirect
+	github.com/charmbracelet/x/etag v0.2.0 // indirect
 	github.com/charmbracelet/x/json v0.2.0 // indirect
 	github.com/charmbracelet/x/termios v0.1.1 // indirect
 	github.com/charmbracelet/x/windows v0.2.2 // indirect
-	github.com/clipperhouse/displaywidth v0.6.0 // indirect
+	github.com/clipperhouse/displaywidth v0.6.1 // indirect
 	github.com/clipperhouse/stringish v0.1.1 // indirect
 	github.com/clipperhouse/uax29/v2 v2.3.0 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect

go.sum 🔗

@@ -1,9 +1,9 @@
 charm.land/bubbles/v2 v2.0.0-rc.1 h1:EiIFVAc3Zi/yY86td+79mPhHR7AqZ1OxF+6ztpOCRaM=
 charm.land/bubbles/v2 v2.0.0-rc.1/go.mod h1:5AbN6cEd/47gkEf8TgiQ2O3RZ5QxMS14l9W+7F9fPC4=
-charm.land/bubbletea/v2 v2.0.0-rc.2.0.20251210233456-3f036811208b h1:naRWnYU7AQfM7yaPiNQ9JfI0VcikCcO7CIFultZO4lA=
-charm.land/bubbletea/v2 v2.0.0-rc.2.0.20251210233456-3f036811208b/go.mod h1:MxP/RlEJqSMLaCCFtqiV1yqlXDq1chrbjhr7jj653ug=
-charm.land/fantasy v0.5.1 h1:Svi/UpI4/DwVjTqNYceDXoJJYn6SVEM5dnLH92UBiEs=
-charm.land/fantasy v0.5.1/go.mod h1:SPOsnIlkBKnhw2Wnasv+wZ82EmCMIGesx0je3tgR6+M=
+charm.land/bubbletea/v2 v2.0.0-rc.2.0.20251212022530-7adbf082fd25 h1:qmVU/kDsds1L+caeJ2LghFyFOn/1iEx9RRbQ6YQkxb4=
+charm.land/bubbletea/v2 v2.0.0-rc.2.0.20251212022530-7adbf082fd25/go.mod h1:C1MMjbspGDebEITrYpuJd6gB42cSTqWgR4/vQPjD224=
+charm.land/fantasy v0.5.2 h1:4zlNsIcsyF3Jr+1onEuhHqZRzuH1LlxBle/gInS00QY=
+charm.land/fantasy v0.5.2/go.mod h1:SPOsnIlkBKnhw2Wnasv+wZ82EmCMIGesx0je3tgR6+M=
 charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251205162909-7869489d8971 h1:xZFcNsJMiIDbFtWRyDmkKNk1sjojfaom4Zoe0cyH/8c=
 charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251205162909-7869489d8971/go.mod h1:i61Y3FmdbcBNSKa+pKB3DaE4uVQmBLMs/xlvRyHcXAE=
 charm.land/x/vcr v0.1.1 h1:PXCFMUG0rPtyk35rhfzYCJEduOzWXCIbrXTFq4OF/9Q=
@@ -88,20 +88,22 @@ github.com/charlievieth/fastwalk v1.0.14 h1:3Eh5uaFGwHZd8EGwTjJnSpBkfwfsak9h6ICg
 github.com/charlievieth/fastwalk v1.0.14/go.mod h1:diVcUreiU1aQ4/Wu3NbxxH4/KYdKpLDojrQ1Bb2KgNY=
 github.com/charmbracelet/anthropic-sdk-go v0.0.0-20251024181547-21d6f3d9a904 h1:rwLdEpG9wE6kL69KkEKDiWprO8pQOZHZXeod6+9K+mw=
 github.com/charmbracelet/anthropic-sdk-go v0.0.0-20251024181547-21d6f3d9a904/go.mod h1:8TIYxZxsuCqqeJ0lga/b91tBwrbjoHDC66Sq5t8N2R4=
-github.com/charmbracelet/catwalk v0.9.7-0.20251208190755-350e2a004c74 h1:pJI8ivIgSWOeCNnZFXeZzL6px1vZVS3LU4Cqk3Gx37I=
-github.com/charmbracelet/catwalk v0.9.7-0.20251208190755-350e2a004c74/go.mod h1:ReU4SdrLfe63jkEjWMdX2wlZMV3k9r11oQAmzN0m+KY=
-github.com/charmbracelet/colorprofile v0.3.3 h1:DjJzJtLP6/NZ8p7Cgjno0CKGr7wwRJGxWUwh2IyhfAI=
-github.com/charmbracelet/colorprofile v0.3.3/go.mod h1:nB1FugsAbzq284eJcjfah2nhdSLppN2NqvfotkfRYP4=
+github.com/charmbracelet/catwalk v0.10.1 h1:Yov/bEni8eDU+uP68YuqgHo0UW1sDozVHwHdlWbklJ4=
+github.com/charmbracelet/catwalk v0.10.1/go.mod h1:qg+Yl9oaZTkTvRscqbxfttzOFQ4v0pOT5XwC7b5O0NQ=
+github.com/charmbracelet/colorprofile v0.4.1 h1:a1lO03qTrSIRaK8c3JRxJDZOvhvIeSco3ej+ngLk1kk=
+github.com/charmbracelet/colorprofile v0.4.1/go.mod h1:U1d9Dljmdf9DLegaJ0nGZNJvoXAhayhmidOdcBwAvKk=
 github.com/charmbracelet/fang v0.4.4 h1:G4qKxF6or/eTPgmAolwPuRNyuci3hTUGGX1rj1YkHJY=
 github.com/charmbracelet/fang v0.4.4/go.mod h1:P5/DNb9DddQ0Z0dbc0P3ol4/ix5Po7Ofr2KMBfAqoCo=
 github.com/charmbracelet/glamour/v2 v2.0.0-20251106195642-800eb8175930 h1:+47Z2jVAWPSLGjPRbfZizW3OpcAYsu7EUk2DR+66FyM=
 github.com/charmbracelet/glamour/v2 v2.0.0-20251106195642-800eb8175930/go.mod h1:izs11tnkYaT3DTEH2E0V/lCb18VGZ7k9HLYEGuvgXGA=
 github.com/charmbracelet/log/v2 v2.0.0-20251106192421-eb64aaa963a0 h1:lxHzxsHd4P7o7+5D5OcEItYkQ1xY3ovNg8Dc5ftd3rI=
 github.com/charmbracelet/log/v2 v2.0.0-20251106192421-eb64aaa963a0/go.mod h1:Q7oMtlboDPnnrYiJDXNwdWmJblOmuOnycPKczlVju6I=
-github.com/charmbracelet/ultraviolet v0.0.0-20251210233322-b32b4bd64885 h1:L+Gmsk8Op+cnW2MSNm3F+iVa4SK5VOTHX0CV06tCxkE=
-github.com/charmbracelet/ultraviolet v0.0.0-20251210233322-b32b4bd64885/go.mod h1:Y6kE2GzHfkyQQVCSL9r2hwokSrIlHGzZG+71+wDYSZI=
-github.com/charmbracelet/x/ansi v0.11.2 h1:XAG3FSjiVtFvgEgGrNBkCNNYrsucAt8c6bfxHyROLLs=
-github.com/charmbracelet/x/ansi v0.11.2/go.mod h1:9tY2bzX5SiJCU0iWyskjBeI2BRQfvPqI+J760Mjf+Rg=
+github.com/charmbracelet/ultraviolet v0.0.0-20251211195649-3a51f4048cae h1:njFQJDtNiWgKXHmYruigCG+9q5Ptq6rWW400UvG/Tpc=
+github.com/charmbracelet/ultraviolet v0.0.0-20251211195649-3a51f4048cae/go.mod h1:VWATWLRwYP06VYCEur7FsNR2B1xAo7Y+xl1PTbd1ePc=
+github.com/charmbracelet/x/ansi v0.11.3 h1:6DcVaqWI82BBVM/atTyq6yBoRLZFBsnoDoX9GCu2YOI=
+github.com/charmbracelet/x/ansi v0.11.3/go.mod h1:yI7Zslym9tCJcedxz5+WBq+eUGMJT0bM06Fqy1/Y4dI=
+github.com/charmbracelet/x/etag v0.2.0 h1:Euj1VkheoHfTYA9y+TCwkeXF/hN8Fb9l4LqZl79pt04=
+github.com/charmbracelet/x/etag v0.2.0/go.mod h1:C1B7/bsgvzzxpfu0Rabbd+rTHJa5TmC/qgTseCf6DF0=
 github.com/charmbracelet/x/exp/charmtone v0.0.0-20250708181618-a60a724ba6c3 h1:1xwHZg6eMZ9Wv5TE1UGub6ARubyOd1Lo5kPUI/6VL50=
 github.com/charmbracelet/x/exp/charmtone v0.0.0-20250708181618-a60a724ba6c3/go.mod h1:T9jr8CzFpjhFVHjNjKwbAD7KwBNyFnj2pntAO7F2zw0=
 github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA=
@@ -120,8 +122,8 @@ github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8
 github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo=
 github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2/jYn2GuM=
 github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k=
-github.com/clipperhouse/displaywidth v0.6.0 h1:k32vueaksef9WIKCNcoqRNyKbyvkvkysNYnAWz2fN4s=
-github.com/clipperhouse/displaywidth v0.6.0/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o=
+github.com/clipperhouse/displaywidth v0.6.1 h1:/zMlAezfDzT2xy6acHBzwIfyu2ic0hgkT83UX5EY2gY=
+github.com/clipperhouse/displaywidth v0.6.1/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o=
 github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
 github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
 github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4=

internal/agent/agent.go 🔗

@@ -65,6 +65,7 @@ type SessionAgent interface {
 	IsSessionBusy(sessionID string) bool
 	IsBusy() bool
 	QueuedPrompts(sessionID string) int
+	QueuedPromptsList(sessionID string) []string
 	ClearQueue(sessionID string)
 	Summarize(context.Context, string, fantasy.ProviderOptions) error
 	Model() Model
@@ -81,6 +82,7 @@ type sessionAgent struct {
 	smallModel           Model
 	systemPromptPrefix   string
 	systemPrompt         string
+	isSubAgent           bool
 	tools                []fantasy.AgentTool
 	sessions             session.Service
 	messages             message.Service
@@ -96,6 +98,7 @@ type SessionAgentOptions struct {
 	SmallModel           Model
 	SystemPromptPrefix   string
 	SystemPrompt         string
+	IsSubAgent           bool
 	DisableAutoSummarize bool
 	IsYolo               bool
 	Sessions             session.Service
@@ -111,6 +114,7 @@ func NewSessionAgent(
 		smallModel:           opts.SmallModel,
 		systemPromptPrefix:   opts.SystemPromptPrefix,
 		systemPrompt:         opts.SystemPrompt,
+		isSubAgent:           opts.IsSubAgent,
 		sessions:             opts.Sessions,
 		messages:             opts.Messages,
 		disableAutoSummarize: opts.DisableAutoSummarize,
@@ -343,9 +347,14 @@ func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy
 				finishReason = message.FinishReasonToolUse
 			}
 			currentAssistant.AddFinish(finishReason, "", "")
-			a.updateSessionUsage(a.largeModel, &currentSession, stepResult.Usage, a.openrouterCost(stepResult.ProviderMetadata))
 			sessionLock.Lock()
-			_, sessionErr := a.sessions.Save(genCtx, currentSession)
+			updatedSession, getSessionErr := a.sessions.Get(genCtx, call.SessionID)
+			if getSessionErr != nil {
+				sessionLock.Unlock()
+				return getSessionErr
+			}
+			a.updateSessionUsage(a.largeModel, &updatedSession, stepResult.Usage, a.openrouterCost(stepResult.ProviderMetadata))
+			_, sessionErr := a.sessions.Save(genCtx, updatedSession)
 			sessionLock.Unlock()
 			if sessionErr != nil {
 				return sessionErr
@@ -531,8 +540,18 @@ func (a *sessionAgent) Summarize(ctx context.Context, sessionID string, opts fan
 		return err
 	}
 
+	summaryPromptText := "Provide a detailed summary of our conversation above."
+	if len(currentSession.Todos) > 0 {
+		summaryPromptText += "\n\n## Current Todo List\n\n"
+		for _, t := range currentSession.Todos {
+			summaryPromptText += fmt.Sprintf("- [%s] %s\n", t.Status, t.Content)
+		}
+		summaryPromptText += "\nInclude these tasks and their statuses in your summary. "
+		summaryPromptText += "Instruct the resuming assistant to use the `todos` tool to continue tracking progress on these tasks."
+	}
+
 	resp, err := agent.Stream(genCtx, fantasy.AgentStreamCall{
-		Prompt:          "Provide a detailed summary of our conversation above.",
+		Prompt:          summaryPromptText,
 		Messages:        aiMsgs,
 		ProviderOptions: opts,
 		PrepareStep: func(callContext context.Context, options fantasy.PrepareStepFunctionOptions) (_ context.Context, prepared fantasy.PrepareStepResult, err error) {
@@ -633,6 +652,15 @@ func (a *sessionAgent) createUserMessage(ctx context.Context, call SessionAgentC
 
 func (a *sessionAgent) preparePrompt(msgs []message.Message, attachments ...message.Attachment) ([]fantasy.Message, []fantasy.FilePart) {
 	var history []fantasy.Message
+	if !a.isSubAgent {
+		history = append(history, fantasy.NewUserMessage(
+			fmt.Sprintf("<system_reminder>%s</system_reminder>",
+				`This is a reminder that your todo list is currently empty. DO NOT mention this to the user explicitly because they are already aware.
+If you are working on tasks that would benefit from a todo list please use the "todos" tool to create one.
+If not, please feel free to ignore. Again do not mention this message to the user.`,
+			),
+		))
+	}
 	for _, m := range msgs {
 		if len(m.Parts) == 0 {
 			continue
@@ -851,6 +879,18 @@ func (a *sessionAgent) QueuedPrompts(sessionID string) int {
 	return len(l)
 }
 
+func (a *sessionAgent) QueuedPromptsList(sessionID string) []string {
+	l, ok := a.messageQueue.Get(sessionID)
+	if !ok {
+		return nil
+	}
+	prompts := make([]string, len(l))
+	for i, call := range l {
+		prompts[i] = call.Prompt
+	}
+	return prompts
+}
+
 func (a *sessionAgent) SetModels(large Model, small Model) {
 	a.largeModel = large
 	a.smallModel = small

internal/agent/agent_test.go 🔗

@@ -453,6 +453,10 @@ func TestCoderAgent(t *testing.T) {
 				require.Contains(t, string(content), "Hello, Crush!", "Expected file to contain 'Hello, Crush!'")
 			})
 			t.Run("sourcegraph tool", func(t *testing.T) {
+				if runtime.GOOS == "darwin" {
+					t.Skip("skipping flacky test on macos for now")
+				}
+
 				agent, env := setupAgent(t, pair)
 
 				session, err := env.sessions.Create(t.Context(), "New Session")

internal/agent/agent_tool.go 🔗

@@ -34,7 +34,7 @@ func (c *coordinator) agentTool(ctx context.Context) (fantasy.AgentTool, error)
 		return nil, err
 	}
 
-	agent, err := c.buildAgent(ctx, prompt, agentCfg)
+	agent, err := c.buildAgent(ctx, prompt, agentCfg, true)
 	if err != nil {
 		return nil, err
 	}

internal/agent/common_test.go 🔗

@@ -149,7 +149,7 @@ func testSessionAgent(env fakeEnv, large, small fantasy.LanguageModel, systemPro
 			DefaultMaxTokens: 10000,
 		},
 	}
-	agent := NewSessionAgent(SessionAgentOptions{largeModel, smallModel, "", systemPrompt, false, true, env.sessions, env.messages, tools})
+	agent := NewSessionAgent(SessionAgentOptions{largeModel, smallModel, "", systemPrompt, false, false, true, env.sessions, env.messages, tools})
 	return agent
 }
 

internal/agent/coordinator.go 🔗

@@ -49,6 +49,7 @@ type Coordinator interface {
 	IsSessionBusy(sessionID string) bool
 	IsBusy() bool
 	QueuedPrompts(sessionID string) int
+	QueuedPromptsList(sessionID string) []string
 	ClearQueue(sessionID string)
 	Summarize(context.Context, string) error
 	Model() Model
@@ -99,7 +100,7 @@ func NewCoordinator(
 		return nil, err
 	}
 
-	agent, err := c.buildAgent(ctx, prompt, agentCfg)
+	agent, err := c.buildAgent(ctx, prompt, agentCfg, false)
 	if err != nil {
 		return nil, err
 	}
@@ -299,7 +300,7 @@ func mergeCallOptions(model Model, cfg config.ProviderConfig) (fantasy.ProviderO
 	return modelOptions, temp, topP, topK, freqPenalty, presPenalty
 }
 
-func (c *coordinator) buildAgent(ctx context.Context, prompt *prompt.Prompt, agent config.Agent) (SessionAgent, error) {
+func (c *coordinator) buildAgent(ctx context.Context, prompt *prompt.Prompt, agent config.Agent, isSubAgent bool) (SessionAgent, error) {
 	large, small, err := c.buildAgentModels(ctx)
 	if err != nil {
 		return nil, err
@@ -316,6 +317,7 @@ func (c *coordinator) buildAgent(ctx context.Context, prompt *prompt.Prompt, age
 		small,
 		largeProviderCfg.SystemPromptPrefix,
 		systemPrompt,
+		isSubAgent,
 		c.cfg.Options.DisableAutoSummarize,
 		c.permissions.SkipRequests(),
 		c.sessions,
@@ -372,6 +374,7 @@ func (c *coordinator) buildTools(ctx context.Context, agent config.Agent) ([]fan
 		tools.NewGrepTool(c.cfg.WorkingDir()),
 		tools.NewLsTool(c.permissions, c.cfg.WorkingDir(), c.cfg.Tools.Ls),
 		tools.NewSourcegraphTool(nil),
+		tools.NewTodosTool(c.sessions),
 		tools.NewViewTool(c.lspClients, c.permissions, c.cfg.WorkingDir()),
 		tools.NewWriteTool(c.lspClients, c.permissions, c.history, c.cfg.WorkingDir()),
 	)
@@ -783,6 +786,10 @@ func (c *coordinator) QueuedPrompts(sessionID string) int {
 	return c.currentAgent.QueuedPrompts(sessionID)
 }
 
+func (c *coordinator) QueuedPromptsList(sessionID string) []string {
+	return c.currentAgent.QueuedPromptsList(sessionID)
+}
+
 func (c *coordinator) Summarize(ctx context.Context, sessionID string) error {
 	providerCfg, ok := c.cfg.Providers.Get(c.currentAgent.Model().ModelCfg.Provider)
 	if !ok {

internal/agent/templates/summary.md 🔗

@@ -43,6 +43,6 @@ Be specific. Don't write "implement authentication" - write:
 2. Update login handler in src/routes/user.js:45 to return token
 3. Test with: npm test -- auth.test.js
 
-**Tone**: Write as if briefing a teammate taking over mid-task. Include everything they'd need to continue without asking questions.
+**Tone**: Write as if briefing a teammate taking over mid-task. Include everything they'd need to continue without asking questions. No emojis ever.
 
 **Length**: No limit. Err on the side of too much detail rather than too little. Critical context is worth the tokens.

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

@@ -25,55 +25,52 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01WbEA766f9Qb2tqVyGdK8Vp","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":152,"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":{"model":"claude-3-5-haiku-20241022","id":"msg_01Ca5xhYzdyJq1rP5TwDth2W","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":152,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"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":"Create"}            }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Bash File"}         }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Bash"}     }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Creation"}           }
 
       event: ping
       data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" File"}               }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" with"}       }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" with"} }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Hello"} }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Hello"}       }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Message"}   }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Content"}               }
 
       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":152,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":10}    }
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":152,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":10}}
 
       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: 578.171791ms
+    duration: 734.910625ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51454
+    content_length: 51899
     host: ""

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

@@ -25,49 +25,46 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_016cryhi9rouvHEAvvdKN8UD","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":160,"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":{"model":"claude-3-5-haiku-20241022","id":"msg_012dSg4T5MVDEgj8PUhB7ihp","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":160,"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":"Downloa"}      }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Downloa"}     }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"d Example"}               }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"d File"}          }
 
       event: ping
       data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Text"}       }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" File"}             }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" from Example URL"}          }
 
       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":160,"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":160,"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: 501.558292ms
+    duration: 733.403208ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51479
+    content_length: 51924
     host: ""

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

@@ -25,46 +25,52 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01PA2SxHoJrhJcDMR54kAth4","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":167,"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":{"model":"claude-3-5-haiku-20241022","id":"msg_0143Jw7v3wgt2bpCFEtGkuHv","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":167,"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":"Web"} }
+      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"}      }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Page Search"} }
 
       event: ping
       data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Content Check"}  }
+      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":" John"}         }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Doe"}             }
 
       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":167,"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":167,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":10}    }
 
       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: 771.713375ms
+    duration: 1.120772708s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51497
+    content_length: 51942
     host: ""

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

@@ -25,49 +25,49 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01MhpV7YNxJwSxgfQbfgDWut","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":142,"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":{"model":"claude-3-5-haiku-20241022","id":"msg_01UJrSNzeuTRKfD6edRAnioA","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":142,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"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":"Fin"}}
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Glob Go"}        }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"d Go"}               }
+      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":" Files Using"}        }
+      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":" Glob"}             }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Current Directory"}              }
 
       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":142,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":9}        }
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":142,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":10}     }
 
       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: 590.110084ms
+    duration: 596.908916ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51415
+    content_length: 51860
     host: ""

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

@@ -25,49 +25,52 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01ReLDtAAvXCD3g8NAwbvwfh","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":144,"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":{"model":"claude-3-5-haiku-20241022","id":"msg_01EPKmtSyVdvAn6uZoDUPvmm","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":144,"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":"Grep"}   }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Searching"}      }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" "}  }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" for "}          }
 
       event: ping
       data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"'package' in Go"}   }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"'package' in Go"}           }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Files"}               }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" files with"}            }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" grep"}}
 
       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":144,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":12}  }
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":144,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":15}           }
 
       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: 499.278667ms
+    duration: 669.560167ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51413
+    content_length: 51858
     host: ""

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

@@ -25,46 +25,37 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01ATXFbLmKeJh2VY3HTYMXWJ","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":140,"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":{"model":"claude-3-5-haiku-20241022","id":"msg_01GS9L44gUzv4ei1fm9E5B1T","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":140,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":6,"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":"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"}           }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Listing Files in Current Directory"}             }
 
       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":140,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":8}      }
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":140,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":9}             }
 
       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: 576.743583ms
+    duration: 588.114167ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51407
+    content_length: 51852
     host: ""

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

@@ -25,55 +25,49 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01YPw8B7xdJgtQzmBD1yTU4e","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":170,"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":{"model":"claude-3-5-haiku-20241022","id":"msg_01Vi9HRV9KsgZmVqi14RD4Qd","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":170,"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":"Modify"}          }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Edit"}      }
 
       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":" code greeting"}            }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Code"}    }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" with"}             }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" mult"}             }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"iedit"}               }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Greeting"}        }
 
       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":170,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":12}       }
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":170,"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: 626.47275ms
+    duration: 672.068792ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51493
+    content_length: 51938
     host: ""

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

@@ -25,52 +25,49 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_017rF4mnQoNTWfhWntCaRXWD","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":159,"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":{"model":"claude-3-5-haiku-20241022","id":"msg_01MvZPBgrJ1PxooW6vcTNgTP","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":159,"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":"Parallel"}   }
+      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"}       }
+      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":" File"}         }
+      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":" Search and Directory"}            }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Listing"}               }
+      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               }
+      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":159,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":12}    }
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":159,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":11} }
 
       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: 585.640291ms
+    duration: 643.790917ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51504
+    content_length: 51949
     host: ""

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

@@ -25,49 +25,49 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01Etybfx88gjFFiDkGoW3TVC","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":134,"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":{"model":"claude-3-5-haiku-20241022","id":"msg_01WSfpakrUTZru3pucFjjWmQ","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":134,"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":"Rea"}}
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Rea"}    }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"d Go"}       }
+      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":" 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":" Details"}         }
+      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":134,"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":134,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":7}          }
 
       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: 655.510125ms
+    duration: 987.366375ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51377
+    content_length: 51822
     host: ""

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

@@ -25,22 +25,22 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01HximU37BpsyPaDMP2TpWQ1","type":"message","role":"assistant","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"}}     }
+      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01TxmeH5H2NGkxM58ZrqhuU1","type":"message","role":"assistant","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":""}      }
+      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":"Quick"}  }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Quick"}        }
 
       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":" Greeting"}      }
 
       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"}
@@ -49,7 +49,7 @@ interactions:
       data: {"type": "ping"}
 
       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":6}         }
+      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":6}    }
 
       event: message_stop
       data: {"type":"message_stop"             }
@@ -59,15 +59,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 808.120542ms
+    duration: 700.496625ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51367
+    content_length: 51812
     host: ""

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

@@ -25,49 +25,49 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01Vumd9wiF4q5LKxZ4nc5eGM","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":145,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":3,"service_tier":"standard"}} }
+      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_014dxeWmvWs82uYJw8q11pgi","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":145,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"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":"Searching Go"}     }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Searching Go"}          }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Repos"}            }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Repos"}       }
 
       event: ping
       data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" for Main"}       }
+      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"}           }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Function"}}
 
       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":145,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":11} }
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":145,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":11}   }
 
       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: 966.588833ms
+    duration: 720.76ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51427
+    content_length: 51872
     host: ""

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

@@ -25,49 +25,49 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01FZibKN7Bdpd79Lx3jXBCqw","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":145,"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":{"model":"claude-3-5-haiku-20241022","id":"msg_018Kk1bqYYWgiDzM5DRrtHhL","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":145,"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":"Update"}            }
+      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"}    }
+      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 Hello"}      }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":".go Hello"}            }
 
       event: content_block_delta
       data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Print"}          }
 
       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":145,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":9} }
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":145,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":9}           }
 
       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: 575.783417ms
+    duration: 694.563833ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51433
+    content_length: 51878
     host: ""

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

@@ -6,9 +6,9 @@ interactions:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 817
+    content_length: 51915
     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\"}''\n \u003cthink\u003e\n\n\u003c/think\u003e","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\u003crules\u003e\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\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'

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

@@ -24,33 +24,39 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj5ey31f4omQlYpBM4nxpPZtHo4q6","object":"chat.completion.chunk","created":1764862552,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Ge9aw4xR7J9UOe"}
+      data: {"id":"chatcmpl-ClYsFUmhoDNbyWMbB2NUY9x4VTTUz","object":"chat.completion.chunk","created":1765451507,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Td2HKw2IKaNJr9"}
 
-      data: {"id":"chatcmpl-Cj5ey31f4omQlYpBM4nxpPZtHo4q6","object":"chat.completion.chunk","created":1764862552,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"Create"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"9mD6Z8e3hz"}
+      data: {"id":"chatcmpl-ClYsFUmhoDNbyWMbB2NUY9x4VTTUz","object":"chat.completion.chunk","created":1765451507,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"Create"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Ey6L7K1jHN"}
 
-      data: {"id":"chatcmpl-Cj5ey31f4omQlYpBM4nxpPZtHo4q6","object":"chat.completion.chunk","created":1764862552,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"uacc3w7vZwR"}
+      data: {"id":"chatcmpl-ClYsFUmhoDNbyWMbB2NUY9x4VTTUz","object":"chat.completion.chunk","created":1765451507,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"fxtu1PxLkFzDn0"}
 
-      data: {"id":"chatcmpl-Cj5ey31f4omQlYpBM4nxpPZtHo4q6","object":"chat.completion.chunk","created":1764862552,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" test"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"XajeGpvAt5S"}
+      data: {"id":"chatcmpl-ClYsFUmhoDNbyWMbB2NUY9x4VTTUz","object":"chat.completion.chunk","created":1765451507,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"test"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"qLh2W9DjfN9T"}
 
-      data: {"id":"chatcmpl-Cj5ey31f4omQlYpBM4nxpPZtHo4q6","object":"chat.completion.chunk","created":1764862552,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":".txt"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"pyGHV4e7XDyx"}
+      data: {"id":"chatcmpl-ClYsFUmhoDNbyWMbB2NUY9x4VTTUz","object":"chat.completion.chunk","created":1765451507,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":".txt"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"sYxRQ6oIdl88"}
 
-      data: {"id":"chatcmpl-Cj5ey31f4omQlYpBM4nxpPZtHo4q6","object":"chat.completion.chunk","created":1764862552,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"rCcPV5Ebktw"}
+      data: {"id":"chatcmpl-ClYsFUmhoDNbyWMbB2NUY9x4VTTUz","object":"chat.completion.chunk","created":1765451507,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"izmAYTbsu7SDTrw"}
 
-      data: {"id":"chatcmpl-Cj5ey31f4omQlYpBM4nxpPZtHo4q6","object":"chat.completion.chunk","created":1764862552,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"2Jhs0JX1uR1H4P"}
+      data: {"id":"chatcmpl-ClYsFUmhoDNbyWMbB2NUY9x4VTTUz","object":"chat.completion.chunk","created":1765451507,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"eQKZqQvnykY"}
 
-      data: {"id":"chatcmpl-Cj5ey31f4omQlYpBM4nxpPZtHo4q6","object":"chat.completion.chunk","created":1764862552,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"hello"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"7cP9d0yjB1m"}
+      data: {"id":"chatcmpl-ClYsFUmhoDNbyWMbB2NUY9x4VTTUz","object":"chat.completion.chunk","created":1765451507,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"CfOJWpN6vzSRL6"}
 
-      data: {"id":"chatcmpl-Cj5ey31f4omQlYpBM4nxpPZtHo4q6","object":"chat.completion.chunk","created":1764862552,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" bash"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"jzkkMLcPlX0"}
+      data: {"id":"chatcmpl-ClYsFUmhoDNbyWMbB2NUY9x4VTTUz","object":"chat.completion.chunk","created":1765451507,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"hello"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"AKmZ7DtXoX1"}
 
-      data: {"id":"chatcmpl-Cj5ey31f4omQlYpBM4nxpPZtHo4q6","object":"chat.completion.chunk","created":1764862552,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ZSTCYu5wWzA9kQl"}
+      data: {"id":"chatcmpl-ClYsFUmhoDNbyWMbB2NUY9x4VTTUz","object":"chat.completion.chunk","created":1765451507,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" bash"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"0jL8W258MN9"}
 
-      data: {"id":"chatcmpl-Cj5ey31f4omQlYpBM4nxpPZtHo4q6","object":"chat.completion.chunk","created":1764862552,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"GS4OajGMLokcX"}
+      data: {"id":"chatcmpl-ClYsFUmhoDNbyWMbB2NUY9x4VTTUz","object":"chat.completion.chunk","created":1765451507,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"hrqjW9CeiV7hZV3"}
 
-      data: {"id":"chatcmpl-Cj5ey31f4omQlYpBM4nxpPZtHo4q6","object":"chat.completion.chunk","created":1764862552,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Bash"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"NnSiqg12rqr"}
+      data: {"id":"chatcmpl-ClYsFUmhoDNbyWMbB2NUY9x4VTTUz","object":"chat.completion.chunk","created":1765451507,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" ("},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"vNmpaJaHqND1Zq"}
 
-      data: {"id":"chatcmpl-Cj5ey31f4omQlYpBM4nxpPZtHo4q6","object":"chat.completion.chunk","created":1764862552,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"vCjULykNu8"}
+      data: {"id":"chatcmpl-ClYsFUmhoDNbyWMbB2NUY9x4VTTUz","object":"chat.completion.chunk","created":1765451507,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"No"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"MIhLl8PruYZSZ4"}
 
-      data: {"id":"chatcmpl-Cj5ey31f4omQlYpBM4nxpPZtHo4q6","object":"chat.completion.chunk","created":1764862552,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[],"usage":{"prompt_tokens":145,"completion_tokens":11,"total_tokens":156,"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":"Wa56pakK1PBNi"}
+      data: {"id":"chatcmpl-ClYsFUmhoDNbyWMbB2NUY9x4VTTUz","object":"chat.completion.chunk","created":1765451507,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Timestamp"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"mawxsP"}
+
+      data: {"id":"chatcmpl-ClYsFUmhoDNbyWMbB2NUY9x4VTTUz","object":"chat.completion.chunk","created":1765451507,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":")"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"mXXHjOhPYNysGmp"}
+
+      data: {"id":"chatcmpl-ClYsFUmhoDNbyWMbB2NUY9x4VTTUz","object":"chat.completion.chunk","created":1765451507,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"ychGSlZNPt"}
+
+      data: {"id":"chatcmpl-ClYsFUmhoDNbyWMbB2NUY9x4VTTUz","object":"chat.completion.chunk","created":1765451507,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[],"usage":{"prompt_tokens":145,"completion_tokens":14,"total_tokens":159,"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":"G55W87gCWryQY"}
 
       data: [DONE]
 
@@ -59,15 +65,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 491.401209ms
+    duration: 868.570625ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49849
+    content_length: 50240
     host: ""

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

@@ -24,23 +24,23 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj5fDSuOWOdQ0SBxZbFOe4k9XflAp","object":"chat.completion.chunk","created":1764862567,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"7tAT0Arcyy78i3"}
+      data: {"id":"chatcmpl-ClYUKarTNIqX0Kpv3s4rrlesi91DJ","object":"chat.completion.chunk","created":1765450024,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"SBHFH8rdbeYWL0"}
 
-      data: {"id":"chatcmpl-Cj5fDSuOWOdQ0SBxZbFOe4k9XflAp","object":"chat.completion.chunk","created":1764862567,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[{"index":0,"delta":{"content":"Download"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"G2Yie7lB"}
+      data: {"id":"chatcmpl-ClYUKarTNIqX0Kpv3s4rrlesi91DJ","object":"chat.completion.chunk","created":1765450024,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[{"index":0,"delta":{"content":"Download"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"bPE41kWI"}
 
-      data: {"id":"chatcmpl-Cj5fDSuOWOdQ0SBxZbFOe4k9XflAp","object":"chat.completion.chunk","created":1764862567,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"mvyX6i8Wzeag"}
+      data: {"id":"chatcmpl-ClYUKarTNIqX0Kpv3s4rrlesi91DJ","object":"chat.completion.chunk","created":1765450024,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"5ATvd6pCxOj1"}
 
-      data: {"id":"chatcmpl-Cj5fDSuOWOdQ0SBxZbFOe4k9XflAp","object":"chat.completion.chunk","created":1764862567,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[{"index":0,"delta":{"content":" Save"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"UGnI0gb7vgN"}
+      data: {"id":"chatcmpl-ClYUKarTNIqX0Kpv3s4rrlesi91DJ","object":"chat.completion.chunk","created":1765450024,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[{"index":0,"delta":{"content":" Save"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"k8YyVLEJsFk"}
 
-      data: {"id":"chatcmpl-Cj5fDSuOWOdQ0SBxZbFOe4k9XflAp","object":"chat.completion.chunk","created":1764862567,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"yeExQxXxzzT"}
+      data: {"id":"chatcmpl-ClYUKarTNIqX0Kpv3s4rrlesi91DJ","object":"chat.completion.chunk","created":1765450024,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[{"index":0,"delta":{"content":" Example"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"4hxPHL2k"}
 
-      data: {"id":"chatcmpl-Cj5fDSuOWOdQ0SBxZbFOe4k9XflAp","object":"chat.completion.chunk","created":1764862567,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[{"index":0,"delta":{"content":" from"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"czMH2AGcASt"}
+      data: {"id":"chatcmpl-ClYUKarTNIqX0Kpv3s4rrlesi91DJ","object":"chat.completion.chunk","created":1765450024,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[{"index":0,"delta":{"content":".txt"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"jBNwgbcsI5wb"}
 
-      data: {"id":"chatcmpl-Cj5fDSuOWOdQ0SBxZbFOe4k9XflAp","object":"chat.completion.chunk","created":1764862567,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[{"index":0,"delta":{"content":" URL"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"3q5ae7tFEpif"}
+      data: {"id":"chatcmpl-ClYUKarTNIqX0Kpv3s4rrlesi91DJ","object":"chat.completion.chunk","created":1765450024,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"mEEqjnrY9iu"}
 
-      data: {"id":"chatcmpl-Cj5fDSuOWOdQ0SBxZbFOe4k9XflAp","object":"chat.completion.chunk","created":1764862567,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"CrxvCdwMyS"}
+      data: {"id":"chatcmpl-ClYUKarTNIqX0Kpv3s4rrlesi91DJ","object":"chat.completion.chunk","created":1765450024,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"mF3cv51yHC"}
 
-      data: {"id":"chatcmpl-Cj5fDSuOWOdQ0SBxZbFOe4k9XflAp","object":"chat.completion.chunk","created":1764862567,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[],"usage":{"prompt_tokens":148,"completion_tokens":6,"total_tokens":154,"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":"z2bJFbxh3bvTFZ"}
+      data: {"id":"chatcmpl-ClYUKarTNIqX0Kpv3s4rrlesi91DJ","object":"chat.completion.chunk","created":1765450024,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_ed643dde95","choices":[],"usage":{"prompt_tokens":148,"completion_tokens":6,"total_tokens":154,"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":"645bmFBdewh6aK"}
 
       data: [DONE]
 
@@ -49,15 +49,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 460.945041ms
+    duration: 2.300206458s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49874
+    content_length: 50265
     host: ""

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

@@ -24,27 +24,29 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj5fOooZsAoBwyWox3o3Q57ukzjEt","object":"chat.completion.chunk","created":1764862578,"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":"sUfkOyWhkBqMQv"}
+      data: {"id":"chatcmpl-ClYURxJKlkr2y8aUeB1zPKa2nZofo","object":"chat.completion.chunk","created":1765450031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"5yRyROJJtY3tB1"}
 
-      data: {"id":"chatcmpl-Cj5fOooZsAoBwyWox3o3Q57ukzjEt","object":"chat.completion.chunk","created":1764862578,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":"Check"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"J4mBcgLDZQA"}
+      data: {"id":"chatcmpl-ClYURxJKlkr2y8aUeB1zPKa2nZofo","object":"chat.completion.chunk","created":1765450031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":"Check"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"yKEWMPUcA8L"}
 
-      data: {"id":"chatcmpl-Cj5fOooZsAoBwyWox3o3Q57ukzjEt","object":"chat.completion.chunk","created":1764862578,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" HTML"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Np4pSOJXim5"}
+      data: {"id":"chatcmpl-ClYURxJKlkr2y8aUeB1zPKa2nZofo","object":"chat.completion.chunk","created":1765450031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":" HTML"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"5BVjTNgwxGF"}
 
-      data: {"id":"chatcmpl-Cj5fOooZsAoBwyWox3o3Q57ukzjEt","object":"chat.completion.chunk","created":1764862578,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" for"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ctxKdhnBw1sf"}
+      data: {"id":"chatcmpl-ClYURxJKlkr2y8aUeB1zPKa2nZofo","object":"chat.completion.chunk","created":1765450031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":" for"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"kp7eosJWJN8K"}
 
-      data: {"id":"chatcmpl-Cj5fOooZsAoBwyWox3o3Q57ukzjEt","object":"chat.completion.chunk","created":1764862578,"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":"o2XTlHg46XowKS"}
+      data: {"id":"chatcmpl-ClYURxJKlkr2y8aUeB1zPKa2nZofo","object":"chat.completion.chunk","created":1765450031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"EI6mQF37usHe1k"}
 
-      data: {"id":"chatcmpl-Cj5fOooZsAoBwyWox3o3Q57ukzjEt","object":"chat.completion.chunk","created":1764862578,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":"John"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"sAhG0QJxuV75"}
+      data: {"id":"chatcmpl-ClYURxJKlkr2y8aUeB1zPKa2nZofo","object":"chat.completion.chunk","created":1765450031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":"John"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ABTUDL8cGfX4"}
 
-      data: {"id":"chatcmpl-Cj5fOooZsAoBwyWox3o3Q57ukzjEt","object":"chat.completion.chunk","created":1764862578,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" Doe"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"NVvpJyxEh7LN"}
+      data: {"id":"chatcmpl-ClYURxJKlkr2y8aUeB1zPKa2nZofo","object":"chat.completion.chunk","created":1765450031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":" Doe"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"wkDSMVE1HEGV"}
 
-      data: {"id":"chatcmpl-Cj5fOooZsAoBwyWox3o3Q57ukzjEt","object":"chat.completion.chunk","created":1764862578,"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":"N7R1RhjYQ459EQ6"}
+      data: {"id":"chatcmpl-ClYURxJKlkr2y8aUeB1zPKa2nZofo","object":"chat.completion.chunk","created":1765450031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"WGqcOyHkVBUn3GN"}
 
-      data: {"id":"chatcmpl-Cj5fOooZsAoBwyWox3o3Q57ukzjEt","object":"chat.completion.chunk","created":1764862578,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" Presence"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"qtid0UV"}
+      data: {"id":"chatcmpl-ClYURxJKlkr2y8aUeB1zPKa2nZofo","object":"chat.completion.chunk","created":1765450031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":" Occ"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"jRNw7JwV0CjM"}
 
-      data: {"id":"chatcmpl-Cj5fOooZsAoBwyWox3o3Q57ukzjEt","object":"chat.completion.chunk","created":1764862578,"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":"iA9pbXYw5z"}
+      data: {"id":"chatcmpl-ClYURxJKlkr2y8aUeB1zPKa2nZofo","object":"chat.completion.chunk","created":1765450031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":"urrence"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"BUi0S3QiX"}
 
-      data: {"id":"chatcmpl-Cj5fOooZsAoBwyWox3o3Q57ukzjEt","object":"chat.completion.chunk","created":1764862578,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[],"usage":{"prompt_tokens":153,"completion_tokens":8,"total_tokens":161,"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":"iCIo2WpyvkXMLT"}
+      data: {"id":"chatcmpl-ClYURxJKlkr2y8aUeB1zPKa2nZofo","object":"chat.completion.chunk","created":1765450031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"8eZz7vsWF5"}
+
+      data: {"id":"chatcmpl-ClYURxJKlkr2y8aUeB1zPKa2nZofo","object":"chat.completion.chunk","created":1765450031,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[],"usage":{"prompt_tokens":153,"completion_tokens":9,"total_tokens":162,"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":"xh04QkW7pY8HBI"}
 
       data: [DONE]
 
@@ -53,15 +55,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 725.754042ms
+    duration: 685.04625ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49892
+    content_length: 50283
     host: ""

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

@@ -24,29 +24,29 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj5fa2QolYljS3qhN3vnLxCmuZoQA","object":"chat.completion.chunk","created":1764862590,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"16RVLBo70eXYyb"}
+      data: {"id":"chatcmpl-ClYUaN1fZ88qHwOrCQkkOMgziqdJE","object":"chat.completion.chunk","created":1765450040,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"OJxEBFRUQsMFtg"}
 
-      data: {"id":"chatcmpl-Cj5fa2QolYljS3qhN3vnLxCmuZoQA","object":"chat.completion.chunk","created":1764862590,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"Find"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"H3CNJR7UnYYf"}
+      data: {"id":"chatcmpl-ClYUaN1fZ88qHwOrCQkkOMgziqdJE","object":"chat.completion.chunk","created":1765450040,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"Finding"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"JOYRZ62s3"}
 
-      data: {"id":"chatcmpl-Cj5fa2QolYljS3qhN3vnLxCmuZoQA","object":"chat.completion.chunk","created":1764862590,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" ."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"8EHPibBq2Oyh5G"}
+      data: {"id":"chatcmpl-ClYUaN1fZ88qHwOrCQkkOMgziqdJE","object":"chat.completion.chunk","created":1765450040,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" ."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"j6Tj6K3c90Yt3W"}
 
-      data: {"id":"chatcmpl-Cj5fa2QolYljS3qhN3vnLxCmuZoQA","object":"chat.completion.chunk","created":1764862590,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"03h9ZkWLJaXLHB"}
+      data: {"id":"chatcmpl-ClYUaN1fZ88qHwOrCQkkOMgziqdJE","object":"chat.completion.chunk","created":1765450040,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"7tEx9wpgaAxzdu"}
 
-      data: {"id":"chatcmpl-Cj5fa2QolYljS3qhN3vnLxCmuZoQA","object":"chat.completion.chunk","created":1764862590,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"WFWFQQFTwW"}
+      data: {"id":"chatcmpl-ClYUaN1fZ88qHwOrCQkkOMgziqdJE","object":"chat.completion.chunk","created":1765450040,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"w8uoytyqQX"}
 
-      data: {"id":"chatcmpl-Cj5fa2QolYljS3qhN3vnLxCmuZoQA","object":"chat.completion.chunk","created":1764862590,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Using"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"iXVvGYfTO3"}
+      data: {"id":"chatcmpl-ClYUaN1fZ88qHwOrCQkkOMgziqdJE","object":"chat.completion.chunk","created":1765450040,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"WoTpGAB81rR"}
 
-      data: {"id":"chatcmpl-Cj5fa2QolYljS3qhN3vnLxCmuZoQA","object":"chat.completion.chunk","created":1764862590,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Glob"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"f0neSnHulJG"}
+      data: {"id":"chatcmpl-ClYUaN1fZ88qHwOrCQkkOMgziqdJE","object":"chat.completion.chunk","created":1765450040,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Glob"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"PhwR6Lr1W2b"}
 
-      data: {"id":"chatcmpl-Cj5fa2QolYljS3qhN3vnLxCmuZoQA","object":"chat.completion.chunk","created":1764862590,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"vCKNavIU1BmBL"}
+      data: {"id":"chatcmpl-ClYUaN1fZ88qHwOrCQkkOMgziqdJE","object":"chat.completion.chunk","created":1765450040,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"wGYtTunHNFOqz"}
 
-      data: {"id":"chatcmpl-Cj5fa2QolYljS3qhN3vnLxCmuZoQA","object":"chat.completion.chunk","created":1764862590,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Current"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"fRjcJFUO"}
+      data: {"id":"chatcmpl-ClYUaN1fZ88qHwOrCQkkOMgziqdJE","object":"chat.completion.chunk","created":1765450040,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Current"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"GmUMW63r"}
 
-      data: {"id":"chatcmpl-Cj5fa2QolYljS3qhN3vnLxCmuZoQA","object":"chat.completion.chunk","created":1764862590,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Directory"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"1GHD97"}
+      data: {"id":"chatcmpl-ClYUaN1fZ88qHwOrCQkkOMgziqdJE","object":"chat.completion.chunk","created":1765450040,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Directory"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"gl03qy"}
 
-      data: {"id":"chatcmpl-Cj5fa2QolYljS3qhN3vnLxCmuZoQA","object":"chat.completion.chunk","created":1764862590,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"srQFH2CGLq"}
+      data: {"id":"chatcmpl-ClYUaN1fZ88qHwOrCQkkOMgziqdJE","object":"chat.completion.chunk","created":1765450040,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"UIlF9C9uHC"}
 
-      data: {"id":"chatcmpl-Cj5fa2QolYljS3qhN3vnLxCmuZoQA","object":"chat.completion.chunk","created":1764862590,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[],"usage":{"prompt_tokens":137,"completion_tokens":9,"total_tokens":146,"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":"5HiN5A4vPg2Ar8"}
+      data: {"id":"chatcmpl-ClYUaN1fZ88qHwOrCQkkOMgziqdJE","object":"chat.completion.chunk","created":1765450040,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[],"usage":{"prompt_tokens":137,"completion_tokens":9,"total_tokens":146,"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":"oFQUOYK96zZmPi"}
 
       data: [DONE]
 
@@ -55,15 +55,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 391.2975ms
+    duration: 947.669917ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49810
+    content_length: 50201
     host: ""

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

@@ -24,31 +24,31 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj5fjQoGed1aYVTFoxik5vpfMdIbm","object":"chat.completion.chunk","created":1764862599,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"zZ50ZbEMxRYuXH"}
+      data: {"id":"chatcmpl-ClYUe1xFnvcKQKG4RuOQ7N6udiviD","object":"chat.completion.chunk","created":1765450044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"POqwkKG8YiDyy0"}
 
-      data: {"id":"chatcmpl-Cj5fjQoGed1aYVTFoxik5vpfMdIbm","object":"chat.completion.chunk","created":1764862599,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"Searching"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"fAoqwuP"}
+      data: {"id":"chatcmpl-ClYUe1xFnvcKQKG4RuOQ7N6udiviD","object":"chat.completion.chunk","created":1765450044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"Search"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"2btCOIXhWM"}
 
-      data: {"id":"chatcmpl-Cj5fjQoGed1aYVTFoxik5vpfMdIbm","object":"chat.completion.chunk","created":1764862599,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Ttcy05xJfpllLS"}
+      data: {"id":"chatcmpl-ClYUe1xFnvcKQKG4RuOQ7N6udiviD","object":"chat.completion.chunk","created":1765450044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" for"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"BwZPah5cfikl"}
 
-      data: {"id":"chatcmpl-Cj5fjQoGed1aYVTFoxik5vpfMdIbm","object":"chat.completion.chunk","created":1764862599,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"package"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"vRH06xd1H"}
+      data: {"id":"chatcmpl-ClYUe1xFnvcKQKG4RuOQ7N6udiviD","object":"chat.completion.chunk","created":1765450044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"qyBZswbttoUeIY"}
 
-      data: {"id":"chatcmpl-Cj5fjQoGed1aYVTFoxik5vpfMdIbm","object":"chat.completion.chunk","created":1764862599,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Jh0yJFeE0iHDn6z"}
+      data: {"id":"chatcmpl-ClYUe1xFnvcKQKG4RuOQ7N6udiviD","object":"chat.completion.chunk","created":1765450044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"package"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"dsDpObmN7"}
 
-      data: {"id":"chatcmpl-Cj5fjQoGed1aYVTFoxik5vpfMdIbm","object":"chat.completion.chunk","created":1764862599,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"4zT1g6XDQ7pe1"}
+      data: {"id":"chatcmpl-ClYUe1xFnvcKQKG4RuOQ7N6udiviD","object":"chat.completion.chunk","created":1765450044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ADkAO80x66rXmxm"}
 
-      data: {"id":"chatcmpl-Cj5fjQoGed1aYVTFoxik5vpfMdIbm","object":"chat.completion.chunk","created":1764862599,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"fPjPGIHYrqbHE"}
+      data: {"id":"chatcmpl-ClYUe1xFnvcKQKG4RuOQ7N6udiviD","object":"chat.completion.chunk","created":1765450044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Dp6aKDV1Z4jnQ"}
 
-      data: {"id":"chatcmpl-Cj5fjQoGed1aYVTFoxik5vpfMdIbm","object":"chat.completion.chunk","created":1764862599,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"bPD8Rv2RcH"}
+      data: {"id":"chatcmpl-ClYUe1xFnvcKQKG4RuOQ7N6udiviD","object":"chat.completion.chunk","created":1765450044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"4UyYDdU3Cadkf"}
 
-      data: {"id":"chatcmpl-Cj5fjQoGed1aYVTFoxik5vpfMdIbm","object":"chat.completion.chunk","created":1764862599,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Using"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ahlv02xaHD"}
+      data: {"id":"chatcmpl-ClYUe1xFnvcKQKG4RuOQ7N6udiviD","object":"chat.completion.chunk","created":1765450044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"xyLaxPFI4m"}
 
-      data: {"id":"chatcmpl-Cj5fjQoGed1aYVTFoxik5vpfMdIbm","object":"chat.completion.chunk","created":1764862599,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Gre"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"RU0L0GKOzVNK"}
+      data: {"id":"chatcmpl-ClYUe1xFnvcKQKG4RuOQ7N6udiviD","object":"chat.completion.chunk","created":1765450044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" using"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"dlRVu0jf49"}
 
-      data: {"id":"chatcmpl-Cj5fjQoGed1aYVTFoxik5vpfMdIbm","object":"chat.completion.chunk","created":1764862599,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"p"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"hc8V5IOCAUK9daI"}
+      data: {"id":"chatcmpl-ClYUe1xFnvcKQKG4RuOQ7N6udiviD","object":"chat.completion.chunk","created":1765450044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" grep"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"odbXZTumUQi"}
 
-      data: {"id":"chatcmpl-Cj5fjQoGed1aYVTFoxik5vpfMdIbm","object":"chat.completion.chunk","created":1764862599,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"wzNpp97sLD"}
+      data: {"id":"chatcmpl-ClYUe1xFnvcKQKG4RuOQ7N6udiviD","object":"chat.completion.chunk","created":1765450044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"sLpASQkyNb"}
 
-      data: {"id":"chatcmpl-Cj5fjQoGed1aYVTFoxik5vpfMdIbm","object":"chat.completion.chunk","created":1764862599,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[],"usage":{"prompt_tokens":138,"completion_tokens":10,"total_tokens":148,"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":"nhNL7XgGE181P"}
+      data: {"id":"chatcmpl-ClYUe1xFnvcKQKG4RuOQ7N6udiviD","object":"chat.completion.chunk","created":1765450044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[],"usage":{"prompt_tokens":138,"completion_tokens":10,"total_tokens":148,"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":"Tdzb4OOwUXRLi"}
 
       data: [DONE]
 
@@ -57,15 +57,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 408.414666ms
+    duration: 518.165708ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49808
+    content_length: 50199
     host: ""

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

@@ -24,27 +24,25 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj5ftyxnkhTHRzQVfq8q6NEKHMlCW","object":"chat.completion.chunk","created":1764862609,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"lEKGFixtSTwuuG"}
+      data: {"id":"chatcmpl-ClYUlAU7xGXiwlwnygOdjHO2xgdO6","object":"chat.completion.chunk","created":1765450051,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"UMEDmK4bRTEHog"}
 
-      data: {"id":"chatcmpl-Cj5ftyxnkhTHRzQVfq8q6NEKHMlCW","object":"chat.completion.chunk","created":1764862609,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"Listing"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"U7TXSpJAq"}
+      data: {"id":"chatcmpl-ClYUlAU7xGXiwlwnygOdjHO2xgdO6","object":"chat.completion.chunk","created":1765450051,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"List"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"wU2AW7M98xeA"}
 
-      data: {"id":"chatcmpl-Cj5ftyxnkhTHRzQVfq8q6NEKHMlCW","object":"chat.completion.chunk","created":1764862609,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"HEdHaFRV8T"}
+      data: {"id":"chatcmpl-ClYUlAU7xGXiwlwnygOdjHO2xgdO6","object":"chat.completion.chunk","created":1765450051,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"caiI3nEYPC"}
 
-      data: {"id":"chatcmpl-Cj5ftyxnkhTHRzQVfq8q6NEKHMlCW","object":"chat.completion.chunk","created":1764862609,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"wB2d2XVHLBZ8d"}
+      data: {"id":"chatcmpl-ClYUlAU7xGXiwlwnygOdjHO2xgdO6","object":"chat.completion.chunk","created":1765450051,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Using"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"LcoGEjOXBA"}
 
-      data: {"id":"chatcmpl-Cj5ftyxnkhTHRzQVfq8q6NEKHMlCW","object":"chat.completion.chunk","created":1764862609,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Current"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"kgBP77mh"}
+      data: {"id":"chatcmpl-ClYUlAU7xGXiwlwnygOdjHO2xgdO6","object":"chat.completion.chunk","created":1765450051,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"olW4ETtXnechmp"}
 
-      data: {"id":"chatcmpl-Cj5ftyxnkhTHRzQVfq8q6NEKHMlCW","object":"chat.completion.chunk","created":1764862609,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Directory"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ctvCBZ"}
+      data: {"id":"chatcmpl-ClYUlAU7xGXiwlwnygOdjHO2xgdO6","object":"chat.completion.chunk","created":1765450051,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"ls"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"YY41B40ymUy5c5"}
 
-      data: {"id":"chatcmpl-Cj5ftyxnkhTHRzQVfq8q6NEKHMlCW","object":"chat.completion.chunk","created":1764862609,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"LPbD93HC4Z5"}
+      data: {"id":"chatcmpl-ClYUlAU7xGXiwlwnygOdjHO2xgdO6","object":"chat.completion.chunk","created":1765450051,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"I2np6t9M3AUO0SA"}
 
-      data: {"id":"chatcmpl-Cj5ftyxnkhTHRzQVfq8q6NEKHMlCW","object":"chat.completion.chunk","created":1764862609,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" ls"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"GiQ4t6YIy0wqe"}
+      data: {"id":"chatcmpl-ClYUlAU7xGXiwlwnygOdjHO2xgdO6","object":"chat.completion.chunk","created":1765450051,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Command"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"RxCH1Yjt"}
 
-      data: {"id":"chatcmpl-Cj5ftyxnkhTHRzQVfq8q6NEKHMlCW","object":"chat.completion.chunk","created":1764862609,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Command"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"oYjzzK1l"}
+      data: {"id":"chatcmpl-ClYUlAU7xGXiwlwnygOdjHO2xgdO6","object":"chat.completion.chunk","created":1765450051,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"zaOmpwBTYJ"}
 
-      data: {"id":"chatcmpl-Cj5ftyxnkhTHRzQVfq8q6NEKHMlCW","object":"chat.completion.chunk","created":1764862609,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"zL9G9EwrVA"}
-
-      data: {"id":"chatcmpl-Cj5ftyxnkhTHRzQVfq8q6NEKHMlCW","object":"chat.completion.chunk","created":1764862609,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[],"usage":{"prompt_tokens":135,"completion_tokens":8,"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":"GTDj004Sv1eK0N"}
+      data: {"id":"chatcmpl-ClYUlAU7xGXiwlwnygOdjHO2xgdO6","object":"chat.completion.chunk","created":1765450051,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[],"usage":{"prompt_tokens":135,"completion_tokens":7,"total_tokens":142,"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":"pORiHZ6J2hI91j"}
 
       data: [DONE]
 
@@ -53,15 +51,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 498.928208ms
+    duration: 599.728125ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49802
+    content_length: 50193
     host: ""

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

@@ -24,35 +24,41 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj5fx91z1nrjlhcuicM6Ph5V4MBTJ","object":"chat.completion.chunk","created":1764862613,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"stHG3s14QOPZyF"}
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"iortuQUqIPUoEk"}
 
-      data: {"id":"chatcmpl-Cj5fx91z1nrjlhcuicM6Ph5V4MBTJ","object":"chat.completion.chunk","created":1764862613,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"Edit"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"WyjZMY1Jzm4x"}
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"Editing"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"fI3ZmnsiJ"}
 
-      data: {"id":"chatcmpl-Cj5fx91z1nrjlhcuicM6Ph5V4MBTJ","object":"chat.completion.chunk","created":1764862613,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"hymoWg3tUTYt3K"}
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ID4EbExPHpfF1A"}
 
-      data: {"id":"chatcmpl-Cj5fx91z1nrjlhcuicM6Ph5V4MBTJ","object":"chat.completion.chunk","created":1764862613,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"Hello"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"R6igk6ddb9R"}
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"Hello"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"1LU3dm8Zp8x"}
 
-      data: {"id":"chatcmpl-Cj5fx91z1nrjlhcuicM6Ph5V4MBTJ","object":"chat.completion.chunk","created":1764862613,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"vC7FXjUh0jVQkmo"}
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"B5PW7DIW7rSFGwV"}
 
-      data: {"id":"chatcmpl-Cj5fx91z1nrjlhcuicM6Ph5V4MBTJ","object":"chat.completion.chunk","created":1764862613,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" World"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"cVhwrNCKc2"}
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" World"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"mUjyCOBM3T"}
 
-      data: {"id":"chatcmpl-Cj5fx91z1nrjlhcuicM6Ph5V4MBTJ","object":"chat.completion.chunk","created":1764862613,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"!'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"y3eaGoswn1iBsD"}
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"!'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"mcUf35wIefGwCd"}
 
-      data: {"id":"chatcmpl-Cj5fx91z1nrjlhcuicM6Ph5V4MBTJ","object":"chat.completion.chunk","created":1764862613,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"7ZI8z3f8WENF"}
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Ks0QkMtefblaP"}
 
-      data: {"id":"chatcmpl-Cj5fx91z1nrjlhcuicM6Ph5V4MBTJ","object":"chat.completion.chunk","created":1764862613,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" add"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"8wJflzWkNePf"}
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"MAPEiKXCsBi2Is"}
 
-      data: {"id":"chatcmpl-Cj5fx91z1nrjlhcuicM6Ph5V4MBTJ","object":"chat.completion.chunk","created":1764862613,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" comment"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"xcpAeA0m"}
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"Hello"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Vr3FLHbug8i"}
 
-      data: {"id":"chatcmpl-Cj5fx91z1nrjlhcuicM6Ph5V4MBTJ","object":"chat.completion.chunk","created":1764862613,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"z6KNcAWuEVhXE"}
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"cZSoyKBYFddeRAh"}
 
-      data: {"id":"chatcmpl-Cj5fx91z1nrjlhcuicM6Ph5V4MBTJ","object":"chat.completion.chunk","created":1764862613,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" main"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Y6NKOFkNUfg"}
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Crush"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"EICPMZXFtU"}
 
-      data: {"id":"chatcmpl-Cj5fx91z1nrjlhcuicM6Ph5V4MBTJ","object":"chat.completion.chunk","created":1764862613,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":".go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"hqzfd1Su6rtfk"}
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"!'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"g0XbhchmFYu4Bq"}
 
-      data: {"id":"chatcmpl-Cj5fx91z1nrjlhcuicM6Ph5V4MBTJ","object":"chat.completion.chunk","created":1764862613,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"WT4QSyUBLY"}
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"nTuUNUj4KNN7H"}
 
-      data: {"id":"chatcmpl-Cj5fx91z1nrjlhcuicM6Ph5V4MBTJ","object":"chat.completion.chunk","created":1764862613,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[],"usage":{"prompt_tokens":157,"completion_tokens":12,"total_tokens":169,"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":"jcSvCeTOgOxD1"}
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" main"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ZXpEc8NVrI6"}
+
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":".go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ka0oJF0AxZj94"}
+
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"RchQvTbfGH"}
+
+      data: {"id":"chatcmpl-ClYUpspfYf2HGT5ZUcnlU3k3uhnSu","object":"chat.completion.chunk","created":1765450055,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[],"usage":{"prompt_tokens":157,"completion_tokens":15,"total_tokens":172,"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":"AJG47qP3jlKeV"}
 
       data: [DONE]
 
@@ -61,15 +67,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 521.312875ms
+    duration: 499.534ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49888
+    content_length: 50279
     host: ""

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

@@ -24,23 +24,27 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj5hNB5pAgYdbghi0IUIxPImpYV6e","object":"chat.completion.chunk","created":1764862701,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"GvtGgFLGU0ASGT"}
+      data: {"id":"chatcmpl-ClYVxXKuDow1gLUqqlvhn6DL3K5CC","object":"chat.completion.chunk","created":1765450125,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"yzhS59uRUu511k"}
 
-      data: {"id":"chatcmpl-Cj5hNB5pAgYdbghi0IUIxPImpYV6e","object":"chat.completion.chunk","created":1764862701,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"Parallel"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"KPzNB1a1"}
+      data: {"id":"chatcmpl-ClYVxXKuDow1gLUqqlvhn6DL3K5CC","object":"chat.completion.chunk","created":1765450125,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"Parallel"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"g3jeuGmp"}
 
-      data: {"id":"chatcmpl-Cj5hNB5pAgYdbghi0IUIxPImpYV6e","object":"chat.completion.chunk","created":1764862701,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Directory"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"AhPPIi"}
+      data: {"id":"chatcmpl-ClYVxXKuDow1gLUqqlvhn6DL3K5CC","object":"chat.completion.chunk","created":1765450125,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" ."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"zPlid6EaNGItod"}
 
-      data: {"id":"chatcmpl-Cj5hNB5pAgYdbghi0IUIxPImpYV6e","object":"chat.completion.chunk","created":1764862701,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Listing"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"65i7X3Dd"}
+      data: {"id":"chatcmpl-ClYVxXKuDow1gLUqqlvhn6DL3K5CC","object":"chat.completion.chunk","created":1765450125,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"XxLnCUgnqeu8Hd"}
 
-      data: {"id":"chatcmpl-Cj5hNB5pAgYdbghi0IUIxPImpYV6e","object":"chat.completion.chunk","created":1764862701,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"iyTL40AOfZ6o"}
+      data: {"id":"chatcmpl-ClYVxXKuDow1gLUqqlvhn6DL3K5CC","object":"chat.completion.chunk","created":1765450125,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ktg1VgFlUwJ"}
 
-      data: {"id":"chatcmpl-Cj5hNB5pAgYdbghi0IUIxPImpYV6e","object":"chat.completion.chunk","created":1764862701,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"j483wg4pRxa"}
+      data: {"id":"chatcmpl-ClYVxXKuDow1gLUqqlvhn6DL3K5CC","object":"chat.completion.chunk","created":1765450125,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Search"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"yx3P32Awb"}
 
-      data: {"id":"chatcmpl-Cj5hNB5pAgYdbghi0IUIxPImpYV6e","object":"chat.completion.chunk","created":1764862701,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Search"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"vaZDxrmKG"}
+      data: {"id":"chatcmpl-ClYVxXKuDow1gLUqqlvhn6DL3K5CC","object":"chat.completion.chunk","created":1765450125,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"GmBe64s4mBbQ"}
 
-      data: {"id":"chatcmpl-Cj5hNB5pAgYdbghi0IUIxPImpYV6e","object":"chat.completion.chunk","created":1764862701,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"r4w1NEK1O3"}
+      data: {"id":"chatcmpl-ClYVxXKuDow1gLUqqlvhn6DL3K5CC","object":"chat.completion.chunk","created":1765450125,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Directory"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"eUHrBf"}
 
-      data: {"id":"chatcmpl-Cj5hNB5pAgYdbghi0IUIxPImpYV6e","object":"chat.completion.chunk","created":1764862701,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[],"usage":{"prompt_tokens":154,"completion_tokens":6,"total_tokens":160,"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":"2PF6LiI3ZI091A"}
+      data: {"id":"chatcmpl-ClYVxXKuDow1gLUqqlvhn6DL3K5CC","object":"chat.completion.chunk","created":1765450125,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Listing"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"CkE7ZUS2"}
+
+      data: {"id":"chatcmpl-ClYVxXKuDow1gLUqqlvhn6DL3K5CC","object":"chat.completion.chunk","created":1765450125,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"UOzkyErMbp"}
+
+      data: {"id":"chatcmpl-ClYVxXKuDow1gLUqqlvhn6DL3K5CC","object":"chat.completion.chunk","created":1765450125,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[],"usage":{"prompt_tokens":154,"completion_tokens":8,"total_tokens":162,"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":"IbYbUzxWouLTaX"}
 
       data: [DONE]
 
@@ -49,15 +53,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 390.648875ms
+    duration: 433.644542ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49899
+    content_length: 50290
     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-Cj5eaZEZPIOCqPFdID2cw2jmvGNIZ","object":"chat.completion.chunk","created":1764862528,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_e819e3438b","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"OTC1pfO77Jn3Ss"}
+      data: {"id":"chatcmpl-ClYTQhlPOe5tl5pF1iOgF0DBvE8Yz","object":"chat.completion.chunk","created":1765449968,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_83554c687e","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Td83oWSapyD29H"}
 
-      data: {"id":"chatcmpl-Cj5eaZEZPIOCqPFdID2cw2jmvGNIZ","object":"chat.completion.chunk","created":1764862528,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_e819e3438b","choices":[{"index":0,"delta":{"content":"Understanding"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"dw0"}
+      data: {"id":"chatcmpl-ClYTQhlPOe5tl5pF1iOgF0DBvE8Yz","object":"chat.completion.chunk","created":1765449968,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_83554c687e","choices":[{"index":0,"delta":{"content":"Understanding"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Bh7"}
 
-      data: {"id":"chatcmpl-Cj5eaZEZPIOCqPFdID2cw2jmvGNIZ","object":"chat.completion.chunk","created":1764862528,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_e819e3438b","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"F7n40gg64Uwt"}
+      data: {"id":"chatcmpl-ClYTQhlPOe5tl5pF1iOgF0DBvE8Yz","object":"chat.completion.chunk","created":1765449968,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_83554c687e","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"jRFD2MUbYjEi"}
 
-      data: {"id":"chatcmpl-Cj5eaZEZPIOCqPFdID2cw2jmvGNIZ","object":"chat.completion.chunk","created":1764862528,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_e819e3438b","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"1iXyRtYoW97wa"}
+      data: {"id":"chatcmpl-ClYTQhlPOe5tl5pF1iOgF0DBvE8Yz","object":"chat.completion.chunk","created":1765449968,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_83554c687e","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"SlRY6qmk8zOaT"}
 
-      data: {"id":"chatcmpl-Cj5eaZEZPIOCqPFdID2cw2jmvGNIZ","object":"chat.completion.chunk","created":1764862528,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_e819e3438b","choices":[{"index":0,"delta":{"content":" Module"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"CQD5wfY5u"}
+      data: {"id":"chatcmpl-ClYTQhlPOe5tl5pF1iOgF0DBvE8Yz","object":"chat.completion.chunk","created":1765449968,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_83554c687e","choices":[{"index":0,"delta":{"content":" Mod"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"kgvSLP9N0drN"}
 
-      data: {"id":"chatcmpl-Cj5eaZEZPIOCqPFdID2cw2jmvGNIZ","object":"chat.completion.chunk","created":1764862528,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_e819e3438b","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"9nCdlqcheyD"}
+      data: {"id":"chatcmpl-ClYTQhlPOe5tl5pF1iOgF0DBvE8Yz","object":"chat.completion.chunk","created":1765449968,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_83554c687e","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"PimRARifiZA"}
 
-      data: {"id":"chatcmpl-Cj5eaZEZPIOCqPFdID2cw2jmvGNIZ","object":"chat.completion.chunk","created":1764862528,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_e819e3438b","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"HG7EcPA8KN"}
+      data: {"id":"chatcmpl-ClYTQhlPOe5tl5pF1iOgF0DBvE8Yz","object":"chat.completion.chunk","created":1765449968,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_83554c687e","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"HPqTpsItZS"}
 
-      data: {"id":"chatcmpl-Cj5eaZEZPIOCqPFdID2cw2jmvGNIZ","object":"chat.completion.chunk","created":1764862528,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_e819e3438b","choices":[],"usage":{"prompt_tokens":129,"completion_tokens":5,"total_tokens":134,"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":"MKsb97i60ViJDJ"}
+      data: {"id":"chatcmpl-ClYTQhlPOe5tl5pF1iOgF0DBvE8Yz","object":"chat.completion.chunk","created":1765449968,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_83554c687e","choices":[],"usage":{"prompt_tokens":129,"completion_tokens":5,"total_tokens":134,"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":"V4VlPjVdvDAOva"}
 
       data: [DONE]
 
@@ -47,15 +47,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 435.350917ms
+    duration: 918.348ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49772
+    content_length: 50163
     host: ""

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

@@ -24,13 +24,15 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj5eXgQs52an8VdAppy67IGNbaNFe","object":"chat.completion.chunk","created":1764862525,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"x7WEcf7ig2ihCK"}
+      data: {"id":"chatcmpl-ClYTNmeHbTg5nOfFSj9b0PfSqnXmI","object":"chat.completion.chunk","created":1765449965,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"lYuAhHNOZyFT78"}
 
-      data: {"id":"chatcmpl-Cj5eXgQs52an8VdAppy67IGNbaNFe","object":"chat.completion.chunk","created":1764862525,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"Greetings"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"33s5BnX"}
+      data: {"id":"chatcmpl-ClYTNmeHbTg5nOfFSj9b0PfSqnXmI","object":"chat.completion.chunk","created":1765449965,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"User"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"tEQ3xb2jGS3z"}
 
-      data: {"id":"chatcmpl-Cj5eXgQs52an8VdAppy67IGNbaNFe","object":"chat.completion.chunk","created":1764862525,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"bh8BPlqlKb"}
+      data: {"id":"chatcmpl-ClYTNmeHbTg5nOfFSj9b0PfSqnXmI","object":"chat.completion.chunk","created":1765449965,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Greeting"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"uf5pfnS"}
 
-      data: {"id":"chatcmpl-Cj5eXgQs52an8VdAppy67IGNbaNFe","object":"chat.completion.chunk","created":1764862525,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[],"usage":{"prompt_tokens":126,"completion_tokens":1,"total_tokens":127,"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":"oXIOkbDShWE4Pf"}
+      data: {"id":"chatcmpl-ClYTNmeHbTg5nOfFSj9b0PfSqnXmI","object":"chat.completion.chunk","created":1765449965,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"BnHYDD4Snx"}
+
+      data: {"id":"chatcmpl-ClYTNmeHbTg5nOfFSj9b0PfSqnXmI","object":"chat.completion.chunk","created":1765449965,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[],"usage":{"prompt_tokens":126,"completion_tokens":2,"total_tokens":128,"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":"kk9wG4HXzAC8D5"}
 
       data: [DONE]
 
@@ -39,15 +41,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 1.042759084s
+    duration: 1.16988225s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49762
+    content_length: 50153
     host: ""

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

@@ -24,31 +24,37 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj5gX0lZaJWKiDMzPW8HDrD3cqbwi","object":"chat.completion.chunk","created":1764862649,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"V7aJpOpFhV5inr"}
+      data: {"id":"chatcmpl-ClYVFpJvAWVs1HZmbLJSHevY7MPdx","object":"chat.completion.chunk","created":1765450081,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"6Uwk6E5ZLxoCKu"}
 
-      data: {"id":"chatcmpl-Cj5gX0lZaJWKiDMzPW8HDrD3cqbwi","object":"chat.completion.chunk","created":1764862649,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"Searching"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"7F8z7KK"}
+      data: {"id":"chatcmpl-ClYVFpJvAWVs1HZmbLJSHevY7MPdx","object":"chat.completion.chunk","created":1765450081,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"Using"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"jmlPS4eKNlU"}
 
-      data: {"id":"chatcmpl-Cj5gX0lZaJWKiDMzPW8HDrD3cqbwi","object":"chat.completion.chunk","created":1764862649,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" for"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"eXjQSVgHlEBT"}
+      data: {"id":"chatcmpl-ClYVFpJvAWVs1HZmbLJSHevY7MPdx","object":"chat.completion.chunk","created":1765450081,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Source"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"suyvSEUrA"}
 
-      data: {"id":"chatcmpl-Cj5gX0lZaJWKiDMzPW8HDrD3cqbwi","object":"chat.completion.chunk","created":1764862649,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"jjWtwgDDjEInPX"}
+      data: {"id":"chatcmpl-ClYVFpJvAWVs1HZmbLJSHevY7MPdx","object":"chat.completion.chunk","created":1765450081,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"graph"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ZnkXVLS9pd9"}
 
-      data: {"id":"chatcmpl-Cj5gX0lZaJWKiDMzPW8HDrD3cqbwi","object":"chat.completion.chunk","created":1764862649,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"func"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"DqNtU8f04iBw"}
+      data: {"id":"chatcmpl-ClYVFpJvAWVs1HZmbLJSHevY7MPdx","object":"chat.completion.chunk","created":1765450081,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"6DDfkjVk33j2S"}
 
-      data: {"id":"chatcmpl-Cj5gX0lZaJWKiDMzPW8HDrD3cqbwi","object":"chat.completion.chunk","created":1764862649,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" main"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"j5LaEOy2UB5"}
+      data: {"id":"chatcmpl-ClYVFpJvAWVs1HZmbLJSHevY7MPdx","object":"chat.completion.chunk","created":1765450081,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Find"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"wh6ozpJ0ICP"}
 
-      data: {"id":"chatcmpl-Cj5gX0lZaJWKiDMzPW8HDrD3cqbwi","object":"chat.completion.chunk","created":1764862649,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"RtYwad29rl58mmW"}
+      data: {"id":"chatcmpl-ClYVFpJvAWVs1HZmbLJSHevY7MPdx","object":"chat.completion.chunk","created":1765450081,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ZGNvhFcisiNv5j"}
 
-      data: {"id":"chatcmpl-Cj5gX0lZaJWKiDMzPW8HDrD3cqbwi","object":"chat.completion.chunk","created":1764862649,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"7odiYfZEyK3eo"}
+      data: {"id":"chatcmpl-ClYVFpJvAWVs1HZmbLJSHevY7MPdx","object":"chat.completion.chunk","created":1765450081,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"func"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"kPFZUGkdYwtc"}
 
-      data: {"id":"chatcmpl-Cj5gX0lZaJWKiDMzPW8HDrD3cqbwi","object":"chat.completion.chunk","created":1764862649,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"PQyYbpPXubI94"}
+      data: {"id":"chatcmpl-ClYVFpJvAWVs1HZmbLJSHevY7MPdx","object":"chat.completion.chunk","created":1765450081,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" main"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"O6L966yuVgp"}
 
-      data: {"id":"chatcmpl-Cj5gX0lZaJWKiDMzPW8HDrD3cqbwi","object":"chat.completion.chunk","created":1764862649,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Re"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"tPfbGjPO0BHQs"}
+      data: {"id":"chatcmpl-ClYVFpJvAWVs1HZmbLJSHevY7MPdx","object":"chat.completion.chunk","created":1765450081,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"XcGGFGl7Nf7RuUM"}
 
-      data: {"id":"chatcmpl-Cj5gX0lZaJWKiDMzPW8HDrD3cqbwi","object":"chat.completion.chunk","created":1764862649,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"positories"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"QIqgGC"}
+      data: {"id":"chatcmpl-ClYVFpJvAWVs1HZmbLJSHevY7MPdx","object":"chat.completion.chunk","created":1765450081,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"2ecov1rE9ImKb"}
 
-      data: {"id":"chatcmpl-Cj5gX0lZaJWKiDMzPW8HDrD3cqbwi","object":"chat.completion.chunk","created":1764862649,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"Af8WMnrBiS"}
+      data: {"id":"chatcmpl-ClYVFpJvAWVs1HZmbLJSHevY7MPdx","object":"chat.completion.chunk","created":1765450081,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"GaBkfJFK8gAxN"}
 
-      data: {"id":"chatcmpl-Cj5gX0lZaJWKiDMzPW8HDrD3cqbwi","object":"chat.completion.chunk","created":1764862649,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[],"usage":{"prompt_tokens":138,"completion_tokens":10,"total_tokens":148,"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":"Ev2kzGJz9hjEP"}
+      data: {"id":"chatcmpl-ClYVFpJvAWVs1HZmbLJSHevY7MPdx","object":"chat.completion.chunk","created":1765450081,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Re"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"sHG1C6ny6Us9z"}
+
+      data: {"id":"chatcmpl-ClYVFpJvAWVs1HZmbLJSHevY7MPdx","object":"chat.completion.chunk","created":1765450081,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"pos"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"NSChIK7VgkOQW"}
+
+      data: {"id":"chatcmpl-ClYVFpJvAWVs1HZmbLJSHevY7MPdx","object":"chat.completion.chunk","created":1765450081,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"RmvItLJGPu"}
+
+      data: {"id":"chatcmpl-ClYVFpJvAWVs1HZmbLJSHevY7MPdx","object":"chat.completion.chunk","created":1765450081,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[],"usage":{"prompt_tokens":138,"completion_tokens":13,"total_tokens":151,"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":"fdcSwuBLeER6h"}
 
       data: [DONE]
 
@@ -57,15 +63,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 392.941917ms
+    duration: 510.380208ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49822
+    content_length: 50213
     host: ""

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

@@ -24,31 +24,31 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj5eivmJnQDYTszC8cSfkpcxC2bPg","object":"chat.completion.chunk","created":1764862536,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"O0oCW5XBCjcl1g"}
+      data: {"id":"chatcmpl-ClYcUERaSodA5TcaAZi62itGcATzy","object":"chat.completion.chunk","created":1765450530,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"suhxmaLssng9GN"}
 
-      data: {"id":"chatcmpl-Cj5eivmJnQDYTszC8cSfkpcxC2bPg","object":"chat.completion.chunk","created":1764862536,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"Update"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"jdQzCLveMQ"}
+      data: {"id":"chatcmpl-ClYcUERaSodA5TcaAZi62itGcATzy","object":"chat.completion.chunk","created":1765450530,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":"Update"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"uq1N9j9GYt"}
 
-      data: {"id":"chatcmpl-Cj5eivmJnQDYTszC8cSfkpcxC2bPg","object":"chat.completion.chunk","created":1764862536,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" main"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"x2BGf6Nj6nD"}
+      data: {"id":"chatcmpl-ClYcUERaSodA5TcaAZi62itGcATzy","object":"chat.completion.chunk","created":1765450530,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":" main"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"2yJ1XcXP92O"}
 
-      data: {"id":"chatcmpl-Cj5eivmJnQDYTszC8cSfkpcxC2bPg","object":"chat.completion.chunk","created":1764862536,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":".go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"tISqXnPiclzEf"}
+      data: {"id":"chatcmpl-ClYcUERaSodA5TcaAZi62itGcATzy","object":"chat.completion.chunk","created":1765450530,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":".go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"o502A8HAiLze4"}
 
-      data: {"id":"chatcmpl-Cj5eivmJnQDYTszC8cSfkpcxC2bPg","object":"chat.completion.chunk","created":1764862536,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"MuitD5R1C0kB2"}
+      data: {"id":"chatcmpl-ClYcUERaSodA5TcaAZi62itGcATzy","object":"chat.completion.chunk","created":1765450530,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"vLmVOOtBoeAm7"}
 
-      data: {"id":"chatcmpl-Cj5eivmJnQDYTszC8cSfkpcxC2bPg","object":"chat.completion.chunk","created":1764862536,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Print"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"WHZ6xue434"}
+      data: {"id":"chatcmpl-ClYcUERaSodA5TcaAZi62itGcATzy","object":"chat.completion.chunk","created":1765450530,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":" Print"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"qd8Oqo9S3r"}
 
-      data: {"id":"chatcmpl-Cj5eivmJnQDYTszC8cSfkpcxC2bPg","object":"chat.completion.chunk","created":1764862536,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Ir1EfbhKQALo1H"}
+      data: {"id":"chatcmpl-ClYcUERaSodA5TcaAZi62itGcATzy","object":"chat.completion.chunk","created":1765450530,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"JlFugTEXdxERyl"}
 
-      data: {"id":"chatcmpl-Cj5eivmJnQDYTszC8cSfkpcxC2bPg","object":"chat.completion.chunk","created":1764862536,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"Hello"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"KXgSqlI9l9u"}
+      data: {"id":"chatcmpl-ClYcUERaSodA5TcaAZi62itGcATzy","object":"chat.completion.chunk","created":1765450530,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":"Hello"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"PSAR2b6MhBJ"}
 
-      data: {"id":"chatcmpl-Cj5eivmJnQDYTszC8cSfkpcxC2bPg","object":"chat.completion.chunk","created":1764862536,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" from"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"7NUoxKXwNCe"}
+      data: {"id":"chatcmpl-ClYcUERaSodA5TcaAZi62itGcATzy","object":"chat.completion.chunk","created":1765450530,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":" from"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"K2DaU062cs5"}
 
-      data: {"id":"chatcmpl-Cj5eivmJnQDYTszC8cSfkpcxC2bPg","object":"chat.completion.chunk","created":1764862536,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Crush"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"N2VQq9pYby"}
+      data: {"id":"chatcmpl-ClYcUERaSodA5TcaAZi62itGcATzy","object":"chat.completion.chunk","created":1765450530,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":" Crush"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"TGAxJqR0xe"}
 
-      data: {"id":"chatcmpl-Cj5eivmJnQDYTszC8cSfkpcxC2bPg","object":"chat.completion.chunk","created":1764862536,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Klq1ycgRs00e1d4"}
+      data: {"id":"chatcmpl-ClYcUERaSodA5TcaAZi62itGcATzy","object":"chat.completion.chunk","created":1765450530,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"bZ8ONMFviIS07qj"}
 
-      data: {"id":"chatcmpl-Cj5eivmJnQDYTszC8cSfkpcxC2bPg","object":"chat.completion.chunk","created":1764862536,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"LS5bPX7l7c"}
+      data: {"id":"chatcmpl-ClYcUERaSodA5TcaAZi62itGcATzy","object":"chat.completion.chunk","created":1765450530,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"MOpaEkBHwD"}
 
-      data: {"id":"chatcmpl-Cj5eivmJnQDYTszC8cSfkpcxC2bPg","object":"chat.completion.chunk","created":1764862536,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[],"usage":{"prompt_tokens":139,"completion_tokens":10,"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":"XI2qPQJkIY4jy"}
+      data: {"id":"chatcmpl-ClYcUERaSodA5TcaAZi62itGcATzy","object":"chat.completion.chunk","created":1765450530,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[],"usage":{"prompt_tokens":139,"completion_tokens":10,"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":"E0DOck4Xo8KnI"}
 
       data: [DONE]
 
@@ -57,15 +57,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 736.477208ms
+    duration: 592.698375ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49828
+    content_length: 50219
     host: ""

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

@@ -24,27 +24,23 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj5h7MQblabwrCdxjqHsbvrQkJxIP","object":"chat.completion.chunk","created":1764862685,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"UrpciigLsIhRQJ"}
+      data: {"id":"chatcmpl-ClYVf4uM2U0ATW18tcIGbdzcFAqWU","object":"chat.completion.chunk","created":1765450107,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ravSmf9KF02hrZ"}
 
-      data: {"id":"chatcmpl-Cj5h7MQblabwrCdxjqHsbvrQkJxIP","object":"chat.completion.chunk","created":1764862685,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"Create"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"VaFd5ML0hs"}
+      data: {"id":"chatcmpl-ClYVf4uM2U0ATW18tcIGbdzcFAqWU","object":"chat.completion.chunk","created":1765450107,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":"Creating"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"gDrbOt0V"}
 
-      data: {"id":"chatcmpl-Cj5h7MQblabwrCdxjqHsbvrQkJxIP","object":"chat.completion.chunk","created":1764862685,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" config"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"8ue07B4W0"}
+      data: {"id":"chatcmpl-ClYVf4uM2U0ATW18tcIGbdzcFAqWU","object":"chat.completion.chunk","created":1765450107,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" config"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ROCqtTpc5"}
 
-      data: {"id":"chatcmpl-Cj5h7MQblabwrCdxjqHsbvrQkJxIP","object":"chat.completion.chunk","created":1764862685,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":".json"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"umBlJVLsIdu"}
+      data: {"id":"chatcmpl-ClYVf4uM2U0ATW18tcIGbdzcFAqWU","object":"chat.completion.chunk","created":1765450107,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":".json"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"pUfVbY4qhPb"}
 
-      data: {"id":"chatcmpl-Cj5h7MQblabwrCdxjqHsbvrQkJxIP","object":"chat.completion.chunk","created":1764862685,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"NmX3UiKvZUE"}
+      data: {"id":"chatcmpl-ClYVf4uM2U0ATW18tcIGbdzcFAqWU","object":"chat.completion.chunk","created":1765450107,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"n1S6JXiKNwn"}
 
-      data: {"id":"chatcmpl-Cj5h7MQblabwrCdxjqHsbvrQkJxIP","object":"chat.completion.chunk","created":1764862685,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"JoTixPL8ppW"}
+      data: {"id":"chatcmpl-ClYVf4uM2U0ATW18tcIGbdzcFAqWU","object":"chat.completion.chunk","created":1765450107,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Test"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"AvqPcgoEKtb"}
 
-      data: {"id":"chatcmpl-Cj5h7MQblabwrCdxjqHsbvrQkJxIP","object":"chat.completion.chunk","created":1764862685,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Sample"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"edJDPMmA2"}
+      data: {"id":"chatcmpl-ClYVf4uM2U0ATW18tcIGbdzcFAqWU","object":"chat.completion.chunk","created":1765450107,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Details"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"rmCpDlnn"}
 
-      data: {"id":"chatcmpl-Cj5h7MQblabwrCdxjqHsbvrQkJxIP","object":"chat.completion.chunk","created":1764862685,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" JSON"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Ekbs2yt8ekn"}
+      data: {"id":"chatcmpl-ClYVf4uM2U0ATW18tcIGbdzcFAqWU","object":"chat.completion.chunk","created":1765450107,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"CEGO6F6IGC"}
 
-      data: {"id":"chatcmpl-Cj5h7MQblabwrCdxjqHsbvrQkJxIP","object":"chat.completion.chunk","created":1764862685,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Content"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"eNjoh3CM"}
-
-      data: {"id":"chatcmpl-Cj5h7MQblabwrCdxjqHsbvrQkJxIP","object":"chat.completion.chunk","created":1764862685,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"sMSdeiR6TM"}
-
-      data: {"id":"chatcmpl-Cj5h7MQblabwrCdxjqHsbvrQkJxIP","object":"chat.completion.chunk","created":1764862685,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[],"usage":{"prompt_tokens":153,"completion_tokens":8,"total_tokens":161,"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":"Vxh04AWWLkhSUd"}
+      data: {"id":"chatcmpl-ClYVf4uM2U0ATW18tcIGbdzcFAqWU","object":"chat.completion.chunk","created":1765450107,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[],"usage":{"prompt_tokens":153,"completion_tokens":6,"total_tokens":159,"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":"Lhyx4FFDmVErjw"}
 
       data: [DONE]
 
@@ -53,15 +49,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 553.310667ms
+    duration: 512.637375ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49865
+    content_length: 50256
     host: ""

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

@@ -6,9 +6,56 @@ interactions:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49961
+    content_length: 803
+    host: ""
+    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n<rules>\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</rules>\n\n /no_think","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''. do not print its timestamp\n <think>\n\n</think>","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.7.1
+    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-1765450159-XJbAh4NJseOmQCFaiLUK","provider":"Novita","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450159,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":""}
+
+      data: {"id":"gen-1765450159-XJbAh4NJseOmQCFaiLUK","provider":"Novita","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450159,"choices":[{"index":0,"delta":{"role":"assistant","content":"Create"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":""}
+
+      data: {"id":"gen-1765450159-XJbAh4NJseOmQCFaiLUK","provider":"Novita","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450159,"choices":[{"index":0,"delta":{"role":"assistant","content":" test"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":""}
+
+      data: {"id":"gen-1765450159-XJbAh4NJseOmQCFaiLUK","provider":"Novita","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450159,"choices":[{"index":0,"delta":{"role":"assistant","content":".txt with"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":""}
+
+      data: {"id":"gen-1765450159-XJbAh4NJseOmQCFaiLUK","provider":"Novita","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450159,"choices":[{"index":0,"delta":{"role":"assistant","content":" hello bash using"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":""}
+
+      data: {"id":"gen-1765450159-XJbAh4NJseOmQCFaiLUK","provider":"Novita","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450159,"choices":[{"index":0,"delta":{"role":"assistant","content":" bash"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":""}
+
+      data: {"id":"gen-1765450159-XJbAh4NJseOmQCFaiLUK","provider":"Novita","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450159,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}],"system_fingerprint":""}
+
+      data: {"id":"gen-1765450159-XJbAh4NJseOmQCFaiLUK","provider":"Novita","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450159,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":151,"completion_tokens":8,"total_tokens":159,"cost":0.00002772,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.00001812,"upstream_inference_completions_cost":0.0000096},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+
+      data: [DONE]
+
+    headers:
+      Content-Type:
+      - text/event-stream
+    status: 200 OK
+    code: 200
+    duration: 795.430042ms
+- id: 1
+  request:
+    proto: HTTP/1.1
+    proto_major: 1
+    proto_minor: 1
+    content_length: 50389
     host: ""

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

@@ -24,25 +24,25 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764862737-zUarDvIkRkWbsTW1b853","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862737,"choices":[{"index":0,"delta":{"role":"assistant","content":"Download"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450178-A3nTohIO2yAJW18wsmyU","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450178,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862737-zUarDvIkRkWbsTW1b853","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862737,"choices":[{"index":0,"delta":{"role":"assistant","content":" and"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450178-A3nTohIO2yAJW18wsmyU","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450178,"choices":[{"index":0,"delta":{"role":"assistant","content":"Download"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862737-zUarDvIkRkWbsTW1b853","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862737,"choices":[{"index":0,"delta":{"role":"assistant","content":" save"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450178-A3nTohIO2yAJW18wsmyU","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450178,"choices":[{"index":0,"delta":{"role":"assistant","content":" example"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862737-zUarDvIkRkWbsTW1b853","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862737,"choices":[{"index":0,"delta":{"role":"assistant","content":" example"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450178-A3nTohIO2yAJW18wsmyU","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450178,"choices":[{"index":0,"delta":{"role":"assistant","content":".txt from example"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862737-zUarDvIkRkWbsTW1b853","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862737,"choices":[{"index":0,"delta":{"role":"assistant","content":".txt"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450178-A3nTohIO2yAJW18wsmyU","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450178,"choices":[{"index":0,"delta":{"role":"assistant","content":"-files"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862737-zUarDvIkRkWbsTW1b853","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862737,"choices":[{"index":0,"delta":{"role":"assistant","content":" from"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450178-A3nTohIO2yAJW18wsmyU","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450178,"choices":[{"index":0,"delta":{"role":"assistant","content":".online"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862737-zUarDvIkRkWbsTW1b853","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862737,"choices":[{"index":0,"delta":{"role":"assistant","content":" given"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450178-A3nTohIO2yAJW18wsmyU","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450178,"choices":[{"index":0,"delta":{"role":"assistant","content":"-"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862737-zUarDvIkRkWbsTW1b853","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862737,"choices":[{"index":0,"delta":{"role":"assistant","content":" URL"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450178-A3nTohIO2yAJW18wsmyU","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450178,"choices":[{"index":0,"delta":{"role":"assistant","content":"convert.com"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862737-zUarDvIkRkWbsTW1b853","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862737,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
+      data: {"id":"gen-1765450178-A3nTohIO2yAJW18wsmyU","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450178,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
 
-      data: {"id":"gen-1764862737-zUarDvIkRkWbsTW1b853","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862737,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":150,"completion_tokens":9,"total_tokens":159,"cost":0.000036,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000225,"upstream_inference_completions_cost":0.0000135},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      data: {"id":"gen-1765450178-A3nTohIO2yAJW18wsmyU","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450178,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":150,"completion_tokens":11,"total_tokens":161,"cost":0.0000357,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000225,"upstream_inference_completions_cost":0.0000132},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
 
       data: [DONE]
 
@@ -51,15 +51,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 982.813875ms
+    duration: 411.759375ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49986
+    content_length: 50414
     host: ""

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

@@ -24,19 +24,25 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764862747-NWcjnST8QJWfug0BMCkp","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862747,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
+      data: {"id":"gen-1765450187-86qtDlWHSSeu17meW5QN","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450187,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862747-NWcjnST8QJWfug0BMCkp","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862747,"choices":[{"index":0,"delta":{"role":"assistant","content":"Check"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
+      data: {"id":"gen-1765450187-86qtDlWHSSeu17meW5QN","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450187,"choices":[{"index":0,"delta":{"role":"assistant","content":"Check"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862747-NWcjnST8QJWfug0BMCkp","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862747,"choices":[{"index":0,"delta":{"role":"assistant","content":" if example"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
+      data: {"id":"gen-1765450187-86qtDlWHSSeu17meW5QN","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450187,"choices":[{"index":0,"delta":{"role":"assistant","content":" if"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862747-NWcjnST8QJWfug0BMCkp","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862747,"choices":[{"index":0,"delta":{"role":"assistant","content":".html contains John"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
+      data: {"id":"gen-1765450187-86qtDlWHSSeu17meW5QN","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450187,"choices":[{"index":0,"delta":{"role":"assistant","content":" example"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862747-NWcjnST8QJWfug0BMCkp","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862747,"choices":[{"index":0,"delta":{"role":"assistant","content":" Doe"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
+      data: {"id":"gen-1765450187-86qtDlWHSSeu17meW5QN","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450187,"choices":[{"index":0,"delta":{"role":"assistant","content":".html"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862747-NWcjnST8QJWfug0BMCkp","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862747,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}],"system_fingerprint":null}
+      data: {"id":"gen-1765450187-86qtDlWHSSeu17meW5QN","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450187,"choices":[{"index":0,"delta":{"role":"assistant","content":" contains"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862747-NWcjnST8QJWfug0BMCkp","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862747,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":159,"completion_tokens":7,"total_tokens":166,"cost":0.00003225,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.00002385,"upstream_inference_completions_cost":0.0000084},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      data: {"id":"gen-1765450187-86qtDlWHSSeu17meW5QN","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450187,"choices":[{"index":0,"delta":{"role":"assistant","content":" John"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1765450187-86qtDlWHSSeu17meW5QN","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450187,"choices":[{"index":0,"delta":{"role":"assistant","content":" Doe"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1765450187-86qtDlWHSSeu17meW5QN","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450187,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
+
+      data: {"id":"gen-1765450187-86qtDlWHSSeu17meW5QN","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450187,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":155,"completion_tokens":8,"total_tokens":163,"cost":0.0000219,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000155,"upstream_inference_completions_cost":0.0000064},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
 
       data: [DONE]
 
@@ -45,15 +51,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 806.467791ms
+    duration: 1.128562167s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50004
+    content_length: 50432
     host: ""

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

@@ -24,31 +24,31 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764862755-jp7G5Oi0A1yIQSAlyPvC","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862755,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450190-HU1ZzT0K8QtwdsvIz0S1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450190,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862755-jp7G5Oi0A1yIQSAlyPvC","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862755,"choices":[{"index":0,"delta":{"role":"assistant","content":"Find"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450190-HU1ZzT0K8QtwdsvIz0S1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450190,"choices":[{"index":0,"delta":{"role":"assistant","content":"Find"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862755-jp7G5Oi0A1yIQSAlyPvC","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862755,"choices":[{"index":0,"delta":{"role":"assistant","content":" all"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450190-HU1ZzT0K8QtwdsvIz0S1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450190,"choices":[{"index":0,"delta":{"role":"assistant","content":" all"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862755-jp7G5Oi0A1yIQSAlyPvC","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862755,"choices":[{"index":0,"delta":{"role":"assistant","content":" ."},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450190-HU1ZzT0K8QtwdsvIz0S1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450190,"choices":[{"index":0,"delta":{"role":"assistant","content":" ."},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862755-jp7G5Oi0A1yIQSAlyPvC","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862755,"choices":[{"index":0,"delta":{"role":"assistant","content":"go"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450190-HU1ZzT0K8QtwdsvIz0S1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450190,"choices":[{"index":0,"delta":{"role":"assistant","content":"go"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862755-jp7G5Oi0A1yIQSAlyPvC","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862755,"choices":[{"index":0,"delta":{"role":"assistant","content":" files"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450190-HU1ZzT0K8QtwdsvIz0S1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450190,"choices":[{"index":0,"delta":{"role":"assistant","content":" files"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862755-jp7G5Oi0A1yIQSAlyPvC","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862755,"choices":[{"index":0,"delta":{"role":"assistant","content":" in"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450190-HU1ZzT0K8QtwdsvIz0S1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450190,"choices":[{"index":0,"delta":{"role":"assistant","content":" in"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862755-jp7G5Oi0A1yIQSAlyPvC","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862755,"choices":[{"index":0,"delta":{"role":"assistant","content":" current"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450190-HU1ZzT0K8QtwdsvIz0S1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450190,"choices":[{"index":0,"delta":{"role":"assistant","content":" current"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862755-jp7G5Oi0A1yIQSAlyPvC","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862755,"choices":[{"index":0,"delta":{"role":"assistant","content":" directory"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450190-HU1ZzT0K8QtwdsvIz0S1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450190,"choices":[{"index":0,"delta":{"role":"assistant","content":" directory"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862755-jp7G5Oi0A1yIQSAlyPvC","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862755,"choices":[{"index":0,"delta":{"role":"assistant","content":" using"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450190-HU1ZzT0K8QtwdsvIz0S1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450190,"choices":[{"index":0,"delta":{"role":"assistant","content":" using"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862755-jp7G5Oi0A1yIQSAlyPvC","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862755,"choices":[{"index":0,"delta":{"role":"assistant","content":" glob"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450190-HU1ZzT0K8QtwdsvIz0S1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450190,"choices":[{"index":0,"delta":{"role":"assistant","content":" glob"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862755-jp7G5Oi0A1yIQSAlyPvC","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862755,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
+      data: {"id":"gen-1765450190-HU1ZzT0K8QtwdsvIz0S1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450190,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
 
-      data: {"id":"gen-1764862755-jp7G5Oi0A1yIQSAlyPvC","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862755,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":139,"completion_tokens":11,"total_tokens":150,"cost":0.000026,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000139,"upstream_inference_completions_cost":0.0000121},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      data: {"id":"gen-1765450190-HU1ZzT0K8QtwdsvIz0S1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450190,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":139,"completion_tokens":11,"total_tokens":150,"cost":0.000026,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000139,"upstream_inference_completions_cost":0.0000121},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
 
       data: [DONE]
 
@@ -57,15 +57,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 418.074333ms
+    duration: 436.118917ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49922
+    content_length: 50350
     host: ""

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

@@ -24,27 +24,17 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764862759-qsI3C4t47te0ib8QGB6x","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862759,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450195-UcNkDgNeGiSDNMOQYMrq","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450195,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
 
-      data: {"id":"gen-1764862759-qsI3C4t47te0ib8QGB6x","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862759,"choices":[{"index":0,"delta":{"role":"assistant","content":"Search"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450195-UcNkDgNeGiSDNMOQYMrq","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450195,"choices":[{"index":0,"delta":{"role":"assistant","content":"Search"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
 
-      data: {"id":"gen-1764862759-qsI3C4t47te0ib8QGB6x","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862759,"choices":[{"index":0,"delta":{"role":"assistant","content":" for"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450195-UcNkDgNeGiSDNMOQYMrq","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450195,"choices":[{"index":0,"delta":{"role":"assistant","content":" for package in Go"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
 
-      data: {"id":"gen-1764862759-qsI3C4t47te0ib8QGB6x","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862759,"choices":[{"index":0,"delta":{"role":"assistant","content":" package"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450195-UcNkDgNeGiSDNMOQYMrq","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450195,"choices":[{"index":0,"delta":{"role":"assistant","content":" files using grep"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
 
-      data: {"id":"gen-1764862759-qsI3C4t47te0ib8QGB6x","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862759,"choices":[{"index":0,"delta":{"role":"assistant","content":" in"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450195-UcNkDgNeGiSDNMOQYMrq","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450195,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}],"system_fingerprint":null}
 
-      data: {"id":"gen-1764862759-qsI3C4t47te0ib8QGB6x","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862759,"choices":[{"index":0,"delta":{"role":"assistant","content":" Go"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764862759-qsI3C4t47te0ib8QGB6x","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862759,"choices":[{"index":0,"delta":{"role":"assistant","content":" files"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764862759-qsI3C4t47te0ib8QGB6x","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862759,"choices":[{"index":0,"delta":{"role":"assistant","content":" using"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764862759-qsI3C4t47te0ib8QGB6x","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862759,"choices":[{"index":0,"delta":{"role":"assistant","content":" grep"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764862759-qsI3C4t47te0ib8QGB6x","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862759,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
-
-      data: {"id":"gen-1764862759-qsI3C4t47te0ib8QGB6x","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862759,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":140,"completion_tokens":9,"total_tokens":149,"cost":0.0000212,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.000014,"upstream_inference_completions_cost":0.0000072},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      data: {"id":"gen-1765450195-UcNkDgNeGiSDNMOQYMrq","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450195,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":144,"completion_tokens":8,"total_tokens":152,"cost":0.0000312,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000216,"upstream_inference_completions_cost":0.0000096},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
 
       data: [DONE]
 
@@ -53,15 +43,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 937.9565ms
+    duration: 931.045916ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49920
+    content_length: 50348
     host: ""

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

@@ -24,21 +24,35 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764862769-xKX5bOBWM8OKXZGpqKYF","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862769,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450201-uCjS9MYSLxlXyzRS6nbO","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450201,"choices":[{"index":0,"delta":{"role":"assistant","content":"Use"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862769-xKX5bOBWM8OKXZGpqKYF","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862769,"choices":[{"index":0,"delta":{"role":"assistant","content":"Use"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450201-uCjS9MYSLxlXyzRS6nbO","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450201,"choices":[{"index":0,"delta":{"role":"assistant","content":" mult"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862769-xKX5bOBWM8OKXZGpqKYF","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862769,"choices":[{"index":0,"delta":{"role":"assistant","content":" multiedit to"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450201-uCjS9MYSLxlXyzRS6nbO","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450201,"choices":[{"index":0,"delta":{"role":"assistant","content":"ied"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862769-xKX5bOBWM8OKXZGpqKYF","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862769,"choices":[{"index":0,"delta":{"role":"assistant","content":" update greeting"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450201-uCjS9MYSLxlXyzRS6nbO","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450201,"choices":[{"index":0,"delta":{"role":"assistant","content":"it"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862769-xKX5bOBWM8OKXZGpqKYF","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862769,"choices":[{"index":0,"delta":{"role":"assistant","content":" and add comment in"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450201-uCjS9MYSLxlXyzRS6nbO","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450201,"choices":[{"index":0,"delta":{"role":"assistant","content":" to"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862769-xKX5bOBWM8OKXZGpqKYF","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862769,"choices":[{"index":0,"delta":{"role":"assistant","content":" main.go"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450201-uCjS9MYSLxlXyzRS6nbO","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450201,"choices":[{"index":0,"delta":{"role":"assistant","content":" update"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862769-xKX5bOBWM8OKXZGpqKYF","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862769,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
+      data: {"id":"gen-1765450201-uCjS9MYSLxlXyzRS6nbO","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450201,"choices":[{"index":0,"delta":{"role":"assistant","content":" greeting"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862769-xKX5bOBWM8OKXZGpqKYF","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862769,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":160,"completion_tokens":14,"total_tokens":174,"cost":0.000045,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.000024,"upstream_inference_completions_cost":0.000021},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      data: {"id":"gen-1765450201-uCjS9MYSLxlXyzRS6nbO","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450201,"choices":[{"index":0,"delta":{"role":"assistant","content":" and"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1765450201-uCjS9MYSLxlXyzRS6nbO","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450201,"choices":[{"index":0,"delta":{"role":"assistant","content":" add"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1765450201-uCjS9MYSLxlXyzRS6nbO","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450201,"choices":[{"index":0,"delta":{"role":"assistant","content":" comment"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1765450201-uCjS9MYSLxlXyzRS6nbO","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450201,"choices":[{"index":0,"delta":{"role":"assistant","content":" in"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1765450201-uCjS9MYSLxlXyzRS6nbO","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450201,"choices":[{"index":0,"delta":{"role":"assistant","content":" main"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1765450201-uCjS9MYSLxlXyzRS6nbO","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450201,"choices":[{"index":0,"delta":{"role":"assistant","content":".go"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+
+      data: {"id":"gen-1765450201-uCjS9MYSLxlXyzRS6nbO","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450201,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
+
+      data: {"id":"gen-1765450201-uCjS9MYSLxlXyzRS6nbO","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450201,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":160,"completion_tokens":14,"total_tokens":174,"cost":0.000045,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.000024,"upstream_inference_completions_cost":0.000021},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
 
       data: [DONE]
 
@@ -47,15 +61,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 547.476834ms
+    duration: 1.045920416s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50000
+    content_length: 50428
     host: ""

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

@@ -24,23 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764862833-tOhYcLNmvlm0xr7L4TiV","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862833,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450253-aB1ptbsaQGZNx7caoOWm","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450253,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862833-tOhYcLNmvlm0xr7L4TiV","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862833,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450253-aB1ptbsaQGZNx7caoOWm","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450253,"choices":[{"index":0,"delta":{"role":"assistant","content":"Find"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862833-tOhYcLNmvlm0xr7L4TiV","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862833,"choices":[{"index":0,"delta":{"role":"assistant","content":"Find"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450253-aB1ptbsaQGZNx7caoOWm","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450253,"choices":[{"index":0,"delta":{"role":"assistant","content":" .go files and"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862833-tOhYcLNmvlm0xr7L4TiV","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862833,"choices":[{"index":0,"delta":{"role":"assistant","content":" .go files and"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450253-aB1ptbsaQGZNx7caoOWm","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450253,"choices":[{"index":0,"delta":{"role":"assistant","content":" list directory"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862833-tOhYcLNmvlm0xr7L4TiV","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862833,"choices":[{"index":0,"delta":{"role":"assistant","content":" list directory"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450253-aB1ptbsaQGZNx7caoOWm","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450253,"choices":[{"index":0,"delta":{"role":"assistant","content":" in"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862833-tOhYcLNmvlm0xr7L4TiV","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862833,"choices":[{"index":0,"delta":{"role":"assistant","content":" in"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450253-aB1ptbsaQGZNx7caoOWm","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450253,"choices":[{"index":0,"delta":{"role":"assistant","content":" parallel"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862833-tOhYcLNmvlm0xr7L4TiV","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862833,"choices":[{"index":0,"delta":{"role":"assistant","content":" parallel"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450253-aB1ptbsaQGZNx7caoOWm","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450253,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
 
-      data: {"id":"gen-1764862833-tOhYcLNmvlm0xr7L4TiV","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862833,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
-
-      data: {"id":"gen-1764862833-tOhYcLNmvlm0xr7L4TiV","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862833,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":156,"completion_tokens":10,"total_tokens":166,"cost":0.00003284,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.00002184,"upstream_inference_completions_cost":0.000011},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      data: {"id":"gen-1765450253-aB1ptbsaQGZNx7caoOWm","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450253,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":156,"completion_tokens":10,"total_tokens":166,"cost":0.0000354,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000234,"upstream_inference_completions_cost":0.000012},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
 
       data: [DONE]
 
@@ -49,15 +47,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 209.204917ms
+    duration: 406.877083ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50011
+    content_length: 50439
     host: ""

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

@@ -24,19 +24,15 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764862715-k965LnDbHybA0s6MJwAs","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862715,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450141-fso4k5alZHsFg1Ss7Y5w","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450141,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
 
-      data: {"id":"gen-1764862715-k965LnDbHybA0s6MJwAs","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862715,"choices":[{"index":0,"delta":{"role":"assistant","content":"Read"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450141-fso4k5alZHsFg1Ss7Y5w","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450141,"choices":[{"index":0,"delta":{"role":"assistant","content":"Read"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
 
-      data: {"id":"gen-1764862715-k965LnDbHybA0s6MJwAs","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862715,"choices":[{"index":0,"delta":{"role":"assistant","content":" the"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450141-fso4k5alZHsFg1Ss7Y5w","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450141,"choices":[{"index":0,"delta":{"role":"assistant","content":" the go mod"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
 
-      data: {"id":"gen-1764862715-k965LnDbHybA0s6MJwAs","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862715,"choices":[{"index":0,"delta":{"role":"assistant","content":" go"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450141-fso4k5alZHsFg1Ss7Y5w","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450141,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}],"system_fingerprint":null}
 
-      data: {"id":"gen-1764862715-k965LnDbHybA0s6MJwAs","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862715,"choices":[{"index":0,"delta":{"role":"assistant","content":" mod"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764862715-k965LnDbHybA0s6MJwAs","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862715,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
-
-      data: {"id":"gen-1764862715-k965LnDbHybA0s6MJwAs","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862715,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":131,"completion_tokens":5,"total_tokens":136,"cost":0.0000171,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000131,"upstream_inference_completions_cost":0.000004},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      data: {"id":"gen-1765450141-fso4k5alZHsFg1Ss7Y5w","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450141,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":135,"completion_tokens":4,"total_tokens":139,"cost":0.00002505,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.00002025,"upstream_inference_completions_cost":0.0000048},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
 
       data: [DONE]
 
@@ -45,15 +41,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 834.326708ms
+    duration: 762.002208ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49884
+    content_length: 50312
     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-1764862714-vD89hN6MMDQXWYsJAuZ4","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862714,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450138-WRCaApYTil43Xf1sSzHC","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450138,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862714-vD89hN6MMDQXWYsJAuZ4","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862714,"choices":[{"index":0,"delta":{"role":"assistant","content":"Hello"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450138-WRCaApYTil43Xf1sSzHC","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450138,"choices":[{"index":0,"delta":{"role":"assistant","content":"Hello"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862714-vD89hN6MMDQXWYsJAuZ4","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862714,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
+      data: {"id":"gen-1765450138-WRCaApYTil43Xf1sSzHC","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450138,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
 
-      data: {"id":"gen-1764862714-vD89hN6MMDQXWYsJAuZ4","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862714,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":128,"completion_tokens":2,"total_tokens":130,"cost":0.000015,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000128,"upstream_inference_completions_cost":0.0000022},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      data: {"id":"gen-1765450138-WRCaApYTil43Xf1sSzHC","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450138,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":128,"completion_tokens":2,"total_tokens":130,"cost":0.0000144,"is_byok":false,"prompt_tokens_details":{"cached_tokens":2,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000128,"upstream_inference_completions_cost":0.0000016},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
 
       data: [DONE]
 
@@ -39,15 +39,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 635.219458ms
+    duration: 1.336080084s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49874
+    content_length: 50302
     host: ""

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

@@ -24,23 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764862780-DxPacjmGBJHtn64cZujI","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862780,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450225-ZNd9O4Gaiw67Y8sUTO9e","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450225,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
 
-      data: {"id":"gen-1764862780-DxPacjmGBJHtn64cZujI","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862780,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450225-ZNd9O4Gaiw67Y8sUTO9e","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450225,"choices":[{"index":0,"delta":{"role":"assistant","content":"Search"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
 
-      data: {"id":"gen-1764862780-DxPacjmGBJHtn64cZujI","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862780,"choices":[{"index":0,"delta":{"role":"assistant","content":"Search"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450225-ZNd9O4Gaiw67Y8sUTO9e","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450225,"choices":[{"index":0,"delta":{"role":"assistant","content":" for func"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
 
-      data: {"id":"gen-1764862780-DxPacjmGBJHtn64cZujI","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862780,"choices":[{"index":0,"delta":{"role":"assistant","content":" for func"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450225-ZNd9O4Gaiw67Y8sUTO9e","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450225,"choices":[{"index":0,"delta":{"role":"assistant","content":" main in Go repositories"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
 
-      data: {"id":"gen-1764862780-DxPacjmGBJHtn64cZujI","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862780,"choices":[{"index":0,"delta":{"role":"assistant","content":" main in Go repositories"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450225-ZNd9O4Gaiw67Y8sUTO9e","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450225,"choices":[{"index":0,"delta":{"role":"assistant","content":" using Sourcegraph"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
 
-      data: {"id":"gen-1764862780-DxPacjmGBJHtn64cZujI","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862780,"choices":[{"index":0,"delta":{"role":"assistant","content":" using Source"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450225-ZNd9O4Gaiw67Y8sUTO9e","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450225,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}],"system_fingerprint":null}
 
-      data: {"id":"gen-1764862780-DxPacjmGBJHtn64cZujI","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862780,"choices":[{"index":0,"delta":{"role":"assistant","content":"graph"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764862780-DxPacjmGBJHtn64cZujI","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862780,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
-
-      data: {"id":"gen-1764862780-DxPacjmGBJHtn64cZujI","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862780,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":140,"completion_tokens":11,"total_tokens":151,"cost":0.0000317,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000196,"upstream_inference_completions_cost":0.0000121},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      data: {"id":"gen-1765450225-ZNd9O4Gaiw67Y8sUTO9e","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450225,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":144,"completion_tokens":10,"total_tokens":154,"cost":0.0000336,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000216,"upstream_inference_completions_cost":0.000012},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
 
       data: [DONE]
 
@@ -49,15 +45,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 252.042666ms
+    duration: 474.183292ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49934
+    content_length: 50362
     host: ""

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

@@ -24,19 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764862718-jb4FsxCbJM3a4t2pBXI6","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862718,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450148-ryE7UAQTZkBmJUJaEF6T","provider":"SiliconFlow","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450148,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":""}
 
-      data: {"id":"gen-1764862718-jb4FsxCbJM3a4t2pBXI6","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862718,"choices":[{"index":0,"delta":{"role":"assistant","content":"Update"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450148-ryE7UAQTZkBmJUJaEF6T","provider":"SiliconFlow","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450148,"choices":[{"index":0,"delta":{"role":"assistant","content":"Update"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":""}
 
-      data: {"id":"gen-1764862718-jb4FsxCbJM3a4t2pBXI6","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862718,"choices":[{"index":0,"delta":{"role":"assistant","content":" main.go to print"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450148-ryE7UAQTZkBmJUJaEF6T","provider":"SiliconFlow","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450148,"choices":[{"index":0,"delta":{"role":"assistant","content":" main.go to print"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":""}
 
-      data: {"id":"gen-1764862718-jb4FsxCbJM3a4t2pBXI6","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862718,"choices":[{"index":0,"delta":{"role":"assistant","content":" hello"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450148-ryE7UAQTZkBmJUJaEF6T","provider":"SiliconFlow","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450148,"choices":[{"index":0,"delta":{"role":"assistant","content":" hello"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":""}
 
-      data: {"id":"gen-1764862718-jb4FsxCbJM3a4t2pBXI6","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862718,"choices":[{"index":0,"delta":{"role":"assistant","content":" from crush"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450148-ryE7UAQTZkBmJUJaEF6T","provider":"SiliconFlow","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450148,"choices":[{"index":0,"delta":{"role":"assistant","content":" from crush"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":""}
 
-      data: {"id":"gen-1764862718-jb4FsxCbJM3a4t2pBXI6","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862718,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
+      data: {"id":"gen-1765450148-ryE7UAQTZkBmJUJaEF6T","provider":"SiliconFlow","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450148,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}],"system_fingerprint":""}
 
-      data: {"id":"gen-1764862718-jb4FsxCbJM3a4t2pBXI6","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862718,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":141,"completion_tokens":9,"total_tokens":150,"cost":0.00003465,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.00002115,"upstream_inference_completions_cost":0.0000135},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      data: {"id":"gen-1765450148-ryE7UAQTZkBmJUJaEF6T","provider":"SiliconFlow","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450148,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":141,"completion_tokens":9,"total_tokens":150,"cost":0.00003234,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.00001974,"upstream_inference_completions_cost":0.0000126},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
 
       data: [DONE]
 
@@ -45,15 +45,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 564.753209ms
+    duration: 2.989851042s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49940
+    content_length: 50368
     host: ""

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

@@ -24,37 +24,25 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764862816-GgtH2XwpV5p6yJl1bP7d","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862816,"choices":[{"index":0,"delta":{"role":"assistant","content":"Create"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450247-TGHyRmlHv3hcgx1rGLqM","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450247,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862816-GgtH2XwpV5p6yJl1bP7d","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862816,"choices":[{"index":0,"delta":{"role":"assistant","content":" config"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450247-TGHyRmlHv3hcgx1rGLqM","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450247,"choices":[{"index":0,"delta":{"role":"assistant","content":"Create"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862816-GgtH2XwpV5p6yJl1bP7d","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862816,"choices":[{"index":0,"delta":{"role":"assistant","content":".json"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450247-TGHyRmlHv3hcgx1rGLqM","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450247,"choices":[{"index":0,"delta":{"role":"assistant","content":" config"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862816-GgtH2XwpV5p6yJl1bP7d","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862816,"choices":[{"index":0,"delta":{"role":"assistant","content":" with"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450247-TGHyRmlHv3hcgx1rGLqM","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450247,"choices":[{"index":0,"delta":{"role":"assistant","content":".json"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862816-GgtH2XwpV5p6yJl1bP7d","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862816,"choices":[{"index":0,"delta":{"role":"assistant","content":" test"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450247-TGHyRmlHv3hcgx1rGLqM","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450247,"choices":[{"index":0,"delta":{"role":"assistant","content":" with"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862816-GgtH2XwpV5p6yJl1bP7d","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862816,"choices":[{"index":0,"delta":{"role":"assistant","content":" name"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450247-TGHyRmlHv3hcgx1rGLqM","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450247,"choices":[{"index":0,"delta":{"role":"assistant","content":" sample"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862816-GgtH2XwpV5p6yJl1bP7d","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862816,"choices":[{"index":0,"delta":{"role":"assistant","content":" and"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450247-TGHyRmlHv3hcgx1rGLqM","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450247,"choices":[{"index":0,"delta":{"role":"assistant","content":" JSON"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862816-GgtH2XwpV5p6yJl1bP7d","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862816,"choices":[{"index":0,"delta":{"role":"assistant","content":" version"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450247-TGHyRmlHv3hcgx1rGLqM","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450247,"choices":[{"index":0,"delta":{"role":"assistant","content":" content"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764862816-GgtH2XwpV5p6yJl1bP7d","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862816,"choices":[{"index":0,"delta":{"role":"assistant","content":" "},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      data: {"id":"gen-1765450247-TGHyRmlHv3hcgx1rGLqM","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450247,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
 
-      data: {"id":"gen-1764862816-GgtH2XwpV5p6yJl1bP7d","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862816,"choices":[{"index":0,"delta":{"role":"assistant","content":"1"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764862816-GgtH2XwpV5p6yJl1bP7d","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862816,"choices":[{"index":0,"delta":{"role":"assistant","content":"."},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764862816-GgtH2XwpV5p6yJl1bP7d","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862816,"choices":[{"index":0,"delta":{"role":"assistant","content":"0"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764862816-GgtH2XwpV5p6yJl1bP7d","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862816,"choices":[{"index":0,"delta":{"role":"assistant","content":"."},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764862816-GgtH2XwpV5p6yJl1bP7d","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862816,"choices":[{"index":0,"delta":{"role":"assistant","content":"0"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764862816-GgtH2XwpV5p6yJl1bP7d","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862816,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
-
-      data: {"id":"gen-1764862816-GgtH2XwpV5p6yJl1bP7d","provider":"AtlasCloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764862816,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":155,"completion_tokens":15,"total_tokens":170,"cost":0.00004575,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.00002325,"upstream_inference_completions_cost":0.0000225},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      data: {"id":"gen-1765450247-TGHyRmlHv3hcgx1rGLqM","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1765450247,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":155,"completion_tokens":8,"total_tokens":163,"cost":0.0000219,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000155,"upstream_inference_completions_cost":0.0000064},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
 
       data: [DONE]
 
@@ -63,15 +51,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 1.202398292s
+    duration: 866.552792ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49977
+    content_length: 50405
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/bash_tool.yaml 🔗

@@ -24,19 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"2025120423410393d676a9732447b6","created":1764862863,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"20251211185119a522591d9348495e","created":1765450279,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"2025120423410393d676a9732447b6","created":1764862863,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Create"}}]}
+      data: {"id":"20251211185119a522591d9348495e","created":1765450279,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Create"}}]}
 
-      data: {"id":"2025120423410393d676a9732447b6","created":1764862863,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" file"}}]}
+      data: {"id":"20251211185119a522591d9348495e","created":1765450279,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" test"}}]}
 
-      data: {"id":"2025120423410393d676a9732447b6","created":1764862863,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
+      data: {"id":"20251211185119a522591d9348495e","created":1765450279,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".txt"}}]}
 
-      data: {"id":"2025120423410393d676a9732447b6","created":1764862863,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" bash"}}]}
+      data: {"id":"20251211185119a522591d9348495e","created":1765450279,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
 
-      data: {"id":"2025120423410393d676a9732447b6","created":1764862863,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" content"}}]}
+      data: {"id":"20251211185119a522591d9348495e","created":1765450279,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" bash"}}]}
 
-      data: {"id":"2025120423410393d676a9732447b6","created":1764862863,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":140,"completion_tokens":9,"total_tokens":149,"prompt_tokens_details":{"cached_tokens":114}}}
+      data: {"id":"20251211185119a522591d9348495e","created":1765450279,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" hello"}}]}
+
+      data: {"id":"20251211185119a522591d9348495e","created":1765450279,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":140,"completion_tokens":10,"total_tokens":150,"prompt_tokens_details":{"cached_tokens":4}}}
 
       data: [DONE]
 
@@ -45,15 +47,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 922.675792ms
+    duration: 1.094726334s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49838
+    content_length: 50229
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/download_tool.yaml 🔗

@@ -24,21 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"202512042341103a97970f105f4cdc","created":1764862870,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"20251211185124c68048d96253469c","created":1765450284,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"202512042341103a97970f105f4cdc","created":1764862870,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Download"}}]}
+      data: {"id":"20251211185124c68048d96253469c","created":1765450284,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Download"}}]}
 
-      data: {"id":"202512042341103a97970f105f4cdc","created":1764862870,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" and"}}]}
+      data: {"id":"20251211185124c68048d96253469c","created":1765450284,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" example"}}]}
 
-      data: {"id":"202512042341103a97970f105f4cdc","created":1764862870,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" save"}}]}
+      data: {"id":"20251211185124c68048d96253469c","created":1765450284,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".txt"}}]}
 
-      data: {"id":"202512042341103a97970f105f4cdc","created":1764862870,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" example"}}]}
+      data: {"id":"20251211185124c68048d96253469c","created":1765450284,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" from"}}]}
 
-      data: {"id":"202512042341103a97970f105f4cdc","created":1764862870,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".txt"}}]}
+      data: {"id":"20251211185124c68048d96253469c","created":1765450284,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" URL"}}]}
 
-      data: {"id":"202512042341103a97970f105f4cdc","created":1764862870,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" file"}}]}
-
-      data: {"id":"202512042341103a97970f105f4cdc","created":1764862870,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":143,"completion_tokens":10,"total_tokens":153,"prompt_tokens_details":{"cached_tokens":4}}}
+      data: {"id":"20251211185124c68048d96253469c","created":1765450284,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":143,"completion_tokens":9,"total_tokens":152,"prompt_tokens_details":{"cached_tokens":4}}}
 
       data: [DONE]
 
@@ -47,15 +45,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 854.211792ms
+    duration: 1.570323542s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49863
+    content_length: 50254
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/fetch_tool.yaml 🔗

@@ -6,9 +6,9 @@ interactions:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 799
+    content_length: 50272
     host: ""
-    body: '{"messages":[{"content":"you will generate a short title based on the first message a user begins a conversation with\n\n<rules>\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</rules>\n\n /no_think","role":"system"},{"content":"Generate a concise title for the following content:\n\nfetch the content from https://example-files.online-convert.com/website/html/example.html and tell me if it contains the word ''John Doe''\n <think>\n\n</think>","role":"user"}],"model":"glm-4.5-air","max_tokens":40,"stream_options":{"include_usage":true},"stream":true}'

internal/agent/testdata/TestCoderAgent/zai-glm4.6/glob_tool.yaml 🔗

@@ -24,19 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"202512042341213988a2cd7dc64fce","created":1764862881,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"20251211185134ebd9fa28ccd3461c","created":1765450294,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"202512042341213988a2cd7dc64fce","created":1764862881,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Find"}}]}
+      data: {"id":"20251211185134ebd9fa28ccd3461c","created":1765450294,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Find"}}]}
 
-      data: {"id":"202512042341213988a2cd7dc64fce","created":1764862881,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Go"}}]}
+      data: {"id":"20251211185134ebd9fa28ccd3461c","created":1765450294,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Go"}}]}
 
-      data: {"id":"202512042341213988a2cd7dc64fce","created":1764862881,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" files"}}]}
+      data: {"id":"20251211185134ebd9fa28ccd3461c","created":1765450294,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" files"}}]}
 
-      data: {"id":"202512042341213988a2cd7dc64fce","created":1764862881,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
+      data: {"id":"20251211185134ebd9fa28ccd3461c","created":1765450294,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
 
-      data: {"id":"202512042341213988a2cd7dc64fce","created":1764862881,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" glob"}}]}
+      data: {"id":"20251211185134ebd9fa28ccd3461c","created":1765450294,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" glob"}}]}
 
-      data: {"id":"202512042341213988a2cd7dc64fce","created":1764862881,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":132,"completion_tokens":9,"total_tokens":141,"prompt_tokens_details":{"cached_tokens":115}}}
+      data: {"id":"20251211185134ebd9fa28ccd3461c","created":1765450294,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":132,"completion_tokens":9,"total_tokens":141,"prompt_tokens_details":{"cached_tokens":114}}}
 
       data: [DONE]
 
@@ -45,15 +45,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.252965458s
+    duration: 981.48325ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49799
+    content_length: 50190
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/grep_tool.yaml 🔗

@@ -24,19 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"202512042341297e6b7b9f2a4448e6","created":1764862889,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"202512111851385170504ea0874cc3","created":1765450299,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"202512042341297e6b7b9f2a4448e6","created":1764862889,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"grep"}}]}
+      data: {"id":"202512111851385170504ea0874cc3","created":1765450299,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"grep"}}]}
 
-      data: {"id":"202512042341297e6b7b9f2a4448e6","created":1764862889,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" package"}}]}
+      data: {"id":"202512111851385170504ea0874cc3","created":1765450299,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" package"}}]}
 
-      data: {"id":"202512042341297e6b7b9f2a4448e6","created":1764862889,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" in"}}]}
+      data: {"id":"202512111851385170504ea0874cc3","created":1765450299,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" in"}}]}
 
-      data: {"id":"202512042341297e6b7b9f2a4448e6","created":1764862889,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" go"}}]}
+      data: {"id":"202512111851385170504ea0874cc3","created":1765450299,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" go"}}]}
 
-      data: {"id":"202512042341297e6b7b9f2a4448e6","created":1764862889,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" files"}}]}
+      data: {"id":"202512111851385170504ea0874cc3","created":1765450299,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" files"}}]}
 
-      data: {"id":"202512042341297e6b7b9f2a4448e6","created":1764862889,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":133,"completion_tokens":9,"total_tokens":142,"prompt_tokens_details":{"cached_tokens":115}}}
+      data: {"id":"202512111851385170504ea0874cc3","created":1765450299,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":133,"completion_tokens":9,"total_tokens":142,"prompt_tokens_details":{"cached_tokens":4}}}
 
       data: [DONE]
 
@@ -45,15 +45,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.198325875s
+    duration: 855.234292ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49797
+    content_length: 50188
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/ls_tool.yaml 🔗

@@ -24,17 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"202512042341454118f616a5d04018","created":1764862905,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"202512111851434c38af7cd171421e","created":1765450303,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"202512042341454118f616a5d04018","created":1764862905,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Listing"}}]}
+      data: {"id":"202512111851434c38af7cd171421e","created":1765450303,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"List"}}]}
 
-      data: {"id":"202512042341454118f616a5d04018","created":1764862905,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Files"}}]}
+      data: {"id":"202512111851434c38af7cd171421e","created":1765450303,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" files"}}]}
 
-      data: {"id":"202512042341454118f616a5d04018","created":1764862905,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
+      data: {"id":"202512111851434c38af7cd171421e","created":1765450303,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
 
-      data: {"id":"202512042341454118f616a5d04018","created":1764862905,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" ls"}}]}
+      data: {"id":"202512111851434c38af7cd171421e","created":1765450303,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" ls"}}]}
 
-      data: {"id":"202512042341454118f616a5d04018","created":1764862905,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":130,"completion_tokens":8,"total_tokens":138,"prompt_tokens_details":{"cached_tokens":114}}}
+      data: {"id":"202512111851434c38af7cd171421e","created":1765450303,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" command"}}]}
+
+      data: {"id":"202512111851434c38af7cd171421e","created":1765450303,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":130,"completion_tokens":9,"total_tokens":139,"prompt_tokens_details":{"cached_tokens":115}}}
 
       data: [DONE]
 
@@ -43,15 +45,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.516923042s
+    duration: 1.021628709s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49791
+    content_length: 50182
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/multiedit_tool.yaml 🔗

@@ -24,21 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"202512042341493c3bdbdd7a5c4a70","created":1764862909,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"20251211185203f1688fa8b72643cb","created":1765450323,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"202512042341493c3bdbdd7a5c4a70","created":1764862909,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Mult"}}]}
+      data: {"id":"20251211185203f1688fa8b72643cb","created":1765450323,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Mult"}}]}
 
-      data: {"id":"202512042341493c3bdbdd7a5c4a70","created":1764862909,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"ied"}}]}
+      data: {"id":"20251211185203f1688fa8b72643cb","created":1765450323,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"ied"}}]}
 
-      data: {"id":"202512042341493c3bdbdd7a5c4a70","created":1764862909,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"it"}}]}
+      data: {"id":"20251211185203f1688fa8b72643cb","created":1765450323,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"it"}}]}
 
-      data: {"id":"202512042341493c3bdbdd7a5c4a70","created":1764862909,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Go"}}]}
+      data: {"id":"20251211185203f1688fa8b72643cb","created":1765450323,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" main"}}]}
 
-      data: {"id":"202512042341493c3bdbdd7a5c4a70","created":1764862909,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" code"}}]}
+      data: {"id":"20251211185203f1688fa8b72643cb","created":1765450323,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".go"}}]}
 
-      data: {"id":"202512042341493c3bdbdd7a5c4a70","created":1764862909,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" modification"}}]}
+      data: {"id":"20251211185203f1688fa8b72643cb","created":1765450323,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" changes"}}]}
 
-      data: {"id":"202512042341493c3bdbdd7a5c4a70","created":1764862909,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":153,"completion_tokens":10,"total_tokens":163,"prompt_tokens_details":{"cached_tokens":114}}}
+      data: {"id":"20251211185203f1688fa8b72643cb","created":1765450323,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":153,"completion_tokens":10,"total_tokens":163,"prompt_tokens_details":{"cached_tokens":4}}}
 
       data: [DONE]
 
@@ -47,15 +47,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.209176375s
+    duration: 845.8035ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49877
+    content_length: 50268
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/parallel_tool_calls.yaml 🔗

@@ -24,19 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20251204234208ed241fdb1ad14397","created":1764862928,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"2025121118522536db54c7dd194969","created":1765450345,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"20251204234208ed241fdb1ad14397","created":1764862928,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Parallel"}}]}
+      data: {"id":"2025121118522536db54c7dd194969","created":1765450345,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Parallel"}}]}
 
-      data: {"id":"20251204234208ed241fdb1ad14397","created":1764862928,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" glob"}}]}
+      data: {"id":"2025121118522536db54c7dd194969","created":1765450345,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" glob"}}]}
 
-      data: {"id":"20251204234208ed241fdb1ad14397","created":1764862928,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" and"}}]}
+      data: {"id":"2025121118522536db54c7dd194969","created":1765450345,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" and"}}]}
 
-      data: {"id":"20251204234208ed241fdb1ad14397","created":1764862928,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" ls"}}]}
+      data: {"id":"2025121118522536db54c7dd194969","created":1765450345,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" ls"}}]}
 
-      data: {"id":"20251204234208ed241fdb1ad14397","created":1764862928,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" commands"}}]}
+      data: {"id":"2025121118522536db54c7dd194969","created":1765450345,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" commands"}}]}
 
-      data: {"id":"20251204234208ed241fdb1ad14397","created":1764862928,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":149,"completion_tokens":9,"total_tokens":158,"prompt_tokens_details":{"cached_tokens":115}}}
+      data: {"id":"2025121118522536db54c7dd194969","created":1765450345,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":149,"completion_tokens":9,"total_tokens":158,"prompt_tokens_details":{"cached_tokens":122}}}
 
       data: [DONE]
 
@@ -45,15 +45,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.525775667s
+    duration: 1.506124709s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49888
+    content_length: 50279
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/simple_test.yaml 🔗

@@ -24,15 +24,11 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20251204234038cdbbcc1a7bc04983","created":1764862839,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"20251211185103d5d62a07ff31425d","created":1765450263,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"20251204234038cdbbcc1a7bc04983","created":1764862839,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"G"}}]}
+      data: {"id":"20251211185103d5d62a07ff31425d","created":1765450263,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Hello"}}]}
 
-      data: {"id":"20251204234038cdbbcc1a7bc04983","created":1764862839,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"reeting"}}]}
-
-      data: {"id":"20251204234038cdbbcc1a7bc04983","created":1764862839,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Message"}}]}
-
-      data: {"id":"20251204234038cdbbcc1a7bc04983","created":1764862839,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":121,"completion_tokens":7,"total_tokens":128,"prompt_tokens_details":{"cached_tokens":114}}}
+      data: {"id":"20251211185103d5d62a07ff31425d","created":1765450263,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":121,"completion_tokens":5,"total_tokens":126,"prompt_tokens_details":{"cached_tokens":4}}}
 
       data: [DONE]
 
@@ -41,15 +37,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.15517175s
+    duration: 1.195221292s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49751
+    content_length: 50142
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/sourcegraph_tool.yaml 🔗

@@ -24,21 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"2025120423415738fbac8fe26e406b","created":1764862917,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"20251211185211c6f3ee23be6f4036","created":1765450331,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"2025120423415738fbac8fe26e406b","created":1764862917,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Search"}}]}
+      data: {"id":"20251211185211c6f3ee23be6f4036","created":1765450331,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Search"}}]}
 
-      data: {"id":"2025120423415738fbac8fe26e406b","created":1764862917,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Go"}}]}
+      data: {"id":"20251211185211c6f3ee23be6f4036","created":1765450331,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Go"}}]}
 
-      data: {"id":"2025120423415738fbac8fe26e406b","created":1764862917,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" repos"}}]}
+      data: {"id":"20251211185211c6f3ee23be6f4036","created":1765450331,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" repos"}}]}
 
-      data: {"id":"2025120423415738fbac8fe26e406b","created":1764862917,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
+      data: {"id":"20251211185211c6f3ee23be6f4036","created":1765450331,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
 
-      data: {"id":"2025120423415738fbac8fe26e406b","created":1764862917,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Source"}}]}
+      data: {"id":"20251211185211c6f3ee23be6f4036","created":1765450331,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Source"}}]}
 
-      data: {"id":"2025120423415738fbac8fe26e406b","created":1764862917,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"graph"}}]}
+      data: {"id":"20251211185211c6f3ee23be6f4036","created":1765450331,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"graph"}}]}
 
-      data: {"id":"2025120423415738fbac8fe26e406b","created":1764862917,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":133,"completion_tokens":10,"total_tokens":143,"prompt_tokens_details":{"cached_tokens":115}}}
+      data: {"id":"20251211185211c6f3ee23be6f4036","created":1765450331,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":133,"completion_tokens":10,"total_tokens":143,"prompt_tokens_details":{"cached_tokens":115}}}
 
       data: [DONE]
 
@@ -47,15 +47,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.250413708s
+    duration: 875.558166ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49811
+    content_length: 50202
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/update_a_file.yaml 🔗

@@ -24,21 +24,25 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"2025120423405085f5f6c62186420b","created":1764862850,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"20251211185111270976ba1e5441c9","created":1765450271,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"2025120423405085f5f6c62186420b","created":1764862850,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Update"}}]}
+      data: {"id":"20251211185111270976ba1e5441c9","created":1765450271,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Update"}}]}
 
-      data: {"id":"2025120423405085f5f6c62186420b","created":1764862850,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" main"}}]}
+      data: {"id":"20251211185111270976ba1e5441c9","created":1765450271,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" main"}}]}
 
-      data: {"id":"2025120423405085f5f6c62186420b","created":1764862850,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".go"}}]}
+      data: {"id":"20251211185111270976ba1e5441c9","created":1765450271,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".go"}}]}
 
-      data: {"id":"2025120423405085f5f6c62186420b","created":1764862850,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
+      data: {"id":"20251211185111270976ba1e5441c9","created":1765450271,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" to"}}]}
 
-      data: {"id":"2025120423405085f5f6c62186420b","created":1764862850,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" hello"}}]}
+      data: {"id":"20251211185111270976ba1e5441c9","created":1765450271,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" print"}}]}
 
-      data: {"id":"2025120423405085f5f6c62186420b","created":1764862850,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" message"}}]}
+      data: {"id":"20251211185111270976ba1e5441c9","created":1765450271,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" hello"}}]}
 
-      data: {"id":"2025120423405085f5f6c62186420b","created":1764862850,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":134,"completion_tokens":10,"total_tokens":144,"prompt_tokens_details":{"cached_tokens":114}}}
+      data: {"id":"20251211185111270976ba1e5441c9","created":1765450271,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" from"}}]}
+
+      data: {"id":"20251211185111270976ba1e5441c9","created":1765450271,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" crush"}}]}
+
+      data: {"id":"20251211185111270976ba1e5441c9","created":1765450271,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":134,"completion_tokens":12,"total_tokens":146,"prompt_tokens_details":{"cached_tokens":114}}}
 
       data: [DONE]
 
@@ -47,15 +51,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.561432209s
+    duration: 812.292167ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49817
+    content_length: 50208
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/write_tool.yaml 🔗

@@ -24,21 +24,23 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"202512042342030bfb852a91a24793","created":1764862923,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"2025121118521783ded8f44859400f","created":1765450337,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"202512042342030bfb852a91a24793","created":1764862923,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Create"}}]}
+      data: {"id":"2025121118521783ded8f44859400f","created":1765450337,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Create"}}]}
 
-      data: {"id":"202512042342030bfb852a91a24793","created":1764862923,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" config"}}]}
+      data: {"id":"2025121118521783ded8f44859400f","created":1765450337,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" config"}}]}
 
-      data: {"id":"202512042342030bfb852a91a24793","created":1764862923,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".json"}}]}
+      data: {"id":"2025121118521783ded8f44859400f","created":1765450337,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".json"}}]}
 
-      data: {"id":"202512042342030bfb852a91a24793","created":1764862923,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
+      data: {"id":"2025121118521783ded8f44859400f","created":1765450337,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" file"}}]}
 
-      data: {"id":"202512042342030bfb852a91a24793","created":1764862923,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" specific"}}]}
+      data: {"id":"2025121118521783ded8f44859400f","created":1765450337,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
 
-      data: {"id":"202512042342030bfb852a91a24793","created":1764862923,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" content"}}]}
+      data: {"id":"2025121118521783ded8f44859400f","created":1765450337,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" JSON"}}]}
 
-      data: {"id":"202512042342030bfb852a91a24793","created":1764862923,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":148,"completion_tokens":10,"total_tokens":158,"prompt_tokens_details":{"cached_tokens":115}}}
+      data: {"id":"2025121118521783ded8f44859400f","created":1765450337,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" content"}}]}
+
+      data: {"id":"2025121118521783ded8f44859400f","created":1765450337,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":148,"completion_tokens":11,"total_tokens":159,"prompt_tokens_details":{"cached_tokens":115}}}
 
       data: [DONE]
 
@@ -47,15 +49,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.199529708s
+    duration: 1.380565417s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49854
+    content_length: 50245
     host: ""

internal/agent/tools/edit.go 🔗

@@ -71,19 +71,12 @@ func NewEditTool(lspClients *csync.Map[string, *lsp.Client], permissions permiss
 
 			if params.OldString == "" {
 				response, err = createNewFile(editCtx, params.FilePath, params.NewString, call)
-				if err != nil {
-					return response, err
-				}
-			}
-
-			if params.NewString == "" {
+			} else if params.NewString == "" {
 				response, err = deleteContent(editCtx, params.FilePath, params.OldString, params.ReplaceAll, call)
-				if err != nil {
-					return response, err
-				}
+			} else {
+				response, err = replaceContent(editCtx, params.FilePath, params.OldString, params.NewString, params.ReplaceAll, call)
 			}
 
-			response, err = replaceContent(editCtx, params.FilePath, params.OldString, params.NewString, params.ReplaceAll, call)
 			if err != nil {
 				return response, err
 			}

internal/agent/tools/ls.go 🔗

@@ -98,7 +98,7 @@ func NewLsTool(permissions permission.Service, workingDir string, lsConfig confi
 
 			output, metadata, err := ListDirectoryTree(searchPath, params, lsConfig)
 			if err != nil {
-				return fantasy.NewTextErrorResponse(err.Error()), err
+				return fantasy.NewTextErrorResponse(err.Error()), nil
 			}
 
 			return fantasy.WithResponseMetadata(

internal/agent/tools/todos.go 🔗

@@ -0,0 +1,134 @@
+package tools
+
+import (
+	"context"
+	_ "embed"
+	"fmt"
+
+	"charm.land/fantasy"
+	"github.com/charmbracelet/crush/internal/session"
+)
+
+//go:embed todos.md
+var todosDescription []byte
+
+const TodosToolName = "todos"
+
+type TodosParams struct {
+	Todos []TodoItem `json:"todos" description:"The updated todo list"`
+}
+
+type TodoItem struct {
+	Content    string `json:"content" description:"What needs to be done (imperative form)"`
+	Status     string `json:"status" description:"Task status: pending, in_progress, or completed"`
+	ActiveForm string `json:"active_form" description:"Present continuous form (e.g., 'Running tests')"`
+}
+
+type TodosResponseMetadata struct {
+	IsNew         bool           `json:"is_new"`
+	Todos         []session.Todo `json:"todos"`
+	JustCompleted []string       `json:"just_completed,omitempty"`
+	JustStarted   string         `json:"just_started,omitempty"`
+	Completed     int            `json:"completed"`
+	Total         int            `json:"total"`
+}
+
+func NewTodosTool(sessions session.Service) fantasy.AgentTool {
+	return fantasy.NewAgentTool(
+		TodosToolName,
+		string(todosDescription),
+		func(ctx context.Context, params TodosParams, call fantasy.ToolCall) (fantasy.ToolResponse, error) {
+			sessionID := GetSessionFromContext(ctx)
+			if sessionID == "" {
+				return fantasy.ToolResponse{}, fmt.Errorf("session ID is required for managing todos")
+			}
+
+			currentSession, err := sessions.Get(ctx, sessionID)
+			if err != nil {
+				return fantasy.ToolResponse{}, fmt.Errorf("failed to get session: %w", err)
+			}
+
+			isNew := len(currentSession.Todos) == 0
+			oldStatusByContent := make(map[string]session.TodoStatus)
+			for _, todo := range currentSession.Todos {
+				oldStatusByContent[todo.Content] = todo.Status
+			}
+
+			for _, item := range params.Todos {
+				switch item.Status {
+				case "pending", "in_progress", "completed":
+				default:
+					return fantasy.ToolResponse{}, fmt.Errorf("invalid status %q for todo %q", item.Status, item.Content)
+				}
+			}
+
+			todos := make([]session.Todo, len(params.Todos))
+			var justCompleted []string
+			var justStarted string
+			completedCount := 0
+
+			for i, item := range params.Todos {
+				todos[i] = session.Todo{
+					Content:    item.Content,
+					Status:     session.TodoStatus(item.Status),
+					ActiveForm: item.ActiveForm,
+				}
+
+				newStatus := session.TodoStatus(item.Status)
+				oldStatus, existed := oldStatusByContent[item.Content]
+
+				if newStatus == session.TodoStatusCompleted {
+					completedCount++
+					if existed && oldStatus != session.TodoStatusCompleted {
+						justCompleted = append(justCompleted, item.Content)
+					}
+				}
+
+				if newStatus == session.TodoStatusInProgress {
+					if !existed || oldStatus != session.TodoStatusInProgress {
+						if item.ActiveForm != "" {
+							justStarted = item.ActiveForm
+						} else {
+							justStarted = item.Content
+						}
+					}
+				}
+			}
+
+			currentSession.Todos = todos
+			_, err = sessions.Save(ctx, currentSession)
+			if err != nil {
+				return fantasy.ToolResponse{}, fmt.Errorf("failed to save todos: %w", err)
+			}
+
+			response := "Todo list updated successfully.\n\n"
+
+			pendingCount := 0
+			inProgressCount := 0
+
+			for _, todo := range todos {
+				switch todo.Status {
+				case session.TodoStatusPending:
+					pendingCount++
+				case session.TodoStatusInProgress:
+					inProgressCount++
+				}
+			}
+
+			response += fmt.Sprintf("Status: %d pending, %d in progress, %d completed\n",
+				pendingCount, inProgressCount, completedCount)
+
+			response += "Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable."
+
+			metadata := TodosResponseMetadata{
+				IsNew:         isNew,
+				Todos:         todos,
+				JustCompleted: justCompleted,
+				JustStarted:   justStarted,
+				Completed:     completedCount,
+				Total:         len(todos),
+			}
+
+			return fantasy.WithResponseMetadata(fantasy.NewTextResponse(response), metadata), nil
+		})
+}

internal/agent/tools/todos.md 🔗

@@ -0,0 +1,90 @@
+Creates and manages a structured task list for tracking progress on complex, multi-step coding tasks.
+
+<when_to_use>
+Use this tool proactively in these scenarios:
+
+- Complex multi-step tasks requiring 3+ distinct steps or actions
+- Non-trivial tasks requiring careful planning or multiple operations
+- User explicitly requests todo list management
+- User provides multiple tasks (numbered or comma-separated list)
+- After receiving new instructions to capture requirements
+- When starting work on a task (mark as in_progress BEFORE beginning)
+- After completing a task (mark completed and add new follow-up tasks)
+</when_to_use>
+
+<when_not_to_use>
+Skip this tool when:
+
+- Single, straightforward task
+- Trivial task with no organizational benefit
+- Task completable in less than 3 trivial steps
+- Purely conversational or informational request
+</when_not_to_use>
+
+<task_states>
+- **pending**: Task not yet started
+- **in_progress**: Currently working on (limit to ONE task at a time)
+- **completed**: Task finished successfully
+
+**IMPORTANT**: Each task requires two forms:
+- **content**: Imperative form describing what needs to be done (e.g., "Run tests", "Build the project")
+- **active_form**: Present continuous form shown during execution (e.g., "Running tests", "Building the project")
+</task_states>
+
+<task_management>
+- Update task status in real-time as you work
+- Mark tasks complete IMMEDIATELY after finishing (don't batch completions)
+- Exactly ONE task must be in_progress at any time (not less, not more)
+- Complete current tasks before starting new ones
+- Remove tasks that are no longer relevant from the list entirely
+</task_management>
+
+<completion_requirements>
+ONLY mark a task as completed when you have FULLY accomplished it.
+
+Never mark completed if:
+- Tests are failing
+- Implementation is partial
+- You encountered unresolved errors
+- You couldn't find necessary files or dependencies
+
+If blocked:
+- Keep task as in_progress
+- Create new task describing what needs to be resolved
+</completion_requirements>
+
+<task_breakdown>
+- Create specific, actionable items
+- Break complex tasks into smaller, manageable steps
+- Use clear, descriptive task names
+- Always provide both content and active_form
+</task_breakdown>
+
+<examples>
+✅ Good task:
+```json
+{
+  "content": "Implement user authentication with JWT tokens",
+  "status": "in_progress",
+  "active_form": "Implementing user authentication with JWT tokens"
+}
+```
+
+❌ Bad task (missing active_form):
+```json
+{
+  "content": "Fix bug",
+  "status": "pending"
+}
+```
+</examples>
+
+<output_behavior>
+**NEVER** print or list todos in your response text. The user sees the todo list in real-time in the UI.
+</output_behavior>
+
+<tips>
+- When in doubt, use this tool - being proactive demonstrates attentiveness
+- One task in_progress at a time keeps work focused
+- Update immediately after state changes for accurate tracking
+</tips>

internal/app/app.go 🔗

@@ -10,6 +10,7 @@ import (
 	"io"
 	"log/slog"
 	"os"
+	"strings"
 	"sync"
 	"time"
 
@@ -30,13 +31,13 @@ import (
 	"github.com/charmbracelet/crush/internal/pubsub"
 	"github.com/charmbracelet/crush/internal/session"
 	"github.com/charmbracelet/crush/internal/shell"
-	"github.com/charmbracelet/crush/internal/term"
 	"github.com/charmbracelet/crush/internal/tui/components/anim"
 	"github.com/charmbracelet/crush/internal/tui/styles"
 	"github.com/charmbracelet/crush/internal/update"
 	"github.com/charmbracelet/crush/internal/version"
 	"github.com/charmbracelet/x/ansi"
 	"github.com/charmbracelet/x/exp/charmtone"
+	"github.com/charmbracelet/x/term"
 )
 
 type App struct {
@@ -61,7 +62,7 @@ type App struct {
 	cleanupFuncs []func() error
 }
 
-// New initializes a new applcation instance.
+// New initializes a new application instance.
 func New(ctx context.Context, conn *sql.DB, cfg *config.Config) (*App, error) {
 	q := db.New(conn)
 	sessions := session.NewService(q)
@@ -129,15 +130,27 @@ func (app *App) RunNonInteractive(ctx context.Context, output io.Writer, prompt
 	ctx, cancel := context.WithCancel(ctx)
 	defer cancel()
 
-	var spinner *format.Spinner
-	if !quiet {
+	var (
+		spinner   *format.Spinner
+		stdoutTTY bool
+		stderrTTY bool
+		stdinTTY  bool
+	)
+
+	if f, ok := output.(*os.File); ok {
+		stdoutTTY = term.IsTerminal(f.Fd())
+	}
+	stderrTTY = term.IsTerminal(os.Stderr.Fd())
+	stdinTTY = term.IsTerminal(os.Stdin.Fd())
+
+	if !quiet && stderrTTY {
 		t := styles.CurrentTheme()
 
 		// Detect background color to set the appropriate color for the
 		// spinner's 'Generating...' text. Without this, that text would be
 		// unreadable in light terminals.
 		hasDarkBG := true
-		if f, ok := output.(*os.File); ok {
+		if f, ok := output.(*os.File); ok && stdinTTY && stdoutTTY {
 			hasDarkBG = lipgloss.HasDarkBackground(os.Stdin, f)
 		}
 		defaultFG := lipgloss.LightDark(hasDarkBG)(charmtone.Pepper, t.FgBase)
@@ -203,10 +216,9 @@ func (app *App) RunNonInteractive(ctx context.Context, output io.Writer, prompt
 
 	messageEvents := app.Messages.Subscribe(ctx)
 	messageReadBytes := make(map[string]int)
-	supportsProgressBar := term.SupportsProgressBar()
 
 	defer func() {
-		if supportsProgressBar {
+		if stderrTTY {
 			_, _ = fmt.Fprintf(os.Stderr, ansi.ResetProgressBar)
 		}
 
@@ -216,9 +228,9 @@ func (app *App) RunNonInteractive(ctx context.Context, output io.Writer, prompt
 	}()
 
 	for {
-		if supportsProgressBar {
-			// HACK: Reinitialize the terminal progress bar on every iteration so
-			// it doesn't get hidden by the terminal due to inactivity.
+		if stderrTTY {
+			// HACK: Reinitialize the terminal progress bar on every iteration
+			// so it doesn't get hidden by the terminal due to inactivity.
 			_, _ = fmt.Fprintf(os.Stderr, ansi.SetIndeterminateProgressBar)
 		}
 
@@ -248,6 +260,11 @@ func (app *App) RunNonInteractive(ctx context.Context, output io.Writer, prompt
 				}
 
 				part := content[readBytes:]
+				// Trim leading whitespace. Sometimes the LLM includes leading
+				// formatting and intentation, which we don't want here.
+				if readBytes == 0 {
+					part = strings.TrimLeft(part, " \t")
+				}
 				fmt.Fprint(output, part)
 				messageReadBytes[msg.ID] = len(content)
 			}

internal/cmd/root.go 🔗

@@ -20,7 +20,6 @@ import (
 	"github.com/charmbracelet/crush/internal/db"
 	"github.com/charmbracelet/crush/internal/event"
 	"github.com/charmbracelet/crush/internal/stringext"
-	termutil "github.com/charmbracelet/crush/internal/term"
 	"github.com/charmbracelet/crush/internal/tui"
 	"github.com/charmbracelet/crush/internal/ui/common"
 	ui "github.com/charmbracelet/crush/internal/ui/model"
@@ -154,8 +153,20 @@ func Execute() {
 	}
 }
 
+// supportsProgressBar tries to determine whether the current terminal supports
+// progress bars by looking into environment variables.
+func supportsProgressBar() bool {
+	if !term.IsTerminal(os.Stderr.Fd()) {
+		return false
+	}
+	termProg := os.Getenv("TERM_PROGRAM")
+	_, isWindowsTerminal := os.LookupEnv("WT_SESSION")
+
+	return isWindowsTerminal || strings.Contains(strings.ToLower(termProg), "ghostty")
+}
+
 func setupAppWithProgressBar(cmd *cobra.Command) (*app.App, error) {
-	if termutil.SupportsProgressBar() {
+	if supportsProgressBar() {
 		_, _ = fmt.Fprintf(os.Stderr, ansi.SetIndeterminateProgressBar)
 		defer func() { _, _ = fmt.Fprintf(os.Stderr, ansi.ResetProgressBar) }()
 	}
@@ -230,7 +241,8 @@ func MaybePrependStdin(prompt string) (string, error) {
 	if err != nil {
 		return prompt, err
 	}
-	if fi.Mode()&os.ModeNamedPipe == 0 {
+	// Check if stdin is a named pipe ( | ) or regular file ( < ).
+	if fi.Mode()&os.ModeNamedPipe == 0 && !fi.Mode().IsRegular() {
 		return prompt, nil
 	}
 	bts, err := io.ReadAll(os.Stdin)

internal/cmd/run.go 🔗

@@ -58,11 +58,6 @@ crush run --quiet "Generate a README for this project"
 			return fmt.Errorf("no prompt provided")
 		}
 
-		// TODO: Make this work when redirected to something other than stdout.
-		// For example:
-		//     crush run "Do something fancy" > output.txt
-		//     echo "Do something fancy" | crush run > output.txt
-		//
 		return app.RunNonInteractive(ctx, os.Stdout, prompt, quiet)
 	},
 }

internal/config/load.go 🔗

@@ -14,6 +14,7 @@ import (
 	"slices"
 	"strconv"
 	"strings"
+	"testing"
 
 	"github.com/charmbracelet/catwalk/pkg/catwalk"
 	"github.com/charmbracelet/crush/internal/csync"
@@ -672,7 +673,7 @@ func hasAWSCredentials(env env.Env) bool {
 		return true
 	}
 
-	if _, err := os.Stat(filepath.Join(home.Dir(), ".aws/credentials")); err == nil {
+	if _, err := os.Stat(filepath.Join(home.Dir(), ".aws/credentials")); err == nil && !testing.Testing() {
 		return true
 	}
 

internal/config/load_test.go 🔗

@@ -487,7 +487,7 @@ func TestConfig_setupAgentsWithDisabledTools(t *testing.T) {
 	coderAgent, ok := cfg.Agents[AgentCoder]
 	require.True(t, ok)
 
-	assert.Equal(t, []string{"agent", "bash", "job_output", "job_kill", "multiedit", "lsp_diagnostics", "lsp_references", "fetch", "agentic_fetch", "glob", "ls", "sourcegraph", "view", "write"}, coderAgent.AllowedTools)
+	assert.Equal(t, []string{"agent", "bash", "job_output", "job_kill", "multiedit", "lsp_diagnostics", "lsp_references", "fetch", "agentic_fetch", "glob", "ls", "sourcegraph", "todos", "view", "write"}, coderAgent.AllowedTools)
 
 	taskAgent, ok := cfg.Agents[AgentTask]
 	require.True(t, ok)
@@ -510,7 +510,7 @@ func TestConfig_setupAgentsWithEveryReadOnlyToolDisabled(t *testing.T) {
 	cfg.SetupAgents()
 	coderAgent, ok := cfg.Agents[AgentCoder]
 	require.True(t, ok)
-	assert.Equal(t, []string{"agent", "bash", "job_output", "job_kill", "download", "edit", "multiedit", "lsp_diagnostics", "lsp_references", "fetch", "agentic_fetch", "write"}, coderAgent.AllowedTools)
+	assert.Equal(t, []string{"agent", "bash", "job_output", "job_kill", "download", "edit", "multiedit", "lsp_diagnostics", "lsp_references", "fetch", "agentic_fetch", "todos", "write"}, coderAgent.AllowedTools)
 
 	taskAgent, ok := cfg.Agents[AgentTask]
 	require.True(t, ok)

internal/db/models.go 🔗

@@ -42,4 +42,5 @@ type Session struct {
 	UpdatedAt        int64          `json:"updated_at"`
 	CreatedAt        int64          `json:"created_at"`
 	SummaryMessageID sql.NullString `json:"summary_message_id"`
+	Todos            sql.NullString `json:"todos"`
 }

internal/db/sessions.sql.go 🔗

@@ -33,7 +33,7 @@ INSERT INTO sessions (
     null,
     strftime('%s', 'now'),
     strftime('%s', 'now')
-) RETURNING id, parent_session_id, title, message_count, prompt_tokens, completion_tokens, cost, updated_at, created_at, summary_message_id
+) RETURNING id, parent_session_id, title, message_count, prompt_tokens, completion_tokens, cost, updated_at, created_at, summary_message_id, todos
 `
 
 type CreateSessionParams struct {
@@ -68,6 +68,7 @@ func (q *Queries) CreateSession(ctx context.Context, arg CreateSessionParams) (S
 		&i.UpdatedAt,
 		&i.CreatedAt,
 		&i.SummaryMessageID,
+		&i.Todos,
 	)
 	return i, err
 }
@@ -83,7 +84,7 @@ func (q *Queries) DeleteSession(ctx context.Context, id string) error {
 }
 
 const getSessionByID = `-- name: GetSessionByID :one
-SELECT id, parent_session_id, title, message_count, prompt_tokens, completion_tokens, cost, updated_at, created_at, summary_message_id
+SELECT id, parent_session_id, title, message_count, prompt_tokens, completion_tokens, cost, updated_at, created_at, summary_message_id, todos
 FROM sessions
 WHERE id = ? LIMIT 1
 `
@@ -102,12 +103,13 @@ func (q *Queries) GetSessionByID(ctx context.Context, id string) (Session, error
 		&i.UpdatedAt,
 		&i.CreatedAt,
 		&i.SummaryMessageID,
+		&i.Todos,
 	)
 	return i, err
 }
 
 const listSessions = `-- name: ListSessions :many
-SELECT id, parent_session_id, title, message_count, prompt_tokens, completion_tokens, cost, updated_at, created_at, summary_message_id
+SELECT id, parent_session_id, title, message_count, prompt_tokens, completion_tokens, cost, updated_at, created_at, summary_message_id, todos
 FROM sessions
 WHERE parent_session_id is NULL
 ORDER BY updated_at DESC
@@ -133,6 +135,7 @@ func (q *Queries) ListSessions(ctx context.Context) ([]Session, error) {
 			&i.UpdatedAt,
 			&i.CreatedAt,
 			&i.SummaryMessageID,
+			&i.Todos,
 		); err != nil {
 			return nil, err
 		}
@@ -154,9 +157,10 @@ SET
     prompt_tokens = ?,
     completion_tokens = ?,
     summary_message_id = ?,
-    cost = ?
+    cost = ?,
+    todos = ?
 WHERE id = ?
-RETURNING id, parent_session_id, title, message_count, prompt_tokens, completion_tokens, cost, updated_at, created_at, summary_message_id
+RETURNING id, parent_session_id, title, message_count, prompt_tokens, completion_tokens, cost, updated_at, created_at, summary_message_id, todos
 `
 
 type UpdateSessionParams struct {
@@ -165,6 +169,7 @@ type UpdateSessionParams struct {
 	CompletionTokens int64          `json:"completion_tokens"`
 	SummaryMessageID sql.NullString `json:"summary_message_id"`
 	Cost             float64        `json:"cost"`
+	Todos            sql.NullString `json:"todos"`
 	ID               string         `json:"id"`
 }
 
@@ -175,6 +180,7 @@ func (q *Queries) UpdateSession(ctx context.Context, arg UpdateSessionParams) (S
 		arg.CompletionTokens,
 		arg.SummaryMessageID,
 		arg.Cost,
+		arg.Todos,
 		arg.ID,
 	)
 	var i Session
@@ -189,6 +195,7 @@ func (q *Queries) UpdateSession(ctx context.Context, arg UpdateSessionParams) (S
 		&i.UpdatedAt,
 		&i.CreatedAt,
 		&i.SummaryMessageID,
+		&i.Todos,
 	)
 	return i, err
 }

internal/db/sql/sessions.sql 🔗

@@ -41,7 +41,8 @@ SET
     prompt_tokens = ?,
     completion_tokens = ?,
     summary_message_id = ?,
-    cost = ?
+    cost = ?,
+    todos = ?
 WHERE id = ?
 RETURNING *;
 

internal/env/env.go 🔗

@@ -1,6 +1,9 @@
 package env
 
-import "os"
+import (
+	"os"
+	"testing"
+)
 
 type Env interface {
 	Get(key string) string
@@ -23,6 +26,9 @@ func (o *osEnv) Env() []string {
 }
 
 func New() Env {
+	if testing.Testing() {
+		return NewFromMap(nil)
+	}
 	return &osEnv{}
 }
 

internal/env/env_test.go 🔗

@@ -8,7 +8,7 @@ import (
 )
 
 func TestOsEnv_Get(t *testing.T) {
-	env := New()
+	env := &osEnv{}
 
 	// Test getting an existing environment variable
 	t.Setenv("TEST_VAR", "test_value")
@@ -22,7 +22,7 @@ func TestOsEnv_Get(t *testing.T) {
 }
 
 func TestOsEnv_Env(t *testing.T) {
-	env := New()
+	env := &osEnv{}
 
 	envVars := env.Env()
 

internal/session/session.go 🔗

@@ -3,7 +3,9 @@ package session
 import (
 	"context"
 	"database/sql"
+	"encoding/json"
 	"fmt"
+	"log/slog"
 	"strings"
 
 	"github.com/charmbracelet/crush/internal/db"
@@ -12,6 +14,20 @@ import (
 	"github.com/google/uuid"
 )
 
+type TodoStatus string
+
+const (
+	TodoStatusPending    TodoStatus = "pending"
+	TodoStatusInProgress TodoStatus = "in_progress"
+	TodoStatusCompleted  TodoStatus = "completed"
+)
+
+type Todo struct {
+	Content    string     `json:"content"`
+	Status     TodoStatus `json:"status"`
+	ActiveForm string     `json:"active_form"`
+}
+
 type Session struct {
 	ID               string
 	ParentSessionID  string
@@ -21,6 +37,7 @@ type Session struct {
 	CompletionTokens int64
 	SummaryMessageID string
 	Cost             float64
+	Todos            []Todo
 	CreatedAt        int64
 	UpdatedAt        int64
 }
@@ -111,6 +128,11 @@ func (s *service) Get(ctx context.Context, id string) (Session, error) {
 }
 
 func (s *service) Save(ctx context.Context, session Session) (Session, error) {
+	todosJSON, err := marshalTodos(session.Todos)
+	if err != nil {
+		return Session{}, err
+	}
+
 	dbSession, err := s.q.UpdateSession(ctx, db.UpdateSessionParams{
 		ID:               session.ID,
 		Title:            session.Title,
@@ -121,6 +143,10 @@ func (s *service) Save(ctx context.Context, session Session) (Session, error) {
 			Valid:  session.SummaryMessageID != "",
 		},
 		Cost: session.Cost,
+		Todos: sql.NullString{
+			String: todosJSON,
+			Valid:  todosJSON != "",
+		},
 	})
 	if err != nil {
 		return Session{}, err
@@ -143,6 +169,10 @@ func (s *service) List(ctx context.Context) ([]Session, error) {
 }
 
 func (s service) fromDBItem(item db.Session) Session {
+	todos, err := unmarshalTodos(item.Todos.String)
+	if err != nil {
+		slog.Error("failed to unmarshal todos", "session_id", item.ID, "error", err)
+	}
 	return Session{
 		ID:               item.ID,
 		ParentSessionID:  item.ParentSessionID.String,
@@ -152,11 +182,34 @@ func (s service) fromDBItem(item db.Session) Session {
 		CompletionTokens: item.CompletionTokens,
 		SummaryMessageID: item.SummaryMessageID.String,
 		Cost:             item.Cost,
+		Todos:            todos,
 		CreatedAt:        item.CreatedAt,
 		UpdatedAt:        item.UpdatedAt,
 	}
 }
 
+func marshalTodos(todos []Todo) (string, error) {
+	if len(todos) == 0 {
+		return "", nil
+	}
+	data, err := json.Marshal(todos)
+	if err != nil {
+		return "", err
+	}
+	return string(data), nil
+}
+
+func unmarshalTodos(data string) ([]Todo, error) {
+	if data == "" {
+		return []Todo{}, nil
+	}
+	var todos []Todo
+	if err := json.Unmarshal([]byte(data), &todos); err != nil {
+		return []Todo{}, err
+	}
+	return todos, nil
+}
+
 func NewService(q db.Querier) Service {
 	broker := pubsub.NewBroker[Session]()
 	return &service{

internal/shell/background_test.go 🔗

@@ -2,6 +2,7 @@ package shell
 
 import (
 	"context"
+	"runtime"
 	"strings"
 	"testing"
 	"time"
@@ -171,6 +172,10 @@ func TestBackgroundShell_WithBlockFuncs(t *testing.T) {
 }
 
 func TestBackgroundShellManager_List(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		t.Skip("skipping flacky test on windows")
+	}
+
 	t.Parallel()
 
 	ctx := context.Background()

internal/term/term.go 🔗

@@ -1,15 +0,0 @@
-package term
-
-import (
-	"os"
-	"strings"
-)
-
-// SupportsProgressBar tries to determine whether the current terminal supports
-// progress bars by looking into environment variables.
-func SupportsProgressBar() bool {
-	termProg := os.Getenv("TERM_PROGRAM")
-	_, isWindowsTerminal := os.LookupEnv("WT_SESSION")
-
-	return isWindowsTerminal || strings.Contains(strings.ToLower(termProg), "ghostty")
-}

internal/tui/components/chat/chat.go 🔗

@@ -2,7 +2,6 @@ package chat
 
 import (
 	"context"
-	"strings"
 	"time"
 
 	"charm.land/bubbles/v2/key"
@@ -73,7 +72,6 @@ type messageListCmp struct {
 	lastClickX    int
 	lastClickY    int
 	clickCount    int
-	promptQueue   int
 }
 
 // New creates a new message list component with custom keybindings
@@ -104,13 +102,6 @@ func (m *messageListCmp) Init() tea.Cmd {
 // Update handles incoming messages and updates the component state.
 func (m *messageListCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) {
 	var cmds []tea.Cmd
-	if m.session.ID != "" && m.app.AgentCoordinator != nil {
-		queueSize := m.app.AgentCoordinator.QueuedPrompts(m.session.ID)
-		if queueSize != m.promptQueue {
-			m.promptQueue = queueSize
-			cmds = append(cmds, m.SetSize(m.width, m.height))
-		}
-	}
 	switch msg := msg.(type) {
 	case tea.KeyPressMsg:
 		if m.listCmp.IsFocused() && m.listCmp.HasSelection() {
@@ -223,24 +214,11 @@ func (m *messageListCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) {
 // View renders the message list or an initial screen if empty.
 func (m *messageListCmp) View() string {
 	t := styles.CurrentTheme()
-	height := m.height
-	if m.promptQueue > 0 {
-		height -= 4 // pill height and padding
-	}
-	view := []string{
-		t.S().Base.
-			Padding(1, 1, 0, 1).
-			Width(m.width).
-			Height(height).
-			Render(
-				m.listCmp.View(),
-			),
-	}
-	if m.app.AgentCoordinator != nil && m.promptQueue > 0 {
-		queuePill := queuePill(m.promptQueue, t)
-		view = append(view, t.S().Base.PaddingLeft(4).PaddingTop(1).Render(queuePill))
-	}
-	return strings.Join(view, "\n")
+	return t.S().Base.
+		Padding(1, 1, 0, 1).
+		Width(m.width).
+		Height(m.height).
+		Render(m.listCmp.View())
 }
 
 func (m *messageListCmp) handlePermissionRequest(permission permission.PermissionNotification) tea.Cmd {
@@ -682,11 +660,6 @@ func (m *messageListCmp) GetSize() (int, int) {
 func (m *messageListCmp) SetSize(width int, height int) tea.Cmd {
 	m.width = width
 	m.height = height
-	if m.promptQueue > 0 {
-		queueHeight := 3 + 1 // 1 for padding top
-		lHight := max(0, height-(1+queueHeight))
-		return m.listCmp.SetSize(width-2, lHight)
-	}
 	return m.listCmp.SetSize(width-2, max(0, height-1)) // for padding
 }
 
@@ -783,11 +756,7 @@ func (m *messageListCmp) CopySelectedText(clear bool) tea.Cmd {
 		return util.ReportInfo("No text selected")
 	}
 
-	if clear {
-		defer func() { m.SelectionClear() }()
-	}
-
-	return tea.Sequence(
+	cmds := []tea.Cmd{
 		// We use both OSC 52 and native clipboard for compatibility with different
 		// terminal emulators and environments.
 		tea.SetClipboard(selectedText),
@@ -796,7 +765,12 @@ func (m *messageListCmp) CopySelectedText(clear bool) tea.Cmd {
 			return nil
 		},
 		util.ReportInfo("Selected text copied to clipboard"),
-	)
+	}
+	if clear {
+		cmds = append(cmds, m.SelectionClear())
+	}
+
+	return tea.Sequence(cmds...)
 }
 
 // abs returns the absolute value of an integer.

internal/tui/components/chat/editor/editor.go 🔗

@@ -550,7 +550,10 @@ func (c *editorCmp) IsEmpty() bool {
 func normalPromptFunc(info textarea.PromptInfo) string {
 	t := styles.CurrentTheme()
 	if info.LineNumber == 0 {
-		return "  > "
+		if info.Focused {
+			return "  > "
+		}
+		return "::: "
 	}
 	if info.Focused {
 		return t.S().Base.Foreground(t.GreenDark).Render("::: ")

internal/tui/components/chat/messages/renderer.go 🔗

@@ -13,6 +13,7 @@ import (
 	"github.com/charmbracelet/crush/internal/agent/tools"
 	"github.com/charmbracelet/crush/internal/ansiext"
 	"github.com/charmbracelet/crush/internal/fsext"
+	"github.com/charmbracelet/crush/internal/tui/components/chat/todos"
 	"github.com/charmbracelet/crush/internal/tui/components/core"
 	"github.com/charmbracelet/crush/internal/tui/highlight"
 	"github.com/charmbracelet/crush/internal/tui/styles"
@@ -197,6 +198,7 @@ func init() {
 	registry.register(tools.LSToolName, func() renderer { return lsRenderer{} })
 	registry.register(tools.SourcegraphToolName, func() renderer { return sourcegraphRenderer{} })
 	registry.register(tools.DiagnosticsToolName, func() renderer { return diagnosticsRenderer{} })
+	registry.register(tools.TodosToolName, func() renderer { return todosRenderer{} })
 	registry.register(agent.AgentToolName, func() renderer { return agentRenderer{} })
 }
 
@@ -1298,6 +1300,8 @@ func prettifyToolName(name string) string {
 		return "List"
 	case tools.SourcegraphToolName:
 		return "Sourcegraph"
+	case tools.TodosToolName:
+		return "To-Do"
 	case tools.ViewToolName:
 		return "View"
 	case tools.WriteToolName:
@@ -1306,3 +1310,94 @@ func prettifyToolName(name string) string {
 		return name
 	}
 }
+
+// -----------------------------------------------------------------------------
+//  Todos renderer
+// -----------------------------------------------------------------------------
+
+type todosRenderer struct {
+	baseRenderer
+}
+
+func (tr todosRenderer) Render(v *toolCallCmp) string {
+	t := styles.CurrentTheme()
+	var params tools.TodosParams
+	var meta tools.TodosResponseMetadata
+	var headerText string
+	var body string
+
+	// Parse params for pending state (before result is available).
+	if err := tr.unmarshalParams(v.call.Input, &params); err == nil {
+		completedCount := 0
+		inProgressTask := ""
+		for _, todo := range params.Todos {
+			if todo.Status == "completed" {
+				completedCount++
+			}
+			if todo.Status == "in_progress" {
+				if todo.ActiveForm != "" {
+					inProgressTask = todo.ActiveForm
+				} else {
+					inProgressTask = todo.Content
+				}
+			}
+		}
+
+		// Default display from params (used when pending or no metadata).
+		ratio := t.S().Base.Foreground(t.BlueDark).Render(fmt.Sprintf("%d/%d", completedCount, len(params.Todos)))
+		headerText = ratio
+		if inProgressTask != "" {
+			headerText = fmt.Sprintf("%s · %s", ratio, inProgressTask)
+		}
+
+		// If we have metadata, use it for richer display.
+		if v.result.Metadata != "" {
+			if err := tr.unmarshalParams(v.result.Metadata, &meta); err == nil {
+				if meta.IsNew {
+					if meta.JustStarted != "" {
+						headerText = fmt.Sprintf("created %d todos, starting first", meta.Total)
+					} else {
+						headerText = fmt.Sprintf("created %d todos", meta.Total)
+					}
+					body = todos.FormatTodosList(meta.Todos, styles.ArrowRightIcon, t, v.textWidth())
+				} else {
+					// Build header based on what changed.
+					hasCompleted := len(meta.JustCompleted) > 0
+					hasStarted := meta.JustStarted != ""
+					allCompleted := meta.Completed == meta.Total
+
+					ratio := t.S().Base.Foreground(t.BlueDark).Render(fmt.Sprintf("%d/%d", meta.Completed, meta.Total))
+					if hasCompleted && hasStarted {
+						text := t.S().Subtle.Render(fmt.Sprintf(" · completed %d, starting next", len(meta.JustCompleted)))
+						headerText = fmt.Sprintf("%s%s", ratio, text)
+					} else if hasCompleted {
+						text := t.S().Subtle.Render(fmt.Sprintf(" · completed %d", len(meta.JustCompleted)))
+						if allCompleted {
+							text = t.S().Subtle.Render(" · completed all")
+						}
+						headerText = fmt.Sprintf("%s%s", ratio, text)
+					} else if hasStarted {
+						headerText = fmt.Sprintf("%s%s", ratio, t.S().Subtle.Render(" · starting task"))
+					} else {
+						headerText = ratio
+					}
+
+					// Build body with details.
+					if allCompleted {
+						// Show all todos when all are completed, like when created
+						body = todos.FormatTodosList(meta.Todos, styles.ArrowRightIcon, t, v.textWidth())
+					} else if meta.JustStarted != "" {
+						body = t.S().Base.Foreground(t.GreenDark).Render(styles.ArrowRightIcon+" ") +
+							t.S().Base.Foreground(t.FgBase).Render(meta.JustStarted)
+					}
+				}
+			}
+		}
+	}
+
+	args := newParamBuilder().addMain(headerText).build()
+
+	return tr.renderWithParams(v, "To-Do", args, func() string {
+		return body
+	})
+}

internal/tui/components/chat/messages/tool.go 🔗

@@ -425,7 +425,7 @@ func (m *toolCallCmp) formatResultForCopy() string {
 		return m.formatWebFetchResultForCopy()
 	case agent.AgentToolName:
 		return m.formatAgentResultForCopy()
-	case tools.DownloadToolName, tools.GrepToolName, tools.GlobToolName, tools.LSToolName, tools.SourcegraphToolName, tools.DiagnosticsToolName:
+	case tools.DownloadToolName, tools.GrepToolName, tools.GlobToolName, tools.LSToolName, tools.SourcegraphToolName, tools.DiagnosticsToolName, tools.TodosToolName:
 		return fmt.Sprintf("```\n%s\n```", m.result.Content)
 	default:
 		return m.result.Content

internal/tui/components/chat/queue.go 🔗

@@ -1,28 +0,0 @@
-package chat
-
-import (
-	"fmt"
-	"strings"
-
-	"charm.land/lipgloss/v2"
-	"github.com/charmbracelet/crush/internal/tui/styles"
-)
-
-func queuePill(queue int, t *styles.Theme) string {
-	if queue <= 0 {
-		return ""
-	}
-	triangles := styles.ForegroundGrad("▶▶▶▶▶▶▶▶▶", false, t.RedDark, t.Accent)
-	if queue < 10 {
-		triangles = triangles[:queue]
-	}
-
-	allTriangles := strings.Join(triangles, "")
-
-	return t.S().Base.
-		BorderStyle(lipgloss.RoundedBorder()).
-		BorderForeground(t.BgOverlay).
-		PaddingLeft(1).
-		PaddingRight(1).
-		Render(fmt.Sprintf("%s %d Queued", allTriangles, queue))
-}

internal/tui/components/chat/todos/todos.go 🔗

@@ -0,0 +1,67 @@
+package todos
+
+import (
+	"slices"
+	"strings"
+
+	"charm.land/lipgloss/v2"
+	"github.com/charmbracelet/crush/internal/session"
+	"github.com/charmbracelet/crush/internal/tui/styles"
+	"github.com/charmbracelet/x/ansi"
+)
+
+func sortTodos(todos []session.Todo) {
+	slices.SortStableFunc(todos, func(a, b session.Todo) int {
+		return statusOrder(a.Status) - statusOrder(b.Status)
+	})
+}
+
+func statusOrder(s session.TodoStatus) int {
+	switch s {
+	case session.TodoStatusCompleted:
+		return 0
+	case session.TodoStatusInProgress:
+		return 1
+	default:
+		return 2
+	}
+}
+
+func FormatTodosList(todos []session.Todo, inProgressIcon string, t *styles.Theme, width int) string {
+	if len(todos) == 0 {
+		return ""
+	}
+
+	sorted := make([]session.Todo, len(todos))
+	copy(sorted, todos)
+	sortTodos(sorted)
+
+	var lines []string
+	for _, todo := range sorted {
+		var prefix string
+		var textStyle lipgloss.Style
+
+		switch todo.Status {
+		case session.TodoStatusCompleted:
+			prefix = t.S().Base.Foreground(t.Green).Render(styles.TodoCompletedIcon) + " "
+			textStyle = t.S().Base.Foreground(t.FgBase)
+		case session.TodoStatusInProgress:
+			prefix = t.S().Base.Foreground(t.GreenDark).Render(inProgressIcon + " ")
+			textStyle = t.S().Base.Foreground(t.FgBase)
+		default:
+			prefix = t.S().Base.Foreground(t.FgMuted).Render(styles.TodoPendingIcon) + " "
+			textStyle = t.S().Base.Foreground(t.FgBase)
+		}
+
+		text := todo.Content
+		if todo.Status == session.TodoStatusInProgress && todo.ActiveForm != "" {
+			text = todo.ActiveForm
+		}
+		line := prefix + textStyle.Render(text)
+		line = ansi.Truncate(line, width, "…")
+
+		lines = append(lines, line)
+	}
+
+	return strings.Join(lines, "\n")
+}

internal/tui/exp/list/list.go 🔗

@@ -350,13 +350,12 @@ func (l *list[T]) selectionView(view string, textOnly bool) string {
 	scr := uv.NewScreenBuffer(area.Dx(), area.Dy())
 	uv.NewStyledString(view).Draw(scr, area)
 
-	selArea := uv.Rectangle{
-		Min: uv.Pos(l.selectionStartCol, l.selectionStartLine),
-		Max: uv.Pos(l.selectionEndCol, l.selectionEndLine),
-	}
-	selArea = selArea.Canon()
-
+	selArea := l.selectionArea(false)
 	specialChars := getSpecialCharsMap()
+	selStyle := uv.Style{
+		Bg: t.TextSelection.GetBackground(),
+		Fg: t.TextSelection.GetForeground(),
+	}
 
 	isNonWhitespace := func(r rune) bool {
 		return r != ' ' && r != '\t' && r != 0 && r != '\n' && r != '\r'
@@ -371,9 +370,9 @@ func (l *list[T]) selectionView(view string, textOnly bool) string {
 	for y := range scr.Height() {
 		bounds := selectionBounds{startX: -1, endX: -1, inSelection: false}
 
-		if y >= selArea.Min.Y && y <= selArea.Max.Y {
+		if y >= selArea.Min.Y && y < selArea.Max.Y {
 			bounds.inSelection = true
-			if selArea.Min.Y == selArea.Max.Y {
+			if selArea.Min.Y == selArea.Max.Y-1 {
 				// Single line selection
 				bounds.startX = selArea.Min.X
 				bounds.endX = selArea.Max.X
@@ -381,7 +380,7 @@ func (l *list[T]) selectionView(view string, textOnly bool) string {
 				// First line of multi-line selection
 				bounds.startX = selArea.Min.X
 				bounds.endX = scr.Width()
-			} else if y == selArea.Max.Y {
+			} else if y == selArea.Max.Y-1 {
 				// Last line of multi-line selection
 				bounds.startX = 0
 				bounds.endX = selArea.Max.X
@@ -470,13 +469,9 @@ func (l *list[T]) selectionView(view string, textOnly bool) string {
 					continue
 				}
 
-				// Text selection styling, which is a Lip Gloss style. We must
-				// extract the values to use in a UV style, below.
-				ts := t.TextSelection
-
 				cell = cell.Clone()
-				cell.Style.Bg = ts.GetBackground()
-				cell.Style.Fg = ts.GetForeground()
+				cell.Style.Bg = selStyle.Bg
+				cell.Style.Fg = selStyle.Fg
 				scr.SetCell(x, y, cell)
 			}
 		}
@@ -864,6 +859,7 @@ func (l *list[T]) selectLastItem() {
 }
 
 func (l *list[T]) firstSelectableItemAbove(inx int) int {
+	unfocusableCount := 0
 	for i := inx - 1; i >= 0; i-- {
 		if i < 0 || i >= len(l.items) {
 			continue
@@ -873,14 +869,16 @@ func (l *list[T]) firstSelectableItemAbove(inx int) int {
 		if _, ok := any(item).(layout.Focusable); ok {
 			return i
 		}
+		unfocusableCount++
 	}
-	if inx == 0 && l.wrap {
+	if unfocusableCount == inx && l.wrap {
 		return l.firstSelectableItemAbove(len(l.items))
 	}
 	return ItemNotFound
 }
 
 func (l *list[T]) firstSelectableItemBelow(inx int) int {
+	unfocusableCount := 0
 	itemsLen := len(l.items)
 	for i := inx + 1; i < itemsLen; i++ {
 		if i < 0 || i >= len(l.items) {
@@ -891,8 +889,9 @@ func (l *list[T]) firstSelectableItemBelow(inx int) int {
 		if _, ok := any(item).(layout.Focusable); ok {
 			return i
 		}
+		unfocusableCount++
 	}
-	if inx == itemsLen-1 && l.wrap {
+	if unfocusableCount == itemsLen-inx-1 && l.wrap {
 		return l.firstSelectableItemBelow(-1)
 	}
 	return ItemNotFound
@@ -1352,6 +1351,14 @@ func (l *list[T]) SelectItemAbove() tea.Cmd {
 	}
 	// Pre-allocate with expected capacity
 	cmds := make([]tea.Cmd, 0, 2)
+	if newIndex > l.selectedItemIdx && l.selectedItemIdx > 0 && l.offset > 0 {
+		// this means there is a section above and not showing on the top, move to the top
+		newIndex = l.selectedItemIdx
+		cmd := l.GoToTop()
+		if cmd != nil {
+			cmds = append(cmds, cmd)
+		}
+	}
 	if newIndex == 1 {
 		peakAboveIndex := l.firstSelectableItemAbove(newIndex)
 		if peakAboveIndex == ItemNotFound {
@@ -1383,12 +1390,16 @@ func (l *list[T]) SelectItemBelow() tea.Cmd {
 
 	newIndex := l.firstSelectableItemBelow(l.selectedItemIdx)
 	if newIndex == ItemNotFound {
-		// no item above
+		// no item below
 		return nil
 	}
 	if newIndex < 0 || newIndex >= len(l.items) {
 		return nil
 	}
+	if newIndex < l.selectedItemIdx {
+		// reset offset when wrap to the top to show the top section if it exists
+		l.offset = 0
+	}
 	l.prevSelectedItemIdx = l.selectedItemIdx
 	l.selectedItemIdx = newIndex
 	l.movingByItem = true
@@ -1465,8 +1476,13 @@ func (l *list[T]) reset(selectedItemID string) tea.Cmd {
 // SetSize implements List.
 func (l *list[T]) SetSize(width int, height int) tea.Cmd {
 	oldWidth := l.width
+	oldHeight := l.height
 	l.width = width
 	l.height = height
+	// Invalidate cache if height changed
+	if oldHeight != height {
+		l.cachedViewDirty = true
+	}
 	if oldWidth != width {
 		// Get current selected item ID before reset
 		selectedID := ""
@@ -1685,11 +1701,75 @@ func (l *list[T]) HasSelection() bool {
 	return l.hasSelection()
 }
 
+func (l *list[T]) selectionArea(absolute bool) uv.Rectangle {
+	var startY int
+	if absolute {
+		startY, _ = l.viewPosition()
+	}
+	selArea := uv.Rectangle{
+		Min: uv.Pos(l.selectionStartCol, l.selectionStartLine+startY),
+		Max: uv.Pos(l.selectionEndCol, l.selectionEndLine+startY),
+	}
+	selArea = selArea.Canon()
+	selArea.Max.Y++ // make max Y exclusive
+	return selArea
+}
+
 // GetSelectedText returns the currently selected text.
 func (l *list[T]) GetSelectedText(paddingLeft int) string {
 	if !l.hasSelection() {
 		return ""
 	}
 
-	return l.selectionView(l.View(), true)
+	selArea := l.selectionArea(true)
+	if selArea.Empty() {
+		return ""
+	}
+
+	selectionHeight := selArea.Dy()
+
+	tempBuf := uv.NewScreenBuffer(l.width, selectionHeight)
+	tempBufArea := tempBuf.Bounds()
+	renderedLines := l.getLines(selArea.Min.Y, selArea.Max.Y)
+	styled := uv.NewStyledString(renderedLines)
+	styled.Draw(tempBuf, tempBufArea)
+
+	// XXX: Left padding assumes the list component is rendered with absolute
+	// positioning. The chat component has a left margin of 1 and items in the
+	// list have a border of 1 plus a padding of 1. The paddingLeft parameter
+	// assumes this total left padding of 3 and we should fix that.
+	leftBorder := paddingLeft - 1
+
+	var b strings.Builder
+	for y := tempBufArea.Min.Y; y < tempBufArea.Max.Y; y++ {
+		var pending strings.Builder
+		for x := tempBufArea.Min.X + leftBorder; x < tempBufArea.Max.X; {
+			cell := tempBuf.CellAt(x, y)
+			if cell == nil || cell.IsZero() {
+				x++
+				continue
+			}
+			if y == 0 && x < selArea.Min.X {
+				x++
+				continue
+			}
+			if y == selectionHeight-1 && x > selArea.Max.X-1 {
+				break
+			}
+			if cell.Width == 1 && cell.Content == " " {
+				pending.WriteString(cell.Content)
+				x++
+				continue
+			}
+			b.WriteString(pending.String())
+			pending.Reset()
+			b.WriteString(cell.Content)
+			x += cell.Width
+		}
+		if y < tempBufArea.Max.Y-1 {
+			b.WriteByte('\n')
+		}
+	}
+
+	return b.String()
 }

internal/tui/page/chat/chat.go 🔗

@@ -57,6 +57,14 @@ const (
 	PanelTypeSplash PanelType = "splash"
 )
 
+// PillSection represents which pill section is focused when in pills panel.
+type PillSection int
+
+const (
+	PillSectionTodos PillSection = iota
+	PillSectionQueue
+)
+
 const (
 	CompactModeWidthBreakpoint  = 120 // Width at which the chat page switches to compact mode
 	CompactModeHeightBreakpoint = 30  // Height at which the chat page switches to compact mode
@@ -116,9 +124,18 @@ type chatPage struct {
 	splashFullScreen bool
 	isOnboarding     bool
 	isProjectInit    bool
+	promptQueue      int
+
+	// Pills state
+	pillsExpanded      bool
+	focusedPillSection PillSection
+
+	// Todo spinner
+	todoSpinner spinner.Model
 }
 
 func New(app *app.App) ChatPage {
+	t := styles.CurrentTheme()
 	return &chatPage{
 		app:         app,
 		keyMap:      DefaultKeyMap(),
@@ -128,6 +145,10 @@ func New(app *app.App) ChatPage {
 		editor:      editor.New(app),
 		splash:      splash.New(),
 		focusedPane: PanelTypeSplash,
+		todoSpinner: spinner.New(
+			spinner.WithSpinner(spinner.MiniDot),
+			spinner.WithStyle(t.S().Base.Foreground(t.GreenDark)),
+		),
 	}
 }
 
@@ -166,6 +187,13 @@ func (p *chatPage) Init() tea.Cmd {
 
 func (p *chatPage) Update(msg tea.Msg) (util.Model, tea.Cmd) {
 	var cmds []tea.Cmd
+	if p.session.ID != "" && p.app.AgentCoordinator != nil {
+		queueSize := p.app.AgentCoordinator.QueuedPrompts(p.session.ID)
+		if queueSize != p.promptQueue {
+			p.promptQueue = queueSize
+			cmds = append(cmds, p.SetSize(p.width, p.height))
+		}
+	}
 	switch msg := msg.(type) {
 	case tea.KeyboardEnhancementsMsg:
 		p.keyboardEnhancements = msg
@@ -268,6 +296,19 @@ func (p *chatPage) Update(msg tea.Msg) (util.Model, tea.Cmd) {
 		p.editor = u.(editor.Editor)
 		return p, cmd
 	case pubsub.Event[session.Session]:
+		if msg.Payload.ID == p.session.ID {
+			prevHasIncompleteTodos := hasIncompleteTodos(p.session.Todos)
+			prevHasInProgress := p.hasInProgressTodo()
+			p.session = msg.Payload
+			newHasIncompleteTodos := hasIncompleteTodos(p.session.Todos)
+			newHasInProgress := p.hasInProgressTodo()
+			if prevHasIncompleteTodos != newHasIncompleteTodos {
+				cmds = append(cmds, p.SetSize(p.width, p.height))
+			}
+			if !prevHasInProgress && newHasInProgress {
+				cmds = append(cmds, p.todoSpinner.Tick)
+			}
+		}
 		u, cmd := p.header.Update(msg)
 		p.header = u.(header.Header)
 		cmds = append(cmds, cmd)
@@ -311,6 +352,17 @@ func (p *chatPage) Update(msg tea.Msg) (util.Model, tea.Cmd) {
 	case pubsub.Event[message.Message],
 		anim.StepMsg,
 		spinner.TickMsg:
+		// Update todo spinner if agent is busy and we have in-progress todos
+		agentBusy := p.app.AgentCoordinator != nil && p.app.AgentCoordinator.IsBusy()
+		if _, ok := msg.(spinner.TickMsg); ok && p.hasInProgressTodo() && agentBusy {
+			var cmd tea.Cmd
+			p.todoSpinner, cmd = p.todoSpinner.Update(msg)
+			cmds = append(cmds, cmd)
+		}
+		// Start spinner when agent becomes busy and we have in-progress todos
+		if _, ok := msg.(pubsub.Event[message.Message]); ok && p.hasInProgressTodo() && agentBusy {
+			cmds = append(cmds, p.todoSpinner.Tick)
+		}
 		if p.focusedPane == PanelTypeSplash {
 			u, cmd := p.splash.Update(msg)
 			p.splash = u.(splash.Splash)
@@ -401,8 +453,7 @@ func (p *chatPage) Update(msg tea.Msg) (util.Model, tea.Cmd) {
 				p.splash = u.(splash.Splash)
 				return p, cmd
 			}
-			p.changeFocus()
-			return p, nil
+			return p, p.changeFocus()
 		case key.Matches(msg, p.keyMap.Cancel):
 			if p.session.ID != "" && p.app.AgentCoordinator.IsBusy() {
 				return p, p.cancel()
@@ -410,6 +461,18 @@ func (p *chatPage) Update(msg tea.Msg) (util.Model, tea.Cmd) {
 		case key.Matches(msg, p.keyMap.Details):
 			p.toggleDetails()
 			return p, nil
+		case key.Matches(msg, p.keyMap.TogglePills):
+			if p.session.ID != "" {
+				return p, p.togglePillsExpanded()
+			}
+		case key.Matches(msg, p.keyMap.PillLeft):
+			if p.session.ID != "" && p.pillsExpanded {
+				return p, p.switchPillSection(-1)
+			}
+		case key.Matches(msg, p.keyMap.PillRight):
+			if p.session.ID != "" && p.pillsExpanded {
+				return p, p.switchPillSection(1)
+			}
 		}
 
 		switch p.focusedPane {
@@ -483,19 +546,91 @@ func (p *chatPage) View() string {
 	} else {
 		messagesView := p.chat.View()
 		editorView := p.editor.View()
+
+		hasIncompleteTodos := hasIncompleteTodos(p.session.Todos)
+		hasQueue := p.promptQueue > 0
+		todosFocused := p.pillsExpanded && p.focusedPillSection == PillSectionTodos
+		queueFocused := p.pillsExpanded && p.focusedPillSection == PillSectionQueue
+
+		// Use spinner when agent is busy, otherwise show static icon
+		agentBusy := p.app.AgentCoordinator != nil && p.app.AgentCoordinator.IsBusy()
+		inProgressIcon := t.S().Base.Foreground(t.GreenDark).Render(styles.CenterSpinnerIcon)
+		if agentBusy {
+			inProgressIcon = p.todoSpinner.View()
+		}
+
+		var pills []string
+		if hasIncompleteTodos {
+			pills = append(pills, todoPill(p.session.Todos, inProgressIcon, todosFocused, p.pillsExpanded, t))
+		}
+		if hasQueue {
+			pills = append(pills, queuePill(p.promptQueue, queueFocused, p.pillsExpanded, t))
+		}
+
+		var expandedList string
+		if p.pillsExpanded {
+			if todosFocused && hasIncompleteTodos {
+				expandedList = todoList(p.session.Todos, inProgressIcon, t, p.width-SideBarWidth)
+			} else if queueFocused && hasQueue {
+				queueItems := p.app.AgentCoordinator.QueuedPromptsList(p.session.ID)
+				expandedList = queueList(queueItems, t)
+			}
+		}
+
+		var pillsArea string
+		if len(pills) > 0 {
+			pillsRow := lipgloss.JoinHorizontal(lipgloss.Top, pills...)
+
+			// Add help hint for expanding/collapsing pills based on state.
+			var helpDesc string
+			if p.pillsExpanded {
+				helpDesc = "close"
+			} else {
+				helpDesc = "open"
+			}
+			// Style to match help section: keys in FgMuted, description in FgSubtle
+			helpKey := t.S().Base.Foreground(t.FgMuted).Render("ctrl+space")
+			helpText := t.S().Base.Foreground(t.FgSubtle).Render(helpDesc)
+			helpHint := lipgloss.JoinHorizontal(lipgloss.Center, helpKey, " ", helpText)
+			pillsRow = lipgloss.JoinHorizontal(lipgloss.Center, pillsRow, " ", helpHint)
+
+			if expandedList != "" {
+				pillsArea = lipgloss.JoinVertical(
+					lipgloss.Left,
+					pillsRow,
+					expandedList,
+				)
+			} else {
+				pillsArea = pillsRow
+			}
+
+			style := t.S().Base.MarginTop(1).PaddingLeft(3)
+			pillsArea = style.Render(pillsArea)
+		}
+
 		if p.compact {
 			headerView := p.header.View()
-			chatView = lipgloss.JoinVertical(
-				lipgloss.Left,
-				headerView,
-				messagesView,
-				editorView,
-			)
+			views := []string{headerView, messagesView}
+			if pillsArea != "" {
+				views = append(views, pillsArea)
+			}
+			views = append(views, editorView)
+			chatView = lipgloss.JoinVertical(lipgloss.Left, views...)
 		} else {
 			sidebarView := p.sidebar.View()
+			var messagesColumn string
+			if pillsArea != "" {
+				messagesColumn = lipgloss.JoinVertical(
+					lipgloss.Left,
+					messagesView,
+					pillsArea,
+				)
+			} else {
+				messagesColumn = messagesView
+			}
 			messages := lipgloss.JoinHorizontal(
 				lipgloss.Left,
-				messagesView,
+				messagesColumn,
 				sidebarView,
 			)
 			chatView = lipgloss.JoinVertical(
@@ -657,14 +792,30 @@ func (p *chatPage) SetSize(width, height int) tea.Cmd {
 			cmds = append(cmds, p.editor.SetPosition(0, height-EditorHeight))
 		}
 	} else {
+		hasIncompleteTodos := hasIncompleteTodos(p.session.Todos)
+		hasQueue := p.promptQueue > 0
+		hasPills := hasIncompleteTodos || hasQueue
+
+		pillsAreaHeight := 0
+		if hasPills {
+			pillsAreaHeight = pillHeightWithBorder + 1 // +1 for padding top
+			if p.pillsExpanded {
+				if p.focusedPillSection == PillSectionTodos && hasIncompleteTodos {
+					pillsAreaHeight += len(p.session.Todos)
+				} else if p.focusedPillSection == PillSectionQueue && hasQueue {
+					pillsAreaHeight += p.promptQueue
+				}
+			}
+		}
+
 		if p.compact {
-			cmds = append(cmds, p.chat.SetSize(width, height-EditorHeight-HeaderHeight))
+			cmds = append(cmds, p.chat.SetSize(width, height-EditorHeight-HeaderHeight-pillsAreaHeight))
 			p.detailsWidth = width - DetailsPositioning
 			cmds = append(cmds, p.sidebar.SetSize(p.detailsWidth-LeftRightBorders, p.detailsHeight-TopBottomBorders))
 			cmds = append(cmds, p.editor.SetSize(width, EditorHeight))
 			cmds = append(cmds, p.header.SetWidth(width-BorderWidth))
 		} else {
-			cmds = append(cmds, p.chat.SetSize(width-SideBarWidth, height-EditorHeight))
+			cmds = append(cmds, p.chat.SetSize(width-SideBarWidth, height-EditorHeight-pillsAreaHeight))
 			cmds = append(cmds, p.editor.SetSize(width, EditorHeight))
 			cmds = append(cmds, p.sidebar.SetSize(SideBarWidth, height-EditorHeight))
 		}
@@ -689,37 +840,77 @@ func (p *chatPage) newSession() tea.Cmd {
 	)
 }
 
-func (p *chatPage) setSession(session session.Session) tea.Cmd {
-	if p.session.ID == session.ID {
+func (p *chatPage) setSession(sess session.Session) tea.Cmd {
+	if p.session.ID == sess.ID {
 		return nil
 	}
 
 	var cmds []tea.Cmd
-	p.session = session
+	p.session = sess
+
+	if p.hasInProgressTodo() {
+		cmds = append(cmds, p.todoSpinner.Tick)
+	}
 
 	cmds = append(cmds, p.SetSize(p.width, p.height))
-	cmds = append(cmds, p.chat.SetSession(session))
-	cmds = append(cmds, p.sidebar.SetSession(session))
-	cmds = append(cmds, p.header.SetSession(session))
-	cmds = append(cmds, p.editor.SetSession(session))
+	cmds = append(cmds, p.chat.SetSession(sess))
+	cmds = append(cmds, p.sidebar.SetSession(sess))
+	cmds = append(cmds, p.header.SetSession(sess))
+	cmds = append(cmds, p.editor.SetSession(sess))
 
 	return tea.Sequence(cmds...)
 }
 
-func (p *chatPage) changeFocus() {
+func (p *chatPage) changeFocus() tea.Cmd {
 	if p.session.ID == "" {
-		return
+		return nil
 	}
+
 	switch p.focusedPane {
-	case PanelTypeChat:
-		p.focusedPane = PanelTypeEditor
-		p.editor.Focus()
-		p.chat.Blur()
 	case PanelTypeEditor:
 		p.focusedPane = PanelTypeChat
 		p.chat.Focus()
 		p.editor.Blur()
+	case PanelTypeChat:
+		p.focusedPane = PanelTypeEditor
+		p.editor.Focus()
+		p.chat.Blur()
+	}
+	return nil
+}
+
+func (p *chatPage) togglePillsExpanded() tea.Cmd {
+	hasPills := hasIncompleteTodos(p.session.Todos) || p.promptQueue > 0
+	if !hasPills {
+		return nil
+	}
+	p.pillsExpanded = !p.pillsExpanded
+	if p.pillsExpanded {
+		if hasIncompleteTodos(p.session.Todos) {
+			p.focusedPillSection = PillSectionTodos
+		} else {
+			p.focusedPillSection = PillSectionQueue
+		}
 	}
+	return p.SetSize(p.width, p.height)
+}
+
+func (p *chatPage) switchPillSection(dir int) tea.Cmd {
+	if !p.pillsExpanded {
+		return nil
+	}
+	hasIncompleteTodos := hasIncompleteTodos(p.session.Todos)
+	hasQueue := p.promptQueue > 0
+
+	if dir < 0 && p.focusedPillSection == PillSectionQueue && hasIncompleteTodos {
+		p.focusedPillSection = PillSectionTodos
+		return p.SetSize(p.width, p.height)
+	}
+	if dir > 0 && p.focusedPillSection == PillSectionTodos && hasQueue {
+		p.focusedPillSection = PillSectionQueue
+		return p.SetSize(p.width, p.height)
+	}
+	return nil
 }
 
 func (p *chatPage) cancel() tea.Cmd {
@@ -1005,18 +1196,34 @@ func (p *chatPage) Help() help.KeyMap {
 		globalBindings := []key.Binding{}
 		// we are in a session
 		if p.session.ID != "" {
-			tabKey := key.NewBinding(
-				key.WithKeys("tab"),
-				key.WithHelp("tab", "focus chat"),
-			)
-			if p.focusedPane == PanelTypeChat {
+			var tabKey key.Binding
+			switch p.focusedPane {
+			case PanelTypeEditor:
+				tabKey = key.NewBinding(
+					key.WithKeys("tab"),
+					key.WithHelp("tab", "focus chat"),
+				)
+			case PanelTypeChat:
 				tabKey = key.NewBinding(
 					key.WithKeys("tab"),
 					key.WithHelp("tab", "focus editor"),
 				)
+			default:
+				tabKey = key.NewBinding(
+					key.WithKeys("tab"),
+					key.WithHelp("tab", "focus chat"),
+				)
 			}
 			shortList = append(shortList, tabKey)
 			globalBindings = append(globalBindings, tabKey)
+
+			// Show left/right to switch sections when expanded and both exist
+			hasTodos := hasIncompleteTodos(p.session.Todos)
+			hasQueue := p.promptQueue > 0
+			if p.pillsExpanded && hasTodos && hasQueue {
+				shortList = append(shortList, p.keyMap.PillLeft)
+				globalBindings = append(globalBindings, p.keyMap.PillLeft)
+			}
 		}
 		commandsBinding := key.NewBinding(
 			key.WithKeys("ctrl+p"),
@@ -1207,3 +1414,12 @@ func (p *chatPage) isMouseOverChat(x, y int) bool {
 	// Check if mouse coordinates are within chat bounds
 	return x >= chatX && x < chatX+chatWidth && y >= chatY && y < chatY+chatHeight
 }
+
+func (p *chatPage) hasInProgressTodo() bool {
+	for _, todo := range p.session.Todos {
+		if todo.Status == session.TodoStatusInProgress {
+			return true
+		}
+	}
+	return false
+}

internal/tui/page/chat/keys.go 🔗

@@ -10,6 +10,9 @@ type KeyMap struct {
 	Cancel        key.Binding
 	Tab           key.Binding
 	Details       key.Binding
+	TogglePills   key.Binding
+	PillLeft      key.Binding
+	PillRight     key.Binding
 }
 
 func DefaultKeyMap() KeyMap {
@@ -34,5 +37,17 @@ func DefaultKeyMap() KeyMap {
 			key.WithKeys("ctrl+d"),
 			key.WithHelp("ctrl+d", "toggle details"),
 		),
+		TogglePills: key.NewBinding(
+			key.WithKeys("ctrl+space"),
+			key.WithHelp("ctrl+space", "toggle tasks"),
+		),
+		PillLeft: key.NewBinding(
+			key.WithKeys("left"),
+			key.WithHelp("←/→", "switch section"),
+		),
+		PillRight: key.NewBinding(
+			key.WithKeys("right"),
+			key.WithHelp("←/→", "switch section"),
+		),
 	}
 }

internal/tui/page/chat/pills.go 🔗

@@ -0,0 +1,125 @@
+package chat
+
+import (
+	"fmt"
+	"strings"
+
+	"charm.land/lipgloss/v2"
+	"github.com/charmbracelet/crush/internal/session"
+	"github.com/charmbracelet/crush/internal/tui/components/chat/todos"
+	"github.com/charmbracelet/crush/internal/tui/styles"
+)
+
+func hasIncompleteTodos(todos []session.Todo) bool {
+	for _, todo := range todos {
+		if todo.Status != session.TodoStatusCompleted {
+			return true
+		}
+	}
+	return false
+}
+
+const (
+	pillHeightWithBorder  = 3
+	maxTaskDisplayLength  = 40
+	maxQueueDisplayLength = 60
+)
+
+func queuePill(queue int, focused, pillsPanelFocused bool, t *styles.Theme) string {
+	if queue <= 0 {
+		return ""
+	}
+	triangles := styles.ForegroundGrad("▶▶▶▶▶▶▶▶▶", false, t.RedDark, t.Accent)
+	if queue < 10 {
+		triangles = triangles[:queue]
+	}
+
+	content := fmt.Sprintf("%s %d Queued", strings.Join(triangles, ""), queue)
+
+	style := t.S().Base.PaddingLeft(1).PaddingRight(1)
+	if !pillsPanelFocused || focused {
+		style = style.BorderStyle(lipgloss.RoundedBorder()).BorderForeground(t.BgOverlay)
+	} else {
+		style = style.BorderStyle(lipgloss.HiddenBorder())
+	}
+	return style.Render(content)
+}
+
+func todoPill(todos []session.Todo, spinnerView string, focused, pillsPanelFocused bool, t *styles.Theme) string {
+	if !hasIncompleteTodos(todos) {
+		return ""
+	}
+
+	completed := 0
+	var currentTodo *session.Todo
+	for i := range todos {
+		switch todos[i].Status {
+		case session.TodoStatusCompleted:
+			completed++
+		case session.TodoStatusInProgress:
+			if currentTodo == nil {
+				currentTodo = &todos[i]
+			}
+		}
+	}
+
+	total := len(todos)
+
+	label := "To-Do"
+	progress := t.S().Base.Foreground(t.FgMuted).Render(fmt.Sprintf("%d/%d", completed, total))
+
+	var content string
+	if pillsPanelFocused {
+		content = fmt.Sprintf("%s %s", label, progress)
+	} else if currentTodo != nil {
+		taskText := currentTodo.Content
+		if currentTodo.ActiveForm != "" {
+			taskText = currentTodo.ActiveForm
+		}
+		if len(taskText) > maxTaskDisplayLength {
+			taskText = taskText[:maxTaskDisplayLength-1] + "…"
+		}
+		task := t.S().Base.Foreground(t.FgSubtle).Render(taskText)
+		content = fmt.Sprintf("%s %s %s  %s", spinnerView, label, progress, task)
+	} else {
+		content = fmt.Sprintf("%s %s", label, progress)
+	}
+
+	style := t.S().Base.PaddingLeft(1).PaddingRight(1)
+	if !pillsPanelFocused || focused {
+		style = style.BorderStyle(lipgloss.RoundedBorder()).BorderForeground(t.BgOverlay)
+	} else {
+		style = style.BorderStyle(lipgloss.HiddenBorder())
+	}
+	return style.Render(content)
+}
+
+func todoList(sessionTodos []session.Todo, spinnerView string, t *styles.Theme, width int) string {
+	return todos.FormatTodosList(sessionTodos, spinnerView, t, width)
+}
+
+func queueList(queueItems []string, t *styles.Theme) string {
+	if len(queueItems) == 0 {
+		return ""
+	}
+
+	var lines []string
+	for _, item := range queueItems {
+		text := item
+		if len(text) > maxQueueDisplayLength {
+			text = text[:maxQueueDisplayLength-1] + "…"
+		}
+		prefix := t.S().Base.Foreground(t.FgMuted).Render("  •") + " "
+		lines = append(lines, prefix+t.S().Base.Foreground(t.FgMuted).Render(text))
+	}
+
+	return strings.Join(lines, "\n")
+}
+
+func sectionLine(availableWidth int, t *styles.Theme) string {
+	if availableWidth <= 0 {
+		return ""
+	}
+	line := strings.Repeat("─", availableWidth)
+	return t.S().Base.Foreground(t.Border).Render(line)
+}

internal/tui/styles/icons.go 🔗

@@ -1,15 +1,17 @@
 package styles
 
 const (
-	CheckIcon    string = "✓"
-	ErrorIcon    string = "×"
-	WarningIcon  string = "⚠"
-	InfoIcon     string = "ⓘ"
-	HintIcon     string = "∵"
-	SpinnerIcon  string = "..."
-	LoadingIcon  string = "⟳"
-	DocumentIcon string = "🖼"
-	ModelIcon    string = "◇"
+	CheckIcon         string = "✓"
+	ErrorIcon         string = "×"
+	WarningIcon       string = "⚠"
+	InfoIcon          string = "ⓘ"
+	HintIcon          string = "∵"
+	SpinnerIcon       string = "..."
+	ArrowRightIcon    string = "→"
+	CenterSpinnerIcon string = "⋯"
+	LoadingIcon       string = "⟳"
+	DocumentIcon      string = "🖼"
+	ModelIcon         string = "◇"
 
 	// Tool call icons
 	ToolPending string = "●"
@@ -18,6 +20,10 @@ const (
 
 	BorderThin  string = "│"
 	BorderThick string = "▌"
+
+	// Todo icons
+	TodoCompletedIcon string = "✓"
+	TodoPendingIcon   string = "•"
 )
 
 var SelectionIgnoreIcons = []string{