From e6862e6e7d657a0c52eabb10b155250e43d21159 Mon Sep 17 00:00:00 2001 From: Hendrik Hogertz Date: Sun, 3 Dec 2023 21:07:15 +0100 Subject: [PATCH] Fix Azure Openai function calling in streaming mode (#13768) - **Description**: This PR addresses an issue with the OpenAI API streaming response, where initially the key (arguments) is provided but the value is None. Subsequently, it updates with {"arguments": "{\n"}, leading to a type inconsistency that causes an exception. The specific error encountered is ValueError: additional_kwargs["arguments"] already exists in this message, but with a different type. This change aims to resolve this inconsistency and ensure smooth API interactions. - **Issue**: None. - **Dependencies**: None. - **Tag maintainer**: @eyurtsev This is an updated version of #13229 based on the refactored code. Credit goes to @superken01. Co-authored-by: Harrison Chase --- libs/core/langchain_core/messages/base.py | 12 +++++++++++- libs/core/tests/unit_tests/test_messages.py | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/libs/core/langchain_core/messages/base.py b/libs/core/langchain_core/messages/base.py index 1c2f97a1392..dd9d81a57a0 100644 --- a/libs/core/langchain_core/messages/base.py +++ b/libs/core/langchain_core/messages/base.py @@ -71,7 +71,17 @@ class BaseMessageChunk(BaseMessage): def _merge_kwargs_dict( self, left: Dict[str, Any], right: Dict[str, Any] ) -> Dict[str, Any]: - """Merge additional_kwargs from another BaseMessageChunk into this one.""" + """Merge additional_kwargs from another BaseMessageChunk into this one, + handling specific scenarios where a key exists in both dictionaries + but has a value of None in 'left'. In such cases, the method uses the + value from 'right' for that key in the merged dictionary. + Example: + If left = {"function_call": {"arguments": None}} and + right = {"function_call": {"arguments": "{\n"}} + then, after merging, for the key "function_call", + the value from 'right' is used, + resulting in merged = {"function_call": {"arguments": "{\n"}}. + """ merged = left.copy() for k, v in right.items(): if k not in merged: diff --git a/libs/core/tests/unit_tests/test_messages.py b/libs/core/tests/unit_tests/test_messages.py index cac2f5d2329..bcb8bc88ce4 100644 --- a/libs/core/tests/unit_tests/test_messages.py +++ b/libs/core/tests/unit_tests/test_messages.py @@ -42,6 +42,9 @@ def test_message_chunks() -> None: AIMessageChunk( content="", additional_kwargs={"function_call": {"name": "web_search"}} ) + + AIMessageChunk( + content="", additional_kwargs={"function_call": {"arguments": None}} + ) + AIMessageChunk( content="", additional_kwargs={"function_call": {"arguments": "{\n"}} )