agentscope-ai / agentscope-ai/agentscope
[Bug]:ToolOffloadMiddleware Prematurely Terminates Conversation When Tools Are Offloaded
- 主要语言
- Python
- 星标
- 31.5k
- 派生
- 3.5k
- 平均合并
- 1 天 23 小时
- 30 天内合并 PR
- 95
描述
# Bug Report: ToolOffloadMiddleware Prematurely Terminates Conversation When Tools Are Offloaded
**Describe the bug**
When a tool execution exceeds the default timeout (10 seconds), `ToolOffloadMiddleware` offloads the tool to background and returns a synthetic `ToolResponse` with state `SUCCESS`. This causes the agent's ReAct loop to incorrectly assume the task is complete and exit prematurely, even though the background tool is still running. When the background tool finally completes, the retrigger mechanism fails to properly resume the conversation because:
1. The injected result is a `HintBlock` (plain text notification) rather than a proper `ToolResultBlock`
2. The agent has already exited the ReAct loop and session is no longer running
3. The conversation ends with incomplete/truncated responses
This is a critical bug in the `ToolOffloadMiddleware` design - the offloaded tool response should not be marked as `SUCCESS`, and the retrigger mechanism cannot reliably resume agent execution.
**To Reproduce**
Steps to reproduce the behavior:
1. Create an agent with a tool that takes longer than 10 seconds to execute (e.g., a file writing tool with large content, or a tool with sleep/delay)
2. Configure the agent via Web UI with default settings:
```python
from agentscope.app import create_app
from agentscope.app.storage import RedisStorage
app = create_app(storage=RedisStorage())
# ToolOffloadMiddleware is automatically added with default timeout_secs=10.0
```
3. Send a message that triggers the slow tool execution via Web UI chat
4. Observe the behavior:
- After ~10 seconds, the tool is offloaded to background
- Agent receives a synthetic `ToolResponse` with placeholder text: "Tool 'xxx' is taking longer than expected..."
- Agent incorrectly assumes task is complete and generates a final response
- Conversation ends prematurely
- The actual background tool result arrives later but cannot be properly injected
**Expected behavior**
When a tool execution times out and is offloaded to background:
1. The agent should NOT mark the tool call as `SUCCESS` or exit the ReAct loop
2. The agent should either:
- Wait for the background tool to complete (blocking execution)
- Continue with other tool calls while the offloaded tool runs in background
- Properly handle the injected `ToolResultBlock` when retriggered after background completion
3. The conversation should NOT end until all tools (including offloaded ones) have completed and their results have been properly processed
4. The retrigger mechanism should reliably resume agent execution and inject actual tool results (not just hint text)
**Error messages**
No explicit error is raised, but the following log messages indicate the bug:
```
Tool 'Write' timed out after 10.0s, offloading to background: session_id=xxx, agent_id=xxx
Synthetic ToolResponse yielded for offloaded tool 'Write': task_id=xxx
Background tool 'Write' completed, pushing result to pending hints: session_id=xxx
Session idle after background tool 'Write' completed, triggering re-invocation: session_id=xxx
```
The final response in Web UI shows:
- Tool call is displayed but result is truncated or missing
- Response ends with incomplete message
- No continuation after tool execution
**Environment (please complete the following information):**
- AgentScope Version: 2.0.0
- Python Version: 3.13
- OS: Linux (Ubuntu/Debian)
**Additional context**
This bug affects any agent that uses tools which may take longer than 10 seconds, including:
- File I/O operations with large content
- API calls to external services with high latency
- Complex computations or data processing
**Root Cause Analysis:**
The issue is in `/agentscope/app/_middleware/_tool_offload_middleware.py`:
1. **Line 404-412**: When timeout occurs, middleware yields a `ToolChunk` and `ToolResponse` with `state=ToolResultState.SUCCESS`, which incorrectly signals completion to the ReAct loop
2. **Line 307-376**: The `_on_complete` callback pushes a `HintBlock` (plain text) rather than a proper `ToolResultBlock`, which the agent cannot properly interpret as a tool result
3. **Line 357-376**: The retrigger mechanism checks `session_manager.is_running(session_id)`, but by the time the background tool completes, the session has already exited, making retrigger unreliable
**Workaround:**
Set a very large timeout to effectively disable offloading:
```bash
export TOOL_OFFLOAD_TIMEOUT=3600 # 1 hour
```
However, this is not a proper fix. The middleware should be redesigned to handle offloaded tools correctly without prematurely terminating the conversation.
**Suggested Fix:**
1. Add a new `ToolResultState.OFFLOADED` or `PENDING` state
2. Modify `_check_next_action()` in `Agent._reply_impl()` to not exit when there are offloaded/pending tool calls
3. Change `_on_complete()` to inject a proper `ToolResultBlock` instead of `HintBlock`
4. Ensure retrigger can reliably resume the ReAct loop even after session completion
贡献指南
评估
这个 Issue 还没有评估数据。