From b1353f4f0f3c5a6eac7689b8f95e35a2e24e5f7c Mon Sep 17 00:00:00 2001 From: Ulises M <30765968+lbux@users.noreply.github.com> Date: Wed, 20 Nov 2024 11:07:04 -0800 Subject: [PATCH] fix: append runtime meta to ChatMessage's extracted meta in AnswerBuilder (#8544) * append runtime meta to extracted meta * add pylint ignore flag to .run() * explicitly convert reply to string --- .../components/builders/answer_builder.py | 11 ++-- ...eta_in_answerbuilder-4103b4ca4590aea5.yaml | 4 ++ .../builders/test_answer_builder.py | 52 +++++++++++++++++++ 3 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 releasenotes/notes/merge_runtime_meta_in_answerbuilder-4103b4ca4590aea5.yaml diff --git a/haystack/components/builders/answer_builder.py b/haystack/components/builders/answer_builder.py index 1577fb3e99..b89d506aec 100644 --- a/haystack/components/builders/answer_builder.py +++ b/haystack/components/builders/answer_builder.py @@ -58,7 +58,7 @@ def __init__(self, pattern: Optional[str] = None, reference_pattern: Optional[st self.reference_pattern = reference_pattern @component.output_types(answers=List[GeneratedAnswer]) - def run( + def run( # pylint: disable=too-many-positional-arguments self, query: str, replies: Union[List[str], List[ChatMessage]], @@ -111,10 +111,13 @@ def run( pattern = pattern or self.pattern reference_pattern = reference_pattern or self.reference_pattern all_answers = [] - for reply, metadata in zip(replies, meta): + for reply, given_metadata in zip(replies, meta): # Extract content from ChatMessage objects if reply is a ChatMessages, else use the string as is - extracted_reply: str = reply.content if isinstance(reply, ChatMessage) else reply # type: ignore - extracted_metadata = reply.meta if isinstance(reply, ChatMessage) else metadata + extracted_reply = reply.content if isinstance(reply, ChatMessage) else str(reply) + extracted_metadata = reply.meta if isinstance(reply, ChatMessage) else {} + + extracted_metadata = {**extracted_metadata, **given_metadata} + referenced_docs = [] if documents: if reference_pattern: diff --git a/releasenotes/notes/merge_runtime_meta_in_answerbuilder-4103b4ca4590aea5.yaml b/releasenotes/notes/merge_runtime_meta_in_answerbuilder-4103b4ca4590aea5.yaml new file mode 100644 index 0000000000..ceab3e07f6 --- /dev/null +++ b/releasenotes/notes/merge_runtime_meta_in_answerbuilder-4103b4ca4590aea5.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - | + When meta is passed into AnswerBuilder.run(), it is now merged into GeneratedAnswer meta diff --git a/test/components/builders/test_answer_builder.py b/test/components/builders/test_answer_builder.py index 46c40e3422..9c220ef477 100644 --- a/test/components/builders/test_answer_builder.py +++ b/test/components/builders/test_answer_builder.py @@ -36,6 +36,16 @@ def test_run_meta_is_an_empty_list(self): assert answers[0].documents == [] assert isinstance(answers[0], GeneratedAnswer) + def test_run_with_meta(self): + component = AnswerBuilder() + output = component.run(query="query", replies=["reply1"], meta=[{"test": "meta"}]) + answers = output["answers"] + assert answers[0].data == "reply1" + assert answers[0].meta == {"test": "meta"} + assert answers[0].query == "query" + assert answers[0].documents == [] + assert isinstance(answers[0], GeneratedAnswer) + def test_run_without_pattern(self): component = AnswerBuilder() output = component.run(query="test query", replies=["Answer: AnswerString"], meta=[{}]) @@ -272,3 +282,45 @@ def test_run_with_chat_message_replies_with_pattern_set_at_runtime(self): assert answers[0].query == "test query" assert answers[0].documents == [] assert isinstance(answers[0], GeneratedAnswer) + + def test_run_with_chat_message_replies_with_meta_set_at_run_time(self): + component = AnswerBuilder() + replies = [ + ChatMessage( + content="AnswerString", + role=ChatRole.ASSISTANT, + name=None, + meta={ + "model": "gpt-4o-mini", + "index": 0, + "finish_reason": "stop", + "usage": {"prompt_tokens": 32, "completion_tokens": 153, "total_tokens": 185}, + }, + ) + ] + output = component.run(query="test query", replies=replies, meta=[{"test": "meta"}]) + answers = output["answers"] + assert len(answers) == 1 + assert answers[0].data == "AnswerString" + assert answers[0].meta == { + "model": "gpt-4o-mini", + "index": 0, + "finish_reason": "stop", + "usage": {"prompt_tokens": 32, "completion_tokens": 153, "total_tokens": 185}, + "test": "meta", + } + assert answers[0].query == "test query" + assert answers[0].documents == [] + assert isinstance(answers[0], GeneratedAnswer) + + def test_run_with_chat_message_no_meta_with_meta_set_at_run_time(self): + component = AnswerBuilder() + replies = [ChatMessage(content="AnswerString", role=ChatRole.ASSISTANT, name=None, meta={})] + output = component.run(query="test query", replies=replies, meta=[{"test": "meta"}]) + answers = output["answers"] + assert len(answers) == 1 + assert answers[0].data == "AnswerString" + assert answers[0].meta == {"test": "meta"} + assert answers[0].query == "test query" + assert answers[0].documents == [] + assert isinstance(answers[0], GeneratedAnswer)