mirror of
https://github.com/hwchase17/langchain.git
synced 2025-08-14 15:16:21 +00:00
fix
This commit is contained in:
parent
4dc3a39522
commit
de26f4966f
@ -35,6 +35,8 @@ from langchain_core.messages import convert_to_openai_data_block, is_data_conten
|
|||||||
from langchain_core.messages.ai import AIMessage, AIMessageChunk
|
from langchain_core.messages.ai import AIMessage, AIMessageChunk
|
||||||
from langchain_core.messages.base import BaseMessage, BaseMessageChunk
|
from langchain_core.messages.base import BaseMessage, BaseMessageChunk
|
||||||
from langchain_core.messages.chat import ChatMessage, ChatMessageChunk
|
from langchain_core.messages.chat import ChatMessage, ChatMessageChunk
|
||||||
|
from langchain_core.messages.content_blocks import ContentBlock
|
||||||
|
from langchain_core.messages.content_blocks import ToolCall as ToolCallV1
|
||||||
from langchain_core.messages.function import FunctionMessage, FunctionMessageChunk
|
from langchain_core.messages.function import FunctionMessage, FunctionMessageChunk
|
||||||
from langchain_core.messages.human import HumanMessage, HumanMessageChunk
|
from langchain_core.messages.human import HumanMessage, HumanMessageChunk
|
||||||
from langchain_core.messages.modifier import RemoveMessage
|
from langchain_core.messages.modifier import RemoveMessage
|
||||||
@ -43,7 +45,7 @@ from langchain_core.messages.tool import ToolCall, ToolMessage, ToolMessageChunk
|
|||||||
from langchain_core.v1.messages import AIMessage as AIMessageV1
|
from langchain_core.v1.messages import AIMessage as AIMessageV1
|
||||||
from langchain_core.v1.messages import AIMessageChunk as AIMessageChunkV1
|
from langchain_core.v1.messages import AIMessageChunk as AIMessageChunkV1
|
||||||
from langchain_core.v1.messages import HumanMessage as HumanMessageV1
|
from langchain_core.v1.messages import HumanMessage as HumanMessageV1
|
||||||
from langchain_core.v1.messages import MessageV1, MessageV1Types
|
from langchain_core.v1.messages import MessageV1, MessageV1Types, ResponseMetadata
|
||||||
from langchain_core.v1.messages import SystemMessage as SystemMessageV1
|
from langchain_core.v1.messages import SystemMessage as SystemMessageV1
|
||||||
from langchain_core.v1.messages import ToolMessage as ToolMessageV1
|
from langchain_core.v1.messages import ToolMessage as ToolMessageV1
|
||||||
|
|
||||||
@ -385,20 +387,28 @@ def convert_from_v1_message(message: MessageV1) -> BaseMessage:
|
|||||||
"""
|
"""
|
||||||
content = cast("Union[str, list[str | dict]]", message.content)
|
content = cast("Union[str, list[str | dict]]", message.content)
|
||||||
if isinstance(message, AIMessageV1):
|
if isinstance(message, AIMessageV1):
|
||||||
|
response_metadata: dict[str, Any] = {}
|
||||||
|
if message.response_metadata:
|
||||||
|
# Copy all fields from the v1 ResponseMetadata to a plain dict
|
||||||
|
response_metadata.update(message.response_metadata)
|
||||||
return AIMessage(
|
return AIMessage(
|
||||||
content=content,
|
content=content,
|
||||||
id=message.id,
|
id=message.id,
|
||||||
name=message.name,
|
name=message.name,
|
||||||
tool_calls=message.tool_calls,
|
tool_calls=message.tool_calls,
|
||||||
response_metadata=cast("dict", message.response_metadata),
|
response_metadata=response_metadata,
|
||||||
)
|
)
|
||||||
if isinstance(message, AIMessageChunkV1):
|
if isinstance(message, AIMessageChunkV1):
|
||||||
|
response_metadata_chunk: dict[str, Any] = {}
|
||||||
|
if message.response_metadata:
|
||||||
|
# Copy all fields from the v1 ResponseMetadata to a plain dict
|
||||||
|
response_metadata_chunk.update(message.response_metadata)
|
||||||
return AIMessageChunk(
|
return AIMessageChunk(
|
||||||
content=content,
|
content=content,
|
||||||
id=message.id,
|
id=message.id,
|
||||||
name=message.name,
|
name=message.name,
|
||||||
tool_call_chunks=message.tool_call_chunks,
|
tool_call_chunks=message.tool_call_chunks,
|
||||||
response_metadata=cast("dict", message.response_metadata),
|
response_metadata=response_metadata_chunk,
|
||||||
)
|
)
|
||||||
if isinstance(message, HumanMessageV1):
|
if isinstance(message, HumanMessageV1):
|
||||||
return HumanMessage(
|
return HumanMessage(
|
||||||
@ -481,6 +491,53 @@ def _convert_to_message(message: MessageLikeRepresentation) -> BaseMessage:
|
|||||||
return message_
|
return message_
|
||||||
|
|
||||||
|
|
||||||
|
def _convert_from_v0_to_v1(message: BaseMessage) -> MessageV1:
|
||||||
|
"""Convert a v0 message to a v1 message."""
|
||||||
|
from langchain_core.messages.content_blocks import create_text_block
|
||||||
|
|
||||||
|
if isinstance(message, HumanMessage): # Checking for v0 HumanMessage
|
||||||
|
content: list[ContentBlock] = [create_text_block(str(message.content))]
|
||||||
|
return HumanMessageV1(content, name=message.name)
|
||||||
|
if isinstance(message, AIMessage): # Checking for v0 AIMessage
|
||||||
|
content = [create_text_block(str(message.content))]
|
||||||
|
# Handle tool calls from v0 messages
|
||||||
|
if message.tool_calls:
|
||||||
|
for tool_call in message.tool_calls:
|
||||||
|
content.append(
|
||||||
|
ToolCallV1(
|
||||||
|
type="tool_call",
|
||||||
|
name=tool_call[
|
||||||
|
"name" # TODO: this is the name of the message, not the tool, so remove? # noqa: E501
|
||||||
|
],
|
||||||
|
args=tool_call["args"],
|
||||||
|
id=tool_call.get("id", ""),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Construct ResponseMetadata TypedDict from v0 response_metadata dict
|
||||||
|
# Since ResponseMetadata has total=False, we can safely cast the dict
|
||||||
|
response_metadata = cast("ResponseMetadata", message.response_metadata or {})
|
||||||
|
return AIMessageV1(
|
||||||
|
content=content,
|
||||||
|
name=message.name,
|
||||||
|
usage_metadata=message.usage_metadata,
|
||||||
|
response_metadata=response_metadata,
|
||||||
|
)
|
||||||
|
if isinstance(message, SystemMessage): # Checking for v0 SystemMessage
|
||||||
|
content = [create_text_block(str(message.content))]
|
||||||
|
return SystemMessageV1(content=content, name=message.name)
|
||||||
|
if isinstance(message, ToolMessage): # Checking for v0 ToolMessage
|
||||||
|
content = [create_text_block(str(message.content))]
|
||||||
|
return ToolMessageV1(
|
||||||
|
content=content,
|
||||||
|
name=message.name, # TODO: this is the name of the message, not the tool, so remove? # noqa: E501
|
||||||
|
tool_call_id=message.tool_call_id,
|
||||||
|
status=message.status,
|
||||||
|
)
|
||||||
|
msg = f"Unsupported v0 message type for conversion to v1: {type(message)}"
|
||||||
|
raise NotImplementedError(msg)
|
||||||
|
|
||||||
|
|
||||||
def _convert_to_message_v1(message: MessageLikeRepresentation) -> MessageV1:
|
def _convert_to_message_v1(message: MessageLikeRepresentation) -> MessageV1:
|
||||||
"""Instantiate a message from a variety of message formats.
|
"""Instantiate a message from a variety of message formats.
|
||||||
|
|
||||||
@ -507,6 +564,9 @@ def _convert_to_message_v1(message: MessageLikeRepresentation) -> MessageV1:
|
|||||||
message_: MessageV1 = message.to_message()
|
message_: MessageV1 = message.to_message()
|
||||||
else:
|
else:
|
||||||
message_ = message
|
message_ = message
|
||||||
|
elif isinstance(message, BaseMessage):
|
||||||
|
# Convert v0 messages to v1 messages
|
||||||
|
message_ = _convert_from_v0_to_v1(message)
|
||||||
elif isinstance(message, str):
|
elif isinstance(message, str):
|
||||||
message_ = _create_message_from_message_type_v1("human", message)
|
message_ = _create_message_from_message_type_v1("human", message)
|
||||||
elif isinstance(message, Sequence) and len(message) == 2:
|
elif isinstance(message, Sequence) and len(message) == 2:
|
||||||
@ -514,6 +574,31 @@ def _convert_to_message_v1(message: MessageLikeRepresentation) -> MessageV1:
|
|||||||
message_type_str, template = message # type: ignore[misc]
|
message_type_str, template = message # type: ignore[misc]
|
||||||
message_ = _create_message_from_message_type_v1(message_type_str, template)
|
message_ = _create_message_from_message_type_v1(message_type_str, template)
|
||||||
elif isinstance(message, dict):
|
elif isinstance(message, dict):
|
||||||
|
# Handle ToolCall content blocks passed as messages
|
||||||
|
if (
|
||||||
|
message.get("type") == "tool_call"
|
||||||
|
and "name" in message
|
||||||
|
and "args" in message
|
||||||
|
and "id" in message
|
||||||
|
and "content" not in message
|
||||||
|
):
|
||||||
|
# Convert ToolCall content block to an AIMessage with the tool call
|
||||||
|
from langchain_core.messages.content_blocks import (
|
||||||
|
ToolCall,
|
||||||
|
create_text_block,
|
||||||
|
)
|
||||||
|
from langchain_core.v1.messages import AIMessage
|
||||||
|
|
||||||
|
tool_call = ToolCall(
|
||||||
|
type="tool_call",
|
||||||
|
name=message[
|
||||||
|
"name"
|
||||||
|
], # TODO: revisit, this is the name of the message, not the tool
|
||||||
|
args=message["args"],
|
||||||
|
id=message["id"],
|
||||||
|
)
|
||||||
|
message_ = AIMessage(content=[create_text_block(""), tool_call])
|
||||||
|
else:
|
||||||
msg_kwargs = message.copy()
|
msg_kwargs = message.copy()
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
@ -523,7 +608,10 @@ def _convert_to_message_v1(message: MessageLikeRepresentation) -> MessageV1:
|
|||||||
# None msg content is not allowed
|
# None msg content is not allowed
|
||||||
msg_content = msg_kwargs.pop("content") or ""
|
msg_content = msg_kwargs.pop("content") or ""
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
msg = f"Message dict must contain 'role' and 'content' keys, got {message}"
|
msg = (
|
||||||
|
"Message dict must contain 'role' and 'content' "
|
||||||
|
f"keys, got {message}"
|
||||||
|
)
|
||||||
msg = create_message(
|
msg = create_message(
|
||||||
message=msg, error_code=ErrorCode.MESSAGE_COERCION_FAILURE
|
message=msg, error_code=ErrorCode.MESSAGE_COERCION_FAILURE
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user