Skip to content

Commit df45d2f

Browse files
feat: control display of tool execution results to llm (#920)
1 parent 618bbcd commit df45d2f

File tree

3 files changed

+34
-10
lines changed

3 files changed

+34
-10
lines changed

packages/ragbits-agents/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
- Add supervisor post-processor (#830)
1818
- Add support for todo lists generated by agents with examples (#827)
1919
- Add long-term semantic memory tools for agents (#839)
20+
- Add control over what output from the tool is passed to the LLM (#920)
2021
- Add support for confirmation requests in agents (#853) (#914)
2122
- Add hooks system (pre- and post-tool) for lifecycle event interception (#914)
2223

packages/ragbits-agents/src/ragbits/agents/_main.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
StreamingPostProcessor,
4343
stream_with_post_processing,
4444
)
45-
from ragbits.agents.tool import Tool, ToolCallResult, ToolChoice
45+
from ragbits.agents.tool import Tool, ToolCallResult, ToolChoice, ToolReturn
4646
from ragbits.core.audit.traces import trace
4747
from ragbits.core.llms.base import (
4848
LLM,
@@ -538,7 +538,9 @@ async def _run_without_post_processing(
538538
):
539539
if isinstance(result, ToolCallResult):
540540
tool_calls.append(result)
541-
prompt_with_history = prompt_with_history.add_tool_use_message(**result.__dict__)
541+
prompt_with_history = prompt_with_history.add_tool_use_message(
542+
id=result.id, name=result.name, arguments=result.arguments, result=result.result
543+
)
542544

543545
turn_count += 1
544546
else:
@@ -764,7 +766,9 @@ async def _stream_internal( # noqa: PLR0912, PLR0915
764766
elif isinstance(result, ToolCallResult):
765767
# Add ALL tool results to history (including pending confirmations)
766768
# This allows the agent to see them in the next turn
767-
prompt_with_history = prompt_with_history.add_tool_use_message(**result.__dict__)
769+
prompt_with_history = prompt_with_history.add_tool_use_message(
770+
id=result.id, name=result.name, arguments=result.arguments, result=result.result
771+
)
768772
returned_tool_call = True
769773

770774
# If we have pending confirmations, prepare for text-only summary generation
@@ -1004,20 +1008,23 @@ async def _execute_tool(
10041008
else asyncio.to_thread(tool.on_tool_call, **call_args)
10051009
)
10061010

1007-
if isinstance(tool_output, AgentResultStreaming):
1011+
if isinstance(tool_output, ToolReturn):
1012+
tool_return = tool_output
1013+
elif isinstance(tool_output, AgentResultStreaming):
10081014
async for downstream_item in tool_output:
10091015
if context.stream_downstream_events:
10101016
yield DownstreamAgentResult(agent_id=tool.id, item=downstream_item)
1011-
1012-
tool_output = {
1013-
"content": tool_output.content,
1017+
metadata = {
10141018
"metadata": tool_output.metadata,
10151019
"tool_calls": tool_output.tool_calls,
10161020
"usage": tool_output.usage,
10171021
}
1022+
tool_return = ToolReturn(value=tool_output.content, metadata=metadata)
1023+
else:
1024+
tool_return = ToolReturn(value=tool_output, metadata=None)
10181025

10191026
outputs.result = {
1020-
"tool_output": tool_output,
1027+
"tool_output": tool_return.value,
10211028
"tool_call_id": tool_call.id,
10221029
}
10231030

@@ -1044,7 +1051,8 @@ async def _execute_tool(
10441051
id=tool_call.id,
10451052
name=tool_call.name,
10461053
arguments=tool_call.arguments,
1047-
result=tool_output,
1054+
result=tool_return.value,
1055+
metadata=tool_return.metadata,
10481056
)
10491057

10501058
@requires_dependencies(["a2a.types"], "a2a")

packages/ragbits-agents/src/ragbits/agents/tool.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,19 @@
1818
from pydantic_ai import Tool as PydanticAITool
1919

2020

21+
@dataclass
22+
class ToolReturn:
23+
"""
24+
Represents an object returned from the tool. If a tool wants to return a value with some content hidden
25+
from LLM, it needs to return an object of this class directly.
26+
"""
27+
28+
value: Any
29+
"Value passed directly to LLM as a result of the tool"
30+
metadata: Any = None
31+
"Metadata not passed to the LLM, but which can be used in the application later on"
32+
33+
2134
@dataclass
2235
class ToolCallResult:
2336
"""
@@ -31,7 +44,9 @@ class ToolCallResult:
3144
arguments: dict[str, Any]
3245
"""Dictionary containing the arguments passed to the tool"""
3346
result: Any
34-
"""The output from the tool call."""
47+
"""The output from the tool call passed to the LLM"""
48+
metadata: Any = None
49+
"""Metadata returned from a tool that is not meant to be seen by the LLM"""
3550

3651

3752
@dataclass

0 commit comments

Comments
 (0)