|
8 | 8 | import pytest |
9 | 9 | from haystack import logging |
10 | 10 | from haystack.components.generators.utils import print_streaming_chunk |
11 | | -from haystack.dataclasses import ChatMessage, ChatRole, ImageContent, StreamingChunk |
| 11 | +from haystack.dataclasses import ChatMessage, ChatRole, ComponentInfo, ImageContent, StreamingChunk |
12 | 12 | from haystack.tools import Tool, Toolset |
13 | 13 | from haystack.utils import Secret |
14 | 14 |
|
@@ -522,6 +522,118 @@ def test_prepare_api_call_image_in_non_user_message(self, mock_watsonx): |
522 | 522 | with pytest.raises(ValueError, match="Image content is only supported for user messages"): |
523 | 523 | generator._prepare_api_call(messages=[message]) |
524 | 524 |
|
| 525 | + def test_convert_chunk_to_streaming_chunk_real_example( |
| 526 | + self, mock_watsonx: dict[str, AsyncMock | MagicMock] |
| 527 | + ) -> None: |
| 528 | + component = WatsonxChatGenerator( |
| 529 | + project_id=Secret.from_token("test-project"), model="meta-llama/llama-3-2-11b-vision-instruct" |
| 530 | + ) |
| 531 | + component_info = ComponentInfo.from_component(component) |
| 532 | + |
| 533 | + # Chunk 1: Text only |
| 534 | + chunk1 = { |
| 535 | + "id": "chatcmpl-21e72dd9-ed65-49cc-9ea2-64d971707cda---2dedc26eab5af753744ed4eaa116a197---e0399d75-cd8c-486e-b907-dc211cb70eac", # noqa: E501 |
| 536 | + "object": "chat.completion.chunk", |
| 537 | + "model_id": "meta-llama/llama-3-2-11b-vision-instruct", |
| 538 | + "model": "meta-llama/llama-3-2-11b-vision-instruct", |
| 539 | + "choices": [ |
| 540 | + { |
| 541 | + "index": 0, |
| 542 | + "finish_reason": None, |
| 543 | + "delta": {"content": "I'll get the weather information for Paris and Berlin"}, |
| 544 | + } |
| 545 | + ], |
| 546 | + "created": 1773250972, |
| 547 | + "model_version": "3.2.0", |
| 548 | + "created_at": "2026-03-11T17:42:52.921Z", |
| 549 | + } |
| 550 | + |
| 551 | + streaming_chunk1 = component._convert_chunk_to_streaming_chunk(chunk=chunk1, component_info=component_info) |
| 552 | + assert streaming_chunk1.content == "I'll get the weather information for Paris and Berlin" |
| 553 | + assert streaming_chunk1.tool_calls is None |
| 554 | + assert streaming_chunk1.finish_reason is None |
| 555 | + assert streaming_chunk1.index == 0 |
| 556 | + assert "created" in streaming_chunk1.meta |
| 557 | + assert "created_at" in streaming_chunk1.meta |
| 558 | + assert "received_at" in streaming_chunk1.meta |
| 559 | + assert streaming_chunk1.meta["model"] == "meta-llama/llama-3-2-11b-vision-instruct" |
| 560 | + assert streaming_chunk1.meta["model_id"] == "meta-llama/llama-3-2-11b-vision-instruct" |
| 561 | + assert streaming_chunk1.meta["model_version"] == "3.2.0" |
| 562 | + assert streaming_chunk1.component_info == component_info |
| 563 | + |
| 564 | + # Chunk 2: Text only |
| 565 | + chunk2 = { |
| 566 | + "id": "chatcmpl-21e72dd9-ed65-49cc-9ea2-64d971707cda---2dedc26eab5af753744ed4eaa116a197---e0399d75-cd8c-486e-b907-dc211cb70eac", # noqa: E501 |
| 567 | + "object": "chat.completion.chunk", |
| 568 | + "model_id": "meta-llama/llama-3-2-11b-vision-instruct", |
| 569 | + "model": "meta-llama/llama-3-2-11b-vision-instruct", |
| 570 | + "choices": [ |
| 571 | + {"index": 0, "finish_reason": None, "delta": {"content": " and present it in a structured format."}} |
| 572 | + ], |
| 573 | + "created": 1773250972, |
| 574 | + "model_version": "3.2.0", |
| 575 | + "created_at": "2026-03-11T17:42:52.929Z", |
| 576 | + } |
| 577 | + |
| 578 | + streaming_chunk2 = component._convert_chunk_to_streaming_chunk(chunk=chunk2, component_info=component_info) |
| 579 | + assert streaming_chunk2.content == " and present it in a structured format." |
| 580 | + assert streaming_chunk2.tool_calls is None |
| 581 | + assert streaming_chunk2.finish_reason is None |
| 582 | + assert streaming_chunk2.index == 0 |
| 583 | + assert "created" in streaming_chunk2.meta |
| 584 | + assert "created_at" in streaming_chunk2.meta |
| 585 | + assert "received_at" in streaming_chunk2.meta |
| 586 | + assert streaming_chunk2.meta["model"] == "meta-llama/llama-3-2-11b-vision-instruct" |
| 587 | + assert streaming_chunk2.meta["model_id"] == "meta-llama/llama-3-2-11b-vision-instruct" |
| 588 | + assert streaming_chunk2.meta["model_version"] == "3.2.0" |
| 589 | + assert streaming_chunk2.component_info == component_info |
| 590 | + |
| 591 | + # Chunk 3: Multiple tool calls (6 function calls) for 2 cities with 3 tools each |
| 592 | + chunk3 = { |
| 593 | + "id": "chatcmpl-6b615ca6-4aa7-4f79-832f-bedce4641c2b---87fdc1a1cd2032ff0c6776ecfc20b6a5---34576777-949d-4df1-b95f-56d14b848eca", # noqa: E501 |
| 594 | + "object": "chat.completion.chunk", |
| 595 | + "model_id": "meta-llama/llama-3-2-11b-vision-instruct", |
| 596 | + "model": "meta-llama/llama-3-2-11b-vision-instruct", |
| 597 | + "choices": [ |
| 598 | + { |
| 599 | + "index": 0, |
| 600 | + "finish_reason": None, |
| 601 | + "delta": { |
| 602 | + "tool_calls": [ |
| 603 | + { |
| 604 | + "index": 0, |
| 605 | + "id": "chatcmpl-tool-9646185282a54afc86c3572513b2dafa", |
| 606 | + "type": "function", |
| 607 | + "function": {"name": "weather", "arguments": ""}, |
| 608 | + } |
| 609 | + ] |
| 610 | + }, |
| 611 | + } |
| 612 | + ], |
| 613 | + "created": 1773252289, |
| 614 | + "model_version": "3.2.0", |
| 615 | + "created_at": "2026-03-11T18:04:49.696Z", |
| 616 | + } |
| 617 | + |
| 618 | + streaming_chunk3 = component._convert_chunk_to_streaming_chunk(chunk=chunk3, component_info=component_info) |
| 619 | + assert streaming_chunk3.content == "" |
| 620 | + assert streaming_chunk3.tool_calls is not None |
| 621 | + assert len(streaming_chunk3.tool_calls) == 1 |
| 622 | + assert streaming_chunk3.finish_reason is None |
| 623 | + assert streaming_chunk3.index == 0 |
| 624 | + assert "created" in streaming_chunk3.meta |
| 625 | + assert "created_at" in streaming_chunk3.meta |
| 626 | + assert "received_at" in streaming_chunk3.meta |
| 627 | + assert streaming_chunk3.meta["model"] == "meta-llama/llama-3-2-11b-vision-instruct" |
| 628 | + assert streaming_chunk3.meta["model_id"] == "meta-llama/llama-3-2-11b-vision-instruct" |
| 629 | + assert streaming_chunk3.meta["model_version"] == "3.2.0" |
| 630 | + assert streaming_chunk3.component_info == component_info |
| 631 | + |
| 632 | + assert streaming_chunk3.tool_calls[0].tool_name == "weather" |
| 633 | + assert streaming_chunk3.tool_calls[0].arguments == "" |
| 634 | + assert streaming_chunk3.tool_calls[0].id == "chatcmpl-tool-9646185282a54afc86c3572513b2dafa" |
| 635 | + assert streaming_chunk3.tool_calls[0].index == 0 |
| 636 | + |
525 | 637 | def test_multimodal_message_processing(self, mock_watsonx): |
526 | 638 | """Test multimodal message processing with mocked model.""" |
527 | 639 | base64_image = ( |
|
0 commit comments