TestXMLToolCallFallback verifies that blocks in text content are extracted as tool calls and not leaked as AgentChoice events.
(t *testing.T)
| 502 | // TestXMLToolCallFallback verifies that <tool_call> blocks in text content |
| 503 | // are extracted as tool calls and not leaked as AgentChoice events. |
| 504 | func TestXMLToolCallFallback(t *testing.T) { |
| 505 | t.Parallel() |
| 506 | |
| 507 | xmlPayload := `<tool_call> |
| 508 | {"name": "shell_exec", "arguments": {"cmd": "ls -la"}} |
| 509 | </tool_call>` |
| 510 | |
| 511 | stream := newStreamBuilder(). |
| 512 | AddContent(xmlPayload). |
| 513 | AddStopWithUsage(10, 15). |
| 514 | Build() |
| 515 | |
| 516 | sess := session.New(session.WithUserMessage("list files")) |
| 517 | events := runSession(t, sess, stream) |
| 518 | |
| 519 | // The XML should be promoted to a PartialToolCall, not remain as plain text. |
| 520 | require.True(t, hasEventType(t, events, &PartialToolCallEvent{}), "Expected PartialToolCallEvent from XML extraction") |
| 521 | |
| 522 | // No raw XML should have been emitted as an AgentChoice event. |
| 523 | for _, ev := range events { |
| 524 | if choice, ok := ev.(*AgentChoiceEvent); ok { |
| 525 | require.NotContains(t, choice.Content, "<tool_call>", "XML tool call block must not appear in AgentChoice events") |
| 526 | } |
| 527 | } |
| 528 | |
| 529 | // Verify the extracted tool call fields. |
| 530 | for _, ev := range events { |
| 531 | if partial, ok := ev.(*PartialToolCallEvent); ok { |
| 532 | require.Equal(t, "shell_exec", partial.ToolCall.Function.Name) |
| 533 | require.JSONEq(t, `{"cmd": "ls -la"}`, partial.ToolCall.Function.Arguments) |
| 534 | } |
| 535 | } |
| 536 | } |
| 537 | |
| 538 | // TestXMLToolCallFallback_WithPreamble verifies that preamble text before a |
| 539 | // <tool_call> block is emitted as AgentChoice while the XML is suppressed. |
nothing calls this directly
no test coverage detected