TestChatToolCallLateIDPreserved: spec ships the tool_call `id` in the first fragment, but a sloppy provider may delay it. The client must update slot.id on any non-empty value (same forgiveness as `name`), else the id stays "" and the next /v1 request 400s on the unpaired tool message.
(t *testing.T)
| 269 | // on any non-empty value (same forgiveness as `name`), else the id stays "" and |
| 270 | // the next /v1 request 400s on the unpaired tool message. |
| 271 | func TestChatToolCallLateIDPreserved(t *testing.T) { |
| 272 | srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { |
| 273 | sseOK(w, []string{ |
| 274 | `{"choices":[{"delta":{"tool_calls":[{"index":0,"function":{"name":"bash"}}]}}]}`, |
| 275 | `{"choices":[{"delta":{"tool_calls":[{"index":0,"id":"call_late","function":{"arguments":"{\"cmd\":\"ls\"}"}}]}}]}`, |
| 276 | `{"choices":[{"delta":{},"finish_reason":"tool_calls"}]}`, |
| 277 | }) |
| 278 | })) |
| 279 | defer srv.Close() |
| 280 | c := New(srv.URL, "m", "") |
| 281 | var got *chmctx.ToolCall |
| 282 | for _, e := range collect(c.Chat(context.Background(), nil, nil)) { |
| 283 | if e.Kind == EventToolCall { |
| 284 | got = e.ToolCall |
| 285 | } |
| 286 | } |
| 287 | if got == nil { |
| 288 | t.Fatal("tool call event missing") |
| 289 | } |
| 290 | if got.ID != "call_late" { |
| 291 | t.Fatalf("late-arriving id lost: got %q, want %q", got.ID, "call_late") |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | // TestChatToolCallMalformedArgsPreservesMarker: on invalid `arguments` JSON |
| 296 | // (provider bug), the client surfaces a sentinel key rather than an empty args |