Merge branch 'main' into server-client-2

Ayman Bagabas created

Change summary

.github/cla-signatures.json                                                        | 104 
.github/labeler.yml                                                                |   2 
.github/workflows/build.yml                                                        |   2 
.github/workflows/cla.yml                                                          |   2 
.github/workflows/schema-update.yml                                                |   2 
.github/workflows/security.yml                                                     |  12 
.github/workflows/snapshot.yml                                                     |   2 
README.md                                                                          |  33 
Taskfile.yaml                                                                      |   8 
go.mod                                                                             |  46 
go.sum                                                                             |  94 
internal/agent/agent.go                                                            |  14 
internal/agent/coordinator.go                                                      |   5 
internal/agent/hyper/provider.json                                                 |   0 
internal/agent/templates/coder.md.tpl                                              |   3 
internal/agent/templates/initialize.md.tpl                                         |   8 
internal/agent/templates/title.md                                                  |  15 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/bash_tool.yaml             |  27 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/download_tool.yaml         |  24 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/fetch_tool.yaml            |  25 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/glob_tool.yaml             |  24 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/grep_tool.yaml             |  21 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/ls_tool.yaml               |  24 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/multiedit_tool.yaml        |  25 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/parallel_tool_calls.yaml   |  33 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/read_a_file.yaml           |  24 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/simple_test.yaml           |  19 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/sourcegraph_tool.yaml      |  22 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/update_a_file.yaml         |  25 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/write_tool.yaml            |  27 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/bash_tool.yaml                 |  24 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/download_tool.yaml             |  22 
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                 |  32 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/ls_tool.yaml                   |  28 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/multiedit_tool.yaml            |  26 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/parallel_tool_calls.yaml       |  28 
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                |  24 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/bash_tool.yaml           |  30 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/download_tool.yaml       |  24 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/fetch_tool.yaml          |  20 
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             |  18 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/multiedit_tool.yaml      |  22 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/parallel_tool_calls.yaml |  32 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/read_a_file.yaml         |  18 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/simple_test.yaml         |  16 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/sourcegraph_tool.yaml    |  30 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/update_a_file.yaml       |  20 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/write_tool.yaml          |  20 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/bash_tool.yaml                   |  20 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/download_tool.yaml               |  18 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/fetch_tool.yaml                  |  30 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/glob_tool.yaml                   |  20 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/grep_tool.yaml                   |  16 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/ls_tool.yaml                     |  18 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/multiedit_tool.yaml              |  24 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/parallel_tool_calls.yaml         |  24 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/read_a_file.yaml                 |  16 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/simple_test.yaml                 |  14 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/sourcegraph_tool.yaml            |  16 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/update_a_file.yaml               |  22 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/write_tool.yaml                  |  22 
internal/agent/tools/fetch.go                                                      |  17 
internal/agent/tools/view.go                                                       |   6 
internal/cmd/gitignore/default                                                     |   4 
internal/cmd/gitignore/old                                                         |   1 
internal/cmd/root.go                                                               |  25 
internal/cmd/session.go                                                            |  78 
internal/commands/commands.go                                                      |  66 
internal/commands/commands_test.go                                                 |  53 
internal/config/config.go                                                          |  14 
internal/config/load.go                                                            |  42 
internal/csync/maps.go                                                             |   2 
internal/db/connect_ncruces.go                                                     |   1 
internal/db/db.go                                                                  |   6 
internal/event/event.go                                                            |   6 
internal/event/event_test.go                                                       |  30 
internal/fsext/ls.go                                                               |  53 
internal/home/home.go                                                              |   9 
internal/log/http.go                                                               |   7 
internal/lsp/manager.go                                                            |  13 
internal/shell/shell.go                                                            |   8 
internal/ui/completions/completions.go                                             | 111 
internal/ui/completions/completions_test.go                                        | 108 
internal/ui/dialog/api_key_input.go                                                |   7 
internal/ui/dialog/commands.go                                                     |   2 
internal/ui/dialog/common.go                                                       |  18 
internal/ui/dialog/models.go                                                       |   7 
internal/ui/dialog/oauth.go                                                        |   2 
internal/ui/diffview/diffview.go                                                   |   2 
internal/ui/diffview/testdata/TestDiffView/Unified/Narrow/DarkMode.golden          |   4 
internal/ui/diffview/testdata/TestDiffView/Unified/Narrow/LightMode.golden         |   4 
internal/ui/diffview/testdata/TestDiffViewLineBreakIssue/Split.golden              |   6 
internal/ui/diffview/testdata/TestDiffViewLineBreakIssue/Unified.golden            |   4 
internal/ui/diffview/udiff_test.go                                                 |   2 
internal/ui/model/history.go                                                       |  31 
internal/ui/model/layout_test.go                                                   | 118 
internal/ui/model/ui.go                                                            | 204 
internal/ui/model/ui_test.go                                                       | 107 
schema.json                                                                        | 196 
107 files changed, 1,791 insertions(+), 1,161 deletions(-)

Detailed changes

.github/cla-signatures.json 🔗

@@ -1367,6 +1367,110 @@
       "created_at": "2026-03-21T03:49:12Z",
       "repoId": 987670088,
       "pullRequestNo": 2449
+    },
+    {
+      "name": "Alex-wuhu",
+      "id": 57132813,
+      "comment_id": 4106451941,
+      "created_at": "2026-03-22T15:26:05Z",
+      "repoId": 987670088,
+      "pullRequestNo": 2454
+    },
+    {
+      "name": "hongquan",
+      "id": 314607,
+      "comment_id": 4112122644,
+      "created_at": "2026-03-23T16:51:09Z",
+      "repoId": 987670088,
+      "pullRequestNo": 2462
+    },
+    {
+      "name": "faelis",
+      "id": 91593249,
+      "comment_id": 4113326932,
+      "created_at": "2026-03-23T19:57:54Z",
+      "repoId": 987670088,
+      "pullRequestNo": 2465
+    },
+    {
+      "name": "UnderLotus",
+      "id": 84985759,
+      "comment_id": 4118727062,
+      "created_at": "2026-03-24T14:25:40Z",
+      "repoId": 987670088,
+      "pullRequestNo": 2475
+    },
+    {
+      "name": "malikwirin",
+      "id": 117918464,
+      "comment_id": 4119816035,
+      "created_at": "2026-03-24T16:51:44Z",
+      "repoId": 987670088,
+      "pullRequestNo": 2476
+    },
+    {
+      "name": "fuleinist",
+      "id": 1163738,
+      "comment_id": 4133146531,
+      "created_at": "2026-03-26T09:45:48Z",
+      "repoId": 987670088,
+      "pullRequestNo": 2492
+    },
+    {
+      "name": "iceymoss",
+      "id": 114280774,
+      "comment_id": 4134659508,
+      "created_at": "2026-03-26T13:13:25Z",
+      "repoId": 987670088,
+      "pullRequestNo": 2493
+    },
+    {
+      "name": "srivilliamsai",
+      "id": 191893106,
+      "comment_id": 4144200398,
+      "created_at": "2026-03-27T17:37:29Z",
+      "repoId": 987670088,
+      "pullRequestNo": 2511
+    },
+    {
+      "name": "Dexterity104",
+      "id": 173429049,
+      "comment_id": 4153067126,
+      "created_at": "2026-03-30T08:05:56Z",
+      "repoId": 987670088,
+      "pullRequestNo": 2525
+    },
+    {
+      "name": "majiayu000",
+      "id": 19658300,
+      "comment_id": 4160074332,
+      "created_at": "2026-03-31T05:44:38Z",
+      "repoId": 987670088,
+      "pullRequestNo": 2534
+    },
+    {
+      "name": "afsuyadi",
+      "id": 104284194,
+      "comment_id": 4160431726,
+      "created_at": "2026-03-31T07:10:20Z",
+      "repoId": 987670088,
+      "pullRequestNo": 2532
+    },
+    {
+      "name": "owldev127",
+      "id": 175169034,
+      "comment_id": 4161299761,
+      "created_at": "2026-03-31T09:44:52Z",
+      "repoId": 987670088,
+      "pullRequestNo": 2538
+    },
+    {
+      "name": "MrRolie",
+      "id": 80284543,
+      "comment_id": 4168509138,
+      "created_at": "2026-04-01T08:44:22Z",
+      "repoId": 987670088,
+      "pullRequestNo": 2544
     }
   ]
 }

.github/labeler.yml 🔗

@@ -45,6 +45,8 @@
   - "/(panic|crash|segfault)/i"
 "provider: anthropic claude":
   - "/(anthropic|claude)/i"
+"provider: avian":
+  - "/avian/i"
 "provider: aws bedrock":
   - "/(aws|bedrock)/i"
 "provider: azure":

.github/workflows/build.yml 🔗

@@ -18,7 +18,7 @@ jobs:
       - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
         with:
           persist-credentials: false
-      - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
+      - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
         with:
           go-version-file: go.mod
       - run: go mod tidy

.github/workflows/cla.yml 🔗

@@ -22,7 +22,7 @@ jobs:
           github.event.comment.body == 'recheck' ||
           github.event.comment.body == 'I have read the Contributor License Agreement (CLA) and hereby sign the CLA.' ||
           github.event_name == 'pull_request_target'
-        uses: contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08 # v2.6.1
+        uses: contributor-assistant/github-action@58daaf842ac3e26d08c2bdf26770d6e9c5b965a9
         env:
           GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
         with:

.github/workflows/schema-update.yml 🔗

@@ -14,7 +14,7 @@ jobs:
       - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
         with:
           token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
-      - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
+      - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
         with:
           go-version-file: go.mod
       - run: go run . schema > ./schema.json

.github/workflows/security.yml 🔗

@@ -30,11 +30,11 @@ jobs:
       - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
         with:
           persist-credentials: false
-      - uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
+      - uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
         with:
           languages: ${{ matrix.language }}
-      - uses: github/codeql-action/autobuild@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
-      - uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
+      - uses: github/codeql-action/autobuild@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
+      - uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
 
   grype:
     runs-on: ubuntu-latest
@@ -52,7 +52,7 @@ jobs:
           path: "."
           fail-build: true
           severity-cutoff: critical
-      - uses: github/codeql-action/upload-sarif@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
+      - uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
         with:
           sarif_file: ${{ steps.scan.outputs.sarif }}
 
@@ -65,7 +65,7 @@ jobs:
       - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
         with:
           persist-credentials: false
-      - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
+      - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
         with:
           go-version: 1.26.1
       - name: Install govulncheck
@@ -73,7 +73,7 @@ jobs:
       - name: Run govulncheck
         run: |
           govulncheck -C . -format sarif ./... > results.sarif
-      - uses: github/codeql-action/upload-sarif@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
+      - uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
         with:
           sarif_file: results.sarif
 

.github/workflows/snapshot.yml 🔗

@@ -22,7 +22,7 @@ jobs:
         with:
           fetch-depth: 0
           persist-credentials: false
-      - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
+      - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
         with:
           go-version-file: go.mod
       - uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0

README.md 🔗

@@ -388,11 +388,23 @@ extending agent capabilities with reusable skill packages. Skills are folders
 containing a `SKILL.md` file with instructions that Crush can discover and
 activate on demand.
 
-Skills are discovered from:
+The global paths we looks for skills are:
 
-- `~/.config/crush/skills/` on Unix (default, can be overridden with `CRUSH_SKILLS_DIR`)
-- `%LOCALAPPDATA%\crush\skills\` on Windows (default, can be overridden with `CRUSH_SKILLS_DIR`)
-- Additional paths configured via `options.skills_paths`
+* `$CRUSH_SKILLS_DIR`
+* `$XDG_CONFIG_HOME/agents/skills` or `~/.config/agents/skills/`
+* `$XDG_CONFIG_HOME/crush/skills` or `~/.config/crush/skills/`
+* On Windows, we _also_ look at
+  * `%LOCALAPPDATA%\agents\skills\` or `%USERPROFILE%\AppData\Local\agents\skills\`
+  * `%LOCALAPPDATA%\crush\skills\` or `%USERPROFILE%\AppData\Local\crush\skills\`
+* Additional paths configured via `options.skills_paths`
+
+On top of that, we _also_ load skills in your project from the following
+relative paths:
+
+* `.agents/skills`
+* `.crush/skills`
+* `.claude/skills`
+* `.cursor/skills`
 
 ```jsonc
 {
@@ -772,6 +784,19 @@ Or by setting the following in your config:
 Crush also respects the `DO_NOT_TRACK` convention which can be enabled via
 `export DO_NOT_TRACK=1`.
 
+## Q&A
+
+### Why is clipboard copy and paste not working?
+
+Installing an extra tool might be needed on Unix-like environments.
+
+| Environment         | Tool                     |
+| ------------------- | ------------------------ |
+| Windows             | Native support           |
+| macOS               | Native support           |
+| Linux/BSD + Wayland | `wl-copy` and `wl-paste` |
+| Linux/BSD + X11     | `xclip` or `xsel`        |
+
 ## Contributing
 
 See the [contributing guide](https://github.com/charmbracelet/crush?tab=contributing-ov-file#contributing).

Taskfile.yaml 🔗

@@ -49,6 +49,9 @@ tasks:
     sources:
       - ./**/*.go
       - go.mod
+      - internal/agent/**/*.md
+      - internal/agent/**/*.md.tpl
+      - internal/agent/hyper/provider.json
     generates:
       - crush{{exeExt}}
 
@@ -74,7 +77,7 @@ tasks:
     cmds:
       - task: build
       - rm -rf tmp/onboarding
-      - ./crush{exeExt} {{.CLI_ARGS}}
+      - ./crush{{exeExt}} {{.CLI_ARGS}}
 
   test:
     desc: Run tests
@@ -120,6 +123,9 @@ tasks:
     sources:
       - ./**/*.go
       - go.mod
+      - internal/agent/**/*.md
+      - internal/agent/**/*.md.tpl
+      - internal/agent/hyper/provider.json
 
   profile:cpu:
     desc: 10s CPU profile

go.mod 🔗

@@ -3,11 +3,11 @@ module github.com/charmbracelet/crush
 go 1.26.1
 
 require (
-	charm.land/bubbles/v2 v2.0.0
+	charm.land/bubbles/v2 v2.1.0
 	charm.land/bubbletea/v2 v2.0.2
-	charm.land/catwalk v0.31.0
+	charm.land/catwalk v0.33.2
 	charm.land/fang/v2 v2.0.1
-	charm.land/fantasy v0.16.0
+	charm.land/fantasy v0.17.1
 	charm.land/glamour/v2 v2.0.0
 	charm.land/lipgloss/v2 v2.0.2
 	charm.land/log/v2 v2.0.0
@@ -41,18 +41,18 @@ require (
 	github.com/disintegration/imaging v1.6.2
 	github.com/dustin/go-humanize v1.0.1
 	github.com/gen2brain/beeep v0.11.2
-	github.com/go-git/go-git/v5 v5.17.0
+	github.com/go-git/go-git/v5 v5.17.1
 	github.com/google/uuid v1.6.0
 	github.com/invopop/jsonschema v0.13.0
 	github.com/joho/godotenv v1.5.1
 	github.com/jordanella/go-ansi-paintbrush v0.0.0-20240728195301-b7ad996ecf3d
-	github.com/lucasb-eyer/go-colorful v1.3.0
+	github.com/lucasb-eyer/go-colorful v1.4.0
 	github.com/mattn/go-isatty v0.0.20
 	github.com/modelcontextprotocol/go-sdk v1.4.1
-	github.com/ncruces/go-sqlite3 v0.32.0
+	github.com/ncruces/go-sqlite3 v0.33.2
 	github.com/nxadm/tail v1.4.11
 	github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
-	github.com/posthog/posthog-go v1.11.1
+	github.com/posthog/posthog-go v1.11.2
 	github.com/pressly/goose/v3 v3.27.0
 	github.com/qjebbs/go-jsons v1.0.0-alpha.4
 	github.com/rivo/uniseg v0.4.7
@@ -72,7 +72,7 @@ require (
 	golang.org/x/text v0.35.0
 	gopkg.in/natefinch/lumberjack.v2 v2.2.1
 	gopkg.in/yaml.v3 v3.0.1
-	modernc.org/sqlite v1.47.0
+	modernc.org/sqlite v1.48.0
 	mvdan.cc/sh/moreinterp v0.0.0-20250902163504-3cf4fd5717a5
 	mvdan.cc/sh/v3 v3.13.0
 )
@@ -88,7 +88,7 @@ require (
 	github.com/KyleBanks/depth v1.2.1 // indirect
 	github.com/andybalholm/cascadia v1.3.3 // indirect
 	github.com/aws/aws-sdk-go-v2 v1.41.4 // indirect
-	github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.6 // indirect
+	github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.7 // indirect
 	github.com/aws/aws-sdk-go-v2/config v1.32.12 // indirect
 	github.com/aws/aws-sdk-go-v2/credentials v1.19.12 // indirect
 	github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20 // indirect
@@ -104,12 +104,13 @@ require (
 	github.com/aws/smithy-go v1.24.2 // indirect
 	github.com/aymerick/douceur v0.2.0 // indirect
 	github.com/bahlo/generic-list-go v0.2.0 // indirect
-	github.com/buger/jsonparser v1.1.1 // indirect
+	github.com/buger/jsonparser v1.1.2 // indirect
 	github.com/cespare/xxhash/v2 v2.3.0 // indirect
 	github.com/charmbracelet/anthropic-sdk-go v0.0.0-20260223140439-63879b0b8dab // indirect
 	github.com/charmbracelet/x/json v0.2.0 // indirect
 	github.com/charmbracelet/x/termios v0.1.1 // indirect
 	github.com/charmbracelet/x/windows v0.2.2 // indirect
+	github.com/cyphar/filepath-securejoin v0.4.1 // indirect
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 	github.com/dlclark/regexp2 v1.11.5 // indirect
 	github.com/ebitengine/purego v0.10.0 // indirect
@@ -136,7 +137,7 @@ require (
 	github.com/google/jsonschema-go v0.4.2 // indirect
 	github.com/google/s2a-go v0.1.9 // indirect
 	github.com/googleapis/enterprise-certificate-proxy v0.3.14 // indirect
-	github.com/googleapis/gax-go/v2 v2.17.0 // indirect
+	github.com/googleapis/gax-go/v2 v2.18.0 // indirect
 	github.com/gorilla/css v1.0.1 // indirect
 	github.com/gorilla/websocket v1.5.3 // indirect
 	github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
@@ -146,13 +147,13 @@ require (
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/kaptinlin/go-i18n v0.2.12 // indirect
 	github.com/kaptinlin/jsonpointer v0.4.17 // indirect
-	github.com/kaptinlin/jsonschema v0.7.5 // indirect
+	github.com/kaptinlin/jsonschema v0.7.6 // indirect
 	github.com/kaptinlin/messageformat-go v0.4.18 // indirect
 	github.com/klauspost/compress v1.18.4 // indirect
 	github.com/klauspost/cpuid/v2 v2.2.10 // indirect
 	github.com/klauspost/pgzip v1.2.6 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
-	github.com/mattn/go-runewidth v0.0.20 // indirect
+	github.com/mattn/go-runewidth v0.0.21 // indirect
 	github.com/mfridman/interpolate v0.0.2 // indirect
 	github.com/microcosm-cc/bluemonday v1.0.27 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
@@ -161,10 +162,12 @@ require (
 	github.com/muesli/mango-cobra v1.2.0 // indirect
 	github.com/muesli/mango-pflag v0.1.0 // indirect
 	github.com/muesli/roff v0.1.0 // indirect
+	github.com/ncruces/go-sqlite3-wasm v1.0.4-0.20260329114232-2491c387476c // indirect
 	github.com/ncruces/go-strftime v1.0.0 // indirect
 	github.com/ncruces/julianday v1.0.0 // indirect
 	github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
 	github.com/pierrec/lz4/v4 v4.1.25 // indirect
+	github.com/pjbgf/sha1cd v0.3.2 // indirect
 	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
 	github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
 	github.com/segmentio/asm v1.2.1 // indirect
@@ -175,7 +178,6 @@ require (
 	github.com/spf13/pflag v1.0.9 // indirect
 	github.com/swaggo/files/v2 v2.0.0 // indirect
 	github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect
-	github.com/tetratelabs/wazero v1.11.0 // indirect
 	github.com/tidwall/match v1.1.1 // indirect
 	github.com/tidwall/pretty v1.2.1 // indirect
 	github.com/u-root/u-root v0.14.1-0.20250807200646-5e7721023dc7 // indirect
@@ -194,17 +196,17 @@ require (
 	go.uber.org/multierr v1.11.0 // indirect
 	go.yaml.in/yaml/v4 v4.0.0-rc.3 // indirect
 	golang.org/x/crypto v0.49.0 // indirect
-	golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect
-	golang.org/x/image v0.36.0 // indirect
-	golang.org/x/mod v0.33.0 // indirect
+	golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect
+	golang.org/x/image v0.38.0 // indirect
+	golang.org/x/mod v0.34.0 // indirect
 	golang.org/x/oauth2 v0.36.0 // indirect
 	golang.org/x/term v0.41.0 // indirect
 	golang.org/x/time v0.15.0 // indirect
-	golang.org/x/tools v0.42.0 // indirect
-	google.golang.org/api v0.270.0 // indirect
-	google.golang.org/genai v1.50.0 // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
-	google.golang.org/grpc v1.79.2 // indirect
+	golang.org/x/tools v0.43.0 // indirect
+	google.golang.org/api v0.271.0 // indirect
+	google.golang.org/genai v1.51.0 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c // indirect
+	google.golang.org/grpc v1.79.3 // indirect
 	google.golang.org/protobuf v1.36.11 // indirect
 	gopkg.in/dnaeon/go-vcr.v4 v4.0.6-0.20251110073552-01de4eb40290 // indirect
 	gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect

go.sum 🔗

@@ -1,13 +1,13 @@
-charm.land/bubbles/v2 v2.0.0 h1:tE3eK/pHjmtrDiRdoC9uGNLgpopOd8fjhEe31B/ai5s=
-charm.land/bubbles/v2 v2.0.0/go.mod h1:rCHoleP2XhU8um45NTuOWBPNVHxnkXKTiZqcclL/qOI=
+charm.land/bubbles/v2 v2.1.0 h1:YSnNh5cPYlYjPxRrzs5VEn3vwhtEn3jVGRBT3M7/I0g=
+charm.land/bubbles/v2 v2.1.0/go.mod h1:l97h4hym2hvWBVfmJDtrEHHCtkIKeTEb3TTJ4ZOB3wY=
 charm.land/bubbletea/v2 v2.0.2 h1:4CRtRnuZOdFDTWSff9r8QFt/9+z6Emubz3aDMnf/dx0=
 charm.land/bubbletea/v2 v2.0.2/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ=
-charm.land/catwalk v0.31.0 h1:ci2LRf5Gy5BgbbQDN7cXEXOeNA2lP1sqVuXdUrAph3w=
-charm.land/catwalk v0.31.0/go.mod h1:+fqw/6YGNtvapvPy9vhwA/fAMxVjD2K8hVIKYov8Vhg=
+charm.land/catwalk v0.33.2 h1:Z6EtzewRcAkUvIH0vIduAhVDC4lwUe4AAD6GTlT78fk=
+charm.land/catwalk v0.33.2/go.mod h1:+fqw/6YGNtvapvPy9vhwA/fAMxVjD2K8hVIKYov8Vhg=
 charm.land/fang/v2 v2.0.1 h1:zQCM8JQJ1JnQX/66B5jlCYBUxL2as5JXQZ2KJ6EL0mY=
 charm.land/fang/v2 v2.0.1/go.mod h1:S1GmkpcvK+OB5w9caywUnJcsMew45Ot8FXqoz8ALrII=
-charm.land/fantasy v0.16.0 h1:vE/6sR9nPcSD8qXJXX6wR8NXjtWlBVAzwQmTh5pHVrs=
-charm.land/fantasy v0.16.0/go.mod h1:VZjpXVh7IgeiIzGQybEnKzd68ofDsRj94+kzH1ZCAfQ=
+charm.land/fantasy v0.17.1 h1:SQzfnyJPDuQWt6e//KKmQmEEXdqHMC0IZz10XwkLcEM=
+charm.land/fantasy v0.17.1/go.mod h1:FF5ALCCHETacHJPBqU42CtwMInYQ0ul52fdzIHQMbQk=
 charm.land/glamour/v2 v2.0.0 h1:IDBoqLEy7Hdpb9VOXN+khLP/XSxtJy1VsHuW/yF87+U=
 charm.land/glamour/v2 v2.0.0/go.mod h1:kjq9WB0s8vuUYZNYey2jp4Lgd9f4cKdzAw88FZtpj/w=
 charm.land/lipgloss/v2 v2.0.2 h1:xFolbF8JdpNkM2cEPTfXEcW1p6NRzOWTSamRfYEw8cs=
@@ -58,8 +58,8 @@ github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z
 github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
 github.com/aws/aws-sdk-go-v2 v1.41.4 h1:10f50G7WyU02T56ox1wWXq+zTX9I1zxG46HYuG1hH/k=
 github.com/aws/aws-sdk-go-v2 v1.41.4/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.6 h1:N4lRUXZpZ1KVEUn6hxtco/1d2lgYhNn1fHkkl8WhlyQ=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.6/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.7 h1:3kGOqnh1pPeddVa/E37XNTaWJ8W6vrbYV9lJEkCnhuY=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.7/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI=
 github.com/aws/aws-sdk-go-v2/config v1.32.12 h1:O3csC7HUGn2895eNrLytOJQdoL2xyJy0iYXhoZ1OmP0=
 github.com/aws/aws-sdk-go-v2/config v1.32.12/go.mod h1:96zTvoOFR4FURjI+/5wY1vc1ABceROO4lWgWJuxgy0g=
 github.com/aws/aws-sdk-go-v2/credentials v1.19.12 h1:oqtA6v+y5fZg//tcTWahyN9PEn5eDU/Wpvc2+kJ4aY8=
@@ -96,8 +96,8 @@ github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPn
 github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
 github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=
 github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
-github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
-github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
+github.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk=
+github.com/buger/jsonparser v1.1.2/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
 github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
 github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/charlievieth/fastwalk v1.0.14 h1:3Eh5uaFGwHZd8EGwTjJnSpBkfwfsak9h6ICgnWlhAyg=
@@ -146,6 +146,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6N
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
 github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
+github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
+github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
@@ -180,8 +182,8 @@ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66D
 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
 github.com/go-git/go-billy/v5 v5.8.0 h1:I8hjc3LbBlXTtVuFNJuwYuMiHvQJDq1AT6u4DwDzZG0=
 github.com/go-git/go-billy/v5 v5.8.0/go.mod h1:RpvI/rw4Vr5QA+Z60c6d6LXH0rYJo0uD5SqfmrrheCY=
-github.com/go-git/go-git/v5 v5.17.0 h1:AbyI4xf+7DsjINHMu35quAh4wJygKBKBuXVjV/pxesM=
-github.com/go-git/go-git/v5 v5.17.0/go.mod h1:f82C4YiLx+Lhi8eHxltLeGC5uBTXSFa6PC5WW9o4SjI=
+github.com/go-git/go-git/v5 v5.17.1 h1:WnljyxIzSj9BRRUlnmAU35ohDsjRK0EKmL0evDqi5Jk=
+github.com/go-git/go-git/v5 v5.17.1/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo=
 github.com/go-json-experiment/json v0.0.0-20260214004413-d219187c3433 h1:vymEbVwYFP/L05h5TKQxvkXoKxNvTpjxYKdF1Nlwuao=
 github.com/go-json-experiment/json v0.0.0-20260214004413-d219187c3433/go.mod h1:tphK2c80bpPhMOI4v6bIc2xWywPfbqi1Z06+RcrMkDg=
 github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
@@ -233,8 +235,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/enterprise-certificate-proxy v0.3.14 h1:yh8ncqsbUY4shRD5dA6RlzjJaT4hi3kII+zYw8wmLb8=
 github.com/googleapis/enterprise-certificate-proxy v0.3.14/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg=
-github.com/googleapis/gax-go/v2 v2.17.0 h1:RksgfBpxqff0EZkDWYuz9q/uWsTVz+kf43LsZ1J6SMc=
-github.com/googleapis/gax-go/v2 v2.17.0/go.mod h1:mzaqghpQp4JDh3HvADwrat+6M3MOIDp5YKHhb9PAgDY=
+github.com/googleapis/gax-go/v2 v2.18.0 h1:jxP5Uuo3bxm3M6gGtV94P4lliVetoCB4Wk2x8QA86LI=
+github.com/googleapis/gax-go/v2 v2.18.0/go.mod h1:uSzZN4a356eRG985CzJ3WfbFSpqkLTjsnhWGJR6EwrE=
 github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
 github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
 github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@@ -262,8 +264,8 @@ github.com/kaptinlin/go-i18n v0.2.12 h1:ywDsvb4KDFddMC2dpI/rrIzGU2mWUSvHmWUm9BMs
 github.com/kaptinlin/go-i18n v0.2.12/go.mod h1:pVcu9qsW5pOIOoZFJXesRYmLos1vMQrby70JPAoWmJU=
 github.com/kaptinlin/jsonpointer v0.4.17 h1:mY9k8ciWncxbsECyaxKnR0MdmxamNdp2tLQkAKVrtSk=
 github.com/kaptinlin/jsonpointer v0.4.17/go.mod h1:SsfsjqnHG5zuKo1DTBzk1VknaHlL4osHw+X9kZKukpU=
-github.com/kaptinlin/jsonschema v0.7.5 h1:jkK4a3NyzNoGlvu12CsL3IcqNMVa5sL51HPVa0nWcPY=
-github.com/kaptinlin/jsonschema v0.7.5/go.mod h1:3gIWnptl+SWMyfMR2r4TXXd0xsQZ1m50AKrwmcUONSg=
+github.com/kaptinlin/jsonschema v0.7.6 h1:UUMqZGFAk7nOzQsYAxvgygm4wpDp/nwXxA4VP9mCPCs=
+github.com/kaptinlin/jsonschema v0.7.6/go.mod h1:GGk/oE+F1lWUfYrzKaCf4QWZmMdytt0LL4XdFEFB0LE=
 github.com/kaptinlin/messageformat-go v0.4.18 h1:RBlHVWgZyoxTcUgGWBsl2AcyScq/urqbLZvzgryTmSI=
 github.com/kaptinlin/messageformat-go v0.4.18/go.mod h1:ntI3154RnqJgr7GaC+vZBnIExl2V3sv9selvRNNEM24=
 github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
@@ -281,8 +283,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
-github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
-github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
+github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4=
+github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
 github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
@@ -290,8 +292,8 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0
 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ=
-github.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
+github.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w=
+github.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
 github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
 github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg=
 github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
@@ -310,8 +312,10 @@ github.com/muesli/mango-pflag v0.1.0 h1:UADqbYgpUyRoBja3g6LUL+3LErjpsOwaC9ywvBWe
 github.com/muesli/mango-pflag v0.1.0/go.mod h1:YEQomTxaCUp8PrbhFh10UfbhbQrM/xJ4i2PB8VTLLW0=
 github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8=
 github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig=
-github.com/ncruces/go-sqlite3 v0.32.0 h1:hNBUXp88LrfQCsuyXLqWTbTUG35sUuktDsqhhgHvU20=
-github.com/ncruces/go-sqlite3 v0.32.0/go.mod h1:MIWTK60ONDl0oVY073zYvJP21C3Dly6P9bxVpgkLwdQ=
+github.com/ncruces/go-sqlite3 v0.33.2 h1:bzzdlEsURPqyQNU9OGKhYrL0k/9tEXrDCtNwa6n1aA0=
+github.com/ncruces/go-sqlite3 v0.33.2/go.mod h1:xhwGW9DTCj/XvJQAOn1oyodYFYN7/nsw5bTH+Y9wPyE=
+github.com/ncruces/go-sqlite3-wasm v1.0.4-0.20260329114232-2491c387476c h1:Fnw6J6r2trodoTlRk7mDo+ZXEnBSJFPmorGV7urtgvI=
+github.com/ncruces/go-sqlite3-wasm v1.0.4-0.20260329114232-2491c387476c/go.mod h1:eewd1iQhpv/1qDXP83cfDk06Bpbhmt3EspN/0krcy70=
 github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
 github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
 github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
@@ -321,10 +325,14 @@ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
 github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
+github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
+github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
 github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
 github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
 github.com/pierrec/lz4/v4 v4.1.25 h1:kocOqRffaIbU5djlIBr7Wh+cx82C0vtFb0fOurZHqD0=
 github.com/pierrec/lz4/v4 v4.1.25/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
+github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
+github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -335,8 +343,8 @@ github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/posthog/posthog-go v1.11.1 h1:P0MHlerMW9rNpjW+1szNsJ5HbdYJUv/9lF2DWZCHztE=
-github.com/posthog/posthog-go v1.11.1/go.mod h1:wB3/9Q7d9gGb1P/yf/Wri9VBlbP8oA8z++prRzL5OcY=
+github.com/posthog/posthog-go v1.11.2 h1:ApKTtOhIeWhUBc4ByO+mlbg2o0iZaEGJnJHX2QDnn5Q=
+github.com/posthog/posthog-go v1.11.2/go.mod h1:xsVOW9YImilUcazwPNEq4PJDqEZf2KeCS758zXjwkPg=
 github.com/pressly/goose/v3 v3.27.0 h1:/D30gVTuQhu0WsNZYbJi4DMOsx1lNq+6SkLe+Wp59BM=
 github.com/pressly/goose/v3 v3.27.0/go.mod h1:3ZBeCXqzkgIRvrEMDkYh1guvtoJTU5oMMuDdkutoM78=
 github.com/qjebbs/go-jsons v1.0.0-alpha.4 h1:Qsb4ohRUHQODIUAsJKdKJ/SIDbsO7oGOzsfy+h1yQZs=
@@ -391,8 +399,6 @@ github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI=
 github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg=
 github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk=
 github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o=
-github.com/tetratelabs/wazero v1.11.0 h1:+gKemEuKCTevU4d7ZTzlsvgd1uaToIDtlQlmNbwqYhA=
-github.com/tetratelabs/wazero v1.11.0/go.mod h1:eV28rsN8Q+xwjogd7f4/Pp4xFxO7uOGbLcD/LzB1wiU=
 github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
 github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
 github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
@@ -455,18 +461,18 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v
 golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
 golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
 golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
-golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
-golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
+golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA=
+golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ=
 golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
-golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4=
+golang.org/x/image v0.38.0 h1:5l+q+Y9JDC7mBOMjo4/aPhMDcxEptsX+Tt3GgRQRPuE=
+golang.org/x/image v0.38.0/go.mod h1:/3f6vaXC+6CEanU4KJxbcUZyEePbyKbaLoDOe4ehFYY=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
-golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
+golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
+golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -541,19 +547,19 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
-golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
-golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
+golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
+golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
 gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
-google.golang.org/api v0.270.0 h1:4rJZbIuWSTohczG9mG2ukSDdt9qKx4sSSHIydTN26L4=
-google.golang.org/api v0.270.0/go.mod h1:5+H3/8DlXpQWrSz4RjGGwz5HfJAQSEI8Bc6JqQNH77U=
-google.golang.org/genai v1.50.0 h1:yHKV/vjoeN9PJ3iF0ur4cBZco4N3Kl7j09rMq7XSoWk=
-google.golang.org/genai v1.50.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
-google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
-google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
+google.golang.org/api v0.271.0 h1:cIPN4qcUc61jlh7oXu6pwOQqbJW2GqYh5PS6rB2C/JY=
+google.golang.org/api v0.271.0/go.mod h1:CGT29bhwkbF+i11qkRUJb2KMKqcJ1hdFceEIRd9u64Q=
+google.golang.org/genai v1.51.0 h1:IZGuUqgfx40INv3hLFGCbOSGp0qFqm7LVmDghzNIYqg=
+google.golang.org/genai v1.51.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c h1:xgCzyF2LFIO/0X2UAoVRiXKU5Xg6VjToG4i2/ecSswk=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
+google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
+google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
 google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
 google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -599,8 +605,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
 modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
 modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
 modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
-modernc.org/sqlite v1.47.0 h1:R1XyaNpoW4Et9yly+I2EeX7pBza/w+pmYee/0HJDyKk=
-modernc.org/sqlite v1.47.0/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig=
+modernc.org/sqlite v1.48.0 h1:ElZyLop3Q2mHYk5IFPPXADejZrlHu7APbpB0sF78bq4=
+modernc.org/sqlite v1.48.0/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig=
 modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
 modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
 modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=

internal/agent/agent.go 🔗

@@ -364,7 +364,9 @@ func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy
 				Finished:         false,
 			}
 			currentAssistant.AddToolCall(toolCall)
-			return a.messages.Update(genCtx, *currentAssistant)
+			// Use parent ctx instead of genCtx to ensure the update succeeds
+			// even if the request is canceled mid-stream
+			return a.messages.Update(ctx, *currentAssistant)
 		},
 		OnRetry: func(err *fantasy.ProviderError, delay time.Duration) {
 			// TODO: implement
@@ -378,11 +380,15 @@ func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy
 				Finished:         true,
 			}
 			currentAssistant.AddToolCall(toolCall)
-			return a.messages.Update(genCtx, *currentAssistant)
+			// Use parent ctx instead of genCtx to ensure the update succeeds
+			// even if the request is canceled mid-stream
+			return a.messages.Update(ctx, *currentAssistant)
 		},
 		OnToolResult: func(result fantasy.ToolResultContent) error {
 			toolResult := a.convertToToolResult(result)
-			_, createMsgErr := a.messages.Create(genCtx, currentAssistant.SessionID, message.CreateMessageParams{
+			// Use parent ctx instead of genCtx to ensure the message is created
+			// even if the request is canceled mid-stream
+			_, createMsgErr := a.messages.Create(ctx, currentAssistant.SessionID, message.CreateMessageParams{
 				Role: message.Tool,
 				Parts: []message.ContentPart{
 					toolResult,
@@ -485,7 +491,7 @@ func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy
 			}
 			content := "There was an error while executing the tool"
 			if isCancelErr {
-				content = "Tool execution canceled by user"
+				content = "Error: user cancelled assistant tool calling"
 			} else if isPermissionErr {
 				content = "User denied permission"
 			}

internal/agent/coordinator.go 🔗

@@ -778,9 +778,8 @@ func (c *coordinator) buildGoogleVertexProvider(headers map[string]string, optio
 	return google.New(opts...)
 }
 
-func (c *coordinator) buildHyperProvider(baseURL, apiKey string) (fantasy.Provider, error) {
+func (c *coordinator) buildHyperProvider(apiKey string) (fantasy.Provider, error) {
 	opts := []hyper.Option{
-		hyper.WithBaseURL(baseURL),
 		hyper.WithAPIKey(apiKey),
 	}
 	if c.cfg.Config().Options.Debug {
@@ -842,7 +841,7 @@ func (c *coordinator) buildProvider(providerCfg config.ProviderConfig, model con
 		}
 		return c.buildOpenaiCompatProvider(baseURL, apiKey, headers, providerCfg.ExtraBody, providerCfg.ID, isSubAgent)
 	case hyper.Name:
-		return c.buildHyperProvider(baseURL, apiKey)
+		return c.buildHyperProvider(apiKey)
 	default:
 		return nil, fmt.Errorf("provider type not supported: %q", providerCfg.Type)
 	}

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

@@ -20,6 +20,7 @@ These rules override everything else. Follow them strictly:
 
 <communication_style>
 Keep responses minimal:
+- ALWAYS think and respond in the same spoken language the prompt was written in. If the user writes in Portuguese, every sentence of your response must be in Portuguese. If the user writes in English, respond in English, and so on.
 - Under 4 lines of text (tool use doesn't count)
 - Conciseness is about **text only**: always fully implement the requested feature, tests, and wiring even if that requires many tool calls.
 - No preamble ("Here's...", "I'll...")
@@ -249,7 +250,7 @@ Common errors:
 <memory_instructions>
 Memory files store commands, preferences, and codebase info. Update them when you discover:
 - Build/test/lint commands
-- Code style preferences  
+- Code style preferences
 - Important codebase patterns
 - Useful project information
 </memory_instructions>

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

@@ -2,7 +2,7 @@ Analyze this codebase and create/update **{{.Config.Options.InitializeAs}}** to
 
 **First**: Check if directory is empty or contains only config files. If so, stop and say "Directory appears empty or only contains config. Add source code first, then run this command to generate {{.Config.Options.InitializeAs}}."
 
-**Goal**: Document what an agent needs to know to work in this codebase - commands, patterns, conventions, gotchas.
+**Goal**: Document what an agent needs to know to work in this codebase - commands, patterns, conventions, gotchas, overall architecture, how components fit together
 
 **Discovery process**:
 
@@ -10,18 +10,20 @@ Analyze this codebase and create/update **{{.Config.Options.InitializeAs}}** to
 2. Look for existing rule files (`.cursor/rules/*.md`, `.cursorrules`, `.github/copilot-instructions.md`, `claude.md`, `agents.md`) - only read if they exist
 3. Identify project type from config files and directory structure
 4. Find build/test/lint commands from config files, scripts, Makefiles, or CI configs
-5. Read representative source files to understand code patterns
+5. Read representative source files to understand code patterns, architecture, control/data flow
 6. If {{.Config.Options.InitializeAs}} exists, read and improve it
 
 **Content to include**:
 
 - Essential commands (build, test, run, deploy, etc.) - whatever is relevant for this project
-- Code organization and structure
+- Code organization and structure, application architecture and control/data flow
 - Naming conventions and style patterns
 - Testing approach and patterns
 - Important gotchas or non-obvious patterns
 - Any project-specific context from existing rule files
 
+**Note:** LLM agents learn and adapt to their context as they obtain it, so mentioning obvious details they would immediately pick up from reading a file or two is actively detrimental. Keep the principles of progressive disclosure in mind and focus primarily on non-obvious knowledge that saves the agent from trial-and-error discovery: gotchas, implicit conventions, commands with surprising flags, and context that isn't self-evident from the code in a single file.
+
 **Format**: Clear markdown sections. Use your judgment on structure based on what you find. Aim for completeness over brevity - include everything an agent would need to know.
 
 **Critical**: Only document what you actually observe. Never invent commands, patterns, or conventions. If you can't find something, don't include it.

internal/agent/templates/title.md 🔗

@@ -1,10 +1,11 @@
-you will generate a short title based on the first message a user begins a conversation with
+You will generate a short title based on the first message a user begins a conversation with.
 
 <rules>
-- ensure it is not more than 50 characters long
-- the title should be a summary of the user's message
-- it should be one line long
-- do not use quotes or colons
-- the entire text you return will be used as the title
-- never return anything that is more than one sentence (one line) long
+- Keep the title in the same language that the user wrote their message in.
+- Ensure it is not more than 50 characters long.
+- The title should be a summary of the user's message.
+- It should be one line long.
+- Do not use quotes or colons.
+- The entire text you return will be used as the title.
+- Never return anything that is more than one sentence (one line) long.
 </rules>

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

@@ -26,52 +26,43 @@ interactions:
     uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01NCBUPGM1ZzefNsxK3oAZsz","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","inference_geo":"not_available"}}     }
+      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01DtaEo6K6Jtip2sMvGuVcs5","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","inference_geo":"not_available"}}}
 
       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: ping
       data: {"type": "ping"}
 
       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":" test"}    }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":".txt file"}        }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" with hello"}             }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" bash content"}  }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" test.txt file with hello bash content"}   }
 
       event: content_block_stop
-      data: {"type":"content_block_stop","index":0               }
+      data: {"type":"content_block_stop","index":0   }
 
       event: message_delta
-      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":152,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":12}   }
+      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":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: 580.853041ms
+    duration: 580.545416ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52585
+    content_length: 52817
     host: ""

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

@@ -26,49 +26,43 @@ interactions:
     uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01HcFVhDJ3LAx7YJAek2tnEX","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","inference_geo":"not_available"}}          }
+      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_017P1SJWwhE4ejMQeJw9zZE3","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","inference_geo":"not_available"}}             }
 
       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: ping
       data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Download"}         }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Download"}   }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" and"}       }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" save example"}             }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":".txt file"}              }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" and save example.txt file"}   }
 
       event: content_block_stop
-      data: {"type":"content_block_stop","index":0           }
+      data: {"type":"content_block_stop","index":0    }
 
       event: message_delta
-      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":160,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":10}}
+      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":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: 458.520167ms
+    duration: 485.789125ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52610
+    content_length: 52842
     host: ""

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

@@ -23,52 +23,45 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
-    uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_019yRu75N7cyTTHykxDghwJc","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","inference_geo":"not_available"}}      }
+      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_015nL1HBJZUm5axuGBKq86fq","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":3,"service_tier":"standard","inference_geo":"not_available"}}       }
 
       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: ping
       data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Check"}      }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" if"}           }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" example"}              }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Fetch HTML"}       }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":".html contains \"John Doe\""}             }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" and search for John Doe"}    }
 
       event: content_block_stop
-      data: {"type":"content_block_stop","index":0          }
+      data: {"type":"content_block_stop","index":0      }
 
       event: message_delta
-      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":167,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":14}       }
+      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":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: 446.485541ms
+    duration: 755.306ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52628
+    content_length: 52860
     host: ""

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

@@ -26,49 +26,43 @@ interactions:
     uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01HC4LX9pv7pQ8XXNZwBNJho","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","inference_geo":"not_available"}}         }
+      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01PsvZKYEKUZb9cyoxEW1NSm","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","inference_geo":"not_available"}}        }
 
       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: ping
       data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Finding"}            }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Finding"}          }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Go"}  }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" files 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":" .go files with 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":8}          }
+      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: 858.447625ms
+    duration: 516.836834ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52546
+    content_length: 52778
     host: ""

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

@@ -26,46 +26,43 @@ interactions:
     uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01HQQmnr4yHdSBMG5kdExyF2","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":1,"service_tier":"standard","inference_geo":"not_available"}}          }
+      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01JX9C9a3C3mcZYmBfvTCXLZ","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":3,"service_tier":"standard","inference_geo":"not_available"}}       }
 
       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: ping
       data: {"type": "ping"}
 
       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":"Grep search"} }
 
       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 'package' in go files"}            }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" for 'package' in Go 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":13}      }
+      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":14}               }
 
       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: 451.462041ms
+    duration: 598.943875ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52544
+    content_length: 52776
     host: ""

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

@@ -26,49 +26,43 @@ interactions:
     uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_016ZF7o5tSUmiNsMcT2yvErw","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","inference_geo":"not_available"}}     }
+      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01EZU8M1DU1DogUtWnVk1e6x","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":2,"service_tier":"standard","inference_geo":"not_available"}}            }
 
       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: ping
       data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Using"}               }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Listing"}         }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" ls"} }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" command"} }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" to list files"}}
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" files with ls command"}  }
 
       event: content_block_stop
-      data: {"type":"content_block_stop","index":0             }
+      data: {"type":"content_block_stop","index":0               }
 
       event: message_delta
-      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":140,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":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":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: 434.346709ms
+    duration: 584.570041ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52538
+    content_length: 52770
     host: ""

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

@@ -26,7 +26,7 @@ interactions:
     uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01DEiHkcPX9joxDtDrsGCY3S","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","inference_geo":"not_available"}}  }
+      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01Gfcq25Lk1PgEAVWHUChno8","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","inference_geo":"not_available"}}               }
 
       event: content_block_start
       data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}   }
@@ -35,43 +35,34 @@ interactions:
       data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Mult"}}
+      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 Hello"}     }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" World"}  }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" to Hello Crush in"}      }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" main.go"} }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"iedit Hello World to Hello Crush with comment"}              }
 
       event: content_block_stop
-      data: {"type":"content_block_stop","index":0               }
+      data: {"type":"content_block_stop","index":0   }
 
       event: message_delta
-      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":170,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":17}         }
+      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":14}  }
 
       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: 469.534792ms
+    duration: 520.459542ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52624
+    content_length: 52856
     host: ""

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

@@ -26,58 +26,43 @@ interactions:
     uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_013JcAgtbnTMEL4aFdyD4MMK","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":1,"service_tier":"standard","inference_geo":"not_available"}}        }
+      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01S8DJt5aBFko4VZKAw5JK1q","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":3,"service_tier":"standard","inference_geo":"not_available"}}      }
 
       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: ping
       data: {"type": "ping"}
 
       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":"Glob ."}       }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" files"}         }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" glob"}    }
-
-      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":" parallel"}   }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" ls directory"}            }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" listing"}           }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"go files and ls directory in parallel"}       }
 
       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":11}         }
+      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":13}          }
 
       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.720958ms
+    duration: 584.945042ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52635
+    content_length: 52867
     host: ""

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

@@ -26,49 +26,43 @@ interactions:
     uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01XmjM7aL79Ah9inAJ6FKFSr","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","inference_geo":"not_available"}}  }
+      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01LtJfXoxrXXhX2NZCJRzw7i","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","inference_geo":"not_available"}}      }
 
       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: ping
       data: {"type": "ping"}
 
       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":"Read"}              }
 
       event: content_block_delta
-      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":" File"}        }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Review"}   }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" the go mod"}          }
 
       event: content_block_stop
-      data: {"type":"content_block_stop","index":0          }
+      data: {"type":"content_block_stop","index":0            }
 
       event: message_delta
-      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":134,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":7}     }
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":134,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":7}            }
 
       event: message_stop
-      data: {"type":"message_stop"     }
+      data: {"type":"message_stop"      }
 
     headers:
       Content-Type:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 614.432792ms
+    duration: 564.084541ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52508
+    content_length: 52740
     host: ""

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

@@ -26,40 +26,43 @@ interactions:
     uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01UUWs1TkN4VRwXg5qqAYi4x","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","inference_geo":"not_available"}}      }
+      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_011rMH49V6yKTZeVv8uuCToD","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","inference_geo":"not_available"}}        }
 
       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: ping
       data: {"type": "ping"}
 
       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":"New"}       }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Conversation"}   }
 
       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":131,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":4}        }
+      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: 464.945084ms
+    duration: 892.834ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52498
+    content_length: 52730
     host: ""

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

@@ -26,31 +26,25 @@ interactions:
     uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01Ndi9GYfffhiodY599f7iFx","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":2,"service_tier":"standard","inference_geo":"not_available"}}          }
+      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01EKQEbCC8jc88SBjmjhi5jz","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":2,"service_tier":"standard","inference_geo":"not_available"}}           }
 
       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: ping
       data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Searching"}            }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Searching"}  }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" for func"}}
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" main in Go repositories with"}    }
-
-      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 func main in Go repositories with Sourcegraph"}         }
 
       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":16}              }
+      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":16}      }
 
       event: message_stop
       data: {"type":"message_stop"        }
@@ -60,15 +54,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 1.13498575s
+    duration: 787.54775ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52558
+    content_length: 52790
     host: ""

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

@@ -23,103 +23,45 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
-    uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01DR6im8rp6CvrbFpFMDz9g7","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","inference_geo":"not_available"}} }
+      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_013oCKmsTTzHR8ghNKXJdns6","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","inference_geo":"not_available"}} }
 
       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: ping
       data: {"type": "ping"}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Update"}        }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" main"}             }
-
-      event: 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":"Update"}           }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" from crush"}        }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" main.go print to say hello from crush"}             }
 
       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":10}  }
+      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":13}       }
 
       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: 470.455ms
+    duration: 684.454333ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52564
-    host: ""

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

@@ -26,52 +26,43 @@ interactions:
     uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01TYYgbCvYvFDfxiDyMKbZuC","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","inference_geo":"not_available"}}   }
+      data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01JQwDhoANA7GJSndUgASpAs","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","inference_geo":"not_available"}} }
 
       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: ping
       data: {"type": "ping"}
 
       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":"Creating"}}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" config"}      }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":".json file"}              }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" with test"}}
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" data"}             }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" config.json file with write command"}   }
 
       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: 807.968541ms
+    duration: 525.598417ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52601
+    content_length: 52833
     host: ""

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

@@ -24,25 +24,25 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-DIgbv0pTSe1Khfah2QQT8m4hsLZHS","object":"chat.completion.chunk","created":1773346071,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"XNeud2NVXIfn5k"}
+      data: {"id":"chatcmpl-DNLTI1nJf8f5pkrWwpaU26SDMJULW","object":"chat.completion.chunk","created":1774456452,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_92d15debfd","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ak9gymROcqmixL"}
 
-      data: {"id":"chatcmpl-DIgbv0pTSe1Khfah2QQT8m4hsLZHS","object":"chat.completion.chunk","created":1773346071,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":"Create"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"asUFZQqxyC"}
+      data: {"id":"chatcmpl-DNLTI1nJf8f5pkrWwpaU26SDMJULW","object":"chat.completion.chunk","created":1774456452,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_92d15debfd","choices":[{"index":0,"delta":{"content":"Creating"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"0CjjkejY"}
 
-      data: {"id":"chatcmpl-DIgbv0pTSe1Khfah2QQT8m4hsLZHS","object":"chat.completion.chunk","created":1773346071,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"R9PoRhaiu1f2AX"}
+      data: {"id":"chatcmpl-DNLTI1nJf8f5pkrWwpaU26SDMJULW","object":"chat.completion.chunk","created":1774456452,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_92d15debfd","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"YIpzKHBxvDl6Dg"}
 
-      data: {"id":"chatcmpl-DIgbv0pTSe1Khfah2QQT8m4hsLZHS","object":"chat.completion.chunk","created":1773346071,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"W1xBbRdHXUF"}
+      data: {"id":"chatcmpl-DNLTI1nJf8f5pkrWwpaU26SDMJULW","object":"chat.completion.chunk","created":1774456452,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_92d15debfd","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"EXA8nGCmQ0U"}
 
-      data: {"id":"chatcmpl-DIgbv0pTSe1Khfah2QQT8m4hsLZHS","object":"chat.completion.chunk","created":1773346071,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"RkrqMVn7kRO"}
+      data: {"id":"chatcmpl-DNLTI1nJf8f5pkrWwpaU26SDMJULW","object":"chat.completion.chunk","created":1774456452,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_92d15debfd","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"uyRGm6tV5kIYK"}
 
-      data: {"id":"chatcmpl-DIgbv0pTSe1Khfah2QQT8m4hsLZHS","object":"chat.completion.chunk","created":1773346071,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Content"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"zE7JYVBh"}
+      data: {"id":"chatcmpl-DNLTI1nJf8f5pkrWwpaU26SDMJULW","object":"chat.completion.chunk","created":1774456452,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_92d15debfd","choices":[{"index":0,"delta":{"content":" Bash"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ffnz0HSlz0Q"}
 
-      data: {"id":"chatcmpl-DIgbv0pTSe1Khfah2QQT8m4hsLZHS","object":"chat.completion.chunk","created":1773346071,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ZQgSormHvSpRP"}
+      data: {"id":"chatcmpl-DNLTI1nJf8f5pkrWwpaU26SDMJULW","object":"chat.completion.chunk","created":1774456452,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_92d15debfd","choices":[{"index":0,"delta":{"content":" Without"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"idN9vNdm"}
 
-      data: {"id":"chatcmpl-DIgbv0pTSe1Khfah2QQT8m4hsLZHS","object":"chat.completion.chunk","created":1773346071,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Bash"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"k3Y3oANLYNy"}
+      data: {"id":"chatcmpl-DNLTI1nJf8f5pkrWwpaU26SDMJULW","object":"chat.completion.chunk","created":1774456452,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_92d15debfd","choices":[{"index":0,"delta":{"content":" Timestamp"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"n0gbdI"}
 
-      data: {"id":"chatcmpl-DIgbv0pTSe1Khfah2QQT8m4hsLZHS","object":"chat.completion.chunk","created":1773346071,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"Wx5pDuKbv6"}
+      data: {"id":"chatcmpl-DNLTI1nJf8f5pkrWwpaU26SDMJULW","object":"chat.completion.chunk","created":1774456452,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_92d15debfd","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"wYOgaaelio"}
 
-      data: {"id":"chatcmpl-DIgbv0pTSe1Khfah2QQT8m4hsLZHS","object":"chat.completion.chunk","created":1773346071,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[],"usage":{"prompt_tokens":145,"completion_tokens":7,"total_tokens":152,"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":"GMNsrdtfCMVZvP"}
+      data: {"id":"chatcmpl-DNLTI1nJf8f5pkrWwpaU26SDMJULW","object":"chat.completion.chunk","created":1774456452,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_92d15debfd","choices":[],"usage":{"prompt_tokens":145,"completion_tokens":7,"total_tokens":152,"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":"eVXTQAUN3DWBYa"}
 
       data: [DONE]
 
@@ -51,15 +51,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 590.488833ms
+    duration: 1.319103375s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50935
+    content_length: 51167
     host: ""

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

@@ -24,23 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-DIgcBCEsQeF7sIYGZFHfvKWv36Jv4","object":"chat.completion.chunk","created":1773346087,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_7c4b976237","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"L6S2S5FbyKuB2Q"}
+      data: {"id":"chatcmpl-DNLTU6WoRMEDEaIrNCUPuvyWb9Abb","object":"chat.completion.chunk","created":1774456464,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_9894c391cd","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"l53a83AoSNOotM"}
 
-      data: {"id":"chatcmpl-DIgcBCEsQeF7sIYGZFHfvKWv36Jv4","object":"chat.completion.chunk","created":1773346087,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_7c4b976237","choices":[{"index":0,"delta":{"content":"Downloading"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"OkXl8"}
+      data: {"id":"chatcmpl-DNLTU6WoRMEDEaIrNCUPuvyWb9Abb","object":"chat.completion.chunk","created":1774456464,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_9894c391cd","choices":[{"index":0,"delta":{"content":"Download"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"0fszLlLN"}
 
-      data: {"id":"chatcmpl-DIgcBCEsQeF7sIYGZFHfvKWv36Jv4","object":"chat.completion.chunk","created":1773346087,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_7c4b976237","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"KMyiVw3C3PUl"}
+      data: {"id":"chatcmpl-DNLTU6WoRMEDEaIrNCUPuvyWb9Abb","object":"chat.completion.chunk","created":1774456464,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_9894c391cd","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"wO4YkhksjnRn"}
 
-      data: {"id":"chatcmpl-DIgcBCEsQeF7sIYGZFHfvKWv36Jv4","object":"chat.completion.chunk","created":1773346087,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_7c4b976237","choices":[{"index":0,"delta":{"content":" Saving"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"LmMpnjEv2"}
+      data: {"id":"chatcmpl-DNLTU6WoRMEDEaIrNCUPuvyWb9Abb","object":"chat.completion.chunk","created":1774456464,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_9894c391cd","choices":[{"index":0,"delta":{"content":" Save"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ehnIUsLCeVj"}
 
-      data: {"id":"chatcmpl-DIgcBCEsQeF7sIYGZFHfvKWv36Jv4","object":"chat.completion.chunk","created":1773346087,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_7c4b976237","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"dJNPJ5bRg2cKOx"}
+      data: {"id":"chatcmpl-DNLTU6WoRMEDEaIrNCUPuvyWb9Abb","object":"chat.completion.chunk","created":1774456464,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_9894c391cd","choices":[{"index":0,"delta":{"content":" Example"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Yn10h99T"}
 
-      data: {"id":"chatcmpl-DIgcBCEsQeF7sIYGZFHfvKWv36Jv4","object":"chat.completion.chunk","created":1773346087,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_7c4b976237","choices":[{"index":0,"delta":{"content":" TXT"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"QrEQMWUTcVaA"}
+      data: {"id":"chatcmpl-DNLTU6WoRMEDEaIrNCUPuvyWb9Abb","object":"chat.completion.chunk","created":1774456464,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_9894c391cd","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Q7kQCbytAsZ"}
 
-      data: {"id":"chatcmpl-DIgcBCEsQeF7sIYGZFHfvKWv36Jv4","object":"chat.completion.chunk","created":1773346087,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_7c4b976237","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Y9rCwhO6q6p"}
+      data: {"id":"chatcmpl-DNLTU6WoRMEDEaIrNCUPuvyWb9Abb","object":"chat.completion.chunk","created":1774456464,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_9894c391cd","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"mYzATcqPdL"}
 
-      data: {"id":"chatcmpl-DIgcBCEsQeF7sIYGZFHfvKWv36Jv4","object":"chat.completion.chunk","created":1773346087,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_7c4b976237","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"ktdWarf7iR"}
-
-      data: {"id":"chatcmpl-DIgcBCEsQeF7sIYGZFHfvKWv36Jv4","object":"chat.completion.chunk","created":1773346087,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_7c4b976237","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":"lw2dl4V3D9MVgE"}
+      data: {"id":"chatcmpl-DNLTU6WoRMEDEaIrNCUPuvyWb9Abb","object":"chat.completion.chunk","created":1774456464,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_9894c391cd","choices":[],"usage":{"prompt_tokens":148,"completion_tokens":5,"total_tokens":153,"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":"gwosEop7ZWtmER"}
 
       data: [DONE]
 
@@ -49,15 +47,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 427.27125ms
+    duration: 636.694292ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50960
+    content_length: 51192
     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-DIgcTmwGKAdkXj8gSUv69bn6kRuIv","object":"chat.completion.chunk","created":1773346105,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"q95A3H5JOC2nwc"}
+      data: {"id":"chatcmpl-DNLTeIbn5fEbZKj1GmomUBGrkUOG2","object":"chat.completion.chunk","created":1774456474,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_6c2e0b41b2","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Hq6GJ6CHHlClRp"}
 
-      data: {"id":"chatcmpl-DIgcTmwGKAdkXj8gSUv69bn6kRuIv","object":"chat.completion.chunk","created":1773346105,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":"Checking"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"D0lLDihL"}
+      data: {"id":"chatcmpl-DNLTeIbn5fEbZKj1GmomUBGrkUOG2","object":"chat.completion.chunk","created":1774456474,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_6c2e0b41b2","choices":[{"index":0,"delta":{"content":"Check"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"worOQrqWVBu"}
 
-      data: {"id":"chatcmpl-DIgcTmwGKAdkXj8gSUv69bn6kRuIv","object":"chat.completion.chunk","created":1773346105,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":" for"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"JRHjAu65Ko0t"}
+      data: {"id":"chatcmpl-DNLTeIbn5fEbZKj1GmomUBGrkUOG2","object":"chat.completion.chunk","created":1774456474,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_6c2e0b41b2","choices":[{"index":0,"delta":{"content":" HTML"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"vcBLE6ESli8"}
 
-      data: {"id":"chatcmpl-DIgcTmwGKAdkXj8gSUv69bn6kRuIv","object":"chat.completion.chunk","created":1773346105,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"SgnzoZUn6ipAdA"}
+      data: {"id":"chatcmpl-DNLTeIbn5fEbZKj1GmomUBGrkUOG2","object":"chat.completion.chunk","created":1774456474,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_6c2e0b41b2","choices":[{"index":0,"delta":{"content":" for"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"GZToq93sljwz"}
 
-      data: {"id":"chatcmpl-DIgcTmwGKAdkXj8gSUv69bn6kRuIv","object":"chat.completion.chunk","created":1773346105,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":"John"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"J1k2pGqzS0OB"}
+      data: {"id":"chatcmpl-DNLTeIbn5fEbZKj1GmomUBGrkUOG2","object":"chat.completion.chunk","created":1774456474,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_6c2e0b41b2","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"0tMeHwodUIoBAL"}
 
-      data: {"id":"chatcmpl-DIgcTmwGKAdkXj8gSUv69bn6kRuIv","object":"chat.completion.chunk","created":1773346105,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":" Doe"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"LYbaXQklKnYy"}
+      data: {"id":"chatcmpl-DNLTeIbn5fEbZKj1GmomUBGrkUOG2","object":"chat.completion.chunk","created":1774456474,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_6c2e0b41b2","choices":[{"index":0,"delta":{"content":"John"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"lwwoxREHB44n"}
 
-      data: {"id":"chatcmpl-DIgcTmwGKAdkXj8gSUv69bn6kRuIv","object":"chat.completion.chunk","created":1773346105,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Ar2v6w44ZhjQoYc"}
+      data: {"id":"chatcmpl-DNLTeIbn5fEbZKj1GmomUBGrkUOG2","object":"chat.completion.chunk","created":1774456474,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_6c2e0b41b2","choices":[{"index":0,"delta":{"content":" Doe"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"wa4Twt6Jpmzi"}
 
-      data: {"id":"chatcmpl-DIgcTmwGKAdkXj8gSUv69bn6kRuIv","object":"chat.completion.chunk","created":1773346105,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"a6qkfWzXtBcKA"}
+      data: {"id":"chatcmpl-DNLTeIbn5fEbZKj1GmomUBGrkUOG2","object":"chat.completion.chunk","created":1774456474,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_6c2e0b41b2","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"yI2ZApnrOmL9JXX"}
 
-      data: {"id":"chatcmpl-DIgcTmwGKAdkXj8gSUv69bn6kRuIv","object":"chat.completion.chunk","created":1773346105,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":" Online"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"s6ocv3ua2"}
+      data: {"id":"chatcmpl-DNLTeIbn5fEbZKj1GmomUBGrkUOG2","object":"chat.completion.chunk","created":1774456474,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_6c2e0b41b2","choices":[{"index":0,"delta":{"content":" Presence"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"QhiyrsY"}
 
-      data: {"id":"chatcmpl-DIgcTmwGKAdkXj8gSUv69bn6kRuIv","object":"chat.completion.chunk","created":1773346105,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":" HTML"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"x2qzNmJwyZN"}
+      data: {"id":"chatcmpl-DNLTeIbn5fEbZKj1GmomUBGrkUOG2","object":"chat.completion.chunk","created":1774456474,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_6c2e0b41b2","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"SJVcozKkm5"}
 
-      data: {"id":"chatcmpl-DIgcTmwGKAdkXj8gSUv69bn6kRuIv","object":"chat.completion.chunk","created":1773346105,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":" Content"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"6tqBHzn7"}
-
-      data: {"id":"chatcmpl-DIgcTmwGKAdkXj8gSUv69bn6kRuIv","object":"chat.completion.chunk","created":1773346105,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"XtbymLtf5u"}
-
-      data: {"id":"chatcmpl-DIgcTmwGKAdkXj8gSUv69bn6kRuIv","object":"chat.completion.chunk","created":1773346105,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","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":"Nts4cEvzbv33W"}
+      data: {"id":"chatcmpl-DNLTeIbn5fEbZKj1GmomUBGrkUOG2","object":"chat.completion.chunk","created":1774456474,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_6c2e0b41b2","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":"ObBF1NIOkET0EP"}
 
       data: [DONE]
 
@@ -57,15 +53,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 1.14852275s
+    duration: 1.414687416s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50978
+    content_length: 51210
     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-DIgclnQPkNxEljF48SWE8JwL4QqK4","object":"chat.completion.chunk","created":1773346123,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"cfoaVgskwEMm1A"}
+      data: {"id":"chatcmpl-DNLTk0x7QU5SmrHLCW8nHq68WApVi","object":"chat.completion.chunk","created":1774456480,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"pMtKY4sEu1jtpF"}
 
-      data: {"id":"chatcmpl-DIgclnQPkNxEljF48SWE8JwL4QqK4","object":"chat.completion.chunk","created":1773346123,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":"Finding"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"w4aoChnGJ"}
+      data: {"id":"chatcmpl-DNLTk0x7QU5SmrHLCW8nHq68WApVi","object":"chat.completion.chunk","created":1774456480,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":"Finding"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"SxnCdjkrg"}
 
-      data: {"id":"chatcmpl-DIgclnQPkNxEljF48SWE8JwL4QqK4","object":"chat.completion.chunk","created":1773346123,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" ."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"KhMLocySx1RQuA"}
+      data: {"id":"chatcmpl-DNLTk0x7QU5SmrHLCW8nHq68WApVi","object":"chat.completion.chunk","created":1774456480,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" ."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"4zPlBnZhMTifrL"}
 
-      data: {"id":"chatcmpl-DIgclnQPkNxEljF48SWE8JwL4QqK4","object":"chat.completion.chunk","created":1773346123,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":"go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"7vdXUA1mdqHC4p"}
+      data: {"id":"chatcmpl-DNLTk0x7QU5SmrHLCW8nHq68WApVi","object":"chat.completion.chunk","created":1774456480,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":"go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"SUef5HGA4b8Cft"}
 
-      data: {"id":"chatcmpl-DIgclnQPkNxEljF48SWE8JwL4QqK4","object":"chat.completion.chunk","created":1773346123,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"vhERhjUtDP"}
+      data: {"id":"chatcmpl-DNLTk0x7QU5SmrHLCW8nHq68WApVi","object":"chat.completion.chunk","created":1774456480,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Algj74QWfR"}
 
-      data: {"id":"chatcmpl-DIgclnQPkNxEljF48SWE8JwL4QqK4","object":"chat.completion.chunk","created":1773346123,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Using"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"IZdmx5EFhP"}
+      data: {"id":"chatcmpl-DNLTk0x7QU5SmrHLCW8nHq68WApVi","object":"chat.completion.chunk","created":1774456480,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"X9LMrHw9A8o"}
 
-      data: {"id":"chatcmpl-DIgclnQPkNxEljF48SWE8JwL4QqK4","object":"chat.completion.chunk","created":1773346123,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Glob"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"XRGDA3U054d"}
+      data: {"id":"chatcmpl-DNLTk0x7QU5SmrHLCW8nHq68WApVi","object":"chat.completion.chunk","created":1774456480,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Glob"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"RovWvD6dTPy"}
 
-      data: {"id":"chatcmpl-DIgclnQPkNxEljF48SWE8JwL4QqK4","object":"chat.completion.chunk","created":1773346123,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"L6KrfgAcH62KR"}
+      data: {"id":"chatcmpl-DNLTk0x7QU5SmrHLCW8nHq68WApVi","object":"chat.completion.chunk","created":1774456480,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"zPD1fBiTLB8uW"}
 
-      data: {"id":"chatcmpl-DIgclnQPkNxEljF48SWE8JwL4QqK4","object":"chat.completion.chunk","created":1773346123,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Current"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"xuOafesK"}
+      data: {"id":"chatcmpl-DNLTk0x7QU5SmrHLCW8nHq68WApVi","object":"chat.completion.chunk","created":1774456480,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Current"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"PWReXPw7"}
 
-      data: {"id":"chatcmpl-DIgclnQPkNxEljF48SWE8JwL4QqK4","object":"chat.completion.chunk","created":1773346123,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Directory"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"vZGKrG"}
+      data: {"id":"chatcmpl-DNLTk0x7QU5SmrHLCW8nHq68WApVi","object":"chat.completion.chunk","created":1774456480,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Directory"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"26mLkk"}
 
-      data: {"id":"chatcmpl-DIgclnQPkNxEljF48SWE8JwL4QqK4","object":"chat.completion.chunk","created":1773346123,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"XFRL0WkCPj"}
+      data: {"id":"chatcmpl-DNLTk0x7QU5SmrHLCW8nHq68WApVi","object":"chat.completion.chunk","created":1774456480,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"dtsbQhSSKo"}
 
-      data: {"id":"chatcmpl-DIgclnQPkNxEljF48SWE8JwL4QqK4","object":"chat.completion.chunk","created":1773346123,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","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":"EDRwFgK6z3hAbw"}
+      data: {"id":"chatcmpl-DNLTk0x7QU5SmrHLCW8nHq68WApVi","object":"chat.completion.chunk","created":1774456480,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","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":"g4ryvzsHRzZXou"}
 
       data: [DONE]
 
@@ -55,15 +55,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 519.51625ms
+    duration: 714.728166ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50896
+    content_length: 51128
     host: ""

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

@@ -24,29 +24,33 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-DIgcuUeVNoSMAoX47EemdZSCJTZzY","object":"chat.completion.chunk","created":1773346132,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"iSldZE4sXLjbM2"}
+      data: {"id":"chatcmpl-DNLTpKJVyp5Lf7K0hb9g1oCeQ1Jf3","object":"chat.completion.chunk","created":1774456485,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"uYyTiIQz0zgplw"}
 
-      data: {"id":"chatcmpl-DIgcuUeVNoSMAoX47EemdZSCJTZzY","object":"chat.completion.chunk","created":1773346132,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":"Searching"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"NEct4Kc"}
+      data: {"id":"chatcmpl-DNLTpKJVyp5Lf7K0hb9g1oCeQ1Jf3","object":"chat.completion.chunk","created":1774456485,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":"Using"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"DCMpreR57CN"}
 
-      data: {"id":"chatcmpl-DIgcuUeVNoSMAoX47EemdZSCJTZzY","object":"chat.completion.chunk","created":1773346132,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"5H5Dj14eWE7hTh"}
+      data: {"id":"chatcmpl-DNLTpKJVyp5Lf7K0hb9g1oCeQ1Jf3","object":"chat.completion.chunk","created":1774456485,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Gre"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"vhhdv4cLF5gE"}
 
-      data: {"id":"chatcmpl-DIgcuUeVNoSMAoX47EemdZSCJTZzY","object":"chat.completion.chunk","created":1773346132,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":"package"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"9Ctm5HZkk"}
+      data: {"id":"chatcmpl-DNLTpKJVyp5Lf7K0hb9g1oCeQ1Jf3","object":"chat.completion.chunk","created":1774456485,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":"p"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"buwfk2P0VKd18Gp"}
 
-      data: {"id":"chatcmpl-DIgcuUeVNoSMAoX47EemdZSCJTZzY","object":"chat.completion.chunk","created":1773346132,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"1NroVJmpjmd6qdP"}
+      data: {"id":"chatcmpl-DNLTpKJVyp5Lf7K0hb9g1oCeQ1Jf3","object":"chat.completion.chunk","created":1774456485,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"mhPukHs1ZJZ7h"}
 
-      data: {"id":"chatcmpl-DIgcuUeVNoSMAoX47EemdZSCJTZzY","object":"chat.completion.chunk","created":1773346132,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"bzjPiNS24nrkg"}
+      data: {"id":"chatcmpl-DNLTpKJVyp5Lf7K0hb9g1oCeQ1Jf3","object":"chat.completion.chunk","created":1774456485,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Find"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"JrC6aT9kFiO"}
 
-      data: {"id":"chatcmpl-DIgcuUeVNoSMAoX47EemdZSCJTZzY","object":"chat.completion.chunk","created":1773346132,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"UqTnKJM4YMTa5"}
+      data: {"id":"chatcmpl-DNLTpKJVyp5Lf7K0hb9g1oCeQ1Jf3","object":"chat.completion.chunk","created":1774456485,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"N9HURje5reRyU"}
 
-      data: {"id":"chatcmpl-DIgcuUeVNoSMAoX47EemdZSCJTZzY","object":"chat.completion.chunk","created":1773346132,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"8bDYz2kt8R"}
+      data: {"id":"chatcmpl-DNLTpKJVyp5Lf7K0hb9g1oCeQ1Jf3","object":"chat.completion.chunk","created":1774456485,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":"Package"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"8W0GAvLPN"}
 
-      data: {"id":"chatcmpl-DIgcuUeVNoSMAoX47EemdZSCJTZzY","object":"chat.completion.chunk","created":1773346132,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"54eqdXTY72H"}
+      data: {"id":"chatcmpl-DNLTpKJVyp5Lf7K0hb9g1oCeQ1Jf3","object":"chat.completion.chunk","created":1774456485,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":"\""},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"M1GYcf28glGrGX"}
 
-      data: {"id":"chatcmpl-DIgcuUeVNoSMAoX47EemdZSCJTZzY","object":"chat.completion.chunk","created":1773346132,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{"content":" grep"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"wMlECx61bJP"}
+      data: {"id":"chatcmpl-DNLTpKJVyp5Lf7K0hb9g1oCeQ1Jf3","object":"chat.completion.chunk","created":1774456485,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"F92WMyZ0C6KHQ"}
 
-      data: {"id":"chatcmpl-DIgcuUeVNoSMAoX47EemdZSCJTZzY","object":"chat.completion.chunk","created":1773346132,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"8ZsVcpfC6F"}
+      data: {"id":"chatcmpl-DNLTpKJVyp5Lf7K0hb9g1oCeQ1Jf3","object":"chat.completion.chunk","created":1774456485,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"eYrDbEEfhd2bm"}
 
-      data: {"id":"chatcmpl-DIgcuUeVNoSMAoX47EemdZSCJTZzY","object":"chat.completion.chunk","created":1773346132,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_22cd3c63e9","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":"5c9sIP95JwyNsv"}
+      data: {"id":"chatcmpl-DNLTpKJVyp5Lf7K0hb9g1oCeQ1Jf3","object":"chat.completion.chunk","created":1774456485,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"TeZoFDOqBC"}
+
+      data: {"id":"chatcmpl-DNLTpKJVyp5Lf7K0hb9g1oCeQ1Jf3","object":"chat.completion.chunk","created":1774456485,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"TA0GZeApUv"}
+
+      data: {"id":"chatcmpl-DNLTpKJVyp5Lf7K0hb9g1oCeQ1Jf3","object":"chat.completion.chunk","created":1774456485,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[],"usage":{"prompt_tokens":138,"completion_tokens":11,"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":"mgDnggJoflZ4P"}
 
       data: [DONE]
 
@@ -55,15 +59,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 517.527708ms
+    duration: 884.009042ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50894
+    content_length: 51126
     host: ""

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

@@ -24,29 +24,27 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-DIgd3usqn3rK2LulE9sOc8Ys9KVyh","object":"chat.completion.chunk","created":1773346141,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"T0PHu5of1dr9ez"}
+      data: {"id":"chatcmpl-DNLTtlrOkX7bjJZckn8V4dImKRy94","object":"chat.completion.chunk","created":1774456489,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"REGF7fP3BceGRl"}
 
-      data: {"id":"chatcmpl-DIgd3usqn3rK2LulE9sOc8Ys9KVyh","object":"chat.completion.chunk","created":1773346141,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":"Using"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"kaV6ojPBQK2"}
+      data: {"id":"chatcmpl-DNLTtlrOkX7bjJZckn8V4dImKRy94","object":"chat.completion.chunk","created":1774456489,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{"content":"Listing"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"G1JxtpiTn"}
 
-      data: {"id":"chatcmpl-DIgd3usqn3rK2LulE9sOc8Ys9KVyh","object":"chat.completion.chunk","created":1773346141,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"2eg2ZonmjCC37E"}
+      data: {"id":"chatcmpl-DNLTtlrOkX7bjJZckn8V4dImKRy94","object":"chat.completion.chunk","created":1774456489,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"X1ADQKBrDK"}
 
-      data: {"id":"chatcmpl-DIgd3usqn3rK2LulE9sOc8Ys9KVyh","object":"chat.completion.chunk","created":1773346141,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":"ls"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"M6sxFQJakJm3dd"}
+      data: {"id":"chatcmpl-DNLTtlrOkX7bjJZckn8V4dImKRy94","object":"chat.completion.chunk","created":1774456489,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"cJAUQxdX14I2J"}
 
-      data: {"id":"chatcmpl-DIgd3usqn3rK2LulE9sOc8Ys9KVyh","object":"chat.completion.chunk","created":1773346141,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"OeQHO5aYO56WDMz"}
+      data: {"id":"chatcmpl-DNLTtlrOkX7bjJZckn8V4dImKRy94","object":"chat.completion.chunk","created":1774456489,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{"content":" Current"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"1ztuwP5N"}
 
-      data: {"id":"chatcmpl-DIgd3usqn3rK2LulE9sOc8Ys9KVyh","object":"chat.completion.chunk","created":1773346141,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"b89MsTugihzdX"}
+      data: {"id":"chatcmpl-DNLTtlrOkX7bjJZckn8V4dImKRy94","object":"chat.completion.chunk","created":1774456489,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{"content":" Directory"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"mK9NJ8"}
 
-      data: {"id":"chatcmpl-DIgd3usqn3rK2LulE9sOc8Ys9KVyh","object":"chat.completion.chunk","created":1773346141,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" List"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"7MEjHpNVcS0"}
+      data: {"id":"chatcmpl-DNLTtlrOkX7bjJZckn8V4dImKRy94","object":"chat.completion.chunk","created":1774456489,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"VHjFAbZ7TQs"}
 
-      data: {"id":"chatcmpl-DIgd3usqn3rK2LulE9sOc8Ys9KVyh","object":"chat.completion.chunk","created":1773346141,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"caJJIZ56Ne"}
+      data: {"id":"chatcmpl-DNLTtlrOkX7bjJZckn8V4dImKRy94","object":"chat.completion.chunk","created":1774456489,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{"content":" LS"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"tpiVLcH8WnXMb"}
 
-      data: {"id":"chatcmpl-DIgd3usqn3rK2LulE9sOc8Ys9KVyh","object":"chat.completion.chunk","created":1773346141,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"YiJDyQc9vBKA7"}
+      data: {"id":"chatcmpl-DNLTtlrOkX7bjJZckn8V4dImKRy94","object":"chat.completion.chunk","created":1774456489,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{"content":" Command"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ulw8QDNP"}
 
-      data: {"id":"chatcmpl-DIgd3usqn3rK2LulE9sOc8Ys9KVyh","object":"chat.completion.chunk","created":1773346141,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Directory"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"1R47Xd"}
+      data: {"id":"chatcmpl-DNLTtlrOkX7bjJZckn8V4dImKRy94","object":"chat.completion.chunk","created":1774456489,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"UqB1kF1w21"}
 
-      data: {"id":"chatcmpl-DIgd3usqn3rK2LulE9sOc8Ys9KVyh","object":"chat.completion.chunk","created":1773346141,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"DT1EYEwtdR"}
-
-      data: {"id":"chatcmpl-DIgd3usqn3rK2LulE9sOc8Ys9KVyh","object":"chat.completion.chunk","created":1773346141,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[],"usage":{"prompt_tokens":135,"completion_tokens":9,"total_tokens":144,"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":"vNwglUmg6ThoSE"}
+      data: {"id":"chatcmpl-DNLTtlrOkX7bjJZckn8V4dImKRy94","object":"chat.completion.chunk","created":1774456489,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","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":"8PP3wNQUKT0u9o"}
 
       data: [DONE]
 
@@ -55,15 +53,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 630.309125ms
+    duration: 600.211084ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50888
+    content_length: 51120
     host: ""

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

@@ -24,27 +24,23 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-DIgdEo8vwexsZno9n14uW5RGLu5Ix","object":"chat.completion.chunk","created":1773346152,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"uHtKH1XdOv3YNP"}
+      data: {"id":"chatcmpl-DNLTyG4VYU1SAZqGTWsqL91dHyBYf","object":"chat.completion.chunk","created":1774456494,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"HFRi6wt7sdJD7K"}
 
-      data: {"id":"chatcmpl-DIgdEo8vwexsZno9n14uW5RGLu5Ix","object":"chat.completion.chunk","created":1773346152,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":"Edit"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"GfD4NZFunoaR"}
+      data: {"id":"chatcmpl-DNLTyG4VYU1SAZqGTWsqL91dHyBYf","object":"chat.completion.chunk","created":1774456494,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{"content":"Updating"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"eUz8plm9"}
 
-      data: {"id":"chatcmpl-DIgdEo8vwexsZno9n14uW5RGLu5Ix","object":"chat.completion.chunk","created":1773346152,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Code"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"P53I5Ex575l"}
+      data: {"id":"chatcmpl-DNLTyG4VYU1SAZqGTWsqL91dHyBYf","object":"chat.completion.chunk","created":1774456494,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{"content":" Greeting"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Y2flVV1"}
 
-      data: {"id":"chatcmpl-DIgdEo8vwexsZno9n14uW5RGLu5Ix","object":"chat.completion.chunk","created":1773346152,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"0KfR1AumNQnz8"}
+      data: {"id":"chatcmpl-DNLTyG4VYU1SAZqGTWsqL91dHyBYf","object":"chat.completion.chunk","created":1774456494,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{"content":" Message"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"hi2D9cm4"}
 
-      data: {"id":"chatcmpl-DIgdEo8vwexsZno9n14uW5RGLu5Ix","object":"chat.completion.chunk","created":1773346152,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Update"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"BWVmTrFNp"}
+      data: {"id":"chatcmpl-DNLTyG4VYU1SAZqGTWsqL91dHyBYf","object":"chat.completion.chunk","created":1774456494,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"X5h37onohN1O"}
 
-      data: {"id":"chatcmpl-DIgdEo8vwexsZno9n14uW5RGLu5Ix","object":"chat.completion.chunk","created":1773346152,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Message"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"0rXfqgvI"}
+      data: {"id":"chatcmpl-DNLTyG4VYU1SAZqGTWsqL91dHyBYf","object":"chat.completion.chunk","created":1774456494,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{"content":" Adding"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"eZ88rSCGN"}
 
-      data: {"id":"chatcmpl-DIgdEo8vwexsZno9n14uW5RGLu5Ix","object":"chat.completion.chunk","created":1773346152,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"8d0rNQbcKmXp"}
+      data: {"id":"chatcmpl-DNLTyG4VYU1SAZqGTWsqL91dHyBYf","object":"chat.completion.chunk","created":1774456494,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{"content":" Comment"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Hdg4fmnv"}
 
-      data: {"id":"chatcmpl-DIgdEo8vwexsZno9n14uW5RGLu5Ix","object":"chat.completion.chunk","created":1773346152,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Add"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"v7IvPTxoRTRT"}
+      data: {"id":"chatcmpl-DNLTyG4VYU1SAZqGTWsqL91dHyBYf","object":"chat.completion.chunk","created":1774456494,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"4bV0QC3zDf"}
 
-      data: {"id":"chatcmpl-DIgdEo8vwexsZno9n14uW5RGLu5Ix","object":"chat.completion.chunk","created":1773346152,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Comment"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Tyf06vBC"}
-
-      data: {"id":"chatcmpl-DIgdEo8vwexsZno9n14uW5RGLu5Ix","object":"chat.completion.chunk","created":1773346152,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"SvGC99IZy2"}
-
-      data: {"id":"chatcmpl-DIgdEo8vwexsZno9n14uW5RGLu5Ix","object":"chat.completion.chunk","created":1773346152,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[],"usage":{"prompt_tokens":157,"completion_tokens":8,"total_tokens":165,"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":"FIcmzhdGIYNUGK"}
+      data: {"id":"chatcmpl-DNLTyG4VYU1SAZqGTWsqL91dHyBYf","object":"chat.completion.chunk","created":1774456494,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_be98c6bd39","choices":[],"usage":{"prompt_tokens":157,"completion_tokens":6,"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":"uUqgNlLbexVFxe"}
 
       data: [DONE]
 
@@ -53,15 +49,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 620.533292ms
+    duration: 924.968666ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50974
+    content_length: 51206
     host: ""

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

@@ -24,25 +24,29 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-DIgfXYcSQXhQvAsfquHHsAqUpAkO2","object":"chat.completion.chunk","created":1773346295,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"vve0SiQeoAve0J"}
+      data: {"id":"chatcmpl-DNLVSW1wlPCzUP2DHwUrRusz2yoRT","object":"chat.completion.chunk","created":1774456586,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"lH98qLyoldWIc9"}
 
-      data: {"id":"chatcmpl-DIgfXYcSQXhQvAsfquHHsAqUpAkO2","object":"chat.completion.chunk","created":1773346295,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":"Parallel"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"LhhJhYlW"}
+      data: {"id":"chatcmpl-DNLVSW1wlPCzUP2DHwUrRusz2yoRT","object":"chat.completion.chunk","created":1774456586,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":"Parallel"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"gNp77kol"}
 
-      data: {"id":"chatcmpl-DIgfXYcSQXhQvAsfquHHsAqUpAkO2","object":"chat.completion.chunk","created":1773346295,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Execution"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"rPvfeJ"}
+      data: {"id":"chatcmpl-DNLVSW1wlPCzUP2DHwUrRusz2yoRT","object":"chat.completion.chunk","created":1774456586,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Commands"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"7yhQp0r"}
 
-      data: {"id":"chatcmpl-DIgfXYcSQXhQvAsfquHHsAqUpAkO2","object":"chat.completion.chunk","created":1773346295,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" of"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"3LZmYKhy5uD0N"}
+      data: {"id":"chatcmpl-DNLVSW1wlPCzUP2DHwUrRusz2yoRT","object":"chat.completion.chunk","created":1774456586,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" for"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"zbaYREjzbXP5"}
 
-      data: {"id":"chatcmpl-DIgfXYcSQXhQvAsfquHHsAqUpAkO2","object":"chat.completion.chunk","created":1773346295,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Glob"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"fa2BY7pEqlg"}
+      data: {"id":"chatcmpl-DNLVSW1wlPCzUP2DHwUrRusz2yoRT","object":"chat.completion.chunk","created":1774456586,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" ."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"QeR2FLWlTMygKJ"}
 
-      data: {"id":"chatcmpl-DIgfXYcSQXhQvAsfquHHsAqUpAkO2","object":"chat.completion.chunk","created":1773346295,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"4hWSdHnJE1dL"}
+      data: {"id":"chatcmpl-DNLVSW1wlPCzUP2DHwUrRusz2yoRT","object":"chat.completion.chunk","created":1774456586,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":"go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"rZvtiTUwa9gc5P"}
 
-      data: {"id":"chatcmpl-DIgfXYcSQXhQvAsfquHHsAqUpAkO2","object":"chat.completion.chunk","created":1773346295,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" LS"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"lD3W51GQd7Fd5"}
+      data: {"id":"chatcmpl-DNLVSW1wlPCzUP2DHwUrRusz2yoRT","object":"chat.completion.chunk","created":1774456586,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"9kglcpYGKF"}
 
-      data: {"id":"chatcmpl-DIgfXYcSQXhQvAsfquHHsAqUpAkO2","object":"chat.completion.chunk","created":1773346295,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Commands"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"9dhzkf7"}
+      data: {"id":"chatcmpl-DNLVSW1wlPCzUP2DHwUrRusz2yoRT","object":"chat.completion.chunk","created":1774456586,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"gpgbw2Rf0BAU"}
 
-      data: {"id":"chatcmpl-DIgfXYcSQXhQvAsfquHHsAqUpAkO2","object":"chat.completion.chunk","created":1773346295,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"yuDuN4bAk4"}
+      data: {"id":"chatcmpl-DNLVSW1wlPCzUP2DHwUrRusz2yoRT","object":"chat.completion.chunk","created":1774456586,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Directory"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"IMrooe"}
 
-      data: {"id":"chatcmpl-DIgfXYcSQXhQvAsfquHHsAqUpAkO2","object":"chat.completion.chunk","created":1773346295,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","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":"5jJIZmrchS4X0N"}
+      data: {"id":"chatcmpl-DNLVSW1wlPCzUP2DHwUrRusz2yoRT","object":"chat.completion.chunk","created":1774456586,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Listing"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"n3y0kd0t"}
+
+      data: {"id":"chatcmpl-DNLVSW1wlPCzUP2DHwUrRusz2yoRT","object":"chat.completion.chunk","created":1774456586,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"Kl0WPDg2JY"}
+
+      data: {"id":"chatcmpl-DNLVSW1wlPCzUP2DHwUrRusz2yoRT","object":"chat.completion.chunk","created":1774456586,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[],"usage":{"prompt_tokens":154,"completion_tokens":9,"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":"0eA5bb9Z0LyJc0"}
 
       data: [DONE]
 
@@ -51,15 +55,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 541.726917ms
+    duration: 682.044666ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50985
+    content_length: 51217
     host: ""

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

@@ -24,17 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-DIgbNR7z9AwDFGGArsrnbo5IHDoFO","object":"chat.completion.chunk","created":1773346037,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_7cdbc83d36","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"h3aEUDsuEOcdM2"}
+      data: {"id":"chatcmpl-DNLSu63OpjOn8cb7DwZwoLjQV0wjd","object":"chat.completion.chunk","created":1774456428,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"2fLhd1wGudN0X8"}
 
-      data: {"id":"chatcmpl-DIgbNR7z9AwDFGGArsrnbo5IHDoFO","object":"chat.completion.chunk","created":1773346037,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_7cdbc83d36","choices":[{"index":0,"delta":{"content":"Understanding"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"lI8"}
+      data: {"id":"chatcmpl-DNLSu63OpjOn8cb7DwZwoLjQV0wjd","object":"chat.completion.chunk","created":1774456428,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":"Reading"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"5u06Dqtj5"}
 
-      data: {"id":"chatcmpl-DIgbNR7z9AwDFGGArsrnbo5IHDoFO","object":"chat.completion.chunk","created":1773346037,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_7cdbc83d36","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"BlCB1J7w94tsJ"}
+      data: {"id":"chatcmpl-DNLSu63OpjOn8cb7DwZwoLjQV0wjd","object":"chat.completion.chunk","created":1774456428,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"der23rJV27R0"}
 
-      data: {"id":"chatcmpl-DIgbNR7z9AwDFGGArsrnbo5IHDoFO","object":"chat.completion.chunk","created":1773346037,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_7cdbc83d36","choices":[{"index":0,"delta":{"content":" Modules"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"SSUmRbVb"}
+      data: {"id":"chatcmpl-DNLSu63OpjOn8cb7DwZwoLjQV0wjd","object":"chat.completion.chunk","created":1774456428,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"67eeIdkhgdKjN"}
 
-      data: {"id":"chatcmpl-DIgbNR7z9AwDFGGArsrnbo5IHDoFO","object":"chat.completion.chunk","created":1773346037,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_7cdbc83d36","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"Lh8q0ncyK0"}
+      data: {"id":"chatcmpl-DNLSu63OpjOn8cb7DwZwoLjQV0wjd","object":"chat.completion.chunk","created":1774456428,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Mod"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"JK0e4jUywCWq"}
 
-      data: {"id":"chatcmpl-DIgbNR7z9AwDFGGArsrnbo5IHDoFO","object":"chat.completion.chunk","created":1773346037,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_7cdbc83d36","choices":[],"usage":{"prompt_tokens":129,"completion_tokens":3,"total_tokens":132,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"eGJiZzX7fhB3DQ"}
+      data: {"id":"chatcmpl-DNLSu63OpjOn8cb7DwZwoLjQV0wjd","object":"chat.completion.chunk","created":1774456428,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"PRUv8ruoaaY"}
+
+      data: {"id":"chatcmpl-DNLSu63OpjOn8cb7DwZwoLjQV0wjd","object":"chat.completion.chunk","created":1774456428,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"cZ0AotOMQp"}
+
+      data: {"id":"chatcmpl-DNLSu63OpjOn8cb7DwZwoLjQV0wjd","object":"chat.completion.chunk","created":1774456428,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","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":"hy1N4ONQpPFz7g"}
 
       data: [DONE]
 
@@ -43,15 +47,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 706.98175ms
+    duration: 1.296206084s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50858
+    content_length: 51090
     host: ""

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

@@ -24,15 +24,15 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-DIgbK6R5yUtBIGQDJgY0TPRYQOi6y","object":"chat.completion.chunk","created":1773346034,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_2a3fb89a78","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"abFmE7omz4JrEU"}
+      data: {"id":"chatcmpl-DNLSsXOs37ig7DqzPR7RJsBrgOpkW","object":"chat.completion.chunk","created":1774456426,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_92d15debfd","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"xpUMdIcnpMeUJ3"}
 
-      data: {"id":"chatcmpl-DIgbK6R5yUtBIGQDJgY0TPRYQOi6y","object":"chat.completion.chunk","created":1773346034,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_2a3fb89a78","choices":[{"index":0,"delta":{"content":"Greeting"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"N38b9dFW"}
+      data: {"id":"chatcmpl-DNLSsXOs37ig7DqzPR7RJsBrgOpkW","object":"chat.completion.chunk","created":1774456426,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_92d15debfd","choices":[{"index":0,"delta":{"content":"User"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ZSfj5D8D3zBr"}
 
-      data: {"id":"chatcmpl-DIgbK6R5yUtBIGQDJgY0TPRYQOi6y","object":"chat.completion.chunk","created":1773346034,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_2a3fb89a78","choices":[{"index":0,"delta":{"content":" Message"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"WJYwnM0H"}
+      data: {"id":"chatcmpl-DNLSsXOs37ig7DqzPR7RJsBrgOpkW","object":"chat.completion.chunk","created":1774456426,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_92d15debfd","choices":[{"index":0,"delta":{"content":" Greeting"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"3JkzS0G"}
 
-      data: {"id":"chatcmpl-DIgbK6R5yUtBIGQDJgY0TPRYQOi6y","object":"chat.completion.chunk","created":1773346034,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_2a3fb89a78","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"HwCdXBSzEC"}
+      data: {"id":"chatcmpl-DNLSsXOs37ig7DqzPR7RJsBrgOpkW","object":"chat.completion.chunk","created":1774456426,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_92d15debfd","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"HmISF5D0TH"}
 
-      data: {"id":"chatcmpl-DIgbK6R5yUtBIGQDJgY0TPRYQOi6y","object":"chat.completion.chunk","created":1773346034,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_2a3fb89a78","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":"VcX20EEMDDv4zM"}
+      data: {"id":"chatcmpl-DNLSsXOs37ig7DqzPR7RJsBrgOpkW","object":"chat.completion.chunk","created":1774456426,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_92d15debfd","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":"c9b4bWVUtITZOd"}
 
       data: [DONE]
 
@@ -41,15 +41,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 919.449334ms
+    duration: 2.221166541s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50848
+    content_length: 51080
     host: ""

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

@@ -24,35 +24,35 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-DIgea9hwz4OpfP3VrP7BqtsKtzHy8","object":"chat.completion.chunk","created":1773346236,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"zkyoMu4xoVx6cx"}
+      data: {"id":"chatcmpl-DNLUHmZ1zJ6XQObTQxMsgGm12G9qg","object":"chat.completion.chunk","created":1774456513,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"4BTtMVWSsc67nO"}
 
-      data: {"id":"chatcmpl-DIgea9hwz4OpfP3VrP7BqtsKtzHy8","object":"chat.completion.chunk","created":1773346236,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":"Searching"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"nDxsCPu"}
+      data: {"id":"chatcmpl-DNLUHmZ1zJ6XQObTQxMsgGm12G9qg","object":"chat.completion.chunk","created":1774456513,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":"Searching"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"u5dEho6"}
 
-      data: {"id":"chatcmpl-DIgea9hwz4OpfP3VrP7BqtsKtzHy8","object":"chat.completion.chunk","created":1773346236,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"BbicZpCukzDvXw"}
+      data: {"id":"chatcmpl-DNLUHmZ1zJ6XQObTQxMsgGm12G9qg","object":"chat.completion.chunk","created":1774456513,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"PkxyNJt8UUu8XY"}
 
-      data: {"id":"chatcmpl-DIgea9hwz4OpfP3VrP7BqtsKtzHy8","object":"chat.completion.chunk","created":1773346236,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":"func"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"YRjaWaC6KPev"}
+      data: {"id":"chatcmpl-DNLUHmZ1zJ6XQObTQxMsgGm12G9qg","object":"chat.completion.chunk","created":1774456513,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":"func"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"lRxnzekgLRUI"}
 
-      data: {"id":"chatcmpl-DIgea9hwz4OpfP3VrP7BqtsKtzHy8","object":"chat.completion.chunk","created":1773346236,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" main"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"P3Wom0W0U5n"}
+      data: {"id":"chatcmpl-DNLUHmZ1zJ6XQObTQxMsgGm12G9qg","object":"chat.completion.chunk","created":1774456513,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" main"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"oVxxgr9Cy87"}
 
-      data: {"id":"chatcmpl-DIgea9hwz4OpfP3VrP7BqtsKtzHy8","object":"chat.completion.chunk","created":1773346236,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"GwooI4y6nUPZXFk"}
+      data: {"id":"chatcmpl-DNLUHmZ1zJ6XQObTQxMsgGm12G9qg","object":"chat.completion.chunk","created":1774456513,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"vAxEDgSzQTmJJP2"}
 
-      data: {"id":"chatcmpl-DIgea9hwz4OpfP3VrP7BqtsKtzHy8","object":"chat.completion.chunk","created":1773346236,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"EE6vq4kWKW1ls"}
+      data: {"id":"chatcmpl-DNLUHmZ1zJ6XQObTQxMsgGm12G9qg","object":"chat.completion.chunk","created":1774456513,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"wk6YTNLpykE0K"}
 
-      data: {"id":"chatcmpl-DIgea9hwz4OpfP3VrP7BqtsKtzHy8","object":"chat.completion.chunk","created":1773346236,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"4jDIiRb3w0zWk"}
+      data: {"id":"chatcmpl-DNLUHmZ1zJ6XQObTQxMsgGm12G9qg","object":"chat.completion.chunk","created":1774456513,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"zbC53NngWNuAP"}
 
-      data: {"id":"chatcmpl-DIgea9hwz4OpfP3VrP7BqtsKtzHy8","object":"chat.completion.chunk","created":1773346236,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Re"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"zZ5LRyqjNOOf4"}
+      data: {"id":"chatcmpl-DNLUHmZ1zJ6XQObTQxMsgGm12G9qg","object":"chat.completion.chunk","created":1774456513,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Re"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"mlFx7kpDlvLkj"}
 
-      data: {"id":"chatcmpl-DIgea9hwz4OpfP3VrP7BqtsKtzHy8","object":"chat.completion.chunk","created":1773346236,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":"positories"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"WIPhQT"}
+      data: {"id":"chatcmpl-DNLUHmZ1zJ6XQObTQxMsgGm12G9qg","object":"chat.completion.chunk","created":1774456513,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":"positories"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"RMn6il"}
 
-      data: {"id":"chatcmpl-DIgea9hwz4OpfP3VrP7BqtsKtzHy8","object":"chat.completion.chunk","created":1773346236,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"I51EX5NB2TH"}
+      data: {"id":"chatcmpl-DNLUHmZ1zJ6XQObTQxMsgGm12G9qg","object":"chat.completion.chunk","created":1774456513,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"s0E4rMH57cv"}
 
-      data: {"id":"chatcmpl-DIgea9hwz4OpfP3VrP7BqtsKtzHy8","object":"chat.completion.chunk","created":1773346236,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Source"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"rD2GUHQ4C"}
+      data: {"id":"chatcmpl-DNLUHmZ1zJ6XQObTQxMsgGm12G9qg","object":"chat.completion.chunk","created":1774456513,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Source"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"JBi6JLhx7"}
 
-      data: {"id":"chatcmpl-DIgea9hwz4OpfP3VrP7BqtsKtzHy8","object":"chat.completion.chunk","created":1773346236,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":"graph"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Dg3TMLF9Ros"}
+      data: {"id":"chatcmpl-DNLUHmZ1zJ6XQObTQxMsgGm12G9qg","object":"chat.completion.chunk","created":1774456513,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":"graph"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"3lXPcuhv6Jp"}
 
-      data: {"id":"chatcmpl-DIgea9hwz4OpfP3VrP7BqtsKtzHy8","object":"chat.completion.chunk","created":1773346236,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"AZaU2kawGZ"}
+      data: {"id":"chatcmpl-DNLUHmZ1zJ6XQObTQxMsgGm12G9qg","object":"chat.completion.chunk","created":1774456513,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"F9DVilghqP"}
 
-      data: {"id":"chatcmpl-DIgea9hwz4OpfP3VrP7BqtsKtzHy8","object":"chat.completion.chunk","created":1773346236,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","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":"DRfU65h3iz1GX"}
+      data: {"id":"chatcmpl-DNLUHmZ1zJ6XQObTQxMsgGm12G9qg","object":"chat.completion.chunk","created":1774456513,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","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":"054TZEKggLyNj"}
 
       data: [DONE]
 
@@ -61,15 +61,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 578.111292ms
+    duration: 2.196706958s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50908
+    content_length: 51140
     host: ""

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

@@ -24,31 +24,25 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-DIgbUxWHI144OwWvmvV6m9MU7HQM2","object":"chat.completion.chunk","created":1773346044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_44968754fe","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"omtKv086CvMki9"}
+      data: {"id":"chatcmpl-DNLT275CAqqb3FVuXGKXsGTOtzgMt","object":"chat.completion.chunk","created":1774456436,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_302b87bc9f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"kyCrZaCvIvtcJ0"}
 
-      data: {"id":"chatcmpl-DIgbUxWHI144OwWvmvV6m9MU7HQM2","object":"chat.completion.chunk","created":1773346044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_44968754fe","choices":[{"index":0,"delta":{"content":"Update"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ZEXCH8fpHw"}
+      data: {"id":"chatcmpl-DNLT275CAqqb3FVuXGKXsGTOtzgMt","object":"chat.completion.chunk","created":1774456436,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_302b87bc9f","choices":[{"index":0,"delta":{"content":"Update"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"B0SZU1IRsc"}
 
-      data: {"id":"chatcmpl-DIgbUxWHI144OwWvmvV6m9MU7HQM2","object":"chat.completion.chunk","created":1773346044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_44968754fe","choices":[{"index":0,"delta":{"content":" main"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"aJATAdu3YXf"}
+      data: {"id":"chatcmpl-DNLT275CAqqb3FVuXGKXsGTOtzgMt","object":"chat.completion.chunk","created":1774456436,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_302b87bc9f","choices":[{"index":0,"delta":{"content":" main"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"H09PWm1kBiq"}
 
-      data: {"id":"chatcmpl-DIgbUxWHI144OwWvmvV6m9MU7HQM2","object":"chat.completion.chunk","created":1773346044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_44968754fe","choices":[{"index":0,"delta":{"content":".go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"65HJPfi0HP3YE"}
+      data: {"id":"chatcmpl-DNLT275CAqqb3FVuXGKXsGTOtzgMt","object":"chat.completion.chunk","created":1774456436,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_302b87bc9f","choices":[{"index":0,"delta":{"content":".go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"fDzEeCSonwasd"}
 
-      data: {"id":"chatcmpl-DIgbUxWHI144OwWvmvV6m9MU7HQM2","object":"chat.completion.chunk","created":1773346044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_44968754fe","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"vnkod9UqKg6kp"}
+      data: {"id":"chatcmpl-DNLT275CAqqb3FVuXGKXsGTOtzgMt","object":"chat.completion.chunk","created":1774456436,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_302b87bc9f","choices":[{"index":0,"delta":{"content":":"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ILGeCAVJBQ30Ujh"}
 
-      data: {"id":"chatcmpl-DIgbUxWHI144OwWvmvV6m9MU7HQM2","object":"chat.completion.chunk","created":1773346044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_44968754fe","choices":[{"index":0,"delta":{"content":" Print"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"yxbUPhFzxi"}
+      data: {"id":"chatcmpl-DNLT275CAqqb3FVuXGKXsGTOtzgMt","object":"chat.completion.chunk","created":1774456436,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_302b87bc9f","choices":[{"index":0,"delta":{"content":" Change"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"2VLAaYsIm"}
 
-      data: {"id":"chatcmpl-DIgbUxWHI144OwWvmvV6m9MU7HQM2","object":"chat.completion.chunk","created":1773346044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_44968754fe","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"q1dEe2zLZzA1S"}
+      data: {"id":"chatcmpl-DNLT275CAqqb3FVuXGKXsGTOtzgMt","object":"chat.completion.chunk","created":1774456436,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_302b87bc9f","choices":[{"index":0,"delta":{"content":" Print"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"oqtkIHqoeR"}
 
-      data: {"id":"chatcmpl-DIgbUxWHI144OwWvmvV6m9MU7HQM2","object":"chat.completion.chunk","created":1773346044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_44968754fe","choices":[{"index":0,"delta":{"content":"Hello"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"p2SCTWanJnk"}
+      data: {"id":"chatcmpl-DNLT275CAqqb3FVuXGKXsGTOtzgMt","object":"chat.completion.chunk","created":1774456436,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_302b87bc9f","choices":[{"index":0,"delta":{"content":" Message"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"yxgBh188"}
 
-      data: {"id":"chatcmpl-DIgbUxWHI144OwWvmvV6m9MU7HQM2","object":"chat.completion.chunk","created":1773346044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_44968754fe","choices":[{"index":0,"delta":{"content":" from"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"qy9fD0ToahO"}
+      data: {"id":"chatcmpl-DNLT275CAqqb3FVuXGKXsGTOtzgMt","object":"chat.completion.chunk","created":1774456436,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_302b87bc9f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"RIXrXeant8"}
 
-      data: {"id":"chatcmpl-DIgbUxWHI144OwWvmvV6m9MU7HQM2","object":"chat.completion.chunk","created":1773346044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_44968754fe","choices":[{"index":0,"delta":{"content":" Crush"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"13k3IIX4dD"}
-
-      data: {"id":"chatcmpl-DIgbUxWHI144OwWvmvV6m9MU7HQM2","object":"chat.completion.chunk","created":1773346044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_44968754fe","choices":[{"index":0,"delta":{"content":"\""},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"22eb1C3HamxEaF"}
-
-      data: {"id":"chatcmpl-DIgbUxWHI144OwWvmvV6m9MU7HQM2","object":"chat.completion.chunk","created":1773346044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_44968754fe","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"NpdtMX0n82"}
-
-      data: {"id":"chatcmpl-DIgbUxWHI144OwWvmvV6m9MU7HQM2","object":"chat.completion.chunk","created":1773346044,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_44968754fe","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":"AiiC5wZHOeur4"}
+      data: {"id":"chatcmpl-DNLT275CAqqb3FVuXGKXsGTOtzgMt","object":"chat.completion.chunk","created":1774456436,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_302b87bc9f","choices":[],"usage":{"prompt_tokens":139,"completion_tokens":7,"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":"BRZfoPmqVdF0Br"}
 
       data: [DONE]
 
@@ -57,15 +51,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 523.732ms
+    duration: 1.529203542s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50914
+    content_length: 51146
     host: ""

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

@@ -24,23 +24,25 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-DIgfCpDj2oYbQgEPcRwZLZ7AyDMyL","object":"chat.completion.chunk","created":1773346274,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"lElIIxTR6SfSJe"}
+      data: {"id":"chatcmpl-DNLUvBP2we6ypSAHwNO6rkeCGTXvc","object":"chat.completion.chunk","created":1774456553,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"nDxfWT7oRFxst6"}
 
-      data: {"id":"chatcmpl-DIgfCpDj2oYbQgEPcRwZLZ7AyDMyL","object":"chat.completion.chunk","created":1773346274,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":"Creating"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"aJcyTcJt"}
+      data: {"id":"chatcmpl-DNLUvBP2we6ypSAHwNO6rkeCGTXvc","object":"chat.completion.chunk","created":1774456553,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":"Creating"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"RWfg0Mnw"}
 
-      data: {"id":"chatcmpl-DIgfCpDj2oYbQgEPcRwZLZ7AyDMyL","object":"chat.completion.chunk","created":1773346274,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" config"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"5h6rbfdKc"}
+      data: {"id":"chatcmpl-DNLUvBP2we6ypSAHwNO6rkeCGTXvc","object":"chat.completion.chunk","created":1774456553,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"hc4Rxu0UG4JOFT"}
 
-      data: {"id":"chatcmpl-DIgfCpDj2oYbQgEPcRwZLZ7AyDMyL","object":"chat.completion.chunk","created":1773346274,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":".json"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"U0XSGt1c8eN"}
+      data: {"id":"chatcmpl-DNLUvBP2we6ypSAHwNO6rkeCGTXvc","object":"chat.completion.chunk","created":1774456553,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" New"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"RMwWczVUZKrF"}
 
-      data: {"id":"chatcmpl-DIgfCpDj2oYbQgEPcRwZLZ7AyDMyL","object":"chat.completion.chunk","created":1773346274,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"LyOc5aUnXjO"}
+      data: {"id":"chatcmpl-DNLUvBP2we6ypSAHwNO6rkeCGTXvc","object":"chat.completion.chunk","created":1774456553,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"4MG211x6hoE"}
 
-      data: {"id":"chatcmpl-DIgfCpDj2oYbQgEPcRwZLZ7AyDMyL","object":"chat.completion.chunk","created":1773346274,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Initial"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"xERgMAB3"}
+      data: {"id":"chatcmpl-DNLUvBP2we6ypSAHwNO6rkeCGTXvc","object":"chat.completion.chunk","created":1774456553,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" Named"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"fgisfXMeAg"}
 
-      data: {"id":"chatcmpl-DIgfCpDj2oYbQgEPcRwZLZ7AyDMyL","object":"chat.completion.chunk","created":1773346274,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{"content":" Content"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"x7cKTSzp"}
+      data: {"id":"chatcmpl-DNLUvBP2we6ypSAHwNO6rkeCGTXvc","object":"chat.completion.chunk","created":1774456553,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":" config"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"m9VSTgbx6"}
 
-      data: {"id":"chatcmpl-DIgfCpDj2oYbQgEPcRwZLZ7AyDMyL","object":"chat.completion.chunk","created":1773346274,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"xt5qjxN5v0"}
+      data: {"id":"chatcmpl-DNLUvBP2we6ypSAHwNO6rkeCGTXvc","object":"chat.completion.chunk","created":1774456553,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{"content":".json"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"x0fWDdVQ846"}
 
-      data: {"id":"chatcmpl-DIgfCpDj2oYbQgEPcRwZLZ7AyDMyL","object":"chat.completion.chunk","created":1773346274,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_18c1fee47e","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":"R31AJ3GYVMTuit"}
+      data: {"id":"chatcmpl-DNLUvBP2we6ypSAHwNO6rkeCGTXvc","object":"chat.completion.chunk","created":1774456553,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"Sc1rkinrDG"}
+
+      data: {"id":"chatcmpl-DNLUvBP2we6ypSAHwNO6rkeCGTXvc","object":"chat.completion.chunk","created":1774456553,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_49bd10b094","choices":[],"usage":{"prompt_tokens":153,"completion_tokens":7,"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":"lr2acshDNFOEcQ"}
 
       data: [DONE]
 
@@ -49,15 +51,15 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 518.668542ms
+    duration: 810.570875ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50951
+    content_length: 51183
     host: ""

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

@@ -15,7 +15,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - OpenAI/Go 2.7.1
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://openrouter.ai/api/v1/chat/completions
     method: POST
   response:
@@ -24,19 +24,29 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1773346329-EWUWqwmb1NUxgPTCQmMN","object":"chat.completion.chunk","created":1773346329,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"Create","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      : OPENROUTER PROCESSING
 
-      data: {"id":"gen-1773346329-EWUWqwmb1NUxgPTCQmMN","object":"chat.completion.chunk","created":1773346329,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" test","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      : OPENROUTER PROCESSING
 
-      data: {"id":"gen-1773346329-EWUWqwmb1NUxgPTCQmMN","object":"chat.completion.chunk","created":1773346329,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":".txt with","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456635-9s4O9wmF0LoJItmVTX4s","object":"chat.completion.chunk","created":1774456635,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"Create","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346329-EWUWqwmb1NUxgPTCQmMN","object":"chat.completion.chunk","created":1773346329,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" hello bash using","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456635-9s4O9wmF0LoJItmVTX4s","object":"chat.completion.chunk","created":1774456635,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" test","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346329-EWUWqwmb1NUxgPTCQmMN","object":"chat.completion.chunk","created":1773346329,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" bash","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456635-9s4O9wmF0LoJItmVTX4s","object":"chat.completion.chunk","created":1774456635,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":".txt","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346329-EWUWqwmb1NUxgPTCQmMN","object":"chat.completion.chunk","created":1773346329,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
+      data: {"id":"gen-1774456635-9s4O9wmF0LoJItmVTX4s","object":"chat.completion.chunk","created":1774456635,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" with","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346329-EWUWqwmb1NUxgPTCQmMN","object":"chat.completion.chunk","created":1773346329,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[],"usage":{"prompt_tokens":151,"completion_tokens":8,"total_tokens":159,"cost":0.0000209625,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.00003225,"upstream_inference_prompt_cost":0.00002265,"upstream_inference_completions_cost":0.0000096},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
+      data: {"id":"gen-1774456635-9s4O9wmF0LoJItmVTX4s","object":"chat.completion.chunk","created":1774456635,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" hello","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+
+      data: {"id":"gen-1774456635-9s4O9wmF0LoJItmVTX4s","object":"chat.completion.chunk","created":1774456635,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" bash","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+
+      data: {"id":"gen-1774456635-9s4O9wmF0LoJItmVTX4s","object":"chat.completion.chunk","created":1774456635,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" using","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+
+      data: {"id":"gen-1774456635-9s4O9wmF0LoJItmVTX4s","object":"chat.completion.chunk","created":1774456635,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" bash","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+
+      data: {"id":"gen-1774456635-9s4O9wmF0LoJItmVTX4s","object":"chat.completion.chunk","created":1774456635,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
+
+      data: {"id":"gen-1774456635-9s4O9wmF0LoJItmVTX4s","object":"chat.completion.chunk","created":1774456635,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}],"usage":{"prompt_tokens":147,"completion_tokens":9,"total_tokens":156,"cost":0.0000246,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.0000246,"upstream_inference_prompt_cost":0.0000147,"upstream_inference_completions_cost":0.0000099},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
 
       data: [DONE]
 
@@ -45,22 +55,22 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 711.943708ms
+    duration: 1.048188458s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51084
+    content_length: 51316
     host: ""

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

@@ -15,7 +15,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - OpenAI/Go 2.7.1
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://openrouter.ai/api/v1/chat/completions
     method: POST
   response:
@@ -24,23 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1773346336-TVqiuHC80xFmriSa1GnB","object":"chat.completion.chunk","created":1773346336,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Google","choices":[{"index":0,"delta":{"content":"Download","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      : OPENROUTER PROCESSING
 
-      data: {"id":"gen-1773346336-TVqiuHC80xFmriSa1GnB","object":"chat.completion.chunk","created":1773346336,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Google","choices":[{"index":0,"delta":{"content":" example","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456643-2NA5CsHETCqN6Kpoh5gg","object":"chat.completion.chunk","created":1774456643,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"Download","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346336-TVqiuHC80xFmriSa1GnB","object":"chat.completion.chunk","created":1773346336,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Google","choices":[{"index":0,"delta":{"content":".txt from example","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456643-2NA5CsHETCqN6Kpoh5gg","object":"chat.completion.chunk","created":1774456643,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" example","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346336-TVqiuHC80xFmriSa1GnB","object":"chat.completion.chunk","created":1773346336,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Google","choices":[{"index":0,"delta":{"content":"-files","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456643-2NA5CsHETCqN6Kpoh5gg","object":"chat.completion.chunk","created":1774456643,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":".txt from example","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346336-TVqiuHC80xFmriSa1GnB","object":"chat.completion.chunk","created":1773346336,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Google","choices":[{"index":0,"delta":{"content":".online","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456643-2NA5CsHETCqN6Kpoh5gg","object":"chat.completion.chunk","created":1774456643,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"-files","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346336-TVqiuHC80xFmriSa1GnB","object":"chat.completion.chunk","created":1773346336,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Google","choices":[{"index":0,"delta":{"content":"-","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456643-2NA5CsHETCqN6Kpoh5gg","object":"chat.completion.chunk","created":1774456643,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":".online-convert.com","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346336-TVqiuHC80xFmriSa1GnB","object":"chat.completion.chunk","created":1773346336,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Google","choices":[{"index":0,"delta":{"content":"convert.com","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456643-2NA5CsHETCqN6Kpoh5gg","object":"chat.completion.chunk","created":1774456643,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
 
-      data: {"id":"gen-1773346336-TVqiuHC80xFmriSa1GnB","object":"chat.completion.chunk","created":1773346336,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Google","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
-
-      data: {"id":"gen-1773346336-TVqiuHC80xFmriSa1GnB","object":"chat.completion.chunk","created":1773346336,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Google","choices":[],"usage":{"prompt_tokens":150,"completion_tokens":11,"total_tokens":161,"cost":0.0000357,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.0000357,"upstream_inference_prompt_cost":0.0000225,"upstream_inference_completions_cost":0.0000132},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
+      data: {"id":"gen-1774456643-2NA5CsHETCqN6Kpoh5gg","object":"chat.completion.chunk","created":1774456643,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}],"usage":{"prompt_tokens":154,"completion_tokens":10,"total_tokens":164,"cost":0.000022815,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.0000351,"upstream_inference_prompt_cost":0.0000231,"upstream_inference_completions_cost":0.000012},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
 
       data: [DONE]
 
@@ -49,22 +47,22 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 729.655584ms
+    duration: 684.727584ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51109
+    content_length: 51341
     host: ""

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

@@ -15,7 +15,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - OpenAI/Go 2.7.1
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://openrouter.ai/api/v1/chat/completions
     method: POST
   response:
@@ -24,17 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1773346345-gWD8OXAwYWldd57opVOW","object":"chat.completion.chunk","created":1773346345,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"Check","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      : OPENROUTER PROCESSING
 
-      data: {"id":"gen-1773346345-gWD8OXAwYWldd57opVOW","object":"chat.completion.chunk","created":1773346345,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" if example","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456656-kLgickPBoh5tJwTa9fWO","object":"chat.completion.chunk","created":1774456656,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"Check","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346345-gWD8OXAwYWldd57opVOW","object":"chat.completion.chunk","created":1773346345,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":".html contains John","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456656-kLgickPBoh5tJwTa9fWO","object":"chat.completion.chunk","created":1774456656,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" if example","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346345-gWD8OXAwYWldd57opVOW","object":"chat.completion.chunk","created":1773346345,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" Doe","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456656-kLgickPBoh5tJwTa9fWO","object":"chat.completion.chunk","created":1774456656,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":".html contains John","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346345-gWD8OXAwYWldd57opVOW","object":"chat.completion.chunk","created":1773346345,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
+      data: {"id":"gen-1774456656-kLgickPBoh5tJwTa9fWO","object":"chat.completion.chunk","created":1774456656,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" Doe","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346345-gWD8OXAwYWldd57opVOW","object":"chat.completion.chunk","created":1773346345,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[],"usage":{"prompt_tokens":159,"completion_tokens":7,"total_tokens":166,"cost":0.0000209625,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.00003225,"upstream_inference_prompt_cost":0.00002385,"upstream_inference_completions_cost":0.0000084},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
+      data: {"id":"gen-1774456656-kLgickPBoh5tJwTa9fWO","object":"chat.completion.chunk","created":1774456656,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
+
+      data: {"id":"gen-1774456656-kLgickPBoh5tJwTa9fWO","object":"chat.completion.chunk","created":1774456656,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}],"usage":{"prompt_tokens":159,"completion_tokens":7,"total_tokens":166,"cost":0.0000209625,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.00003225,"upstream_inference_prompt_cost":0.00002385,"upstream_inference_completions_cost":0.0000084},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
 
       data: [DONE]
 
@@ -43,22 +45,22 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 706.07425ms
+    duration: 561.340875ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51127
+    content_length: 51359
     host: ""

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

@@ -15,7 +15,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - OpenAI/Go 2.7.1
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://openrouter.ai/api/v1/chat/completions
     method: POST
   response:
@@ -24,29 +24,29 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1773346355-xVkkhvwNqJJ5XlXkXyr1","object":"chat.completion.chunk","created":1773346355,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"Find","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456666-K5jCTkoQpskLWE04K0W8","object":"chat.completion.chunk","created":1774456666,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"Find","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346355-xVkkhvwNqJJ5XlXkXyr1","object":"chat.completion.chunk","created":1773346355,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" all","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456666-K5jCTkoQpskLWE04K0W8","object":"chat.completion.chunk","created":1774456666,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" all","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346355-xVkkhvwNqJJ5XlXkXyr1","object":"chat.completion.chunk","created":1773346355,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" .","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456666-K5jCTkoQpskLWE04K0W8","object":"chat.completion.chunk","created":1774456666,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" .","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346355-xVkkhvwNqJJ5XlXkXyr1","object":"chat.completion.chunk","created":1773346355,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"go","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456666-K5jCTkoQpskLWE04K0W8","object":"chat.completion.chunk","created":1774456666,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"go","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346355-xVkkhvwNqJJ5XlXkXyr1","object":"chat.completion.chunk","created":1773346355,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" files","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456666-K5jCTkoQpskLWE04K0W8","object":"chat.completion.chunk","created":1774456666,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" files","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346355-xVkkhvwNqJJ5XlXkXyr1","object":"chat.completion.chunk","created":1773346355,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" in","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456666-K5jCTkoQpskLWE04K0W8","object":"chat.completion.chunk","created":1774456666,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" in","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346355-xVkkhvwNqJJ5XlXkXyr1","object":"chat.completion.chunk","created":1773346355,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" current","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456666-K5jCTkoQpskLWE04K0W8","object":"chat.completion.chunk","created":1774456666,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" current","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346355-xVkkhvwNqJJ5XlXkXyr1","object":"chat.completion.chunk","created":1773346355,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" directory","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456666-K5jCTkoQpskLWE04K0W8","object":"chat.completion.chunk","created":1774456666,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" directory","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346355-xVkkhvwNqJJ5XlXkXyr1","object":"chat.completion.chunk","created":1773346355,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" using","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456666-K5jCTkoQpskLWE04K0W8","object":"chat.completion.chunk","created":1774456666,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" using","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346355-xVkkhvwNqJJ5XlXkXyr1","object":"chat.completion.chunk","created":1773346355,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" glob","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456666-K5jCTkoQpskLWE04K0W8","object":"chat.completion.chunk","created":1774456666,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" glob","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346355-xVkkhvwNqJJ5XlXkXyr1","object":"chat.completion.chunk","created":1773346355,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
+      data: {"id":"gen-1774456666-K5jCTkoQpskLWE04K0W8","object":"chat.completion.chunk","created":1774456666,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
 
-      data: {"id":"gen-1773346355-xVkkhvwNqJJ5XlXkXyr1","object":"chat.completion.chunk","created":1773346355,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[],"usage":{"prompt_tokens":139,"completion_tokens":11,"total_tokens":150,"cost":0.000026,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.000026,"upstream_inference_prompt_cost":0.0000139,"upstream_inference_completions_cost":0.0000121},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
+      data: {"id":"gen-1774456666-K5jCTkoQpskLWE04K0W8","object":"chat.completion.chunk","created":1774456666,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}],"usage":{"prompt_tokens":139,"completion_tokens":11,"total_tokens":150,"cost":0.000026,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.000026,"upstream_inference_prompt_cost":0.0000139,"upstream_inference_completions_cost":0.0000121},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
 
       data: [DONE]
 
@@ -55,22 +55,22 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 828.859041ms
+    duration: 447.589459ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51045
+    content_length: 51277
     host: ""

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

@@ -15,7 +15,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - OpenAI/Go 2.7.1
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://openrouter.ai/api/v1/chat/completions
     method: POST
   response:
@@ -24,25 +24,15 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1773346362-BgYEc5fC5xu3HVSCxh3l","object":"chat.completion.chunk","created":1773346362,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"Search","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456675-MJCODZaHeH6YCYQp6Dsu","object":"chat.completion.chunk","created":1774456675,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"DeepInfra","choices":[{"index":0,"delta":{"content":"Search","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346362-BgYEc5fC5xu3HVSCxh3l","object":"chat.completion.chunk","created":1773346362,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" for","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456675-MJCODZaHeH6YCYQp6Dsu","object":"chat.completion.chunk","created":1774456675,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"DeepInfra","choices":[{"index":0,"delta":{"content":" for package in Go","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346362-BgYEc5fC5xu3HVSCxh3l","object":"chat.completion.chunk","created":1773346362,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" package","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456675-MJCODZaHeH6YCYQp6Dsu","object":"chat.completion.chunk","created":1774456675,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"DeepInfra","choices":[{"index":0,"delta":{"content":" files using grep","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346362-BgYEc5fC5xu3HVSCxh3l","object":"chat.completion.chunk","created":1773346362,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" in","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456675-MJCODZaHeH6YCYQp6Dsu","object":"chat.completion.chunk","created":1774456675,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"DeepInfra","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
 
-      data: {"id":"gen-1773346362-BgYEc5fC5xu3HVSCxh3l","object":"chat.completion.chunk","created":1773346362,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" Go","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
-
-      data: {"id":"gen-1773346362-BgYEc5fC5xu3HVSCxh3l","object":"chat.completion.chunk","created":1773346362,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" files","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
-
-      data: {"id":"gen-1773346362-BgYEc5fC5xu3HVSCxh3l","object":"chat.completion.chunk","created":1773346362,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" using","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
-
-      data: {"id":"gen-1773346362-BgYEc5fC5xu3HVSCxh3l","object":"chat.completion.chunk","created":1773346362,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" grep","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
-
-      data: {"id":"gen-1773346362-BgYEc5fC5xu3HVSCxh3l","object":"chat.completion.chunk","created":1773346362,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
-
-      data: {"id":"gen-1773346362-BgYEc5fC5xu3HVSCxh3l","object":"chat.completion.chunk","created":1773346362,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[],"usage":{"prompt_tokens":140,"completion_tokens":9,"total_tokens":149,"cost":0.0000239,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.0000239,"upstream_inference_prompt_cost":0.000014,"upstream_inference_completions_cost":0.0000099},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
+      data: {"id":"gen-1774456675-MJCODZaHeH6YCYQp6Dsu","object":"chat.completion.chunk","created":1774456675,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"DeepInfra","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}],"usage":{"prompt_tokens":140,"completion_tokens":9,"total_tokens":149,"cost":0.0000225,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.0000225,"upstream_inference_prompt_cost":0.0000126,"upstream_inference_completions_cost":0.0000099},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
 
       data: [DONE]
 
@@ -51,22 +41,22 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 911.277333ms
+    duration: 352.105208ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51043
+    content_length: 51275
     host: ""

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

@@ -15,7 +15,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - OpenAI/Go 2.7.1
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://openrouter.ai/api/v1/chat/completions
     method: POST
   response:
@@ -24,17 +24,17 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1773346371-4q88aKcjB5AruprasyF5","object":"chat.completion.chunk","created":1773346371,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Novita","choices":[{"index":0,"delta":{"content":"List","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      : OPENROUTER PROCESSING
 
-      data: {"id":"gen-1773346371-4q88aKcjB5AruprasyF5","object":"chat.completion.chunk","created":1773346371,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Novita","choices":[{"index":0,"delta":{"content":" files in current directory","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456682-e8NSNDQng0ucLwb9TZoG","object":"chat.completion.chunk","created":1774456682,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"List","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346371-4q88aKcjB5AruprasyF5","object":"chat.completion.chunk","created":1773346371,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Novita","choices":[{"index":0,"delta":{"content":" with","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456682-e8NSNDQng0ucLwb9TZoG","object":"chat.completion.chunk","created":1774456682,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" files in current directory","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346371-4q88aKcjB5AruprasyF5","object":"chat.completion.chunk","created":1773346371,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Novita","choices":[{"index":0,"delta":{"content":" ls","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456682-e8NSNDQng0ucLwb9TZoG","object":"chat.completion.chunk","created":1774456682,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" using ls","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346371-4q88aKcjB5AruprasyF5","object":"chat.completion.chunk","created":1773346371,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Novita","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
+      data: {"id":"gen-1774456682-e8NSNDQng0ucLwb9TZoG","object":"chat.completion.chunk","created":1774456682,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
 
-      data: {"id":"gen-1773346371-4q88aKcjB5AruprasyF5","object":"chat.completion.chunk","created":1773346371,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Novita","choices":[],"usage":{"prompt_tokens":141,"completion_tokens":7,"total_tokens":148,"cost":0.00003165,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.00003165,"upstream_inference_prompt_cost":0.00002115,"upstream_inference_completions_cost":0.0000105},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
+      data: {"id":"gen-1774456682-e8NSNDQng0ucLwb9TZoG","object":"chat.completion.chunk","created":1774456682,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}],"usage":{"prompt_tokens":141,"completion_tokens":7,"total_tokens":148,"cost":0.0000192075,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.00002955,"upstream_inference_prompt_cost":0.00002115,"upstream_inference_completions_cost":0.0000084},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
 
       data: [DONE]
 
@@ -43,22 +43,22 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 917.901459ms
+    duration: 854.344417ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51037
+    content_length: 51269
     host: ""

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

@@ -15,7 +15,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - OpenAI/Go 2.7.1
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://openrouter.ai/api/v1/chat/completions
     method: POST
   response:
@@ -24,19 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1773346378-hfheSaAb9O98TBQ0ELoK","object":"chat.completion.chunk","created":1773346378,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Novita","choices":[{"index":0,"delta":{"content":"Use","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      : OPENROUTER PROCESSING
 
-      data: {"id":"gen-1773346378-hfheSaAb9O98TBQ0ELoK","object":"chat.completion.chunk","created":1773346378,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Novita","choices":[{"index":0,"delta":{"content":" multiedit to","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456692-1bw7QI4pqgllPdwXginq","object":"chat.completion.chunk","created":1774456692,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Google","choices":[{"index":0,"delta":{"content":"Use","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346378-hfheSaAb9O98TBQ0ELoK","object":"chat.completion.chunk","created":1773346378,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Novita","choices":[{"index":0,"delta":{"content":" update greeting","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456692-1bw7QI4pqgllPdwXginq","object":"chat.completion.chunk","created":1774456692,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Google","choices":[{"index":0,"delta":{"content":" multiedit to","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346378-hfheSaAb9O98TBQ0ELoK","object":"chat.completion.chunk","created":1773346378,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Novita","choices":[{"index":0,"delta":{"content":" and add comment in","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456692-1bw7QI4pqgllPdwXginq","object":"chat.completion.chunk","created":1774456692,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Google","choices":[{"index":0,"delta":{"content":" update greeting","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346378-hfheSaAb9O98TBQ0ELoK","object":"chat.completion.chunk","created":1773346378,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Novita","choices":[{"index":0,"delta":{"content":" main.go","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456692-1bw7QI4pqgllPdwXginq","object":"chat.completion.chunk","created":1774456692,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Google","choices":[{"index":0,"delta":{"content":" and add comment in","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346378-hfheSaAb9O98TBQ0ELoK","object":"chat.completion.chunk","created":1773346378,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Novita","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
+      data: {"id":"gen-1774456692-1bw7QI4pqgllPdwXginq","object":"chat.completion.chunk","created":1774456692,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Google","choices":[{"index":0,"delta":{"content":" main.go","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346378-hfheSaAb9O98TBQ0ELoK","object":"chat.completion.chunk","created":1773346378,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Novita","choices":[],"usage":{"prompt_tokens":164,"completion_tokens":13,"total_tokens":177,"cost":0.0000441,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.0000441,"upstream_inference_prompt_cost":0.0000246,"upstream_inference_completions_cost":0.0000195},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
+      data: {"id":"gen-1774456692-1bw7QI4pqgllPdwXginq","object":"chat.completion.chunk","created":1774456692,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Google","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
+
+      data: {"id":"gen-1774456692-1bw7QI4pqgllPdwXginq","object":"chat.completion.chunk","created":1774456692,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Google","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}],"usage":{"prompt_tokens":160,"completion_tokens":14,"total_tokens":174,"cost":0.0000408,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.0000408,"upstream_inference_prompt_cost":0.000024,"upstream_inference_completions_cost":0.0000168},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
 
       data: [DONE]
 
@@ -45,22 +47,22 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 890.058625ms
+    duration: 683.094417ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51123
+    content_length: 51355
     host: ""

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

@@ -15,7 +15,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - OpenAI/Go 2.7.1
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://openrouter.ai/api/v1/chat/completions
     method: POST
   response:
@@ -24,27 +24,31 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1773346444-K8iqCl6Tq9o7IKocQEz7","object":"chat.completion.chunk","created":1773346444,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"Find","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      : OPENROUTER PROCESSING
 
-      data: {"id":"gen-1773346444-K8iqCl6Tq9o7IKocQEz7","object":"chat.completion.chunk","created":1773346444,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" .","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456756-qbHZbvAkQphT61DYgXUh","object":"chat.completion.chunk","created":1774456756,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"Run","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346444-K8iqCl6Tq9o7IKocQEz7","object":"chat.completion.chunk","created":1773346444,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"go","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456756-qbHZbvAkQphT61DYgXUh","object":"chat.completion.chunk","created":1774456756,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" glob","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346444-K8iqCl6Tq9o7IKocQEz7","object":"chat.completion.chunk","created":1773346444,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" files","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456756-qbHZbvAkQphT61DYgXUh","object":"chat.completion.chunk","created":1774456756,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" for","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346444-K8iqCl6Tq9o7IKocQEz7","object":"chat.completion.chunk","created":1773346444,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" and","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456756-qbHZbvAkQphT61DYgXUh","object":"chat.completion.chunk","created":1774456756,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" .","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346444-K8iqCl6Tq9o7IKocQEz7","object":"chat.completion.chunk","created":1773346444,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" list","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456756-qbHZbvAkQphT61DYgXUh","object":"chat.completion.chunk","created":1774456756,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"go","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346444-K8iqCl6Tq9o7IKocQEz7","object":"chat.completion.chunk","created":1773346444,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" directory","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456756-qbHZbvAkQphT61DYgXUh","object":"chat.completion.chunk","created":1774456756,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" files","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346444-K8iqCl6Tq9o7IKocQEz7","object":"chat.completion.chunk","created":1773346444,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" in","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456756-qbHZbvAkQphT61DYgXUh","object":"chat.completion.chunk","created":1774456756,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" and","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346444-K8iqCl6Tq9o7IKocQEz7","object":"chat.completion.chunk","created":1773346444,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" parallel","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456756-qbHZbvAkQphT61DYgXUh","object":"chat.completion.chunk","created":1774456756,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" ls","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346444-K8iqCl6Tq9o7IKocQEz7","object":"chat.completion.chunk","created":1773346444,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
+      data: {"id":"gen-1774456756-qbHZbvAkQphT61DYgXUh","object":"chat.completion.chunk","created":1774456756,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" in","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346444-K8iqCl6Tq9o7IKocQEz7","object":"chat.completion.chunk","created":1773346444,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[],"usage":{"prompt_tokens":156,"completion_tokens":10,"total_tokens":166,"cost":0.0000266,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.0000266,"upstream_inference_prompt_cost":0.0000156,"upstream_inference_completions_cost":0.000011},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
+      data: {"id":"gen-1774456756-qbHZbvAkQphT61DYgXUh","object":"chat.completion.chunk","created":1774456756,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" parallel","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+
+      data: {"id":"gen-1774456756-qbHZbvAkQphT61DYgXUh","object":"chat.completion.chunk","created":1774456756,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
+
+      data: {"id":"gen-1774456756-qbHZbvAkQphT61DYgXUh","object":"chat.completion.chunk","created":1774456756,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}],"usage":{"prompt_tokens":156,"completion_tokens":11,"total_tokens":167,"cost":0.0000277,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.0000277,"upstream_inference_prompt_cost":0.0000156,"upstream_inference_completions_cost":0.0000121},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
 
       data: [DONE]
 
@@ -53,22 +57,22 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 785.290041ms
+    duration: 485.97875ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51134
+    content_length: 51366
     host: ""

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

@@ -15,7 +15,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - OpenAI/Go 2.7.1
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://openrouter.ai/api/v1/chat/completions
     method: POST
   response:
@@ -24,17 +24,15 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1773346308-4TglX5eq0OVD4GrTmKz4","object":"chat.completion.chunk","created":1773346308,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"Read","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      : OPENROUTER PROCESSING
 
-      data: {"id":"gen-1773346308-4TglX5eq0OVD4GrTmKz4","object":"chat.completion.chunk","created":1773346308,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" the","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456604-qXmqMZzVgJogU5OQuEYa","object":"chat.completion.chunk","created":1774456604,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Novita","choices":[{"index":0,"delta":{"content":"Read","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346308-4TglX5eq0OVD4GrTmKz4","object":"chat.completion.chunk","created":1773346308,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" go","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456604-qXmqMZzVgJogU5OQuEYa","object":"chat.completion.chunk","created":1774456604,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Novita","choices":[{"index":0,"delta":{"content":" the go mod","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346308-4TglX5eq0OVD4GrTmKz4","object":"chat.completion.chunk","created":1773346308,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" mod","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456604-qXmqMZzVgJogU5OQuEYa","object":"chat.completion.chunk","created":1774456604,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Novita","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
 
-      data: {"id":"gen-1773346308-4TglX5eq0OVD4GrTmKz4","object":"chat.completion.chunk","created":1773346308,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
-
-      data: {"id":"gen-1773346308-4TglX5eq0OVD4GrTmKz4","object":"chat.completion.chunk","created":1773346308,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[],"usage":{"prompt_tokens":131,"completion_tokens":5,"total_tokens":136,"cost":0.0000186,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.0000186,"upstream_inference_prompt_cost":0.0000131,"upstream_inference_completions_cost":0.0000055},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
+      data: {"id":"gen-1774456604-qXmqMZzVgJogU5OQuEYa","object":"chat.completion.chunk","created":1774456604,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Novita","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}],"usage":{"prompt_tokens":135,"completion_tokens":4,"total_tokens":139,"cost":0.00002625,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.00002625,"upstream_inference_prompt_cost":0.00002025,"upstream_inference_completions_cost":0.000006},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
 
       data: [DONE]
 
@@ -43,22 +41,22 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 1.141124667s
+    duration: 794.436292ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51007
+    content_length: 51239
     host: ""

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

@@ -15,7 +15,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - OpenAI/Go 2.7.1
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://openrouter.ai/api/v1/chat/completions
     method: POST
   response:
@@ -24,11 +24,15 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1773346305-EPRD1xczhbGL5Lx61Bxi","object":"chat.completion.chunk","created":1773346305,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"DeepInfra","choices":[{"index":0,"delta":{"content":"Hello","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      : OPENROUTER PROCESSING
 
-      data: {"id":"gen-1773346305-EPRD1xczhbGL5Lx61Bxi","object":"chat.completion.chunk","created":1773346305,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"DeepInfra","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
+      : OPENROUTER PROCESSING
 
-      data: {"id":"gen-1773346305-EPRD1xczhbGL5Lx61Bxi","object":"chat.completion.chunk","created":1773346305,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"DeepInfra","choices":[],"usage":{"prompt_tokens":128,"completion_tokens":2,"total_tokens":130,"cost":0.00001372,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.00001372,"upstream_inference_prompt_cost":0.00001152,"upstream_inference_completions_cost":0.0000022},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
+      data: {"id":"gen-1774456601-VF56KloP49tZGyNR9PD6","object":"chat.completion.chunk","created":1774456601,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"Hello","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+
+      data: {"id":"gen-1774456601-VF56KloP49tZGyNR9PD6","object":"chat.completion.chunk","created":1774456601,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
+
+      data: {"id":"gen-1774456601-VF56KloP49tZGyNR9PD6","object":"chat.completion.chunk","created":1774456601,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}],"usage":{"prompt_tokens":132,"completion_tokens":1,"total_tokens":133,"cost":0.00001365,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.000021,"upstream_inference_prompt_cost":0.0000198,"upstream_inference_completions_cost":0.0000012},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
 
       data: [DONE]
 
@@ -37,22 +41,22 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 1.422850834s
+    duration: 1.54613175s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50997
+    content_length: 51229
     host: ""

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

@@ -15,7 +15,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - OpenAI/Go 2.7.1
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://openrouter.ai/api/v1/chat/completions
     method: POST
   response:
@@ -24,29 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1773346408-HguKLPahQGX0ilVWriIv","object":"chat.completion.chunk","created":1773346408,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"Search","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      : OPENROUTER PROCESSING
 
-      data: {"id":"gen-1773346408-HguKLPahQGX0ilVWriIv","object":"chat.completion.chunk","created":1773346408,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" for","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456734-n88rDjuZXAhxc7zcBVBK","object":"chat.completion.chunk","created":1774456734,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"Search","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346408-HguKLPahQGX0ilVWriIv","object":"chat.completion.chunk","created":1773346408,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" func","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456734-n88rDjuZXAhxc7zcBVBK","object":"chat.completion.chunk","created":1774456734,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" for func","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346408-HguKLPahQGX0ilVWriIv","object":"chat.completion.chunk","created":1773346408,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" main","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456734-n88rDjuZXAhxc7zcBVBK","object":"chat.completion.chunk","created":1774456734,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" main in Go repositories","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346408-HguKLPahQGX0ilVWriIv","object":"chat.completion.chunk","created":1773346408,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" in","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456734-n88rDjuZXAhxc7zcBVBK","object":"chat.completion.chunk","created":1774456734,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" using Sourcegraph","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346408-HguKLPahQGX0ilVWriIv","object":"chat.completion.chunk","created":1773346408,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" Go","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456734-n88rDjuZXAhxc7zcBVBK","object":"chat.completion.chunk","created":1774456734,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
 
-      data: {"id":"gen-1773346408-HguKLPahQGX0ilVWriIv","object":"chat.completion.chunk","created":1773346408,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" repositories","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
-
-      data: {"id":"gen-1773346408-HguKLPahQGX0ilVWriIv","object":"chat.completion.chunk","created":1773346408,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" using","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
-
-      data: {"id":"gen-1773346408-HguKLPahQGX0ilVWriIv","object":"chat.completion.chunk","created":1773346408,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":" Source","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
-
-      data: {"id":"gen-1773346408-HguKLPahQGX0ilVWriIv","object":"chat.completion.chunk","created":1773346408,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"graph","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
-
-      data: {"id":"gen-1773346408-HguKLPahQGX0ilVWriIv","object":"chat.completion.chunk","created":1773346408,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
-
-      data: {"id":"gen-1773346408-HguKLPahQGX0ilVWriIv","object":"chat.completion.chunk","created":1773346408,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Parasail","choices":[],"usage":{"prompt_tokens":140,"completion_tokens":11,"total_tokens":151,"cost":0.0000261,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.0000261,"upstream_inference_prompt_cost":0.000014,"upstream_inference_completions_cost":0.0000121},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
+      data: {"id":"gen-1774456734-n88rDjuZXAhxc7zcBVBK","object":"chat.completion.chunk","created":1774456734,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}],"usage":{"prompt_tokens":144,"completion_tokens":10,"total_tokens":154,"cost":0.00002184,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.0000336,"upstream_inference_prompt_cost":0.0000216,"upstream_inference_completions_cost":0.000012},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
 
       data: [DONE]
 
@@ -55,22 +45,22 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 667.337583ms
+    duration: 956.934708ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51057
+    content_length: 51289
     host: ""

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

@@ -15,7 +15,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - OpenAI/Go 2.7.1
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://openrouter.ai/api/v1/chat/completions
     method: POST
   response:
@@ -24,17 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1773346314-pTxjL4NOw61KwDwlBC4C","object":"chat.completion.chunk","created":1773346314,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"Update","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      : OPENROUTER PROCESSING
 
-      data: {"id":"gen-1773346314-pTxjL4NOw61KwDwlBC4C","object":"chat.completion.chunk","created":1773346314,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" main.go to print","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456613-kga4lFcyckfpo5fCgXsx","object":"chat.completion.chunk","created":1774456613,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"Update","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346314-pTxjL4NOw61KwDwlBC4C","object":"chat.completion.chunk","created":1773346314,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" hello","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456613-kga4lFcyckfpo5fCgXsx","object":"chat.completion.chunk","created":1774456613,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" main.go to print","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346314-pTxjL4NOw61KwDwlBC4C","object":"chat.completion.chunk","created":1773346314,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" from crush","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456613-kga4lFcyckfpo5fCgXsx","object":"chat.completion.chunk","created":1774456613,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" hello","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346314-pTxjL4NOw61KwDwlBC4C","object":"chat.completion.chunk","created":1773346314,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
+      data: {"id":"gen-1774456613-kga4lFcyckfpo5fCgXsx","object":"chat.completion.chunk","created":1774456613,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" from crush","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346314-pTxjL4NOw61KwDwlBC4C","object":"chat.completion.chunk","created":1773346314,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[],"usage":{"prompt_tokens":145,"completion_tokens":8,"total_tokens":153,"cost":0.0000203775,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.00003135,"upstream_inference_prompt_cost":0.00002175,"upstream_inference_completions_cost":0.0000096},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
+      data: {"id":"gen-1774456613-kga4lFcyckfpo5fCgXsx","object":"chat.completion.chunk","created":1774456613,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
+
+      data: {"id":"gen-1774456613-kga4lFcyckfpo5fCgXsx","object":"chat.completion.chunk","created":1774456613,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}],"usage":{"prompt_tokens":145,"completion_tokens":8,"total_tokens":153,"cost":0.0000203775,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.00003135,"upstream_inference_prompt_cost":0.00002175,"upstream_inference_completions_cost":0.0000096},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
 
       data: [DONE]
 
@@ -43,22 +45,22 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 667.790583ms
+    duration: 598.857875ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51063
+    content_length: 51295
     host: ""

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

@@ -15,7 +15,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - OpenAI/Go 2.7.1
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://openrouter.ai/api/v1/chat/completions
     method: POST
   response:
@@ -24,17 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1773346434-55tqPNTfjytUMCK8C2DN","object":"chat.completion.chunk","created":1773346434,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"Create","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      : OPENROUTER PROCESSING
 
-      data: {"id":"gen-1773346434-55tqPNTfjytUMCK8C2DN","object":"chat.completion.chunk","created":1773346434,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" config.json with sample","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456747-3dOGy2K1ZrWDbyNYaNyT","object":"chat.completion.chunk","created":1774456747,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"Create","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346434-55tqPNTfjytUMCK8C2DN","object":"chat.completion.chunk","created":1773346434,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" JSON","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456747-3dOGy2K1ZrWDbyNYaNyT","object":"chat.completion.chunk","created":1774456747,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" config.json with sample","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346434-55tqPNTfjytUMCK8C2DN","object":"chat.completion.chunk","created":1773346434,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" content","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
+      data: {"id":"gen-1774456747-3dOGy2K1ZrWDbyNYaNyT","object":"chat.completion.chunk","created":1774456747,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" JSON","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346434-55tqPNTfjytUMCK8C2DN","object":"chat.completion.chunk","created":1773346434,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
+      data: {"id":"gen-1774456747-3dOGy2K1ZrWDbyNYaNyT","object":"chat.completion.chunk","created":1774456747,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":" content","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1773346434-55tqPNTfjytUMCK8C2DN","object":"chat.completion.chunk","created":1773346434,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[],"usage":{"prompt_tokens":159,"completion_tokens":7,"total_tokens":166,"cost":0.0000209625,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.00003225,"upstream_inference_prompt_cost":0.00002385,"upstream_inference_completions_cost":0.0000084},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
+      data: {"id":"gen-1774456747-3dOGy2K1ZrWDbyNYaNyT","object":"chat.completion.chunk","created":1774456747,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
+
+      data: {"id":"gen-1774456747-3dOGy2K1ZrWDbyNYaNyT","object":"chat.completion.chunk","created":1774456747,"model":"qwen/qwen3-next-80b-a3b-instruct-2509","provider":"Alibaba","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}],"usage":{"prompt_tokens":159,"completion_tokens":7,"total_tokens":166,"cost":0.0000209625,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.00003225,"upstream_inference_prompt_cost":0.00002385,"upstream_inference_completions_cost":0.0000084},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}
 
       data: [DONE]
 
@@ -43,22 +45,22 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 1.003629375s
+    duration: 569.744791ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 51100
+    content_length: 51332
     host: ""

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

@@ -24,21 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"2026031304143176ff481eb8d34725","created":1773346471,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"20260326003947ebfb4d16b83248b7","created":1774456787,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"2026031304143176ff481eb8d34725","created":1773346471,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Creating"}}]}
+      data: {"id":"20260326003947ebfb4d16b83248b7","created":1774456787,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"B"}}]}
 
-      data: {"id":"2026031304143176ff481eb8d34725","created":1773346471,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" test"}}]}
+      data: {"id":"20260326003947ebfb4d16b83248b7","created":1774456787,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"ash"}}]}
 
-      data: {"id":"2026031304143176ff481eb8d34725","created":1773346471,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".txt"}}]}
+      data: {"id":"20260326003947ebfb4d16b83248b7","created":1774456787,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" file"}}]}
 
-      data: {"id":"2026031304143176ff481eb8d34725","created":1773346471,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
+      data: {"id":"20260326003947ebfb4d16b83248b7","created":1774456787,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" creation"}}]}
 
-      data: {"id":"2026031304143176ff481eb8d34725","created":1773346471,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" bash"}}]}
+      data: {"id":"20260326003947ebfb4d16b83248b7","created":1774456787,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" without"}}]}
 
-      data: {"id":"2026031304143176ff481eb8d34725","created":1773346471,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" content"}}]}
+      data: {"id":"20260326003947ebfb4d16b83248b7","created":1774456787,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" timestamp"}}]}
 
-      data: {"id":"2026031304143176ff481eb8d34725","created":1773346471,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":140,"completion_tokens":10,"total_tokens":150,"prompt_tokens_details":{"cached_tokens":114}}}
+      data: {"id":"20260326003947ebfb4d16b83248b7","created":1774456787,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":140,"completion_tokens":10,"total_tokens":150,"prompt_tokens_details":{"cached_tokens":114}}}
 
       data: [DONE]
 
@@ -47,15 +47,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 627.333917ms
+    duration: 670.626042ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50924
+    content_length: 51156
     host: ""

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

@@ -24,19 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20260313041436a1f83a7f81b64392","created":1773346476,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"20260326003953b49a83f756f94900","created":1774456793,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"20260313041436a1f83a7f81b64392","created":1773346476,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Download"}}]}
+      data: {"id":"20260326003953b49a83f756f94900","created":1774456793,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Download"}}]}
 
-      data: {"id":"20260313041436a1f83a7f81b64392","created":1773346476,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" example"}}]}
+      data: {"id":"20260326003953b49a83f756f94900","created":1774456793,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" file"}}]}
 
-      data: {"id":"20260313041436a1f83a7f81b64392","created":1773346476,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".txt"}}]}
+      data: {"id":"20260326003953b49a83f756f94900","created":1774456793,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" example"}}]}
 
-      data: {"id":"20260313041436a1f83a7f81b64392","created":1773346476,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" from"}}]}
+      data: {"id":"20260326003953b49a83f756f94900","created":1774456793,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" from"}}]}
 
-      data: {"id":"20260313041436a1f83a7f81b64392","created":1773346476,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" URL"}}]}
+      data: {"id":"20260326003953b49a83f756f94900","created":1774456793,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" URL"}}]}
 
-      data: {"id":"20260313041436a1f83a7f81b64392","created":1773346476,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":143,"completion_tokens":9,"total_tokens":152,"prompt_tokens_details":{"cached_tokens":114}}}
+      data: {"id":"20260326003953b49a83f756f94900","created":1774456793,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":143,"completion_tokens":9,"total_tokens":152,"prompt_tokens_details":{"cached_tokens":114}}}
 
       data: [DONE]
 
@@ -45,15 +45,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 687.490875ms
+    duration: 804.547167ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50949
+    content_length: 51181
     host: ""

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

@@ -24,23 +24,31 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20260313041457b8e4f6c46e7c468d","created":1773346497,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"2026032600395898ee153e91124c9d","created":1774456798,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"20260313041457b8e4f6c46e7c468d","created":1773346497,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Check"}}]}
+      data: {"id":"2026032600395898ee153e91124c9d","created":1774456798,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Fetch"}}]}
 
-      data: {"id":"20260313041457b8e4f6c46e7c468d","created":1773346497,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" for"}}]}
+      data: {"id":"2026032600395898ee153e91124c9d","created":1774456798,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" and"}}]}
 
-      data: {"id":"20260313041457b8e4f6c46e7c468d","created":1773346497,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" John"}}]}
+      data: {"id":"2026032600395898ee153e91124c9d","created":1774456798,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" check"}}]}
 
-      data: {"id":"20260313041457b8e4f6c46e7c468d","created":1773346497,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Doe"}}]}
+      data: {"id":"2026032600395898ee153e91124c9d","created":1774456798,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" for"}}]}
 
-      data: {"id":"20260313041457b8e4f6c46e7c468d","created":1773346497,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" in"}}]}
+      data: {"id":"2026032600395898ee153e91124c9d","created":1774456798,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" '"}}]}
 
-      data: {"id":"20260313041457b8e4f6c46e7c468d","created":1773346497,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" HTML"}}]}
+      data: {"id":"2026032600395898ee153e91124c9d","created":1774456798,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"John"}}]}
 
-      data: {"id":"20260313041457b8e4f6c46e7c468d","created":1773346497,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" content"}}]}
+      data: {"id":"2026032600395898ee153e91124c9d","created":1774456798,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Doe"}}]}
 
-      data: {"id":"20260313041457b8e4f6c46e7c468d","created":1773346497,"object":"chat.completion.chunk","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":"2026032600395898ee153e91124c9d","created":1774456798,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"'"}}]}
+
+      data: {"id":"2026032600395898ee153e91124c9d","created":1774456798,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" in"}}]}
+
+      data: {"id":"2026032600395898ee153e91124c9d","created":1774456798,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" HTML"}}]}
+
+      data: {"id":"2026032600395898ee153e91124c9d","created":1774456798,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" content"}}]}
+
+      data: {"id":"2026032600395898ee153e91124c9d","created":1774456798,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":148,"completion_tokens":15,"total_tokens":163,"prompt_tokens_details":{"cached_tokens":114}}}
 
       data: [DONE]
 
@@ -49,15 +57,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 653.304417ms
+    duration: 665.613834ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50967
+    content_length: 51199
     host: ""

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

@@ -24,21 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"202603130415039728beb3b5dc461d","created":1773346503,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"2026032600400301b4c6a0d1fe40ef","created":1774456803,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"202603130415039728beb3b5dc461d","created":1773346503,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Find"}}]}
+      data: {"id":"2026032600400301b4c6a0d1fe40ef","created":1774456803,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Go"}}]}
 
-      data: {"id":"202603130415039728beb3b5dc461d","created":1773346503,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" all"}}]}
+      data: {"id":"2026032600400301b4c6a0d1fe40ef","created":1774456803,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" file"}}]}
 
-      data: {"id":"202603130415039728beb3b5dc461d","created":1773346503,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Go"}}]}
+      data: {"id":"2026032600400301b4c6a0d1fe40ef","created":1774456803,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" search"}}]}
 
-      data: {"id":"202603130415039728beb3b5dc461d","created":1773346503,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" files"}}]}
+      data: {"id":"2026032600400301b4c6a0d1fe40ef","created":1774456803,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
 
-      data: {"id":"202603130415039728beb3b5dc461d","created":1773346503,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
+      data: {"id":"2026032600400301b4c6a0d1fe40ef","created":1774456803,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" glob"}}]}
 
-      data: {"id":"202603130415039728beb3b5dc461d","created":1773346503,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" glob"}}]}
-
-      data: {"id":"202603130415039728beb3b5dc461d","created":1773346503,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":132,"completion_tokens":10,"total_tokens":142,"prompt_tokens_details":{"cached_tokens":115}}}
+      data: {"id":"2026032600400301b4c6a0d1fe40ef","created":1774456803,"object":"chat.completion.chunk","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]
 
@@ -47,15 +45,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 692.47975ms
+    duration: 671.620667ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50885
+    content_length: 51117
     host: ""

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

@@ -24,17 +24,17 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20260313041507c3bb3653caaa4a29","created":1773346507,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"20260326004006160d61700e42415d","created":1774456806,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"20260313041507c3bb3653caaa4a29","created":1773346507,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"grep"}}]}
+      data: {"id":"20260326004006160d61700e42415d","created":1774456806,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"grep"}}]}
 
-      data: {"id":"20260313041507c3bb3653caaa4a29","created":1773346507,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" package"}}]}
+      data: {"id":"20260326004006160d61700e42415d","created":1774456806,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" package"}}]}
 
-      data: {"id":"20260313041507c3bb3653caaa4a29","created":1773346507,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" *."}}]}
+      data: {"id":"20260326004006160d61700e42415d","created":1774456806,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" *."}}]}
 
-      data: {"id":"20260313041507c3bb3653caaa4a29","created":1773346507,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"go"}}]}
+      data: {"id":"20260326004006160d61700e42415d","created":1774456806,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"go"}}]}
 
-      data: {"id":"20260313041507c3bb3653caaa4a29","created":1773346507,"object":"chat.completion.chunk","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":115}}}
+      data: {"id":"20260326004006160d61700e42415d","created":1774456806,"object":"chat.completion.chunk","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":115}}}
 
       data: [DONE]
 
@@ -43,15 +43,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 608.726334ms
+    duration: 705.752167ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50883
+    content_length: 51115
     host: ""

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

@@ -24,17 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20260313041513cafe5646e30a4b09","created":1773346513,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"202603260040152d5e76d3cea9425a","created":1774456815,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"20260313041513cafe5646e30a4b09","created":1773346513,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"List"}}]}
+      data: {"id":"202603260040152d5e76d3cea9425a","created":1774456815,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"List"}}]}
 
-      data: {"id":"20260313041513cafe5646e30a4b09","created":1773346513,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Files"}}]}
+      data: {"id":"202603260040152d5e76d3cea9425a","created":1774456815,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" files"}}]}
 
-      data: {"id":"20260313041513cafe5646e30a4b09","created":1773346513,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
+      data: {"id":"202603260040152d5e76d3cea9425a","created":1774456815,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
 
-      data: {"id":"20260313041513cafe5646e30a4b09","created":1773346513,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" ls"}}]}
+      data: {"id":"202603260040152d5e76d3cea9425a","created":1774456815,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" ls"}}]}
 
-      data: {"id":"20260313041513cafe5646e30a4b09","created":1773346513,"object":"chat.completion.chunk","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":115}}}
+      data: {"id":"202603260040152d5e76d3cea9425a","created":1774456815,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" command"}}]}
+
+      data: {"id":"202603260040152d5e76d3cea9425a","created":1774456815,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":130,"completion_tokens":9,"total_tokens":139,"prompt_tokens_details":{"cached_tokens":115}}}
 
       data: [DONE]
 
@@ -43,15 +45,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 650.921958ms
+    duration: 640.512209ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50877
+    content_length: 51109
     host: ""

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

@@ -24,21 +24,25 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"2026031304151715bb72c64ce040ce","created":1773346517,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"20260326004018b881b8e25e054a99","created":1774456818,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"2026031304151715bb72c64ce040ce","created":1773346517,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Mult"}}]}
+      data: {"id":"20260326004018b881b8e25e054a99","created":1774456818,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Mult"}}]}
 
-      data: {"id":"2026031304151715bb72c64ce040ce","created":1773346517,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"ied"}}]}
+      data: {"id":"20260326004018b881b8e25e054a99","created":1774456818,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"ied"}}]}
 
-      data: {"id":"2026031304151715bb72c64ce040ce","created":1773346517,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"it"}}]}
+      data: {"id":"20260326004018b881b8e25e054a99","created":1774456818,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"it"}}]}
 
-      data: {"id":"2026031304151715bb72c64ce040ce","created":1773346517,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Go"}}]}
+      data: {"id":"20260326004018b881b8e25e054a99","created":1774456818,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" changes"}}]}
 
-      data: {"id":"2026031304151715bb72c64ce040ce","created":1773346517,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Code"}}]}
+      data: {"id":"20260326004018b881b8e25e054a99","created":1774456818,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" in"}}]}
 
-      data: {"id":"2026031304151715bb72c64ce040ce","created":1773346517,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Modification"}}]}
+      data: {"id":"20260326004018b881b8e25e054a99","created":1774456818,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" main"}}]}
 
-      data: {"id":"2026031304151715bb72c64ce040ce","created":1773346517,"object":"chat.completion.chunk","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":115}}}
+      data: {"id":"20260326004018b881b8e25e054a99","created":1774456818,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".go"}}]}
+
+      data: {"id":"20260326004018b881b8e25e054a99","created":1774456818,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" file"}}]}
+
+      data: {"id":"20260326004018b881b8e25e054a99","created":1774456818,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":153,"completion_tokens":12,"total_tokens":165,"prompt_tokens_details":{"cached_tokens":115}}}
 
       data: [DONE]
 
@@ -47,15 +51,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 617.22425ms
+    duration: 700.349292ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50963
+    content_length: 51195
     host: ""

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

@@ -24,25 +24,25 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20260313041539bcf7d231fb614122","created":1773346539,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"202603260040440feda096cd8a4f0c","created":1774456844,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"20260313041539bcf7d231fb614122","created":1773346539,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Parallel"}}]}
+      data: {"id":"202603260040440feda096cd8a4f0c","created":1774456844,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"glob"}}]}
 
-      data: {"id":"20260313041539bcf7d231fb614122","created":1773346539,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" glob"}}]}
+      data: {"id":"202603260040440feda096cd8a4f0c","created":1774456844,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" find"}}]}
 
-      data: {"id":"20260313041539bcf7d231fb614122","created":1773346539,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" and"}}]}
+      data: {"id":"202603260040440feda096cd8a4f0c","created":1774456844,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" go"}}]}
 
-      data: {"id":"20260313041539bcf7d231fb614122","created":1773346539,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" ls"}}]}
+      data: {"id":"202603260040440feda096cd8a4f0c","created":1774456844,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" files"}}]}
 
-      data: {"id":"20260313041539bcf7d231fb614122","created":1773346539,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" commands"}}]}
+      data: {"id":"202603260040440feda096cd8a4f0c","created":1774456844,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" ls"}}]}
 
-      data: {"id":"20260313041539bcf7d231fb614122","created":1773346539,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" for"}}]}
+      data: {"id":"202603260040440feda096cd8a4f0c","created":1774456844,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" list"}}]}
 
-      data: {"id":"20260313041539bcf7d231fb614122","created":1773346539,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Go"}}]}
+      data: {"id":"202603260040440feda096cd8a4f0c","created":1774456844,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" directory"}}]}
 
-      data: {"id":"20260313041539bcf7d231fb614122","created":1773346539,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" files"}}]}
+      data: {"id":"202603260040440feda096cd8a4f0c","created":1774456844,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" parallel"}}]}
 
-      data: {"id":"20260313041539bcf7d231fb614122","created":1773346539,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":149,"completion_tokens":12,"total_tokens":161,"prompt_tokens_details":{"cached_tokens":122}}}
+      data: {"id":"202603260040440feda096cd8a4f0c","created":1774456844,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":149,"completion_tokens":12,"total_tokens":161,"prompt_tokens_details":{"cached_tokens":122}}}
 
       data: [DONE]
 
@@ -51,15 +51,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 698.619667ms
+    duration: 587.556292ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50974
+    content_length: 51206
     host: ""

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

@@ -24,15 +24,17 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20260313041419382e7728255d4003","created":1773346459,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"202603260039353515ac4e38944910","created":1774456776,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"20260313041419382e7728255d4003","created":1773346459,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Go"}}]}
+      data: {"id":"202603260039353515ac4e38944910","created":1774456776,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Read"}}]}
 
-      data: {"id":"20260313041419382e7728255d4003","created":1773346459,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" mod"}}]}
+      data: {"id":"202603260039353515ac4e38944910","created":1774456776,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" the"}}]}
 
-      data: {"id":"20260313041419382e7728255d4003","created":1773346459,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" reading"}}]}
+      data: {"id":"202603260039353515ac4e38944910","created":1774456776,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" go"}}]}
 
-      data: {"id":"20260313041419382e7728255d4003","created":1773346459,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":124,"completion_tokens":7,"total_tokens":131,"prompt_tokens_details":{"cached_tokens":114}}}
+      data: {"id":"202603260039353515ac4e38944910","created":1774456776,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" mod"}}]}
+
+      data: {"id":"202603260039353515ac4e38944910","created":1774456776,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":124,"completion_tokens":8,"total_tokens":132,"prompt_tokens_details":{"cached_tokens":114}}}
 
       data: [DONE]
 
@@ -41,15 +43,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 751.460042ms
+    duration: 701.49375ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50847
+    content_length: 51079
     host: ""

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

@@ -24,13 +24,15 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"202603130414168ff3a068e783494c","created":1773346456,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"20260326003933b3aba6ff49a24113","created":1774456773,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"202603130414168ff3a068e783494c","created":1773346456,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"G"}}]}
+      data: {"id":"20260326003933b3aba6ff49a24113","created":1774456773,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Simple"}}]}
 
-      data: {"id":"202603130414168ff3a068e783494c","created":1773346456,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"reeting"}}]}
+      data: {"id":"20260326003933b3aba6ff49a24113","created":1774456773,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" G"}}]}
 
-      data: {"id":"202603130414168ff3a068e783494c","created":1773346456,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":121,"completion_tokens":6,"total_tokens":127,"prompt_tokens_details":{"cached_tokens":4}}}
+      data: {"id":"20260326003933b3aba6ff49a24113","created":1774456773,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"reeting"}}]}
+
+      data: {"id":"20260326003933b3aba6ff49a24113","created":1774456773,"object":"chat.completion.chunk","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":4}}}
 
       data: [DONE]
 
@@ -39,15 +41,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.762131625s
+    duration: 2.772573542s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50837
+    content_length: 51069
     host: ""

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

@@ -24,17 +24,17 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"202603130415283ca31ec31524434b","created":1773346528,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"20260326004031f8bdfe37dc4a4d25","created":1774456831,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"202603130415283ca31ec31524434b","created":1773346528,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Go"}}]}
+      data: {"id":"20260326004031f8bdfe37dc4a4d25","created":1774456831,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Go"}}]}
 
-      data: {"id":"202603130415283ca31ec31524434b","created":1773346528,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" main"}}]}
+      data: {"id":"20260326004031f8bdfe37dc4a4d25","created":1774456831,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" function"}}]}
 
-      data: {"id":"202603130415283ca31ec31524434b","created":1773346528,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" function"}}]}
+      data: {"id":"20260326004031f8bdfe37dc4a4d25","created":1774456831,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" main"}}]}
 
-      data: {"id":"202603130415283ca31ec31524434b","created":1773346528,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" search"}}]}
+      data: {"id":"20260326004031f8bdfe37dc4a4d25","created":1774456831,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" search"}}]}
 
-      data: {"id":"202603130415283ca31ec31524434b","created":1773346528,"object":"chat.completion.chunk","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":115}}}
+      data: {"id":"20260326004031f8bdfe37dc4a4d25","created":1774456831,"object":"chat.completion.chunk","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":115}}}
 
       data: [DONE]
 
@@ -43,15 +43,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 676.245916ms
+    duration: 681.869334ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50897
+    content_length: 51129
     host: ""

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

@@ -24,21 +24,23 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"2026031304142637b25add063545df","created":1773346466,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"2026032600393934a6335421aa4b8e","created":1774456780,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"2026031304142637b25add063545df","created":1773346466,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Update"}}]}
+      data: {"id":"2026032600393934a6335421aa4b8e","created":1774456780,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Update"}}]}
 
-      data: {"id":"2026031304142637b25add063545df","created":1773346466,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" main"}}]}
+      data: {"id":"2026032600393934a6335421aa4b8e","created":1774456780,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" main"}}]}
 
-      data: {"id":"2026031304142637b25add063545df","created":1773346466,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".go"}}]}
+      data: {"id":"2026032600393934a6335421aa4b8e","created":1774456780,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".go"}}]}
 
-      data: {"id":"2026031304142637b25add063545df","created":1773346466,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" to"}}]}
+      data: {"id":"2026032600393934a6335421aa4b8e","created":1774456780,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" to"}}]}
 
-      data: {"id":"2026031304142637b25add063545df","created":1773346466,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" print"}}]}
+      data: {"id":"2026032600393934a6335421aa4b8e","created":1774456780,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" print"}}]}
 
-      data: {"id":"2026031304142637b25add063545df","created":1773346466,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" hello"}}]}
+      data: {"id":"2026032600393934a6335421aa4b8e","created":1774456780,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" hello"}}]}
 
-      data: {"id":"2026031304142637b25add063545df","created":1773346466,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":134,"completion_tokens":10,"total_tokens":144,"prompt_tokens_details":{"cached_tokens":114}}}
+      data: {"id":"2026032600393934a6335421aa4b8e","created":1774456780,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" crush"}}]}
+
+      data: {"id":"2026032600393934a6335421aa4b8e","created":1774456780,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":134,"completion_tokens":11,"total_tokens":145,"prompt_tokens_details":{"cached_tokens":114}}}
 
       data: [DONE]
 
@@ -47,15 +49,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.264043875s
+    duration: 715.173125ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50903
+    content_length: 51135
     host: ""

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

@@ -24,23 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"202603130415354342f3e7fce041ac","created":1773346535,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
+      data: {"id":"202603260040399cfa6f5afdb84416","created":1774456839,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"\n"}}]}
 
-      data: {"id":"202603130415354342f3e7fce041ac","created":1773346535,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Creating"}}]}
+      data: {"id":"202603260040399cfa6f5afdb84416","created":1774456839,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Create"}}]}
 
-      data: {"id":"202603130415354342f3e7fce041ac","created":1773346535,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" config"}}]}
+      data: {"id":"202603260040399cfa6f5afdb84416","created":1774456839,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" config"}}]}
 
-      data: {"id":"202603130415354342f3e7fce041ac","created":1773346535,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".json"}}]}
+      data: {"id":"202603260040399cfa6f5afdb84416","created":1774456839,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".json"}}]}
 
-      data: {"id":"202603130415354342f3e7fce041ac","created":1773346535,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" file"}}]}
+      data: {"id":"202603260040399cfa6f5afdb84416","created":1774456839,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
 
-      data: {"id":"202603130415354342f3e7fce041ac","created":1773346535,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
+      data: {"id":"202603260040399cfa6f5afdb84416","created":1774456839,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" content"}}]}
 
-      data: {"id":"202603130415354342f3e7fce041ac","created":1773346535,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" write"}}]}
-
-      data: {"id":"202603130415354342f3e7fce041ac","created":1773346535,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" command"}}]}
-
-      data: {"id":"202603130415354342f3e7fce041ac","created":1773346535,"object":"chat.completion.chunk","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":"202603260040399cfa6f5afdb84416","created":1774456839,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"finish_reason":"stop","delta":{"role":"assistant","content":""}}],"usage":{"prompt_tokens":148,"completion_tokens":9,"total_tokens":157,"prompt_tokens_details":{"cached_tokens":115}}}
 
       data: [DONE]
 
@@ -49,15 +45,15 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 626.617ms
+    duration: 697.623042ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50940
+    content_length: 51172
     host: ""

internal/agent/tools/fetch.go 🔗

@@ -16,7 +16,10 @@ import (
 	"github.com/charmbracelet/crush/internal/permission"
 )
 
-const FetchToolName = "fetch"
+const (
+	FetchToolName = "fetch"
+	MaxFetchSize  = 1 * 1024 * 1024 // 1MB
+)
 
 //go:embed fetch.md
 var fetchDescription []byte
@@ -105,11 +108,7 @@ func NewFetchTool(permissions permission.Service, workingDir string, client *htt
 				return fantasy.NewTextErrorResponse(fmt.Sprintf("Request failed with status code: %d", resp.StatusCode)), nil
 			}
 
-			// maxFetchResponseSizeBytes is the maximum size of response body to read (5MB)
-			const maxFetchResponseSizeBytes = int64(5 * 1024 * 1024)
-
-			maxSize := maxFetchResponseSizeBytes
-			body, err := io.ReadAll(io.LimitReader(resp.Body, maxSize))
+			body, err := io.ReadAll(io.LimitReader(resp.Body, MaxFetchSize))
 			if err != nil {
 				return fantasy.NewTextErrorResponse("Failed to read response body: " + err.Error()), nil
 			}
@@ -161,9 +160,9 @@ func NewFetchTool(permissions permission.Service, workingDir string, client *htt
 				}
 			}
 			// truncate content if it exceeds max read size
-			if int64(len(content)) > MaxReadSize {
-				content = content[:MaxReadSize]
-				content += fmt.Sprintf("\n\n[Content truncated to %d bytes]", MaxReadSize)
+			if int64(len(content)) > MaxFetchSize {
+				content = content[:MaxFetchSize]
+				content += fmt.Sprintf("\n\n[Content truncated to %d bytes]", MaxFetchSize)
 			}
 
 			return fantasy.NewTextResponse(content), nil

internal/agent/tools/view.go 🔗

@@ -53,7 +53,7 @@ type ViewResponseMetadata struct {
 
 const (
 	ViewToolName     = "view"
-	MaxReadSize      = 5 * 1024 * 1024 // 5MB
+	MaxViewSize      = 1 * 1024 * 1024 // 1MB
 	DefaultReadLimit = 2000
 	MaxLineLength    = 2000
 )
@@ -155,9 +155,9 @@ func NewViewTool(
 			}
 
 			// Based on the specifications we should not limit the skills read.
-			if !isSkillFile && fileInfo.Size() > MaxReadSize {
+			if !isSkillFile && fileInfo.Size() > MaxViewSize {
 				return fantasy.NewTextErrorResponse(fmt.Sprintf("File is too large (%d bytes). Maximum size is %d bytes",
-					fileInfo.Size(), MaxReadSize)), nil
+					fileInfo.Size(), MaxViewSize)), nil
 			}
 
 			// Set default limit if not provided (no limit for SKILL.md files)

internal/cmd/root.go 🔗

@@ -3,6 +3,7 @@ package cmd
 import (
 	"bytes"
 	"context"
+	_ "embed"
 	"errors"
 	"fmt"
 	"io"
@@ -592,3 +593,27 @@ func ResolveCwd(cmd *cobra.Command) (string, error) {
 	}
 	return cwd, nil
 }
+
+func createDotCrushDir(dir string) error {
+	if err := os.MkdirAll(dir, 0o700); err != nil {
+		return fmt.Errorf("failed to create data directory: %q %w", dir, err)
+	}
+
+	gitIgnorePath := filepath.Join(dir, ".gitignore")
+	content, err := os.ReadFile(gitIgnorePath)
+
+	// create or update if old version
+	if os.IsNotExist(err) || string(content) == oldGitIgnore {
+		if err := os.WriteFile(gitIgnorePath, []byte(defaultGitIgnore), 0o644); err != nil {
+			return fmt.Errorf("failed to create .gitignore file: %q %w", gitIgnorePath, err)
+		}
+	}
+
+	return nil
+}
+
+//go:embed gitignore/old
+var oldGitIgnore string
+
+//go:embed gitignore/default
+var defaultGitIgnore string

internal/cmd/session.go 🔗

@@ -9,12 +9,14 @@ import (
 	"os"
 	"os/exec"
 	"runtime"
+	"sort"
 	"strings"
 	"syscall"
 	"time"
 
 	"charm.land/lipgloss/v2"
 	"github.com/charmbracelet/colorprofile"
+	"github.com/charmbracelet/crush/internal/agent/tools"
 	"github.com/charmbracelet/crush/internal/config"
 	"github.com/charmbracelet/crush/internal/db"
 	"github.com/charmbracelet/crush/internal/event"
@@ -397,6 +399,7 @@ func messagePtrs(msgs []message.Message) []*message.Message {
 }
 
 func outputSessionJSON(w io.Writer, sess session.Session, msgs []*message.Message) error {
+	skills := extractSkillsFromMessages(msgs)
 	output := sessionShowOutput{
 		Meta: sessionShowMeta{
 			ID:               session.HashID(sess.ID),
@@ -408,6 +411,7 @@ func outputSessionJSON(w io.Writer, sess session.Session, msgs []*message.Messag
 			PromptTokens:     sess.PromptTokens,
 			CompletionTokens: sess.CompletionTokens,
 			TotalTokens:      sess.PromptTokens + sess.CompletionTokens,
+			Skills:           skills,
 		},
 		Messages: make([]sessionShowMessage, len(msgs)),
 	}
@@ -444,6 +448,8 @@ func outputSessionHuman(ctx context.Context, sess session.Session, msgs []*messa
 	hash := session.HashID(sess.ID)[:12]
 	created := time.Unix(sess.CreatedAt, 0).Format("Mon Jan 2 15:04:05 2006 -0700")
 
+	skills := extractSkillsFromMessages(msgs)
+
 	// Render to buffer to determine actual height
 	var buf strings.Builder
 
@@ -451,6 +457,19 @@ func outputSessionHuman(ctx context.Context, sess session.Session, msgs []*messa
 	fmt.Fprintln(&buf, keyStyle.Render("UUID:  ")+valStyle.Render(sess.ID))
 	fmt.Fprintln(&buf, keyStyle.Render("Title: ")+valStyle.Render(sess.Title))
 	fmt.Fprintln(&buf, keyStyle.Render("Date:  ")+valStyle.Render(created))
+	if len(skills) > 0 {
+		skillNames := make([]string, len(skills))
+		for i, s := range skills {
+			timestamp := time.Unix(sess.CreatedAt, 0).Format("15:04:05 -0700")
+			if s.LoadedAt != "" {
+				if t, err := time.Parse(time.RFC3339, s.LoadedAt); err == nil {
+					timestamp = t.Format("15:04:05 -0700")
+				}
+			}
+			skillNames[i] = fmt.Sprintf("%s (%s)", s.Name, timestamp)
+		}
+		fmt.Fprintln(&buf, keyStyle.Render("Skills: ")+valStyle.Render(strings.Join(skillNames, ", ")))
+	}
 	fmt.Fprintln(&buf)
 
 	first := true
@@ -539,15 +558,22 @@ func sessionWriter(ctx context.Context, contentHeight int) (io.Writer, func(), b
 }
 
 type sessionShowMeta struct {
-	ID               string  `json:"id"`
-	UUID             string  `json:"uuid"`
-	Title            string  `json:"title"`
-	Created          string  `json:"created"`
-	Modified         string  `json:"modified"`
-	Cost             float64 `json:"cost"`
-	PromptTokens     int64   `json:"prompt_tokens"`
-	CompletionTokens int64   `json:"completion_tokens"`
-	TotalTokens      int64   `json:"total_tokens"`
+	ID               string             `json:"id"`
+	UUID             string             `json:"uuid"`
+	Title            string             `json:"title"`
+	Created          string             `json:"created"`
+	Modified         string             `json:"modified"`
+	Cost             float64            `json:"cost"`
+	PromptTokens     int64              `json:"prompt_tokens"`
+	CompletionTokens int64              `json:"completion_tokens"`
+	TotalTokens      int64              `json:"total_tokens"`
+	Skills           []sessionShowSkill `json:"skills,omitempty"`
+}
+
+type sessionShowSkill struct {
+	Name        string `json:"name"`
+	Description string `json:"description"`
+	LoadedAt    string `json:"loaded_at"`
 }
 
 type sessionShowMessage struct {
@@ -592,6 +618,40 @@ type sessionShowPart struct {
 	Time   int64  `json:"time,omitempty"`
 }
 
+func extractSkillsFromMessages(msgs []*message.Message) []sessionShowSkill {
+	var skills []sessionShowSkill
+	seen := make(map[string]bool)
+
+	for _, msg := range msgs {
+		for _, part := range msg.Parts {
+			if tr, ok := part.(message.ToolResult); ok && tr.Metadata != "" {
+				var meta tools.ViewResponseMetadata
+				if err := json.Unmarshal([]byte(tr.Metadata), &meta); err == nil {
+					if meta.ResourceType == tools.ViewResourceSkill && meta.ResourceName != "" {
+						if !seen[meta.ResourceName] {
+							seen[meta.ResourceName] = true
+							skills = append(skills, sessionShowSkill{
+								Name:        meta.ResourceName,
+								Description: meta.ResourceDescription,
+								LoadedAt:    time.Unix(msg.CreatedAt, 0).Format(time.RFC3339),
+							})
+						}
+					}
+				}
+			}
+		}
+	}
+
+	sort.Slice(skills, func(i, j int) bool {
+		if skills[i].LoadedAt == skills[j].LoadedAt {
+			return skills[i].Name < skills[j].Name
+		}
+		return skills[i].LoadedAt < skills[j].LoadedAt
+	})
+
+	return skills
+}
+
 func convertParts(parts []message.ContentPart) []sessionShowPart {
 	result := make([]sessionShowPart, 0, len(parts))
 	for _, part := range parts {

internal/commands/commands.go 🔗

@@ -7,6 +7,7 @@ import (
 	"path/filepath"
 	"regexp"
 	"strings"
+	"time"
 
 	"github.com/charmbracelet/crush/internal/agent/tools/mcp"
 	"github.com/charmbracelet/crush/internal/config"
@@ -90,31 +91,20 @@ func LoadMCPPrompts() ([]MCPPrompt, error) {
 }
 
 func buildCommandSources(cfg *config.Config) []commandSource {
-	var sources []commandSource
-
-	// XDG config directory
-	if dir := getXDGCommandsDir(); dir != "" {
-		sources = append(sources, commandSource{
-			path:   dir,
+	return []commandSource{
+		{
+			path:   filepath.Join(home.Config(), "crush", "commands"),
 			prefix: userCommandPrefix,
-		})
-	}
-
-	// Home directory
-	if home := home.Dir(); home != "" {
-		sources = append(sources, commandSource{
-			path:   filepath.Join(home, ".crush", "commands"),
+		},
+		{
+			path:   filepath.Join(home.Dir(), ".crush", "commands"),
 			prefix: userCommandPrefix,
-		})
+		},
+		{
+			path:   filepath.Join(cfg.Options.DataDirectory, "commands"),
+			prefix: projectCommandPrefix,
+		},
 	}
-
-	// Project directory
-	sources = append(sources, commandSource{
-		path:   filepath.Join(cfg.Options.DataDirectory, "commands"),
-		prefix: projectCommandPrefix,
-	})
-
-	return sources
 }
 
 func loadAll(sources []commandSource) ([]CustomCommand, error) {
@@ -130,8 +120,8 @@ func loadAll(sources []commandSource) ([]CustomCommand, error) {
 }
 
 func loadFromSource(source commandSource) ([]CustomCommand, error) {
-	if err := ensureDir(source.path); err != nil {
-		return nil, err
+	if _, err := os.Stat(source.path); os.IsNotExist(err) {
+		return nil, nil
 	}
 
 	var commands []CustomCommand
@@ -203,33 +193,17 @@ func buildCommandID(path, baseDir, prefix string) string {
 	return prefix + strings.Join(parts, ":")
 }
 
-func getXDGCommandsDir() string {
-	xdgHome := os.Getenv("XDG_CONFIG_HOME")
-	if xdgHome == "" {
-		if home := home.Dir(); home != "" {
-			xdgHome = filepath.Join(home, ".config")
-		}
-	}
-	if xdgHome != "" {
-		return filepath.Join(xdgHome, "crush", "commands")
-	}
-	return ""
-}
-
-func ensureDir(path string) error {
-	if _, err := os.Stat(path); os.IsNotExist(err) {
-		return os.MkdirAll(path, 0o755)
-	}
-	return nil
-}
-
 func isMarkdownFile(name string) bool {
 	return strings.HasSuffix(strings.ToLower(name), ".md")
 }
 
 func GetMCPPrompt(cfg *config.ConfigStore, clientID, promptID string, args map[string]string) (string, error) {
-	// TODO: we should pass the context down
-	result, err := mcp.GetPromptMessages(context.Background(), cfg, clientID, promptID, args)
+	// Create a context with timeout since tea.Cmd doesn't support context passing.
+	// The MCP client has its own timeout, but this provides an additional safeguard.
+	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+	defer cancel()
+
+	result, err := mcp.GetPromptMessages(ctx, cfg, clientID, promptID, args)
 	if err != nil {
 		return "", err
 	}

internal/commands/commands_test.go 🔗

@@ -0,0 +1,53 @@
+package commands
+
+import (
+	"os"
+	"path/filepath"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestLoadFromSource_NonExistentDir(t *testing.T) {
+	t.Parallel()
+
+	dir := filepath.Join(t.TempDir(), "does-not-exist")
+
+	cmds, err := loadFromSource(commandSource{path: dir, prefix: userCommandPrefix})
+	require.NoError(t, err)
+	require.Empty(t, cmds)
+
+	// directory must NOT have been created
+	_, statErr := os.Stat(dir)
+	require.True(t, os.IsNotExist(statErr))
+}
+
+func TestLoadFromSource_ExistingDir(t *testing.T) {
+	t.Parallel()
+
+	dir := t.TempDir()
+	require.NoError(t, os.WriteFile(filepath.Join(dir, "hello.md"), []byte("say hello"), 0o644))
+
+	cmds, err := loadFromSource(commandSource{path: dir, prefix: userCommandPrefix})
+	require.NoError(t, err)
+	require.Len(t, cmds, 1)
+	require.Equal(t, "user:hello", cmds[0].ID)
+	require.Equal(t, "say hello", cmds[0].Content)
+}
+
+func TestLoadAll_MixedSources(t *testing.T) {
+	t.Parallel()
+
+	existing := t.TempDir()
+	require.NoError(t, os.WriteFile(filepath.Join(existing, "cmd.md"), []byte("content"), 0o644))
+
+	missing := filepath.Join(t.TempDir(), "nope")
+
+	cmds, err := loadAll([]commandSource{
+		{path: existing, prefix: userCommandPrefix},
+		{path: missing, prefix: projectCommandPrefix},
+	})
+	require.NoError(t, err)
+	require.Len(t, cmds, 1)
+	require.Equal(t, "user:cmd", cmds[0].ID)
+}

internal/config/config.go 🔗

@@ -125,16 +125,16 @@ type ProviderConfig struct {
 }
 
 // ToProvider converts the [ProviderConfig] to a [catwalk.Provider].
-func (pc *ProviderConfig) ToProvider() catwalk.Provider {
+func (c *ProviderConfig) ToProvider() catwalk.Provider {
 	// Convert config provider to provider.Provider format
 	provider := catwalk.Provider{
-		Name:   pc.Name,
-		ID:     catwalk.InferenceProvider(pc.ID),
-		Models: make([]catwalk.Model, len(pc.Models)),
+		Name:   c.Name,
+		ID:     catwalk.InferenceProvider(c.ID),
+		Models: make([]catwalk.Model, len(c.Models)),
 	}
 
 	// Convert models
-	for i, model := range pc.Models {
+	for i, model := range c.Models {
 		provider.Models[i] = catwalk.Model{
 			ID:                     model.ID,
 			Name:                   model.Name,
@@ -154,8 +154,8 @@ func (pc *ProviderConfig) ToProvider() catwalk.Provider {
 	return provider
 }
 
-func (pc *ProviderConfig) SetupGitHubCopilot() {
-	maps.Copy(pc.ExtraHeaders, copilot.Headers())
+func (c *ProviderConfig) SetupGitHubCopilot() {
+	maps.Copy(c.ExtraHeaders, copilot.Headers())
 }
 
 type MCPType string

internal/config/load.go 🔗

@@ -407,6 +407,9 @@ func (c *Config) setDefaults(workingDir, dataDir string) {
 		}
 	}
 
+	// Project specific skills dirs.
+	c.Options.SkillsPaths = append(c.Options.SkillsPaths, ProjectSkillsDir(workingDir)...)
+
 	if str, ok := os.LookupEnv("CRUSH_DISABLE_PROVIDER_AUTO_UPDATE"); ok {
 		c.Options.DisableProviderAutoUpdate, _ = strconv.ParseBool(str)
 	}
@@ -736,10 +739,7 @@ func GlobalConfig() string {
 	if crushGlobal := os.Getenv("CRUSH_GLOBAL_CONFIG"); crushGlobal != "" {
 		return filepath.Join(crushGlobal, fmt.Sprintf("%s.json", appName))
 	}
-	if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" {
-		return filepath.Join(xdgConfigHome, appName, fmt.Sprintf("%s.json", appName))
-	}
-	return filepath.Join(home.Dir(), ".config", appName, fmt.Sprintf("%s.json", appName))
+	return filepath.Join(home.Config(), appName, fmt.Sprintf("%s.json", appName))
 }
 
 // GlobalCacheDir returns the path to the global cache directory for the
@@ -817,22 +817,36 @@ func GlobalSkillsDirs() []string {
 		return []string{crushSkills}
 	}
 
-	// Determine the base config directory.
-	var configBase string
-	if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" {
-		configBase = xdgConfigHome
-	} else if runtime.GOOS == "windows" {
-		configBase = cmp.Or(
+	paths := []string{
+		filepath.Join(home.Config(), appName, "skills"),
+		filepath.Join(home.Config(), "agents", "skills"),
+	}
+
+	// On Windows, also load from app data on top of `$HOME/.config/crush`.
+	// This is here mostly for backwards compatibility.
+	if runtime.GOOS == "windows" {
+		appData := cmp.Or(
 			os.Getenv("LOCALAPPDATA"),
 			filepath.Join(os.Getenv("USERPROFILE"), "AppData", "Local"),
 		)
-	} else {
-		configBase = filepath.Join(home.Dir(), ".config")
+		paths = append(
+			paths,
+			filepath.Join(appData, appName, "skills"),
+			filepath.Join(appData, "agents", "skills"),
+		)
 	}
 
+	return paths
+}
+
+// ProjectSkillsDir returns the default project directories for which Crush
+// will look for skills.
+func ProjectSkillsDir(workingDir string) []string {
 	return []string{
-		filepath.Join(configBase, appName, "skills"),
-		filepath.Join(configBase, "agents", "skills"),
+		filepath.Join(workingDir, ".agents/skills"),
+		filepath.Join(workingDir, ".crush/skills"),
+		filepath.Join(workingDir, ".claude/skills"),
+		filepath.Join(workingDir, ".cursor/skills"),
 	}
 }
 

internal/csync/maps.go 🔗

@@ -131,7 +131,7 @@ var (
 	_ json.Marshaler   = &Map[string, any]{}
 )
 
-func (Map[K, V]) JSONSchemaAlias() any { //nolint
+func (*Map[K, V]) JSONSchemaAlias() any {
 	m := map[K]V{}
 	return m
 }

internal/db/connect_ncruces.go 🔗

@@ -8,7 +8,6 @@ import (
 
 	"github.com/ncruces/go-sqlite3"
 	"github.com/ncruces/go-sqlite3/driver"
-	_ "github.com/ncruces/go-sqlite3/embed"
 )
 
 func openDB(dbPath string) (*sql.DB, error) {

internal/db/db.go 🔗

@@ -11,10 +11,10 @@ import (
 )
 
 type DBTX interface {
-	ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
+	ExecContext(context.Context, string, ...any) (sql.Result, error)
 	PrepareContext(context.Context, string) (*sql.Stmt, error)
-	QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
-	QueryRowContext(context.Context, string, ...interface{}) *sql.Row
+	QueryContext(context.Context, string, ...any) (*sql.Rows, error)
+	QueryRowContext(context.Context, string, ...any) *sql.Row
 }
 
 func New(db DBTX) *Queries {

internal/event/event.go 🔗

@@ -127,7 +127,11 @@ func pairsToProps(props ...any) posthog.Properties {
 	}
 
 	for i := 0; i < len(props); i += 2 {
-		key := props[i].(string)
+		key, ok := props[i].(string)
+		if !ok {
+			slog.Error("Event property key must be a string", "key", props[i], "index", i)
+			continue
+		}
 		value := props[i+1]
 		p = p.Set(key, value)
 	}

internal/event/event_test.go 🔗

@@ -4,7 +4,10 @@ package event
 // scenarios. These tests will not log anything.
 
 import (
+	"reflect"
 	"testing"
+
+	"github.com/posthog/posthog-go"
 )
 
 func TestError(t *testing.T) {
@@ -59,6 +62,33 @@ func TestError(t *testing.T) {
 	})
 }
 
+func TestPairsToProps(t *testing.T) {
+	t.Run("sets valid key value pairs", func(t *testing.T) {
+		got := pairsToProps("foo", "bar", "count", 3)
+		want := posthog.NewProperties().
+			Set("foo", "bar").
+			Set("count", 3)
+		if !reflect.DeepEqual(got, want) {
+			t.Fatalf("pairsToProps() = %#v, want %#v", got, want)
+		}
+	})
+
+	t.Run("returns empty properties for odd pairs", func(t *testing.T) {
+		got := pairsToProps("foo", "bar", "count")
+		if len(got) != 0 {
+			t.Fatalf("pairsToProps() should return empty properties, got %#v", got)
+		}
+	})
+
+	t.Run("ignores non-string key and continues", func(t *testing.T) {
+		got := pairsToProps(123, "bad", "ok", true)
+		want := posthog.NewProperties().Set("ok", true)
+		if !reflect.DeepEqual(got, want) {
+			t.Fatalf("pairsToProps() = %#v, want %#v", got, want)
+		}
+	})
+}
+
 // newDefaultTestError creates a test error that mimics runtime panic
 // errors. This helps us testing that the Error function can handle various
 // error types, including those that might be passed from a panic recovery

internal/fsext/ls.go 🔗

@@ -1,6 +1,7 @@
 package fsext
 
 import (
+	"cmp"
 	"errors"
 	"log/slog"
 	"os"
@@ -12,6 +13,7 @@ import (
 	"github.com/charlievieth/fastwalk"
 	"github.com/charmbracelet/crush/internal/csync"
 	"github.com/charmbracelet/crush/internal/home"
+	gitconfig "github.com/go-git/go-git/v5/config"
 	"github.com/go-git/go-git/v5/plumbing/format/gitignore"
 )
 
@@ -80,18 +82,44 @@ var commonIgnorePatterns = sync.OnceValue(func() []gitignore.Pattern {
 	return parsePatterns(patterns, nil)
 })
 
-var homeIgnorePatterns = sync.OnceValue(func() []gitignore.Pattern {
-	homeDir := home.Dir()
-	var lines []string
-	for _, name := range []string{
-		filepath.Join(homeDir, ".gitignore"),
-		filepath.Join(homeDir, ".config", "git", "ignore"),
-		filepath.Join(homeDir, ".config", "crush", "ignore"),
-	} {
-		if bts, err := os.ReadFile(name); err == nil {
-			lines = append(lines, strings.Split(string(bts), "\n")...)
+// gitGlobalIgnorePatterns returns patterns from git's global excludes file
+// (core.excludesFile), following git's config resolution order.
+var gitGlobalIgnorePatterns = sync.OnceValue(func() []gitignore.Pattern {
+	cfg, err := gitconfig.LoadConfig(gitconfig.GlobalScope)
+	if err != nil {
+		slog.Debug("Failed to load global git config", "error", err)
+		return nil
+	}
+
+	excludesFilePath := cmp.Or(
+		cfg.Raw.Section("core").Options.Get("excludesfile"),
+		filepath.Join(home.Config(), "git", "ignore"),
+	)
+	excludesFilePath = home.Long(excludesFilePath)
+
+	bts, err := os.ReadFile(excludesFilePath)
+	if err != nil {
+		if !os.IsNotExist(err) {
+			slog.Debug("Failed to read git global excludes file", "path", excludesFilePath, "error", err)
+		}
+		return nil
+	}
+
+	return parsePatterns(strings.Split(string(bts), "\n"), nil)
+})
+
+// crushGlobalIgnorePatterns returns patterns from the user's
+// ~/.config/crush/ignore file.
+var crushGlobalIgnorePatterns = sync.OnceValue(func() []gitignore.Pattern {
+	name := filepath.Join(home.Config(), "crush", "ignore")
+	bts, err := os.ReadFile(name)
+	if err != nil {
+		if !os.IsNotExist(err) {
+			slog.Debug("Failed to read crush global ignore file", "path", name, "error", err)
 		}
+		return nil
 	}
+	lines := strings.Split(string(bts), "\n")
 	return parsePatterns(lines, nil)
 })
 
@@ -169,8 +197,9 @@ func (dl *directoryLister) getCombinedMatcher(dir string) gitignore.Matcher {
 		// Add common patterns first (lowest priority).
 		allPatterns = append(allPatterns, commonIgnorePatterns()...)
 
-		// Add home ignore patterns.
-		allPatterns = append(allPatterns, homeIgnorePatterns()...)
+		// Add global ignore patterns (git core.excludesFile + crush global ignore).
+		allPatterns = append(allPatterns, gitGlobalIgnorePatterns()...)
+		allPatterns = append(allPatterns, crushGlobalIgnorePatterns()...)
 
 		// Collect patterns from root to this directory.
 		relDir, _ := filepath.Rel(dl.rootPath, dir)

internal/home/home.go 🔗

@@ -2,6 +2,7 @@
 package home
 
 import (
+	"cmp"
 	"log/slog"
 	"os"
 	"path/filepath"
@@ -21,6 +22,14 @@ func Dir() string {
 	return homedir
 }
 
+// Config returns the user config directory.
+func Config() string {
+	return cmp.Or(
+		os.Getenv("XDG_CONFIG_HOME"),
+		filepath.Join(Dir(), ".config"),
+	)
+}
+
 // Short replaces the actual home path from [Dir] with `~`.
 func Short(p string) string {
 	if homedir == "" || !strings.HasPrefix(p, homedir) {

internal/log/http.go 🔗

@@ -63,6 +63,10 @@ func (h *HTTPRoundTripLogger) RoundTrip(req *http.Request) (*http.Response, erro
 	}
 
 	save, resp.Body, err = drainBody(resp.Body)
+	if err != nil {
+		slog.Error("Failed to drain response body", "error", err)
+		return resp, err
+	}
 	if slog.Default().Enabled(req.Context(), slog.LevelDebug) {
 		slog.Debug(
 			"HTTP Response",
@@ -72,10 +76,9 @@ func (h *HTTPRoundTripLogger) RoundTrip(req *http.Request) (*http.Response, erro
 			"body", bodyToString(save),
 			"content_length", resp.ContentLength,
 			"duration_ms", duration.Milliseconds(),
-			"error", err,
 		)
 	}
-	return resp, err
+	return resp, nil
 }
 
 func bodyToString(body io.ReadCloser) string {

internal/lsp/manager.go 🔗

@@ -141,6 +141,15 @@ var skipAutoStartCommands = map[string]bool{
 }
 
 func (s *Manager) startServer(ctx context.Context, name, filepath string, server *powernapconfig.ServerConfig) {
+	var (
+		isUserConfigured = s.isUserConfigured(name)
+		autoLSP          = s.cfg.Config().Options.AutoLSP
+	)
+	if !isUserConfigured && autoLSP != nil && !*autoLSP {
+		slog.Debug("Auto-start LSP disabled", "name", name)
+		return
+	}
+
 	cfg := s.buildConfig(name, server)
 	if cfg.Disabled {
 		return
@@ -159,9 +168,7 @@ func (s *Manager) startServer(ctx context.Context, name, filepath string, server
 		}
 	}
 
-	userConfigured := s.isUserConfigured(name)
-
-	if !userConfigured {
+	if !isUserConfigured {
 		if _, err := exec.LookPath(server.Command); err != nil {
 			slog.Debug("LSP server not installed, skipping", "name", name, "command", server.Command)
 			unavailable.Set(name, struct{}{})

internal/shell/shell.go 🔗

@@ -82,6 +82,14 @@ func NewShell(opts *Options) *Shell {
 		env = os.Environ()
 	}
 
+	// Allow tools to detect execution by Crush.
+	env = append(
+		env,
+		"CRUSH=1",
+		"AGENT=crush",
+		"AI_AGENT=crush",
+	)
+
 	logger := opts.Logger
 	if logger == nil {
 		logger = noopLogger{}

internal/ui/completions/completions.go 🔗

@@ -2,6 +2,7 @@ package completions
 
 import (
 	"cmp"
+	"path/filepath"
 	"slices"
 	"strings"
 	"sync"
@@ -21,6 +22,11 @@ const (
 	maxHeight = 10
 	minWidth  = 10
 	maxWidth  = 100
+
+	tierExactName = iota
+	tierPrefixName
+	tierPathSegment
+	tierFallback
 )
 
 // SelectionMsg is sent when a completion is selected.
@@ -58,6 +64,35 @@ type Completions struct {
 	normalStyle  lipgloss.Style
 	focusedStyle lipgloss.Style
 	matchStyle   lipgloss.Style
+
+	allItems []list.FilterableItem
+	filtered []list.FilterableItem
+}
+
+type namePriorityRule struct {
+	tier  int
+	match func(pathLower, baseLower, stemLower, queryLower string) bool
+}
+
+var namePriorityRules = []namePriorityRule{
+	{
+		tier: tierExactName,
+		match: func(_ string, baseLower, stemLower, queryLower string) bool {
+			return baseLower == queryLower || stemLower == queryLower
+		},
+	},
+	{
+		tier: tierPrefixName,
+		match: func(_ string, baseLower, _ string, queryLower string) bool {
+			return strings.HasPrefix(baseLower, queryLower)
+		},
+	},
+	{
+		tier: tierPathSegment,
+		match: func(pathLower, _ string, _ string, queryLower string) bool {
+			return hasPathSegment(pathLower, queryLower)
+		},
+	},
 }
 
 // New creates a new completions component.
@@ -87,7 +122,7 @@ func (c *Completions) Query() string {
 
 // Size returns the visible size of the popup.
 func (c *Completions) Size() (width, height int) {
-	visible := len(c.list.FilteredItems())
+	visible := len(c.filtered)
 	return c.width, min(visible, c.height)
 }
 
@@ -142,7 +177,9 @@ func (c *Completions) SetItems(files []FileCompletionValue, resources []Resource
 
 	c.open = true
 	c.query = ""
-	c.list.SetItems(items...)
+	c.allItems = items
+	c.filtered = append([]list.FilterableItem(nil), items...)
+	c.list.SetItems(c.filtered...)
 	c.list.SetFilter("")
 	c.list.Focus()
 
@@ -171,13 +208,67 @@ func (c *Completions) Filter(query string) {
 	}
 
 	c.query = query
-	c.list.SetFilter(query)
+	c.applyNamePriorityFilter(query)
 
 	c.updateSize()
 }
 
+func (c *Completions) applyNamePriorityFilter(query string) {
+	if query == "" {
+		c.filtered = append([]list.FilterableItem(nil), c.allItems...)
+		c.list.SetItems(c.filtered...)
+		return
+	}
+
+	c.list.SetItems(c.allItems...)
+	c.list.SetFilter(query)
+	raw := c.list.FilteredItems()
+	filtered := make([]list.FilterableItem, 0, len(raw))
+	for _, item := range raw {
+		filterable, ok := item.(list.FilterableItem)
+		if !ok {
+			continue
+		}
+		filtered = append(filtered, filterable)
+	}
+
+	queryLower := strings.ToLower(strings.TrimSpace(query))
+	slices.SortStableFunc(filtered, func(a, b list.FilterableItem) int {
+		return namePriorityTier(a.Filter(), queryLower) - namePriorityTier(b.Filter(), queryLower)
+	})
+	c.filtered = filtered
+	c.list.SetItems(c.filtered...)
+}
+
+func namePriorityTier(path, queryLower string) int {
+	if queryLower == "" {
+		return tierFallback
+	}
+
+	pathLower := strings.ToLower(path)
+	baseLower := strings.ToLower(filepath.Base(strings.ReplaceAll(path, `\`, `/`)))
+	stemLower := strings.TrimSuffix(baseLower, filepath.Ext(baseLower))
+	for _, rule := range namePriorityRules {
+		if rule.match(pathLower, baseLower, stemLower, queryLower) {
+			return rule.tier
+		}
+	}
+	return tierFallback
+}
+
+func hasPathSegment(pathLower, queryLower string) bool {
+	for _, part := range strings.FieldsFunc(pathLower, func(r rune) bool {
+		return r == '/' || r == '\\'
+	}) {
+		if part == queryLower {
+			return true
+		}
+	}
+	return false
+}
+
 func (c *Completions) updateSize() {
-	items := c.list.FilteredItems()
+	items := c.filtered
 	start, end := c.list.VisibleItemIndices()
 	width := 0
 	for i := start; i <= end; i++ {
@@ -197,7 +288,7 @@ func (c *Completions) updateSize() {
 
 // HasItems returns whether there are visible items.
 func (c *Completions) HasItems() bool {
-	return len(c.list.FilteredItems()) > 0
+	return len(c.filtered) > 0
 }
 
 // Update handles key events for the completions.
@@ -236,7 +327,7 @@ func (c *Completions) Update(msg tea.KeyPressMsg) (tea.Msg, bool) {
 
 // selectPrev selects the previous item with circular navigation.
 func (c *Completions) selectPrev() {
-	items := c.list.FilteredItems()
+	items := c.filtered
 	if len(items) == 0 {
 		return
 	}
@@ -248,7 +339,7 @@ func (c *Completions) selectPrev() {
 
 // selectNext selects the next item with circular navigation.
 func (c *Completions) selectNext() {
-	items := c.list.FilteredItems()
+	items := c.filtered
 	if len(items) == 0 {
 		return
 	}
@@ -260,7 +351,7 @@ func (c *Completions) selectNext() {
 
 // selectCurrent returns a command with the currently selected item.
 func (c *Completions) selectCurrent(keepOpen bool) tea.Msg {
-	items := c.list.FilteredItems()
+	items := c.filtered
 	if len(items) == 0 {
 		return nil
 	}
@@ -301,12 +392,12 @@ func (c *Completions) Render() string {
 		return ""
 	}
 
-	items := c.list.FilteredItems()
+	items := c.filtered
 	if len(items) == 0 {
 		return ""
 	}
 
-	return c.list.Render()
+	return c.list.List.Render()
 }
 
 func loadFiles(depth, limit int) []FileCompletionValue {

internal/ui/completions/completions_test.go 🔗

@@ -0,0 +1,108 @@
+package completions
+
+import (
+	"testing"
+
+	"charm.land/lipgloss/v2"
+	"github.com/stretchr/testify/require"
+)
+
+func TestFilterPrefersExactBasenameStem(t *testing.T) {
+	t.Parallel()
+
+	c := New(lipgloss.NewStyle(), lipgloss.NewStyle(), lipgloss.NewStyle())
+	c.SetItems([]FileCompletionValue{
+		{Path: "internal/ui/chat/search.go"},
+		{Path: "internal/ui/chat/user.go"},
+	}, nil)
+
+	c.Filter("user")
+
+	filtered := c.filtered
+	require.NotEmpty(t, filtered)
+	first, ok := filtered[0].(*CompletionItem)
+	require.True(t, ok)
+	require.Equal(t, "internal/ui/chat/user.go", first.Text())
+	require.NotEmpty(t, first.match.MatchedIndexes)
+}
+
+func TestFilterPrefersBasenamePrefix(t *testing.T) {
+	t.Parallel()
+
+	c := New(lipgloss.NewStyle(), lipgloss.NewStyle(), lipgloss.NewStyle())
+	c.SetItems([]FileCompletionValue{
+		{Path: "internal/ui/chat/mcp.go"},
+		{Path: "internal/ui/model/chat.go"},
+	}, nil)
+
+	c.Filter("chat.g")
+
+	filtered := c.filtered
+	require.NotEmpty(t, filtered)
+	first, ok := filtered[0].(*CompletionItem)
+	require.True(t, ok)
+	require.Equal(t, "internal/ui/model/chat.go", first.Text())
+	require.NotEmpty(t, first.match.MatchedIndexes)
+}
+
+func TestNamePriorityTier(t *testing.T) {
+	t.Parallel()
+
+	tests := []struct {
+		name     string
+		path     string
+		query    string
+		wantTier int
+	}{
+		{
+			name:     "exact stem",
+			path:     "internal/ui/chat/user.go",
+			query:    "user",
+			wantTier: tierExactName,
+		},
+		{
+			name:     "basename prefix",
+			path:     "internal/ui/model/chat.go",
+			query:    "chat.g",
+			wantTier: tierPrefixName,
+		},
+		{
+			name:     "path segment exact",
+			path:     "internal/ui/chat/mcp.go",
+			query:    "chat",
+			wantTier: tierPathSegment,
+		},
+		{
+			name:     "fallback",
+			path:     "internal/ui/chat/search.go",
+			query:    "user",
+			wantTier: tierFallback,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			t.Parallel()
+			got := namePriorityTier(tt.path, tt.query)
+			require.Equal(t, tt.wantTier, got)
+		})
+	}
+}
+
+func TestFilterPrefersPathSegmentExact(t *testing.T) {
+	t.Parallel()
+
+	c := New(lipgloss.NewStyle(), lipgloss.NewStyle(), lipgloss.NewStyle())
+	c.SetItems([]FileCompletionValue{
+		{Path: "internal/ui/model/xychat.go"},
+		{Path: "internal/ui/chat/mcp.go"},
+	}, nil)
+
+	c.Filter("chat")
+
+	filtered := c.filtered
+	require.NotEmpty(t, filtered)
+	first, ok := filtered[0].(*CompletionItem)
+	require.True(t, ok)
+	require.Equal(t, "internal/ui/chat/mcp.go", first.Text())
+}

internal/ui/dialog/api_key_input.go 🔗

@@ -182,13 +182,8 @@ func (m *APIKeyInput) Draw(scr uv.Screen, area uv.Rectangle) *tea.Cursor {
 
 	if m.isOnboarding {
 		view := content
+		cur = adjustOnboardingInputCursor(t, cur)
 		DrawOnboardingCursor(scr, area, view, cur)
-
-		// FIXME(@andreynering): Figure it out how to properly fix this
-		if cur != nil {
-			cur.Y -= 1
-			cur.X -= 1
-		}
 	} else {
 		view := dialogStyle.Render(content)
 		DrawCenterCursor(scr, area, view, cur)

internal/ui/dialog/commands.go 🔗

@@ -464,7 +464,7 @@ func (c *Commands) defaultCommands() []*CommandItem {
 		model := cfgPrime.GetModelByType(agentCfg.Model)
 		if model != nil && model.SupportsImages {
 			commands = append(commands, NewCommandItem(c.com.Styles, "file_picker", "Open File Picker", "ctrl+f", ActionOpenDialog{
-				// TODO: Pass in the file picker dialog id
+				DialogID: FilePickerID,
 			}))
 		}
 	}

internal/ui/dialog/common.go 🔗

@@ -38,6 +38,24 @@ func InputCursor(t *styles.Styles, cur *tea.Cursor) *tea.Cursor {
 	return cur
 }
 
+// adjustOnboardingInputCursor removes the dialog view frame offset from an
+// input cursor. Onboarding dialogs render without Dialog.View frame, while
+// InputCursor includes that frame offset for regular dialogs.
+func adjustOnboardingInputCursor(t *styles.Styles, cur *tea.Cursor) *tea.Cursor {
+	if cur == nil {
+		return nil
+	}
+
+	dialogStyle := t.Dialog.View
+	cur.X -= dialogStyle.GetBorderLeftSize() +
+		dialogStyle.GetPaddingLeft() +
+		dialogStyle.GetMarginLeft()
+	cur.Y -= dialogStyle.GetBorderTopSize() +
+		dialogStyle.GetPaddingTop() +
+		dialogStyle.GetMarginTop()
+	return cur
+}
+
 // RenderContext is a dialog rendering context that can be used to render
 // common dialog layouts.
 type RenderContext struct {

internal/ui/dialog/models.go 🔗

@@ -292,13 +292,8 @@ func (m *Models) Draw(scr uv.Screen, area uv.Rectangle) *tea.Cursor {
 		rc.TitleInfo = ""
 		rc.IsOnboarding = true
 		view := rc.Render()
+		cur = adjustOnboardingInputCursor(t, cur)
 		DrawOnboardingCursor(scr, area, view, cur)
-
-		// FIXME(@andreynering): Figure it out how to properly fix this
-		if cur != nil {
-			cur.Y -= 1
-			cur.X -= 1
-		}
 	} else {
 		view := rc.Render()
 		DrawCenterCursor(scr, area, view, cur)

internal/ui/dialog/oauth.go 🔗

@@ -332,7 +332,7 @@ func (m *OAuth) ShortHelp() []key.Binding {
 	case OAuthStateSuccess:
 		return []key.Binding{
 			key.NewBinding(
-				key.WithKeys("finish", "ctrl+y", "esc"),
+				key.WithKeys("enter", "ctrl+y", "esc"),
 				key.WithHelp("enter", "finish"),
 			),
 		}

internal/ui/diffview/diffview.go 🔗

@@ -248,7 +248,7 @@ func (dv *DiffView) computeDiff() error {
 		return dv.err
 	}
 	dv.isComputed = true
-	dv.edits = udiff.Strings(
+	dv.edits = udiff.Lines(
 		dv.before.content,
 		dv.after.content,
 	)

internal/ui/diffview/testdata/TestDiffView/Unified/Narrow/DarkMode.golden 🔗

@@ -1,7 +1,7 @@
  …  …   @@ -1,3 +1,3 @@   
  1    - a                 
-    1 + d                 
  2    - b                 
-    2 + e                 
  3    - c                 
+    1 + d                 
+    2 + e                 
     3 + f                 

internal/ui/diffview/testdata/TestDiffView/Unified/Narrow/LightMode.golden 🔗

@@ -1,7 +1,7 @@
  …  …   @@ -1,3 +1,3 @@   
  1    - a                 
-    1 + d                 
  2    - b                 
-    2 + e                 
  3    - c                 
+    1 + d                 
+    2 + e                 
     3 + f                 

internal/ui/diffview/testdata/TestDiffViewLineBreakIssue/Split.golden 🔗

@@ -1,8 +1,8 @@
   …   @@ -1,6 +1,8 @@                     …                                     
   1 - // this is                          1 + /**                               
-                                          2 +  * this is                        
-  2 - // a regular                        3 +  * a block                        
-  3 - // comment                          4 +  * comment                        
+  2 - // a regular                        2 +  * this is                        
+  3 - // comment                          3 +  * a block                        
+                                          4 +  * comment                        
                                           5 +  */                               
   4   $(function() {                      6   $(function() {                    
   5       console.log("Hello, world!");   7       console.log("Hello, world!"); 

internal/ui/diffview/testdata/TestDiffViewLineBreakIssue/Unified.golden 🔗

@@ -1,10 +1,10 @@
   …   …   @@ -1,6 +1,8 @@                   
   1     - // this is                        
+  2     - // a regular                      
+  3     - // comment                        
       1 + /**                               
       2 +  * this is                        
-  2     - // a regular                      
       3 +  * a block                        
-  3     - // comment                        
       4 +  * comment                        
       5 +  */                               
   4   6   $(function() {                    

internal/ui/diffview/udiff_test.go 🔗

@@ -38,7 +38,7 @@ func TestUdiff(t *testing.T) {
 
 	t.Run("ToUnifiedDiff", func(t *testing.T) {
 		toUnifiedDiff := func(t *testing.T, before, after string, contextLines int) udiff.UnifiedDiff {
-			edits := udiff.Strings(before, after)
+			edits := udiff.Lines(before, after)
 			unifiedDiff, err := udiff.ToUnifiedDiff("main.go", "main.go", before, edits, contextLines)
 			if err != nil {
 				t.Fatalf("ToUnifiedDiff failed: %v", err)

internal/ui/model/history.go 🔗

@@ -43,14 +43,13 @@ func (m *UI) loadPromptHistory() tea.Cmd {
 
 // handleHistoryUp handles up arrow for history navigation.
 func (m *UI) handleHistoryUp(msg tea.Msg) tea.Cmd {
+	prevHeight := m.textarea.Height()
 	// Navigate to older history entry from cursor position (0,0).
 	if m.textarea.Length() == 0 || m.isAtEditorStart() {
 		if m.historyPrev() {
 			// we send this so that the textarea moves the view to the correct position
 			// without this the cursor will show up in the wrong place.
-			ta, cmd := m.textarea.Update(nil)
-			m.textarea = ta
-			return cmd
+			return m.updateTextareaWithPrevHeight(nil, prevHeight)
 		}
 	}
 
@@ -61,54 +60,44 @@ func (m *UI) handleHistoryUp(msg tea.Msg) tea.Cmd {
 	}
 
 	// Let textarea handle normal cursor movement.
-	ta, cmd := m.textarea.Update(msg)
-	m.textarea = ta
-	return cmd
+	return m.updateTextarea(msg)
 }
 
 // handleHistoryDown handles down arrow for history navigation.
 func (m *UI) handleHistoryDown(msg tea.Msg) tea.Cmd {
+	prevHeight := m.textarea.Height()
 	// Navigate to newer history entry from end of text.
 	if m.isAtEditorEnd() {
 		if m.historyNext() {
 			// we send this so that the textarea moves the view to the correct position
 			// without this the cursor will show up in the wrong place.
-			ta, cmd := m.textarea.Update(nil)
-			m.textarea = ta
-			return cmd
+			return m.updateTextareaWithPrevHeight(nil, prevHeight)
 		}
 	}
 
 	// First move cursor to end before navigating history.
 	if m.textarea.Line() == max(m.textarea.LineCount()-1, 0) {
 		m.textarea.MoveToEnd()
-		ta, cmd := m.textarea.Update(nil)
-		m.textarea = ta
-		return cmd
+		return m.updateTextarea(nil)
 	}
 
 	// Let textarea handle normal cursor movement.
-	ta, cmd := m.textarea.Update(msg)
-	m.textarea = ta
-	return cmd
+	return m.updateTextarea(msg)
 }
 
 // handleHistoryEscape handles escape for exiting history navigation.
 func (m *UI) handleHistoryEscape(msg tea.Msg) tea.Cmd {
+	prevHeight := m.textarea.Height()
 	// Return to current draft when browsing history.
 	if m.promptHistory.index >= 0 {
 		m.promptHistory.index = -1
 		m.textarea.Reset()
 		m.textarea.InsertString(m.promptHistory.draft)
-		ta, cmd := m.textarea.Update(nil)
-		m.textarea = ta
-		return cmd
+		return m.updateTextareaWithPrevHeight(nil, prevHeight)
 	}
 
 	// Let textarea handle escape normally.
-	ta, cmd := m.textarea.Update(msg)
-	m.textarea = ta
-	return cmd
+	return m.updateTextarea(msg)
 }
 
 // updateHistoryDraft updates history state when text is modified.

internal/ui/model/layout_test.go 🔗

@@ -0,0 +1,118 @@
+package model
+
+import (
+	"strconv"
+	"strings"
+	"testing"
+
+	"charm.land/bubbles/v2/textarea"
+	"github.com/charmbracelet/crush/internal/ui/chat"
+	"github.com/charmbracelet/crush/internal/ui/common"
+)
+
+// testMessageItem is a minimal chat item used to populate the chat list
+// without pulling in full message rendering machinery.
+type testMessageItem struct {
+	id   string
+	text string
+}
+
+func (m testMessageItem) ID() string           { return m.id }
+func (m testMessageItem) Render(int) string    { return m.text }
+func (m testMessageItem) RawRender(int) string { return m.text }
+
+var _ chat.MessageItem = testMessageItem{}
+
+// newTestUI builds a focused uiChat model with dynamic textarea sizing enabled.
+// It intentionally keeps dependencies minimal so layout behavior can be tested
+// in isolation.
+func newTestUI() *UI {
+	com := common.DefaultCommon(nil)
+
+	ta := textarea.New()
+	ta.SetStyles(com.Styles.TextArea)
+	ta.ShowLineNumbers = false
+	ta.CharLimit = -1
+	ta.SetVirtualCursor(false)
+	ta.DynamicHeight = true
+	ta.MinHeight = TextareaMinHeight
+	ta.MaxHeight = TextareaMaxHeight
+	ta.Focus()
+
+	u := &UI{
+		com:      com,
+		status:   NewStatus(com, nil),
+		chat:     NewChat(com),
+		textarea: ta,
+		state:    uiChat,
+		focus:    uiFocusEditor,
+		width:    140,
+		height:   45,
+	}
+
+	return u
+}
+
+func TestUpdateLayoutAndSize_EditorGrowthShrinksChat(t *testing.T) {
+	t.Parallel()
+
+	// Baseline layout at min textarea height.
+	u := newTestUI()
+	u.updateLayoutAndSize()
+
+	initialEditorHeight := u.layout.editor.Dy()
+	initialChatHeight := u.layout.main.Dy()
+
+	// Increase textarea content enough to trigger growth, then run the
+	// same resize hook used in the real update path.
+	prevHeight := u.textarea.Height()
+	u.textarea.SetValue(strings.Repeat("line\n", 8))
+	u.textarea.MoveToEnd()
+	_ = u.handleTextareaHeightChange(prevHeight)
+
+	if got := u.layout.editor.Dy(); got <= initialEditorHeight {
+		t.Fatalf("expected editor to grow: got %d, want > %d", got, initialEditorHeight)
+	}
+
+	if got := u.layout.main.Dy(); got >= initialChatHeight {
+		t.Fatalf("expected chat to shrink: got %d, want < %d", got, initialChatHeight)
+	}
+}
+
+func TestHandleTextareaHeightChange_FollowModeStaysAtBottom(t *testing.T) {
+	t.Parallel()
+
+	// Use enough messages to make the chat scrollable so AtBottom/Follow
+	// assertions are meaningful.
+	u := newTestUI()
+
+	msgs := make([]chat.MessageItem, 0, 60)
+	for i := range 60 {
+		msgs = append(msgs, testMessageItem{
+			id:   "m-" + strconv.Itoa(i),
+			text: "message " + strconv.Itoa(i),
+		})
+	}
+	u.chat.SetMessages(msgs...)
+	u.updateLayoutAndSize()
+
+	// Enter follow mode and verify we're anchored at the bottom first.
+	u.chat.ScrollToBottom()
+	if !u.chat.AtBottom() {
+		t.Fatal("expected chat to start at bottom")
+	}
+
+	// Grow the editor; follow mode should keep the chat pinned to the end
+	// even as the chat viewport shrinks.
+	prevHeight := u.textarea.Height()
+	u.textarea.SetValue(strings.Repeat("line\n", 10))
+	u.textarea.MoveToEnd()
+	_ = u.handleTextareaHeightChange(prevHeight)
+
+	if !u.chat.Follow() {
+		t.Fatal("expected follow mode to remain enabled")
+	}
+	if !u.chat.AtBottom() {
+		t.Fatal("expected chat to remain at bottom after editor resize in follow mode")
+	}
+}

internal/ui/model/ui.go 🔗

@@ -66,12 +66,25 @@ const (
 	compactModeHeightBreakpoint = 30
 )
 
-// If pasted text has more than 2 newlines, treat it as a file attachment.
+// If pasted text has more than 10 newlines, treat it as a file attachment.
 const pasteLinesThreshold = 10
 
+// If pasted text has more than 1000 columns, treat it as a file attachment.
+const pasteColsThreshold = 1000
+
 // Session details panel max height.
 const sessionDetailsMaxHeight = 20
 
+// TextareaMaxHeight is the maximum height of the prompt textarea.
+const TextareaMaxHeight = 15
+
+// editorHeightMargin is the vertical margin added to the textarea height to
+// account for the attachments row (top) and bottom margin.
+const editorHeightMargin = 2
+
+// TextareaMinHeight is the minimum height of the prompt textarea.
+const TextareaMinHeight = 3
+
 // uiFocusState represents the current focus state of the UI.
 type uiFocusState uint8
 
@@ -254,6 +267,9 @@ func New(com *common.Common, initialSessionID string, continueLast bool) *UI {
 	ta.ShowLineNumbers = false
 	ta.CharLimit = -1
 	ta.SetVirtualCursor(false)
+	ta.DynamicHeight = true
+	ta.MinHeight = TextareaMinHeight
+	ta.MaxHeight = TextareaMaxHeight
 	ta.Focus()
 
 	ch := NewChat(com)
@@ -815,13 +831,10 @@ func (m *UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 			cmds = append(cmds, cmd)
 		}
 	case openEditorMsg:
-		var cmd tea.Cmd
+		prevHeight := m.textarea.Height()
 		m.textarea.SetValue(msg.Text)
 		m.textarea.MoveToEnd()
-		m.textarea, cmd = m.textarea.Update(msg)
-		if cmd != nil {
-			cmds = append(cmds, cmd)
-		}
+		cmds = append(cmds, m.updateTextareaWithPrevHeight(msg, prevHeight))
 	case util.InfoMsg:
 		if msg.Type == util.InfoTypeError {
 			slog.Error("Error reported", "error", msg.Msg)
@@ -1712,23 +1725,36 @@ func (m *UI) handleKeyPressMsg(msg tea.KeyPressMsg) tea.Cmd {
 
 			switch {
 			case key.Matches(msg, m.keyMap.Editor.AddImage):
+				if !m.currentModelSupportsImages() {
+					break
+				}
 				if cmd := m.openFilesDialog(); cmd != nil {
 					cmds = append(cmds, cmd)
 				}
 
 			case key.Matches(msg, m.keyMap.Editor.PasteImage):
+				if !m.currentModelSupportsImages() {
+					break
+				}
 				cmds = append(cmds, m.pasteImageFromClipboard)
 
 			case key.Matches(msg, m.keyMap.Editor.SendMessage):
+				prevHeight := m.textarea.Height()
 				value := m.textarea.Value()
 				if before, ok := strings.CutSuffix(value, "\\"); ok {
 					// If the last character is a backslash, remove it and add a newline.
 					m.textarea.SetValue(before)
+					if cmd := m.handleTextareaHeightChange(prevHeight); cmd != nil {
+						cmds = append(cmds, cmd)
+					}
 					break
 				}
 
 				// Otherwise, send the message
 				m.textarea.Reset()
+				if cmd := m.handleTextareaHeightChange(prevHeight); cmd != nil {
+					cmds = append(cmds, cmd)
+				}
 
 				value = strings.TrimSpace(value)
 				if value == "exit" || value == "quit" {
@@ -1770,11 +1796,10 @@ func (m *UI) handleKeyPressMsg(msg tea.KeyPressMsg) tea.Cmd {
 				}
 				cmds = append(cmds, m.openEditor(m.textarea.Value()))
 			case key.Matches(msg, m.keyMap.Editor.Newline):
+				prevHeight := m.textarea.Height()
 				m.textarea.InsertRune('\n')
 				m.closeCompletions()
-				ta, cmd := m.textarea.Update(msg)
-				m.textarea = ta
-				cmds = append(cmds, cmd)
+				cmds = append(cmds, m.updateTextareaWithPrevHeight(msg, prevHeight))
 			case key.Matches(msg, m.keyMap.Editor.HistoryPrev):
 				cmd := m.handleHistoryUp(msg)
 				if cmd != nil {
@@ -1823,9 +1848,8 @@ func (m *UI) handleKeyPressMsg(msg tea.KeyPressMsg) tea.Cmd {
 					m.updateLayoutAndSize()
 				}
 
-				ta, cmd := m.textarea.Update(msg)
-				m.textarea = ta
-				cmds = append(cmds, cmd)
+				prevHeight := m.textarea.Height()
+				cmds = append(cmds, m.updateTextareaWithPrevHeight(msg, prevHeight))
 
 				// Any text modification becomes the current draft.
 				m.updateHistoryDraft(curValue)
@@ -2244,15 +2268,15 @@ func (m *UI) FullHelp() [][]key.Binding {
 
 		switch m.focus {
 		case uiFocusEditor:
-			binds = append(binds,
-				[]key.Binding{
-					k.Editor.Newline,
-					k.Editor.AddImage,
-					k.Editor.PasteImage,
-					k.Editor.MentionFile,
-					k.Editor.OpenEditor,
-				},
-			)
+			editorBinds := []key.Binding{
+				k.Editor.Newline,
+				k.Editor.MentionFile,
+				k.Editor.OpenEditor,
+			}
+			if m.currentModelSupportsImages() {
+				editorBinds = append(editorBinds, k.Editor.AddImage, k.Editor.PasteImage)
+			}
+			binds = append(binds, editorBinds)
 			if hasAttachments {
 				binds = append(binds,
 					[]key.Binding{
@@ -2294,14 +2318,16 @@ func (m *UI) FullHelp() [][]key.Binding {
 					k.Models,
 					k.Sessions,
 				},
-				[]key.Binding{
-					k.Editor.Newline,
-					k.Editor.AddImage,
-					k.Editor.PasteImage,
-					k.Editor.MentionFile,
-					k.Editor.OpenEditor,
-				},
 			)
+			editorBinds := []key.Binding{
+				k.Editor.Newline,
+				k.Editor.MentionFile,
+				k.Editor.OpenEditor,
+			}
+			if m.currentModelSupportsImages() {
+				editorBinds = append(editorBinds, k.Editor.AddImage, k.Editor.PasteImage)
+			}
+			binds = append(binds, editorBinds)
 			if hasAttachments {
 				binds = append(binds,
 					[]key.Binding{
@@ -2311,11 +2337,6 @@ func (m *UI) FullHelp() [][]key.Binding {
 					},
 				)
 			}
-			binds = append(binds,
-				[]key.Binding{
-					help,
-				},
-			)
 		}
 	}
 
@@ -2329,6 +2350,19 @@ func (m *UI) FullHelp() [][]key.Binding {
 	return binds
 }
 
+func (m *UI) currentModelSupportsImages() bool {
+	cfg := m.com.Config()
+	if cfg == nil {
+		return false
+	}
+	agentCfg, ok := cfg.Agents[config.AgentCoder]
+	if !ok {
+		return false
+	}
+	model := cfg.GetModelByType(agentCfg.Model)
+	return model != nil && model.SupportsImages
+}
+
 // toggleCompactMode toggles compact mode between uiChat and uiChatCompact states.
 func (m *UI) toggleCompactMode() tea.Cmd {
 	m.forceCompactMode = !m.forceCompactMode
@@ -2349,17 +2383,59 @@ func (m *UI) updateLayoutAndSize() {
 	if m.state == uiChat {
 		if m.forceCompactMode {
 			m.isCompact = true
-			return
-		}
-		if m.width < compactModeWidthBreakpoint || m.height < compactModeHeightBreakpoint {
+		} else if m.width < compactModeWidthBreakpoint || m.height < compactModeHeightBreakpoint {
 			m.isCompact = true
 		} else {
 			m.isCompact = false
 		}
 	}
 
+	// First pass sizes components from the current textarea height.
 	m.layout = m.generateLayout(m.width, m.height)
+	prevHeight := m.textarea.Height()
 	m.updateSize()
+
+	// SetWidth can change textarea height due to soft-wrap recalculation.
+	// If that happens, run one reconciliation pass with the new height.
+	if m.textarea.Height() != prevHeight {
+		m.layout = m.generateLayout(m.width, m.height)
+		m.updateSize()
+	}
+}
+
+// handleTextareaHeightChange checks whether the textarea height changed and,
+// if so, recalculates the layout. When the chat is in follow mode it keeps
+// the view scrolled to the bottom. The returned command, if non-nil, must be
+// batched by the caller.
+func (m *UI) handleTextareaHeightChange(prevHeight int) tea.Cmd {
+	if m.textarea.Height() == prevHeight {
+		return nil
+	}
+	m.updateLayoutAndSize()
+	if m.state == uiChat && m.chat.Follow() {
+		return m.chat.ScrollToBottomAndAnimate()
+	}
+	return nil
+}
+
+// updateTextarea updates the textarea for msg and then reconciles layout if
+// the textarea height changed as a result.
+func (m *UI) updateTextarea(msg tea.Msg) tea.Cmd {
+	return m.updateTextareaWithPrevHeight(msg, m.textarea.Height())
+}
+
+// updateTextareaWithPrevHeight is for cases when the height of the layout may
+// have changed.
+//
+// Particularly, it's for cases where the textarea changes before
+// textarea.Update is called (for example, SetValue, Reset, and InsertRune). We
+// pass the height from before those changes took place so we can compare
+// "before" vs "after" sizing and recalculate the layout if the textarea grew
+// or shrank.
+func (m *UI) updateTextareaWithPrevHeight(msg tea.Msg, prevHeight int) tea.Cmd {
+	ta, cmd := m.textarea.Update(msg)
+	m.textarea = ta
+	return tea.Batch(cmd, m.handleTextareaHeightChange(prevHeight))
 }
 
 // updateSize updates the sizes of UI components based on the current layout.
@@ -2368,11 +2444,8 @@ func (m *UI) updateSize() {
 	m.status.SetWidth(m.layout.status.Dx())
 
 	m.chat.SetSize(m.layout.main.Dx(), m.layout.main.Dy())
+	m.textarea.MaxHeight = TextareaMaxHeight
 	m.textarea.SetWidth(m.layout.editor.Dx())
-	// TODO: Abstract the textarea and attachments into a single editor
-	// component so we don't have to manually account for the attachments
-	// height here.
-	m.textarea.SetHeight(m.layout.editor.Dy() - 2) // Account for top margin/attachments and bottom margin
 	m.renderPills()
 
 	// Handle different app states
@@ -2392,8 +2465,8 @@ func (m *UI) generateLayout(w, h int) uiLayout {
 
 	// The help height
 	helpHeight := 1
-	// The editor height
-	editorHeight := 5
+	// The editor height: textarea height + margin for attachments and bottom spacing.
+	editorHeight := m.textarea.Height() + editorHeightMargin
 	// The sidebar width
 	sidebarWidth := 30
 	// The header height
@@ -2562,13 +2635,14 @@ func (m *UI) openEditor(value string) tea.Cmd {
 	if err != nil {
 		return util.ReportError(err)
 	}
+	tmpPath := tmpfile.Name()
 	defer tmpfile.Close() //nolint:errcheck
 	if _, err := tmpfile.WriteString(value); err != nil {
 		return util.ReportError(err)
 	}
 	cmd, err := editor.Command(
 		"crush",
-		tmpfile.Name(),
+		tmpPath,
 		editor.AtPosition(
 			m.textarea.Line()+1,
 			m.textarea.Column()+1,
@@ -2578,17 +2652,20 @@ func (m *UI) openEditor(value string) tea.Cmd {
 		return util.ReportError(err)
 	}
 	return tea.ExecProcess(cmd, func(err error) tea.Msg {
+		defer func() {
+			_ = os.Remove(tmpPath)
+		}()
+
 		if err != nil {
 			return util.ReportError(err)
 		}
-		content, err := os.ReadFile(tmpfile.Name())
+		content, err := os.ReadFile(tmpPath)
 		if err != nil {
 			return util.ReportError(err)
 		}
 		if len(content) == 0 {
 			return util.ReportWarn("Message is empty")
 		}
-		os.Remove(tmpfile.Name())
 		return openEditorMsg{
 			Text: strings.TrimSpace(string(content)),
 		}
@@ -2666,11 +2743,13 @@ func (m *UI) insertCompletionText(text string) bool {
 // insertFileCompletion inserts the selected file path into the textarea,
 // replacing the @query, and adds the file as an attachment.
 func (m *UI) insertFileCompletion(path string) tea.Cmd {
+	prevHeight := m.textarea.Height()
 	if !m.insertCompletionText(path) {
 		return nil
 	}
+	heightCmd := m.handleTextareaHeightChange(prevHeight)
 
-	return func() tea.Msg {
+	fileCmd := func() tea.Msg {
 		absPath, _ := filepath.Abs(path)
 
 		if m.hasSession() {
@@ -2701,6 +2780,7 @@ func (m *UI) insertFileCompletion(path string) tea.Cmd {
 			Content:  content,
 		}
 	}
+	return tea.Batch(heightCmd, fileCmd)
 }
 
 // insertMCPResourceCompletion inserts the selected resource into the textarea,
@@ -2708,11 +2788,13 @@ func (m *UI) insertFileCompletion(path string) tea.Cmd {
 func (m *UI) insertMCPResourceCompletion(item completions.ResourceCompletionValue) tea.Cmd {
 	displayText := cmp.Or(item.Title, item.URI)
 
+	prevHeight := m.textarea.Height()
 	if !m.insertCompletionText(displayText) {
 		return nil
 	}
+	heightCmd := m.handleTextareaHeightChange(prevHeight)
 
-	return func() tea.Msg {
+	resourceCmd := func() tea.Msg {
 		contents, err := m.com.Workspace.ReadMCPResource(
 			context.Background(),
 			item.MCPName,
@@ -2752,6 +2834,7 @@ func (m *UI) insertMCPResourceCompletion(item completions.ResourceCompletionValu
 			Content:  data,
 		}
 	}
+	return tea.Batch(heightCmd, resourceCmd)
 }
 
 // completionsPosition returns the X and Y position for the completions popup.
@@ -2951,6 +3034,10 @@ func (m *UI) openDialog(id string) tea.Cmd {
 		if cmd := m.openReasoningDialog(); cmd != nil {
 			cmds = append(cmds, cmd)
 		}
+	case dialog.FilePickerID:
+		if cmd := m.openFilesDialog(); cmd != nil {
+			cmds = append(cmds, cmd)
+		}
 	case dialog.QuitID:
 		if cmd := m.openQuitDialog(); cmd != nil {
 			cmds = append(cmds, cmd)
@@ -3160,7 +3247,7 @@ func (m *UI) handlePasteMsg(msg tea.PasteMsg) tea.Cmd {
 		return nil
 	}
 
-	if strings.Count(msg.Content, "\n") > pasteLinesThreshold {
+	if hasPasteExceededThreshold(msg) {
 		return func() tea.Msg {
 			content := []byte(msg.Content)
 			if int64(len(content)) > common.MaxAttachmentSize {
@@ -3206,9 +3293,8 @@ func (m *UI) handlePasteMsg(msg tea.PasteMsg) tea.Cmd {
 		return true
 	}
 	if !allExistsAndValid() {
-		var cmd tea.Cmd
-		m.textarea, cmd = m.textarea.Update(msg)
-		return cmd
+		prevHeight := m.textarea.Height()
+		return m.updateTextareaWithPrevHeight(msg, prevHeight)
 	}
 
 	var cmds []tea.Cmd
@@ -3218,6 +3304,22 @@ func (m *UI) handlePasteMsg(msg tea.PasteMsg) tea.Cmd {
 	return tea.Batch(cmds...)
 }
 
+func hasPasteExceededThreshold(msg tea.PasteMsg) bool {
+	var (
+		lineCount = 0
+		colCount  = 0
+	)
+	for line := range strings.SplitSeq(msg.Content, "\n") {
+		lineCount++
+		colCount = max(colCount, len(line))
+
+		if lineCount > pasteLinesThreshold || colCount > pasteColsThreshold {
+			return true
+		}
+	}
+	return false
+}
+
 // handleFilePathPaste handles a pasted file path.
 func (m *UI) handleFilePathPaste(path string) tea.Cmd {
 	return func() tea.Msg {

internal/ui/model/ui_test.go 🔗

@@ -0,0 +1,107 @@
+package model
+
+import (
+	"reflect"
+	"testing"
+	"unsafe"
+
+	"charm.land/catwalk/pkg/catwalk"
+	"github.com/charmbracelet/crush/internal/app"
+	"github.com/charmbracelet/crush/internal/config"
+	"github.com/charmbracelet/crush/internal/csync"
+	"github.com/charmbracelet/crush/internal/ui/common"
+	"github.com/stretchr/testify/require"
+)
+
+func TestCurrentModelSupportsImages(t *testing.T) {
+	t.Parallel()
+
+	t.Run("returns false when config is nil", func(t *testing.T) {
+		t.Parallel()
+
+		ui := newTestUIWithConfig(t, nil)
+		require.False(t, ui.currentModelSupportsImages())
+	})
+
+	t.Run("returns false when coder agent is missing", func(t *testing.T) {
+		t.Parallel()
+
+		cfg := &config.Config{
+			Providers: csync.NewMap[string, config.ProviderConfig](),
+			Agents:    map[string]config.Agent{},
+		}
+		ui := newTestUIWithConfig(t, cfg)
+		require.False(t, ui.currentModelSupportsImages())
+	})
+
+	t.Run("returns false when model is not found", func(t *testing.T) {
+		t.Parallel()
+
+		cfg := &config.Config{
+			Providers: csync.NewMap[string, config.ProviderConfig](),
+			Agents: map[string]config.Agent{
+				config.AgentCoder: {Model: config.SelectedModelTypeLarge},
+			},
+		}
+		ui := newTestUIWithConfig(t, cfg)
+		require.False(t, ui.currentModelSupportsImages())
+	})
+
+	t.Run("returns true when current model supports images", func(t *testing.T) {
+		t.Parallel()
+
+		providers := csync.NewMap[string, config.ProviderConfig]()
+		providers.Set("test-provider", config.ProviderConfig{
+			ID: "test-provider",
+			Models: []catwalk.Model{
+				{ID: "test-model", SupportsImages: true},
+			},
+		})
+
+		cfg := &config.Config{
+			Models: map[config.SelectedModelType]config.SelectedModel{
+				config.SelectedModelTypeLarge: {
+					Provider: "test-provider",
+					Model:    "test-model",
+				},
+			},
+			Providers: providers,
+			Agents: map[string]config.Agent{
+				config.AgentCoder: {Model: config.SelectedModelTypeLarge},
+			},
+		}
+
+		ui := newTestUIWithConfig(t, cfg)
+		require.True(t, ui.currentModelSupportsImages())
+	})
+}
+
+func newTestUIWithConfig(t *testing.T, cfg *config.Config) *UI {
+	t.Helper()
+
+	store := &config.ConfigStore{}
+	setUnexportedField(t, store, "config", cfg)
+
+	appInstance := &app.App{}
+	setUnexportedField(t, appInstance, "config", store)
+
+	return &UI{
+		com: &common.Common{
+			App: appInstance,
+		},
+	}
+}
+
+func setUnexportedField(t *testing.T, target any, name string, value any) {
+	t.Helper()
+
+	v := reflect.ValueOf(target)
+	require.Equal(t, reflect.Pointer, v.Kind())
+	require.False(t, v.IsNil())
+
+	field := v.Elem().FieldByName(name)
+	require.Truef(t, field.IsValid(), "field %q not found", name)
+
+	fieldValue := reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem()
+	fieldValue.Set(reflect.ValueOf(value))
+}

schema.json 🔗

@@ -64,10 +64,7 @@
           "description": "Model configurations for different model types"
         },
         "providers": {
-          "additionalProperties": {
-            "$ref": "#/$defs/ProviderConfig"
-          },
-          "type": "object",
+          "$ref": "#/$defs/Map[string,github.com/charmbracelet/crush/internal/config.ProviderConfig]",
           "description": "AI provider configurations"
         },
         "mcp": {
@@ -265,88 +262,8 @@
       },
       "type": "object"
     },
-    "Model": {
-      "properties": {
-        "id": {
-          "type": "string"
-        },
-        "name": {
-          "type": "string"
-        },
-        "cost_per_1m_in": {
-          "type": "number"
-        },
-        "cost_per_1m_out": {
-          "type": "number"
-        },
-        "cost_per_1m_in_cached": {
-          "type": "number"
-        },
-        "cost_per_1m_out_cached": {
-          "type": "number"
-        },
-        "context_window": {
-          "type": "integer"
-        },
-        "default_max_tokens": {
-          "type": "integer"
-        },
-        "can_reason": {
-          "type": "boolean"
-        },
-        "reasoning_levels": {
-          "items": {
-            "type": "string"
-          },
-          "type": "array"
-        },
-        "default_reasoning_effort": {
-          "type": "string"
-        },
-        "supports_attachments": {
-          "type": "boolean"
-        },
-        "options": {
-          "$ref": "#/$defs/ModelOptions"
-        }
-      },
-      "additionalProperties": false,
-      "type": "object",
-      "required": [
-        "id",
-        "name",
-        "cost_per_1m_in",
-        "cost_per_1m_out",
-        "cost_per_1m_in_cached",
-        "cost_per_1m_out_cached",
-        "context_window",
-        "default_max_tokens",
-        "can_reason",
-        "supports_attachments",
-        "options"
-      ]
-    },
-    "ModelOptions": {
-      "properties": {
-        "temperature": {
-          "type": "number"
-        },
-        "top_p": {
-          "type": "number"
-        },
-        "top_k": {
-          "type": "integer"
-        },
-        "frequency_penalty": {
-          "type": "number"
-        },
-        "presence_penalty": {
-          "type": "number"
-        },
-        "provider_options": {
-          "type": "object"
-        }
-      },
+    "Map[string,github.com/charmbracelet/crush/internal/config.ProviderConfig]": {
+      "properties": {},
       "additionalProperties": false,
       "type": "object"
     },
@@ -478,89 +395,6 @@
       "additionalProperties": false,
       "type": "object"
     },
-    "ProviderConfig": {
-      "properties": {
-        "id": {
-          "type": "string",
-          "description": "Unique identifier for the provider",
-          "examples": [
-            "openai"
-          ]
-        },
-        "name": {
-          "type": "string",
-          "description": "Human-readable name for the provider",
-          "examples": [
-            "OpenAI"
-          ]
-        },
-        "base_url": {
-          "type": "string",
-          "format": "uri",
-          "description": "Base URL for the provider's API",
-          "examples": [
-            "https://api.openai.com/v1"
-          ]
-        },
-        "type": {
-          "type": "string",
-          "enum": [
-            "openai",
-            "openai-compat",
-            "anthropic",
-            "gemini",
-            "azure",
-            "vertexai"
-          ],
-          "description": "Provider type that determines the API format",
-          "default": "openai"
-        },
-        "api_key": {
-          "type": "string",
-          "description": "API key for authentication with the provider",
-          "examples": [
-            "$OPENAI_API_KEY"
-          ]
-        },
-        "oauth": {
-          "$ref": "#/$defs/Token",
-          "description": "OAuth2 token for authentication with the provider"
-        },
-        "disable": {
-          "type": "boolean",
-          "description": "Whether this provider is disabled",
-          "default": false
-        },
-        "system_prompt_prefix": {
-          "type": "string",
-          "description": "Custom prefix to add to system prompts for this provider"
-        },
-        "extra_headers": {
-          "additionalProperties": {
-            "type": "string"
-          },
-          "type": "object",
-          "description": "Additional HTTP headers to send with requests"
-        },
-        "extra_body": {
-          "type": "object",
-          "description": "Additional fields to include in request bodies"
-        },
-        "provider_options": {
-          "type": "object",
-          "description": "Additional provider-specific options for this provider"
-        },
-        "models": {
-          "items": {
-            "$ref": "#/$defs/Model"
-          },
-          "type": "array",
-          "description": "List of models available from this provider"
-        }
-      },
-      "additionalProperties": false,
-      "type": "object"
-    },
     "SelectedModel": {
       "properties": {
         "model": {
@@ -671,30 +505,6 @@
         "completions"
       ]
     },
-    "Token": {
-      "properties": {
-        "access_token": {
-          "type": "string"
-        },
-        "refresh_token": {
-          "type": "string"
-        },
-        "expires_in": {
-          "type": "integer"
-        },
-        "expires_at": {
-          "type": "integer"
-        }
-      },
-      "additionalProperties": false,
-      "type": "object",
-      "required": [
-        "access_token",
-        "refresh_token",
-        "expires_in",
-        "expires_at"
-      ]
-    },
     "ToolGrep": {
       "properties": {
         "timeout": {