mirror of
https://github.com/AstrBotDevs/AstrBot.git
synced 2026-09-24 16:39:52 +08:00
fix(agent): pass tool_call_timeout to subagent handsoff, cron and background task execution, and increase default timeout from 60 to 120 (#6713)
* fix(agent): pass tool_call_timeout to SubAgent handoff execution - Add tool_call_timeout parameter to _execute_handoff method - Pass run_context.tool_call_timeout to ctx.tool_loop_agent - Add unit test to verify tool_call_timeout is correctly passed - Fixes #6711: SubAgent MCP tool call timeout now respects configured timeout The SubAgent handoff execution was using the default 60-second timeout instead of the configured tool_call_timeout from provider settings. This change ensures that SubAgent MCP tool calls respect the user's configured timeout settings. * test: add unit test for tool_call_timeout in SubAgent handoff * fix: restore deleted test and fix test assertion - Restore test_collect_handoff_image_urls_filters_extensionless_missing_event_file - Fix test_collect_handoff_image_urls_keeps_extensionless_existing_event_file assertion - Keep new test_execute_handoff_passes_tool_call_timeout_to_tool_loop_agent * refactor: simplify tool_call_timeout passing in _execute_handoff - Pass run_context.tool_call_timeout directly to ctx.tool_loop_agent - Remove unnecessary local variable assignment - Addresses review feedback from Sourcery AI * fix(config): increase default tool call timeout from 60 to 120 seconds --------- Co-authored-by: LehaoLin <linlehao@cuhk.edu.cn> Co-authored-by: Soulter <905617992@qq.com>
This commit is contained in:
co-authored by
LehaoLin
Soulter
parent
b273ba2a19
commit
8d9838a293
@@ -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]
|
||||
|
||||
@@ -303,6 +303,7 @@ class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]):
|
||||
tools=toolset,
|
||||
contexts=contexts,
|
||||
max_steps=agent_max_step,
|
||||
tool_call_timeout=run_context.tool_call_timeout,
|
||||
stream=stream,
|
||||
)
|
||||
yield mcp.types.CallToolResult(
|
||||
@@ -481,7 +482,7 @@ class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]):
|
||||
)
|
||||
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),
|
||||
|
||||
@@ -117,7 +117,7 @@ DEFAULT_CONFIG = {
|
||||
"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
|
||||
|
||||
@@ -307,8 +307,11 @@ class CronJobManager:
|
||||
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,
|
||||
)
|
||||
|
||||
@@ -378,7 +378,7 @@ class ThirdPartyAgentSubStage(Stage):
|
||||
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,
|
||||
|
||||
@@ -153,7 +153,7 @@ class Context:
|
||||
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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -272,6 +272,55 @@ async def test_collect_handoff_image_urls_filters_extensionless_missing_event_fi
|
||||
assert 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,
|
||||
|
||||
Reference in New Issue
Block a user