Merge branch 'main' into ui

Ayman Bagabas created

Change summary

.github/cla-signatures.json                                                        |  16 
.github/workflows/nightly.yml                                                      |   2 
.github/workflows/schema-update.yml                                                |   2 
go.mod                                                                             |  16 
go.sum                                                                             |  29 
internal/agent/agent.go                                                            | 159 
internal/agent/agentic_fetch_tool.go                                               |  56 
internal/agent/errors.go                                                           |   9 
internal/agent/templates/agentic_fetch.md                                          |  59 
internal/agent/templates/agentic_fetch_prompt.md.tpl                               |  51 
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            |  32 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/glob_tool.yaml             |  25 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/grep_tool.yaml             |  22 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/ls_tool.yaml               |  25 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/multiedit_tool.yaml        |  26 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/parallel_tool_calls.yaml   |  26 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/read_a_file.yaml           |  16 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/simple_test.yaml           |  18 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/sourcegraph_tool.yaml      |  23 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/update_a_file.yaml         |  22 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/write_tool.yaml            |  20 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/bash_tool.yaml                 |  32 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/download_tool.yaml             |  24 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/fetch_tool.yaml                |  30 
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            |  34 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/parallel_tool_calls.yaml       |  24 
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          |  34 
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           |   6 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/download_tool.yaml       |  26 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/fetch_tool.yaml          |   2 
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             |   3 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/multiedit_tool.yaml      |  36 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/parallel_tool_calls.yaml |  26 
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       |  26 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/write_tool.yaml          |  36 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/bash_tool.yaml                   |  18 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/download_tool.yaml               |  20 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/fetch_tool.yaml                  |  22 
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                 |   3 
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/diagnostics.go                                                |   2 
internal/agent/tools/fetch_helpers.go                                              |  90 
internal/agent/tools/fetch_types.go                                                |  15 
internal/agent/tools/mcp-tools.go                                                  |  22 
internal/agent/tools/mcp/init.go                                                   |  31 
internal/agent/tools/mcp/tools.go                                                  |  73 
internal/agent/tools/multiedit.go                                                  |  21 
internal/agent/tools/search.go                                                     | 183 
internal/agent/tools/tools.go                                                      |  35 
internal/agent/tools/view.go                                                       |  34 
internal/agent/tools/view.md                                                       |   7 
internal/agent/tools/web_search.go                                                 |  51 
internal/agent/tools/web_search.md                                                 |  18 
internal/app/app.go                                                                |  35 
internal/app/lsp.go                                                                |   8 
internal/tui/components/chat/messages/messages.go                                  |  15 
internal/tui/components/chat/messages/renderer.go                                  | 123 
internal/tui/components/chat/messages/tool.go                                      |  14 
internal/tui/components/dialogs/permissions/permissions.go                         |   9 
internal/tui/components/image/load.go                                              |  23 
internal/tui/exp/list/filterable.go                                                |  14 
internal/tui/page/chat/chat.go                                                     |  13 
84 files changed, 1,616 insertions(+), 780 deletions(-)

Detailed changes

.github/cla-signatures.json 🔗

@@ -919,6 +919,22 @@
       "created_at": "2025-12-05T15:51:04Z",
       "repoId": 987670088,
       "pullRequestNo": 1555
+    },
+    {
+      "name": "mikluko",
+      "id": 42915,
+      "comment_id": 3620605876,
+      "created_at": "2025-12-06T15:43:45Z",
+      "repoId": 987670088,
+      "pullRequestNo": 1558
+    },
+    {
+      "name": "Gustave-241021",
+      "id": 185743951,
+      "comment_id": 3620851967,
+      "created_at": "2025-12-06T18:13:11Z",
+      "repoId": 987670088,
+      "pullRequestNo": 1560
     }
   ]
 }

.github/workflows/nightly.yml 🔗

@@ -11,7 +11,7 @@ jobs:
     outputs:
       should_run: ${{ steps.check.outputs.should_run }}
     steps:
-      - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
         with:
           fetch-depth: 1
       - id: check

.github/workflows/schema-update.yml 🔗

@@ -10,7 +10,7 @@ jobs:
   update-schema:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
         with:
           token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
       - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0

go.mod 🔗

@@ -5,7 +5,7 @@ go 1.25.0
 require (
 	charm.land/bubbles/v2 v2.0.0-rc.1
 	charm.land/bubbletea/v2 v2.0.0-rc.2.0.20251202162339-5fa38b798f16
-	charm.land/fantasy v0.4.0
+	charm.land/fantasy v0.5.1
 	charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251119143523-0334bb4562ca
 	charm.land/x/vcr v0.1.1
 	github.com/JohannesKaufmann/html-to-markdown v1.6.0
@@ -16,7 +16,7 @@ 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.4
+	github.com/charmbracelet/catwalk v0.9.5
 	github.com/charmbracelet/colorprofile v0.3.3
 	github.com/charmbracelet/fang v0.4.4
 	github.com/charmbracelet/glamour/v2 v2.0.0-20251106195642-800eb8175930
@@ -37,7 +37,7 @@ require (
 	github.com/lucasb-eyer/go-colorful v1.3.0
 	github.com/modelcontextprotocol/go-sdk v1.1.0
 	github.com/muesli/termenv v0.16.0
-	github.com/ncruces/go-sqlite3 v0.30.2
+	github.com/ncruces/go-sqlite3 v0.30.3
 	github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
 	github.com/nxadm/tail v1.4.11
 	github.com/openai/openai-go/v2 v2.7.1
@@ -48,13 +48,14 @@ require (
 	github.com/rivo/uniseg v0.4.7
 	github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
 	github.com/sahilm/fuzzy v0.1.1
-	github.com/spf13/cobra v1.10.1
+	github.com/spf13/cobra v1.10.2
 	github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c
 	github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef
 	github.com/stretchr/testify v1.11.1
 	github.com/tidwall/sjson v1.2.5
 	github.com/zeebo/xxh3 v1.0.2
 	golang.org/x/mod v0.30.0
+	golang.org/x/net v0.47.0
 	golang.org/x/sync v0.18.0
 	golang.org/x/text v0.31.0
 	gopkg.in/natefinch/lumberjack.v2 v2.2.1
@@ -71,7 +72,7 @@ require (
 	github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
 	github.com/RealAlexandreAI/json-repair v0.0.14 // indirect
 	github.com/andybalholm/cascadia v1.3.3 // indirect
-	github.com/aws/aws-sdk-go-v2 v1.40.0 // indirect
+	github.com/aws/aws-sdk-go-v2 v1.40.1 // indirect
 	github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect
 	github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect
 	github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect
@@ -84,7 +85,7 @@ require (
 	github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 // indirect
 	github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect
 	github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect
-	github.com/aws/smithy-go v1.23.2 // indirect
+	github.com/aws/smithy-go v1.24.0 // indirect
 	github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
 	github.com/aymerick/douceur v0.2.0 // indirect
 	github.com/bahlo/generic-list-go v0.2.0 // indirect
@@ -164,13 +165,12 @@ require (
 	golang.org/x/crypto v0.45.0 // indirect
 	golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
 	golang.org/x/image v0.27.0 // indirect
-	golang.org/x/net v0.47.0 // indirect
 	golang.org/x/oauth2 v0.33.0 // indirect
 	golang.org/x/sys v0.38.0 // indirect
 	golang.org/x/term v0.37.0 // indirect
 	golang.org/x/time v0.12.0 // indirect
 	google.golang.org/api v0.239.0 // indirect
-	google.golang.org/genai v1.36.0 // indirect
+	google.golang.org/genai v1.37.0 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
 	google.golang.org/grpc v1.74.2 // indirect
 	google.golang.org/protobuf v1.36.10 // indirect

go.sum 🔗

@@ -2,8 +2,8 @@ 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.20251202162339-5fa38b798f16 h1:9iVAss7WF8Ax5QBzmZE77aA08JbOMuDpbEhl/Uvc3Eo=
 charm.land/bubbletea/v2 v2.0.0-rc.2.0.20251202162339-5fa38b798f16/go.mod h1:Vsh7/MLC7LQ2Ab8H63SXm6yD/L6o4HDvhdD/IrIRXrU=
-charm.land/fantasy v0.4.0 h1:q2Yy3uu5Fh8GMZXO12zemuOMQt1czd3NO0OwVqfzcdg=
-charm.land/fantasy v0.4.0/go.mod h1:mGwXNfKUyRm+npj1LLr2mQZorkc8rgVOGWAV/l0fqMk=
+charm.land/fantasy v0.5.1 h1:Svi/UpI4/DwVjTqNYceDXoJJYn6SVEM5dnLH92UBiEs=
+charm.land/fantasy v0.5.1/go.mod h1:SPOsnIlkBKnhw2Wnasv+wZ82EmCMIGesx0je3tgR6+M=
 charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251119143523-0334bb4562ca h1:6bVc8OFotCS4sS7HKqxTudP7yn8Y0ODR6df2pdlY/+s=
 charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251119143523-0334bb4562ca/go.mod h1:XSJjv7DaH4zd1Y27kZis295RkEj9OFR9zh2WffQQsKQ=
 charm.land/x/vcr v0.1.1 h1:PXCFMUG0rPtyk35rhfzYCJEduOzWXCIbrXTFq4OF/9Q=
@@ -44,8 +44,8 @@ github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kk
 github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
 github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
 github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
-github.com/aws/aws-sdk-go-v2 v1.40.0 h1:/WMUA0kjhZExjOQN2z3oLALDREea1A7TobfuiBrKlwc=
-github.com/aws/aws-sdk-go-v2 v1.40.0/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE=
+github.com/aws/aws-sdk-go-v2 v1.40.1 h1:difXb4maDZkRH0x//Qkwcfpdg1XQVXEAEs2DdXldFFc=
+github.com/aws/aws-sdk-go-v2 v1.40.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
 github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg=
 github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3/go.mod h1:UbnqO+zjqk3uIt9yCACHJ9IVNhyhOCnYk8yA19SAWrM=
 github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90=
@@ -70,8 +70,8 @@ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrA
 github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw=
 github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE=
 github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ=
-github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM=
-github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
+github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
+github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
 github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
 github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
 github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY=
@@ -88,8 +88,8 @@ 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.4 h1:et3nP3p1jfJbQE9UiN9vzfojsihgtQp2r9tvn8qEL28=
-github.com/charmbracelet/catwalk v0.9.4/go.mod h1:ReU4SdrLfe63jkEjWMdX2wlZMV3k9r11oQAmzN0m+KY=
+github.com/charmbracelet/catwalk v0.9.5 h1:QLqajLJfjGTVh2MIVIdAhww2XvPklxmu+p0Z4wrT7KU=
+github.com/charmbracelet/catwalk v0.9.5/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/fang v0.4.4 h1:G4qKxF6or/eTPgmAolwPuRNyuci3hTUGGX1rj1YkHJY=
@@ -246,8 +246,8 @@ github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8=
 github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig=
 github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
 github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
-github.com/ncruces/go-sqlite3 v0.30.2 h1:1GVbHAkKAOwjJd3JYl8ldrYROudfZUOah7oXPD7VZbQ=
-github.com/ncruces/go-sqlite3 v0.30.2/go.mod h1:AxKu9sRxkludimFocbktlY6LiYSkxiI5gTA8r+os/Nw=
+github.com/ncruces/go-sqlite3 v0.30.3 h1:X/CgWW9GzmIAkEPrifhKqf0cC15DuOVxAJaHFTTAURQ=
+github.com/ncruces/go-sqlite3 v0.30.3/go.mod h1:AxKu9sRxkludimFocbktlY6LiYSkxiI5gTA8r+os/Nw=
 github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
 github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
 github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
@@ -294,8 +294,8 @@ github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah
 github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas=
 github.com/sourcegraph/jsonrpc2 v0.2.1 h1:2GtljixMQYUYCmIg7W9aF2dFmniq/mOr2T9tFRh6zSQ=
 github.com/sourcegraph/jsonrpc2 v0.2.1/go.mod h1:ZafdZgk/axhT1cvZAPOhw+95nz2I/Ra5qMlU4gTRwIo=
-github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
-github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
+github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
+github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
 github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
 github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE=
@@ -358,6 +358,7 @@ go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mx
 go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
 go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
 go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
+go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
 go.yaml.in/yaml/v4 v4.0.0-rc.3 h1:3h1fjsh1CTAPjW7q/EMe+C8shx5d8ctzZTrLcs/j8Go=
 go.yaml.in/yaml/v4 v4.0.0-rc.3/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -459,8 +460,8 @@ golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/api v0.239.0 h1:2hZKUnFZEy81eugPs4e2XzIJ5SOwQg0G82bpXD65Puo=
 google.golang.org/api v0.239.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
-google.golang.org/genai v1.36.0 h1:sJCIjqTAmwrtAIaemtTiKkg2TO1RxnYEusTmEQ3nGxM=
-google.golang.org/genai v1.36.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk=
+google.golang.org/genai v1.37.0 h1:dgp71k1wQ+/+APdZrN3LFgAGnVnr5IdTF1Oj0Dg+BQc=
+google.golang.org/genai v1.37.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
 google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=

internal/agent/agent.go 🔗

@@ -11,6 +11,7 @@ import (
 	"cmp"
 	"context"
 	_ "embed"
+	"encoding/base64"
 	"errors"
 	"fmt"
 	"log/slog"
@@ -204,10 +205,8 @@ func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy
 		PresencePenalty:  call.PresencePenalty,
 		TopK:             call.TopK,
 		FrequencyPenalty: call.FrequencyPenalty,
-		// Before each step create a new assistant message.
 		PrepareStep: func(callContext context.Context, options fantasy.PrepareStepFunctionOptions) (_ context.Context, prepared fantasy.PrepareStepResult, err error) {
 			prepared.Messages = options.Messages
-			// Reset all cached items.
 			for i := range prepared.Messages {
 				prepared.Messages[i].ProviderOptions = nil
 			}
@@ -222,6 +221,8 @@ func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy
 				prepared.Messages = append(prepared.Messages, userMessage.ToAIMessage()...)
 			}
 
+			prepared.Messages = a.workaroundProviderMediaLimitations(prepared.Messages)
+
 			lastSystemRoleInx := 0
 			systemMessageUpdated := false
 			for i, msg := range prepared.Messages {
@@ -253,6 +254,8 @@ func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy
 				return callContext, prepared, err
 			}
 			callContext = context.WithValue(callContext, tools.MessageIDContextKey, assistantMsg.ID)
+			callContext = context.WithValue(callContext, tools.SupportsImagesContextKey, a.largeModel.CatwalkCfg.SupportsImages)
+			callContext = context.WithValue(callContext, tools.ModelNameContextKey, a.largeModel.CatwalkCfg.Name)
 			currentAssistant = &assistantMsg
 			return callContext, prepared, err
 		},
@@ -320,40 +323,14 @@ func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy
 			return a.messages.Update(genCtx, *currentAssistant)
 		},
 		OnToolResult: func(result fantasy.ToolResultContent) error {
-			var resultContent string
-			isError := false
-			switch result.Result.GetType() {
-			case fantasy.ToolResultContentTypeText:
-				r, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentText](result.Result)
-				if ok {
-					resultContent = r.Text
-				}
-			case fantasy.ToolResultContentTypeError:
-				r, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentError](result.Result)
-				if ok {
-					isError = true
-					resultContent = r.Error.Error()
-				}
-			case fantasy.ToolResultContentTypeMedia:
-				// TODO: handle this message type
-			}
-			toolResult := message.ToolResult{
-				ToolCallID: result.ToolCallID,
-				Name:       result.ToolName,
-				Content:    resultContent,
-				IsError:    isError,
-				Metadata:   result.ClientMetadata,
-			}
+			toolResult := a.convertToToolResult(result)
 			_, createMsgErr := a.messages.Create(genCtx, currentAssistant.SessionID, message.CreateMessageParams{
 				Role: message.Tool,
 				Parts: []message.ContentPart{
 					toolResult,
 				},
 			})
-			if createMsgErr != nil {
-				return createMsgErr
-			}
-			return nil
+			return createMsgErr
 		},
 		OnStepFinish: func(stepResult fantasy.StepResult) error {
 			finishReason := message.FinishReasonUnknown
@@ -899,3 +876,125 @@ func (a *sessionAgent) isClaudeCode() bool {
 	pc, ok := cfg.Providers.Get(a.largeModel.ModelCfg.Provider)
 	return ok && pc.ID == string(catwalk.InferenceProviderAnthropic) && pc.OAuthToken != nil
 }
+
+// convertToToolResult converts a fantasy tool result to a message tool result.
+func (a *sessionAgent) convertToToolResult(result fantasy.ToolResultContent) message.ToolResult {
+	baseResult := message.ToolResult{
+		ToolCallID: result.ToolCallID,
+		Name:       result.ToolName,
+		Metadata:   result.ClientMetadata,
+	}
+
+	switch result.Result.GetType() {
+	case fantasy.ToolResultContentTypeText:
+		if r, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentText](result.Result); ok {
+			baseResult.Content = r.Text
+		}
+	case fantasy.ToolResultContentTypeError:
+		if r, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentError](result.Result); ok {
+			baseResult.Content = r.Error.Error()
+			baseResult.IsError = true
+		}
+	case fantasy.ToolResultContentTypeMedia:
+		if r, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentMedia](result.Result); ok {
+			content := r.Text
+			if content == "" {
+				content = fmt.Sprintf("Loaded %s content", r.MediaType)
+			}
+			baseResult.Content = content
+			baseResult.Data = r.Data
+			baseResult.MIMEType = r.MediaType
+		}
+	}
+
+	return baseResult
+}
+
+// workaroundProviderMediaLimitations converts media content in tool results to
+// user messages for providers that don't natively support images in tool results.
+//
+// Problem: OpenAI, Google, OpenRouter, and other OpenAI-compatible providers
+// don't support sending images/media in tool result messages - they only accept
+// text in tool results. However, they DO support images in user messages.
+//
+// If we send media in tool results to these providers, the API returns an error.
+//
+// Solution: For these providers, we:
+//  1. Replace the media in the tool result with a text placeholder
+//  2. Inject a user message immediately after with the image as a file attachment
+//  3. This maintains the tool execution flow while working around API limitations
+//
+// Anthropic and Bedrock support images natively in tool results, so we skip
+// this workaround for them.
+//
+// Example transformation:
+//
+//	BEFORE: [tool result: image data]
+//	AFTER:  [tool result: "Image loaded - see attached"], [user: image attachment]
+func (a *sessionAgent) workaroundProviderMediaLimitations(messages []fantasy.Message) []fantasy.Message {
+	providerSupportsMedia := a.largeModel.ModelCfg.Provider == string(catwalk.InferenceProviderAnthropic) ||
+		a.largeModel.ModelCfg.Provider == string(catwalk.InferenceProviderBedrock)
+
+	if providerSupportsMedia {
+		return messages
+	}
+
+	convertedMessages := make([]fantasy.Message, 0, len(messages))
+
+	for _, msg := range messages {
+		if msg.Role != fantasy.MessageRoleTool {
+			convertedMessages = append(convertedMessages, msg)
+			continue
+		}
+
+		textParts := make([]fantasy.MessagePart, 0, len(msg.Content))
+		var mediaFiles []fantasy.FilePart
+
+		for _, part := range msg.Content {
+			toolResult, ok := fantasy.AsMessagePart[fantasy.ToolResultPart](part)
+			if !ok {
+				textParts = append(textParts, part)
+				continue
+			}
+
+			if media, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentMedia](toolResult.Output); ok {
+				decoded, err := base64.StdEncoding.DecodeString(media.Data)
+				if err != nil {
+					slog.Warn("failed to decode media data", "error", err)
+					textParts = append(textParts, part)
+					continue
+				}
+
+				mediaFiles = append(mediaFiles, fantasy.FilePart{
+					Data:      decoded,
+					MediaType: media.MediaType,
+					Filename:  fmt.Sprintf("tool-result-%s", toolResult.ToolCallID),
+				})
+
+				textParts = append(textParts, fantasy.ToolResultPart{
+					ToolCallID: toolResult.ToolCallID,
+					Output: fantasy.ToolResultOutputContentText{
+						Text: "[Image/media content loaded - see attached file]",
+					},
+					ProviderOptions: toolResult.ProviderOptions,
+				})
+			} else {
+				textParts = append(textParts, part)
+			}
+		}
+
+		convertedMessages = append(convertedMessages, fantasy.Message{
+			Role:    fantasy.MessageRoleTool,
+			Content: textParts,
+		})
+
+		if len(mediaFiles) > 0 {
+			convertedMessages = append(convertedMessages, fantasy.NewUserMessage(
+				"Here is the media content from the tool result:",
+				mediaFiles...,
+			))
+		}
+	}
+
+	return convertedMessages
+}

internal/agent/agentic_fetch_tool.go 🔗

@@ -27,10 +27,6 @@ type agenticFetchValidationResult struct {
 
 // validateAgenticFetchParams validates the tool call parameters and extracts required context values.
 func validateAgenticFetchParams(ctx context.Context, params tools.AgenticFetchParams) (agenticFetchValidationResult, error) {
-	if params.URL == "" {
-		return agenticFetchValidationResult{}, errors.New("url is required")
-	}
-
 	if params.Prompt == "" {
 		return agenticFetchValidationResult{}, errors.New("prompt is required")
 	}
@@ -75,6 +71,14 @@ func (c *coordinator) agenticFetchTool(_ context.Context, client *http.Client) (
 				return fantasy.NewTextErrorResponse(err.Error()), nil
 			}
 
+			// Determine description based on mode.
+			var description string
+			if params.URL != "" {
+				description = fmt.Sprintf("Fetch and analyze content from URL: %s", params.URL)
+			} else {
+				description = "Search the web and analyze results"
+			}
+
 			p := c.permissions.Request(
 				permission.CreatePermissionRequest{
 					SessionID:   validationResult.SessionID,
@@ -82,7 +86,7 @@ func (c *coordinator) agenticFetchTool(_ context.Context, client *http.Client) (
 					ToolCallID:  call.ID,
 					ToolName:    tools.AgenticFetchToolName,
 					Action:      "fetch",
-					Description: fmt.Sprintf("Fetch and analyze content from URL: %s", params.URL),
+					Description: description,
 					Params:      tools.AgenticFetchPermissionsParams(params),
 				},
 			)
@@ -91,36 +95,43 @@ func (c *coordinator) agenticFetchTool(_ context.Context, client *http.Client) (
 				return fantasy.ToolResponse{}, permission.ErrorPermissionDenied
 			}
 
-			content, err := tools.FetchURLAndConvert(ctx, client, params.URL)
-			if err != nil {
-				return fantasy.NewTextErrorResponse(fmt.Sprintf("Failed to fetch URL: %s", err)), nil
-			}
-
 			tmpDir, err := os.MkdirTemp(c.cfg.Options.DataDirectory, "crush-fetch-*")
 			if err != nil {
 				return fantasy.NewTextErrorResponse(fmt.Sprintf("Failed to create temporary directory: %s", err)), nil
 			}
 			defer os.RemoveAll(tmpDir)
 
-			hasLargeContent := len(content) > tools.LargeContentThreshold
 			var fullPrompt string
 
-			if hasLargeContent {
-				tempFile, err := os.CreateTemp(tmpDir, "page-*.md")
+			if params.URL != "" {
+				// URL mode: fetch the URL content first.
+				content, err := tools.FetchURLAndConvert(ctx, client, params.URL)
 				if err != nil {
-					return fantasy.NewTextErrorResponse(fmt.Sprintf("Failed to create temporary file: %s", err)), nil
+					return fantasy.NewTextErrorResponse(fmt.Sprintf("Failed to fetch URL: %s", err)), nil
 				}
-				tempFilePath := tempFile.Name()
 
-				if _, err := tempFile.WriteString(content); err != nil {
+				hasLargeContent := len(content) > tools.LargeContentThreshold
+
+				if hasLargeContent {
+					tempFile, err := os.CreateTemp(tmpDir, "page-*.md")
+					if err != nil {
+						return fantasy.NewTextErrorResponse(fmt.Sprintf("Failed to create temporary file: %s", err)), nil
+					}
+					tempFilePath := tempFile.Name()
+
+					if _, err := tempFile.WriteString(content); err != nil {
+						tempFile.Close()
+						return fantasy.NewTextErrorResponse(fmt.Sprintf("Failed to write content to file: %s", err)), nil
+					}
 					tempFile.Close()
-					return fantasy.NewTextErrorResponse(fmt.Sprintf("Failed to write content to file: %s", err)), nil
-				}
-				tempFile.Close()
 
-				fullPrompt = fmt.Sprintf("%s\n\nThe web page from %s has been saved to: %s\n\nUse the view and grep tools to analyze this file and extract the requested information.", params.Prompt, params.URL, tempFilePath)
+					fullPrompt = fmt.Sprintf("%s\n\nThe web page from %s has been saved to: %s\n\nUse the view and grep tools to analyze this file and extract the requested information.", params.Prompt, params.URL, tempFilePath)
+				} else {
+					fullPrompt = fmt.Sprintf("%s\n\nWeb page URL: %s\n\n<webpage_content>\n%s\n</webpage_content>", params.Prompt, params.URL, content)
+				}
 			} else {
-				fullPrompt = fmt.Sprintf("%s\n\nWeb page URL: %s\n\n<webpage_content>\n%s\n</webpage_content>", params.Prompt, params.URL, content)
+				// Search mode: let the sub-agent search and fetch as needed.
+				fullPrompt = fmt.Sprintf("%s\n\nUse the web_search tool to find relevant information. Break down the question into smaller, focused searches if needed. After searching, use web_fetch to get detailed content from the most relevant results.", params.Prompt)
 			}
 
 			promptOpts := []prompt.Option{
@@ -148,10 +159,13 @@ func (c *coordinator) agenticFetchTool(_ context.Context, client *http.Client) (
 			}
 
 			webFetchTool := tools.NewWebFetchTool(tmpDir, client)
+			webSearchTool := tools.NewWebSearchTool(client)
 			fetchTools := []fantasy.AgentTool{
 				webFetchTool,
+				webSearchTool,
 				tools.NewGlobTool(tmpDir),
 				tools.NewGrepTool(tmpDir),
+				tools.NewSourcegraphTool(client),
 				tools.NewViewTool(c.lspClients, c.permissions, tmpDir),
 			}
 

internal/agent/errors.go 🔗

@@ -1,9 +1,6 @@
 package agent
 
-import (
-	"context"
-	"errors"
-)
+import "errors"
 
 var (
 	ErrRequestCancelled = errors.New("request canceled by user")
@@ -11,7 +8,3 @@ var (
 	ErrEmptyPrompt      = errors.New("prompt is empty")
 	ErrSessionMissing   = errors.New("session id is missing")
 )
-
-func isCancelledErr(err error) bool {
-	return errors.Is(err, context.Canceled) || errors.Is(err, ErrRequestCancelled)
-}

internal/agent/templates/agentic_fetch.md 🔗

@@ -1,12 +1,12 @@
-Fetches content from a specified URL and processes it using an AI model to extract information or answer questions.
+Fetches content from a URL or searches the web, then processes it using an AI model to extract information or answer questions.
 
 <when_to_use>
 Use this tool when you need to:
-- Extract specific information from a webpage (e.g., "get pricing info")
-- Answer questions about web content (e.g., "what does this article say about X?")
+- Search the web for information (omit the url parameter)
+- Extract specific information from a webpage (provide a url)
+- Answer questions about web content
 - Summarize or analyze web pages
-- Find specific data within large pages
-- Interpret or process web content with AI
+- Research topics by searching and following links
 
 DO NOT use this tool when:
 - You just need raw content without analysis (use fetch instead - faster and cheaper)
@@ -15,37 +15,50 @@ DO NOT use this tool when:
 </when_to_use>
 
 <usage>
-- Takes a URL and a prompt as input
-- Fetches the URL content, converts HTML to markdown
-- Processes the content with the prompt using a small, fast model
-- Returns the model's response about the content
-- Use this tool when you need to retrieve and analyze web content
+- Provide a prompt describing what information you want to find or extract (required)
+- Optionally provide a URL to fetch and analyze specific content
+- If no URL is provided, the agent will search the web to find relevant information
+- The tool spawns a sub-agent with web_search, web_fetch, and analysis tools
+- Returns the agent's response about the content
 </usage>
 
-<usage_notes>
+<parameters>
+- prompt: What information you want to find or extract (required)
+- url: The URL to fetch content from (optional - if not provided, agent will search the web)
+</parameters>
 
+<usage_notes>
 - IMPORTANT: If an MCP-provided web fetch tool is available, prefer using that tool instead of this one, as it may have fewer restrictions. All MCP-provided tools start with "mcp_".
-- The URL must be a fully-formed valid URL
-- HTTP URLs will be automatically upgraded to HTTPS
-- The prompt should describe what information you want to extract from the page
-- This tool is read-only and does not modify any files
-- Results will be summarized if the content is very large
-- For very large pages, the content will be saved to a temporary file and the agent will have access to grep/view tools to analyze it
-- When a URL redirects to a different host, the tool will inform you and provide the redirect URL. You should then make a new fetch request with the redirect URL to fetch the content.
-- This tool uses AI processing and costs more tokens than the simple fetch tool
-  </usage_notes>
+- When using URL mode: The URL must be a fully-formed valid URL. HTTP URLs will be automatically upgraded to HTTPS.
+- When searching: Just provide the prompt describing what you want to find - the agent will search and fetch relevant pages.
+- The sub-agent can perform multiple searches and fetch multiple pages to gather comprehensive information.
+- This tool is read-only and does not modify any files.
+- Results will be summarized if the content is very large.
+- This tool uses AI processing and costs more tokens than the simple fetch tool.
+</usage_notes>
 
 <limitations>
-- Max response size: 5MB
+- Max response size: 5MB per page
 - Only supports HTTP and HTTPS protocols
 - Cannot handle authentication or cookies
 - Some websites may block automated requests
 - Uses additional tokens for AI processing
+- Search results depend on DuckDuckGo availability
 </limitations>
 
 <tips>
-- Be specific in your prompt about what information you want to extract
+- Be specific in your prompt about what information you want
+- For research tasks, omit the URL and let the agent search and follow relevant links
 - For complex pages, ask the agent to focus on specific sections
-- The agent has access to grep and view tools when analyzing large pages
+- The agent has access to web_search, web_fetch, grep, and view tools
 - If you just need raw content, use the fetch tool instead to save tokens
 </tips>
+
+<examples>
+Search for information:
+- prompt: "What are the main new features in the latest Python release?"
+
+Fetch and analyze a URL:
+- url: "https://docs.python.org/3/whatsnew/3.12.html"
+- prompt: "Summarize the key changes in Python 3.12"
+</examples>

internal/agent/templates/agentic_fetch_prompt.md.tpl 🔗

@@ -1,18 +1,38 @@
-You are a web content analysis agent for Crush. Your task is to analyze web page content and extract the information requested by the user.
+You are a web content analysis agent for Crush. Your task is to analyze web content, search results, or web pages to extract the information requested by the user.
 
 <rules>
-1. You should be concise and direct in your responses
+1. Be concise and direct in your responses
 2. Focus only on the information requested in the user's prompt
 3. If the content is provided in a file path, use the grep and view tools to efficiently search through it
-4. When relevant, quote specific sections from the page to support your answer
+4. When relevant, quote specific sections from the content to support your answer
 5. If the requested information is not found, clearly state that
 6. Any file paths you use MUST be absolute
-7. **IMPORTANT**: If you need information from a linked page to answer the question, use the web_fetch tool to follow that link
-8. After fetching a link, analyze the content yourself to extract what's needed
-9. Don't hesitate to follow multiple links if necessary to get complete information
-10. **CRITICAL**: At the end of your response, include a "Sources" section listing ALL URLs that were useful in answering the question
+7. **IMPORTANT**: If you need information from a linked page or search result, use the web_fetch tool to get that content
+8. **IMPORTANT**: If you need to search for more information, use the web_search tool
+9. After fetching a link, analyze the content yourself to extract what's needed
+10. Don't hesitate to follow multiple links or perform multiple searches if necessary to get complete information
+11. **CRITICAL**: At the end of your response, include a "Sources" section listing ALL URLs that were useful in answering the question
 </rules>
 
+<search_strategy>
+When searching for information:
+
+1. **Break down complex questions** - If the user's question has multiple parts, search for each part separately
+2. **Use specific, targeted queries** - Prefer multiple small searches over one broad search
+   - Bad: "Python 3.12 new features performance improvements async changes"
+   - Good: First "Python 3.12 new features", then "Python 3.12 performance improvements", then "Python 3.12 async changes"
+3. **Iterate and refine** - If initial results aren't helpful, try different search terms or more specific queries
+4. **Search for different aspects** - For comprehensive answers, search for different angles of the topic
+5. **Follow up on promising results** - When you find a good source, fetch it and look for links to related information
+
+Example workflow for "What are the pros and cons of using Rust vs Go for web services?":
+- Search 1: "Rust web services advantages"
+- Search 2: "Go web services advantages"
+- Search 3: "Rust vs Go performance comparison"
+- Search 4: "Rust vs Go developer experience"
+- Then fetch the most relevant results from each search
+</search_strategy>
+
 <response_format>
 Your response should be structured as follows:
 
@@ -24,7 +44,7 @@ Your response should be structured as follows:
 - [URL 3 that was useful]
 ...
 
-Only include URLs that actually contributed information to your answer. The main URL is always included. Add any additional URLs you fetched that provided relevant information.
+Only include URLs that actually contributed information to your answer. Include the main URL or search results that were helpful. Add any additional URLs you fetched that provided relevant information.
 </response_format>
 
 <env>
@@ -33,9 +53,20 @@ Platform: {{.Platform}}
 Today's date: {{.Date}}
 </env>
 
+<web_search_tool>
+You have access to a web_search tool that allows you to search the web:
+- Provide a search query and optionally max_results (default: 10)
+- The tool returns search results with titles, URLs, and snippets
+- After getting search results, use web_fetch to get full content from relevant URLs
+- **Prefer multiple focused searches over single broad searches**
+- Keep queries short and specific (3-6 words is often ideal)
+- If results aren't relevant, try rephrasing with different keywords
+- Don't be afraid to do 3-5+ searches to thoroughly answer a complex question
+</web_search_tool>
+
 <web_fetch_tool>
-You have access to a web_fetch tool that allows you to fetch additional web pages:
-- Use it when you need to follow links from the current page
+You have access to a web_fetch tool that allows you to fetch web pages:
+- Use it when you need to follow links from search results or the current page
 - Provide just the URL (no prompt parameter)
 - The tool will fetch and return the content (or save to a file if large)
 - YOU must then analyze that content to answer the user's question

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

@@ -25,52 +25,55 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01EVjRPtXckEg8o8Yvn7agqP","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"}}     }
+      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"}}       }
 
       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":"Bash File"}   }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Create"}            }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Creation"} }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Bash"}     }
 
       event: ping
       data: {"type": "ping"}
 
       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":" File"}               }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Hello"}              }
+      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":" Message"}     }
+      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"}   }
 
       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: 685.304458ms
+    duration: 578.171791ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51300
+    content_length: 51454
     host: ""

internal/agent/testdata/TestCoderAgent/anthropic-sonnet/download_tool.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_01Pic6S9YBCaoX3zxshFpwQy","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_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"}}         }
 
       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 Example"}               }
 
       event: ping
       data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" File from"}       }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Given"}   }
+      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":" URL"}    }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" File"}             }
 
       event: content_block_stop
       data: {"type":"content_block_stop","index":0       }
 
       event: message_delta
-      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":160,"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":160,"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: 511.539167ms
+    duration: 501.558292ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51325
+    content_length: 51479
     host: ""

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

@@ -25,58 +25,46 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01Ds8FsARNrw2dstATwh6ffe","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_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"}}    }
 
       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"}      }
 
       event: ping
       data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Search"}   }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" for"}          }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Name"}             }
-
-      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"}}
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Content Check"}  }
 
       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":11}        }
+      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}}
 
       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: 551.193ms
+    duration: 771.713375ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51343
+    content_length: 51497
     host: ""

internal/agent/testdata/TestCoderAgent/anthropic-sonnet/glob_tool.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_01MqD4XtY2L8ZLAktkRQxoJY","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_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"}}              }
 
       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":"Fin"}}
 
       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":" Files"}           }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Files Using"}        }
 
       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":" Glob"}  }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Glob"}             }
 
       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":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: 625.632958ms
+    duration: 590.110084ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51261
+    content_length: 51415
     host: ""

internal/agent/testdata/TestCoderAgent/anthropic-sonnet/grep_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_012d9z357hq8o7FexFbhvKSZ","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":4,"service_tier":"standard"}}}
+      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"}}   }
 
       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 for "}       }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Grep"}   }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"'package' in Go"}  }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" "}  }
 
       event: ping
       data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" files with"}}
+      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":" grep"}           }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Files"}               }
 
       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":15}  }
+      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}  }
 
       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: 524.120125ms
+    duration: 499.278667ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51259
+    content_length: 51413
     host: ""

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

@@ -25,31 +25,28 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01DVab3iiGDnPNnULDQhzY71","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":3,"service_tier":"standard"}}             }
+      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"}}             }
 
       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":"Listing Files"}       }
+      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":" in Current Directory"}             }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Files"}}
 
       event: ping
       data: {"type": "ping"}
 
-      event: content_block_stop
-      data: {"type":"content_block_stop","index":0               }
-
-      event: ping
-      data: {"type": "ping"}
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" in Current Directory"}           }
 
-      event: ping
-      data: {"type": "ping"}
+      event: content_block_stop
+      data: {"type":"content_block_stop","index":0              }
 
       event: message_delta
-      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":140,"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":140,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":8}      }
 
       event: message_stop
       data: {"type":"message_stop"}
@@ -59,15 +56,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 573.010667ms
+    duration: 576.743583ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51253
+    content_length: 51407
     host: ""

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

@@ -25,49 +25,55 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_019yUAeaWYLfDspRWMnKiGuE","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"}}}
+      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"}}               }
 
       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":"Edit"}       }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Modify"}          }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" 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":" Program"}         }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" code greeting"}            }
 
       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":" 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"}               }
 
       event: content_block_stop
       data: {"type":"content_block_stop","index":0       }
 
       event: message_delta
-      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":170,"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":170,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":12}       }
 
       event: message_stop
-      data: {"type":"message_stop"            }
+      data: {"type":"message_stop"}
 
     headers:
       Content-Type:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 484.884292ms
+    duration: 626.47275ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51339
+    content_length: 51493
     host: ""

internal/agent/testdata/TestCoderAgent/anthropic-sonnet/parallel_tool_calls.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_01H7snK8RBDfgYzyE21txgqF","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_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"}}            }
 
       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 file"}           }
+      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":" and directory listing"}              }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" File"}         }
+
+      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"}               }
 
       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":10}          }
+      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}    }
 
       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: 630.2585ms
+    duration: 585.640291ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51350
+    content_length: 51504
     host: ""

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

@@ -25,13 +25,13 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01NFzWcYPQ8noTqfq5LotH3a","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_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"}}  }
 
       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"}       }
@@ -40,10 +40,10 @@ interactions:
       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":" Details"}         }
 
       event: content_block_stop
       data: {"type":"content_block_stop","index":0 }
@@ -52,22 +52,22 @@ interactions:
       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: 574.917208ms
+    duration: 655.510125ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51223
+    content_length: 51377
     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_01FUVJPcax9JwJYovTpykB8W","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_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"}}     }
 
       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":" Hello"}          }
+      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,25 +49,25 @@ 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":5}          }
+      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" }
+      data: {"type":"message_stop"             }
 
     headers:
       Content-Type:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 592.833625ms
+    duration: 808.120542ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51213
+    content_length: 51367
     host: ""

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

@@ -25,46 +25,49 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01TzNt7N2xCqujhq73UrL2TC","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_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"}} }
 
       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 Main"}             }
+      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":" Functions with"}   }
+      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":" Sourcegraph"}      }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" for Main"}       }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Functions"}           }
 
       event: content_block_stop
-      data: {"type":"content_block_stop","index":0   }
+      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":12}      }
+      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: 655.598416ms
+    duration: 966.588833ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51273
+    content_length: 51427
     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_01QvCQEZTwSzm6ArsDvybN6B","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_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"}}               }
 
       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":" Message"}               }
+      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: 638.412875ms
+    duration: 575.783417ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51279
+    content_length: 51433
     host: ""

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

@@ -25,13 +25,13 @@ interactions:
     content_length: -1
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01STFeYffS4q4ZsMUo3RRGro","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":161,"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_01JiVSoTmsmdUjG7LXaAnYWL","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":161,"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":"Create"}          }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Create"}     }
 
       event: content_block_delta
       data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" config"}         }
@@ -40,34 +40,34 @@ interactions:
       data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":".json file with JSON"}           }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":".json file with JSON"}       }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" content"}    }
+      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":161,"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":161,"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: 647.593208ms
+    duration: 542.582666ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51316
+    content_length: 51470
     host: ""

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

@@ -24,29 +24,33 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj534Wsmb0qdA9mWKjp4j4Rsa4YYs","object":"chat.completion.chunk","created":1764860202,"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":"TAZTeZWvVxFxoP"}
+      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-Cj534Wsmb0qdA9mWKjp4j4Rsa4YYs","object":"chat.completion.chunk","created":1764860202,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"B"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"hBXa3fagEUrE6jJ"}
+      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-Cj534Wsmb0qdA9mWKjp4j4Rsa4YYs","object":"chat.completion.chunk","created":1764860202,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"ash"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"CyeAiu8IZPzB0"}
+      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-Cj534Wsmb0qdA9mWKjp4j4Rsa4YYs","object":"chat.completion.chunk","created":1764860202,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Script"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"EmTjbMCg4"}
+      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-Cj534Wsmb0qdA9mWKjp4j4Rsa4YYs","object":"chat.completion.chunk","created":1764860202,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Y4BDCQdK7Xopv"}
+      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-Cj534Wsmb0qdA9mWKjp4j4Rsa4YYs","object":"chat.completion.chunk","created":1764860202,"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":"XOJ5bw0lw"}
+      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-Cj534Wsmb0qdA9mWKjp4j4Rsa4YYs","object":"chat.completion.chunk","created":1764860202,"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":"n01VQF4aJD8"}
+      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-Cj534Wsmb0qdA9mWKjp4j4Rsa4YYs","object":"chat.completion.chunk","created":1764860202,"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":"22IrDPSm0Ers"}
+      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-Cj534Wsmb0qdA9mWKjp4j4Rsa4YYs","object":"chat.completion.chunk","created":1764860202,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Without"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Au1AtNtb"}
+      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-Cj534Wsmb0qdA9mWKjp4j4Rsa4YYs","object":"chat.completion.chunk","created":1764860202,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Timestamp"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"hh8A8H"}
+      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-Cj534Wsmb0qdA9mWKjp4j4Rsa4YYs","object":"chat.completion.chunk","created":1764860202,"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":"HywMesJLaN"}
+      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-Cj534Wsmb0qdA9mWKjp4j4Rsa4YYs","object":"chat.completion.chunk","created":1764860202,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[],"usage":{"prompt_tokens":145,"completion_tokens":9,"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":"CQS50HbFC5kJkY"}
+      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-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-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: [DONE]
 
@@ -55,15 +59,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 547.9735ms
+    duration: 491.401209ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49695
+    content_length: 49849
     host: ""

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

@@ -24,25 +24,23 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj53LQQE8myVYt6Og68Q2Tmvnq8Zq","object":"chat.completion.chunk","created":1764860219,"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":"4aWeZdas5ga0vS"}
+      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-Cj53LQQE8myVYt6Og68Q2Tmvnq8Zq","object":"chat.completion.chunk","created":1764860219,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":"Download"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"wwN4WDqz"}
+      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-Cj53LQQE8myVYt6Og68Q2Tmvnq8Zq","object":"chat.completion.chunk","created":1764860219,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"0VDcB7AJsv3f"}
+      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-Cj53LQQE8myVYt6Og68Q2Tmvnq8Zq","object":"chat.completion.chunk","created":1764860219,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":" Save"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"D5NVweYuVWX"}
+      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-Cj53LQQE8myVYt6Og68Q2Tmvnq8Zq","object":"chat.completion.chunk","created":1764860219,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"qpjVng08xNJ"}
+      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-Cj53LQQE8myVYt6Og68Q2Tmvnq8Zq","object":"chat.completion.chunk","created":1764860219,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":" as"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"UcOYSptrSwzlx"}
+      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-Cj53LQQE8myVYt6Og68Q2Tmvnq8Zq","object":"chat.completion.chunk","created":1764860219,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":" example"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"0QcVctY0"}
+      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-Cj53LQQE8myVYt6Og68Q2Tmvnq8Zq","object":"chat.completion.chunk","created":1764860219,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[{"index":0,"delta":{"content":".txt"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"gsMzdjWfyCqD"}
+      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-Cj53LQQE8myVYt6Og68Q2Tmvnq8Zq","object":"chat.completion.chunk","created":1764860219,"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":"k3z2McnDZS"}
-
-      data: {"id":"chatcmpl-Cj53LQQE8myVYt6Og68Q2Tmvnq8Zq","object":"chat.completion.chunk","created":1764860219,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_37d212baff","choices":[],"usage":{"prompt_tokens":148,"completion_tokens":7,"total_tokens":155,"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":"QYATZ2rRRCxY4h"}
+      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: [DONE]
 
@@ -51,15 +49,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 441.057958ms
+    duration: 460.945041ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49720
+    content_length: 49874
     host: ""

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

@@ -24,31 +24,27 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj53ZjAPs86JEZ45lsxkFbsekRzmi","object":"chat.completion.chunk","created":1764860233,"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":"p3FAuIIvP40AGt"}
+      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-Cj53ZjAPs86JEZ45lsxkFbsekRzmi","object":"chat.completion.chunk","created":1764860233,"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":"2zQiK028cyC"}
+      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-Cj53ZjAPs86JEZ45lsxkFbsekRzmi","object":"chat.completion.chunk","created":1764860233,"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":"t5Dbze6JVcMf"}
+      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-Cj53ZjAPs86JEZ45lsxkFbsekRzmi","object":"chat.completion.chunk","created":1764860233,"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":"g2LVvR5jOQrSTB"}
+      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-Cj53ZjAPs86JEZ45lsxkFbsekRzmi","object":"chat.completion.chunk","created":1764860233,"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":"73pY8mr75Ipx"}
+      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-Cj53ZjAPs86JEZ45lsxkFbsekRzmi","object":"chat.completion.chunk","created":1764860233,"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":"Rh33jjTIQNbP"}
+      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-Cj53ZjAPs86JEZ45lsxkFbsekRzmi","object":"chat.completion.chunk","created":1764860233,"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":"yBuIcpDXjMRzZYt"}
+      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-Cj53ZjAPs86JEZ45lsxkFbsekRzmi","object":"chat.completion.chunk","created":1764860233,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"kbl7tT4umVvzN"}
+      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-Cj53ZjAPs86JEZ45lsxkFbsekRzmi","object":"chat.completion.chunk","created":1764860233,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" Example"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"26Eisxv6"}
+      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-Cj53ZjAPs86JEZ45lsxkFbsekRzmi","object":"chat.completion.chunk","created":1764860233,"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":"O4w8wnvRwzz"}
+      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-Cj53ZjAPs86JEZ45lsxkFbsekRzmi","object":"chat.completion.chunk","created":1764860233,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"36EHMtRPOzO"}
-
-      data: {"id":"chatcmpl-Cj53ZjAPs86JEZ45lsxkFbsekRzmi","object":"chat.completion.chunk","created":1764860233,"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":"7EQ3yGAlPi"}
-
-      data: {"id":"chatcmpl-Cj53ZjAPs86JEZ45lsxkFbsekRzmi","object":"chat.completion.chunk","created":1764860233,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[],"usage":{"prompt_tokens":153,"completion_tokens":10,"total_tokens":163,"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":"tHxxBcUGppg3r"}
+      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: [DONE]
 
@@ -57,15 +53,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 473.407583ms
+    duration: 725.754042ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49738
+    content_length: 49892
     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-Cj53hbJEtQwnfdnCtZAQrC5jzHLJq","object":"chat.completion.chunk","created":1764860241,"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":"ZXeRi6jk2tQYT7"}
+      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-Cj53hbJEtQwnfdnCtZAQrC5jzHLJq","object":"chat.completion.chunk","created":1764860241,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"Finding"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"QMosZk0Hk"}
+      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-Cj53hbJEtQwnfdnCtZAQrC5jzHLJq","object":"chat.completion.chunk","created":1764860241,"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":"RbdLJD1Zj0loPl"}
+      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-Cj53hbJEtQwnfdnCtZAQrC5jzHLJq","object":"chat.completion.chunk","created":1764860241,"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":"hUuIQPuKdkJ2tT"}
+      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-Cj53hbJEtQwnfdnCtZAQrC5jzHLJq","object":"chat.completion.chunk","created":1764860241,"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":"jylp97Zx5U"}
+      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-Cj53hbJEtQwnfdnCtZAQrC5jzHLJq","object":"chat.completion.chunk","created":1764860241,"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":"HKJBsQFUCjg"}
+      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-Cj53hbJEtQwnfdnCtZAQrC5jzHLJq","object":"chat.completion.chunk","created":1764860241,"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":"YtLEKIcQm5l"}
+      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-Cj53hbJEtQwnfdnCtZAQrC5jzHLJq","object":"chat.completion.chunk","created":1764860241,"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":"iZBNzPvTo0jxu"}
+      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-Cj53hbJEtQwnfdnCtZAQrC5jzHLJq","object":"chat.completion.chunk","created":1764860241,"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":"KOgh1lds"}
+      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-Cj53hbJEtQwnfdnCtZAQrC5jzHLJq","object":"chat.completion.chunk","created":1764860241,"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":"S5QHgt"}
+      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-Cj53hbJEtQwnfdnCtZAQrC5jzHLJq","object":"chat.completion.chunk","created":1764860241,"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":"DLenypXNtD"}
+      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-Cj53hbJEtQwnfdnCtZAQrC5jzHLJq","object":"chat.completion.chunk","created":1764860241,"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":"LF5oCHHqFEhI0Q"}
+      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: [DONE]
 
@@ -55,15 +55,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 440.474708ms
+    duration: 391.2975ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49656
+    content_length: 49810
     host: ""

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

@@ -24,29 +24,31 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj53mSmwVnxGtZofUwSXFCPFNSxhC","object":"chat.completion.chunk","created":1764860246,"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":"8ENL2KwAOKWm2P"}
+      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-Cj53mSmwVnxGtZofUwSXFCPFNSxhC","object":"chat.completion.chunk","created":1764860246,"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":"nXP26Dv"}
+      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-Cj53mSmwVnxGtZofUwSXFCPFNSxhC","object":"chat.completion.chunk","created":1764860246,"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":"mrtPrnqaJAogN3"}
+      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-Cj53mSmwVnxGtZofUwSXFCPFNSxhC","object":"chat.completion.chunk","created":1764860246,"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":"D8O8HF4Iw"}
+      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-Cj53mSmwVnxGtZofUwSXFCPFNSxhC","object":"chat.completion.chunk","created":1764860246,"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":"m5rTAX5RQKwNEDn"}
+      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-Cj53mSmwVnxGtZofUwSXFCPFNSxhC","object":"chat.completion.chunk","created":1764860246,"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":"nHVnJ6Pugdy8G"}
+      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-Cj53mSmwVnxGtZofUwSXFCPFNSxhC","object":"chat.completion.chunk","created":1764860246,"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":"2uMzwVuOLlNEE"}
+      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-Cj53mSmwVnxGtZofUwSXFCPFNSxhC","object":"chat.completion.chunk","created":1764860246,"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":"I1BwV9nt8j"}
+      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-Cj53mSmwVnxGtZofUwSXFCPFNSxhC","object":"chat.completion.chunk","created":1764860246,"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":"f8BRRjoL8W"}
+      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-Cj53mSmwVnxGtZofUwSXFCPFNSxhC","object":"chat.completion.chunk","created":1764860246,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" grep"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"bFJsX6luiJ3"}
+      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-Cj53mSmwVnxGtZofUwSXFCPFNSxhC","object":"chat.completion.chunk","created":1764860246,"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":"Ll6LURzlOm"}
+      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-Cj53mSmwVnxGtZofUwSXFCPFNSxhC","object":"chat.completion.chunk","created":1764860246,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[],"usage":{"prompt_tokens":138,"completion_tokens":9,"total_tokens":147,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"dCwOnjbzR5Qg3M"}
+      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-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: [DONE]
 
@@ -55,15 +57,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 527.178125ms
+    duration: 408.414666ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49654
+    content_length: 49808
     host: ""

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

@@ -24,27 +24,27 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj53tDX93W5QLNUH1jJSamFv4ynJ0","object":"chat.completion.chunk","created":1764860253,"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":"TW4STb9WfcQek9"}
+      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-Cj53tDX93W5QLNUH1jJSamFv4ynJ0","object":"chat.completion.chunk","created":1764860253,"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":"aUmWLGHp2Bm"}
+      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-Cj53tDX93W5QLNUH1jJSamFv4ynJ0","object":"chat.completion.chunk","created":1764860253,"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":"T3KgkFusYBvWNU"}
+      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-Cj53tDX93W5QLNUH1jJSamFv4ynJ0","object":"chat.completion.chunk","created":1764860253,"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":"TlW97DPuD2hCZ3"}
+      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-Cj53tDX93W5QLNUH1jJSamFv4ynJ0","object":"chat.completion.chunk","created":1764860253,"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":"WZULsUKRTG7t9ff"}
+      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-Cj53tDX93W5QLNUH1jJSamFv4ynJ0","object":"chat.completion.chunk","created":1764860253,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"j7V92bM1wOZvs"}
+      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-Cj53tDX93W5QLNUH1jJSamFv4ynJ0","object":"chat.completion.chunk","created":1764860253,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" List"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"4wnO0foP5O9"}
+      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-Cj53tDX93W5QLNUH1jJSamFv4ynJ0","object":"chat.completion.chunk","created":1764860253,"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":"PZzUNS"}
+      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-Cj53tDX93W5QLNUH1jJSamFv4ynJ0","object":"chat.completion.chunk","created":1764860253,"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":"XvVmL40npE"}
+      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-Cj53tDX93W5QLNUH1jJSamFv4ynJ0","object":"chat.completion.chunk","created":1764860253,"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":"rTKwCg6iL8"}
+      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-Cj53tDX93W5QLNUH1jJSamFv4ynJ0","object":"chat.completion.chunk","created":1764860253,"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":"k7W4A9LOGIMzb3"}
+      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: [DONE]
 
@@ -53,15 +53,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 668.433542ms
+    duration: 498.928208ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49648
+    content_length: 49802
     host: ""

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

@@ -24,29 +24,35 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj53yeWKMaglUOpLcl7LleXTOVKQa","object":"chat.completion.chunk","created":1764860258,"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":"rdbCWgFFflV0nK"}
+      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-Cj53yeWKMaglUOpLcl7LleXTOVKQa","object":"chat.completion.chunk","created":1764860258,"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":"jHHKGN3xXyh6"}
+      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-Cj53yeWKMaglUOpLcl7LleXTOVKQa","object":"chat.completion.chunk","created":1764860258,"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":"y2bRDJK2Qy4"}
+      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-Cj53yeWKMaglUOpLcl7LleXTOVKQa","object":"chat.completion.chunk","created":1764860258,"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":"gh0erNeqd8TOY"}
+      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-Cj53yeWKMaglUOpLcl7LleXTOVKQa","object":"chat.completion.chunk","created":1764860258,"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":"aI0oZtT4R1VbQMR"}
+      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-Cj53yeWKMaglUOpLcl7LleXTOVKQa","object":"chat.completion.chunk","created":1764860258,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Change"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"7BXN6zwu4"}
+      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-Cj53yeWKMaglUOpLcl7LleXTOVKQa","object":"chat.completion.chunk","created":1764860258,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Message"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"bEsmlz4O"}
+      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-Cj53yeWKMaglUOpLcl7LleXTOVKQa","object":"chat.completion.chunk","created":1764860258,"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":"3snlOQd7wEti"}
+      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-Cj53yeWKMaglUOpLcl7LleXTOVKQa","object":"chat.completion.chunk","created":1764860258,"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":"OOU0Qs7kuDay"}
+      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-Cj53yeWKMaglUOpLcl7LleXTOVKQa","object":"chat.completion.chunk","created":1764860258,"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":"86gXokeu"}
+      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-Cj53yeWKMaglUOpLcl7LleXTOVKQa","object":"chat.completion.chunk","created":1764860258,"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":"olFaSH9ymG"}
+      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-Cj53yeWKMaglUOpLcl7LleXTOVKQa","object":"chat.completion.chunk","created":1764860258,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[],"usage":{"prompt_tokens":157,"completion_tokens":9,"total_tokens":166,"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":"XsHrQzfIXL0KsK"}
+      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-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-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-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: [DONE]
 
@@ -55,15 +61,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 589.191917ms
+    duration: 521.312875ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49734
+    content_length: 49888
     host: ""

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

@@ -24,25 +24,23 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj56QaweOhKN8xt2ehOSo1ppHg8mN","object":"chat.completion.chunk","created":1764860410,"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":"en71lxqxsv2hgF"}
+      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-Cj56QaweOhKN8xt2ehOSo1ppHg8mN","object":"chat.completion.chunk","created":1764860410,"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":"kYYTItfM"}
+      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-Cj56QaweOhKN8xt2ehOSo1ppHg8mN","object":"chat.completion.chunk","created":1764860410,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Execution"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"06T3zw"}
+      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-Cj56QaweOhKN8xt2ehOSo1ppHg8mN","object":"chat.completion.chunk","created":1764860410,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" of"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"2ulP9GZWdkI7b"}
+      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-Cj56QaweOhKN8xt2ehOSo1ppHg8mN","object":"chat.completion.chunk","created":1764860410,"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":"1xxXmgF94JF"}
+      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-Cj56QaweOhKN8xt2ehOSo1ppHg8mN","object":"chat.completion.chunk","created":1764860410,"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":"iubcqPaFJlOR"}
+      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-Cj56QaweOhKN8xt2ehOSo1ppHg8mN","object":"chat.completion.chunk","created":1764860410,"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":"ncbuO6HYbg9l2"}
+      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-Cj56QaweOhKN8xt2ehOSo1ppHg8mN","object":"chat.completion.chunk","created":1764860410,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Commands"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"8q7GfLq"}
+      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-Cj56QaweOhKN8xt2ehOSo1ppHg8mN","object":"chat.completion.chunk","created":1764860410,"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":"9PidwyIEv3"}
-
-      data: {"id":"chatcmpl-Cj56QaweOhKN8xt2ehOSo1ppHg8mN","object":"chat.completion.chunk","created":1764860410,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[],"usage":{"prompt_tokens":154,"completion_tokens":7,"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":"OykJ1M0K9hlmGC"}
+      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: [DONE]
 
@@ -51,15 +49,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 590.331542ms
+    duration: 390.648875ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49745
+    content_length: 49899
     host: ""

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

@@ -24,19 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj52hLwenYEpU1rz1YgdEneB92NSv","object":"chat.completion.chunk","created":1764860179,"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":"sg557YmnPCYToa"}
+      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-Cj52hLwenYEpU1rz1YgdEneB92NSv","object":"chat.completion.chunk","created":1764860179,"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":"CnV"}
+      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-Cj52hLwenYEpU1rz1YgdEneB92NSv","object":"chat.completion.chunk","created":1764860179,"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":"T5eYmBas7ArdI"}
+      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-Cj52hLwenYEpU1rz1YgdEneB92NSv","object":"chat.completion.chunk","created":1764860179,"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":"o1vgqEEdc"}
+      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-Cj52hLwenYEpU1rz1YgdEneB92NSv","object":"chat.completion.chunk","created":1764860179,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_e819e3438b","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"d9JYQg2CoN"}
+      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-Cj52hLwenYEpU1rz1YgdEneB92NSv","object":"chat.completion.chunk","created":1764860179,"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":"D7Vt1TxFsO"}
+      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-Cj52hLwenYEpU1rz1YgdEneB92NSv","object":"chat.completion.chunk","created":1764860179,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_e819e3438b","choices":[],"usage":{"prompt_tokens":129,"completion_tokens":4,"total_tokens":133,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"3vdJjCHn4KZa8P"}
+      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-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: [DONE]
 
@@ -45,15 +47,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 896.270958ms
+    duration: 435.350917ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49618
+    content_length: 49772
     host: ""

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

@@ -24,15 +24,13 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj52eQv000o2d2FsaPX9G1AUgNM1Z","object":"chat.completion.chunk","created":1764860176,"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":"FNyX50dDJ2igV0"}
+      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-Cj52eQv000o2d2FsaPX9G1AUgNM1Z","object":"chat.completion.chunk","created":1764860176,"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":"VNA3w0Nf"}
+      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-Cj52eQv000o2d2FsaPX9G1AUgNM1Z","object":"chat.completion.chunk","created":1764860176,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a4d13246c5","choices":[{"index":0,"delta":{"content":" Message"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"cZ3GHyvB"}
+      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-Cj52eQv000o2d2FsaPX9G1AUgNM1Z","object":"chat.completion.chunk","created":1764860176,"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":"VRCS3ZwSnL"}
-
-      data: {"id":"chatcmpl-Cj52eQv000o2d2FsaPX9G1AUgNM1Z","object":"chat.completion.chunk","created":1764860176,"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":"Z12k1kJzry5Mc3"}
+      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: [DONE]
 
@@ -41,15 +39,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 1.139960292s
+    duration: 1.042759084s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49608
+    content_length: 49762
     host: ""

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

@@ -24,35 +24,31 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj54SiDhwbm1JyeUaCZv372W8GeWR","object":"chat.completion.chunk","created":1764860288,"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":"FwIT7GcDhGfsWm"}
+      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-Cj54SiDhwbm1JyeUaCZv372W8GeWR","object":"chat.completion.chunk","created":1764860288,"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":"GP5VW04"}
+      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-Cj54SiDhwbm1JyeUaCZv372W8GeWR","object":"chat.completion.chunk","created":1764860288,"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":"2lnilml1wHI2Ki"}
+      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-Cj54SiDhwbm1JyeUaCZv372W8GeWR","object":"chat.completion.chunk","created":1764860288,"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":"hL3JLfrlvtqH"}
+      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-Cj54SiDhwbm1JyeUaCZv372W8GeWR","object":"chat.completion.chunk","created":1764860288,"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":"oxV2laCPWBR"}
+      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-Cj54SiDhwbm1JyeUaCZv372W8GeWR","object":"chat.completion.chunk","created":1764860288,"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":"IqpyU0lRgCoAHXs"}
+      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-Cj54SiDhwbm1JyeUaCZv372W8GeWR","object":"chat.completion.chunk","created":1764860288,"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":"MnazWvhAjJJP4"}
+      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-Cj54SiDhwbm1JyeUaCZv372W8GeWR","object":"chat.completion.chunk","created":1764860288,"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":"hmYkZli8CMxRX"}
+      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-Cj54SiDhwbm1JyeUaCZv372W8GeWR","object":"chat.completion.chunk","created":1764860288,"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":"5bvlgICSA2yz7"}
+      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-Cj54SiDhwbm1JyeUaCZv372W8GeWR","object":"chat.completion.chunk","created":1764860288,"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":"TZFoH6"}
+      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-Cj54SiDhwbm1JyeUaCZv372W8GeWR","object":"chat.completion.chunk","created":1764860288,"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":"wfCJPYmS5ZG"}
+      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-Cj54SiDhwbm1JyeUaCZv372W8GeWR","object":"chat.completion.chunk","created":1764860288,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Source"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"2h98aPtH1"}
+      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-Cj54SiDhwbm1JyeUaCZv372W8GeWR","object":"chat.completion.chunk","created":1764860288,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"graph"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"eNqG37bZBVO"}
-
-      data: {"id":"chatcmpl-Cj54SiDhwbm1JyeUaCZv372W8GeWR","object":"chat.completion.chunk","created":1764860288,"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":"1IM1DjdGd1"}
-
-      data: {"id":"chatcmpl-Cj54SiDhwbm1JyeUaCZv372W8GeWR","object":"chat.completion.chunk","created":1764860288,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[],"usage":{"prompt_tokens":138,"completion_tokens":12,"total_tokens":150,"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":"QId9tVVvmq9Oy"}
+      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: [DONE]
 
@@ -61,15 +57,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 702.195458ms
+    duration: 392.941917ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49668
+    content_length: 49822
     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-Cj52n4VMlKNW7EGkIbPmSQesUOOik","object":"chat.completion.chunk","created":1764860185,"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":"jnSvoeCULFRnhj"}
+      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-Cj52n4VMlKNW7EGkIbPmSQesUOOik","object":"chat.completion.chunk","created":1764860185,"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":"uXOZRc2qKz"}
+      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-Cj52n4VMlKNW7EGkIbPmSQesUOOik","object":"chat.completion.chunk","created":1764860185,"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":"nItVEjzPoDU"}
+      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-Cj52n4VMlKNW7EGkIbPmSQesUOOik","object":"chat.completion.chunk","created":1764860185,"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":"lyLnr9oGQaSEw"}
+      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-Cj52n4VMlKNW7EGkIbPmSQesUOOik","object":"chat.completion.chunk","created":1764860185,"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":"UYysqz5a9XBvI"}
+      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-Cj52n4VMlKNW7EGkIbPmSQesUOOik","object":"chat.completion.chunk","created":1764860185,"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":"AnNteEYj92"}
+      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-Cj52n4VMlKNW7EGkIbPmSQesUOOik","object":"chat.completion.chunk","created":1764860185,"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":"AltRzBMbqoi7i7"}
+      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-Cj52n4VMlKNW7EGkIbPmSQesUOOik","object":"chat.completion.chunk","created":1764860185,"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":"LikEhFp6Tid"}
+      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-Cj52n4VMlKNW7EGkIbPmSQesUOOik","object":"chat.completion.chunk","created":1764860185,"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":"KApBBXWRhC4"}
+      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-Cj52n4VMlKNW7EGkIbPmSQesUOOik","object":"chat.completion.chunk","created":1764860185,"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":"qHtFcOFWtP"}
+      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-Cj52n4VMlKNW7EGkIbPmSQesUOOik","object":"chat.completion.chunk","created":1764860185,"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":"r01R3jirRbsgssi"}
+      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-Cj52n4VMlKNW7EGkIbPmSQesUOOik","object":"chat.completion.chunk","created":1764860185,"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":"NncQw3AoFf"}
+      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-Cj52n4VMlKNW7EGkIbPmSQesUOOik","object":"chat.completion.chunk","created":1764860185,"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":"S327t5vBpGUSI"}
+      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: [DONE]
 
@@ -57,15 +57,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 380.115ms
+    duration: 736.477208ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49674
+    content_length: 49828
     host: ""

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

@@ -24,23 +24,27 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Cj567SdJJ6Y35usztT9T5n3BPi9IV","object":"chat.completion.chunk","created":1764860391,"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":"Ll4G39fplXyLa3"}
+      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-Cj567SdJJ6Y35usztT9T5n3BPi9IV","object":"chat.completion.chunk","created":1764860391,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":"Creating"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"LwKLUI4c"}
+      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-Cj567SdJJ6Y35usztT9T5n3BPi9IV","object":"chat.completion.chunk","created":1764860391,"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":"ieYAD0604"}
+      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-Cj567SdJJ6Y35usztT9T5n3BPi9IV","object":"chat.completion.chunk","created":1764860391,"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":"nzt1YriXO91"}
+      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-Cj567SdJJ6Y35usztT9T5n3BPi9IV","object":"chat.completion.chunk","created":1764860391,"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":"64PpynSdPwB"}
+      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-Cj567SdJJ6Y35usztT9T5n3BPi9IV","object":"chat.completion.chunk","created":1764860391,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Version"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"7Ln6yEWd"}
+      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-Cj567SdJJ6Y35usztT9T5n3BPi9IV","object":"chat.completion.chunk","created":1764860391,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","choices":[{"index":0,"delta":{"content":" Details"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"c29ykvWL"}
+      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-Cj567SdJJ6Y35usztT9T5n3BPi9IV","object":"chat.completion.chunk","created":1764860391,"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":"VHMkTQcvbL"}
+      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-Cj567SdJJ6Y35usztT9T5n3BPi9IV","object":"chat.completion.chunk","created":1764860391,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_689bad8e9a","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":"FMZwMj7NqHf5y9"}
+      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: [DONE]
 
@@ -49,15 +53,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 1.278842625s
+    duration: 553.310667ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49711
+    content_length: 49865
     host: ""

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

@@ -24,27 +24,25 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764860474-RQkeWP32sYgnPRNbmeA8","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860474,"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":"Download"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860474-RQkeWP32sYgnPRNbmeA8","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860474,"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":" and"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860474-RQkeWP32sYgnPRNbmeA8","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860474,"choices":[{"index":0,"delta":{"role":"assistant","content":" and"},"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-1764860474-RQkeWP32sYgnPRNbmeA8","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860474,"choices":[{"index":0,"delta":{"role":"assistant","content":" save"},"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-1764860474-RQkeWP32sYgnPRNbmeA8","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860474,"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":".txt"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860474-RQkeWP32sYgnPRNbmeA8","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860474,"choices":[{"index":0,"delta":{"role":"assistant","content":".txt"},"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-1764860474-RQkeWP32sYgnPRNbmeA8","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860474,"choices":[{"index":0,"delta":{"role":"assistant","content":" from"},"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-1764860474-RQkeWP32sYgnPRNbmeA8","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860474,"choices":[{"index":0,"delta":{"role":"assistant","content":" provided"},"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-1764860474-RQkeWP32sYgnPRNbmeA8","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860474,"choices":[{"index":0,"delta":{"role":"assistant","content":" link"},"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-1764860474-RQkeWP32sYgnPRNbmeA8","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860474,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
-
-      data: {"id":"gen-1764860474-RQkeWP32sYgnPRNbmeA8","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860474,"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.0000222,"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.000015,"upstream_inference_completions_cost":0.0000072},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      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: [DONE]
 
@@ -53,15 +51,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 659.271625ms
+    duration: 982.813875ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49832
+    content_length: 49986
     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-1764860501-aWUnryJd9D8qGKSo7gpD","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860501,"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":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860501-aWUnryJd9D8qGKSo7gpD","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860501,"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":"Find"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860501-aWUnryJd9D8qGKSo7gpD","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860501,"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":" all"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860501-aWUnryJd9D8qGKSo7gpD","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860501,"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":" ."},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860501-aWUnryJd9D8qGKSo7gpD","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860501,"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":"go"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860501-aWUnryJd9D8qGKSo7gpD","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860501,"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":" files"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860501-aWUnryJd9D8qGKSo7gpD","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860501,"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":" in"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860501-aWUnryJd9D8qGKSo7gpD","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860501,"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":" current"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860501-aWUnryJd9D8qGKSo7gpD","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860501,"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":" directory"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860501-aWUnryJd9D8qGKSo7gpD","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860501,"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":" using"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860501-aWUnryJd9D8qGKSo7gpD","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860501,"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":" glob"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860501-aWUnryJd9D8qGKSo7gpD","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860501,"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":"stop","native_finish_reason":"stop","logprobs":null}]}
 
-      data: {"id":"gen-1764860501-aWUnryJd9D8qGKSo7gpD","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860501,"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-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: [DONE]
 
@@ -57,15 +57,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 514.748625ms
+    duration: 418.074333ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49768
+    content_length: 49922
     host: ""

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

@@ -24,27 +24,27 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764860512-hch3EulzIe9JptTZ7Sr4","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860512,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"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":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860512-hch3EulzIe9JptTZ7Sr4","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860512,"choices":[{"index":0,"delta":{"role":"assistant","content":"Search"},"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":"Search"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860512-hch3EulzIe9JptTZ7Sr4","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860512,"choices":[{"index":0,"delta":{"role":"assistant","content":" for"},"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":" for"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860512-hch3EulzIe9JptTZ7Sr4","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860512,"choices":[{"index":0,"delta":{"role":"assistant","content":" package"},"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":" package"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860512-hch3EulzIe9JptTZ7Sr4","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860512,"choices":[{"index":0,"delta":{"role":"assistant","content":" in"},"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":" in"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860512-hch3EulzIe9JptTZ7Sr4","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860512,"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":" Go"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860512-hch3EulzIe9JptTZ7Sr4","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860512,"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":" files"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860512-hch3EulzIe9JptTZ7Sr4","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860512,"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":" using"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860512-hch3EulzIe9JptTZ7Sr4","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860512,"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":" grep"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860512-hch3EulzIe9JptTZ7Sr4","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860512,"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":"stop","native_finish_reason":"stop","logprobs":null}]}
 
-      data: {"id":"gen-1764860512-hch3EulzIe9JptTZ7Sr4","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860512,"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-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: [DONE]
 
@@ -53,15 +53,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 1.222643542s
+    duration: 937.9565ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49766
+    content_length: 49920
     host: ""

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

@@ -6,9 +6,9 @@ interactions:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 758
+    content_length: 49914
     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 ls to list the files in the current directory\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}'

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

@@ -24,37 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764860550-qwKwAdsbZP6NLTumPLXj","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860550,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"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}]}
 
-      data: {"id":"gen-1764860550-qwKwAdsbZP6NLTumPLXj","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860550,"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-1764860550-qwKwAdsbZP6NLTumPLXj","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860550,"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-1764860550-qwKwAdsbZP6NLTumPLXj","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860550,"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-1764860550-qwKwAdsbZP6NLTumPLXj","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860550,"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-1764860550-qwKwAdsbZP6NLTumPLXj","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860550,"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-1764860550-qwKwAdsbZP6NLTumPLXj","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860550,"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-1764860550-qwKwAdsbZP6NLTumPLXj","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860550,"choices":[{"index":0,"delta":{"role":"assistant","content":" greeting"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764860550-qwKwAdsbZP6NLTumPLXj","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860550,"choices":[{"index":0,"delta":{"role":"assistant","content":" and"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764860550-qwKwAdsbZP6NLTumPLXj","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860550,"choices":[{"index":0,"delta":{"role":"assistant","content":" add"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764860550-qwKwAdsbZP6NLTumPLXj","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860550,"choices":[{"index":0,"delta":{"role":"assistant","content":" comment"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764860550-qwKwAdsbZP6NLTumPLXj","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860550,"choices":[{"index":0,"delta":{"role":"assistant","content":" in"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764860550-qwKwAdsbZP6NLTumPLXj","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860550,"choices":[{"index":0,"delta":{"role":"assistant","content":" main"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764860550-qwKwAdsbZP6NLTumPLXj","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860550,"choices":[{"index":0,"delta":{"role":"assistant","content":".go"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764860550-qwKwAdsbZP6NLTumPLXj","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860550,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
-
-      data: {"id":"gen-1764860550-qwKwAdsbZP6NLTumPLXj","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860550,"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.0000314,"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.000016,"upstream_inference_completions_cost":0.0000154},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      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: [DONE]
 
@@ -63,15 +47,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 440.768084ms
+    duration: 547.476834ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49846
+    content_length: 50000
     host: ""

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

@@ -24,27 +24,23 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764861346-84GGRpYW82ojLwfwakO9","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764861346,"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-1764861346-84GGRpYW82ojLwfwakO9","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764861346,"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":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764861346-84GGRpYW82ojLwfwakO9","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764861346,"choices":[{"index":0,"delta":{"role":"assistant","content":" .go"},"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-1764861346-84GGRpYW82ojLwfwakO9","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764861346,"choices":[{"index":0,"delta":{"role":"assistant","content":" files"},"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-1764861346-84GGRpYW82ojLwfwakO9","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764861346,"choices":[{"index":0,"delta":{"role":"assistant","content":" 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":" list directory"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764861346-84GGRpYW82ojLwfwakO9","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764861346,"choices":[{"index":0,"delta":{"role":"assistant","content":" list"},"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-1764861346-84GGRpYW82ojLwfwakO9","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764861346,"choices":[{"index":0,"delta":{"role":"assistant","content":" 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":" parallel"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764861346-84GGRpYW82ojLwfwakO9","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764861346,"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":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
 
-      data: {"id":"gen-1764861346-84GGRpYW82ojLwfwakO9","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764861346,"choices":[{"index":0,"delta":{"role":"assistant","content":" parallel"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764861346-84GGRpYW82ojLwfwakO9","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764861346,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
-
-      data: {"id":"gen-1764861346-84GGRpYW82ojLwfwakO9","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764861346,"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.0000236,"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.0000156,"upstream_inference_completions_cost":0.000008},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      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: [DONE]
 
@@ -53,15 +49,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 787.066959ms
+    duration: 209.204917ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49857
+    content_length: 50011
     host: ""

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

@@ -24,15 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764860443-j9UaVrCmDKJ0A9f5GZzs","provider":"Novita","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860443,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":""}
+      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-1764860443-j9UaVrCmDKJ0A9f5GZzs","provider":"Novita","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860443,"choices":[{"index":0,"delta":{"role":"assistant","content":"Read"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":""}
+      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-1764860443-j9UaVrCmDKJ0A9f5GZzs","provider":"Novita","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860443,"choices":[{"index":0,"delta":{"role":"assistant","content":" the go mod"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":""}
+      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-1764860443-j9UaVrCmDKJ0A9f5GZzs","provider":"Novita","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860443,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}],"system_fingerprint":""}
+      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-1764860443-j9UaVrCmDKJ0A9f5GZzs","provider":"Novita","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860443,"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.000021,"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.0000162,"upstream_inference_completions_cost":0.0000048},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      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: [DONE]
 
@@ -41,15 +45,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 775.315459ms
+    duration: 834.326708ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49730
+    content_length: 49884
     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-1764860441-GMNHj2of9NQ3cXlu3CuH","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860441,"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":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860441-GMNHj2of9NQ3cXlu3CuH","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860441,"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":"Hello"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860441-GMNHj2of9NQ3cXlu3CuH","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860441,"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":"stop","native_finish_reason":"stop","logprobs":null}]}
 
-      data: {"id":"gen-1764860441-GMNHj2of9NQ3cXlu3CuH","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860441,"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-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: [DONE]
 
@@ -39,15 +39,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 690.760166ms
+    duration: 635.219458ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49720
+    content_length: 49874
     host: ""

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

@@ -24,19 +24,23 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764860570-F646zP90Bn5IvXdQ1YrY","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860570,"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-1764860570-F646zP90Bn5IvXdQ1YrY","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860570,"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":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860570-F646zP90Bn5IvXdQ1YrY","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860570,"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":"Search"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860570-F646zP90Bn5IvXdQ1YrY","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860570,"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":" for func"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860570-F646zP90Bn5IvXdQ1YrY","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860570,"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":" main in Go repositories"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860570-F646zP90Bn5IvXdQ1YrY","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860570,"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":" using Source"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860570-F646zP90Bn5IvXdQ1YrY","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860570,"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: {"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: [DONE]
 
@@ -45,15 +49,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 384.048083ms
+    duration: 252.042666ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49780
+    content_length: 49934
     host: ""

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

@@ -24,27 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764860445-Dmt3pqTmVAZMlkdQEQC1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860445,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      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-1764860445-Dmt3pqTmVAZMlkdQEQC1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860445,"choices":[{"index":0,"delta":{"role":"assistant","content":"Update"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      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-1764860445-Dmt3pqTmVAZMlkdQEQC1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860445,"choices":[{"index":0,"delta":{"role":"assistant","content":" main"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      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-1764860445-Dmt3pqTmVAZMlkdQEQC1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860445,"choices":[{"index":0,"delta":{"role":"assistant","content":".go"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      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-1764860445-Dmt3pqTmVAZMlkdQEQC1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860445,"choices":[{"index":0,"delta":{"role":"assistant","content":" to"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      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-1764860445-Dmt3pqTmVAZMlkdQEQC1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860445,"choices":[{"index":0,"delta":{"role":"assistant","content":" print"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      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-1764860445-Dmt3pqTmVAZMlkdQEQC1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860445,"choices":[{"index":0,"delta":{"role":"assistant","content":" hello"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764860445-Dmt3pqTmVAZMlkdQEQC1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860445,"choices":[{"index":0,"delta":{"role":"assistant","content":" from"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764860445-Dmt3pqTmVAZMlkdQEQC1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860445,"choices":[{"index":0,"delta":{"role":"assistant","content":" crush"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1764860445-Dmt3pqTmVAZMlkdQEQC1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860445,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
-
-      data: {"id":"gen-1764860445-Dmt3pqTmVAZMlkdQEQC1","provider":"Parasail","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860445,"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.000024,"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.0000141,"upstream_inference_completions_cost":0.0000099},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      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: [DONE]
 
@@ -53,15 +45,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 410.42625ms
+    duration: 564.753209ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49786
+    content_length: 49940
     host: ""

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

@@ -24,21 +24,37 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1764860585-301yZuEohfa4EcNFE5cu","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860585,"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":"Create"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860585-301yZuEohfa4EcNFE5cu","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860585,"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":" config"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860585-301yZuEohfa4EcNFE5cu","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860585,"choices":[{"index":0,"delta":{"role":"assistant","content":" config.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":".json"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860585-301yZuEohfa4EcNFE5cu","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860585,"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":" with"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860585-301yZuEohfa4EcNFE5cu","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860585,"choices":[{"index":0,"delta":{"role":"assistant","content":" test"},"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-1764860585-301yZuEohfa4EcNFE5cu","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860585,"choices":[{"index":0,"delta":{"role":"assistant","content":" data"},"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-1764860585-301yZuEohfa4EcNFE5cu","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860585,"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":" and"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
 
-      data: {"id":"gen-1764860585-301yZuEohfa4EcNFE5cu","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1764860585,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":155,"completion_tokens":7,"total_tokens":162,"cost":0.0000211,"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.0000056},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      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-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":"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: [DONE]
 
@@ -47,15 +63,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 1.211276584s
+    duration: 1.202398292s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49823
+    content_length: 49977
     host: ""

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

@@ -24,19 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20251204230343fd79eaea54ef4569","created":1764860623,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"20251204230343fd79eaea54ef4569","created":1764860623,"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":"Create"}}]}
 
-      data: {"id":"20251204230343fd79eaea54ef4569","created":1764860623,"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,"delta":{"role":"assistant","content":" file"}}]}
 
-      data: {"id":"20251204230343fd79eaea54ef4569","created":1764860623,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" file"}}]}
+      data: {"id":"2025120423410393d676a9732447b6","created":1764862863,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
 
-      data: {"id":"20251204230343fd79eaea54ef4569","created":1764860623,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" without"}}]}
+      data: {"id":"2025120423410393d676a9732447b6","created":1764862863,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" bash"}}]}
 
-      data: {"id":"20251204230343fd79eaea54ef4569","created":1764860623,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" timestamp"}}]}
+      data: {"id":"2025120423410393d676a9732447b6","created":1764862863,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" content"}}]}
 
-      data: {"id":"20251204230343fd79eaea54ef4569","created":1764860623,"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":"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: [DONE]
 
@@ -45,15 +45,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 946.089834ms
+    duration: 922.675792ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49684
+    content_length: 49838
     host: ""

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

@@ -24,17 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"202512042303475de998759ed148b9","created":1764860627,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"202512042303475de998759ed148b9","created":1764860627,"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":"Download"}}]}
 
-      data: {"id":"202512042303475de998759ed148b9","created":1764860627,"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,"delta":{"role":"assistant","content":" and"}}]}
 
-      data: {"id":"202512042303475de998759ed148b9","created":1764860627,"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":"202512042303475de998759ed148b9","created":1764860627,"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":"202512042303475de998759ed148b9","created":1764860627,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":143,"completion_tokens":8,"total_tokens":151,"prompt_tokens_details":{"cached_tokens":4}}}
+      data: {"id":"202512042341103a97970f105f4cdc","created":1764862870,"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":" 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: [DONE]
 
@@ -43,15 +47,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 919.008791ms
+    duration: 854.211792ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49709
+    content_length: 49863
     host: ""

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

@@ -24,23 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"202512042303517f424406d8ec4cc0","created":1764860631,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"20251204234115eb5d1cccaf564c17","created":1764862875,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"202512042303517f424406d8ec4cc0","created":1764860631,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Check"}}]}
+      data: {"id":"20251204234115eb5d1cccaf564c17","created":1764862875,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Check"}}]}
 
-      data: {"id":"202512042303517f424406d8ec4cc0","created":1764860631,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" HTML"}}]}
+      data: {"id":"20251204234115eb5d1cccaf564c17","created":1764862875,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" if"}}]}
 
-      data: {"id":"202512042303517f424406d8ec4cc0","created":1764860631,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" for"}}]}
+      data: {"id":"20251204234115eb5d1cccaf564c17","created":1764862875,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" HTML"}}]}
 
-      data: {"id":"202512042303517f424406d8ec4cc0","created":1764860631,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" '"}}]}
+      data: {"id":"20251204234115eb5d1cccaf564c17","created":1764862875,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" contains"}}]}
 
-      data: {"id":"202512042303517f424406d8ec4cc0","created":1764860631,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"John"}}]}
+      data: {"id":"20251204234115eb5d1cccaf564c17","created":1764862875,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" John"}}]}
 
-      data: {"id":"202512042303517f424406d8ec4cc0","created":1764860631,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Doe"}}]}
+      data: {"id":"20251204234115eb5d1cccaf564c17","created":1764862875,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Doe"}}]}
 
-      data: {"id":"202512042303517f424406d8ec4cc0","created":1764860631,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"'"}}]}
-
-      data: {"id":"202512042303517f424406d8ec4cc0","created":1764860631,"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":114}}}
+      data: {"id":"20251204234115eb5d1cccaf564c17","created":1764862875,"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":114}}}
 
       data: [DONE]
 
@@ -49,15 +47,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 946.023291ms
+    duration: 1.056403084s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49727
+    content_length: 49881
     host: ""

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

@@ -24,19 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20251204230357fe9efc8f55384994","created":1764860637,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"20251204230357fe9efc8f55384994","created":1764860637,"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":"Find"}}]}
 
-      data: {"id":"20251204230357fe9efc8f55384994","created":1764860637,"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":" Go"}}]}
 
-      data: {"id":"20251204230357fe9efc8f55384994","created":1764860637,"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":" files"}}]}
 
-      data: {"id":"20251204230357fe9efc8f55384994","created":1764860637,"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":" with"}}]}
 
-      data: {"id":"20251204230357fe9efc8f55384994","created":1764860637,"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,"delta":{"role":"assistant","content":" glob"}}]}
 
-      data: {"id":"20251204230357fe9efc8f55384994","created":1764860637,"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":"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: [DONE]
 
@@ -45,15 +45,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.985502666s
+    duration: 1.252965458s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49645
+    content_length: 49799
     host: ""

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

@@ -24,17 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"202512042304045f5077f67feb41c7","created":1764860644,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"202512042304045f5077f67feb41c7","created":1764860644,"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":"grep"}}]}
 
-      data: {"id":"202512042304045f5077f67feb41c7","created":1764860644,"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":" package"}}]}
 
-      data: {"id":"202512042304045f5077f67feb41c7","created":1764860644,"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":" in"}}]}
 
-      data: {"id":"202512042304045f5077f67feb41c7","created":1764860644,"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,"delta":{"role":"assistant","content":" go"}}]}
 
-      data: {"id":"202512042304045f5077f67feb41c7","created":1764860644,"model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":133,"completion_tokens":8,"total_tokens":141,"prompt_tokens_details":{"cached_tokens":114}}}
+      data: {"id":"202512042341297e6b7b9f2a4448e6","created":1764862889,"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: [DONE]
 
@@ -43,15 +45,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.592793542s
+    duration: 1.198325875s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49643
+    content_length: 49797
     host: ""

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

@@ -24,19 +24,17 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20251204230409eba1d5ce5b754bb8","created":1764860649,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"20251204230409eba1d5ce5b754bb8","created":1764860649,"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":"Listing"}}]}
 
-      data: {"id":"20251204230409eba1d5ce5b754bb8","created":1764860649,"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":" Files"}}]}
 
-      data: {"id":"20251204230409eba1d5ce5b754bb8","created":1764860649,"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":" with"}}]}
 
-      data: {"id":"20251204230409eba1d5ce5b754bb8","created":1764860649,"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,"delta":{"role":"assistant","content":" ls"}}]}
 
-      data: {"id":"20251204230409eba1d5ce5b754bb8","created":1764860649,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" command"}}]}
-
-      data: {"id":"20251204230409eba1d5ce5b754bb8","created":1764860649,"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: {"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: [DONE]
 
@@ -45,15 +43,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.308563333s
+    duration: 1.516923042s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49637
+    content_length: 49791
     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":"202512042311374d2c2de9ad4148fa","created":1764861097,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"202512042311374d2c2de9ad4148fa","created":1764861097,"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":"Mult"}}]}
 
-      data: {"id":"202512042311374d2c2de9ad4148fa","created":1764861097,"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":"ied"}}]}
 
-      data: {"id":"202512042311374d2c2de9ad4148fa","created":1764861097,"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":"it"}}]}
 
-      data: {"id":"202512042311374d2c2de9ad4148fa","created":1764861097,"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":" Go"}}]}
 
-      data: {"id":"202512042311374d2c2de9ad4148fa","created":1764861097,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" code"}}]}
+      data: {"id":"202512042341493c3bdbdd7a5c4a70","created":1764862909,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" code"}}]}
 
-      data: {"id":"202512042311374d2c2de9ad4148fa","created":1764861097,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" modification"}}]}
+      data: {"id":"202512042341493c3bdbdd7a5c4a70","created":1764862909,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" modification"}}]}
 
-      data: {"id":"202512042311374d2c2de9ad4148fa","created":1764861097,"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: {"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: [DONE]
 
@@ -47,15 +47,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.333233625s
+    duration: 1.209176375s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49723
+    content_length: 49877
     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":"20251204231155ed6588b6ced5427c","created":1764861115,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"20251204231155ed6588b6ced5427c","created":1764861115,"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":"Parallel"}}]}
 
-      data: {"id":"20251204231155ed6588b6ced5427c","created":1764861115,"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":" glob"}}]}
 
-      data: {"id":"20251204231155ed6588b6ced5427c","created":1764861115,"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":" and"}}]}
 
-      data: {"id":"20251204231155ed6588b6ced5427c","created":1764861115,"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":" ls"}}]}
 
-      data: {"id":"20251204231155ed6588b6ced5427c","created":1764861115,"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,"delta":{"role":"assistant","content":" commands"}}]}
 
-      data: {"id":"20251204231155ed6588b6ced5427c","created":1764861115,"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":114}}}
+      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: [DONE]
 
@@ -45,15 +45,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 740.234333ms
+    duration: 1.525775667s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49734
+    content_length: 49888
     host: ""

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

@@ -6,9 +6,9 @@ interactions:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 678
+    content_length: 49761
     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\nRead the go mod\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/simple_test.yaml 🔗

@@ -24,11 +24,15 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20251204230317161563337b27418e","created":1764860597,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"20251204230317161563337b27418e","created":1764860597,"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":"G"}}]}
 
-      data: {"id":"20251204230317161563337b27418e","created":1764860597,"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":114}}}
+      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: [DONE]
 
@@ -37,15 +41,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 2.824408542s
+    duration: 1.15517175s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49597
+    content_length: 49751
     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":"20251204231146c1c8e521eb3a437a","created":1764861106,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"20251204231146c1c8e521eb3a437a","created":1764861106,"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":"Search"}}]}
 
-      data: {"id":"20251204231146c1c8e521eb3a437a","created":1764861106,"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":" Go"}}]}
 
-      data: {"id":"20251204231146c1c8e521eb3a437a","created":1764861106,"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":" repos"}}]}
 
-      data: {"id":"20251204231146c1c8e521eb3a437a","created":1764861106,"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":" with"}}]}
 
-      data: {"id":"20251204231146c1c8e521eb3a437a","created":1764861106,"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":" Source"}}]}
 
-      data: {"id":"20251204231146c1c8e521eb3a437a","created":1764861106,"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,"delta":{"role":"assistant","content":"graph"}}]}
 
-      data: {"id":"20251204231146c1c8e521eb3a437a","created":1764861106,"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":114}}}
+      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: [DONE]
 
@@ -47,15 +47,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 836.516375ms
+    duration: 1.250413708s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49657
+    content_length: 49811
     host: ""

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

@@ -24,25 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20251204230332c69ccaef1c0b47a0","created":1764860612,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"20251204230332c69ccaef1c0b47a0","created":1764860612,"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":"Update"}}]}
 
-      data: {"id":"20251204230332c69ccaef1c0b47a0","created":1764860612,"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":" main"}}]}
 
-      data: {"id":"20251204230332c69ccaef1c0b47a0","created":1764860612,"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":".go"}}]}
 
-      data: {"id":"20251204230332c69ccaef1c0b47a0","created":1764860612,"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":" with"}}]}
 
-      data: {"id":"20251204230332c69ccaef1c0b47a0","created":1764860612,"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":" hello"}}]}
 
-      data: {"id":"20251204230332c69ccaef1c0b47a0","created":1764860612,"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,"delta":{"role":"assistant","content":" message"}}]}
 
-      data: {"id":"20251204230332c69ccaef1c0b47a0","created":1764860612,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" from"}}]}
-
-      data: {"id":"20251204230332c69ccaef1c0b47a0","created":1764860612,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" crush"}}]}
-
-      data: {"id":"20251204230332c69ccaef1c0b47a0","created":1764860612,"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: {"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: [DONE]
 
@@ -51,15 +47,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.093262583s
+    duration: 1.561432209s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49663
+    content_length: 49817
     host: ""

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

@@ -24,23 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"202512042311517a074c1c79344375","created":1764861111,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"202512042311517a074c1c79344375","created":1764861111,"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":"Create"}}]}
 
-      data: {"id":"202512042311517a074c1c79344375","created":1764861111,"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":" config"}}]}
 
-      data: {"id":"202512042311517a074c1c79344375","created":1764861111,"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":".json"}}]}
 
-      data: {"id":"202512042311517a074c1c79344375","created":1764861111,"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":" with"}}]}
 
-      data: {"id":"202512042311517a074c1c79344375","created":1764861111,"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":" specific"}}]}
 
-      data: {"id":"202512042311517a074c1c79344375","created":1764861111,"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":" content"}}]}
 
-      data: {"id":"202512042311517a074c1c79344375","created":1764861111,"model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" content"}}]}
-
-      data: {"id":"202512042311517a074c1c79344375","created":1764861111,"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: {"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: [DONE]
 
@@ -49,15 +47,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 812.216416ms
+    duration: 1.199529708s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 49700
+    content_length: 49854
     host: ""

internal/agent/tools/diagnostics.go 🔗

@@ -94,7 +94,7 @@ func getDiagnostics(filePath string, lsps *csync.Map[string, *lsp.Client]) strin
 	}
 
 	out := output.String()
-	slog.Info("Diagnostics", "output", out)
+	slog.Debug("Diagnostics", "output", out)
 	return out
 }
 

internal/agent/tools/fetch_helpers.go 🔗

@@ -8,12 +8,17 @@ import (
 	"fmt"
 	"io"
 	"net/http"
+	"regexp"
 	"strings"
 	"unicode/utf8"
 
 	md "github.com/JohannesKaufmann/html-to-markdown"
+	"golang.org/x/net/html"
 )
 
+// BrowserUserAgent is a realistic browser User-Agent for better compatibility.
+const BrowserUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
+
 // FetchURLAndConvert fetches a URL and converts HTML content to markdown.
 func FetchURLAndConvert(ctx context.Context, client *http.Client, url string) (string, error) {
 	req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
@@ -21,7 +26,10 @@ func FetchURLAndConvert(ctx context.Context, client *http.Client, url string) (s
 		return "", fmt.Errorf("failed to create request: %w", err)
 	}
 
-	req.Header.Set("User-Agent", "crush/1.0")
+	// Use realistic browser headers for better compatibility.
+	req.Header.Set("User-Agent", BrowserUserAgent)
+	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
+	req.Header.Set("Accept-Language", "en-US,en;q=0.5")
 
 	resp, err := client.Do(req)
 	if err != nil {
@@ -49,11 +57,13 @@ func FetchURLAndConvert(ctx context.Context, client *http.Client, url string) (s
 
 	// Convert HTML to markdown for better AI processing.
 	if strings.Contains(contentType, "text/html") {
-		markdown, err := ConvertHTMLToMarkdown(content)
+		// Remove noisy elements before conversion.
+		cleanedHTML := removeNoisyElements(content)
+		markdown, err := ConvertHTMLToMarkdown(cleanedHTML)
 		if err != nil {
 			return "", fmt.Errorf("failed to convert HTML to markdown: %w", err)
 		}
-		content = markdown
+		content = cleanupMarkdown(markdown)
 	} else if strings.Contains(contentType, "application/json") || strings.Contains(contentType, "text/json") {
 		// Format JSON for better readability.
 		formatted, err := FormatJSON(content)
@@ -66,11 +76,79 @@ func FetchURLAndConvert(ctx context.Context, client *http.Client, url string) (s
 	return content, nil
 }
 
+// removeNoisyElements removes script, style, nav, header, footer, and other
+// noisy elements from HTML to improve content extraction.
+func removeNoisyElements(htmlContent string) string {
+	doc, err := html.Parse(strings.NewReader(htmlContent))
+	if err != nil {
+		// If parsing fails, return original content.
+		return htmlContent
+	}
+
+	// Elements to remove entirely.
+	noisyTags := map[string]bool{
+		"script":   true,
+		"style":    true,
+		"nav":      true,
+		"header":   true,
+		"footer":   true,
+		"aside":    true,
+		"noscript": true,
+		"iframe":   true,
+		"svg":      true,
+	}
+
+	var removeNodes func(*html.Node)
+	removeNodes = func(n *html.Node) {
+		var toRemove []*html.Node
+
+		for c := n.FirstChild; c != nil; c = c.NextSibling {
+			if c.Type == html.ElementNode && noisyTags[c.Data] {
+				toRemove = append(toRemove, c)
+			} else {
+				removeNodes(c)
+			}
+		}
+
+		for _, node := range toRemove {
+			n.RemoveChild(node)
+		}
+	}
+
+	removeNodes(doc)
+
+	var buf bytes.Buffer
+	if err := html.Render(&buf, doc); err != nil {
+		return htmlContent
+	}
+
+	return buf.String()
+}
+
+// cleanupMarkdown removes excessive whitespace and blank lines from markdown.
+func cleanupMarkdown(content string) string {
+	// Collapse multiple blank lines into at most two.
+	multipleNewlines := regexp.MustCompile(`\n{3,}`)
+	content = multipleNewlines.ReplaceAllString(content, "\n\n")
+
+	// Remove trailing whitespace from each line.
+	lines := strings.Split(content, "\n")
+	for i, line := range lines {
+		lines[i] = strings.TrimRight(line, " \t")
+	}
+	content = strings.Join(lines, "\n")
+
+	// Trim leading/trailing whitespace.
+	content = strings.TrimSpace(content)
+
+	return content
+}
+
 // ConvertHTMLToMarkdown converts HTML content to markdown format.
-func ConvertHTMLToMarkdown(html string) (string, error) {
+func ConvertHTMLToMarkdown(htmlContent string) (string, error) {
 	converter := md.NewConverter("", true, nil)
 
-	markdown, err := converter.ConvertString(html)
+	markdown, err := converter.ConvertString(htmlContent)
 	if err != nil {
 		return "", err
 	}
@@ -80,7 +158,7 @@ func ConvertHTMLToMarkdown(html string) (string, error) {
 
 // FormatJSON formats JSON content with proper indentation.
 func FormatJSON(content string) (string, error) {
-	var data interface{}
+	var data any
 	if err := json.Unmarshal([]byte(content), &data); err != nil {
 		return "", err
 	}

internal/agent/tools/fetch_types.go 🔗

@@ -6,18 +6,21 @@ const AgenticFetchToolName = "agentic_fetch"
 // WebFetchToolName is the name of the web_fetch tool.
 const WebFetchToolName = "web_fetch"
 
+// WebSearchToolName is the name of the web_search tool for sub-agents.
+const WebSearchToolName = "web_search"
+
 // LargeContentThreshold is the size threshold for saving content to a file.
 const LargeContentThreshold = 50000 // 50KB
 
 // AgenticFetchParams defines the parameters for the agentic fetch tool.
 type AgenticFetchParams struct {
-	URL    string `json:"url" description:"The URL to fetch content from"`
-	Prompt string `json:"prompt" description:"The prompt to run on the fetched content"`
+	URL    string `json:"url,omitempty" description:"The URL to fetch content from (optional - if not provided, the agent will search the web)"`
+	Prompt string `json:"prompt" description:"The prompt describing what information to find or extract"`
 }
 
 // AgenticFetchPermissionsParams defines the permission parameters for the agentic fetch tool.
 type AgenticFetchPermissionsParams struct {
-	URL    string `json:"url"`
+	URL    string `json:"url,omitempty"`
 	Prompt string `json:"prompt"`
 }
 
@@ -26,6 +29,12 @@ type WebFetchParams struct {
 	URL string `json:"url" description:"The URL to fetch content from"`
 }
 
+// WebSearchParams defines the parameters for the web_search tool.
+type WebSearchParams struct {
+	Query      string `json:"query" description:"The search query to find information on the web"`
+	MaxResults int    `json:"max_results,omitempty" description:"Maximum number of results to return (default: 10, max: 20)"`
+}
+
 // FetchParams defines the parameters for the simple fetch tool.
 type FetchParams struct {
 	URL     string `json:"url" description:"The URL to fetch content from"`

internal/agent/tools/mcp-tools.go 🔗

@@ -104,9 +104,27 @@ func (m *Tool) Run(ctx context.Context, params fantasy.ToolCall) (fantasy.ToolRe
 		return fantasy.ToolResponse{}, permission.ErrorPermissionDenied
 	}
 
-	content, err := mcp.RunTool(ctx, m.mcpName, m.tool.Name, params.Input)
+	result, err := mcp.RunTool(ctx, m.mcpName, m.tool.Name, params.Input)
 	if err != nil {
 		return fantasy.NewTextErrorResponse(err.Error()), nil
 	}
-	return fantasy.NewTextResponse(content), nil
+
+	switch result.Type {
+	case "image", "media":
+		if !GetSupportsImagesFromContext(ctx) {
+			modelName := GetModelNameFromContext(ctx)
+			return fantasy.NewTextErrorResponse(fmt.Sprintf("This model (%s) does not support image data.", modelName)), nil
+		}
+
+		var response fantasy.ToolResponse
+		if result.Type == "image" {
+			response = fantasy.NewImageResponse(result.Data, result.MediaType)
+		} else {
+			response = fantasy.NewMediaResponse(result.Data, result.MediaType)
+		}
+		response.Content = result.Content
+		return response, nil
+	default:
+		return fantasy.NewTextResponse(result.Content), nil
+	}
 }

internal/agent/tools/mcp/init.go 🔗

@@ -109,14 +109,26 @@ func GetState(name string) (ClientInfo, bool) {
 // Close closes all MCP clients. This should be called during application shutdown.
 func Close() error {
 	var errs []error
+	var wg sync.WaitGroup
 	for name, session := range sessions.Seq2() {
-		if err := session.Close(); err != nil &&
-			!errors.Is(err, io.EOF) &&
-			!errors.Is(err, context.Canceled) &&
-			err.Error() != "signal: killed" {
-			errs = append(errs, fmt.Errorf("close mcp: %s: %w", name, err))
-		}
+		wg.Go(func() {
+			done := make(chan bool, 1)
+			go func() {
+				if err := session.Close(); err != nil &&
+					!errors.Is(err, io.EOF) &&
+					!errors.Is(err, context.Canceled) &&
+					err.Error() != "signal: killed" {
+					errs = append(errs, fmt.Errorf("close mcp: %s: %w", name, err))
+				}
+				done <- true
+			}()
+			select {
+			case <-done:
+			case <-time.After(time.Millisecond * 250):
+			}
+		})
 	}
+	wg.Wait()
 	broker.Shutdown()
 	return errors.Join(errs...)
 }
@@ -279,9 +291,8 @@ func createSession(ctx context.Context, name string, m config.MCPConfig, resolve
 				})
 			},
 			LoggingMessageHandler: func(_ context.Context, req *mcp.LoggingMessageRequest) {
-				slog.Info("mcp log", "name", name, "data", req.Params.Data)
+				slog.Info("MCP log", "name", name, "data", req.Params.Data)
 			},
-			KeepAlive: time.Minute * 10,
 		},
 	)
 
@@ -289,14 +300,14 @@ func createSession(ctx context.Context, name string, m config.MCPConfig, resolve
 	if err != nil {
 		err = maybeStdioErr(err, transport)
 		updateState(name, StateError, maybeTimeoutErr(err, timeout), nil, Counts{})
-		slog.Error("error starting mcp client", "error", err, "name", name)
+		slog.Error("MCP client failed to initialize", "error", err, "name", name)
 		cancel()
 		cancelTimer.Stop()
 		return nil, err
 	}
 
 	cancelTimer.Stop()
-	slog.Info("Initialized mcp client", "name", name)
+	slog.Info("MCP client initialized", "name", name)
 	return session, nil
 }
 

internal/agent/tools/mcp/tools.go 🔗

@@ -14,6 +14,14 @@ import (
 
 type Tool = mcp.Tool
 
+// ToolResult represents the result of running an MCP tool.
+type ToolResult struct {
+	Type      string
+	Content   string
+	Data      []byte
+	MediaType string
+}
+
 var allTools = csync.NewMap[string, []*Tool]()
 
 // Tools returns all available MCP tools.
@@ -22,33 +30,78 @@ func Tools() iter.Seq2[string, []*Tool] {
 }
 
 // RunTool runs an MCP tool with the given input parameters.
-func RunTool(ctx context.Context, name, toolName string, input string) (string, error) {
+func RunTool(ctx context.Context, name, toolName string, input string) (ToolResult, error) {
 	var args map[string]any
 	if err := json.Unmarshal([]byte(input), &args); err != nil {
-		return "", fmt.Errorf("error parsing parameters: %s", err)
+		return ToolResult{}, fmt.Errorf("error parsing parameters: %s", err)
 	}
 
 	c, err := getOrRenewClient(ctx, name)
 	if err != nil {
-		return "", err
+		return ToolResult{}, err
 	}
 	result, err := c.CallTool(ctx, &mcp.CallToolParams{
 		Name:      toolName,
 		Arguments: args,
 	})
 	if err != nil {
-		return "", err
+		return ToolResult{}, err
+	}
+
+	if len(result.Content) == 0 {
+		return ToolResult{Type: "text", Content: ""}, nil
 	}
 
-	output := make([]string, 0, len(result.Content))
+	var textParts []string
+	var imageData []byte
+	var imageMimeType string
+	var audioData []byte
+	var audioMimeType string
+
 	for _, v := range result.Content {
-		if vv, ok := v.(*mcp.TextContent); ok {
-			output = append(output, vv.Text)
-		} else {
-			output = append(output, fmt.Sprintf("%v", v))
+		switch content := v.(type) {
+		case *mcp.TextContent:
+			textParts = append(textParts, content.Text)
+		case *mcp.ImageContent:
+			if imageData == nil {
+				imageData = content.Data
+				imageMimeType = content.MIMEType
+			}
+		case *mcp.AudioContent:
+			if audioData == nil {
+				audioData = content.Data
+				audioMimeType = content.MIMEType
+			}
+		default:
+			textParts = append(textParts, fmt.Sprintf("%v", v))
 		}
 	}
-	return strings.Join(output, "\n"), nil
+
+	textContent := strings.Join(textParts, "\n")
+
+	// MCP SDK returns Data as already base64-encoded, so we use it directly.
+	if imageData != nil {
+		return ToolResult{
+			Type:      "image",
+			Content:   textContent,
+			Data:      imageData,
+			MediaType: imageMimeType,
+		}, nil
+	}
+
+	if audioData != nil {
+		return ToolResult{
+			Type:      "media",
+			Content:   textContent,
+			Data:      audioData,
+			MediaType: audioMimeType,
+		}, nil
+	}
+
+	return ToolResult{
+		Type:    "text",
+		Content: textContent,
+	}, nil
 }
 
 // RefreshTools gets the updated list of tools from the MCP and updates the

internal/agent/tools/multiedit.go 🔗

@@ -165,13 +165,20 @@ func processMultiEditWithCreation(edit editContext, params MultiEditParams, call
 	// Check permissions
 	_, additions, removals := diff.GenerateDiff("", currentContent, strings.TrimPrefix(params.FilePath, edit.workingDir))
 
+	editsApplied := len(params.Edits) - len(failedEdits)
+	var description string
+	if len(failedEdits) > 0 {
+		description = fmt.Sprintf("Create file %s with %d of %d edits (%d failed)", params.FilePath, editsApplied, len(params.Edits), len(failedEdits))
+	} else {
+		description = fmt.Sprintf("Create file %s with %d edits", params.FilePath, editsApplied)
+	}
 	p := edit.permissions.Request(permission.CreatePermissionRequest{
 		SessionID:   sessionID,
 		Path:        fsext.PathOrPrefix(params.FilePath, edit.workingDir),
 		ToolCallID:  call.ID,
 		ToolName:    MultiEditToolName,
 		Action:      "write",
-		Description: fmt.Sprintf("Create file %s with %d edits", params.FilePath, len(params.Edits)),
+		Description: description,
 		Params: MultiEditPermissionsParams{
 			FilePath:   params.FilePath,
 			OldContent: "",
@@ -202,7 +209,6 @@ func processMultiEditWithCreation(edit editContext, params MultiEditParams, call
 	recordFileWrite(params.FilePath)
 	recordFileRead(params.FilePath)
 
-	editsApplied := len(params.Edits) - len(failedEdits)
 	var message string
 	if len(failedEdits) > 0 {
 		message = fmt.Sprintf("File created with %d of %d edits: %s (%d edit(s) failed)", editsApplied, len(params.Edits), params.FilePath, len(failedEdits))
@@ -299,13 +305,21 @@ func processMultiEditExistingFile(edit editContext, params MultiEditParams, call
 
 	// Generate diff and check permissions
 	_, additions, removals := diff.GenerateDiff(oldContent, currentContent, strings.TrimPrefix(params.FilePath, edit.workingDir))
+
+	editsApplied := len(params.Edits) - len(failedEdits)
+	var description string
+	if len(failedEdits) > 0 {
+		description = fmt.Sprintf("Apply %d of %d edits to file %s (%d failed)", editsApplied, len(params.Edits), params.FilePath, len(failedEdits))
+	} else {
+		description = fmt.Sprintf("Apply %d edits to file %s", editsApplied, params.FilePath)
+	}
 	p := edit.permissions.Request(permission.CreatePermissionRequest{
 		SessionID:   sessionID,
 		Path:        fsext.PathOrPrefix(params.FilePath, edit.workingDir),
 		ToolCallID:  call.ID,
 		ToolName:    MultiEditToolName,
 		Action:      "write",
-		Description: fmt.Sprintf("Apply %d edits to file %s", len(params.Edits), params.FilePath),
+		Description: description,
 		Params: MultiEditPermissionsParams{
 			FilePath:   params.FilePath,
 			OldContent: oldContent,
@@ -351,7 +365,6 @@ func processMultiEditExistingFile(edit editContext, params MultiEditParams, call
 	recordFileWrite(params.FilePath)
 	recordFileRead(params.FilePath)
 
-	editsApplied := len(params.Edits) - len(failedEdits)
 	var message string
 	if len(failedEdits) > 0 {
 		message = fmt.Sprintf("Applied %d of %d edits to file: %s (%d edit(s) failed)", editsApplied, len(params.Edits), params.FilePath, len(failedEdits))

internal/agent/tools/search.go 🔗

@@ -0,0 +1,183 @@
+package tools
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"net/http"
+	"net/url"
+	"slices"
+	"strings"
+
+	"golang.org/x/net/html"
+)
+
+// SearchResult represents a single search result from DuckDuckGo.
+type SearchResult struct {
+	Title    string
+	Link     string
+	Snippet  string
+	Position int
+}
+
+// searchDuckDuckGo performs a web search using DuckDuckGo's HTML endpoint.
+func searchDuckDuckGo(ctx context.Context, client *http.Client, query string, maxResults int) ([]SearchResult, error) {
+	if maxResults <= 0 {
+		maxResults = 10
+	}
+
+	formData := url.Values{}
+	formData.Set("q", query)
+	formData.Set("b", "")
+	formData.Set("kl", "")
+
+	req, err := http.NewRequestWithContext(ctx, "POST", "https://html.duckduckgo.com/html", strings.NewReader(formData.Encode()))
+	if err != nil {
+		return nil, fmt.Errorf("failed to create request: %w", err)
+	}
+
+	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+	req.Header.Set("User-Agent", BrowserUserAgent)
+
+	resp, err := client.Do(req)
+	if err != nil {
+		return nil, fmt.Errorf("failed to execute search: %w", err)
+	}
+	defer resp.Body.Close()
+
+	if resp.StatusCode != http.StatusOK {
+		return nil, fmt.Errorf("search failed with status code: %d", resp.StatusCode)
+	}
+
+	body, err := io.ReadAll(resp.Body)
+	if err != nil {
+		return nil, fmt.Errorf("failed to read response: %w", err)
+	}
+
+	return parseSearchResults(string(body), maxResults)
+}
+
+// parseSearchResults extracts search results from DuckDuckGo HTML response.
+func parseSearchResults(htmlContent string, maxResults int) ([]SearchResult, error) {
+	doc, err := html.Parse(strings.NewReader(htmlContent))
+	if err != nil {
+		return nil, fmt.Errorf("failed to parse HTML: %w", err)
+	}
+
+	var results []SearchResult
+	var traverse func(*html.Node)
+
+	traverse = func(n *html.Node) {
+		if n.Type == html.ElementNode && n.Data == "div" && hasClass(n, "result") {
+			result := extractResult(n)
+			if result != nil && result.Link != "" && !strings.Contains(result.Link, "y.js") {
+				result.Position = len(results) + 1
+				results = append(results, *result)
+				if len(results) >= maxResults {
+					return
+				}
+			}
+		}
+		for c := n.FirstChild; c != nil && len(results) < maxResults; c = c.NextSibling {
+			traverse(c)
+		}
+	}
+
+	traverse(doc)
+	return results, nil
+}
+
+// hasClass checks if an HTML node has a specific class.
+func hasClass(n *html.Node, class string) bool {
+	for _, attr := range n.Attr {
+		if attr.Key == "class" {
+			return slices.Contains(strings.Fields(attr.Val), class)
+		}
+	}
+	return false
+}
+
+// extractResult extracts a search result from a result div node.
+func extractResult(n *html.Node) *SearchResult {
+	result := &SearchResult{}
+
+	var traverse func(*html.Node)
+	traverse = func(node *html.Node) {
+		if node.Type == html.ElementNode {
+			// Look for title link.
+			if node.Data == "a" && hasClass(node, "result__a") {
+				result.Title = getTextContent(node)
+				for _, attr := range node.Attr {
+					if attr.Key == "href" {
+						result.Link = cleanDuckDuckGoURL(attr.Val)
+						break
+					}
+				}
+			}
+			// Look for snippet.
+			if node.Data == "a" && hasClass(node, "result__snippet") {
+				result.Snippet = getTextContent(node)
+			}
+		}
+		for c := node.FirstChild; c != nil; c = c.NextSibling {
+			traverse(c)
+		}
+	}
+
+	traverse(n)
+	return result
+}
+
+// getTextContent extracts all text content from a node and its children.
+func getTextContent(n *html.Node) string {
+	var text strings.Builder
+	var traverse func(*html.Node)
+
+	traverse = func(node *html.Node) {
+		if node.Type == html.TextNode {
+			text.WriteString(node.Data)
+		}
+		for c := node.FirstChild; c != nil; c = c.NextSibling {
+			traverse(c)
+		}
+	}
+
+	traverse(n)
+	return strings.TrimSpace(text.String())
+}
+
+// cleanDuckDuckGoURL extracts the actual URL from DuckDuckGo's redirect URL.
+func cleanDuckDuckGoURL(rawURL string) string {
+	if strings.HasPrefix(rawURL, "//duckduckgo.com/l/?uddg=") {
+		// Extract the actual URL from the redirect.
+		if idx := strings.Index(rawURL, "uddg="); idx != -1 {
+			encoded := rawURL[idx+5:]
+			if ampIdx := strings.Index(encoded, "&"); ampIdx != -1 {
+				encoded = encoded[:ampIdx]
+			}
+			decoded, err := url.QueryUnescape(encoded)
+			if err == nil {
+				return decoded
+			}
+		}
+	}
+	return rawURL
+}
+
+// formatSearchResults formats search results for LLM consumption.
+func formatSearchResults(results []SearchResult) string {
+	if len(results) == 0 {
+		return "No results were found for your search query. This could be due to DuckDuckGo's bot detection or the query returned no matches. Please try rephrasing your search or try again in a few minutes."
+	}
+
+	var sb strings.Builder
+	sb.WriteString(fmt.Sprintf("Found %d search results:\n\n", len(results)))
+
+	for _, result := range results {
+		sb.WriteString(fmt.Sprintf("%d. %s\n", result.Position, result.Title))
+		sb.WriteString(fmt.Sprintf("   URL: %s\n", result.Link))
+		sb.WriteString(fmt.Sprintf("   Summary: %s\n\n", result.Snippet))
+	}
+
+	return sb.String()
+}

internal/agent/tools/tools.go 🔗

@@ -7,13 +7,22 @@ import (
 type (
 	sessionIDContextKey string
 	messageIDContextKey string
+	supportsImagesKey   string
+	modelNameKey        string
 )
 
 const (
+	// SessionIDContextKey is the key for the session ID in the context.
 	SessionIDContextKey sessionIDContextKey = "session_id"
+	// MessageIDContextKey is the key for the message ID in the context.
 	MessageIDContextKey messageIDContextKey = "message_id"
+	// SupportsImagesContextKey is the key for the model's image support capability.
+	SupportsImagesContextKey supportsImagesKey = "supports_images"
+	// ModelNameContextKey is the key for the model name in the context.
+	ModelNameContextKey modelNameKey = "model_name"
 )
 
+// GetSessionFromContext retrieves the session ID from the context.
 func GetSessionFromContext(ctx context.Context) string {
 	sessionID := ctx.Value(SessionIDContextKey)
 	if sessionID == nil {
@@ -26,6 +35,7 @@ func GetSessionFromContext(ctx context.Context) string {
 	return s
 }
 
+// GetMessageFromContext retrieves the message ID from the context.
 func GetMessageFromContext(ctx context.Context) string {
 	messageID := ctx.Value(MessageIDContextKey)
 	if messageID == nil {
@@ -37,3 +47,28 @@ func GetMessageFromContext(ctx context.Context) string {
 	}
 	return s
 }
+
+// GetSupportsImagesFromContext retrieves whether the model supports images from the context.
+func GetSupportsImagesFromContext(ctx context.Context) bool {
+	supportsImages := ctx.Value(SupportsImagesContextKey)
+	if supportsImages == nil {
+		return false
+	}
+	if supports, ok := supportsImages.(bool); ok {
+		return supports
+	}
+	return false
+}
+
+// GetModelNameFromContext retrieves the model name from the context.
+func GetModelNameFromContext(ctx context.Context) string {
+	modelName := ctx.Value(ModelNameContextKey)
+	if modelName == nil {
+		return ""
+	}
+	s, ok := modelName.(string)
+	if !ok {
+		return ""
+	}
+	return s
+}

internal/agent/tools/view.go 🔗

@@ -4,6 +4,7 @@ import (
 	"bufio"
 	"context"
 	_ "embed"
+	"encoding/base64"
 	"fmt"
 	"io"
 	"os"
@@ -46,7 +47,7 @@ type ViewResponseMetadata struct {
 
 const (
 	ViewToolName     = "view"
-	MaxReadSize      = 250 * 1024
+	MaxReadSize      = 5 * 1024 * 1024 // 5MB
 	DefaultReadLimit = 2000
 	MaxLineLength    = 2000
 )
@@ -147,11 +148,20 @@ func NewViewTool(lspClients *csync.Map[string, *lsp.Client], permissions permiss
 				params.Limit = DefaultReadLimit
 			}
 
-			// Check if it's an image file
-			isImage, imageType := isImageFile(filePath)
-			// TODO: handle images
+			isImage, mimeType := getImageMimeType(filePath)
 			if isImage {
-				return fantasy.NewTextErrorResponse(fmt.Sprintf("This is an image file of type: %s\n", imageType)), nil
+				if !GetSupportsImagesFromContext(ctx) {
+					modelName := GetModelNameFromContext(ctx)
+					return fantasy.NewTextErrorResponse(fmt.Sprintf("This model (%s) does not support image data.", modelName)), nil
+				}
+
+				imageData, err := os.ReadFile(filePath)
+				if err != nil {
+					return fantasy.ToolResponse{}, fmt.Errorf("error reading image file: %w", err)
+				}
+
+				encoded := base64.StdEncoding.EncodeToString(imageData)
+				return fantasy.NewImageResponse([]byte(encoded), mimeType), nil
 			}
 
 			// Read the file content
@@ -263,21 +273,21 @@ func readTextFile(filePath string, offset, limit int) (string, int, error) {
 	return strings.Join(lines, "\n"), lineCount, nil
 }
 
-func isImageFile(filePath string) (bool, string) {
+func getImageMimeType(filePath string) (bool, string) {
 	ext := strings.ToLower(filepath.Ext(filePath))
 	switch ext {
 	case ".jpg", ".jpeg":
-		return true, "JPEG"
+		return true, "image/jpeg"
 	case ".png":
-		return true, "PNG"
+		return true, "image/png"
 	case ".gif":
-		return true, "GIF"
+		return true, "image/gif"
 	case ".bmp":
-		return true, "BMP"
+		return true, "image/bmp"
 	case ".svg":
-		return true, "SVG"
+		return true, "image/svg+xml"
 	case ".webp":
-		return true, "WebP"
+		return true, "image/webp"
 	default:
 		return false, ""
 	}

internal/agent/tools/view.md 🔗

@@ -5,6 +5,7 @@ Reads and displays file contents with line numbers for examining code, logs, or
 - Optional offset: start reading from specific line (0-based)
 - Optional limit: control lines read (default 2000)
 - Don't use for directories (use LS tool instead)
+- Supports image files (PNG, JPEG, GIF, BMP, SVG, WebP)
 </usage>
 
 <features>
@@ -13,13 +14,14 @@ Reads and displays file contents with line numbers for examining code, logs, or
 - Handles large files by limiting lines read
 - Auto-truncates very long lines for display
 - Suggests similar filenames when file not found
+- Renders image files directly in terminal
 </features>
 
 <limitations>
-- Max file size: 250KB
+- Max file size: 5MB
 - Default limit: 2000 lines
 - Lines >2000 chars truncated
-- Cannot display binary files/images (identifies them)
+- Binary files (except images) cannot be displayed
 </limitations>
 
 <cross_platform>
@@ -32,4 +34,5 @@ Reads and displays file contents with line numbers for examining code, logs, or
 - Use with Glob to find files first
 - For code exploration: Grep to find relevant files, then View to examine
 - For large files: use offset parameter for specific sections
+- View tool automatically detects and renders image files
 </tips>

internal/agent/tools/web_search.go 🔗

@@ -0,0 +1,51 @@
+package tools
+
+import (
+	"context"
+	_ "embed"
+	"net/http"
+	"time"
+
+	"charm.land/fantasy"
+)
+
+//go:embed web_search.md
+var webSearchToolDescription []byte
+
+// NewWebSearchTool creates a web search tool for sub-agents (no permissions needed).
+func NewWebSearchTool(client *http.Client) fantasy.AgentTool {
+	if client == nil {
+		client = &http.Client{
+			Timeout: 30 * time.Second,
+			Transport: &http.Transport{
+				MaxIdleConns:        100,
+				MaxIdleConnsPerHost: 10,
+				IdleConnTimeout:     90 * time.Second,
+			},
+		}
+	}
+
+	return fantasy.NewParallelAgentTool(
+		WebSearchToolName,
+		string(webSearchToolDescription),
+		func(ctx context.Context, params WebSearchParams, call fantasy.ToolCall) (fantasy.ToolResponse, error) {
+			if params.Query == "" {
+				return fantasy.NewTextErrorResponse("query is required"), nil
+			}
+
+			maxResults := params.MaxResults
+			if maxResults <= 0 {
+				maxResults = 10
+			}
+			if maxResults > 20 {
+				maxResults = 20
+			}
+
+			results, err := searchDuckDuckGo(ctx, client, params.Query, maxResults)
+			if err != nil {
+				return fantasy.NewTextErrorResponse("Failed to search: " + err.Error()), nil
+			}
+
+			return fantasy.NewTextResponse(formatSearchResults(results)), nil
+		})
+}

internal/agent/tools/web_search.md 🔗

@@ -0,0 +1,18 @@
+Searches the web using DuckDuckGo and returns search results.
+
+<usage>
+- Provide a search query to find information on the web
+- Returns a list of search results with titles, URLs, and snippets
+- Use this to find relevant web pages, then use web_fetch to get full content
+</usage>
+
+<parameters>
+- query: The search query string (required)
+- max_results: Maximum number of results to return (default: 10, max: 20)
+</parameters>
+
+<tips>
+- Use specific, targeted search queries for better results
+- After getting results, use web_fetch to get the full content of relevant pages
+- Combine multiple searches to gather comprehensive information
+</tips>

internal/app/app.go 🔗

@@ -260,6 +260,9 @@ func (app *App) RunNonInteractive(ctx context.Context, output io.Writer, prompt
 }
 
 func (app *App) UpdateAgentModel(ctx context.Context) error {
+	if app.AgentCoordinator == nil {
+		return fmt.Errorf("agent configuration is missing")
+	}
 	return app.AgentCoordinator.UpdateModels(ctx)
 }
 
@@ -370,30 +373,42 @@ func (app *App) Subscribe(program *tea.Program) {
 
 // Shutdown performs a graceful shutdown of the application.
 func (app *App) Shutdown() {
+	start := time.Now()
+	defer func() { slog.Info("Shutdown took " + time.Since(start).String()) }()
+	var wg sync.WaitGroup
 	if app.AgentCoordinator != nil {
-		app.AgentCoordinator.CancelAll()
+		wg.Go(func() {
+			app.AgentCoordinator.CancelAll()
+		})
 	}
 
 	// Kill all background shells.
-	shell.GetBackgroundShellManager().KillAll()
+	wg.Go(func() {
+		shell.GetBackgroundShellManager().KillAll()
+	})
 
 	// Shutdown all LSP clients.
 	for name, client := range app.LSPClients.Seq2() {
-		shutdownCtx, cancel := context.WithTimeout(app.globalCtx, 5*time.Second)
-		if err := client.Close(shutdownCtx); err != nil {
-			slog.Error("Failed to shutdown LSP client", "name", name, "error", err)
-		}
-		cancel()
+		wg.Go(func() {
+			shutdownCtx, cancel := context.WithTimeout(app.globalCtx, 5*time.Second)
+			defer cancel()
+			if err := client.Close(shutdownCtx); err != nil {
+				slog.Error("Failed to shutdown LSP client", "name", name, "error", err)
+			}
+		})
 	}
 
 	// Call call cleanup functions.
 	for _, cleanup := range app.cleanupFuncs {
 		if cleanup != nil {
-			if err := cleanup(); err != nil {
-				slog.Error("Failed to cleanup app properly on shutdown", "error", err)
-			}
+			wg.Go(func() {
+				if err := cleanup(); err != nil {
+					slog.Error("Failed to cleanup app properly on shutdown", "error", err)
+				}
+			})
 		}
 	}
+	wg.Wait()
 }
 
 // checkForUpdates checks for available updates.

internal/app/lsp.go 🔗

@@ -23,11 +23,11 @@ func (app *App) initLSPClients(ctx context.Context) {
 
 // createAndStartLSPClient creates a new LSP client, initializes it, and starts its workspace watcher
 func (app *App) createAndStartLSPClient(ctx context.Context, name string, config config.LSPConfig) {
-	slog.Info("Creating LSP client", "name", name, "command", config.Command, "fileTypes", config.FileTypes, "args", config.Args)
+	slog.Debug("Creating LSP client", "name", name, "command", config.Command, "fileTypes", config.FileTypes, "args", config.Args)
 
 	// Check if any root markers exist in the working directory (config now has defaults)
 	if !lsp.HasRootMarkers(app.config.WorkingDir(), config.RootMarkers) {
-		slog.Info("Skipping LSP client - no root markers found", "name", name, "rootMarkers", config.RootMarkers)
+		slog.Debug("Skipping LSP client: no root markers found", "name", name, "rootMarkers", config.RootMarkers)
 		updateLSPState(name, lsp.StateDisabled, nil, nil, 0)
 		return
 	}
@@ -53,7 +53,7 @@ func (app *App) createAndStartLSPClient(ctx context.Context, name string, config
 	// Initialize LSP client.
 	_, err = lspClient.Initialize(initCtx, app.config.WorkingDir())
 	if err != nil {
-		slog.Error("Initialize failed", "name", name, "error", err)
+		slog.Error("LSP client initialization failed", "name", name, "error", err)
 		updateLSPState(name, lsp.StateError, err, lspClient, 0)
 		lspClient.Close(ctx)
 		return
@@ -68,7 +68,7 @@ func (app *App) createAndStartLSPClient(ctx context.Context, name string, config
 		updateLSPState(name, lsp.StateError, err, lspClient, 0)
 	} else {
 		// Server reached a ready state scuccessfully.
-		slog.Info("LSP server is ready", "name", name)
+		slog.Debug("LSP server is ready", "name", name)
 		lspClient.SetServerState(lsp.StateReady)
 		updateLSPState(name, lsp.StateReady, nil, lspClient, 0)
 	}

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

@@ -181,17 +181,18 @@ func (msg *messageCmp) style() lipgloss.Style {
 func (m *messageCmp) renderAssistantMessage() string {
 	t := styles.CurrentTheme()
 	parts := []string{}
-	content := m.message.Content().String()
+	content := strings.TrimSpace(m.message.Content().String())
 	thinking := m.message.IsThinking()
+	thinkingContent := strings.TrimSpace(m.message.ReasoningContent().Thinking)
 	finished := m.message.IsFinished()
 	finishedData := m.message.FinishPart()
-	thinkingContent := ""
 
-	if thinking || strings.TrimSpace(m.message.ReasoningContent().Thinking) != "" {
+	if thinking || thinkingContent != "" {
 		m.anim.SetLabel("Thinking")
 		thinkingContent = m.renderThinkingContent()
 	} else if finished && content == "" && finishedData.Reason == message.FinishReasonEndTurn {
-		content = ""
+		// Don't render empty assistant messages with EndTurn
+		return ""
 	} else if finished && content == "" && finishedData.Reason == message.FinishReasonCanceled {
 		content = "*Canceled*"
 	} else if finished && content == "" && finishedData.Reason == message.FinishReasonError {
@@ -310,7 +311,11 @@ func (m *messageCmp) renderThinkingContent() string {
 		}
 	}
 	lineStyle := t.S().Subtle.Background(t.BgBaseLighter)
-	return lineStyle.Width(m.textWidth()).Padding(0, 1).Render(m.thinkingViewport.View()) + "\n\n" + footer
+	result := lineStyle.Width(m.textWidth()).Padding(0, 1).Render(m.thinkingViewport.View())
+	if footer != "" {
+		result += "\n\n" + footer
+	}
+	return result
 }
 
 // shouldSpin determines whether the message should show a loading animation.

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

@@ -52,6 +52,23 @@ var registry = renderRegistry{}
 // baseRenderer provides common functionality for all tool renderers
 type baseRenderer struct{}
 
+func (br baseRenderer) Render(v *toolCallCmp) string {
+	if v.result.Data != "" {
+		if strings.HasPrefix(v.result.MIMEType, "image/") {
+			return br.renderWithParams(v, v.call.Name, nil, func() string {
+				return renderImageContent(v, v.result.Data, v.result.MIMEType, v.result.Content)
+			})
+		}
+		return br.renderWithParams(v, v.call.Name, nil, func() string {
+			return renderMediaContent(v, v.result.MIMEType, v.result.Content)
+		})
+	}
+
+	return br.renderWithParams(v, v.call.Name, nil, func() string {
+		return renderPlainContent(v, v.result.Content)
+	})
+}
+
 // paramBuilder helps construct parameter lists for tool headers
 type paramBuilder struct {
 	args []string
@@ -174,6 +191,7 @@ func init() {
 	registry.register(tools.FetchToolName, func() renderer { return simpleFetchRenderer{} })
 	registry.register(tools.AgenticFetchToolName, func() renderer { return agenticFetchRenderer{} })
 	registry.register(tools.WebFetchToolName, func() renderer { return webFetchRenderer{} })
+	registry.register(tools.WebSearchToolName, func() renderer { return webSearchRenderer{} })
 	registry.register(tools.GlobToolName, func() renderer { return globRenderer{} })
 	registry.register(tools.GrepToolName, func() renderer { return grepRenderer{} })
 	registry.register(tools.LSToolName, func() renderer { return lsRenderer{} })
@@ -191,8 +209,18 @@ type genericRenderer struct {
 	baseRenderer
 }
 
-// Render displays the tool call with its raw input and plain content output
 func (gr genericRenderer) Render(v *toolCallCmp) string {
+	if v.result.Data != "" {
+		if strings.HasPrefix(v.result.MIMEType, "image/") {
+			return gr.renderWithParams(v, prettifyToolName(v.call.Name), []string{v.call.Input}, func() string {
+				return renderImageContent(v, v.result.Data, v.result.MIMEType, v.result.Content)
+			})
+		}
+		return gr.renderWithParams(v, prettifyToolName(v.call.Name), []string{v.call.Input}, func() string {
+			return renderMediaContent(v, v.result.MIMEType, v.result.Content)
+		})
+	}
+
 	return gr.renderWithParams(v, prettifyToolName(v.call.Name), []string{v.call.Input}, func() string {
 		return renderPlainContent(v, v.result.Content)
 	})
@@ -408,6 +436,10 @@ func (vr viewRenderer) Render(v *toolCallCmp) string {
 		build()
 
 	return vr.renderWithParams(v, "View", args, func() string {
+		if v.result.Data != "" && strings.HasPrefix(v.result.MIMEType, "image/") {
+			return renderImageContent(v, v.result.Data, v.result.MIMEType, "")
+		}
+
 		var meta tools.ViewResponseMetadata
 		if err := vr.unmarshalParams(v.result.Metadata, &meta); err != nil {
 			return renderPlainContent(v, v.result.Content)
@@ -605,15 +637,17 @@ type agenticFetchRenderer struct {
 	baseRenderer
 }
 
-// Render displays the fetched URL with prompt parameter and nested tool calls
+// Render displays the fetched URL or web search with prompt parameter and nested tool calls
 func (fr agenticFetchRenderer) Render(v *toolCallCmp) string {
 	t := styles.CurrentTheme()
 	var params tools.AgenticFetchParams
 	var args []string
 	if err := fr.unmarshalParams(v.call.Input, &params); err == nil {
-		args = newParamBuilder().
-			addMain(params.URL).
-			build()
+		if params.URL != "" {
+			args = newParamBuilder().
+				addMain(params.URL).
+				build()
+		}
 	}
 
 	prompt := params.Prompt
@@ -700,6 +734,30 @@ func (wfr webFetchRenderer) Render(v *toolCallCmp) string {
 	})
 }
 
+// -----------------------------------------------------------------------------
+//  Web search renderer
+// -----------------------------------------------------------------------------
+
+// webSearchRenderer handles web search with query display
+type webSearchRenderer struct {
+	baseRenderer
+}
+
+// Render displays a compact view of web_search with just the query
+func (wsr webSearchRenderer) Render(v *toolCallCmp) string {
+	var params tools.WebSearchParams
+	var args []string
+	if err := wsr.unmarshalParams(v.call.Input, &params); err == nil {
+		args = newParamBuilder().
+			addMain(params.Query).
+			build()
+	}
+
+	return wsr.renderWithParams(v, "Search", args, func() string {
+		return renderMarkdownContent(v, v.result.Content)
+	})
+}
+
 // -----------------------------------------------------------------------------
 //  Download renderer
 // -----------------------------------------------------------------------------
@@ -1025,7 +1083,7 @@ func renderPlainContent(v *toolCallCmp, content string) string {
 		}
 		ln = ansiext.Escape(ln)
 		ln = " " + ln
-		if len(ln) > width {
+		if lipgloss.Width(ln) > width {
 			ln = v.fit(ln, width)
 		}
 		out = append(out, t.S().Muted.
@@ -1143,6 +1201,55 @@ func renderCodeContent(v *toolCallCmp, path, content string, offset int) string
 	return lipgloss.JoinVertical(lipgloss.Left, lines...)
 }
 
+// renderImageContent renders image data with optional text content (for MCP tools).
+func renderImageContent(v *toolCallCmp, data, mediaType, textContent string) string {
+	t := styles.CurrentTheme()
+
+	dataSize := len(data) * 3 / 4
+	sizeStr := formatSize(dataSize)
+
+	loaded := t.S().Base.Foreground(t.Green).Render("Loaded")
+	arrow := t.S().Base.Foreground(t.GreenDark).Render("→")
+	typeStyled := t.S().Base.Render(mediaType)
+	sizeStyled := t.S().Subtle.Render(sizeStr)
+
+	imageDisplay := fmt.Sprintf("%s %s %s %s", loaded, arrow, typeStyled, sizeStyled)
+	if strings.TrimSpace(textContent) != "" {
+		textDisplay := renderPlainContent(v, textContent)
+		return lipgloss.JoinVertical(lipgloss.Left, textDisplay, "", imageDisplay)
+	}
+
+	return imageDisplay
+}
+
+// renderMediaContent renders non-image media content.
+func renderMediaContent(v *toolCallCmp, mediaType, textContent string) string {
+	t := styles.CurrentTheme()
+
+	loaded := t.S().Base.Foreground(t.Green).Render("Loaded")
+	arrow := t.S().Base.Foreground(t.GreenDark).Render("→")
+	typeStyled := t.S().Base.Render(mediaType)
+	mediaDisplay := fmt.Sprintf("%s %s %s", loaded, arrow, typeStyled)
+
+	if strings.TrimSpace(textContent) != "" {
+		textDisplay := renderPlainContent(v, textContent)
+		return lipgloss.JoinVertical(lipgloss.Left, textDisplay, "", mediaDisplay)
+	}
+
+	return mediaDisplay
+}
+
+// formatSize formats byte count as human-readable size.
+func formatSize(bytes int) string {
+	if bytes < 1024 {
+		return fmt.Sprintf("%d B", bytes)
+	}
+	if bytes < 1024*1024 {
+		return fmt.Sprintf("%.1f KB", float64(bytes)/1024)
+	}
+	return fmt.Sprintf("%.1f MB", float64(bytes)/(1024*1024))
+}
+
 func (v *toolCallCmp) renderToolError() string {
 	t := styles.CurrentTheme()
 	err := strings.ReplaceAll(v.result.Content, "\n", " ")
@@ -1180,7 +1287,9 @@ func prettifyToolName(name string) string {
 	case tools.AgenticFetchToolName:
 		return "Agentic Fetch"
 	case tools.WebFetchToolName:
-		return "Fetching"
+		return "Fetch"
+	case tools.WebSearchToolName:
+		return "Search"
 	case tools.GlobToolName:
 		return "Glob"
 	case tools.GrepToolName:

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

@@ -301,7 +301,9 @@ func (m *toolCallCmp) formatParametersForCopy() string {
 		var params tools.AgenticFetchParams
 		if json.Unmarshal([]byte(m.call.Input), &params) == nil {
 			var parts []string
-			parts = append(parts, fmt.Sprintf("**URL:** %s", params.URL))
+			if params.URL != "" {
+				parts = append(parts, fmt.Sprintf("**URL:** %s", params.URL))
+			}
 			if params.Prompt != "" {
 				parts = append(parts, fmt.Sprintf("**Prompt:** %s", params.Prompt))
 			}
@@ -397,6 +399,13 @@ func (m *toolCallCmp) formatParametersForCopy() string {
 }
 
 func (m *toolCallCmp) formatResultForCopy() string {
+	if m.result.Data != "" {
+		if strings.HasPrefix(m.result.MIMEType, "image/") {
+			return fmt.Sprintf("[Image: %s]", m.result.MIMEType)
+		}
+		return fmt.Sprintf("[Media: %s]", m.result.MIMEType)
+	}
+
 	switch m.call.Name {
 	case tools.BashToolName:
 		return m.formatBashResultForCopy()
@@ -790,6 +799,9 @@ func (m *toolCallCmp) textWidth() int {
 
 // fit truncates content to fit within the specified width with ellipsis
 func (m *toolCallCmp) fit(content string, width int) string {
+	if lipgloss.Width(content) <= width {
+		return content
+	}
 	t := styles.CurrentTheme()
 	lineStyle := t.S().Muted
 	dots := lineStyle.Render("…")

internal/tui/components/dialogs/permissions/permissions.go 🔗

@@ -389,7 +389,7 @@ func (p *permissionDialogCmp) renderHeader() string {
 	case tools.AgenticFetchToolName:
 		headerParts = append(headerParts,
 			baseStyle.Render(strings.Repeat(" ", p.width)),
-			t.S().Muted.Width(p.width).Bold(true).Render("URL"),
+			t.S().Muted.Width(p.width).Bold(true).Render("Web"),
 		)
 	case tools.ViewToolName:
 		params := p.permission.Params.(tools.ViewPermissionsParams)
@@ -605,7 +605,12 @@ func (p *permissionDialogCmp) generateAgenticFetchContent() string {
 	t := styles.CurrentTheme()
 	baseStyle := t.S().Base.Background(t.BgSubtle)
 	if pr, ok := p.permission.Params.(tools.AgenticFetchPermissionsParams); ok {
-		content := fmt.Sprintf("URL: %s\n\nPrompt: %s", pr.URL, pr.Prompt)
+		var content string
+		if pr.URL != "" {
+			content = fmt.Sprintf("URL: %s\n\nPrompt: %s", pr.URL, pr.Prompt)
+		} else {
+			content = fmt.Sprintf("Prompt: %s", pr.Prompt)
+		}
 		finalContent := baseStyle.
 			Padding(1, 2).
 			Width(p.contentViewPort.Width()).

internal/tui/components/image/load.go 🔗

@@ -3,7 +3,9 @@
 package image
 
 import (
+	"bytes"
 	"context"
+	"encoding/base64"
 	"image"
 	"image/png"
 	"io"
@@ -144,3 +146,24 @@ func svgToImage(width uint, height uint, r io.Reader) (string, error) {
 	}
 	return imageToString(width, height, img)
 }
+
+// ImageFromBase64 renders an image from base64-encoded data.
+func ImageFromBase64(width, height uint, data, mediaType string) (string, error) {
+	decoded, err := base64.StdEncoding.DecodeString(data)
+	if err != nil {
+		return "", err
+	}
+
+	r := bytes.NewReader(decoded)
+
+	if strings.Contains(mediaType, "svg") {
+		return svgToImage(width, height, r)
+	}
+
+	img, _, err := imageorient.Decode(r)
+	if err != nil {
+		return "", err
+	}
+
+	return imageToString(width, height, img)
+}

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

@@ -245,7 +245,7 @@ func (f *filterableList[T]) Filter(query string) tea.Cmd {
 
 	f.selectedItemIdx = -1
 	if query == "" || len(f.items) == 0 {
-		return f.list.SetItems(f.items)
+		return f.list.SetItems(f.visibleItems(f.items))
 	}
 
 	matches := fuzzy.FindFrom(query, f)
@@ -274,7 +274,7 @@ func (f *filterableList[T]) Filter(query string) tea.Cmd {
 
 func (f *filterableList[T]) SetItems(items []T) tea.Cmd {
 	f.items = items
-	return f.list.SetItems(items)
+	return f.list.SetItems(f.visibleItems(items))
 }
 
 func (f *filterableList[T]) Cursor() *tea.Cursor {
@@ -317,3 +317,13 @@ func (f *filterableList[T]) String(i int) string {
 func (f *filterableList[T]) Len() int {
 	return len(f.items)
 }
+
+// visibleItems returns the subset of items that should be rendered based on
+// the configured resultsSize limit. The underlying source (f.items) remains
+// intact so filtering still searches the full set.
+func (f *filterableList[T]) visibleItems(items []T) []T {
+	if f.resultsSize > 0 && len(items) > f.resultsSize {
+		return items[:f.resultsSize]
+	}
+	return items
+}

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

@@ -181,7 +181,7 @@ func (p *chatPage) Update(msg tea.Msg) (util.Model, tea.Cmd) {
 		}
 		return p, nil
 	case tea.MouseClickMsg:
-		if p.isOnboarding {
+		if p.isOnboarding || p.isProjectInit {
 			return p, nil
 		}
 		if p.compact {
@@ -210,7 +210,7 @@ func (p *chatPage) Update(msg tea.Msg) (util.Model, tea.Cmd) {
 		}
 		return p, nil
 	case tea.MouseReleaseMsg:
-		if p.isOnboarding {
+		if p.isOnboarding || p.isProjectInit {
 			return p, nil
 		}
 		if p.compact {
@@ -379,8 +379,17 @@ func (p *chatPage) Update(msg tea.Msg) (util.Model, tea.Cmd) {
 			}
 			return p, p.newSession()
 		case key.Matches(msg, p.keyMap.AddAttachment):
+			// Skip attachment handling during onboarding/splash screen
+			if p.focusedPane == PanelTypeSplash || p.isOnboarding {
+				u, cmd := p.splash.Update(msg)
+				p.splash = u.(splash.Splash)
+				return p, cmd
+			}
 			agentCfg := config.Get().Agents[config.AgentCoder]
 			model := config.Get().GetModelByType(agentCfg.Model)
+			if model == nil {
+				return p, util.ReportWarn("No model configured yet")
+			}
 			if model.SupportsImages {
 				return p, util.CmdHandler(commands.OpenFilePickerMsg{})
 			} else {