Merge branch 'main' into server-client-2

Ayman Bagabas created

Change summary

.github/cla-signatures.json                                                        |  16 
.github/labeler.yml                                                                |   2 
go.mod                                                                             |  28 
go.sum                                                                             |  56 
internal/agent/agent.go                                                            |  16 
internal/agent/agent_test.go                                                       |   2 
internal/agent/coordinator.go                                                      |  16 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/bash_tool.yaml             |  29 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/download_tool.yaml         |  27 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/fetch_tool.yaml            |  33 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/glob_tool.yaml             |  30 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/grep_tool.yaml             |  31 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/ls_tool.yaml               |  28 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/multiedit_tool.yaml        |  29 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/parallel_tool_calls.yaml   |  34 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/read_a_file.yaml           |  27 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/simple_test.yaml           |  27 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/sourcegraph_tool.yaml      |  27 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/update_a_file.yaml         |  27 
internal/agent/testdata/TestCoderAgent/anthropic-sonnet/write_tool.yaml            |  30 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/bash_tool.yaml                 |  26 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/download_tool.yaml             |  24 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/fetch_tool.yaml                |  32 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/glob_tool.yaml                 |  30 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/grep_tool.yaml                 |  34 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/ls_tool.yaml                   |  30 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/multiedit_tool.yaml            |  42 
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               |  16 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/sourcegraph_tool.yaml          |  36 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/update_a_file.yaml             |  32 
internal/agent/testdata/TestCoderAgent/openai-gpt-5/write_tool.yaml                |  24 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/bash_tool.yaml           |  20 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/download_tool.yaml       |  22 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/fetch_tool.yaml          |  18 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/glob_tool.yaml           |  28 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/grep_tool.yaml           |   2 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/ls_tool.yaml             |   2 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/multiedit_tool.yaml      |  22 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/parallel_tool_calls.yaml |  26 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/read_a_file.yaml         |  18 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/simple_test.yaml         |  12 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/sourcegraph_tool.yaml    |   2 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/update_a_file.yaml       |  20 
internal/agent/testdata/TestCoderAgent/openrouter-kimi-k2/write_tool.yaml          |  16 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/bash_tool.yaml                   |  22 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/download_tool.yaml               |  20 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/fetch_tool.yaml                  |  24 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/glob_tool.yaml                   |  22 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/grep_tool.yaml                   |   2 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/ls_tool.yaml                     |  20 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/multiedit_tool.yaml              |  26 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/parallel_tool_calls.yaml         |  26 
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            |  20 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/update_a_file.yaml               |  22 
internal/agent/testdata/TestCoderAgent/zai-glm4.6/write_tool.yaml                  |  24 
internal/agent/tools/bash.go                                                       |  29 
internal/agent/tools/bash.tpl                                                      |   2 
internal/agent/tools/bash_test.go                                                  | 103 
internal/cmd/root.go                                                               |   3 
internal/cmd/session.go                                                            | 641 
internal/config/config.go                                                          |   9 
internal/config/store.go                                                           |   9 
internal/db/db.go                                                                  |  10 
internal/db/models.go                                                              |   2 
internal/db/querier.go                                                             |   1 
internal/db/read_files.sql.go                                                      |  53 
internal/db/sessions.sql.go                                                        |  20 
internal/db/sql/sessions.sql                                                       |   9 
internal/session/session.go                                                        |  18 
internal/ui/AGENTS.md                                                              | 202 
internal/ui/dialog/actions.go                                                      |  24 
internal/ui/dialog/commands.go                                                     |  32 
internal/ui/model/ui.go                                                            |  43 
77 files changed, 1,798 insertions(+), 767 deletions(-)

Detailed changes

.github/cla-signatures.json 🔗

@@ -1335,6 +1335,22 @@
       "created_at": "2026-03-09T17:00:06Z",
       "repoId": 987670088,
       "pullRequestNo": 2390
+    },
+    {
+      "name": "seroperson",
+      "id": 3791221,
+      "comment_id": 4047392328,
+      "created_at": "2026-03-12T14:53:20Z",
+      "repoId": 987670088,
+      "pullRequestNo": 2401
+    },
+    {
+      "name": "xulongwu4",
+      "id": 16892446,
+      "comment_id": 4062024320,
+      "created_at": "2026-03-15T02:30:55Z",
+      "repoId": 987670088,
+      "pullRequestNo": 2410
     }
   ]
 }

.github/labeler.yml 🔗

@@ -69,6 +69,8 @@
   - "/openrouter/i"
 "provider: qwen":
   - "/qwen/i"
+"provider: vercel":
+  - "/vercel/i"
 "provider: xai grok":
   - "/(xai|x\\.ai|grok)/i"
 "security":

go.mod 🔗

@@ -5,15 +5,16 @@ go 1.26.1
 require (
 	charm.land/bubbles/v2 v2.0.0
 	charm.land/bubbletea/v2 v2.0.2
-	charm.land/catwalk v0.28.4
-	charm.land/fantasy v0.12.1
+	charm.land/catwalk v0.30.0
+	charm.land/fang/v2 v2.0.1
+	charm.land/fantasy v0.12.3
 	charm.land/glamour/v2 v2.0.0
-	charm.land/lipgloss/v2 v2.0.1
+	charm.land/lipgloss/v2 v2.0.2
 	charm.land/log/v2 v2.0.0
 	charm.land/x/vcr v0.1.1
 	github.com/JohannesKaufmann/html-to-markdown v1.6.0
 	github.com/MakeNowJust/heredoc v1.0.0
-	github.com/PuerkitoBio/goquery v1.11.0
+	github.com/PuerkitoBio/goquery v1.12.0
 	github.com/alecthomas/chroma/v2 v2.23.1
 	github.com/atotto/clipboard v0.1.4
 	github.com/aymanbagabas/go-nativeclipboard v0.1.3
@@ -21,7 +22,6 @@ require (
 	github.com/bmatcuk/doublestar/v4 v4.10.0
 	github.com/charlievieth/fastwalk v1.0.14
 	github.com/charmbracelet/colorprofile v0.4.3
-	github.com/charmbracelet/fang v1.0.0
 	github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8
 	github.com/charmbracelet/x/ansi v0.11.6
 	github.com/charmbracelet/x/editor v0.2.0
@@ -46,12 +46,12 @@ require (
 	github.com/jordanella/go-ansi-paintbrush v0.0.0-20240728195301-b7ad996ecf3d
 	github.com/lucasb-eyer/go-colorful v1.3.0
 	github.com/mattn/go-isatty v0.0.20
-	github.com/modelcontextprotocol/go-sdk v1.4.0
-	github.com/ncruces/go-sqlite3 v0.31.1
+	github.com/modelcontextprotocol/go-sdk v1.4.1
+	github.com/ncruces/go-sqlite3 v0.32.0
 	github.com/nxadm/tail v1.4.11
-	github.com/openai/openai-go/v2 v2.7.1
+	github.com/openai/openai-go/v3 v3.28.0
 	github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
-	github.com/posthog/posthog-go v1.10.0
+	github.com/posthog/posthog-go v1.11.1
 	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
@@ -63,9 +63,9 @@ require (
 	github.com/tidwall/sjson v1.2.5
 	github.com/zeebo/xxh3 v1.1.0
 	go.uber.org/goleak v1.3.0
-	golang.org/x/net v0.51.0
+	golang.org/x/net v0.52.0
 	golang.org/x/sync v0.20.0
-	golang.org/x/text v0.34.0
+	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.46.1
@@ -159,7 +159,7 @@ require (
 	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
-	github.com/segmentio/encoding v0.5.3 // indirect
+	github.com/segmentio/encoding v0.5.4 // indirect
 	github.com/sergeymakinen/go-bmp v1.0.0 // indirect
 	github.com/sergeymakinen/go-ico v1.0.0-beta.0 // indirect
 	github.com/sethvargo/go-retry v0.3.0 // indirect
@@ -183,12 +183,12 @@ require (
 	go.opentelemetry.io/otel/trace v1.40.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.yaml.in/yaml/v4 v4.0.0-rc.3 // indirect
-	golang.org/x/crypto v0.48.0 // 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/oauth2 v0.36.0 // indirect
 	golang.org/x/sys v0.42.0 // indirect
-	golang.org/x/term v0.40.0 // indirect
+	golang.org/x/term v0.41.0 // indirect
 	golang.org/x/time v0.14.0 // indirect
 	google.golang.org/api v0.269.0 // indirect
 	google.golang.org/genai v1.49.0 // indirect

go.sum 🔗

@@ -2,14 +2,16 @@ 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/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.28.4 h1:YaaXA1k0v7CKvvT+Gh1pDD7XrlUR93kROdaWqkkglRw=
-charm.land/catwalk v0.28.4/go.mod h1:+fqw/6YGNtvapvPy9vhwA/fAMxVjD2K8hVIKYov8Vhg=
-charm.land/fantasy v0.12.1 h1:awszoi5O9FIjMEkfyCMiLJfVRNLckp/zQkFrA6IxQqc=
-charm.land/fantasy v0.12.1/go.mod h1:QeRVUeG1XNTWBszRAbhUtPyX1VWs6zjkCxwfcwnICdc=
+charm.land/catwalk v0.30.0 h1:CgWN3hM0HYYXlxMFsd1mfpBliqvx9gH3LolVi1VfMSU=
+charm.land/catwalk v0.30.0/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.12.3 h1:gvqRWD7vWmpNN0VcQ+rSku5QdTlLegqrlJDVCDdAh58=
+charm.land/fantasy v0.12.3/go.mod h1:noWyUtEgUrfsRXqmGbz7NQlZpf6KFwNwjA+jzdS3No8=
 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.1 h1:6Xzrn49+Py1Um5q/wZG1gWgER2+7dUyZ9XMEufqPSys=
-charm.land/lipgloss/v2 v2.0.1/go.mod h1:KjPle2Qd3YmvP1KL5OMHiHysGcNwq6u83MUjYkFvEkM=
+charm.land/lipgloss/v2 v2.0.2 h1:xFolbF8JdpNkM2cEPTfXEcW1p6NRzOWTSamRfYEw8cs=
+charm.land/lipgloss/v2 v2.0.2/go.mod h1:KjPle2Qd3YmvP1KL5OMHiHysGcNwq6u83MUjYkFvEkM=
 charm.land/log/v2 v2.0.0 h1:SY3Cey7ipx86/MBXQHwsguOT6X1exT94mmJRdzTNs+s=
 charm.land/log/v2 v2.0.0/go.mod h1:c3cZSRqm20qUVVAR1WmS/7ab8bgha3C6G7DjPcaVZz0=
 charm.land/x/vcr v0.1.1 h1:PXCFMUG0rPtyk35rhfzYCJEduOzWXCIbrXTFq4OF/9Q=
@@ -39,8 +41,8 @@ github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6
 github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
 github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
 github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk=
-github.com/PuerkitoBio/goquery v1.11.0 h1:jZ7pwMQXIITcUXNH83LLk+txlaEy6NVOfTuP43xxfqw=
-github.com/PuerkitoBio/goquery v1.11.0/go.mod h1:wQHgxUOU3JGuj3oD/QFfxUdlzW6xPHfqyHre6VMY4DQ=
+github.com/PuerkitoBio/goquery v1.12.0 h1:pAcL4g3WRXekcB9AU/y1mbKez2dbY2AajVhtkO8RIBo=
+github.com/PuerkitoBio/goquery v1.12.0/go.mod h1:802ej+gV2y7bbIhOIoPY5sT183ZW0YFofScC4q/hIpQ=
 github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
 github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
 github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY=
@@ -102,8 +104,6 @@ github.com/charmbracelet/anthropic-sdk-go v0.0.0-20260223140439-63879b0b8dab h1:
 github.com/charmbracelet/anthropic-sdk-go v0.0.0-20260223140439-63879b0b8dab/go.mod h1:hqlYqR7uPKOKfnNeicUbZp0Ps0GeYFlKYtwh5HGDCx8=
 github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q=
 github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q=
-github.com/charmbracelet/fang v1.0.0 h1:jESBY40agJOlLYnnv9jE0mLqDGTxEk0hkOnx7YGyRlQ=
-github.com/charmbracelet/fang v1.0.0/go.mod h1:P5/DNb9DddQ0Z0dbc0P3ol4/ix5Po7Ofr2KMBfAqoCo=
 github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 h1:eyFRbAmexyt43hVfeyBofiGSEmJ7krjLOYt/9CF5NKA=
 github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8/go.mod h1:SQpCTRNBtzJkwku5ye4S3HEuthAlGy2n9VXZnWkEW98=
 github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8=
@@ -279,8 +279,8 @@ github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwX
 github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/modelcontextprotocol/go-sdk v1.4.0 h1:u0kr8lbJc1oBcawK7Df+/ajNMpIDFE41OEPxdeTLOn8=
-github.com/modelcontextprotocol/go-sdk v1.4.0/go.mod h1:Nxc2n+n/GdCebUaqCOhTetptS17SXXNu9IfNTaLDi1E=
+github.com/modelcontextprotocol/go-sdk v1.4.1 h1:M4x9GyIPj+HoIlHNGpK2hq5o3BFhC+78PkEaldQRphc=
+github.com/modelcontextprotocol/go-sdk v1.4.1/go.mod h1:Bo/mS87hPQqHSRkMv4dQq1XCu6zv4INdXnFZabkNU6s=
 github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
 github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
 github.com/muesli/mango v0.1.0 h1:DZQK45d2gGbql1arsYA4vfg4d7I9Hfx5rX/GCmzsAvI=
@@ -291,8 +291,8 @@ 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.31.1 h1:F76NF4NTLNOabLUKuEb2xqjBW+/Ub+MR59/Q7dACRo8=
-github.com/ncruces/go-sqlite3 v0.31.1/go.mod h1:L9OWFjYG/+4dq9O6bFCYoWLG0a7LmtgR6v26TvABmwg=
+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-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=
@@ -301,8 +301,8 @@ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6
 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
 github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
 github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
-github.com/openai/openai-go/v2 v2.7.1 h1:/tfvTJhfv7hTSL8mWwc5VL4WLLSDL5yn9VqVykdu9r8=
-github.com/openai/openai-go/v2 v2.7.1/go.mod h1:jrJs23apqJKKbT+pqtFgNKpRju/KP9zpUTZhz3GElQE=
+github.com/openai/openai-go/v3 v3.28.0 h1:2+FfrCVMdGXSQrBv1tLWtokm+BU7+3hJ/8rAHPQ63KM=
+github.com/openai/openai-go/v3 v3.28.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo=
 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=
@@ -317,8 +317,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.10.0 h1:wfoy7Jfb4LigCoHYyMZoiJmmEoCLOkSaYfDxM/NtCqY=
-github.com/posthog/posthog-go v1.10.0/go.mod h1:wB3/9Q7d9gGb1P/yf/Wri9VBlbP8oA8z++prRzL5OcY=
+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/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=
@@ -336,8 +336,8 @@ github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624
 github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
 github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
 github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
-github.com/segmentio/encoding v0.5.3 h1:OjMgICtcSFuNvQCdwqMCv9Tg7lEOXGwm1J5RPQccx6w=
-github.com/segmentio/encoding v0.5.3/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0=
+github.com/segmentio/encoding v0.5.4 h1:OW1VRern8Nw6ITAtwSZ7Idrl3MXCFwXHPgqESYfvNt0=
+github.com/segmentio/encoding v0.5.4/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0=
 github.com/sergeymakinen/go-bmp v1.0.0 h1:SdGTzp9WvCV0A1V0mBeaS7kQAwNLdVJbmHlqNWq0R+M=
 github.com/sergeymakinen/go-bmp v1.0.0/go.mod h1:/mxlAQZRLxSvJFNIEGGLBE/m40f3ZnUifpgVDlcUIEY=
 github.com/sergeymakinen/go-ico v1.0.0-beta.0 h1:m5qKH7uPKLdrygMWxbamVn+tl2HfiA3K6MFJw4GfZvQ=
@@ -428,8 +428,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
 golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
 golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
 golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
-golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
-golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
+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/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -453,8 +453,8 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
 golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
 golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
 golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
-golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
-golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
+golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
+golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
 golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
 golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -495,8 +495,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
 golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
 golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
 golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
-golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
-golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
+golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
+golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
@@ -506,8 +506,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
-golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
-golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
+golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
+golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
 golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
 golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

internal/agent/agent.go 🔗

@@ -55,6 +55,8 @@ const (
 	smallContextWindowRatio     = 0.2
 )
 
+var userAgent = fmt.Sprintf("Charm-Crush/%s (https://charm.land/crush)", version.Version)
+
 //go:embed templates/title.md
 var titlePrompt []byte
 
@@ -201,7 +203,7 @@ func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy
 		largeModel.Model,
 		fantasy.WithSystemPrompt(systemPrompt),
 		fantasy.WithTools(agentTools...),
-		fantasy.WithUserAgent("Charm Crush/"+version.Version),
+		fantasy.WithUserAgent(userAgent),
 	)
 
 	sessionLock := sync.Mutex{}
@@ -610,7 +612,7 @@ func (a *sessionAgent) Summarize(ctx context.Context, sessionID string, opts fan
 
 	agent := fantasy.NewAgent(largeModel.Model,
 		fantasy.WithSystemPrompt(string(summaryPrompt)),
-		fantasy.WithUserAgent("Charm Crush/"+version.Version),
+		fantasy.WithUserAgent(userAgent),
 	)
 	summaryMessage, err := a.messages.Create(ctx, sessionID, message.CreateMessageParams{
 		Role:             message.Assistant,
@@ -806,7 +808,7 @@ func (a *sessionAgent) generateTitle(ctx context.Context, sessionID string, user
 		return fantasy.NewAgent(m,
 			fantasy.WithSystemPrompt(string(p)+"\n /no_think"),
 			fantasy.WithMaxOutputTokens(tok),
-			fantasy.WithUserAgent("Charm Crush/"+version.Version),
+			fantasy.WithUserAgent(userAgent),
 		)
 	}
 
@@ -842,9 +844,9 @@ func (a *sessionAgent) generateTitle(ctx context.Context, sessionID string, user
 			// Welp, the large model didn't work either. Use the default
 			// session name and return.
 			slog.Error("Error generating title with large model", "err", err)
-			saveErr := a.sessions.UpdateTitleAndUsage(ctx, sessionID, DefaultSessionName, 0, 0, 0)
+			saveErr := a.sessions.Rename(ctx, sessionID, DefaultSessionName)
 			if saveErr != nil {
-				slog.Error("Failed to save session title and usage", "error", saveErr)
+				slog.Error("Failed to save session title", "error", saveErr)
 			}
 			return
 		}
@@ -854,9 +856,9 @@ func (a *sessionAgent) generateTitle(ctx context.Context, sessionID string, user
 		// Actually, we didn't get a response so we can't. Use the default
 		// session name and return.
 		slog.Error("Response is nil; can't generate title")
-		saveErr := a.sessions.UpdateTitleAndUsage(ctx, sessionID, DefaultSessionName, 0, 0, 0)
+		saveErr := a.sessions.Rename(ctx, sessionID, DefaultSessionName)
 		if saveErr != nil {
-			slog.Error("Failed to save session title and usage", "error", saveErr)
+			slog.Error("Failed to save session title", "error", saveErr)
 		}
 		return
 	}

internal/agent/agent_test.go 🔗

@@ -20,7 +20,7 @@ import (
 )
 
 var modelPairs = []modelPair{
-	{"anthropic-sonnet", anthropicBuilder("claude-sonnet-4-5-20250929"), anthropicBuilder("claude-3-5-haiku-20241022")},
+	{"anthropic-sonnet", anthropicBuilder("claude-sonnet-4-6"), anthropicBuilder("claude-haiku-4-5-20251001")},
 	{"openai-gpt-5", openaiBuilder("gpt-5"), openaiBuilder("gpt-4o")},
 	{"openrouter-kimi-k2", openRouterBuilder("moonshotai/kimi-k2-0905"), openRouterBuilder("qwen/qwen3-next-80b-a3b-instruct")},
 	{"zai-glm4.6", zAIBuilder("glm-4.6"), zAIBuilder("glm-4.5-air")},

internal/agent/coordinator.go 🔗

@@ -41,7 +41,7 @@ import (
 	"charm.land/fantasy/providers/openaicompat"
 	"charm.land/fantasy/providers/openrouter"
 	"charm.land/fantasy/providers/vercel"
-	openaisdk "github.com/openai/openai-go/v2/option"
+	openaisdk "github.com/openai/openai-go/v3/option"
 	"github.com/qjebbs/go-jsons"
 )
 
@@ -725,7 +725,7 @@ func (c *coordinator) buildAzureProvider(baseURL, apiKey string, headers map[str
 	return azure.New(opts...)
 }
 
-func (c *coordinator) buildBedrockProvider(headers map[string]string) (fantasy.Provider, error) {
+func (c *coordinator) buildBedrockProvider(apiKey string, headers map[string]string) (fantasy.Provider, error) {
 	var opts []bedrock.Option
 	if c.cfg.Config().Options.Debug {
 		httpClient := log.NewHTTPClient()
@@ -734,9 +734,13 @@ func (c *coordinator) buildBedrockProvider(headers map[string]string) (fantasy.P
 	if len(headers) > 0 {
 		opts = append(opts, bedrock.WithHeaders(headers))
 	}
-	bearerToken := os.Getenv("AWS_BEARER_TOKEN_BEDROCK")
-	if bearerToken != "" {
-		opts = append(opts, bedrock.WithAPIKey(bearerToken))
+	switch {
+	case apiKey != "":
+		opts = append(opts, bedrock.WithAPIKey(apiKey))
+	case os.Getenv("AWS_BEARER_TOKEN_BEDROCK") != "":
+		opts = append(opts, bedrock.WithAPIKey(os.Getenv("AWS_BEARER_TOKEN_BEDROCK")))
+	default:
+		// Skip, let the SDK do authentication.
 	}
 	return bedrock.New(opts...)
 }
@@ -824,7 +828,7 @@ func (c *coordinator) buildProvider(providerCfg config.ProviderConfig, model con
 	case azure.Name:
 		return c.buildAzureProvider(baseURL, apiKey, headers, providerCfg.ExtraParams)
 	case bedrock.Name:
-		return c.buildBedrockProvider(headers)
+		return c.buildBedrockProvider(apiKey, headers)
 	case google.Name:
 		return c.buildGoogleProvider(baseURL, apiKey, headers)
 	case "google-vertex":

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

@@ -8,14 +8,14 @@ interactions:
     proto_minor: 1
     content_length: 802
     host: ""
-    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse bash to create a file named test.txt with content ''hello bash''. do not print its timestamp\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse bash to create a file named test.txt with content ''hello bash''. do not print its timestamp\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-haiku-4-5-20251001","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
     headers:
       Accept:
       - application/json
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.14.0
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://api.anthropic.com/v1/messages
     method: POST
   response:
@@ -23,61 +23,62 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
+    uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01Lij7hAdrqXtCCiddzXdoGK","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":2,"service_tier":"standard"}}}
+      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"}}     }
 
       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":"Bash"} }
+      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":" File"}              }
+      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":" Creation"}            }
+      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":" Comman"}          }
+      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":"d"}    }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" 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":8}           }
+      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: 811.339375ms
+    duration: 580.853041ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52393
+    content_length: 52585
     host: ""

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

@@ -8,14 +8,14 @@ interactions:
     proto_minor: 1
     content_length: 823
     host: ""
-    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\ndownload the file from https://example-files.online-convert.com/document/txt/example.txt and save it as example.txt\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\ndownload the file from https://example-files.online-convert.com/document/txt/example.txt and save it as example.txt\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-haiku-4-5-20251001","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
     headers:
       Accept:
       - application/json
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.14.0
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://api.anthropic.com/v1/messages
     method: POST
   response:
@@ -23,58 +23,59 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
+    uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_011YAinXEYrTqbpsq4sBCjxA","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":160,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard"}}        }
+      data: {"type":"message_start","message":{"model":"claude-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"}}          }
 
       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":"Downloa"}             }
+      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":"d File"}         }
+      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":" from Example"}       }
+      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":" URL"}              }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":".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":8} }
+      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: 640.901ms
+    duration: 458.520167ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52418
+    content_length: 52610
     host: ""

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

@@ -8,14 +8,14 @@ interactions:
     proto_minor: 1
     content_length: 844
     host: ""
-    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nfetch the content from https://example-files.online-convert.com/website/html/example.html and tell me if it contains the word ''John Doe''\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nfetch the content from https://example-files.online-convert.com/website/html/example.html and tell me if it contains the word ''John Doe''\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-haiku-4-5-20251001","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
     headers:
       Accept:
       - application/json
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.14.0
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://api.anthropic.com/v1/messages
     method: POST
   response:
@@ -23,64 +23,59 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
+    uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01QHs42eeZPJbxjrFBiaSQu3","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":167,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard"}}              }
+      data: {"type":"message_start","message":{"model":"claude-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"}}      }
 
       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":"Website"}       }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Content"}         }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Check"}      }
+      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":" for"}   }
+      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":" 'John Doe"}              }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" example"}              }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"'"}           }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":".html contains \"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":13}       }
+      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}       }
 
       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: 601.885125ms
+    duration: 446.485541ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52436
+    content_length: 52628
     host: ""

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

@@ -8,14 +8,14 @@ interactions:
     proto_minor: 1
     content_length: 763
     host: ""
-    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse glob to find all .go files in the current directory\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse glob to find all .go files in the current directory\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-haiku-4-5-20251001","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
     headers:
       Accept:
       - application/json
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.14.0
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://api.anthropic.com/v1/messages
     method: POST
   response:
@@ -23,61 +23,59 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
+    uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_016WcJGfCcpgVqfScPMNdmBp","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":142,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard"}}              }
+      data: {"type":"message_start","message":{"model":"claude-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"}}         }
 
       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":"Fin"}  }
+      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":"d Go"}              }
+      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"}     }
+      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":" with"}            }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Glob"}       }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" glob"}              }
 
       event: content_block_stop
-      data: {"type":"content_block_stop","index":0             }
+      data: {"type":"content_block_stop","index":0   }
 
       event: message_delta
-      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":142,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":9}            }
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":142,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":8}          }
 
       event: message_stop
-      data: {"type":"message_stop"         }
+      data: {"type":"message_stop"           }
 
     headers:
       Content-Type:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 683.862917ms
+    duration: 858.447625ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52354
+    content_length: 52546
     host: ""

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

@@ -8,14 +8,14 @@ interactions:
     proto_minor: 1
     content_length: 761
     host: ""
-    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse grep to search for the word ''package'' in go files\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse grep to search for the word ''package'' in go files\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-haiku-4-5-20251001","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
     headers:
       Accept:
       - application/json
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.14.0
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://api.anthropic.com/v1/messages
     method: POST
   response:
@@ -23,61 +23,56 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
+    uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_0181LpjAHqcVep2LP8kMttkT","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"}}               }
+      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"}}          }
 
       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":"grep"}     }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Files"}        }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" search"}          }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Package"} }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Search with"}              }
-
-      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":" 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":10}         }
+      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}      }
 
       event: message_stop
-      data: {"type":"message_stop"  }
+      data: {"type":"message_stop"           }
 
     headers:
       Content-Type:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 647.254041ms
+    duration: 451.462041ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52352
+    content_length: 52544
     host: ""

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

@@ -8,14 +8,14 @@ interactions:
     proto_minor: 1
     content_length: 757
     host: ""
-    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse ls to list the files in the current directory\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse ls to list the files in the current directory\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-haiku-4-5-20251001","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
     headers:
       Accept:
       - application/json
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.14.0
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://api.anthropic.com/v1/messages
     method: POST
   response:
@@ -23,55 +23,59 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
+    uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01MFyJCeDt5XVr7qQrdbfQ3Z","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":140,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard"}}  }
+      data: {"type":"message_start","message":{"model":"claude-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"}}     }
 
       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":"List"}      }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Using"}               }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Files"}      }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" ls"} }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" in Current Directory"}        }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" command"} }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" to list 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":140,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":8} }
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":140,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":9}            }
 
       event: message_stop
-      data: {"type":"message_stop"          }
+      data: {"type":"message_stop"      }
 
     headers:
       Content-Type:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 539.973208ms
+    duration: 434.346709ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52346
+    content_length: 52538
     host: ""

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

@@ -8,14 +8,14 @@ interactions:
     proto_minor: 1
     content_length: 836
     host: ""
-    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse multiedit to change ''Hello, World!'' to ''Hello, Crush!'' and add a comment ''// Greeting'' above the fmt.Println line in main.go\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse multiedit to change ''Hello, World!'' to ''Hello, Crush!'' and add a comment ''// Greeting'' above the fmt.Println line in main.go\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-haiku-4-5-20251001","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
     headers:
       Accept:
       - application/json
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.14.0
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://api.anthropic.com/v1/messages
     method: POST
   response:
@@ -23,61 +23,62 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
+    uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01MWKFC4YJpdfdLd6h1kfcfd","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":170,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":2,"service_tier":"standard"}}   }
+      data: {"type":"message_start","message":{"model":"claude-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"}}  }
 
       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":"Modify"}     }
+      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":" Go"}               }
+      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":" Hello"}              }
+      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":" Worl"}  }
+      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":"d Greeting"}           }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" main.go"} }
 
       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":10}               }
+      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}         }
 
       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: 664.226709ms
+    duration: 469.534792ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52432
+    content_length: 52624
     host: ""

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

@@ -8,14 +8,14 @@ interactions:
     proto_minor: 1
     content_length: 842
     host: ""
-    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse glob to find all .go files and use ls to list the current directory, it is very important that you run both tool calls in parallel\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse glob to find all .go files and use ls to list the current directory, it is very important that you run both tool calls in parallel\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-haiku-4-5-20251001","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
     headers:
       Accept:
       - application/json
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.14.0
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://api.anthropic.com/v1/messages
     method: POST
   response:
@@ -23,58 +23,68 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
+    uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_011AxTk6fRGrP3MaJPbdM1kh","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":159,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":2,"service_tier":"standard"}}               }
+      data: {"type":"message_start","message":{"model":"claude-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"}}        }
 
       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":"Parallel"}}
+      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"}         }
+
+      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":" Go File"}       }
+      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":" an"}             }
+      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":"d Directory Listing"}            }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" listing"}           }
 
       event: content_block_stop
-      data: {"type":"content_block_stop","index":0        }
+      data: {"type":"content_block_stop","index":0}
 
       event: message_delta
       data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":159,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":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: 636.447167ms
+    duration: 638.720958ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52443
+    content_length: 52635
     host: ""

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

@@ -8,14 +8,14 @@ interactions:
     proto_minor: 1
     content_length: 723
     host: ""
-    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nRead the go mod\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nRead the go mod\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-haiku-4-5-20251001","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
     headers:
       Accept:
       - application/json
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.14.0
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://api.anthropic.com/v1/messages
     method: POST
   response:
@@ -23,58 +23,59 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
+    uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01BS8RX55UAXGbe4XdL5VxK5","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":134,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard"}}          }
+      data: {"type":"message_start","message":{"model":"claude-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"}}  }
 
       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":"Rea"}     }
+      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":"d Go"}          }
+      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":" Module"}               }
+      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":" Details"}     }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Review"}   }
 
       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: 589.305792ms
+    duration: 614.432792ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52316
+    content_length: 52508
     host: ""

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

@@ -8,14 +8,14 @@ interactions:
     proto_minor: 1
     content_length: 713
     host: ""
-    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nHello\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nHello\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-haiku-4-5-20251001","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
     headers:
       Accept:
       - application/json
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.14.0
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://api.anthropic.com/v1/messages
     method: POST
   response:
@@ -23,55 +23,50 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
+    uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01RhwrPwqgU78kv4XsoesFPF","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":131,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard"}}}
+      data: {"type":"message_start","message":{"model":"claude-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"}}      }
 
       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":"Quick"}              }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Chat"}        }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Opener"}   }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello"}}
 
       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":7}}
+      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}        }
 
       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: 705.524375ms
+    duration: 464.945084ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52306
+    content_length: 52498
     host: ""

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

@@ -8,14 +8,14 @@ interactions:
     proto_minor: 1
     content_length: 768
     host: ""
-    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse sourcegraph to search for ''func main'' in Go repositories\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse sourcegraph to search for ''func main'' in Go repositories\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-haiku-4-5-20251001","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
     headers:
       Accept:
       - application/json
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.14.0
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://api.anthropic.com/v1/messages
     method: POST
   response:
@@ -23,58 +23,59 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
+    uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_01FkLqqw1crC8WC9dAUtwxqu","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":145,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":3,"service_tier":"standard"}}          }
+      data: {"type":"message_start","message":{"model":"claude-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"}}          }
 
       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 Go"}        }
+      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":" Repos"}}
+      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":" for Main"}            }
+      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":" Function"}              }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" 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":11}           }
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":145,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":16}              }
 
       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: 640.628291ms
+    duration: 1.13498575s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52366
+    content_length: 52558
     host: ""

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

@@ -8,14 +8,14 @@ interactions:
     proto_minor: 1
     content_length: 777
     host: ""
-    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nupdate the main.go file by changing the print to say hello from crush\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nupdate the main.go file by changing the print to say hello from crush\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-haiku-4-5-20251001","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
     headers:
       Accept:
       - application/json
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.14.0
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://api.anthropic.com/v1/messages
     method: POST
   response:
@@ -23,58 +23,59 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
+    uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_0198CQ2JnP8dYvrKr27saGVX","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":145,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard"}}    }
+      data: {"type":"message_start","message":{"model":"claude-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"}} }
 
       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"}      }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Update"}        }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" main"}               }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" main"}             }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":".go print"}        }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":".go hello"}               }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" message"}           }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" 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":9}             }
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":145,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":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: 557.108833ms
+    duration: 470.455ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52372
+    content_length: 52564
     host: ""

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

@@ -8,14 +8,14 @@ interactions:
     proto_minor: 1
     content_length: 817
     host: ""
-    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse write to create a new file called config.json with content ''{\"name\": \"test\", \"version\": \"1.0.0\"}''\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-3-5-haiku-20241022","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
+    body: '{"max_tokens":40,"messages":[{"content":[{"text":"Generate a concise title for the following content:\n\nuse write to create a new file called config.json with content ''{\"name\": \"test\", \"version\": \"1.0.0\"}''\n \u003cthink\u003e\n\n\u003c/think\u003e","type":"text"}],"role":"user"}],"model":"claude-haiku-4-5-20251001","system":[{"text":"you will generate a short title based on the first message a user begins a conversation with\n\n\u003crules\u003e\n- ensure it is not more than 50 characters long\n- the title should be a summary of the user''s message\n- it should be one line long\n- do not use quotes or colons\n- the entire text you return will be used as the title\n- never return anything that is more than one sentence (one line) long\n\u003c/rules\u003e\n\n /no_think","type":"text"}],"stream":true}'
     headers:
       Accept:
       - application/json
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.14.0
+      - Charm-Crush/devel (https://charm.land/crush)
     url: https://api.anthropic.com/v1/messages
     method: POST
   response:
@@ -23,58 +23,62 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
+    uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"model":"claude-3-5-haiku-20241022","id":"msg_016VUcmtZyoNJiJysc1oxRtZ","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":161,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard"}}     }
+      data: {"type":"message_start","message":{"model":"claude-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"}}   }
 
       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":"Creating"}            }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Create"}             }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" config"}           }
+      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 with JSON"}}
+      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":" data"}        }
+      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"}             }
 
       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":10}   }
+      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: 555.094125ms
+    duration: 807.968541ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 52409
+    content_length: 52601
     host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/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://api.openai.com/v1/chat/completions
     method: POST
   response:
@@ -24,23 +24,25 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Czjp9999VWZzcDOifgxBIBqcSm4HT","object":"chat.completion.chunk","created":1768830191,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"bUV63yG95BqGXw"}
+      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-Czjp9999VWZzcDOifgxBIBqcSm4HT","object":"chat.completion.chunk","created":1768830191,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"Create"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"1z0Fv3Tkd6"}
+      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-Czjp9999VWZzcDOifgxBIBqcSm4HT","object":"chat.completion.chunk","created":1768830191,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"C426rRcRvG6"}
+      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-Czjp9999VWZzcDOifgxBIBqcSm4HT","object":"chat.completion.chunk","created":1768830191,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"FngAUBvZG3n71"}
+      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-Czjp9999VWZzcDOifgxBIBqcSm4HT","object":"chat.completion.chunk","created":1768830191,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Bash"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"k82T3NyIeZn"}
+      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-Czjp9999VWZzcDOifgxBIBqcSm4HT","object":"chat.completion.chunk","created":1768830191,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Without"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Vbe4EU54"}
+      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-Czjp9999VWZzcDOifgxBIBqcSm4HT","object":"chat.completion.chunk","created":1768830191,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Timestamp"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"yGQZi2"}
+      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-Czjp9999VWZzcDOifgxBIBqcSm4HT","object":"chat.completion.chunk","created":1768830191,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"fC0Xm5I8zq"}
+      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-Czjp9999VWZzcDOifgxBIBqcSm4HT","object":"chat.completion.chunk","created":1768830191,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[],"usage":{"prompt_tokens":145,"completion_tokens":6,"total_tokens":151,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"PJLKHqx144Bd0A"}
+      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-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: [DONE]
 
@@ -49,22 +51,22 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 462.517083ms
+    duration: 590.488833ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50734
+    content_length: 50935
     host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/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://api.openai.com/v1/chat/completions
     method: POST
   response:
@@ -24,23 +24,23 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-CzjpMASHGa0KE7gogMQsoEw5kBkKm","object":"chat.completion.chunk","created":1768830204,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_deacdd5f6f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"tc5dsBZDiWj1KC"}
+      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-CzjpMASHGa0KE7gogMQsoEw5kBkKm","object":"chat.completion.chunk","created":1768830204,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_deacdd5f6f","choices":[{"index":0,"delta":{"content":"Download"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"5EIK1K0G"}
+      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-CzjpMASHGa0KE7gogMQsoEw5kBkKm","object":"chat.completion.chunk","created":1768830204,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_deacdd5f6f","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"iZvzUc95rMPu"}
+      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-CzjpMASHGa0KE7gogMQsoEw5kBkKm","object":"chat.completion.chunk","created":1768830204,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_deacdd5f6f","choices":[{"index":0,"delta":{"content":" Save"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"c4VqjRgTgUo"}
+      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-CzjpMASHGa0KE7gogMQsoEw5kBkKm","object":"chat.completion.chunk","created":1768830204,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_deacdd5f6f","choices":[{"index":0,"delta":{"content":" Example"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"90hZHZYg"}
+      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-CzjpMASHGa0KE7gogMQsoEw5kBkKm","object":"chat.completion.chunk","created":1768830204,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_deacdd5f6f","choices":[{"index":0,"delta":{"content":".txt"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"99FcHSsVLzva"}
+      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-CzjpMASHGa0KE7gogMQsoEw5kBkKm","object":"chat.completion.chunk","created":1768830204,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_deacdd5f6f","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"cdp2a07T0OB"}
+      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-CzjpMASHGa0KE7gogMQsoEw5kBkKm","object":"chat.completion.chunk","created":1768830204,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_deacdd5f6f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"ijDn66iVAI"}
+      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-CzjpMASHGa0KE7gogMQsoEw5kBkKm","object":"chat.completion.chunk","created":1768830204,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_deacdd5f6f","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":"C9d9Vz5rJwg0pZ"}
+      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: [DONE]
 
@@ -49,22 +49,22 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 1.09768275s
+    duration: 427.27125ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50759
+    content_length: 50960
     host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/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://api.openai.com/v1/chat/completions
     method: POST
   response:
@@ -24,29 +24,31 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-CzjpXY0NnY3HE3lqVJsX1E0QZnClg","object":"chat.completion.chunk","created":1768830215,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"VhKLdJMzPv4zTF"}
+      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-CzjpXY0NnY3HE3lqVJsX1E0QZnClg","object":"chat.completion.chunk","created":1768830215,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"Check"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"hrg10QzQcmP"}
+      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-CzjpXY0NnY3HE3lqVJsX1E0QZnClg","object":"chat.completion.chunk","created":1768830215,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" HTML"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"NAFAT7HZQQx"}
+      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-CzjpXY0NnY3HE3lqVJsX1E0QZnClg","object":"chat.completion.chunk","created":1768830215,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" for"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"9R8aoN7LrXit"}
+      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-CzjpXY0NnY3HE3lqVJsX1E0QZnClg","object":"chat.completion.chunk","created":1768830215,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"mDowc6tWWiEJXY"}
+      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-CzjpXY0NnY3HE3lqVJsX1E0QZnClg","object":"chat.completion.chunk","created":1768830215,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"John"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"wabcvWDKuvBw"}
+      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-CzjpXY0NnY3HE3lqVJsX1E0QZnClg","object":"chat.completion.chunk","created":1768830215,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Doe"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"p6l0NKowhtjv"}
+      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-CzjpXY0NnY3HE3lqVJsX1E0QZnClg","object":"chat.completion.chunk","created":1768830215,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"kDCOIpSDBsg27ap"}
+      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-CzjpXY0NnY3HE3lqVJsX1E0QZnClg","object":"chat.completion.chunk","created":1768830215,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Occ"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"hlKaj6olmcVp"}
+      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-CzjpXY0NnY3HE3lqVJsX1E0QZnClg","object":"chat.completion.chunk","created":1768830215,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"urrence"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"bK6IboJu4"}
+      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-CzjpXY0NnY3HE3lqVJsX1E0QZnClg","object":"chat.completion.chunk","created":1768830215,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"jz37ZuJ2Cs"}
+      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-CzjpXY0NnY3HE3lqVJsX1E0QZnClg","object":"chat.completion.chunk","created":1768830215,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[],"usage":{"prompt_tokens":153,"completion_tokens":9,"total_tokens":162,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"oGOHC8f5F7ED98"}
+      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: [DONE]
 
@@ -55,22 +57,22 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 485.428208ms
+    duration: 1.14852275s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50777
+    content_length: 50978
     host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/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://api.openai.com/v1/chat/completions
     method: POST
   response:
@@ -24,29 +24,29 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Czjpfn0duo3n07ZV2M1UoetlL84LL","object":"chat.completion.chunk","created":1768830223,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"AN8kcBopW7413w"}
+      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-Czjpfn0duo3n07ZV2M1UoetlL84LL","object":"chat.completion.chunk","created":1768830223,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"Finding"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"s9ELbRDAV"}
+      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-Czjpfn0duo3n07ZV2M1UoetlL84LL","object":"chat.completion.chunk","created":1768830223,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" ."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"O9h76mLSPhdkPa"}
+      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-Czjpfn0duo3n07ZV2M1UoetlL84LL","object":"chat.completion.chunk","created":1768830223,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"uzz6sXLNppHb1H"}
+      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-Czjpfn0duo3n07ZV2M1UoetlL84LL","object":"chat.completion.chunk","created":1768830223,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"clQKAC0BtS"}
+      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-Czjpfn0duo3n07ZV2M1UoetlL84LL","object":"chat.completion.chunk","created":1768830223,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"iMDIUEkMuf4"}
+      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-Czjpfn0duo3n07ZV2M1UoetlL84LL","object":"chat.completion.chunk","created":1768830223,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Glob"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"N6NRkYKNrMR"}
+      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-Czjpfn0duo3n07ZV2M1UoetlL84LL","object":"chat.completion.chunk","created":1768830223,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"phy8zvhGTaAdn"}
+      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-Czjpfn0duo3n07ZV2M1UoetlL84LL","object":"chat.completion.chunk","created":1768830223,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Current"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"M4ITICZy"}
+      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-Czjpfn0duo3n07ZV2M1UoetlL84LL","object":"chat.completion.chunk","created":1768830223,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Directory"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"1tNMzp"}
+      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-Czjpfn0duo3n07ZV2M1UoetlL84LL","object":"chat.completion.chunk","created":1768830223,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"bPVsxaKeA3"}
+      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-Czjpfn0duo3n07ZV2M1UoetlL84LL","object":"chat.completion.chunk","created":1768830223,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","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":"pCeZlHbKDEb9MQ"}
+      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: [DONE]
 
@@ -55,22 +55,22 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 565.294416ms
+    duration: 519.51625ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50695
+    content_length: 50896
     host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/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://api.openai.com/v1/chat/completions
     method: POST
   response:
@@ -24,33 +24,29 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-CzjpkEXSYoFaA6TqesglhFgtKBe5E","object":"chat.completion.chunk","created":1768830228,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"TvvAs6UXCKtJpO"}
+      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-CzjpkEXSYoFaA6TqesglhFgtKBe5E","object":"chat.completion.chunk","created":1768830228,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"Using"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"8mJifko0V1D"}
+      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-CzjpkEXSYoFaA6TqesglhFgtKBe5E","object":"chat.completion.chunk","created":1768830228,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Gre"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"7Gbs6dE1n9QQ"}
+      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-CzjpkEXSYoFaA6TqesglhFgtKBe5E","object":"chat.completion.chunk","created":1768830228,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"p"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"gsKuzPEBBzSDIgF"}
+      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-CzjpkEXSYoFaA6TqesglhFgtKBe5E","object":"chat.completion.chunk","created":1768830228,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Jd1M7N6pYuirn"}
+      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-CzjpkEXSYoFaA6TqesglhFgtKBe5E","object":"chat.completion.chunk","created":1768830228,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Search"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"WPPnJsnrD"}
+      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-CzjpkEXSYoFaA6TqesglhFgtKBe5E","object":"chat.completion.chunk","created":1768830228,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"3FD4N3lDA8dIIq"}
+      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-CzjpkEXSYoFaA6TqesglhFgtKBe5E","object":"chat.completion.chunk","created":1768830228,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"Package"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"sYRitOpVY"}
+      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-CzjpkEXSYoFaA6TqesglhFgtKBe5E","object":"chat.completion.chunk","created":1768830228,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Psh8uHyftKu9OaD"}
+      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-CzjpkEXSYoFaA6TqesglhFgtKBe5E","object":"chat.completion.chunk","created":1768830228,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"uB9fseVHm8Qq9"}
+      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-CzjpkEXSYoFaA6TqesglhFgtKBe5E","object":"chat.completion.chunk","created":1768830228,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"toOBGh8cblQKy"}
+      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-CzjpkEXSYoFaA6TqesglhFgtKBe5E","object":"chat.completion.chunk","created":1768830228,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Px8UAjDQ1Y"}
-
-      data: {"id":"chatcmpl-CzjpkEXSYoFaA6TqesglhFgtKBe5E","object":"chat.completion.chunk","created":1768830228,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"WEiddfZXsi"}
-
-      data: {"id":"chatcmpl-CzjpkEXSYoFaA6TqesglhFgtKBe5E","object":"chat.completion.chunk","created":1768830228,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","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":"fyOv9URDB7WPO"}
+      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: [DONE]
 
@@ -59,22 +55,22 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 529.456125ms
+    duration: 517.527708ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50693
+    content_length: 50894
     host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/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://api.openai.com/v1/chat/completions
     method: POST
   response:
@@ -24,23 +24,29 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Czjpp21JrAlDsrAmzS6iFO2WfXAXE","object":"chat.completion.chunk","created":1768830233,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"n0nG28t5ZBF6ER"}
+      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-Czjpp21JrAlDsrAmzS6iFO2WfXAXE","object":"chat.completion.chunk","created":1768830233,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"Listing"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Qy6L2dEVd"}
+      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-Czjpp21JrAlDsrAmzS6iFO2WfXAXE","object":"chat.completion.chunk","created":1768830233,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Files"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"OGWA86hnC9"}
+      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-Czjpp21JrAlDsrAmzS6iFO2WfXAXE","object":"chat.completion.chunk","created":1768830233,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"d0UrCtvqjuH"}
+      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-Czjpp21JrAlDsrAmzS6iFO2WfXAXE","object":"chat.completion.chunk","created":1768830233,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"KJia9s0n7rDV"}
+      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-Czjpp21JrAlDsrAmzS6iFO2WfXAXE","object":"chat.completion.chunk","created":1768830233,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" ls"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"3rzKom80l93ug"}
+      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-Czjpp21JrAlDsrAmzS6iFO2WfXAXE","object":"chat.completion.chunk","created":1768830233,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Command"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"lyiPHQGe"}
+      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-Czjpp21JrAlDsrAmzS6iFO2WfXAXE","object":"chat.completion.chunk","created":1768830233,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"JDQYzoRO2P"}
+      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-Czjpp21JrAlDsrAmzS6iFO2WfXAXE","object":"chat.completion.chunk","created":1768830233,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[],"usage":{"prompt_tokens":135,"completion_tokens":6,"total_tokens":141,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"EPoJDe4VnXLh1e"}
+      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-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-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: [DONE]
 
@@ -49,22 +55,22 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 411.950625ms
+    duration: 630.309125ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50687
+    content_length: 50888
     host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/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://api.openai.com/v1/chat/completions
     method: POST
   response:
@@ -24,41 +24,27 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"w8sqWhzpcnHs6W"}
+      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-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"Edit"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ctpbhoqwzTZz"}
+      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-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"TGykGuKGPdZeN0"}
+      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-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"Hello"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"61NaUxH95hU"}
+      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-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"eDLlGtoT0ySeGqD"}
+      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-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" World"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"8EscbuFp3X"}
+      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-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"!'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"FDQCMsLNraJW6l"}
+      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-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"PZtbSLH8ktyFq"}
+      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-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"31dms5V3FvO5X1"}
+      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-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"Hello"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"oLxfEtBAmAi"}
+      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-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"YCAS81ZDASz7hmB"}
-
-      data: {"id":"chatcmpl-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Crush"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ZBh8BjoPYS"}
-
-      data: {"id":"chatcmpl-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"!'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"LCOdBS6YPqpvye"}
-
-      data: {"id":"chatcmpl-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"woB21MizPF1qF"}
-
-      data: {"id":"chatcmpl-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" main"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"3vlYGdke04Q"}
-
-      data: {"id":"chatcmpl-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":".go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"n2Zprwwja22n4"}
-
-      data: {"id":"chatcmpl-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"syai28mVpc"}
-
-      data: {"id":"chatcmpl-CzjptZarMAkGsZTFKUM0EMMzEmTkf","object":"chat.completion.chunk","created":1768830237,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[],"usage":{"prompt_tokens":157,"completion_tokens":15,"total_tokens":172,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"52ea3nLBvH3wB"}
+      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: [DONE]
 
@@ -67,22 +53,22 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 469.62075ms
+    duration: 620.533292ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50773
+    content_length: 50974
     host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/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://api.openai.com/v1/chat/completions
     method: POST
   response:
@@ -24,27 +24,25 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-CzjqSIDKk0IIoCdj8CTB9GrShYjL0","object":"chat.completion.chunk","created":1768830272,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Thp3GWPBtcfpFl"}
+      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-CzjqSIDKk0IIoCdj8CTB9GrShYjL0","object":"chat.completion.chunk","created":1768830272,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"Parallel"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"WE3oG6Dc"}
+      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-CzjqSIDKk0IIoCdj8CTB9GrShYjL0","object":"chat.completion.chunk","created":1768830272,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Execution"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"BhxBUy"}
+      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-CzjqSIDKk0IIoCdj8CTB9GrShYjL0","object":"chat.completion.chunk","created":1768830272,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" of"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"CerEoaZkPYIr3"}
+      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-CzjqSIDKk0IIoCdj8CTB9GrShYjL0","object":"chat.completion.chunk","created":1768830272,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"njaky8RPXtu"}
+      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-CzjqSIDKk0IIoCdj8CTB9GrShYjL0","object":"chat.completion.chunk","created":1768830272,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Search"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ShEOqgaKt"}
+      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-CzjqSIDKk0IIoCdj8CTB9GrShYjL0","object":"chat.completion.chunk","created":1768830272,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"yRmX9ZfGFg03"}
+      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-CzjqSIDKk0IIoCdj8CTB9GrShYjL0","object":"chat.completion.chunk","created":1768830272,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Directory"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"R5Yuho"}
+      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-CzjqSIDKk0IIoCdj8CTB9GrShYjL0","object":"chat.completion.chunk","created":1768830272,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Listing"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"XV9SCefj"}
+      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-CzjqSIDKk0IIoCdj8CTB9GrShYjL0","object":"chat.completion.chunk","created":1768830272,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"ChtzpEnrlI"}
-
-      data: {"id":"chatcmpl-CzjqSIDKk0IIoCdj8CTB9GrShYjL0","object":"chat.completion.chunk","created":1768830272,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[],"usage":{"prompt_tokens":154,"completion_tokens":8,"total_tokens":162,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"Cnz16IJuNPSTX6"}
+      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: [DONE]
 
@@ -53,22 +51,22 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 743.282416ms
+    duration: 541.726917ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50784
+    content_length: 50985
     host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/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://api.openai.com/v1/chat/completions
     method: POST
   response:
@@ -24,19 +24,17 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-CzjouBic6rLxQKHupRoN2PEBP7e5B","object":"chat.completion.chunk","created":1768830176,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_deacdd5f6f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"FDQDoWDckcMAqF"}
+      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-CzjouBic6rLxQKHupRoN2PEBP7e5B","object":"chat.completion.chunk","created":1768830176,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_deacdd5f6f","choices":[{"index":0,"delta":{"content":"Reading"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"SU89d8sKD"}
+      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-CzjouBic6rLxQKHupRoN2PEBP7e5B","object":"chat.completion.chunk","created":1768830176,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_deacdd5f6f","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"W3MgsDujc3Eaul"}
+      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-CzjouBic6rLxQKHupRoN2PEBP7e5B","object":"chat.completion.chunk","created":1768830176,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_deacdd5f6f","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"fgaFCwoo9EflX"}
+      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-CzjouBic6rLxQKHupRoN2PEBP7e5B","object":"chat.completion.chunk","created":1768830176,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_deacdd5f6f","choices":[{"index":0,"delta":{"content":" Module"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"OembTm90U"}
+      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-CzjouBic6rLxQKHupRoN2PEBP7e5B","object":"chat.completion.chunk","created":1768830176,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_deacdd5f6f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"fz77ZNNj1l"}
-
-      data: {"id":"chatcmpl-CzjouBic6rLxQKHupRoN2PEBP7e5B","object":"chat.completion.chunk","created":1768830176,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_deacdd5f6f","choices":[],"usage":{"prompt_tokens":129,"completion_tokens":4,"total_tokens":133,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"cXX7n4KtoXfrel"}
+      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: [DONE]
 
@@ -45,22 +43,22 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 2.249190917s
+    duration: 706.98175ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50657
+    content_length: 50858
     host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/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://api.openai.com/v1/chat/completions
     method: POST
   response:
@@ -24,15 +24,15 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Czjoqy3qhdl7QlaVUezlnqVq4Su8C","object":"chat.completion.chunk","created":1768830172,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"TDnVpvMW88Xmde"}
+      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-Czjoqy3qhdl7QlaVUezlnqVq4Su8C","object":"chat.completion.chunk","created":1768830172,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":"Friendly"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"xQaCvs2o"}
+      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-Czjoqy3qhdl7QlaVUezlnqVq4Su8C","object":"chat.completion.chunk","created":1768830172,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{"content":" Greeting"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"k1WWCN6"}
+      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-Czjoqy3qhdl7QlaVUezlnqVq4Su8C","object":"chat.completion.chunk","created":1768830172,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"mnZ0FAHYdF"}
+      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-Czjoqy3qhdl7QlaVUezlnqVq4Su8C","object":"chat.completion.chunk","created":1768830172,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_cbf1785567","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":"DmwwbNsKumqAUt"}
+      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: [DONE]
 
@@ -41,22 +41,22 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 1.949141s
+    duration: 919.449334ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50647
+    content_length: 50848
     host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/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://api.openai.com/v1/chat/completions
     method: POST
   response:
@@ -24,35 +24,35 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Czk1rASc3CYebBgESFcb9JMKFkFn1","object":"chat.completion.chunk","created":1768830979,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"R95a3iTSrhETUb"}
+      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-Czk1rASc3CYebBgESFcb9JMKFkFn1","object":"chat.completion.chunk","created":1768830979,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"Search"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"5SjkmG65LN"}
+      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-Czk1rASc3CYebBgESFcb9JMKFkFn1","object":"chat.completion.chunk","created":1768830979,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" '"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"PuilvpfYYLgM5x"}
+      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-Czk1rASc3CYebBgESFcb9JMKFkFn1","object":"chat.completion.chunk","created":1768830979,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"func"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"KvyZFscXzPeq"}
+      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-Czk1rASc3CYebBgESFcb9JMKFkFn1","object":"chat.completion.chunk","created":1768830979,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" main"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"8eYsEmg7Ldr"}
+      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-Czk1rASc3CYebBgESFcb9JMKFkFn1","object":"chat.completion.chunk","created":1768830979,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"'"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"8kZnxLjyyHcmhAJ"}
+      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-Czk1rASc3CYebBgESFcb9JMKFkFn1","object":"chat.completion.chunk","created":1768830979,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"iNM0tkifwexEs"}
+      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-Czk1rASc3CYebBgESFcb9JMKFkFn1","object":"chat.completion.chunk","created":1768830979,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"CVXDb6ymhmDeW"}
+      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-Czk1rASc3CYebBgESFcb9JMKFkFn1","object":"chat.completion.chunk","created":1768830979,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Re"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"CQ8kNt0Llm7Uy"}
+      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-Czk1rASc3CYebBgESFcb9JMKFkFn1","object":"chat.completion.chunk","created":1768830979,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"positories"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"KbLwwJ"}
+      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-Czk1rASc3CYebBgESFcb9JMKFkFn1","object":"chat.completion.chunk","created":1768830979,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Using"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"L75wF53MuD"}
+      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-Czk1rASc3CYebBgESFcb9JMKFkFn1","object":"chat.completion.chunk","created":1768830979,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Source"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"MKSonEgLp"}
+      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-Czk1rASc3CYebBgESFcb9JMKFkFn1","object":"chat.completion.chunk","created":1768830979,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"graph"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"w04Ibu9PdcW"}
+      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-Czk1rASc3CYebBgESFcb9JMKFkFn1","object":"chat.completion.chunk","created":1768830979,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"ukXsXPKqhG"}
+      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-Czk1rASc3CYebBgESFcb9JMKFkFn1","object":"chat.completion.chunk","created":1768830979,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","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":"hPBvtCMxVf9cE"}
+      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: [DONE]
 
@@ -61,22 +61,22 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 552.732542ms
+    duration: 578.111292ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50707
+    content_length: 50908
     host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/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://api.openai.com/v1/chat/completions
     method: POST
   response:
@@ -24,25 +24,31 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-Czjp135HaPU3V24nyjS3BuWy7rZ18","object":"chat.completion.chunk","created":1768830183,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"lyN8ETBdlgol0g"}
+      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-Czjp135HaPU3V24nyjS3BuWy7rZ18","object":"chat.completion.chunk","created":1768830183,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"Update"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"slpbVLVP2H"}
+      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-Czjp135HaPU3V24nyjS3BuWy7rZ18","object":"chat.completion.chunk","created":1768830183,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Print"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"csnlJXHkWq"}
+      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-Czjp135HaPU3V24nyjS3BuWy7rZ18","object":"chat.completion.chunk","created":1768830183,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Message"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"vgiX0tTd"}
+      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-Czjp135HaPU3V24nyjS3BuWy7rZ18","object":"chat.completion.chunk","created":1768830183,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"yL0ebVNjRLVaR"}
+      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-Czjp135HaPU3V24nyjS3BuWy7rZ18","object":"chat.completion.chunk","created":1768830183,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" main"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"tnpOnQL3w8K"}
+      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-Czjp135HaPU3V24nyjS3BuWy7rZ18","object":"chat.completion.chunk","created":1768830183,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":".go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"UYuaUVZqGFdSu"}
+      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-Czjp135HaPU3V24nyjS3BuWy7rZ18","object":"chat.completion.chunk","created":1768830183,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" File"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"2sEh73qqzkE"}
+      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-Czjp135HaPU3V24nyjS3BuWy7rZ18","object":"chat.completion.chunk","created":1768830183,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"gf6rrszRnY"}
+      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-Czjp135HaPU3V24nyjS3BuWy7rZ18","object":"chat.completion.chunk","created":1768830183,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","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":"42QprxWa0oBMFL"}
+      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: [DONE]
 
@@ -51,22 +57,22 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 1.424788125s
+    duration: 523.732ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50713
+    content_length: 50914
     host: ""

internal/agent/testdata/TestCoderAgent/openai-gpt-5/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://api.openai.com/v1/chat/completions
     method: POST
   response:
@@ -24,23 +24,23 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"chatcmpl-CzjqJgtYTNQ1LzNr2Vy8XQCD5uR5p","object":"chat.completion.chunk","created":1768830263,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"lbWZeXAjCgr2xM"}
+      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-CzjqJgtYTNQ1LzNr2Vy8XQCD5uR5p","object":"chat.completion.chunk","created":1768830263,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":"Create"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"g2vTNiK29d"}
+      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-CzjqJgtYTNQ1LzNr2Vy8XQCD5uR5p","object":"chat.completion.chunk","created":1768830263,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" config"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"NSDOMK424"}
+      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-CzjqJgtYTNQ1LzNr2Vy8XQCD5uR5p","object":"chat.completion.chunk","created":1768830263,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":".json"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"dfB4le0vurg"}
+      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-CzjqJgtYTNQ1LzNr2Vy8XQCD5uR5p","object":"chat.completion.chunk","created":1768830263,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" with"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"FxUaaSwfBEd"}
+      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-CzjqJgtYTNQ1LzNr2Vy8XQCD5uR5p","object":"chat.completion.chunk","created":1768830263,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" JSON"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"pg0cGCkRGcE"}
+      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-CzjqJgtYTNQ1LzNr2Vy8XQCD5uR5p","object":"chat.completion.chunk","created":1768830263,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{"content":" Content"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"FYNYBrua"}
+      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-CzjqJgtYTNQ1LzNr2Vy8XQCD5uR5p","object":"chat.completion.chunk","created":1768830263,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"VsEMoKTn2b"}
+      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-CzjqJgtYTNQ1LzNr2Vy8XQCD5uR5p","object":"chat.completion.chunk","created":1768830263,"model":"gpt-4o-2024-08-06","service_tier":"default","system_fingerprint":"fp_a0e9480a2f","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":"SeLpiA4w7bzNvd"}
+      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: [DONE]
 
@@ -49,22 +49,22 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 481.66725ms
+    duration: 518.668542ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50750
+    content_length: 50951
     host: ""

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

@@ -24,21 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1768830633-Osz1qPrYiTrZY6O7qshP","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830633,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":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":"Create","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830633-Osz1qPrYiTrZY6O7qshP","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830633,"choices":[{"index":0,"delta":{"role":"assistant","content":"Create"},"finish_reason":null,"native_finish_reason":null,"logprobs":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":" test","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830633-Osz1qPrYiTrZY6O7qshP","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830633,"choices":[{"index":0,"delta":{"role":"assistant","content":" test"},"finish_reason":null,"native_finish_reason":null,"logprobs":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":".txt with","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830633-Osz1qPrYiTrZY6O7qshP","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830633,"choices":[{"index":0,"delta":{"role":"assistant","content":".txt with"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830633-Osz1qPrYiTrZY6O7qshP","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830633,"choices":[{"index":0,"delta":{"role":"assistant","content":" hello bash using"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830633-Osz1qPrYiTrZY6O7qshP","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830633,"choices":[{"index":0,"delta":{"role":"assistant","content":" bash"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830633-Osz1qPrYiTrZY6O7qshP","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830633,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
-
-      data: {"id":"gen-1768830633-Osz1qPrYiTrZY6O7qshP","provider":"Google","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830633,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":147,"completion_tokens":9,"total_tokens":156,"cost":0.00003285,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.00002205,"upstream_inference_completions_cost":0.0000108},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      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: [DONE]
 
@@ -47,15 +45,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 627.379083ms
+    duration: 711.943708ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50883
+    content_length: 51084
     host: ""

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

@@ -24,19 +24,23 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1768830324-DpEBUpsxBtavj73Ij4Xl","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830324,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":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":"Download","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830324-DpEBUpsxBtavj73Ij4Xl","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830324,"choices":[{"index":0,"delta":{"role":"assistant","content":"Download"},"finish_reason":null,"native_finish_reason":null,"logprobs":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":" example","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830324-DpEBUpsxBtavj73Ij4Xl","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830324,"choices":[{"index":0,"delta":{"role":"assistant","content":" and save example.txt"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830324-DpEBUpsxBtavj73Ij4Xl","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830324,"choices":[{"index":0,"delta":{"role":"assistant","content":" from provided"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830324-DpEBUpsxBtavj73Ij4Xl","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830324,"choices":[{"index":0,"delta":{"role":"assistant","content":" link"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830324-DpEBUpsxBtavj73Ij4Xl","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830324,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":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-1768830324-DpEBUpsxBtavj73Ij4Xl","provider":"GMICloud","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830324,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":150,"completion_tokens":9,"total_tokens":159,"cost":0.000036,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000225,"upstream_inference_completions_cost":0.0000135},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      data: {"id":"gen-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-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: [DONE]
 
@@ -45,15 +49,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 1.180815667s
+    duration: 729.655584ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50908
+    content_length: 51109
     host: ""

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

@@ -24,19 +24,17 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1768830332-uymAi6cUGQh14tZVvvWc","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830332,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":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":"Check","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830332-uymAi6cUGQh14tZVvvWc","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830332,"choices":[{"index":0,"delta":{"role":"assistant","content":"Check"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":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":" if example","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830332-uymAi6cUGQh14tZVvvWc","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830332,"choices":[{"index":0,"delta":{"role":"assistant","content":" if example"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":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-1768830332-uymAi6cUGQh14tZVvvWc","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830332,"choices":[{"index":0,"delta":{"role":"assistant","content":".html contains John"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":null}
+      data: {"id":"gen-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-1768830332-uymAi6cUGQh14tZVvvWc","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830332,"choices":[{"index":0,"delta":{"role":"assistant","content":" Doe"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":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-1768830332-uymAi6cUGQh14tZVvvWc","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830332,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}],"system_fingerprint":null}
-
-      data: {"id":"gen-1768830332-uymAi6cUGQh14tZVvvWc","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830332,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":159,"completion_tokens":7,"total_tokens":166,"cost":0.00003225,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.00002385,"upstream_inference_completions_cost":0.0000084},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      data: {"id":"gen-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: [DONE]
 
@@ -45,15 +43,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 1.455522416s
+    duration: 706.07425ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50926
+    content_length: 51127
     host: ""

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

@@ -24,21 +24,29 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1768830601-JFP8REyTpY04VjYTZEmH","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830601,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":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":"Find","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830601-JFP8REyTpY04VjYTZEmH","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830601,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830601-JFP8REyTpY04VjYTZEmH","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830601,"choices":[{"index":0,"delta":{"role":"assistant","content":"Find"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830601-JFP8REyTpY04VjYTZEmH","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830601,"choices":[{"index":0,"delta":{"role":"assistant","content":" all .go files"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830601-JFP8REyTpY04VjYTZEmH","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830601,"choices":[{"index":0,"delta":{"role":"assistant","content":" in current directory using"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830601-JFP8REyTpY04VjYTZEmH","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830601,"choices":[{"index":0,"delta":{"role":"assistant","content":" glob"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830601-JFP8REyTpY04VjYTZEmH","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830601,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":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-1768830601-JFP8REyTpY04VjYTZEmH","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830601,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":139,"completion_tokens":11,"total_tokens":150,"cost":0.00002461,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.00001251,"upstream_inference_completions_cost":0.0000121},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      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-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-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-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-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: [DONE]
 
@@ -47,15 +55,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 730.054792ms
+    duration: 828.859041ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50844
+    content_length: 51045
     host: ""

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

@@ -24,23 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1768830361-KnDZJcRrhDeKwzt90zgG","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830361,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":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":"Use","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830361-KnDZJcRrhDeKwzt90zgG","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830361,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":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":" multiedit to","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830361-KnDZJcRrhDeKwzt90zgG","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830361,"choices":[{"index":0,"delta":{"role":"assistant","content":"Use"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830361-KnDZJcRrhDeKwzt90zgG","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830361,"choices":[{"index":0,"delta":{"role":"assistant","content":" multiedit to"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830361-KnDZJcRrhDeKwzt90zgG","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830361,"choices":[{"index":0,"delta":{"role":"assistant","content":" update greeting"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830361-KnDZJcRrhDeKwzt90zgG","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830361,"choices":[{"index":0,"delta":{"role":"assistant","content":" and add comment in"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830361-KnDZJcRrhDeKwzt90zgG","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830361,"choices":[{"index":0,"delta":{"role":"assistant","content":" main.go"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1768830361-KnDZJcRrhDeKwzt90zgG","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830361,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
-
-      data: {"id":"gen-1768830361-KnDZJcRrhDeKwzt90zgG","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830361,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":160,"completion_tokens":14,"total_tokens":174,"cost":0.0000298,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000144,"upstream_inference_completions_cost":0.0000154},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      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: [DONE]
 
@@ -49,15 +45,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 239.99125ms
+    duration: 890.058625ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50922
+    content_length: 51123
     host: ""

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

@@ -24,21 +24,27 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1768830385-x9fwT8MATFhFKpxBh31a","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830385,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":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":"Find","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830385-x9fwT8MATFhFKpxBh31a","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830385,"choices":[{"index":0,"delta":{"role":"assistant","content":"Find"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":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":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830385-x9fwT8MATFhFKpxBh31a","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830385,"choices":[{"index":0,"delta":{"role":"assistant","content":" .go files and"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":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-1768830385-x9fwT8MATFhFKpxBh31a","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830385,"choices":[{"index":0,"delta":{"role":"assistant","content":" list directory"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":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-1768830385-x9fwT8MATFhFKpxBh31a","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830385,"choices":[{"index":0,"delta":{"role":"assistant","content":" in"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":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-1768830385-x9fwT8MATFhFKpxBh31a","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830385,"choices":[{"index":0,"delta":{"role":"assistant","content":" parallel"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":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-1768830385-x9fwT8MATFhFKpxBh31a","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830385,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}],"system_fingerprint":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-1768830385-x9fwT8MATFhFKpxBh31a","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830385,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":160,"completion_tokens":9,"total_tokens":169,"cost":0.0000348,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.000024,"upstream_inference_completions_cost":0.0000108},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      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-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-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-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: [DONE]
 
@@ -47,15 +53,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 832.842584ms
+    duration: 785.290041ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50933
+    content_length: 51134
     host: ""

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

@@ -24,19 +24,17 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1768830283-jqcQ1UYtDnQXJSsQIqAv","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830283,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":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":"Read","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830283-jqcQ1UYtDnQXJSsQIqAv","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830283,"choices":[{"index":0,"delta":{"role":"assistant","content":"Read"},"finish_reason":null,"native_finish_reason":null,"logprobs":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":" the","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830283-jqcQ1UYtDnQXJSsQIqAv","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830283,"choices":[{"index":0,"delta":{"role":"assistant","content":" the"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830283-jqcQ1UYtDnQXJSsQIqAv","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830283,"choices":[{"index":0,"delta":{"role":"assistant","content":" go"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830283-jqcQ1UYtDnQXJSsQIqAv","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830283,"choices":[{"index":0,"delta":{"role":"assistant","content":" mod"},"finish_reason":null,"native_finish_reason":null,"logprobs":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":"","role":"assistant"},"finish_reason":"stop","native_finish_reason":"stop"}]}
 
-      data: {"id":"gen-1768830283-jqcQ1UYtDnQXJSsQIqAv","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830283,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
-
-      data: {"id":"gen-1768830283-jqcQ1UYtDnQXJSsQIqAv","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830283,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":131,"completion_tokens":5,"total_tokens":136,"cost":0.0000171,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000131,"upstream_inference_completions_cost":0.000004},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      data: {"id":"gen-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: [DONE]
 
@@ -45,15 +43,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 1.759914166s
+    duration: 1.141124667s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50806
+    content_length: 51007
     host: ""

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

@@ -24,13 +24,11 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1768830280-4PCDv2pnxJ4GGNJaNBDx","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830280,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      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}]}
 
-      data: {"id":"gen-1768830280-4PCDv2pnxJ4GGNJaNBDx","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830280,"choices":[{"index":0,"delta":{"role":"assistant","content":"Hello"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
+      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"}]}
 
-      data: {"id":"gen-1768830280-4PCDv2pnxJ4GGNJaNBDx","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830280,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
-
-      data: {"id":"gen-1768830280-4PCDv2pnxJ4GGNJaNBDx","provider":"Chutes","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830280,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":128,"completion_tokens":2,"total_tokens":130,"cost":0.0000144,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.0000128,"upstream_inference_completions_cost":0.0000016},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      data: {"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: [DONE]
 
@@ -39,15 +37,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 1.783372292s
+    duration: 1.422850834s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50796
+    content_length: 50997
     host: ""

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

@@ -24,21 +24,17 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1768830290-g9cszM7AWBXcykR0NTwS","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830290,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":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":"Update","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830290-g9cszM7AWBXcykR0NTwS","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830290,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":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":" main.go to print","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830290-g9cszM7AWBXcykR0NTwS","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830290,"choices":[{"index":0,"delta":{"role":"assistant","content":"Update"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830290-g9cszM7AWBXcykR0NTwS","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830290,"choices":[{"index":0,"delta":{"role":"assistant","content":" main.go to print"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830290-g9cszM7AWBXcykR0NTwS","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830290,"choices":[{"index":0,"delta":{"role":"assistant","content":" hello"},"finish_reason":null,"native_finish_reason":null,"logprobs":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-1768830290-g9cszM7AWBXcykR0NTwS","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830290,"choices":[{"index":0,"delta":{"role":"assistant","content":" from crush"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
-
-      data: {"id":"gen-1768830290-g9cszM7AWBXcykR0NTwS","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830290,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
-
-      data: {"id":"gen-1768830290-g9cszM7AWBXcykR0NTwS","provider":"DeepInfra","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830290,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":141,"completion_tokens":9,"total_tokens":150,"cost":0.00002259,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.00001269,"upstream_inference_completions_cost":0.0000099},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      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: [DONE]
 
@@ -47,15 +43,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 982.306417ms
+    duration: 667.790583ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50862
+    content_length: 51063
     host: ""

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

@@ -24,17 +24,17 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"gen-1768830376-47Lo1VDfcxY5VPrlmIsL","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830376,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":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":"Create","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830376-47Lo1VDfcxY5VPrlmIsL","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830376,"choices":[{"index":0,"delta":{"role":"assistant","content":"Create"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":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":" config.json with sample","role":"assistant"},"finish_reason":null,"native_finish_reason":null}]}
 
-      data: {"id":"gen-1768830376-47Lo1VDfcxY5VPrlmIsL","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830376,"choices":[{"index":0,"delta":{"role":"assistant","content":" config.json with test"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":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-1768830376-47Lo1VDfcxY5VPrlmIsL","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830376,"choices":[{"index":0,"delta":{"role":"assistant","content":" data"},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"system_fingerprint":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-1768830376-47Lo1VDfcxY5VPrlmIsL","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830376,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}],"system_fingerprint":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-1768830376-47Lo1VDfcxY5VPrlmIsL","provider":"Alibaba","model":"qwen/qwen3-next-80b-a3b-instruct","object":"chat.completion.chunk","created":1768830376,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":159,"completion_tokens":6,"total_tokens":165,"cost":0.00003105,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.00002385,"upstream_inference_completions_cost":0.0000072},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}
+      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: [DONE]
 
@@ -43,15 +43,15 @@ interactions:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 401.234708ms
+    duration: 1.003629375s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50899
+    content_length: 51100
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/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://api.z.ai/api/coding/paas/v4/chat/completions
     method: POST
   response:
@@ -24,21 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20260119214720f5bafbb053254ba2","created":1768830440,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"20260119214720f5bafbb053254ba2","created":1768830440,"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":"Creating"}}]}
 
-      data: {"id":"20260119214720f5bafbb053254ba2","created":1768830440,"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":" test"}}]}
 
-      data: {"id":"20260119214720f5bafbb053254ba2","created":1768830440,"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":".txt"}}]}
 
-      data: {"id":"20260119214720f5bafbb053254ba2","created":1768830440,"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":" with"}}]}
 
-      data: {"id":"20260119214720f5bafbb053254ba2","created":1768830440,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" with"}}]}
+      data: {"id":"2026031304143176ff481eb8d34725","created":1773346471,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" bash"}}]}
 
-      data: {"id":"20260119214720f5bafbb053254ba2","created":1768830440,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" content"}}]}
+      data: {"id":"2026031304143176ff481eb8d34725","created":1773346471,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" content"}}]}
 
-      data: {"id":"20260119214720f5bafbb053254ba2","created":1768830440,"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":"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: [DONE]
 
@@ -47,22 +47,22 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.716247583s
+    duration: 627.333917ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50723
+    content_length: 50924
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/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://api.z.ai/api/coding/paas/v4/chat/completions
     method: POST
   response:
@@ -24,19 +24,19 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20260119214746ff0f57f2dd6f4a3c","created":1768830466,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"20260119214746ff0f57f2dd6f4a3c","created":1768830466,"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":"Download"}}]}
 
-      data: {"id":"20260119214746ff0f57f2dd6f4a3c","created":1768830466,"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":" example"}}]}
 
-      data: {"id":"20260119214746ff0f57f2dd6f4a3c","created":1768830466,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" as"}}]}
+      data: {"id":"20260313041436a1f83a7f81b64392","created":1773346476,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".txt"}}]}
 
-      data: {"id":"20260119214746ff0f57f2dd6f4a3c","created":1768830466,"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":"20260119214746ff0f57f2dd6f4a3c","created":1768830466,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".txt"}}]}
+      data: {"id":"20260313041436a1f83a7f81b64392","created":1773346476,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" URL"}}]}
 
-      data: {"id":"20260119214746ff0f57f2dd6f4a3c","created":1768830466,"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":"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: [DONE]
 
@@ -45,22 +45,22 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.298214334s
+    duration: 687.490875ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50748
+    content_length: 50949
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/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://api.z.ai/api/coding/paas/v4/chat/completions
     method: POST
   response:
@@ -24,19 +24,23 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"2026011921475024193c5bdb7a439a","created":1768830470,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"2026011921475024193c5bdb7a439a","created":1768830470,"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":"Check"}}]}
 
-      data: {"id":"2026011921475024193c5bdb7a439a","created":1768830470,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" HTML"}}]}
+      data: {"id":"20260313041457b8e4f6c46e7c468d","created":1773346497,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" for"}}]}
 
-      data: {"id":"2026011921475024193c5bdb7a439a","created":1768830470,"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":" John"}}]}
 
-      data: {"id":"2026011921475024193c5bdb7a439a","created":1768830470,"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":" Doe"}}]}
 
-      data: {"id":"2026011921475024193c5bdb7a439a","created":1768830470,"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,"delta":{"role":"assistant","content":" in"}}]}
 
-      data: {"id":"2026011921475024193c5bdb7a439a","created":1768830470,"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":114}}}
+      data: {"id":"20260313041457b8e4f6c46e7c468d","created":1773346497,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" HTML"}}]}
+
+      data: {"id":"20260313041457b8e4f6c46e7c468d","created":1773346497,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" content"}}]}
+
+      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: [DONE]
 
@@ -45,22 +49,22 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 2.103121375s
+    duration: 653.304417ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50766
+    content_length: 50967
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/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://api.z.ai/api/coding/paas/v4/chat/completions
     method: POST
   response:
@@ -24,17 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"2026011921480674cd894f317040ff","created":1768830486,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"2026011921480674cd894f317040ff","created":1768830486,"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":"Find"}}]}
 
-      data: {"id":"2026011921480674cd894f317040ff","created":1768830486,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" find"}}]}
+      data: {"id":"202603130415039728beb3b5dc461d","created":1773346503,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" all"}}]}
 
-      data: {"id":"2026011921480674cd894f317040ff","created":1768830486,"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":" Go"}}]}
 
-      data: {"id":"2026011921480674cd894f317040ff","created":1768830486,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" files"}}]}
+      data: {"id":"202603130415039728beb3b5dc461d","created":1773346503,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" files"}}]}
 
-      data: {"id":"2026011921480674cd894f317040ff","created":1768830486,"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":8,"total_tokens":140,"prompt_tokens_details":{"cached_tokens":4}}}
+      data: {"id":"202603130415039728beb3b5dc461d","created":1773346503,"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":" 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: [DONE]
 
@@ -43,22 +47,22 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.183180875s
+    duration: 692.47975ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50684
+    content_length: 50885
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/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://api.z.ai/api/coding/paas/v4/chat/completions
     method: POST
   response:
@@ -24,19 +24,17 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20260119214825c9d8845a1ce84ef4","created":1768830505,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"20260119214825c9d8845a1ce84ef4","created":1768830505,"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":"List"}}]}
 
-      data: {"id":"20260119214825c9d8845a1ce84ef4","created":1768830505,"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":" Files"}}]}
 
-      data: {"id":"20260119214825c9d8845a1ce84ef4","created":1768830505,"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":" with"}}]}
 
-      data: {"id":"20260119214825c9d8845a1ce84ef4","created":1768830505,"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,"delta":{"role":"assistant","content":" ls"}}]}
 
-      data: {"id":"20260119214825c9d8845a1ce84ef4","created":1768830505,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" command"}}]}
-
-      data: {"id":"20260119214825c9d8845a1ce84ef4","created":1768830505,"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":4}}}
+      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: [DONE]
 
@@ -45,22 +43,22 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.619916917s
+    duration: 650.921958ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50676
+    content_length: 50877
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/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://api.z.ai/api/coding/paas/v4/chat/completions
     method: POST
   response:
@@ -24,25 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20260119214830f5b9b304dd864346","created":1768830510,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"20260119214830f5b9b304dd864346","created":1768830510,"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":"Mult"}}]}
 
-      data: {"id":"20260119214830f5b9b304dd864346","created":1768830510,"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":"ied"}}]}
 
-      data: {"id":"20260119214830f5b9b304dd864346","created":1768830510,"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":"it"}}]}
 
-      data: {"id":"20260119214830f5b9b304dd864346","created":1768830510,"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":" Go"}}]}
 
-      data: {"id":"20260119214830f5b9b304dd864346","created":1768830510,"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,"delta":{"role":"assistant","content":" Code"}}]}
 
-      data: {"id":"20260119214830f5b9b304dd864346","created":1768830510,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":".go"}}]}
+      data: {"id":"2026031304151715bb72c64ce040ce","created":1773346517,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Modification"}}]}
 
-      data: {"id":"20260119214830f5b9b304dd864346","created":1768830510,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Title"}}]}
-
-      data: {"id":"20260119214830f5b9b304dd864346","created":1768830510,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Change"}}]}
-
-      data: {"id":"20260119214830f5b9b304dd864346","created":1768830510,"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: {"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: [DONE]
 
@@ -51,22 +47,22 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.904839708s
+    duration: 617.22425ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50762
+    content_length: 50963
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/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://api.z.ai/api/coding/paas/v4/chat/completions
     method: POST
   response:
@@ -24,23 +24,25 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"202601192148452cbea4d5a4814811","created":1768830525,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"202601192148452cbea4d5a4814811","created":1768830525,"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,"delta":{"role":"assistant","content":"Parallel"}}]}
 
-      data: {"id":"202601192148452cbea4d5a4814811","created":1768830525,"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":"202601192148452cbea4d5a4814811","created":1768830525,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" and"}}]}
+      data: {"id":"20260313041539bcf7d231fb614122","created":1773346539,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" and"}}]}
 
-      data: {"id":"202601192148452cbea4d5a4814811","created":1768830525,"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":" ls"}}]}
 
-      data: {"id":"202601192148452cbea4d5a4814811","created":1768830525,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" for"}}]}
+      data: {"id":"20260313041539bcf7d231fb614122","created":1773346539,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" commands"}}]}
 
-      data: {"id":"202601192148452cbea4d5a4814811","created":1768830525,"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":" for"}}]}
 
-      data: {"id":"202601192148452cbea4d5a4814811","created":1768830525,"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":" Go"}}]}
 
-      data: {"id":"202601192148452cbea4d5a4814811","created":1768830525,"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":11,"total_tokens":160,"prompt_tokens_details":{"cached_tokens":4}}}
+      data: {"id":"20260313041539bcf7d231fb614122","created":1773346539,"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,"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]
 
@@ -49,22 +51,22 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.2044225s
+    duration: 698.619667ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50773
+    content_length: 50974
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/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://api.z.ai/api/coding/paas/v4/chat/completions
     method: POST
   response:
@@ -24,15 +24,15 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20260119214656028e1a27796245c0","created":1768830416,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"20260119214656028e1a27796245c0","created":1768830416,"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,"delta":{"role":"assistant","content":"Go"}}]}
 
-      data: {"id":"20260119214656028e1a27796245c0","created":1768830416,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Module"}}]}
+      data: {"id":"20260313041419382e7728255d4003","created":1773346459,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" mod"}}]}
 
-      data: {"id":"20260119214656028e1a27796245c0","created":1768830416,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Summary"}}]}
+      data: {"id":"20260313041419382e7728255d4003","created":1773346459,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" reading"}}]}
 
-      data: {"id":"20260119214656028e1a27796245c0","created":1768830416,"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":"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: [DONE]
 
@@ -41,22 +41,22 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.35162425s
+    duration: 751.460042ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50646
+    content_length: 50847
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/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://api.z.ai/api/coding/paas/v4/chat/completions
     method: POST
   response:
@@ -24,11 +24,13 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"2026011921463481193bf2b83c45e5","created":1768830394,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"2026011921463481193bf2b83c45e5","created":1768830394,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Hello"}}]}
+      data: {"id":"202603130414168ff3a068e783494c","created":1773346456,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"G"}}]}
 
-      data: {"id":"2026011921463481193bf2b83c45e5","created":1768830394,"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":5,"total_tokens":126,"prompt_tokens_details":{"cached_tokens":4}}}
+      data: {"id":"202603130414168ff3a068e783494c","created":1773346456,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"reeting"}}]}
+
+      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: [DONE]
 
@@ -37,22 +39,22 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.262129958s
+    duration: 1.762131625s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50636
+    content_length: 50837
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/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://api.z.ai/api/coding/paas/v4/chat/completions
     method: POST
   response:
@@ -24,19 +24,17 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20260119215657a528cbba8dc945c7","created":1768831017,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"20260119215657a528cbba8dc945c7","created":1768831017,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Source"}}]}
+      data: {"id":"202603130415283ca31ec31524434b","created":1773346528,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Go"}}]}
 
-      data: {"id":"20260119215657a528cbba8dc945c7","created":1768831017,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"graph"}}]}
+      data: {"id":"202603130415283ca31ec31524434b","created":1773346528,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" main"}}]}
 
-      data: {"id":"20260119215657a528cbba8dc945c7","created":1768831017,"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":" function"}}]}
 
-      data: {"id":"20260119215657a528cbba8dc945c7","created":1768831017,"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":"20260119215657a528cbba8dc945c7","created":1768831017,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" Search"}}]}
-
-      data: {"id":"20260119215657a528cbba8dc945c7","created":1768831017,"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":9,"total_tokens":142,"prompt_tokens_details":{"cached_tokens":4}}}
+      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: [DONE]
 
@@ -45,22 +43,22 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.964927833s
+    duration: 676.245916ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50696
+    content_length: 50897
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/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://api.z.ai/api/coding/paas/v4/chat/completions
     method: POST
   response:
@@ -24,17 +24,21 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"2026011921470892df6a623ba442e8","created":1768830428,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"2026011921470892df6a623ba442e8","created":1768830428,"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":"Update"}}]}
 
-      data: {"id":"2026011921470892df6a623ba442e8","created":1768830428,"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":" main"}}]}
 
-      data: {"id":"2026011921470892df6a623ba442e8","created":1768830428,"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":".go"}}]}
 
-      data: {"id":"2026011921470892df6a623ba442e8","created":1768830428,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" greeting"}}]}
+      data: {"id":"2026031304142637b25add063545df","created":1773346466,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":" to"}}]}
 
-      data: {"id":"2026011921470892df6a623ba442e8","created":1768830428,"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":8,"total_tokens":142,"prompt_tokens_details":{"cached_tokens":114}}}
+      data: {"id":"2026031304142637b25add063545df","created":1773346466,"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":"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: [DONE]
 
@@ -43,22 +47,22 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 2.524076791s
+    duration: 1.264043875s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50702
+    content_length: 50903
     host: ""

internal/agent/testdata/TestCoderAgent/zai-glm4.6/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://api.z.ai/api/coding/paas/v4/chat/completions
     method: POST
   response:
@@ -24,19 +24,23 @@ interactions:
     proto_minor: 0
     content_length: -1
     body: |+
-      data: {"id":"20260119214841d5e404cbb41f4b39","created":1768830521,"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","reasoning_content":"\n"}}]}
 
-      data: {"id":"20260119214841d5e404cbb41f4b39","created":1768830521,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Creating"}}]}
+      data: {"id":"202603130415354342f3e7fce041ac","created":1773346535,"object":"chat.completion.chunk","model":"glm-4.5-air","choices":[{"index":0,"delta":{"role":"assistant","content":"Creating"}}]}
 
-      data: {"id":"20260119214841d5e404cbb41f4b39","created":1768830521,"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":" config"}}]}
 
-      data: {"id":"20260119214841d5e404cbb41f4b39","created":1768830521,"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":".json"}}]}
 
-      data: {"id":"20260119214841d5e404cbb41f4b39","created":1768830521,"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":" file"}}]}
 
-      data: {"id":"20260119214841d5e404cbb41f4b39","created":1768830521,"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":" with"}}]}
 
-      data: {"id":"20260119214841d5e404cbb41f4b39","created":1768830521,"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: {"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: [DONE]
 
@@ -45,22 +49,22 @@ interactions:
       - text/event-stream;charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 990.550333ms
+    duration: 626.617ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 50739
+    content_length: 50940
     host: ""

internal/agent/tools/bash.go 🔗

@@ -20,17 +20,19 @@ import (
 )
 
 type BashParams struct {
-	Description     string `json:"description" description:"A brief description of what the command does, try to keep it under 30 characters or so"`
-	Command         string `json:"command" description:"The command to execute"`
-	WorkingDir      string `json:"working_dir,omitempty" description:"The working directory to execute the command in (defaults to current directory)"`
-	RunInBackground bool   `json:"run_in_background,omitempty" description:"Set to true (boolean) to run this command in the background. Use job_output to read the output later."`
+	Description         string `json:"description" description:"A brief description of what the command does, try to keep it under 30 characters or so"`
+	Command             string `json:"command" description:"The command to execute"`
+	WorkingDir          string `json:"working_dir,omitempty" description:"The working directory to execute the command in (defaults to current directory)"`
+	RunInBackground     bool   `json:"run_in_background,omitempty" description:"Set to true (boolean) to run this command in the background. Use job_output to read the output later."`
+	AutoBackgroundAfter int    `json:"auto_background_after,omitempty" description:"Seconds to wait before automatically moving the command to a background job (default: 60)"`
 }
 
 type BashPermissionsParams struct {
-	Description     string `json:"description"`
-	Command         string `json:"command"`
-	WorkingDir      string `json:"working_dir"`
-	RunInBackground bool   `json:"run_in_background"`
+	Description         string `json:"description"`
+	Command             string `json:"command"`
+	WorkingDir          string `json:"working_dir"`
+	RunInBackground     bool   `json:"run_in_background"`
+	AutoBackgroundAfter int    `json:"auto_background_after"`
 }
 
 type BashResponseMetadata struct {
@@ -46,9 +48,9 @@ type BashResponseMetadata struct {
 const (
 	BashToolName = "bash"
 
-	AutoBackgroundThreshold = 1 * time.Minute // Commands taking longer automatically become background jobs
-	MaxOutputLength         = 30000
-	BashNoOutput            = "no output"
+	DefaultAutoBackgroundAfter = 60 // Commands taking longer automatically become background jobs
+	MaxOutputLength            = 30000
+	BashNoOutput               = "no output"
 )
 
 //go:embed bash.tpl
@@ -303,7 +305,10 @@ func NewBashTool(permissions permission.Service, workingDir string, attribution
 			// Wait for either completion, auto-background threshold, or context cancellation
 			ticker := time.NewTicker(100 * time.Millisecond)
 			defer ticker.Stop()
-			timeout := time.After(AutoBackgroundThreshold)
+
+			autoBackgroundAfter := cmp.Or(params.AutoBackgroundAfter, DefaultAutoBackgroundAfter)
+			autoBackgroundThreshold := time.Duration(autoBackgroundAfter) * time.Second
+			timeout := time.After(autoBackgroundThreshold)
 
 			var stdout, stderr string
 			var done bool

internal/agent/tools/bash.tpl 🔗

@@ -10,7 +10,7 @@ Common shell builtins and core utils available on Windows.
 1. Directory Verification: If creating directories/files, use LS tool to verify parent exists
 2. Security Check: Banned commands ({{ .BannedCommands }}) return error - explain to user. Safe read-only commands execute without prompts
 3. Command Execution: Execute with proper quoting, capture output
-4. Auto-Background: Commands exceeding 1 minute automatically move to background and return shell ID
+4. Auto-Background: Commands exceeding 1 minute (default, configurable via `auto_background_after`) automatically move to background and return shell ID
 5. Output Processing: Truncate if exceeds {{ .MaxOutputLength }} characters
 6. Return Result: Include errors, metadata with <cwd></cwd> tags
 </execution_steps>

internal/agent/tools/bash_test.go 🔗

@@ -0,0 +1,103 @@
+package tools
+
+import (
+	"context"
+	"encoding/json"
+	"testing"
+
+	"charm.land/fantasy"
+	"github.com/charmbracelet/crush/internal/config"
+	"github.com/charmbracelet/crush/internal/permission"
+	"github.com/charmbracelet/crush/internal/pubsub"
+	"github.com/charmbracelet/crush/internal/shell"
+	"github.com/stretchr/testify/require"
+)
+
+type mockBashPermissionService struct {
+	*pubsub.Broker[permission.PermissionRequest]
+}
+
+func (m *mockBashPermissionService) Request(ctx context.Context, req permission.CreatePermissionRequest) (bool, error) {
+	return true, nil
+}
+
+func (m *mockBashPermissionService) Grant(req permission.PermissionRequest) {}
+
+func (m *mockBashPermissionService) Deny(req permission.PermissionRequest) {}
+
+func (m *mockBashPermissionService) GrantPersistent(req permission.PermissionRequest) {}
+
+func (m *mockBashPermissionService) AutoApproveSession(sessionID string) {}
+
+func (m *mockBashPermissionService) SetSkipRequests(skip bool) {}
+
+func (m *mockBashPermissionService) SkipRequests() bool {
+	return false
+}
+
+func (m *mockBashPermissionService) SubscribeNotifications(ctx context.Context) <-chan pubsub.Event[permission.PermissionNotification] {
+	return make(<-chan pubsub.Event[permission.PermissionNotification])
+}
+
+func TestBashTool_DefaultAutoBackgroundThreshold(t *testing.T) {
+	workingDir := t.TempDir()
+	tool := newBashToolForTest(workingDir)
+	ctx := context.WithValue(context.Background(), SessionIDContextKey, "test-session")
+
+	resp := runBashTool(t, tool, ctx, BashParams{
+		Description: "default threshold",
+		Command:     "echo done",
+	})
+
+	require.False(t, resp.IsError)
+	var meta BashResponseMetadata
+	require.NoError(t, json.Unmarshal([]byte(resp.Metadata), &meta))
+	require.False(t, meta.Background)
+	require.Empty(t, meta.ShellID)
+	require.Contains(t, meta.Output, "done")
+}
+
+func TestBashTool_CustomAutoBackgroundThreshold(t *testing.T) {
+	workingDir := t.TempDir()
+	tool := newBashToolForTest(workingDir)
+	ctx := context.WithValue(context.Background(), SessionIDContextKey, "test-session")
+
+	resp := runBashTool(t, tool, ctx, BashParams{
+		Description:         "custom threshold",
+		Command:             "sleep 1.5 && echo done",
+		AutoBackgroundAfter: 1,
+	})
+
+	require.False(t, resp.IsError)
+	var meta BashResponseMetadata
+	require.NoError(t, json.Unmarshal([]byte(resp.Metadata), &meta))
+	require.True(t, meta.Background)
+	require.NotEmpty(t, meta.ShellID)
+	require.Contains(t, resp.Content, "moved to background")
+
+	bgManager := shell.GetBackgroundShellManager()
+	require.NoError(t, bgManager.Kill(meta.ShellID))
+}
+
+func newBashToolForTest(workingDir string) fantasy.AgentTool {
+	permissions := &mockBashPermissionService{Broker: pubsub.NewBroker[permission.PermissionRequest]()}
+	attribution := &config.Attribution{TrailerStyle: config.TrailerStyleNone}
+	return NewBashTool(permissions, workingDir, attribution, "test-model")
+}
+
+func runBashTool(t *testing.T, tool fantasy.AgentTool, ctx context.Context, params BashParams) fantasy.ToolResponse {
+	t.Helper()
+
+	input, err := json.Marshal(params)
+	require.NoError(t, err)
+
+	call := fantasy.ToolCall{
+		ID:    "test-call",
+		Name:  BashToolName,
+		Input: string(input),
+	}
+
+	resp, err := tool.Run(ctx, call)
+	require.NoError(t, err)
+	return resp
+}

internal/cmd/root.go 🔗

@@ -18,6 +18,7 @@ import (
 	"time"
 
 	tea "charm.land/bubbletea/v2"
+	fang "charm.land/fang/v2"
 	"charm.land/lipgloss/v2"
 	"github.com/charmbracelet/colorprofile"
 	"github.com/charmbracelet/crush/internal/client"
@@ -29,7 +30,6 @@ import (
 	ui "github.com/charmbracelet/crush/internal/ui/model"
 	"github.com/charmbracelet/crush/internal/version"
 	"github.com/charmbracelet/crush/internal/workspace"
-	"github.com/charmbracelet/fang"
 	uv "github.com/charmbracelet/ultraviolet"
 	"github.com/charmbracelet/x/exp/charmtone"
 	"github.com/charmbracelet/x/term"
@@ -55,6 +55,7 @@ func init() {
 		schemaCmd,
 		loginCmd,
 		statsCmd,
+		sessionCmd,
 	)
 }
 

internal/cmd/session.go 🔗

@@ -0,0 +1,641 @@
+package cmd
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+	"os/exec"
+	"runtime"
+	"strings"
+	"syscall"
+	"time"
+
+	"charm.land/lipgloss/v2"
+	"github.com/charmbracelet/colorprofile"
+	"github.com/charmbracelet/crush/internal/config"
+	"github.com/charmbracelet/crush/internal/db"
+	"github.com/charmbracelet/crush/internal/message"
+	"github.com/charmbracelet/crush/internal/session"
+	"github.com/charmbracelet/crush/internal/ui/chat"
+	"github.com/charmbracelet/crush/internal/ui/styles"
+	"github.com/charmbracelet/x/ansi"
+	"github.com/charmbracelet/x/exp/charmtone"
+	"github.com/charmbracelet/x/term"
+	"github.com/spf13/cobra"
+)
+
+var sessionCmd = &cobra.Command{
+	Use:     "session",
+	Aliases: []string{"sessions"},
+	Short:   "Manage sessions",
+	Long:    "Manage Crush sessions. Agents can use --json for machine-readable output.",
+}
+
+var (
+	sessionListJSON   bool
+	sessionShowJSON   bool
+	sessionLastJSON   bool
+	sessionDeleteJSON bool
+	sessionRenameJSON bool
+)
+
+var sessionListCmd = &cobra.Command{
+	Use:     "list",
+	Aliases: []string{"ls"},
+	Short:   "List all sessions",
+	Long:    "List all sessions. Use --json for machine-readable output.",
+	RunE:    runSessionList,
+}
+
+var sessionShowCmd = &cobra.Command{
+	Use:   "show <id>",
+	Short: "Show session details",
+	Long:  "Show session details. Use --json for machine-readable output. ID can be a UUID, full hash, or hash prefix.",
+	Args:  cobra.ExactArgs(1),
+	RunE:  runSessionShow,
+}
+
+var sessionLastCmd = &cobra.Command{
+	Use:   "last",
+	Short: "Show most recent session",
+	Long:  "Show the last updated session. Use --json for machine-readable output.",
+	RunE:  runSessionLast,
+}
+
+var sessionDeleteCmd = &cobra.Command{
+	Use:     "delete <id>",
+	Aliases: []string{"rm"},
+	Short:   "Delete a session",
+	Long:    "Delete a session by ID. Use --json for machine-readable output. ID can be a UUID, full hash, or hash prefix.",
+	Args:    cobra.ExactArgs(1),
+	RunE:    runSessionDelete,
+}
+
+var sessionRenameCmd = &cobra.Command{
+	Use:   "rename <id> <title>",
+	Short: "Rename a session",
+	Long:  "Rename a session by ID. Use --json for machine-readable output. ID can be a UUID, full hash, or hash prefix.",
+	Args:  cobra.MinimumNArgs(2),
+	RunE:  runSessionRename,
+}
+
+func init() {
+	sessionListCmd.Flags().BoolVar(&sessionListJSON, "json", false, "output in JSON format")
+	sessionShowCmd.Flags().BoolVar(&sessionShowJSON, "json", false, "output in JSON format")
+	sessionLastCmd.Flags().BoolVar(&sessionLastJSON, "json", false, "output in JSON format")
+	sessionDeleteCmd.Flags().BoolVar(&sessionDeleteJSON, "json", false, "output in JSON format")
+	sessionRenameCmd.Flags().BoolVar(&sessionRenameJSON, "json", false, "output in JSON format")
+	sessionCmd.AddCommand(sessionListCmd)
+	sessionCmd.AddCommand(sessionShowCmd)
+	sessionCmd.AddCommand(sessionLastCmd)
+	sessionCmd.AddCommand(sessionDeleteCmd)
+	sessionCmd.AddCommand(sessionRenameCmd)
+}
+
+type sessionServices struct {
+	sessions session.Service
+	messages message.Service
+}
+
+func sessionSetup(cmd *cobra.Command) (context.Context, *sessionServices, func(), error) {
+	dataDir, _ := cmd.Flags().GetString("data-dir")
+	ctx := cmd.Context()
+
+	if dataDir == "" {
+		cfg, err := config.Init("", "", false)
+		if err != nil {
+			return nil, nil, nil, fmt.Errorf("failed to initialize config: %w", err)
+		}
+		dataDir = cfg.Config().Options.DataDirectory
+	}
+
+	conn, err := db.Connect(ctx, dataDir)
+	if err != nil {
+		return nil, nil, nil, fmt.Errorf("failed to connect to database: %w", err)
+	}
+
+	queries := db.New(conn)
+	svc := &sessionServices{
+		sessions: session.NewService(queries, conn),
+		messages: message.NewService(queries),
+	}
+	return ctx, svc, func() { conn.Close() }, nil
+}
+
+func runSessionList(cmd *cobra.Command, _ []string) error {
+	ctx, svc, cleanup, err := sessionSetup(cmd)
+	if err != nil {
+		return err
+	}
+	defer cleanup()
+
+	list, err := svc.sessions.List(ctx)
+	if err != nil {
+		return fmt.Errorf("failed to list sessions: %w", err)
+	}
+
+	if sessionListJSON {
+		out := cmd.OutOrStdout()
+		output := make([]sessionJSON, len(list))
+		for i, s := range list {
+			output[i] = sessionJSON{
+				ID:       session.HashID(s.ID),
+				UUID:     s.ID,
+				Title:    s.Title,
+				Created:  time.Unix(s.CreatedAt, 0).Format(time.RFC3339),
+				Modified: time.Unix(s.UpdatedAt, 0).Format(time.RFC3339),
+			}
+		}
+		enc := json.NewEncoder(out)
+		enc.SetEscapeHTML(false)
+		return enc.Encode(output)
+	}
+
+	w, cleanup, usingPager := sessionWriter(ctx, len(list))
+	defer cleanup()
+
+	hashStyle := lipgloss.NewStyle().Foreground(charmtone.Malibu)
+	dateStyle := lipgloss.NewStyle().Foreground(charmtone.Damson)
+
+	width := sessionOutputWidth
+	if tw, _, err := term.GetSize(os.Stdout.Fd()); err == nil && tw > 0 {
+		width = tw
+	}
+	// 7 (hash) + 1 (space) + 25 (RFC3339 date) + 1 (space) = 34 chars prefix.
+	titleWidth := width - 34
+	if titleWidth < 10 {
+		titleWidth = 10
+	}
+
+	var writeErr error
+	for _, s := range list {
+		hash := session.HashID(s.ID)[:7]
+		date := time.Unix(s.CreatedAt, 0).Format(time.RFC3339)
+		title := strings.ReplaceAll(s.Title, "\n", " ")
+		title = ansi.Truncate(title, titleWidth, "…")
+		_, writeErr = fmt.Fprintln(w, hashStyle.Render(hash), dateStyle.Render(date), title)
+		if writeErr != nil {
+			break
+		}
+	}
+	if writeErr != nil && usingPager && isBrokenPipe(writeErr) {
+		return nil
+	}
+	return writeErr
+}
+
+type sessionJSON struct {
+	ID       string `json:"id"`
+	UUID     string `json:"uuid"`
+	Title    string `json:"title"`
+	Created  string `json:"created"`
+	Modified string `json:"modified"`
+}
+
+type sessionMutationResult struct {
+	ID      string `json:"id"`
+	UUID    string `json:"uuid"`
+	Title   string `json:"title"`
+	Deleted bool   `json:"deleted,omitempty"`
+	Renamed bool   `json:"renamed,omitempty"`
+}
+
+// resolveSessionID resolves a session ID that can be a UUID, full hash, or hash prefix.
+// Returns an error if the prefix is ambiguous (matches multiple sessions).
+func resolveSessionID(ctx context.Context, svc session.Service, id string) (session.Session, error) {
+	// Try direct UUID lookup first
+	if s, err := svc.Get(ctx, id); err == nil {
+		return s, nil
+	}
+
+	// List all sessions and check for hash matches
+	sessions, err := svc.List(ctx)
+	if err != nil {
+		return session.Session{}, err
+	}
+
+	var matches []session.Session
+	for _, s := range sessions {
+		hash := session.HashID(s.ID)
+		if hash == id || strings.HasPrefix(hash, id) {
+			matches = append(matches, s)
+		}
+	}
+
+	if len(matches) == 0 {
+		return session.Session{}, fmt.Errorf("session not found: %s", id)
+	}
+
+	if len(matches) == 1 {
+		return matches[0], nil
+	}
+
+	// Ambiguous - show matches like Git does
+	var sb strings.Builder
+	fmt.Fprintf(&sb, "session ID '%s' is ambiguous. Matches:\n\n", id)
+	for _, m := range matches {
+		hash := session.HashID(m.ID)
+		created := time.Unix(m.CreatedAt, 0).Format("2006-01-02")
+		// Keep title on one line by replacing newlines with spaces, and truncate.
+		title := strings.ReplaceAll(m.Title, "\n", " ")
+		title = ansi.Truncate(title, 50, "…")
+		fmt.Fprintf(&sb, "  %s... %q (created %s)\n", hash[:12], title, created)
+	}
+	sb.WriteString("\nUse more characters or the full hash")
+	return session.Session{}, errors.New(sb.String())
+}
+
+func runSessionShow(cmd *cobra.Command, args []string) error {
+	ctx, svc, cleanup, err := sessionSetup(cmd)
+	if err != nil {
+		return err
+	}
+	defer cleanup()
+
+	sess, err := resolveSessionID(ctx, svc.sessions, args[0])
+	if err != nil {
+		return err
+	}
+
+	msgs, err := svc.messages.List(ctx, sess.ID)
+	if err != nil {
+		return fmt.Errorf("failed to list messages: %w", err)
+	}
+
+	msgPtrs := messagePtrs(msgs)
+	if sessionShowJSON {
+		return outputSessionJSON(cmd.OutOrStdout(), sess, msgPtrs)
+	}
+	return outputSessionHuman(ctx, sess, msgPtrs)
+}
+
+func runSessionDelete(cmd *cobra.Command, args []string) error {
+	ctx, svc, cleanup, err := sessionSetup(cmd)
+	if err != nil {
+		return err
+	}
+	defer cleanup()
+
+	sess, err := resolveSessionID(ctx, svc.sessions, args[0])
+	if err != nil {
+		return err
+	}
+
+	if err := svc.sessions.Delete(ctx, sess.ID); err != nil {
+		return fmt.Errorf("failed to delete session: %w", err)
+	}
+
+	out := cmd.OutOrStdout()
+	if sessionDeleteJSON {
+		enc := json.NewEncoder(out)
+		enc.SetEscapeHTML(false)
+		return enc.Encode(sessionMutationResult{
+			ID:      session.HashID(sess.ID),
+			UUID:    sess.ID,
+			Title:   sess.Title,
+			Deleted: true,
+		})
+	}
+
+	fmt.Fprintf(out, "Deleted session %s\n", session.HashID(sess.ID)[:12])
+	return nil
+}
+
+func runSessionRename(cmd *cobra.Command, args []string) error {
+	ctx, svc, cleanup, err := sessionSetup(cmd)
+	if err != nil {
+		return err
+	}
+	defer cleanup()
+
+	sess, err := resolveSessionID(ctx, svc.sessions, args[0])
+	if err != nil {
+		return err
+	}
+
+	newTitle := strings.Join(args[1:], " ")
+	if err := svc.sessions.Rename(ctx, sess.ID, newTitle); err != nil {
+		return fmt.Errorf("failed to rename session: %w", err)
+	}
+
+	out := cmd.OutOrStdout()
+	if sessionRenameJSON {
+		enc := json.NewEncoder(out)
+		enc.SetEscapeHTML(false)
+		return enc.Encode(sessionMutationResult{
+			ID:      session.HashID(sess.ID),
+			UUID:    sess.ID,
+			Title:   newTitle,
+			Renamed: true,
+		})
+	}
+
+	fmt.Fprintf(out, "Renamed session %s to %q\n", session.HashID(sess.ID)[:12], newTitle)
+	return nil
+}
+
+func runSessionLast(cmd *cobra.Command, _ []string) error {
+	ctx, svc, cleanup, err := sessionSetup(cmd)
+	if err != nil {
+		return err
+	}
+	defer cleanup()
+
+	list, err := svc.sessions.List(ctx)
+	if err != nil {
+		return fmt.Errorf("failed to list sessions: %w", err)
+	}
+
+	if len(list) == 0 {
+		return fmt.Errorf("no sessions found")
+	}
+
+	sess := list[0]
+
+	msgs, err := svc.messages.List(ctx, sess.ID)
+	if err != nil {
+		return fmt.Errorf("failed to list messages: %w", err)
+	}
+
+	msgPtrs := messagePtrs(msgs)
+	if sessionLastJSON {
+		return outputSessionJSON(cmd.OutOrStdout(), sess, msgPtrs)
+	}
+	return outputSessionHuman(ctx, sess, msgPtrs)
+}
+
+const (
+	sessionOutputWidth     = 80
+	sessionMaxContentWidth = 120
+)
+
+func messagePtrs(msgs []message.Message) []*message.Message {
+	ptrs := make([]*message.Message, len(msgs))
+	for i := range msgs {
+		ptrs[i] = &msgs[i]
+	}
+	return ptrs
+}
+
+func outputSessionJSON(w io.Writer, sess session.Session, msgs []*message.Message) error {
+	output := sessionShowOutput{
+		Meta: sessionShowMeta{
+			ID:               session.HashID(sess.ID),
+			UUID:             sess.ID,
+			Title:            sess.Title,
+			Created:          time.Unix(sess.CreatedAt, 0).Format(time.RFC3339),
+			Modified:         time.Unix(sess.UpdatedAt, 0).Format(time.RFC3339),
+			Cost:             sess.Cost,
+			PromptTokens:     sess.PromptTokens,
+			CompletionTokens: sess.CompletionTokens,
+			TotalTokens:      sess.PromptTokens + sess.CompletionTokens,
+		},
+		Messages: make([]sessionShowMessage, len(msgs)),
+	}
+
+	for i, msg := range msgs {
+		output.Messages[i] = sessionShowMessage{
+			ID:       msg.ID,
+			Role:     string(msg.Role),
+			Created:  time.Unix(msg.CreatedAt, 0).Format(time.RFC3339),
+			Model:    msg.Model,
+			Provider: msg.Provider,
+			Parts:    convertParts(msg.Parts),
+		}
+	}
+
+	enc := json.NewEncoder(w)
+	enc.SetEscapeHTML(false)
+	return enc.Encode(output)
+}
+
+func outputSessionHuman(ctx context.Context, sess session.Session, msgs []*message.Message) error {
+	sty := styles.DefaultStyles()
+	toolResults := chat.BuildToolResultMap(msgs)
+
+	width := sessionOutputWidth
+	if w, _, err := term.GetSize(os.Stdout.Fd()); err == nil && w > 0 {
+		width = w
+	}
+	contentWidth := min(width, sessionMaxContentWidth)
+
+	keyStyle := lipgloss.NewStyle().Foreground(charmtone.Damson)
+	valStyle := lipgloss.NewStyle().Foreground(charmtone.Malibu)
+
+	hash := session.HashID(sess.ID)[:12]
+	created := time.Unix(sess.CreatedAt, 0).Format("Mon Jan 2 15:04:05 2006 -0700")
+
+	// Render to buffer to determine actual height
+	var buf strings.Builder
+
+	fmt.Fprintln(&buf, keyStyle.Render("ID:    ")+valStyle.Render(hash))
+	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))
+	fmt.Fprintln(&buf)
+
+	first := true
+	for _, msg := range msgs {
+		items := chat.ExtractMessageItems(&sty, msg, toolResults)
+		for _, item := range items {
+			if !first {
+				fmt.Fprintln(&buf)
+			}
+			first = false
+			fmt.Fprintln(&buf, item.Render(contentWidth))
+		}
+	}
+	fmt.Fprintln(&buf)
+
+	contentHeight := strings.Count(buf.String(), "\n")
+	w, cleanup, usingPager := sessionWriter(ctx, contentHeight)
+	defer cleanup()
+
+	_, err := io.WriteString(w, buf.String())
+	// Ignore broken pipe errors when using a pager. This happens when the user
+	// exits the pager early (e.g., pressing 'q' in less), which closes the pipe
+	// and causes subsequent writes to fail. These errors are expected user behavior.
+	if err != nil && usingPager && isBrokenPipe(err) {
+		return nil
+	}
+	return err
+}
+
+func isBrokenPipe(err error) bool {
+	if err == nil {
+		return false
+	}
+	// Check for syscall.EPIPE (broken pipe)
+	if errors.Is(err, syscall.EPIPE) {
+		return true
+	}
+	// Also check for "broken pipe" in the error message
+	return strings.Contains(err.Error(), "broken pipe")
+}
+
+// sessionWriter returns a writer, cleanup function, and a bool indicating if a pager is used.
+// When the content fits within the terminal (or stdout is not a TTY), it returns
+// a colorprofile.Writer wrapping stdout. When content exceeds terminal height,
+// it starts a pager process (respecting $PAGER, defaulting to "less -R").
+func sessionWriter(ctx context.Context, contentHeight int) (io.Writer, func(), bool) {
+	// Use NewWriter which automatically detects TTY and strips ANSI when redirected
+	if runtime.GOOS == "windows" || !term.IsTerminal(os.Stdout.Fd()) {
+		return colorprofile.NewWriter(os.Stdout, os.Environ()), func() {}, false
+	}
+
+	_, termHeight, err := term.GetSize(os.Stdout.Fd())
+	if err != nil || contentHeight <= termHeight {
+		return colorprofile.NewWriter(os.Stdout, os.Environ()), func() {}, false
+	}
+
+	// Detect color profile from stderr since stdout is piped to the pager.
+	profile := colorprofile.Detect(os.Stderr, os.Environ())
+
+	pager := os.Getenv("PAGER")
+	if pager == "" {
+		pager = "less -R"
+	}
+
+	parts := strings.Fields(pager)
+	cmd := exec.CommandContext(ctx, parts[0], parts[1:]...) //nolint:gosec
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+
+	pipe, err := cmd.StdinPipe()
+	if err != nil {
+		return colorprofile.NewWriter(os.Stdout, os.Environ()), func() {}, false
+	}
+
+	if err := cmd.Start(); err != nil {
+		return colorprofile.NewWriter(os.Stdout, os.Environ()), func() {}, false
+	}
+
+	return &colorprofile.Writer{
+			Forward: pipe,
+			Profile: profile,
+		}, func() {
+			pipe.Close()
+			_ = cmd.Wait()
+		}, true
+}
+
+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"`
+}
+
+type sessionShowMessage struct {
+	ID       string            `json:"id"`
+	Role     string            `json:"role"`
+	Created  string            `json:"created"`
+	Model    string            `json:"model,omitempty"`
+	Provider string            `json:"provider,omitempty"`
+	Parts    []sessionShowPart `json:"parts"`
+}
+
+type sessionShowPart struct {
+	Type string `json:"type"`
+
+	// Text content
+	Text string `json:"text,omitempty"`
+
+	// Reasoning
+	Thinking   string `json:"thinking,omitempty"`
+	StartedAt  int64  `json:"started_at,omitempty"`
+	FinishedAt int64  `json:"finished_at,omitempty"`
+
+	// Tool call
+	ToolCallID string `json:"tool_call_id,omitempty"`
+	Name       string `json:"name,omitempty"`
+	Input      string `json:"input,omitempty"`
+
+	// Tool result
+	Content  string `json:"content,omitempty"`
+	IsError  bool   `json:"is_error,omitempty"`
+	MIMEType string `json:"mime_type,omitempty"`
+
+	// Binary
+	Size int64 `json:"size,omitempty"`
+
+	// Image URL
+	URL    string `json:"url,omitempty"`
+	Detail string `json:"detail,omitempty"`
+
+	// Finish
+	Reason string `json:"reason,omitempty"`
+	Time   int64  `json:"time,omitempty"`
+}
+
+func convertParts(parts []message.ContentPart) []sessionShowPart {
+	result := make([]sessionShowPart, 0, len(parts))
+	for _, part := range parts {
+		switch p := part.(type) {
+		case message.TextContent:
+			result = append(result, sessionShowPart{
+				Type: "text",
+				Text: p.Text,
+			})
+		case message.ReasoningContent:
+			result = append(result, sessionShowPart{
+				Type:       "reasoning",
+				Thinking:   p.Thinking,
+				StartedAt:  p.StartedAt,
+				FinishedAt: p.FinishedAt,
+			})
+		case message.ToolCall:
+			result = append(result, sessionShowPart{
+				Type:       "tool_call",
+				ToolCallID: p.ID,
+				Name:       p.Name,
+				Input:      p.Input,
+			})
+		case message.ToolResult:
+			result = append(result, sessionShowPart{
+				Type:       "tool_result",
+				ToolCallID: p.ToolCallID,
+				Name:       p.Name,
+				Content:    p.Content,
+				IsError:    p.IsError,
+				MIMEType:   p.MIMEType,
+			})
+		case message.BinaryContent:
+			result = append(result, sessionShowPart{
+				Type:     "binary",
+				MIMEType: p.MIMEType,
+				Size:     int64(len(p.Data)),
+			})
+		case message.ImageURLContent:
+			result = append(result, sessionShowPart{
+				Type:   "image_url",
+				URL:    p.URL,
+				Detail: p.Detail,
+			})
+		case message.Finish:
+			result = append(result, sessionShowPart{
+				Type:   "finish",
+				Reason: string(p.Reason),
+				Time:   p.Time,
+			})
+		default:
+			result = append(result, sessionShowPart{
+				Type: "unknown",
+			})
+		}
+	}
+	return result
+}
+
+type sessionShowOutput struct {
+	Meta     sessionShowMeta      `json:"meta"`
+	Messages []sessionShowMessage `json:"messages"`
+}

internal/config/config.go 🔗

@@ -3,6 +3,7 @@ package config
 import (
 	"cmp"
 	"context"
+	"errors"
 	"fmt"
 	"log/slog"
 	"maps"
@@ -583,6 +584,14 @@ func (c *ProviderConfig) TestConnection(resolver VariableResolver) error {
 		baseURL, _ := resolver.ResolveValue(c.BaseURL)
 		baseURL = cmp.Or(baseURL, "https://generativelanguage.googleapis.com")
 		testURL = baseURL + "/v1beta/models?key=" + url.QueryEscape(apiKey)
+	case catwalk.TypeBedrock:
+		// NOTE: Bedrock has a `/foundation-models` endpoint that we could in
+		// theory use, but apparently the authorization is region-specific,
+		// so it's not so trivial.
+		if strings.HasPrefix(apiKey, "ABSK") { // Bedrock API keys
+			return nil
+		}
+		return errors.New("not a valid bedrock api key")
 	}
 
 	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)

internal/config/store.go 🔗

@@ -177,6 +177,15 @@ func (s *ConfigStore) SetCompactMode(scope Scope, enabled bool) error {
 	return s.SetConfigField(scope, "options.tui.compact_mode", enabled)
 }
 
+// SetTransparentBackground sets the transparent background setting and persists it.
+func (s *ConfigStore) SetTransparentBackground(scope Scope, enabled bool) error {
+	if s.config.Options == nil {
+		s.config.Options = &Options{}
+	}
+	s.config.Options.TUI.Transparent = &enabled
+	return s.SetConfigField(scope, "options.tui.transparent", enabled)
+}
+
 // SetProviderAPIKey sets the API key for a provider and persists it.
 func (s *ConfigStore) SetProviderAPIKey(scope Scope, providerID string, apiKey any) error {
 	var providerConfig ProviderConfig

internal/db/db.go 🔗

@@ -120,6 +120,9 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) {
 	if q.recordFileReadStmt, err = db.PrepareContext(ctx, recordFileRead); err != nil {
 		return nil, fmt.Errorf("error preparing query RecordFileRead: %w", err)
 	}
+	if q.renameSessionStmt, err = db.PrepareContext(ctx, renameSession); err != nil {
+		return nil, fmt.Errorf("error preparing query RenameSession: %w", err)
+	}
 	if q.updateMessageStmt, err = db.PrepareContext(ctx, updateMessage); err != nil {
 		return nil, fmt.Errorf("error preparing query UpdateMessage: %w", err)
 	}
@@ -294,6 +297,11 @@ func (q *Queries) Close() error {
 			err = fmt.Errorf("error closing recordFileReadStmt: %w", cerr)
 		}
 	}
+	if q.renameSessionStmt != nil {
+		if cerr := q.renameSessionStmt.Close(); cerr != nil {
+			err = fmt.Errorf("error closing renameSessionStmt: %w", cerr)
+		}
+	}
 	if q.updateMessageStmt != nil {
 		if cerr := q.updateMessageStmt.Close(); cerr != nil {
 			err = fmt.Errorf("error closing updateMessageStmt: %w", cerr)
@@ -380,6 +388,7 @@ type Queries struct {
 	listSessionsStmt               *sql.Stmt
 	listUserMessagesBySessionStmt  *sql.Stmt
 	recordFileReadStmt             *sql.Stmt
+	renameSessionStmt              *sql.Stmt
 	updateMessageStmt              *sql.Stmt
 	updateSessionStmt              *sql.Stmt
 	updateSessionTitleAndUsageStmt *sql.Stmt
@@ -421,6 +430,7 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries {
 		listSessionsStmt:               q.listSessionsStmt,
 		listUserMessagesBySessionStmt:  q.listUserMessagesBySessionStmt,
 		recordFileReadStmt:             q.recordFileReadStmt,
+		renameSessionStmt:              q.renameSessionStmt,
 		updateMessageStmt:              q.updateMessageStmt,
 		updateSessionStmt:              q.updateSessionStmt,
 		updateSessionTitleAndUsageStmt: q.updateSessionTitleAndUsageStmt,

internal/db/models.go 🔗

@@ -34,7 +34,7 @@ type Message struct {
 type ReadFile struct {
 	SessionID string `json:"session_id"`
 	Path      string `json:"path"`
-	ReadAt    int64  `json:"read_at"` // Unix timestamp when file was last read
+	ReadAt    int64  `json:"read_at"`
 }
 
 type Session struct {

internal/db/querier.go 🔗

@@ -41,6 +41,7 @@ type Querier interface {
 	ListSessions(ctx context.Context) ([]Session, error)
 	ListUserMessagesBySession(ctx context.Context, sessionID string) ([]Message, error)
 	RecordFileRead(ctx context.Context, arg RecordFileReadParams) error
+	RenameSession(ctx context.Context, arg RenameSessionParams) error
 	UpdateMessage(ctx context.Context, arg UpdateMessageParams) error
 	UpdateSession(ctx context.Context, arg UpdateSessionParams) (Session, error)
 	UpdateSessionTitleAndUsage(ctx context.Context, arg UpdateSessionTitleAndUsageParams) error

internal/db/read_files.sql.go 🔗

@@ -22,32 +22,10 @@ type GetFileReadParams struct {
 func (q *Queries) GetFileRead(ctx context.Context, arg GetFileReadParams) (ReadFile, error) {
 	row := q.queryRow(ctx, q.getFileReadStmt, getFileRead, arg.SessionID, arg.Path)
 	var i ReadFile
-	err := row.Scan(
-		&i.SessionID,
-		&i.Path,
-		&i.ReadAt,
-	)
+	err := row.Scan(&i.SessionID, &i.Path, &i.ReadAt)
 	return i, err
 }
 
-const recordFileRead = `-- name: RecordFileRead :exec
-INSERT INTO read_files (
-    session_id,
-    path,
-    read_at
-) VALUES (
-    ?,
-    ?,
-    strftime('%s', 'now')
-) ON CONFLICT(path, session_id) DO UPDATE SET
-    read_at = excluded.read_at
-`
-
-type RecordFileReadParams struct {
-	SessionID string `json:"session_id"`
-	Path      string `json:"path"`
-}
-
 const listSessionReadFiles = `-- name: ListSessionReadFiles :many
 SELECT session_id, path, read_at FROM read_files
 WHERE session_id = ?
@@ -63,11 +41,7 @@ func (q *Queries) ListSessionReadFiles(ctx context.Context, sessionID string) ([
 	items := []ReadFile{}
 	for rows.Next() {
 		var i ReadFile
-		if err := rows.Scan(
-			&i.SessionID,
-			&i.Path,
-			&i.ReadAt,
-		); err != nil {
+		if err := rows.Scan(&i.SessionID, &i.Path, &i.ReadAt); err != nil {
 			return nil, err
 		}
 		items = append(items, i)
@@ -81,10 +55,25 @@ func (q *Queries) ListSessionReadFiles(ctx context.Context, sessionID string) ([
 	return items, nil
 }
 
+const recordFileRead = `-- name: RecordFileRead :exec
+INSERT INTO read_files (
+    session_id,
+    path,
+    read_at
+) VALUES (
+    ?,
+    ?,
+    strftime('%s', 'now')
+) ON CONFLICT(path, session_id) DO UPDATE SET
+    read_at = excluded.read_at
+`
+
+type RecordFileReadParams struct {
+	SessionID string `json:"session_id"`
+	Path      string `json:"path"`
+}
+
 func (q *Queries) RecordFileRead(ctx context.Context, arg RecordFileReadParams) error {
-	_, err := q.exec(ctx, q.recordFileReadStmt, recordFileRead,
-		arg.SessionID,
-		arg.Path,
-	)
+	_, err := q.exec(ctx, q.recordFileReadStmt, recordFileRead, arg.SessionID, arg.Path)
 	return err
 }

internal/db/sessions.sql.go 🔗

@@ -150,6 +150,23 @@ func (q *Queries) ListSessions(ctx context.Context) ([]Session, error) {
 	return items, nil
 }
 
+const renameSession = `-- name: RenameSession :exec
+UPDATE sessions
+SET
+    title = ?
+WHERE id = ?
+`
+
+type RenameSessionParams struct {
+	Title string `json:"title"`
+	ID    string `json:"id"`
+}
+
+func (q *Queries) RenameSession(ctx context.Context, arg RenameSessionParams) error {
+	_, err := q.exec(ctx, q.renameSessionStmt, renameSession, arg.Title, arg.ID)
+	return err
+}
+
 const updateSession = `-- name: UpdateSession :one
 UPDATE sessions
 SET
@@ -206,7 +223,8 @@ SET
     title = ?,
     prompt_tokens = prompt_tokens + ?,
     completion_tokens = completion_tokens + ?,
-    cost = cost + ?
+    cost = cost + ?,
+    updated_at = strftime('%s', 'now')
 WHERE id = ?
 `
 

internal/db/sql/sessions.sql 🔗

@@ -52,10 +52,17 @@ SET
     title = ?,
     prompt_tokens = prompt_tokens + ?,
     completion_tokens = completion_tokens + ?,
-    cost = cost + ?
+    cost = cost + ?,
+    updated_at = strftime('%s', 'now')
 WHERE id = ?;
 
 
+-- name: RenameSession :exec
+UPDATE sessions
+SET
+    title = ?
+WHERE id = ?;
+
 -- name: DeleteSession :exec
 DELETE FROM sessions
 WHERE id = ?;

internal/session/session.go 🔗

@@ -12,6 +12,7 @@ import (
 	"github.com/charmbracelet/crush/internal/event"
 	"github.com/charmbracelet/crush/internal/pubsub"
 	"github.com/google/uuid"
+	"github.com/zeebo/xxh3"
 )
 
 type TodoStatus string
@@ -22,6 +23,13 @@ const (
 	TodoStatusCompleted  TodoStatus = "completed"
 )
 
+// HashID returns the XXH3 hash of a session ID (UUID) as a hex string.
+func HashID(id string) string {
+	h := xxh3.New()
+	h.WriteString(id)
+	return fmt.Sprintf("%x", h.Sum(nil))
+}
+
 type Todo struct {
 	Content    string     `json:"content"`
 	Status     TodoStatus `json:"status"`
@@ -61,6 +69,7 @@ type Service interface {
 	List(ctx context.Context) ([]Session, error)
 	Save(ctx context.Context, session Session) (Session, error)
 	UpdateTitleAndUsage(ctx context.Context, sessionID, title string, promptTokens, completionTokens int64, cost float64) error
+	Rename(ctx context.Context, id string, title string) error
 	Delete(ctx context.Context, id string) error
 
 	// Agent tool session management
@@ -198,6 +207,15 @@ func (s *service) UpdateTitleAndUsage(ctx context.Context, sessionID, title stri
 	})
 }
 
+// Rename updates only the title of a session without touching updated_at or
+// usage fields.
+func (s *service) Rename(ctx context.Context, id string, title string) error {
+	return s.q.RenameSession(ctx, db.RenameSessionParams{
+		ID:    id,
+		Title: title,
+	})
+}
+
 func (s *service) List(ctx context.Context) ([]Session, error) {
 	dbSessions, err := s.q.ListSessions(ctx)
 	if err != nil {

internal/ui/AGENTS.md 🔗

@@ -2,78 +2,198 @@
 
 ## General Guidelines
 
-- Never use commands to send messages when you can directly mutate children or state.
+- Never use commands to send messages when you can directly mutate children
+  or state.
 - Keep things simple; do not overcomplicate.
 - Create files if needed to separate logic; do not nest models.
 - Never do IO or expensive work in `Update`; always use a `tea.Cmd`.
-- Never change the model state inside of a command use messages and than update the state in the main loop
-- Use the `github.com/charmbracelet/x/ansi` package for any string manipulation
-  that might involves ANSI codes. Do not manipulate ANSI strings at byte level!
-  Some useful functions:
-  * `ansi.Cut`
-  * `ansi.StringWidth`
-  * `ansi.Strip`
-  * `ansi.Truncate`
-
+- Never change the model state inside of a command. Use messages and update
+  the state in the main `Update` loop.
+- Use the `github.com/charmbracelet/x/ansi` package for any string
+  manipulation that might involve ANSI codes. Do not manipulate ANSI strings
+  at byte level! Some useful functions:
+  - `ansi.Cut`
+  - `ansi.StringWidth`
+  - `ansi.Strip`
+  - `ansi.Truncate`
 
 ## Architecture
 
+### Rendering Pipeline
+
+The UI uses a **hybrid rendering** approach:
+
+1. **Screen-based (Ultraviolet)**: The top-level `UI` model creates a
+   `uv.ScreenBuffer`, and components draw into sub-regions using
+   `uv.NewStyledString(str).Draw(scr, rect)`. Layout is rectangle-based via
+   a `uiLayout` struct with fields like `layout.header`, `layout.main`,
+   `layout.editor`, `layout.sidebar`, `layout.pills`, `layout.status`.
+2. **String-based**: Sub-components like `list.List` and `completions` render
+   to strings, which are painted onto the screen buffer.
+3. **`View()`** creates the screen buffer, calls `Draw()`, then
+   `canvas.Render()` flattens it to a string for Bubble Tea.
+
 ### Main Model (`model/ui.go`)
 
-Keep most of the logic and state in the main model. This is where:
-- Message routing happens
+The `UI` struct is the top-level Bubble Tea model. Key fields:
+
+- `width`, `height` — terminal dimensions
+- `layout uiLayout` — computed layout rectangles
+- `state uiState` — `uiOnboarding | uiInitialize | uiLanding | uiChat`
+- `focus uiFocusState` — `uiFocusNone | uiFocusEditor | uiFocusMain`
+- `chat *Chat` — wraps `list.List` for the message view
+- `textarea textarea.Model` — the input editor
+- `dialog *dialog.Overlay` — stacked dialog system
+- `completions`, `attachments` — sub-components
+
+Keep most logic and state here. This is where:
+
+- Message routing happens (giant `switch msg.(type)` in `Update`)
 - Focus and UI state is managed
 - Layout calculations are performed
 - Dialogs are orchestrated
 
-### Components Should Be Dumb
+### Centralized Message Handling
+
+The `UI` model is the **sole Bubble Tea model**. Sub-components (`Chat`,
+`List`, `Attachments`, `Completions`, etc.) do not participate in the
+standard Elm architecture message loop. They are stateful structs with
+imperative methods that the main model calls directly:
+
+- **`Chat`** and **`List`** have no `Update` method at all. The main model
+  calls targeted methods like `HandleMouseDown()`, `ScrollBy()`,
+  `SetMessages()`, `Animate()`.
+- **`Attachments`** and **`Completions`** have non-standard `Update`
+  signatures (e.g., returning `bool` for "consumed") that act as guards, not
+  as full Bubble Tea models.
+- **Sidebar** is not its own model: it's a `drawSidebar()` method on `UI`.
+
+When writing new components, follow this pattern:
+
+- Expose imperative methods for state changes (not `Update(tea.Msg)`).
+- Return `tea.Cmd` from methods when side effects are needed.
+- Handle rendering via `Render(width int) string` or
+  `Draw(scr uv.Screen, area uv.Rectangle)`.
+- Let the main `UI.Update()` decide when and how to call into the component.
 
-Components should not handle bubbletea messages directly. Instead:
-- Expose methods for state changes
-- Return `tea.Cmd` from methods when side effects are needed
-- Handle their own rendering via `Render(width int) string`
+### Chat View (`model/chat.go`)
 
-### Chat Logic (`model/chat.go`)
+The `Chat` struct wraps a `list.List` with an ID-to-index map, mouse
+tracking (drag, double/triple click), animation management, and a `follow`
+flag for auto-scroll. It bridges screen-based and string-based rendering:
 
-Most chat-related logic belongs here. Individual chat items in `chat/` should be simple renderers that cache their output and invalidate when data changes (see `cachedMessageItem` in `chat/messages.go`).
+```go
+func (m *Chat) Draw(scr uv.Screen, area uv.Rectangle) {
+    uv.NewStyledString(m.list.Render()).Draw(scr, area)
+}
+```
+
+Individual chat items in `chat/` should be simple renderers that cache their
+output and invalidate when data changes (see `cachedMessageItem` in
+`chat/messages.go`).
 
 ## Key Patterns
 
 ### Composition Over Inheritance
 
-Use struct embedding for shared behaviors. See `chat/messages.go` for examples of reusable embedded structs for highlighting, caching, and focus.
+Use struct embedding for shared behaviors. See `chat/messages.go` for
+examples of reusable embedded structs for highlighting, caching, and focus.
+
+### Interface Hierarchy
+
+The chat message system uses layered interface composition:
+
+- **`list.Item`** — base: `Render(width int) string`
+- **`MessageItem`** — extends `list.Item` + `list.RawRenderable` +
+  `Identifiable`
+- **`ToolMessageItem`** — extends `MessageItem` with tool call/result/status
+  methods
+- **Opt-in capabilities**: `Focusable`, `Highlightable`, `Expandable`,
+  `Animatable`, `Compactable`, `KeyEventHandler`
+
+Key interface locations:
+
+- List item interfaces: `list/item.go`
+- Chat message interfaces: `chat/messages.go`
+- Tool message interfaces: `chat/tools.go`
+- Dialog interface: `dialog/dialog.go`
 
-### Interfaces
+### Tool Renderers
 
-- List item interfaces are in `list/item.go`
-- Chat message interfaces are in `chat/messages.go`
-- Dialog interface is in `dialog/dialog.go`
+Each tool has a dedicated renderer in `chat/`. The `ToolRenderer` interface
+requires:
+
+```go
+RenderTool(sty *styles.Styles, width int, opts *ToolRenderOpts) string
+```
+
+`NewToolMessageItem` in `chat/tools.go` is the central factory that routes
+tool names to specific types:
+
+| File                  | Tools rendered                                 |
+| --------------------- | ---------------------------------------------- |
+| `chat/bash.go`        | Bash, JobOutput, JobKill                       |
+| `chat/file.go`        | View, Write, Edit, MultiEdit, Download         |
+| `chat/search.go`      | Glob, Grep, LS, Sourcegraph                    |
+| `chat/fetch.go`       | Fetch, WebFetch, WebSearch                     |
+| `chat/agent.go`       | Agent, AgenticFetch                            |
+| `chat/diagnostics.go` | Diagnostics                                    |
+| `chat/references.go`  | References                                     |
+| `chat/lsp_restart.go` | LSPRestart                                     |
+| `chat/todos.go`       | Todos                                          |
+| `chat/mcp.go`         | MCP tools (`mcp_` prefix)                      |
+| `chat/generic.go`     | Fallback for unrecognized tools                |
+| `chat/assistant.go`   | Assistant messages (thinking, content, errors) |
+| `chat/user.go`        | User messages (input + attachments)            |
 
 ### Styling
 
-- All styles are defined in `styles/styles.go`
-- Access styles via `*common.Common` passed to components
-- Use semantic color fields rather than hardcoded colors
+- All styles are defined in `styles/styles.go` (massive `Styles` struct with
+  nested groups for Header, Pills, Dialog, Help, etc.).
+- Access styles via `*common.Common` passed to components.
+- Use semantic color fields rather than hardcoded colors.
 
 ### Dialogs
 
-- Implement the dialog interface in `dialog/dialog.go`
-- Return message types from `Update()` to signal actions to the main model
-- Use the overlay system for managing dialog lifecycle
+- Implement the `Dialog` interface in `dialog/dialog.go`:
+  `ID()`, `HandleMsg()` returning an `Action`, `Draw()` onto `uv.Screen`.
+- `Overlay` manages a stack of dialogs with push/pop/contains operations.
+- Dialogs draw last and overlay everything else.
+- Use `RenderContext` from `dialog/common.go` for consistent layout (title
+  gradients, width, gap, cursor offset helpers).
+
+### Shared Context
+
+The `common.Common` struct holds `*app.App` and `*styles.Styles`. Thread it
+through all components that need access to app state or styles.
 
 ## File Organization
 
-- `model/` - Main UI model and major components (chat, sidebar, etc.)
-- `chat/` - Chat message item types and renderers
-- `dialog/` - Dialog implementations
-- `list/` - Generic list component with lazy rendering
-- `common/` - Shared utilities and the Common struct
-- `styles/` - All style definitions
-- `anim/` - Animation system
-- `logo/` - Logo rendering
+- `model/` — Main UI model and major sub-models (chat, sidebar, header,
+  status, pills, session, onboarding, keys, etc.)
+- `chat/` — Chat message item types and tool renderers
+- `dialog/` — Dialog implementations (models, sessions, commands,
+  permissions, API key, OAuth, filepicker, reasoning, quit)
+- `list/` — Generic lazy-rendered scrollable list with viewport tracking
+- `common/` — Shared `Common` struct, layout helpers, markdown rendering,
+  diff rendering, scrollbar
+- `completions/` — Autocomplete popup with filterable list
+- `attachments/` — File attachment management
+- `styles/` — All style definitions, color tokens, icons
+- `diffview/` — Unified and split diff rendering with syntax highlighting
+- `anim/` — Animated spinnner
+- `image/` — Terminal image rendering (Kitty graphics)
+- `logo/` — Logo rendering
+- `util/` — Small shared utilities and message types
 
 ## Common Gotchas
 
-- Always account for padding/borders in width calculations
-- Use `tea.Batch()` when returning multiple commands
-- Pass `*common.Common` to components that need styles or app access
+- Always account for padding/borders in width calculations.
+- Use `tea.Batch()` when returning multiple commands.
+- Pass `*common.Common` to components that need styles or app access.
+- The `list.List` only renders visible items (lazy). No render cache exists
+  at the list level — items should cache internally if rendering is
+  expensive.
+- Dialog messages are intercepted first in `Update` before other routing.
+- Focus state determines key event routing: `uiFocusEditor` sends keys to
+  the textarea, `uiFocusMain` sends them to the chat list.

internal/ui/dialog/actions.go 🔗

@@ -44,19 +44,21 @@ type ActionSelectModel struct {
 
 // Messages for commands
 type (
-	ActionNewSession        struct{}
-	ActionToggleHelp        struct{}
-	ActionToggleCompactMode struct{}
-	ActionToggleThinking    struct{}
-	ActionTogglePills       struct{}
-	ActionExternalEditor    struct{}
-	ActionToggleYoloMode    struct{}
-	// ActionInitializeProject is a message to initialize a project.
-	ActionInitializeProject struct{}
-	ActionSummarize         struct {
+	ActionNewSession                  struct{}
+	ActionToggleHelp                  struct{}
+	ActionToggleCompactMode           struct{}
+	ActionToggleThinking              struct{}
+	ActionTogglePills                 struct{}
+	ActionExternalEditor              struct{}
+	ActionToggleYoloMode              struct{}
+	ActionToggleNotifications         struct{}
+	ActionToggleTransparentBackground struct{}
+	ActionInitializeProject           struct{}
+	ActionSummarize                   struct {
 		SessionID string
 	}
-	// ActionSelectReasoningEffort is a message indicating a reasoning effort has been selected.
+	// ActionSelectReasoningEffort is a message indicating a reasoning effort
+	// has been selected.
 	ActionSelectReasoningEffort struct {
 		Effort string
 	}

internal/ui/dialog/commands.go 🔗

@@ -427,9 +427,9 @@ func (c *Commands) defaultCommands() []*CommandItem {
 		commands = append(commands, NewCommandItem(c.com.Styles, "toggle_sidebar", "Toggle Sidebar", "", ActionToggleCompactMode{}))
 	}
 	if c.hasSession {
-		cfg := c.com.Config()
-		agentCfg := cfg.Agents[config.AgentCoder]
-		model := cfg.GetModelByType(agentCfg.Model)
+		cfgPrime := c.com.Config()
+		agentCfg := cfgPrime.Agents[config.AgentCoder]
+		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
@@ -437,8 +437,11 @@ func (c *Commands) defaultCommands() []*CommandItem {
 		}
 	}
 
-	// Add external editor command if $EDITOR is available
-	// TODO: Use [tea.EnvMsg] to get environment variable instead of os.Getenv
+	// Add external editor command if $EDITOR is available.
+	//
+	// TODO: Use [tea.EnvMsg] to get environment variable instead of os.Getenv;
+	// because os.Getenv does IO is breaks the TEA paradigm and is generally an
+	// antipattern.
 	if os.Getenv("EDITOR") != "" {
 		commands = append(commands, NewCommandItem(c.com.Styles, "open_external_editor", "Open External Editor", "ctrl+o", ActionExternalEditor{}))
 	}
@@ -456,10 +459,29 @@ func (c *Commands) defaultCommands() []*CommandItem {
 		commands = append(commands, NewCommandItem(c.com.Styles, "toggle_pills", label, "ctrl+t", ActionTogglePills{}))
 	}
 
+	// Add a command for toggling notifications.
+	cfg = c.com.Config()
+	notificationsDisabled := cfg != nil && cfg.Options != nil && cfg.Options.DisableNotifications
+	notificationLabel := "Disable Notifications"
+	if notificationsDisabled {
+		notificationLabel = "Enable Notifications"
+	}
+	commands = append(commands, NewCommandItem(c.com.Styles, "toggle_notifications", notificationLabel, "", ActionToggleNotifications{}))
+
 	commands = append(commands,
 		NewCommandItem(c.com.Styles, "toggle_yolo", "Toggle Yolo Mode", "", ActionToggleYoloMode{}),
 		NewCommandItem(c.com.Styles, "toggle_help", "Toggle Help", "ctrl+g", ActionToggleHelp{}),
 		NewCommandItem(c.com.Styles, "init", "Initialize Project", "", ActionInitializeProject{}),
+	)
+
+	// Add transparent background toggle.
+	transparentLabel := "Disable Background Color"
+	if cfg != nil && cfg.Options != nil && cfg.Options.TUI.Transparent != nil && *cfg.Options.TUI.Transparent {
+		transparentLabel = "Enable Background Color"
+	}
+	commands = append(commands, NewCommandItem(c.com.Styles, "toggle_transparent", transparentLabel, "", ActionToggleTransparentBackground{}))
+
+	commands = append(commands,
 		NewCommandItem(c.com.Styles, "quit", "Quit", "ctrl+c", tea.QuitMsg{}),
 	)
 

internal/ui/model/ui.go 🔗

@@ -1232,24 +1232,40 @@ func (m *UI) handleDialogMsg(msg tea.Msg) tea.Cmd {
 			cmds = append(cmds, msg.Cmd)
 		}
 
-	// Session dialog messages
+	// Session dialog messages.
 	case dialog.ActionSelectSession:
 		m.dialog.CloseDialog(dialog.SessionsID)
 		cmds = append(cmds, m.loadSession(msg.Session.ID))
 
-	// Open dialog message
+	// Open dialog message.
 	case dialog.ActionOpenDialog:
 		m.dialog.CloseDialog(dialog.CommandsID)
 		if cmd := m.openDialog(msg.DialogID); cmd != nil {
 			cmds = append(cmds, cmd)
 		}
 
-	// Command dialog messages
+	// Command dialog messages.
 	case dialog.ActionToggleYoloMode:
 		yolo := !m.com.Workspace.PermissionSkipRequests()
 		m.com.Workspace.PermissionSetSkipRequests(yolo)
 		m.setEditorPrompt(yolo)
 		m.dialog.CloseDialog(dialog.CommandsID)
+	case dialog.ActionToggleNotifications:
+		cfg := m.com.Config()
+		if cfg != nil && cfg.Options != nil {
+			disabled := !cfg.Options.DisableNotifications
+			cfg.Options.DisableNotifications = disabled
+			if err := m.com.Workspace.SetConfigField(config.ScopeGlobal, "options.disable_notifications", disabled); err != nil {
+				cmds = append(cmds, util.ReportError(err))
+			} else {
+				status := "enabled"
+				if disabled {
+					status = "disabled"
+				}
+				cmds = append(cmds, util.CmdHandler(util.NewInfoMsg("Notifications "+status)))
+			}
+		}
+		m.dialog.CloseDialog(dialog.CommandsID)
 	case dialog.ActionNewSession:
 		if m.isAgentBusy() {
 			cmds = append(cmds, util.ReportWarn("Agent is busy, please wait before starting a new session..."))
@@ -1315,6 +1331,27 @@ func (m *UI) handleDialogMsg(msg tea.Msg) tea.Cmd {
 			return util.NewInfoMsg("Thinking mode " + status)
 		})
 		m.dialog.CloseDialog(dialog.CommandsID)
+	case dialog.ActionToggleTransparentBackground:
+		cmds = append(cmds, func() tea.Msg {
+			cfg := m.com.Config()
+			if cfg == nil {
+				return util.ReportError(errors.New("configuration not found"))()
+			}
+
+			isTransparent := cfg.Options != nil && cfg.Options.TUI.Transparent != nil && *cfg.Options.TUI.Transparent
+			newValue := !isTransparent
+			if err := m.com.Workspace.SetConfigField(config.ScopeGlobal, "options.tui.transparent", newValue); err != nil {
+				return util.ReportError(err)()
+			}
+			m.isTransparent = newValue
+
+			status := "disabled"
+			if newValue {
+				status = "enabled"
+			}
+			return util.NewInfoMsg("Transparent background " + status)
+		})
+		m.dialog.CloseDialog(dialog.CommandsID)
 	case dialog.ActionQuit:
 		cmds = append(cmds, tea.Quit)
 	case dialog.ActionInitializeProject: