carry over changes

This commit is contained in:
Chester Curme
2025-07-08 14:56:53 -04:00
parent 612ccf847a
commit 0d66cc2638
12 changed files with 1095 additions and 73 deletions

View File

@@ -311,6 +311,18 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
does not properly support streaming.
"""
output_version: str = "v0"
"""Version of AIMessage output format to use.
This field is used to roll-out new output formats for chat model AIMessages
in a backwards-compatible way.
All chat models currently support the default of ``"v0"``. Chat model subclasses
can override with (customizable) supported values.
.. versionadded:: 0.3.68
"""
@model_validator(mode="before")
@classmethod
def raise_deprecation(cls, values: dict) -> Any:

View File

@@ -33,6 +33,15 @@ if TYPE_CHECKING:
)
from langchain_core.messages.chat import ChatMessage, ChatMessageChunk
from langchain_core.messages.content_blocks import (
Base64ContentBlock,
ContentBlock,
DocumentCitation,
NonStandardAnnotation,
NonStandardContentBlock,
ReasoningContentBlock,
TextContentBlock,
ToolCallContentBlock,
UrlCitation,
convert_to_openai_data_block,
convert_to_openai_image_block,
is_data_content_block,
@@ -66,23 +75,32 @@ __all__ = (
"AIMessage",
"AIMessageChunk",
"AnyMessage",
"Base64ContentBlock",
"BaseMessage",
"BaseMessageChunk",
"ChatMessage",
"ChatMessageChunk",
"ContentBlock",
"DocumentCitation",
"FunctionMessage",
"FunctionMessageChunk",
"HumanMessage",
"HumanMessageChunk",
"InvalidToolCall",
"MessageLikeRepresentation",
"NonStandardAnnotation",
"NonStandardContentBlock",
"ReasoningContentBlock",
"RemoveMessage",
"SystemMessage",
"SystemMessageChunk",
"TextContentBlock",
"ToolCall",
"ToolCallChunk",
"ToolCallContentBlock",
"ToolMessage",
"ToolMessageChunk",
"UrlCitation",
"_message_from_dict",
"convert_to_messages",
"convert_to_openai_data_block",
@@ -103,25 +121,34 @@ __all__ = (
_dynamic_imports = {
"AIMessage": "ai",
"AIMessageChunk": "ai",
"Base64ContentBlock": "content_blocks",
"BaseMessage": "base",
"BaseMessageChunk": "base",
"merge_content": "base",
"message_to_dict": "base",
"messages_to_dict": "base",
"ContentBlock": "content_blocks",
"ChatMessage": "chat",
"ChatMessageChunk": "chat",
"DocumentCitation": "content_blocks",
"FunctionMessage": "function",
"FunctionMessageChunk": "function",
"HumanMessage": "human",
"HumanMessageChunk": "human",
"NonStandardAnnotation": "content_blocks",
"NonStandardContentBlock": "content_blocks",
"ReasoningContentBlock": "content_blocks",
"RemoveMessage": "modifier",
"SystemMessage": "system",
"SystemMessageChunk": "system",
"InvalidToolCall": "tool",
"TextContentBlock": "content_blocks",
"ToolCall": "tool",
"ToolCallChunk": "tool",
"ToolCallContentBlock": "content_blocks",
"ToolMessage": "tool",
"ToolMessageChunk": "tool",
"UrlCitation": "content_blocks",
"AnyMessage": "utils",
"MessageLikeRepresentation": "utils",
"_message_from_dict": "utils",

View File

@@ -7,6 +7,7 @@ from typing import TYPE_CHECKING, Any, Optional, Union, cast
from pydantic import ConfigDict, Field
from langchain_core.load.serializable import Serializable
from langchain_core.messages import ContentBlock
from langchain_core.utils import get_bolded_text
from langchain_core.utils._merge import merge_dicts, merge_lists
from langchain_core.utils.interactive_env import is_interactive_env
@@ -23,7 +24,7 @@ class BaseMessage(Serializable):
Messages are the inputs and outputs of ChatModels.
"""
content: Union[str, list[Union[str, dict]]]
content: Union[str, list[Union[str, ContentBlock, dict]]]
"""The string contents of the message."""
additional_kwargs: dict = Field(default_factory=dict)

View File

@@ -7,6 +7,93 @@ from pydantic import TypeAdapter, ValidationError
from typing_extensions import NotRequired, TypedDict
# Text and annotations
class UrlCitation(TypedDict, total=False):
"""Citation from a URL."""
type: Literal["url_citation"]
url: str
"""Source URL."""
title: NotRequired[str]
"""Source title."""
cited_text: NotRequired[str]
"""Text from the source that is being cited."""
start_index: NotRequired[int]
"""Start index of the response text for which the annotation applies."""
end_index: NotRequired[int]
"""End index of the response text for which the annotation applies."""
class DocumentCitation(TypedDict, total=False):
"""Annotation for data from a document."""
type: Literal["document_citation"]
title: NotRequired[str]
"""Source title."""
cited_text: NotRequired[str]
"""Text from the source that is being cited."""
start_index: NotRequired[int]
"""Start index of the response text for which the annotation applies."""
end_index: NotRequired[int]
"""End index of the response text for which the annotation applies."""
class NonStandardAnnotation(TypedDict, total=False):
"""Provider-specific annotation format."""
type: Literal["non_standard_annotation"]
"""Type of the content block."""
value: dict[str, Any]
"""Provider-specific annotation data."""
class TextContentBlock(TypedDict, total=False):
"""Content block for text output."""
type: Literal["text"]
"""Type of the content block."""
text: str
"""Block text."""
annotations: NotRequired[
list[Union[UrlCitation, DocumentCitation, NonStandardAnnotation]]
]
"""Citations and other annotations."""
# Tool calls
class ToolCallContentBlock(TypedDict, total=False):
"""Content block for tool calls.
These are references to a :class:`~langchain_core.messages.tool.ToolCall` in the
message's ``tool_calls`` attribute.
"""
type: Literal["tool_call"]
"""Type of the content block."""
id: str
"""Tool call ID."""
# Reasoning
class ReasoningContentBlock(TypedDict, total=False):
"""Content block for reasoning output."""
type: Literal["reasoning"]
"""Type of the content block."""
reasoning: NotRequired[str]
"""Reasoning text."""
# Multi-modal
class BaseDataContentBlock(TypedDict, total=False):
"""Base class for data content blocks."""
@@ -68,6 +155,28 @@ DataContentBlock = Union[
_DataContentBlockAdapter: TypeAdapter[DataContentBlock] = TypeAdapter(DataContentBlock)
# Non-standard
class NonStandardContentBlock(TypedDict, total=False):
"""Content block provider-specific data.
This block contains data for which there is not yet a standard type.
"""
type: Literal["non_standard"]
"""Type of the content block."""
value: dict[str, Any]
"""Provider-specific data."""
ContentBlock = Union[
TextContentBlock,
ToolCallContentBlock,
ReasoningContentBlock,
DataContentBlock,
NonStandardContentBlock,
]
def is_data_content_block(
content_block: dict,
) -> bool:

View File

@@ -300,8 +300,9 @@ def test_llm_representation_for_serializable() -> None:
assert chat._get_llm_string() == (
'{"id": ["tests", "unit_tests", "language_models", "chat_models", '
'"test_cache", "CustomChat"], "kwargs": {"messages": {"id": '
'["builtins", "list_iterator"], "lc": 1, "type": "not_implemented"}}, "lc": '
'1, "name": "CustomChat", "type": "constructor"}---[(\'stop\', None)]'
'["builtins", "list_iterator"], "lc": 1, "type": "not_implemented"}, '
'"output_version": "v0"}, "lc": 1, "name": "CustomChat", "type": '
"\"constructor\"}---[('stop', None)]"
)