core[minor]: rename ToolMessage.raw_output -> artifact (#24185)

This commit is contained in:
Bagatur 2024-07-12 09:52:44 -07:00 committed by GitHub
parent d77d9bfc00
commit 6166ea67a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 144 additions and 106 deletions

View File

@ -21,8 +21,11 @@ class ToolMessage(BaseMessage):
ToolMessage(content='42', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL') 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 raw_output. and the full output is passed in to artifact.
.. versionadded:: 0.2.17
.. code-block:: python .. code-block:: python
@ -36,7 +39,7 @@ class ToolMessage(BaseMessage):
ToolMessage( ToolMessage(
content=tool_output["stdout"], content=tool_output["stdout"],
raw_output=tool_output, artifact=tool_output,
tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL',
) )
@ -54,12 +57,14 @@ class ToolMessage(BaseMessage):
type: Literal["tool"] = "tool" 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"."""
raw_output: Any = None artifact: Any = None
"""The raw output of the tool. """Artifact of the Tool execution which is not meant to be sent to the model.
**Not part of the payload sent to the model.** Should only be specified if it is Should only be specified if it is different from the message content, e.g. if only
different from the message content, i.e. if only a subset of the full tool output a subset of the full tool output is being passed as message content but the full
is being passed as message content. output is needed in other parts of the code.
.. versionadded:: 0.2.17
""" """
@classmethod @classmethod
@ -106,7 +111,7 @@ class ToolMessageChunk(ToolMessage, BaseMessageChunk):
return self.__class__( return self.__class__(
tool_call_id=self.tool_call_id, tool_call_id=self.tool_call_id,
content=merge_content(self.content, other.content), content=merge_content(self.content, other.content),
raw_output=merge_obj(self.raw_output, other.raw_output), artifact=merge_obj(self.artifact, other.artifact),
additional_kwargs=merge_dicts( additional_kwargs=merge_dicts(
self.additional_kwargs, other.additional_kwargs self.additional_kwargs, other.additional_kwargs
), ),

View File

@ -221,8 +221,8 @@ def _create_message_from_message_type(
elif message_type == "function": elif message_type == "function":
message = FunctionMessage(content=content, **kwargs) message = FunctionMessage(content=content, **kwargs)
elif message_type == "tool": elif message_type == "tool":
raw_output = kwargs.get("additional_kwargs", {}).pop("raw_output", None) artifact = kwargs.get("additional_kwargs", {}).pop("artifact", None)
message = ToolMessage(content=content, raw_output=raw_output, **kwargs) message = ToolMessage(content=content, artifact=artifact, **kwargs)
elif message_type == "remove": elif message_type == "remove":
message = RemoveMessage(**kwargs) message = RemoveMessage(**kwargs)
else: else:

View File

@ -382,12 +382,12 @@ class ChildTool(BaseTool):
] = False ] = False
"""Handle the content of the ValidationError thrown.""" """Handle the content of the ValidationError thrown."""
response_format: Literal["content", "content_and_raw_output"] = "content" response_format: Literal["content", "content_and_artifact"] = "content"
"""The tool response format. """The tool response format.
If "content" then the output of the tool is interpreted as the contents of a If "content" then the output of the tool is interpreted as the contents of a
ToolMessage. If "content_and_raw_output" then the output is expected to be a ToolMessage. If "content_and_artifact" then the output is expected to be a
two-tuple corresponding to the (content, raw_output) of a ToolMessage. two-tuple corresponding to the (content, artifact) of a ToolMessage.
""" """
class Config(Serializable.Config): class Config(Serializable.Config):
@ -540,7 +540,7 @@ class ChildTool(BaseTool):
) )
content = None content = None
raw_output = None artifact = None
error_to_raise: Union[Exception, KeyboardInterrupt, None] = None error_to_raise: Union[Exception, KeyboardInterrupt, None] = None
try: try:
child_config = patch_config(config, callbacks=run_manager.get_child()) child_config = patch_config(config, callbacks=run_manager.get_child())
@ -553,15 +553,15 @@ class ChildTool(BaseTool):
if config_param := _get_runnable_config_param(self._run): if config_param := _get_runnable_config_param(self._run):
tool_kwargs[config_param] = config tool_kwargs[config_param] = config
response = context.run(self._run, *tool_args, **tool_kwargs) response = context.run(self._run, *tool_args, **tool_kwargs)
if self.response_format == "content_and_raw_output": if self.response_format == "content_and_artifact":
if not isinstance(response, tuple) or len(response) != 2: if not isinstance(response, tuple) or len(response) != 2:
raise ValueError( raise ValueError(
"Since response_format='content_and_raw_output' " "Since response_format='content_and_artifact' "
"a two-tuple of the message content and raw tool output is " "a two-tuple of the message content and raw tool output is "
f"expected. Instead generated response of type: " f"expected. Instead generated response of type: "
f"{type(response)}." f"{type(response)}."
) )
content, raw_output = response content, artifact = response
else: else:
content = response content = response
except ValidationError as e: except ValidationError as e:
@ -580,7 +580,7 @@ class ChildTool(BaseTool):
if error_to_raise: if error_to_raise:
run_manager.on_tool_error(error_to_raise) run_manager.on_tool_error(error_to_raise)
raise error_to_raise raise error_to_raise
output = _format_output(content, raw_output, tool_call_id) output = _format_output(content, artifact, tool_call_id)
run_manager.on_tool_end(output, color=color, name=self.name, **kwargs) run_manager.on_tool_end(output, color=color, name=self.name, **kwargs)
return output return output
@ -624,7 +624,7 @@ class ChildTool(BaseTool):
**kwargs, **kwargs,
) )
content = None content = None
raw_output = None artifact = None
error_to_raise: Optional[Union[Exception, KeyboardInterrupt]] = None error_to_raise: Optional[Union[Exception, KeyboardInterrupt]] = None
try: try:
tool_args, tool_kwargs = self._to_args_and_kwargs(tool_input) tool_args, tool_kwargs = self._to_args_and_kwargs(tool_input)
@ -644,15 +644,15 @@ class ChildTool(BaseTool):
response = await asyncio.create_task(coro, context=context) # type: ignore response = await asyncio.create_task(coro, context=context) # type: ignore
else: else:
response = await coro response = await coro
if self.response_format == "content_and_raw_output": if self.response_format == "content_and_artifact":
if not isinstance(response, tuple) or len(response) != 2: if not isinstance(response, tuple) or len(response) != 2:
raise ValueError( raise ValueError(
"Since response_format='content_and_raw_output' " "Since response_format='content_and_artifact' "
"a two-tuple of the message content and raw tool output is " "a two-tuple of the message content and raw tool output is "
f"expected. Instead generated response of type: " f"expected. Instead generated response of type: "
f"{type(response)}." f"{type(response)}."
) )
content, raw_output = response content, artifact = response
else: else:
content = response content = response
except ValidationError as e: except ValidationError as e:
@ -672,7 +672,7 @@ class ChildTool(BaseTool):
await run_manager.on_tool_error(error_to_raise) await run_manager.on_tool_error(error_to_raise)
raise error_to_raise raise error_to_raise
output = _format_output(content, raw_output, tool_call_id) output = _format_output(content, artifact, tool_call_id)
await run_manager.on_tool_end(output, color=color, name=self.name, **kwargs) await run_manager.on_tool_end(output, color=color, name=self.name, **kwargs)
return output return output
@ -883,7 +883,7 @@ class StructuredTool(BaseTool):
args_schema: Optional[Type[BaseModel]] = None, args_schema: Optional[Type[BaseModel]] = None,
infer_schema: bool = True, infer_schema: bool = True,
*, *,
response_format: Literal["content", "content_and_raw_output"] = "content", response_format: Literal["content", "content_and_artifact"] = "content",
parse_docstring: bool = False, parse_docstring: bool = False,
error_on_invalid_docstring: bool = False, error_on_invalid_docstring: bool = False,
**kwargs: Any, **kwargs: Any,
@ -902,8 +902,8 @@ class StructuredTool(BaseTool):
infer_schema: Whether to infer the schema from the function's signature infer_schema: Whether to infer the schema from the function's signature
response_format: The tool response format. If "content" then the output of response_format: The tool response format. If "content" then the output of
the tool is interpreted as the contents of a ToolMessage. If the tool is interpreted as the contents of a ToolMessage. If
"content_and_raw_output" then the output is expected to be a two-tuple "content_and_artifact" then the output is expected to be a two-tuple
corresponding to the (content, raw_output) of a ToolMessage. corresponding to the (content, artifact) of a ToolMessage.
parse_docstring: if ``infer_schema`` and ``parse_docstring``, will attempt parse_docstring: if ``infer_schema`` and ``parse_docstring``, will attempt
to parse parameter descriptions from Google Style function docstrings. to parse parameter descriptions from Google Style function docstrings.
error_on_invalid_docstring: if ``parse_docstring`` is provided, configures error_on_invalid_docstring: if ``parse_docstring`` is provided, configures
@ -980,7 +980,7 @@ def tool(
return_direct: bool = False, return_direct: bool = False,
args_schema: Optional[Type[BaseModel]] = None, args_schema: Optional[Type[BaseModel]] = None,
infer_schema: bool = True, infer_schema: bool = True,
response_format: Literal["content", "content_and_raw_output"] = "content", response_format: Literal["content", "content_and_artifact"] = "content",
parse_docstring: bool = False, parse_docstring: bool = False,
error_on_invalid_docstring: bool = True, error_on_invalid_docstring: bool = True,
) -> Callable: ) -> Callable:
@ -996,8 +996,8 @@ def tool(
accept a dictionary input to its `run()` function. accept a dictionary input to its `run()` function.
response_format: The tool response format. If "content" then the output of response_format: The tool response format. If "content" then the output of
the tool is interpreted as the contents of a ToolMessage. If the tool is interpreted as the contents of a ToolMessage. If
"content_and_raw_output" then the output is expected to be a two-tuple "content_and_artifact" then the output is expected to be a two-tuple
corresponding to the (content, raw_output) of a ToolMessage. corresponding to the (content, artifact) of a ToolMessage.
parse_docstring: if ``infer_schema`` and ``parse_docstring``, will attempt to parse_docstring: if ``infer_schema`` and ``parse_docstring``, will attempt to
parse parameter descriptions from Google Style function docstrings. parse parameter descriptions from Google Style function docstrings.
error_on_invalid_docstring: if ``parse_docstring`` is provided, configures error_on_invalid_docstring: if ``parse_docstring`` is provided, configures
@ -1020,7 +1020,7 @@ def tool(
# Searches the API for the query. # Searches the API for the query.
return return
@tool(response_format="content_and_raw_output") @tool(response_format="content_and_artifact")
def search_api(query: str) -> Tuple[str, dict]: def search_api(query: str) -> Tuple[str, dict]:
return "partial json of results", {"full": "object of results"} return "partial json of results", {"full": "object of results"}
@ -1385,7 +1385,7 @@ def _prep_run_args(
def _format_output( def _format_output(
content: Any, raw_output: Any, tool_call_id: Optional[str] content: Any, artifact: Any, tool_call_id: Optional[str]
) -> Union[ToolMessage, Any]: ) -> Union[ToolMessage, Any]:
if tool_call_id: if tool_call_id:
# NOTE: This will fail to stringify lists which aren't actually content blocks # NOTE: This will fail to stringify lists which aren't actually content blocks
@ -1397,7 +1397,7 @@ def _format_output(
and isinstance(content[0], (str, dict)) and isinstance(content[0], (str, dict))
): ):
content = _stringify(content) content = _stringify(content)
return ToolMessage(content, raw_output=raw_output, tool_call_id=tool_call_id) return ToolMessage(content, artifact=artifact, tool_call_id=tool_call_id)
else: else:
return content return content

View File

@ -457,8 +457,11 @@
ToolMessage(content='42', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL') 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 raw_output. and the full output is passed in to artifact.
.. versionadded:: 0.2.17
.. code-block:: python .. code-block:: python
@ -472,7 +475,7 @@
ToolMessage( ToolMessage(
content=tool_output["stdout"], content=tool_output["stdout"],
raw_output=tool_output, artifact=tool_output,
tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL',
) )
@ -485,6 +488,9 @@
'title': 'Additional Kwargs', 'title': 'Additional Kwargs',
'type': 'object', 'type': 'object',
}), }),
'artifact': dict({
'title': 'Artifact',
}),
'content': dict({ 'content': dict({
'anyOf': list([ 'anyOf': list([
dict({ dict({
@ -514,9 +520,6 @@
'title': 'Name', 'title': 'Name',
'type': 'string', 'type': 'string',
}), }),
'raw_output': dict({
'title': 'Raw Output',
}),
'response_metadata': dict({ 'response_metadata': dict({
'title': 'Response Metadata', 'title': 'Response Metadata',
'type': 'object', 'type': 'object',
@ -1062,8 +1065,11 @@
ToolMessage(content='42', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL') 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 raw_output. and the full output is passed in to artifact.
.. versionadded:: 0.2.17
.. code-block:: python .. code-block:: python
@ -1077,7 +1083,7 @@
ToolMessage( ToolMessage(
content=tool_output["stdout"], content=tool_output["stdout"],
raw_output=tool_output, artifact=tool_output,
tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL',
) )
@ -1090,6 +1096,9 @@
'title': 'Additional Kwargs', 'title': 'Additional Kwargs',
'type': 'object', 'type': 'object',
}), }),
'artifact': dict({
'title': 'Artifact',
}),
'content': dict({ 'content': dict({
'anyOf': list([ 'anyOf': list([
dict({ dict({
@ -1119,9 +1128,6 @@
'title': 'Name', 'title': 'Name',
'type': 'string', 'type': 'string',
}), }),
'raw_output': dict({
'title': 'Raw Output',
}),
'response_metadata': dict({ 'response_metadata': dict({
'title': 'Response Metadata', 'title': 'Response Metadata',
'type': 'object', 'type': 'object',

View File

@ -813,8 +813,11 @@
ToolMessage(content='42', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL') 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 raw_output. and the full output is passed in to artifact.
.. versionadded:: 0.2.17
.. code-block:: python .. code-block:: python
@ -828,7 +831,7 @@
ToolMessage( ToolMessage(
content=tool_output["stdout"], content=tool_output["stdout"],
raw_output=tool_output, artifact=tool_output,
tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL',
) )
@ -841,6 +844,9 @@
'title': 'Additional Kwargs', 'title': 'Additional Kwargs',
'type': 'object', 'type': 'object',
}), }),
'artifact': dict({
'title': 'Artifact',
}),
'content': dict({ 'content': dict({
'anyOf': list([ 'anyOf': list([
dict({ dict({
@ -870,9 +876,6 @@
'title': 'Name', 'title': 'Name',
'type': 'string', 'type': 'string',
}), }),
'raw_output': dict({
'title': 'Raw Output',
}),
'response_metadata': dict({ 'response_metadata': dict({
'title': 'Response Metadata', 'title': 'Response Metadata',
'type': 'object', 'type': 'object',

View File

@ -5739,8 +5739,11 @@
ToolMessage(content='42', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL') 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 raw_output. and the full output is passed in to artifact.
.. versionadded:: 0.2.17
.. code-block:: python .. code-block:: python
@ -5754,7 +5757,7 @@
ToolMessage( ToolMessage(
content=tool_output["stdout"], content=tool_output["stdout"],
raw_output=tool_output, artifact=tool_output,
tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL',
) )
@ -5767,6 +5770,9 @@
'title': 'Additional Kwargs', 'title': 'Additional Kwargs',
'type': 'object', 'type': 'object',
}), }),
'artifact': dict({
'title': 'Artifact',
}),
'content': dict({ 'content': dict({
'anyOf': list([ 'anyOf': list([
dict({ dict({
@ -5796,9 +5802,6 @@
'title': 'Name', 'title': 'Name',
'type': 'string', 'type': 'string',
}), }),
'raw_output': dict({
'title': 'Raw Output',
}),
'response_metadata': dict({ 'response_metadata': dict({
'title': 'Response Metadata', 'title': 'Response Metadata',
'type': 'object', 'type': 'object',
@ -6413,8 +6416,11 @@
ToolMessage(content='42', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL') 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 raw_output. and the full output is passed in to artifact.
.. versionadded:: 0.2.17
.. code-block:: python .. code-block:: python
@ -6428,7 +6434,7 @@
ToolMessage( ToolMessage(
content=tool_output["stdout"], content=tool_output["stdout"],
raw_output=tool_output, artifact=tool_output,
tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL',
) )
@ -6441,6 +6447,9 @@
'title': 'Additional Kwargs', 'title': 'Additional Kwargs',
'type': 'object', 'type': 'object',
}), }),
'artifact': dict({
'title': 'Artifact',
}),
'content': dict({ 'content': dict({
'anyOf': list([ 'anyOf': list([
dict({ dict({
@ -6470,9 +6479,6 @@
'title': 'Name', 'title': 'Name',
'type': 'string', 'type': 'string',
}), }),
'raw_output': dict({
'title': 'Raw Output',
}),
'response_metadata': dict({ 'response_metadata': dict({
'title': 'Response Metadata', 'title': 'Response Metadata',
'type': 'object', 'type': 'object',
@ -7002,8 +7008,11 @@
ToolMessage(content='42', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL') 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 raw_output. and the full output is passed in to artifact.
.. versionadded:: 0.2.17
.. code-block:: python .. code-block:: python
@ -7017,7 +7026,7 @@
ToolMessage( ToolMessage(
content=tool_output["stdout"], content=tool_output["stdout"],
raw_output=tool_output, artifact=tool_output,
tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL',
) )
@ -7030,6 +7039,9 @@
'title': 'Additional Kwargs', 'title': 'Additional Kwargs',
'type': 'object', 'type': 'object',
}), }),
'artifact': dict({
'title': 'Artifact',
}),
'content': dict({ 'content': dict({
'anyOf': list([ 'anyOf': list([
dict({ dict({
@ -7059,9 +7071,6 @@
'title': 'Name', 'title': 'Name',
'type': 'string', 'type': 'string',
}), }),
'raw_output': dict({
'title': 'Raw Output',
}),
'response_metadata': dict({ 'response_metadata': dict({
'title': 'Response Metadata', 'title': 'Response Metadata',
'type': 'object', 'type': 'object',
@ -7648,8 +7657,11 @@
ToolMessage(content='42', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL') 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 raw_output. and the full output is passed in to artifact.
.. versionadded:: 0.2.17
.. code-block:: python .. code-block:: python
@ -7663,7 +7675,7 @@
ToolMessage( ToolMessage(
content=tool_output["stdout"], content=tool_output["stdout"],
raw_output=tool_output, artifact=tool_output,
tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL',
) )
@ -7676,6 +7688,9 @@
'title': 'Additional Kwargs', 'title': 'Additional Kwargs',
'type': 'object', 'type': 'object',
}), }),
'artifact': dict({
'title': 'Artifact',
}),
'content': dict({ 'content': dict({
'anyOf': list([ 'anyOf': list([
dict({ dict({
@ -7705,9 +7720,6 @@
'title': 'Name', 'title': 'Name',
'type': 'string', 'type': 'string',
}), }),
'raw_output': dict({
'title': 'Raw Output',
}),
'response_metadata': dict({ 'response_metadata': dict({
'title': 'Response Metadata', 'title': 'Response Metadata',
'type': 'object', 'type': 'object',
@ -8297,8 +8309,11 @@
ToolMessage(content='42', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL') 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 raw_output. and the full output is passed in to artifact.
.. versionadded:: 0.2.17
.. code-block:: python .. code-block:: python
@ -8312,7 +8327,7 @@
ToolMessage( ToolMessage(
content=tool_output["stdout"], content=tool_output["stdout"],
raw_output=tool_output, artifact=tool_output,
tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL',
) )
@ -8325,6 +8340,9 @@
'title': 'Additional Kwargs', 'title': 'Additional Kwargs',
'type': 'object', 'type': 'object',
}), }),
'artifact': dict({
'title': 'Artifact',
}),
'content': dict({ 'content': dict({
'anyOf': list([ 'anyOf': list([
dict({ dict({
@ -8354,9 +8372,6 @@
'title': 'Name', 'title': 'Name',
'type': 'string', 'type': 'string',
}), }),
'raw_output': dict({
'title': 'Raw Output',
}),
'response_metadata': dict({ 'response_metadata': dict({
'title': 'Response Metadata', 'title': 'Response Metadata',
'type': 'object', 'type': 'object',
@ -8893,8 +8908,11 @@
ToolMessage(content='42', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL') 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 raw_output. and the full output is passed in to artifact.
.. versionadded:: 0.2.17
.. code-block:: python .. code-block:: python
@ -8908,7 +8926,7 @@
ToolMessage( ToolMessage(
content=tool_output["stdout"], content=tool_output["stdout"],
raw_output=tool_output, artifact=tool_output,
tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL',
) )
@ -8921,6 +8939,9 @@
'title': 'Additional Kwargs', 'title': 'Additional Kwargs',
'type': 'object', 'type': 'object',
}), }),
'artifact': dict({
'title': 'Artifact',
}),
'content': dict({ 'content': dict({
'anyOf': list([ 'anyOf': list([
dict({ dict({
@ -8950,9 +8971,6 @@
'title': 'Name', 'title': 'Name',
'type': 'string', 'type': 'string',
}), }),
'raw_output': dict({
'title': 'Raw Output',
}),
'response_metadata': dict({ 'response_metadata': dict({
'title': 'Response Metadata', 'title': 'Response Metadata',
'type': 'object', 'type': 'object',
@ -9462,8 +9480,11 @@
ToolMessage(content='42', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL') 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 raw_output. and the full output is passed in to artifact.
.. versionadded:: 0.2.17
.. code-block:: python .. code-block:: python
@ -9477,7 +9498,7 @@
ToolMessage( ToolMessage(
content=tool_output["stdout"], content=tool_output["stdout"],
raw_output=tool_output, artifact=tool_output,
tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL',
) )
@ -9490,6 +9511,9 @@
'title': 'Additional Kwargs', 'title': 'Additional Kwargs',
'type': 'object', 'type': 'object',
}), }),
'artifact': dict({
'title': 'Artifact',
}),
'content': dict({ 'content': dict({
'anyOf': list([ 'anyOf': list([
dict({ dict({
@ -9519,9 +9543,6 @@
'title': 'Name', 'title': 'Name',
'type': 'string', 'type': 'string',
}), }),
'raw_output': dict({
'title': 'Raw Output',
}),
'response_metadata': dict({ 'response_metadata': dict({
'title': 'Response Metadata', 'title': 'Response Metadata',
'type': 'object', 'type': 'object',
@ -10140,8 +10161,11 @@
ToolMessage(content='42', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL') 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 raw_output. and the full output is passed in to artifact.
.. versionadded:: 0.2.17
.. code-block:: python .. code-block:: python
@ -10155,7 +10179,7 @@
ToolMessage( ToolMessage(
content=tool_output["stdout"], content=tool_output["stdout"],
raw_output=tool_output, artifact=tool_output,
tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL', tool_call_id='call_Jja7J89XsjrOLA5r!MEOW!SL',
) )
@ -10168,6 +10192,9 @@
'title': 'Additional Kwargs', 'title': 'Additional Kwargs',
'type': 'object', 'type': 'object',
}), }),
'artifact': dict({
'title': 'Artifact',
}),
'content': dict({ 'content': dict({
'anyOf': list([ 'anyOf': list([
dict({ dict({
@ -10197,9 +10224,6 @@
'title': 'Name', 'title': 'Name',
'type': 'string', 'type': 'string',
}), }),
'raw_output': dict({
'title': 'Raw Output',
}),
'response_metadata': dict({ 'response_metadata': dict({
'title': 'Response Metadata', 'title': 'Response Metadata',
'type': 'object', 'type': 'object',

View File

@ -662,7 +662,7 @@ def test_convert_to_messages() -> None:
"role": "tool", "role": "tool",
"tool_call_id": "tool_id2", "tool_call_id": "tool_id2",
"content": "Bye!", "content": "Bye!",
"raw_output": {"foo": 123}, "artifact": {"foo": 123},
}, },
{"role": "remove", "id": "message_to_remove", "content": ""}, {"role": "remove", "id": "message_to_remove", "content": ""},
] ]
@ -685,7 +685,7 @@ def test_convert_to_messages() -> None:
tool_calls=[ToolCall(name="greet", args={"name": "Jane"}, id="tool_id")], tool_calls=[ToolCall(name="greet", args={"name": "Jane"}, id="tool_id")],
), ),
ToolMessage(tool_call_id="tool_id", content="Hi!"), ToolMessage(tool_call_id="tool_id", content="Hi!"),
ToolMessage(tool_call_id="tool_id2", content="Bye!", raw_output={"foo": 123}), ToolMessage(tool_call_id="tool_id2", content="Bye!", artifact={"foo": 123}),
RemoveMessage(id="message_to_remove"), RemoveMessage(id="message_to_remove"),
] ]
assert expected == actual assert expected == actual
@ -787,7 +787,7 @@ def test_merge_tool_calls() -> None:
def test_tool_message_serdes() -> None: def test_tool_message_serdes() -> None:
message = ToolMessage("foo", raw_output={"bar": {"baz": 123}}, tool_call_id="1") message = ToolMessage("foo", artifact={"bar": {"baz": 123}}, tool_call_id="1")
ser_message = { ser_message = {
"lc": 1, "lc": 1,
"type": "constructor", "type": "constructor",
@ -796,7 +796,7 @@ def test_tool_message_serdes() -> None:
"content": "foo", "content": "foo",
"type": "tool", "type": "tool",
"tool_call_id": "1", "tool_call_id": "1",
"raw_output": {"bar": {"baz": 123}}, "artifact": {"bar": {"baz": 123}},
}, },
} }
assert dumpd(message) == ser_message assert dumpd(message) == ser_message
@ -809,7 +809,7 @@ class BadObject:
def test_tool_message_ser_non_serializable() -> None: def test_tool_message_ser_non_serializable() -> None:
bad_obj = BadObject() bad_obj = BadObject()
message = ToolMessage("foo", raw_output=bad_obj, tool_call_id="1") message = ToolMessage("foo", artifact=bad_obj, tool_call_id="1")
ser_message = { ser_message = {
"lc": 1, "lc": 1,
"type": "constructor", "type": "constructor",
@ -818,7 +818,7 @@ def test_tool_message_ser_non_serializable() -> None:
"content": "foo", "content": "foo",
"type": "tool", "type": "tool",
"tool_call_id": "1", "tool_call_id": "1",
"raw_output": { "artifact": {
"lc": 1, "lc": 1,
"type": "not_implemented", "type": "not_implemented",
"id": ["tests", "unit_tests", "test_messages", "BadObject"], "id": ["tests", "unit_tests", "test_messages", "BadObject"],
@ -832,14 +832,14 @@ def test_tool_message_ser_non_serializable() -> None:
def test_tool_message_to_dict() -> None: def test_tool_message_to_dict() -> None:
message = ToolMessage("foo", raw_output={"bar": {"baz": 123}}, tool_call_id="1") message = ToolMessage("foo", artifact={"bar": {"baz": 123}}, tool_call_id="1")
expected = { expected = {
"type": "tool", "type": "tool",
"data": { "data": {
"content": "foo", "content": "foo",
"additional_kwargs": {}, "additional_kwargs": {},
"response_metadata": {}, "response_metadata": {},
"raw_output": {"bar": {"baz": 123}}, "artifact": {"bar": {"baz": 123}},
"type": "tool", "type": "tool",
"name": None, "name": None,
"id": None, "id": None,
@ -851,16 +851,16 @@ def test_tool_message_to_dict() -> None:
def test_tool_message_repr() -> None: def test_tool_message_repr() -> None:
message = ToolMessage("foo", raw_output={"bar": {"baz": 123}}, tool_call_id="1") message = ToolMessage("foo", artifact={"bar": {"baz": 123}}, tool_call_id="1")
expected = ( expected = (
"ToolMessage(content='foo', tool_call_id='1', raw_output={'bar': {'baz': 123}})" "ToolMessage(content='foo', tool_call_id='1', artifact={'bar': {'baz': 123}})"
) )
actual = repr(message) actual = repr(message)
assert expected == actual assert expected == actual
def test_tool_message_str() -> None: def test_tool_message_str() -> None:
message = ToolMessage("foo", raw_output={"bar": {"baz": 123}}, tool_call_id="1") message = ToolMessage("foo", artifact={"bar": {"baz": 123}}, tool_call_id="1")
expected = "content='foo' tool_call_id='1' raw_output={'bar': {'baz': 123}}" expected = "content='foo' tool_call_id='1' artifact={'bar': {'baz': 123}}"
actual = str(message) actual = str(message)
assert expected == actual assert expected == actual

View File

@ -1150,7 +1150,7 @@ class _MockStructuredToolWithRawOutput(BaseTool):
name: str = "structured_api" name: str = "structured_api"
args_schema: Type[BaseModel] = _MockSchema args_schema: Type[BaseModel] = _MockSchema
description: str = "A Structured Tool" description: str = "A Structured Tool"
response_format: Literal["content_and_raw_output"] = "content_and_raw_output" response_format: Literal["content_and_artifact"] = "content_and_artifact"
def _run( def _run(
self, arg1: int, arg2: bool, arg3: Optional[dict] = None self, arg1: int, arg2: bool, arg3: Optional[dict] = None
@ -1158,8 +1158,8 @@ class _MockStructuredToolWithRawOutput(BaseTool):
return f"{arg1} {arg2}", {"arg1": arg1, "arg2": arg2, "arg3": arg3} return f"{arg1} {arg2}", {"arg1": arg1, "arg2": arg2, "arg3": arg3}
@tool("structured_api", response_format="content_and_raw_output") @tool("structured_api", response_format="content_and_artifact")
def _mock_structured_tool_with_raw_output( def _mock_structured_tool_with_artifact(
arg1: int, arg2: bool, arg3: Optional[dict] = None arg1: int, arg2: bool, arg3: Optional[dict] = None
) -> Tuple[str, dict]: ) -> Tuple[str, dict]:
"""A Structured Tool""" """A Structured Tool"""
@ -1167,16 +1167,16 @@ def _mock_structured_tool_with_raw_output(
@pytest.mark.parametrize( @pytest.mark.parametrize(
"tool", [_MockStructuredToolWithRawOutput(), _mock_structured_tool_with_raw_output] "tool", [_MockStructuredToolWithRawOutput(), _mock_structured_tool_with_artifact]
) )
def test_tool_call_input_tool_message_with_raw_output(tool: BaseTool) -> None: def test_tool_call_input_tool_message_with_artifact(tool: BaseTool) -> None:
tool_call: Dict = { tool_call: Dict = {
"name": "structured_api", "name": "structured_api",
"args": {"arg1": 1, "arg2": True, "arg3": {"img": "base64string..."}}, "args": {"arg1": 1, "arg2": True, "arg3": {"img": "base64string..."}},
"id": "123", "id": "123",
"type": "tool_call", "type": "tool_call",
} }
expected = ToolMessage("1 True", raw_output=tool_call["args"], tool_call_id="123") expected = ToolMessage("1 True", artifact=tool_call["args"], tool_call_id="123")
actual = tool.invoke(tool_call) actual = tool.invoke(tool_call)
assert actual == expected assert actual == expected

View File

@ -127,7 +127,7 @@ class SessionsPythonREPLTool(BaseTool):
session_id: str = str(uuid4()) session_id: str = str(uuid4())
"""The session ID to use for the code interpreter. Defaults to a random UUID.""" """The session ID to use for the code interpreter. Defaults to a random UUID."""
response_format: Literal["content_and_raw_output"] = "content_and_raw_output" response_format: Literal["content_and_artifact"] = "content_and_artifact"
def _build_url(self, path: str) -> str: def _build_url(self, path: str) -> str:
pool_management_endpoint = self.pool_management_endpoint pool_management_endpoint = self.pool_management_endpoint