agentscope-ai / agentscope-ai/QwenPaw
[Bug]: Long-running shell commands bypass shell_command_timeout and block the feishu session indefinitely (orphan subprocess on cancel, no per-channel total timeout)
- Vorherrschende Sprache
- Python
- Sterne
- 34.9k
- Forks
- 3.1k
- Ø Merge
- 1 T. 15 Std.
- Gemergte PRs (30 T.)
- 225
Beschreibung
## Summary
A long-running `execute_shell_command` (a dedup script hitting the Feishu Bitable API) blocked a feishu chat session for **1.5 hours**. The user's follow-up messages were received but never processed (queued behind the stuck task). The session only recovered after the system cancelled the task; however the spawned shell subprocess **survived the cancellation** and kept running until manually killed.
Three mechanism-level gaps are involved:
### 1. Explicit LLM-provided `timeout` bypasses `shell_command_timeout`
`agents/tools/shell.py` (~line 568):
```python
# Apply agent-configured default when the caller used the hardcoded
# default (60.0). An explicit LLM-provided value != 60.0 is kept.
if timeout == 60.0:
configured = get_current_shell_command_timeout()
if configured is not None:
timeout = configured
```
If the agent explicitly passes `timeout=3600` (or larger), the configured default `shell_command_timeout: 60.0` is silently ignored. There is **no upper bound** on what an LLM can request. A single tool call can therefore run for hours.
### 2. Cancellation does not kill the spawned subprocess (orphan)
When the session task was cancelled (`cancel_cleanup: cancelled ... CancelledError`), the asyncio task was cancelled but the already-spawned `python3 dedup_bitable.py` process **kept running** (PID survived from 15:34 until manually killed at ~17:07). The `except (asyncio.TimeoutError, asyncio.CancelledError)` branch in `shell.py` only runs when the *tool-internal* timeout/cancel fires; an external session-level cancellation (error_hook `cancel_cleanup`) does not reach the subprocess. Result: orphan processes keep consuming resources after the turn is cancelled.
### 3. Feishu channel has no total task timeout fallback
`task_timeout_ms: 3600000` is configured only for the `xiaoyi` channel in `agent.json`. The feishu channel has no equivalent, so there is no last-resort upper bound on how long a single turn can block the session queue. New messages are queued with no feedback to the user.
## Impact
- A feishu chat becomes unresponsive for arbitrarily long (observed 1.5h+).
- Follow-up messages queue silently; user has no indication why.
- Cancelled turns leave orphan subprocesses running.
- Session recovery can re-run the same long task again (observed: after cancel, the agent re-invoked the same script).
## Environment
- QwenPaw version: 2.0.0.post4 (or current master)
- Channel: feishu, Linux (Debian-based container)
## Suggested fixes
1. Cap the effective shell timeout (e.g. `min(timeout, max_shell_timeout)` or clamp LLM-provided timeout to the configured default as an upper bound).
2. On session/turn cancellation, kill the process group of any spawned subprocess (align with the existing `killpg` logic used on tool-internal timeout).
3. Add a per-channel task timeout for feishu (and other chat channels) as a last-resort watchdog, with user-visible feedback when a turn is still running.
## Related
- #6565 / #6566 (PIPE-mode background process hang — different root cause but same symptom class)
- #6527 (cancellation-safe lifecycle hooks — related to cancellation semantics)
Beitragsleitfaden
Bewertung
Dieses Issue wurde noch nicht bewertet.