This commit is contained in:
Mason Daugherty
2025-08-18 15:54:53 -04:00
parent 3a78f4fef9
commit 2dfbcc5738
9 changed files with 189 additions and 185 deletions

View File

@@ -65,6 +65,7 @@ class InputTokenDetails(TypedDict, total=False):
Since there was a cache hit, the tokens were read from the cache. More precisely,
the model state given these tokens was read from the cache.
"""
@@ -92,6 +93,7 @@ class OutputTokenDetails(TypedDict, total=False):
Tokens generated by the model in a chain of thought process (i.e. by OpenAI's o1
models) that are not returned as part of model output.
"""
@@ -139,6 +141,7 @@ class UsageMetadata(TypedDict):
"""Breakdown of output token counts.
Does *not* need to sum to full output token count. Does *not* need to have all keys.
"""
@@ -150,12 +153,14 @@ class AIMessage(BaseMessage):
This message represents the output of the model and consists of both
the raw output as returned by the model together standardized fields
(e.g., tool calls, usage metadata) added by the LangChain framework.
"""
example: bool = False
"""Use to denote that a message is part of an example conversation.
At the moment, this is ignored by most models. Usage is discouraged.
"""
tool_calls: list[ToolCall] = []
@@ -166,6 +171,7 @@ class AIMessage(BaseMessage):
"""If provided, usage metadata for a message, such as token counts.
This is a standard representation of token usage that is consistent across models.
"""
type: Literal["ai"] = "ai"
@@ -178,35 +184,12 @@ class AIMessage(BaseMessage):
**kwargs: Any,
) -> None: ...
@overload
def __init__(
self,
content: Optional[Union[str, list[Union[str, dict]]]] = None,
content_blocks: Optional[list[types.ContentBlock]] = None,
**kwargs: Any,
) -> None: ...
Args:
content: The content of the message.
kwargs: Additional arguments to pass to the parent class.
def __init__(
self,
content: Optional[Union[str, list[Union[str, dict]]]] = None,
content_blocks: Optional[list[types.ContentBlock]] = None,
**kwargs: Any,
) -> None:
"""Specify ``content`` as positional arg or ``content_blocks`` for typing."""
if content_blocks is not None:
# If there are tool calls in content_blocks, but not in tool_calls, add them
content_tool_calls = [
block for block in content_blocks if block.get("type") == "tool_call"
]
if content_tool_calls and "tool_calls" not in kwargs:
kwargs["tool_calls"] = content_tool_calls
super().__init__(
content=cast("Union[str, list[Union[str, dict]]]", content_blocks),
**kwargs,
)
else:
super().__init__(content=content, **kwargs)
"""
super().__init__(content=content, **kwargs)
@property
def lc_attributes(self) -> dict:
@@ -316,6 +299,7 @@ class AIMessage(BaseMessage):
Returns:
A pretty representation of the message.
"""
base = super().pretty_repr(html=html)
lines = []
@@ -355,7 +339,10 @@ class AIMessageChunk(AIMessage, BaseMessageChunk):
# non-chunk variant.
type: Literal["AIMessageChunk"] = "AIMessageChunk" # type: ignore[assignment]
"""The type of the message (used for deserialization).
Defaults to "AIMessageChunk"."""
Defaults to ``AIMessageChunk``.
"""
tool_call_chunks: list[ToolCallChunk] = []
"""If provided, tool call chunks associated with the message."""
@@ -419,6 +406,7 @@ class AIMessageChunk(AIMessage, BaseMessageChunk):
Raises:
ValueError: If the tool call chunks are malformed.
"""
if not self.tool_call_chunks:
if self.tool_calls:
@@ -632,9 +620,9 @@ def add_usage(
def subtract_usage(
left: Optional[UsageMetadata], right: Optional[UsageMetadata]
) -> UsageMetadata:
"""Recursively subtract two UsageMetadata objects.
"""Recursively subtract two ``UsageMetadata`` objects.
Token counts cannot be negative so the actual operation is max(left - right, 0).
Token counts cannot be negative so the actual operation is ``max(left - right, 0)``.
Example:
.. code-block:: python

View File

@@ -58,8 +58,11 @@ class BaseMessage(Serializable):
"""
id: Optional[str] = Field(default=None, coerce_numbers_to_str=True)
"""An optional unique identifier for the message. This should ideally be
provided by the provider/model which created the message."""
"""An optional unique identifier for the message.
This should ideally be provided by the provider/model which created the message.
"""
model_config = ConfigDict(
extra="allow",
@@ -72,25 +75,11 @@ class BaseMessage(Serializable):
**kwargs: Any,
) -> None: ...
@overload
def __init__(
self,
content: Optional[Union[str, list[Union[str, dict]]]] = None,
content_blocks: Optional[list[types.ContentBlock]] = None,
**kwargs: Any,
) -> None: ...
Args:
content: The string contents of the message.
def __init__(
self,
content: Optional[Union[str, list[Union[str, dict]]]] = None,
content_blocks: Optional[list[types.ContentBlock]] = None,
**kwargs: Any,
) -> None:
"""Specify ``content`` as positional arg or ``content_blocks`` for typing."""
if content_blocks is not None:
super().__init__(content=content_blocks, **kwargs)
else:
super().__init__(content=content, **kwargs)
"""
super().__init__(content=content, **kwargs)
@classmethod
def is_lc_serializable(cls) -> bool:
@@ -106,6 +95,7 @@ class BaseMessage(Serializable):
"""Get the namespace of the langchain object.
Default is ``['langchain', 'schema', 'messages']``.
"""
return ["langchain", "schema", "messages"]

View File

@@ -30,7 +30,10 @@ class ChatMessageChunk(ChatMessage, BaseMessageChunk):
# non-chunk variant.
type: Literal["ChatMessageChunk"] = "ChatMessageChunk" # type: ignore[assignment]
"""The type of the message (used during serialization).
Defaults to "ChatMessageChunk"."""
Defaults to ``ChatMessageChunk``.
"""
@override
def __add__(self, other: Any) -> BaseMessageChunk: # type: ignore[override]

View File

@@ -15,19 +15,20 @@ from langchain_core.utils._merge import merge_dicts
class FunctionMessage(BaseMessage):
"""Message for passing the result of executing a tool back to a model.
FunctionMessage are an older version of the ToolMessage schema, and
do not contain the tool_call_id field.
``FunctionMessage`` are an older version of the ``ToolMessage`` schema, and
do not contain the ``tool_call_id`` field.
The tool_call_id field is used to associate the tool call request with the
The ``tool_call_id`` field is used to associate the tool call request with the
tool call response. This is useful in situations where a chat model is able
to request multiple tool calls in parallel.
"""
name: str
"""The name of the function that was executed."""
type: Literal["function"] = "function"
"""The type of the message (used for serialization). Defaults to "function"."""
"""The type of the message (used for serialization). Defaults to ``'function'``."""
class FunctionMessageChunk(FunctionMessage, BaseMessageChunk):
@@ -38,7 +39,10 @@ class FunctionMessageChunk(FunctionMessage, BaseMessageChunk):
# non-chunk variant.
type: Literal["FunctionMessageChunk"] = "FunctionMessageChunk" # type: ignore[assignment]
"""The type of the message (used for serialization).
Defaults to "FunctionMessageChunk"."""
Defaults to ``FunctionMessageChunk``.
"""
@override
def __add__(self, other: Any) -> BaseMessageChunk: # type: ignore[override]

View File

@@ -9,7 +9,7 @@ from langchain_core.messages.base import BaseMessage, BaseMessageChunk
class HumanMessage(BaseMessage):
"""Message from a human.
HumanMessages are messages that are passed in from a human to the model.
``HumanMessage``s are messages that are passed in from a human to the model.
Example:
@@ -37,10 +37,15 @@ class HumanMessage(BaseMessage):
At the moment, this is ignored by most models. Usage is discouraged.
Defaults to False.
"""
type: Literal["human"] = "human"
"""The type of the message (used for serialization). Defaults to "human"."""
"""The type of the message (used for serialization).
Defaults to ``'human'``.
"""
@overload
def __init__(
@@ -49,28 +54,12 @@ class HumanMessage(BaseMessage):
**kwargs: Any,
) -> None: ...
@overload
def __init__(
self,
content: Optional[Union[str, list[Union[str, dict]]]] = None,
content_blocks: Optional[list[types.ContentBlock]] = None,
**kwargs: Any,
) -> None: ...
Args:
content: The string contents of the message.
kwargs: Additional fields to pass to the message.
def __init__(
self,
content: Optional[Union[str, list[Union[str, dict]]]] = None,
content_blocks: Optional[list[types.ContentBlock]] = None,
**kwargs: Any,
) -> None:
"""Specify ``content`` as positional arg or ``content_blocks`` for typing."""
if content_blocks is not None:
super().__init__(
content=cast("Union[str, list[Union[str, dict]]]", content_blocks),
**kwargs,
)
else:
super().__init__(content=content, **kwargs)
"""
super().__init__(content=content, **kwargs)
class HumanMessageChunk(HumanMessage, BaseMessageChunk):

View File

@@ -24,6 +24,7 @@ class RemoveMessage(BaseMessage):
Raises:
ValueError: If the 'content' field is passed in kwargs.
"""
if kwargs.pop("content", None):
msg = "RemoveMessage does not support 'content' field."

View File

@@ -33,7 +33,11 @@ class SystemMessage(BaseMessage):
"""
type: Literal["system"] = "system"
"""The type of the message (used for serialization). Defaults to "system"."""
"""The type of the message (used for serialization).
Defaults to ``'system'``.
"""
@overload
def __init__(
@@ -74,4 +78,7 @@ class SystemMessageChunk(SystemMessage, BaseMessageChunk):
# non-chunk variant.
type: Literal["SystemMessageChunk"] = "SystemMessageChunk" # type: ignore[assignment]
"""The type of the message (used for serialization).
Defaults to "SystemMessageChunk"."""
Defaults to ``'SystemMessageChunk'``.
"""

View File

@@ -16,19 +16,20 @@ from langchain_core.utils._merge import merge_dicts, merge_obj
class ToolOutputMixin:
"""Mixin for objects that tools can return directly.
If a custom BaseTool is invoked with a ToolCall and the output of custom code is
not an instance of ToolOutputMixin, the output will automatically be coerced to a
string and wrapped in a ToolMessage.
If a custom BaseTool is invoked with a ``ToolCall`` and the output of custom code is
not an instance of ``ToolOutputMixin``, the output will automatically be coerced to
a string and wrapped in a ``ToolMessage``.
"""
class ToolMessage(BaseMessage, ToolOutputMixin):
"""Message for passing the result of executing a tool back to a model.
ToolMessages contain the result of a tool invocation. Typically, the result
is encoded inside the `content` field.
``ToolMessage``s contain the result of a tool invocation. Typically, the result
is encoded inside the ``content`` field.
Example: A ToolMessage representing a result of 42 from a tool call with id
Example: A ``ToolMessage`` representing a result of ``42`` from a tool call with id
.. code-block:: python
@@ -37,7 +38,7 @@ class ToolMessage(BaseMessage, ToolOutputMixin):
ToolMessage(content='42', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL')
Example: A ToolMessage where only part of the tool output is sent to the model
Example: A ``ToolMessage`` where only part of the tool output is sent to the model
and the full output is passed in to artifact.
.. versionadded:: 0.2.17
@@ -58,7 +59,7 @@ class ToolMessage(BaseMessage, ToolOutputMixin):
tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL',
)
The tool_call_id field is used to associate the tool call request with the
The ``tool_call_id`` field is used to associate the tool call request with the
tool call response. This is useful in situations where a chat model is able
to request multiple tool calls in parallel.
@@ -68,7 +69,11 @@ class ToolMessage(BaseMessage, ToolOutputMixin):
"""Tool call that this message is responding to."""
type: Literal["tool"] = "tool"
"""The type of the message (used for serialization). Defaults to "tool"."""
"""The type of the message (used for serialization).
Defaults to ``'tool'``.
"""
artifact: Any = None
"""Artifact of the Tool execution which is not meant to be sent to the model.
@@ -78,12 +83,14 @@ class ToolMessage(BaseMessage, ToolOutputMixin):
output is needed in other parts of the code.
.. versionadded:: 0.2.17
"""
status: Literal["success", "error"] = "success"
"""Status of the tool invocation.
.. versionadded:: 0.2.24
"""
additional_kwargs: dict = Field(default_factory=dict, repr=False)
@@ -98,6 +105,7 @@ class ToolMessage(BaseMessage, ToolOutputMixin):
Args:
values: The model arguments.
"""
content = values["content"]
if isinstance(content, tuple):
@@ -142,28 +150,12 @@ class ToolMessage(BaseMessage, ToolOutputMixin):
**kwargs: Any,
) -> None: ...
@overload
def __init__(
self,
content: Optional[Union[str, list[Union[str, dict]]]] = None,
content_blocks: Optional[list[types.ContentBlock]] = None,
**kwargs: Any,
) -> None: ...
Args:
content: The string contents of the message.
**kwargs: Additional fields.
def __init__(
self,
content: Optional[Union[str, list[Union[str, dict]]]] = None,
content_blocks: Optional[list[types.ContentBlock]] = None,
**kwargs: Any,
) -> None:
"""Specify ``content`` as positional arg or ``content_blocks`` for typing."""
if content_blocks is not None:
super().__init__(
content=cast("Union[str, list[Union[str, dict]]]", content_blocks),
**kwargs,
)
else:
super().__init__(content=content, **kwargs)
"""
super().__init__(content=content, **kwargs)
class ToolMessageChunk(ToolMessage, BaseMessageChunk):
@@ -211,8 +203,8 @@ class ToolCall(TypedDict):
"id": "123"
}
This represents a request to call the tool named "foo" with arguments {"a": 1}
and an identifier of "123".
This represents a request to call the tool named ``'foo'`` with arguments
``{"a": 1}`` and an identifier of ``'123'``.
"""
@@ -225,6 +217,7 @@ class ToolCall(TypedDict):
An identifier is needed to associate a tool call request with a tool
call result in events when multiple concurrent tool calls are made.
"""
type: NotRequired[Literal["tool_call"]]
@@ -241,6 +234,7 @@ def tool_call(
name: The name of the tool to be called.
args: The arguments to the tool call.
id: An identifier associated with the tool call.
"""
return ToolCall(name=name, args=args, id=id, type="tool_call")
@@ -248,9 +242,9 @@ def tool_call(
class ToolCallChunk(TypedDict):
"""A chunk of a tool call (e.g., as part of a stream).
When merging ToolCallChunks (e.g., via AIMessageChunk.__add__),
When merging ``ToolCallChunk``s (e.g., via ``AIMessageChunk.__add__``),
all string attributes are concatenated. Chunks are only merged if their
values of `index` are equal and not None.
values of ``index`` are equal and not None.
Example:
@@ -291,12 +285,32 @@ def tool_call_chunk(
args: The arguments to the tool call.
id: An identifier associated with the tool call.
index: The index of the tool call in a sequence.
"""
return ToolCallChunk(
name=name, args=args, id=id, index=index, type="tool_call_chunk"
)
class InvalidToolCall(TypedDict):
"""Allowance for errors made by LLM.
Here we add an ``error`` key to surface errors made during generation
(e.g., invalid JSON arguments.)
"""
name: Optional[str]
"""The name of the tool to be called."""
args: Optional[str]
"""The arguments to the tool call."""
id: Optional[str]
"""An identifier associated with the tool call."""
error: Optional[str]
"""An error message associated with the tool call."""
type: NotRequired[Literal["invalid_tool_call"]]
def invalid_tool_call(
*,
name: Optional[str] = None,
@@ -311,6 +325,7 @@ def invalid_tool_call(
args: The arguments to the tool call.
id: An identifier associated with the tool call.
error: An error message associated with the tool call.
"""
return InvalidToolCall(
name=name, args=args, id=id, error=error, type="invalid_tool_call"

View File

@@ -5,6 +5,7 @@ Some examples of what you can do with these functions include:
* Convert messages to strings (serialization)
* Convert messages from dicts to Message objects (deserialization)
* Filter messages from a list of messages based on name, type or id etc.
"""
from __future__ import annotations
@@ -89,13 +90,13 @@ AnyMessage = Annotated[
def get_buffer_string(
messages: Sequence[BaseMessage], human_prefix: str = "Human", ai_prefix: str = "AI"
) -> str:
r"""Convert a sequence of Messages to strings and concatenate them into one string.
r"""Convert a sequence of messages to strings and concatenate them into one string.
Args:
messages: Messages to be converted to strings.
human_prefix: The prefix to prepend to contents of HumanMessages.
human_prefix: The prefix to prepend to contents of ``HumanMessage``s.
Default is "Human".
ai_prefix: THe prefix to prepend to contents of AIMessages. Default is "AI".
ai_prefix: The prefix to prepend to contents of AIMessages. Default is ``'AI'``.
Returns:
A single string concatenation of all input messages.
@@ -174,19 +175,20 @@ def _message_from_dict(message: dict) -> BaseMessage:
def messages_from_dict(messages: Sequence[dict]) -> list[BaseMessage]:
"""Convert a sequence of messages from dicts to Message objects.
"""Convert a sequence of messages from dicts to ``Message`` objects.
Args:
messages: Sequence of messages (as dicts) to convert.
Returns:
list of messages (BaseMessages).
"""
return [_message_from_dict(m) for m in messages]
def message_chunk_to_message(chunk: BaseMessageChunk) -> BaseMessage:
"""Convert a message chunk to a message.
"""Convert a message chunk to a ``Message``.
Args:
chunk: Message chunk to convert.
@@ -219,10 +221,10 @@ def _create_message_from_message_type(
id: Optional[str] = None,
**additional_kwargs: Any,
) -> BaseMessage:
"""Create a message from a message type and content string.
"""Create a message from a ``Message`` type and content string.
Args:
message_type: (str) the type of the message (e.g., "human", "ai", etc.).
message_type: (str) the type of the message (e.g., ``'human'``, ``'ai'``, etc.).
content: (str) the content string.
name: (str) the name of the message. Default is None.
tool_call_id: (str) the tool call id. Default is None.
@@ -234,8 +236,9 @@ def _create_message_from_message_type(
a message of the appropriate type.
Raises:
ValueError: if the message type is not one of "human", "user", "ai",
"assistant", "function", "tool", "system", or "developer".
ValueError: if the message type is not one of ``'human'``, ``'user'``, ``'ai'``,
``'assistant'``, ``'function'``, ``'tool'``, ``'system'``, or
``'developer'``.
"""
kwargs: dict[str, Any] = {}
if name is not None:
@@ -298,15 +301,15 @@ def _create_message_from_message_type(
def _convert_to_message(message: MessageLikeRepresentation) -> BaseMessage:
"""Instantiate a message from a variety of message formats.
"""Instantiate a ``Message`` from a variety of message formats.
The message format can be one of the following:
- BaseMessagePromptTemplate
- BaseMessage
- 2-tuple of (role string, template); e.g., ("human", "{user_input}")
- ``BaseMessagePromptTemplate``
- ``BaseMessage``
- 2-tuple of (role string, template); e.g., (``'human'``, ``'{user_input}'``)
- dict: a message dict with role and content keys
- string: shorthand for ("human", template); e.g., "{user_input}"
- string: shorthand for (``'human'``, template); e.g., ``'{user_input}'``
Args:
message: a representation of a message in one of the supported formats.
@@ -317,6 +320,7 @@ def _convert_to_message(message: MessageLikeRepresentation) -> BaseMessage:
Raises:
NotImplementedError: if the message type is not supported.
ValueError: if the message dict does not contain the required keys.
"""
if isinstance(message, BaseMessage):
message_ = message
@@ -362,6 +366,7 @@ def convert_to_messages(
Returns:
list of messages (BaseMessages).
"""
# Import here to avoid circular imports
from langchain_core.prompt_values import PromptValue
@@ -411,31 +416,31 @@ def filter_messages(
exclude_ids: Optional[Sequence[str]] = None,
exclude_tool_calls: Optional[Sequence[str] | bool] = None,
) -> list[BaseMessage]:
"""Filter messages based on name, type or id.
"""Filter messages based on ``name``, ``type`` or ``id``.
Args:
messages: Sequence Message-like objects to filter.
include_names: Message names to include. Default is None.
exclude_names: Messages names to exclude. Default is None.
include_types: Message types to include. Can be specified as string names (e.g.
"system", "human", "ai", ...) or as BaseMessage classes (e.g.
SystemMessage, HumanMessage, AIMessage, ...). Default is None.
``'system'``, ``'human'``, ``'ai'``, ...) or as ``BaseMessage`` classes (e.g.
``SystemMessage``, ``HumanMessage``, ``AIMessage``, ...). Default is None.
exclude_types: Message types to exclude. Can be specified as string names (e.g.
"system", "human", "ai", ...) or as BaseMessage classes (e.g.
SystemMessage, HumanMessage, AIMessage, ...). Default is None.
``'system'``, ``'human'``, ``'ai'``, ...) or as ``BaseMessage`` classes (e.g.
``SystemMessage``, ``HumanMessage``, ``AIMessage``, ...). Default is None.
include_ids: Message IDs to include. Default is None.
exclude_ids: Message IDs to exclude. Default is None.
exclude_tool_calls: Tool call IDs to exclude. Default is None.
Can be one of the following:
- `True`: all AIMessages with tool calls and all ToolMessages will be excluded.
- ``True``: all ``AIMessage``s with tool calls and all ``ToolMessage``s will be excluded.
- a sequence of tool call IDs to exclude:
- ToolMessages with the corresponding tool call ID will be excluded.
- The `tool_calls` in the AIMessage will be updated to exclude matching tool calls.
If all tool_calls are filtered from an AIMessage, the whole message is excluded.
- ``ToolMessage``s with the corresponding tool call ID will be excluded.
- The ``tool_calls`` in the AIMessage will be updated to exclude matching tool calls.
If all ``tool_calls`` are filtered from an AIMessage, the whole message is excluded.
Returns:
A list of Messages that meets at least one of the incl_* conditions and none
of the excl_* conditions. If not incl_* conditions are specified then
A list of Messages that meets at least one of the ``incl_*`` conditions and none
of the ``excl_*`` conditions. If not ``incl_*`` conditions are specified then
anything that is not explicitly excluded will be included.
Raises:
@@ -536,13 +541,14 @@ def merge_message_runs(
) -> list[BaseMessage]:
r"""Merge consecutive Messages of the same type.
**NOTE**: ToolMessages are not merged, as each has a distinct tool call id that
can't be merged.
.. note::
ToolMessages are not merged, as each has a distinct tool call id that can't be
merged.
Args:
messages: Sequence Message-like objects to merge.
chunk_separator: Specify the string to be inserted between message chunks.
Default is "\n".
Default is ``'\n'``.
Returns:
list of BaseMessages with consecutive runs of message types merged into single
@@ -651,22 +657,22 @@ def trim_messages(
) -> list[BaseMessage]:
r"""Trim messages to be below a token count.
trim_messages can be used to reduce the size of a chat history to a specified token
count or specified message count.
``trim_messages`` can be used to reduce the size of a chat history to a specified
token count or specified message count.
In either case, if passing the trimmed chat history back into a chat model
directly, the resulting chat history should usually satisfy the following
properties:
1. The resulting chat history should be valid. Most chat models expect that chat
history starts with either (1) a ``HumanMessage`` or (2) a ``SystemMessage`` followed
by a ``HumanMessage``. To achieve this, set ``start_on="human"``.
history starts with either (1) a ``HumanMessage`` or (2) a ``SystemMessage``
followed by a ``HumanMessage``. To achieve this, set ``start_on='human'``.
In addition, generally a ``ToolMessage`` can only appear after an ``AIMessage``
that involved a tool call.
Please see the following link for more information about messages:
https://python.langchain.com/docs/concepts/#messages
2. It includes recent messages and drops old messages in the chat history.
To achieve this set the ``strategy="last"``.
To achieve this set the ``strategy='last'``.
3. Usually, the new chat history should include the ``SystemMessage`` if it
was present in the original chat history since the ``SystemMessage`` includes
special instructions to the chat model. The ``SystemMessage`` is almost always
@@ -680,65 +686,66 @@ def trim_messages(
Args:
messages: Sequence of Message-like objects to trim.
max_tokens: Max token count of trimmed messages.
token_counter: Function or llm for counting tokens in a BaseMessage or a list of
BaseMessage. If a BaseLanguageModel is passed in then
BaseLanguageModel.get_num_tokens_from_messages() will be used.
Set to `len` to count the number of **messages** in the chat history.
token_counter: Function or llm for counting tokens in a ``BaseMessage`` or a
list of ``BaseMessage``. If a ``BaseLanguageModel`` is passed in then
``BaseLanguageModel.get_num_tokens_from_messages()`` will be used.
Set to ``len`` to count the number of **messages** in the chat history.
.. note::
Use `count_tokens_approximately` to get fast, approximate token counts.
This is recommended for using `trim_messages` on the hot path, where
Use ``count_tokens_approximately`` to get fast, approximate token counts.
This is recommended for using ``trim_messages`` on the hot path, where
exact token counting is not necessary.
strategy: Strategy for trimming.
- "first": Keep the first <= n_count tokens of the messages.
- "last": Keep the last <= n_count tokens of the messages.
Default is "last".
- ``'first'``: Keep the first ``<= n_count`` tokens of the messages.
- ``'last'``: Keep the last ``<= n_count`` tokens of the messages.
Default is ``'last'``.
allow_partial: Whether to split a message if only part of the message can be
included. If ``strategy="last"`` then the last partial contents of a message
are included. If ``strategy="first"`` then the first partial contents of a
included. If ``strategy='last'`` then the last partial contents of a message
are included. If ``strategy='first'`` then the first partial contents of a
message are included.
Default is False.
end_on: The message type to end on. If specified then every message after the
last occurrence of this type is ignored. If ``strategy=="last"`` then this
last occurrence of this type is ignored. If ``strategy='last'`` then this
is done before we attempt to get the last ``max_tokens``. If
``strategy=="first"`` then this is done after we get the first
``max_tokens``. Can be specified as string names (e.g. "system", "human",
"ai", ...) or as BaseMessage classes (e.g. SystemMessage, HumanMessage,
AIMessage, ...). Can be a single type or a list of types.
``strategy='first'`` then this is done after we get the first
``max_tokens``. Can be specified as string names (e.g. ``'system'``,
``'human'``, ``'ai'``, ...) or as ``BaseMessage`` classes (e.g.
``SystemMessage``, ``HumanMessage``, ``AIMessage``, ...). Can be a single
type or a list of types.
Default is None.
start_on: The message type to start on. Should only be specified if
``strategy="last"``. If specified then every message before
``strategy='last'``. If specified then every message before
the first occurrence of this type is ignored. This is done after we trim
the initial messages to the last ``max_tokens``. Does not
apply to a SystemMessage at index 0 if ``include_system=True``. Can be
specified as string names (e.g. "system", "human", "ai", ...) or as
BaseMessage classes (e.g. SystemMessage, HumanMessage, AIMessage, ...). Can
be a single type or a list of types.
apply to a ``SystemMessage`` at index 0 if ``include_system=True``. Can be
specified as string names (e.g. ``'system'``, ``'human'``, ``'ai'``, ...) or
as ``BaseMessage`` classes (e.g. ``SystemMessage``, ``HumanMessage``,
``AIMessage``, ...). Can be a single type or a list of types.
Default is None.
include_system: Whether to keep the SystemMessage if there is one at index 0.
Should only be specified if ``strategy="last"``.
Default is False.
text_splitter: Function or ``langchain_text_splitters.TextSplitter`` for
splitting the string contents of a message. Only used if
``allow_partial=True``. If ``strategy="last"`` then the last split tokens
from a partial message will be included. if ``strategy=="first"`` then the
``allow_partial=True``. If ``strategy='last'`` then the last split tokens
from a partial message will be included. if ``strategy='first'`` then the
first split tokens from a partial message will be included. Token splitter
assumes that separators are kept, so that split contents can be directly
concatenated to recreate the original text. Defaults to splitting on
newlines.
Returns:
list of trimmed BaseMessages.
list of trimmed ``BaseMessage``.
Raises:
ValueError: if two incompatible arguments are specified or an unrecognized
``strategy`` is specified.
Example:
Trim chat history based on token count, keeping the SystemMessage if
present, and ensuring that the chat history starts with a HumanMessage (
or a SystemMessage followed by a HumanMessage).
Trim chat history based on token count, keeping the ``SystemMessage`` if
present, and ensuring that the chat history starts with a ``HumanMessage`` (
or a ``SystemMessage`` followed by a ``HumanMessage``).
.. code-block:: python
@@ -787,9 +794,9 @@ def trim_messages(
HumanMessage(content='what do you call a speechless parrot'),
]
Trim chat history based on the message count, keeping the SystemMessage if
present, and ensuring that the chat history starts with a HumanMessage (
or a SystemMessage followed by a HumanMessage).
Trim chat history based on the message count, keeping the ``SystemMessage`` if
present, and ensuring that the chat history starts with a ``HumanMessage`` (
or a ``SystemMessage`` followed by a ``HumanMessage``).
trim_messages(
messages,
@@ -955,16 +962,16 @@ def convert_to_openai_messages(
in OpenAI, Anthropic, Bedrock Converse, or VertexAI formats.
text_format: How to format string or text block contents:
- "string":
- ``'string'``:
If a message has a string content, this is left as a string. If
a message has content blocks that are all of type 'text', these are
joined with a newline to make a single string. If a message has
content blocks and at least one isn't of type 'text', then
a message has content blocks that are all of type ``'text'``, these
are joined with a newline to make a single string. If a message has
content blocks and at least one isn't of type ``'text'``, then
all blocks are left as dicts.
- "block":
If a message has a string content, this is turned into a list
with a single content block of type 'text'. If a message has content
blocks these are left as is.
with a single content block of type ``'text'``. If a message has
content blocks these are left as is.
Returns:
The return type depends on the input type: