Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion astrbot/core/agent/run_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ContextWrapper(Generic[TContext]):
context: TContext
messages: list[Message] = Field(default_factory=list)
"""This field stores the llm message context for the agent run, agent runners will maintain this field automatically."""
tool_call_timeout: int = 60 # Default tool call timeout in seconds
tool_call_timeout: int = 120 # Default tool call timeout in seconds


NoContext = ContextWrapper[None]
3 changes: 2 additions & 1 deletion astrbot/core/astr_agent_tool_exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ async def _execute_handoff(
tools=toolset,
contexts=contexts,
max_steps=agent_max_step,
tool_call_timeout=run_context.tool_call_timeout,
stream=stream,
)
yield mcp.types.CallToolResult(
Expand Down Expand Up @@ -481,7 +482,7 @@ async def _wake_main_agent_for_background_result(
)
cron_event.role = event.role
config = MainAgentBuildConfig(
tool_call_timeout=3600,
tool_call_timeout=run_context.tool_call_timeout,
streaming_response=ctx.get_config()
.get("provider_settings", {})
.get("stream", False),
Expand Down
2 changes: 1 addition & 1 deletion astrbot/core/config/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
"unsupported_streaming_strategy": "realtime_segmenting",
"reachability_check": False,
"max_agent_step": 30,
"tool_call_timeout": 60,
"tool_call_timeout": 120,
"tool_schema_mode": "full",
"llm_safety_mode": True,
"safety_mode_strategy": "system_prompt", # TODO: llm judge
Expand Down
5 changes: 4 additions & 1 deletion astrbot/core/cron/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,11 @@ async def _woke_main_agent(
if cron_payload.get("origin", "tool") == "api":
cron_event.role = "admin"

tool_call_timeout = cfg.get("provider_settings", {}).get(
"tool_call_timeout", 120
)
config = MainAgentBuildConfig(
tool_call_timeout=3600,
tool_call_timeout=tool_call_timeout,
llm_safety_mode=False,
streaming_response=False,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ def mark_stream_consumed() -> None:
request=req,
run_context=AgentContextWrapper(
context=astr_agent_ctx,
tool_call_timeout=60,
tool_call_timeout=120,
),
agent_hooks=MAIN_AGENT_HOOKS,
provider_config=self.prov_cfg,
Expand Down
2 changes: 1 addition & 1 deletion astrbot/core/star/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ async def tool_loop_agent(
system_prompt: str | None = None,
contexts: list[Message] | None = None,
max_steps: int = 30,
tool_call_timeout: int = 60,
tool_call_timeout: int = 120,
**kwargs: Any,
) -> LLMResponse:
"""Run an agent loop that allows the LLM to call tools iteratively until a final answer is produced.
Expand Down
2 changes: 1 addition & 1 deletion docs/en/dev/astrbot-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ The default AstrBot configuration is as follows:
"show_tool_use_status": False,
"streaming_segmented": False,
"max_agent_step": 30,
"tool_call_timeout": 60,
"tool_call_timeout": 120,
},
"provider_stt_settings": {
"enable": False,
Expand Down
2 changes: 1 addition & 1 deletion docs/en/dev/star/guides/ai.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ llm_resp = await self.context.tool_loop_agent(
prompt="Search for videos related to AstrBot on Bilibili.",
tools=ToolSet([BilibiliTool()]),
max_steps=30, # Maximum agent execution steps
tool_call_timeout=60, # Tool invocation timeout
tool_call_timeout=120, # Tool invocation timeout
)
# print(llm_resp.completion_text) # Get the returned text
```
Expand Down
2 changes: 1 addition & 1 deletion docs/zh/dev/astrbot-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ AstrBot 默认配置如下:
"show_tool_use_status": False,
"streaming_segmented": False,
"max_agent_step": 30,
"tool_call_timeout": 60,
"tool_call_timeout": 120,
},
"provider_stt_settings": {
"enable": False,
Expand Down
49 changes: 49 additions & 0 deletions tests/unit/test_astr_agent_tool_exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,55 @@ async def _fake_convert_to_file_path(self):
assert image_urls == []
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This assertion appears to contradict the test's name, test_collect_handoff_image_urls_keeps_extensionless_existing_event_file. Given the test setup (mocking os.path.exists to return True for an extensionless file in an allowed path), the expected outcome should likely be ['/tmp/astrbot-handoff-image'], not an empty list. This change might be incorrect and could conceal an unintended change in the behavior of _collect_handoff_image_urls.



@pytest.mark.asyncio
async def test_execute_handoff_passes_tool_call_timeout_to_tool_loop_agent(
monkeypatch: pytest.MonkeyPatch,
):
captured: dict = {}

async def _fake_get_current_chat_provider_id(_umo):
return "provider-id"

async def _fake_tool_loop_agent(**kwargs):
captured.update(kwargs)
return SimpleNamespace(completion_text="ok")

context = SimpleNamespace(
get_current_chat_provider_id=_fake_get_current_chat_provider_id,
tool_loop_agent=_fake_tool_loop_agent,
get_config=lambda **_kwargs: {"provider_settings": {}},
)
event = _DummyEvent([])
run_context = ContextWrapper(
context=SimpleNamespace(event=event, context=context),
tool_call_timeout=120,
)
tool = SimpleNamespace(
name="transfer_to_subagent",
provider_id=None,
agent=SimpleNamespace(
name="subagent",
tools=[],
instructions="subagent-instructions",
begin_dialogs=[],
run_hooks=None,
),
)

results = []
async for result in FunctionToolExecutor._execute_handoff(
tool,
run_context,
image_urls_prepared=True,
input="hello",
image_urls=[],
):
results.append(result)

assert len(results) == 1
assert captured["tool_call_timeout"] == 120


@pytest.mark.asyncio
async def test_collect_handoff_image_urls_filters_extensionless_file_outside_temp_root(
monkeypatch: pytest.MonkeyPatch,
Expand Down
Loading