Rebase onto upstream (a4d95fd)
#12
+45
-1
@@ -21,6 +21,7 @@ from nanobot.agent.tools.message import MessageTool
|
|||||||
from nanobot.agent.tools.spawn import SpawnTool
|
from nanobot.agent.tools.spawn import SpawnTool
|
||||||
from nanobot.agent.tools.wait import WaitForSubagentsTool
|
from nanobot.agent.tools.wait import WaitForSubagentsTool
|
||||||
from nanobot.agent.tools.cron import CronTool
|
from nanobot.agent.tools.cron import CronTool
|
||||||
|
from nanobot.agent.tools.anthropic.base import ToolResult, CLIResult
|
||||||
from nanobot.agent.memory import MemoryStore
|
from nanobot.agent.memory import MemoryStore
|
||||||
from nanobot.agent.subagent import SubagentManager
|
from nanobot.agent.subagent import SubagentManager
|
||||||
from nanobot.agent.visibility import sign_content, has_forged_marker, strip_all_hidden_markers
|
from nanobot.agent.visibility import sign_content, has_forged_marker, strip_all_hidden_markers
|
||||||
@@ -395,8 +396,51 @@ class AgentLoop:
|
|||||||
args_str = json.dumps(tool_call.arguments, ensure_ascii=False)
|
args_str = json.dumps(tool_call.arguments, ensure_ascii=False)
|
||||||
logger.info(f"Tool call: {tool_call.name}({args_str[:200]})")
|
logger.info(f"Tool call: {tool_call.name}({args_str[:200]})")
|
||||||
result = await self.tools.execute(tool_call.name, tool_call.arguments)
|
result = await self.tools.execute(tool_call.name, tool_call.arguments)
|
||||||
|
|
||||||
|
# Handle different result types
|
||||||
|
if isinstance(result, ToolResult):
|
||||||
|
# Native Anthropic tool result
|
||||||
|
content_parts = []
|
||||||
|
|
||||||
|
# Add text content
|
||||||
|
if result.output:
|
||||||
|
text_content = result.output
|
||||||
|
elif result.error:
|
||||||
|
text_content = f"Error: {result.error}"
|
||||||
|
else:
|
||||||
|
text_content = ""
|
||||||
|
|
||||||
|
# If both output and error, combine them
|
||||||
|
if result.output and result.error:
|
||||||
|
text_content = f"{result.output}\n\nError: {result.error}"
|
||||||
|
|
||||||
|
# If there's an image, use multipart content
|
||||||
|
if result.base64_image:
|
||||||
|
content_parts = [
|
||||||
|
{"type": "text", "text": text_content},
|
||||||
|
{
|
||||||
|
"type": "image",
|
||||||
|
"source": {
|
||||||
|
"type": "base64",
|
||||||
|
"media_type": "image/png",
|
||||||
|
"data": result.base64_image,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
tool_content = content_parts
|
||||||
|
else:
|
||||||
|
tool_content = text_content
|
||||||
|
|
||||||
|
elif isinstance(result, CLIResult):
|
||||||
|
# CLI-style tool result (text editor)
|
||||||
|
tool_content = result.output
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Legacy string result from function tools
|
||||||
|
tool_content = result
|
||||||
|
|
||||||
messages = self.context.add_tool_result(
|
messages = self.context.add_tool_result(
|
||||||
messages, tool_call.id, tool_call.name, result
|
messages, tool_call.id, tool_call.name, tool_content
|
||||||
)
|
)
|
||||||
# Interleaved CoT: reflect before next action (skip when thinking is active)
|
# Interleaved CoT: reflect before next action (skip when thinking is active)
|
||||||
if not getattr(self.provider, 'thinking_budget', 0):
|
if not getattr(self.provider, 'thinking_budget', 0):
|
||||||
|
|||||||
Reference in New Issue
Block a user