mirror of
https://github.com/open-webui/computer.git
synced 2026-11-05 01:17:24 +00:00
[GH-ISSUE #195] bug: the claude CLI subprocess is torn down at the end of every turn, killing in-flight background agents #112
Labels
No labels
enhancement
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
open-webui/computer#112
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @penradioGables on GitHub (Jul 28, 2026).
Original GitHub issue: https://github.com/open-webui/computer/issues/195
Summary
run_claude_code_agent()disconnects itsClaudeSDKClientin afinallyat the end of every turn, which SIGTERM/SIGKILLs the underlyingclaudeCLI subprocess. Any background/Task-tool agent spawned during that turn is an in-process async task inside that subprocess, so it is destroyed at the turn boundary regardless of how much work it had left. Every turn also pays a full process spawn plus session replay.Verified still present in v0.9.15 —
cptr/utils/agents/claude_code.pyis byte-identical between thev0.9.10andv0.9.15tags.Symptom
A background agent started in one turn never returns results. The user sees a
<task-notification status="stopped">with wording that hedges about whether the process exited — "It may have been stopped, or it may have been running when the previous Claude Code process exited". In practice the exit is deterministic, not ambiguous: it happens at the end of every turn, in-flight work or not.Root cause
The client is constructed fresh, connected, given exactly one
query(), streamed toResultMessage, then unconditionally torn down (L146–147 and L241–242):disconnect()→Query.close()→SubprocessCLITransport.close(), which closes stdin then escalates SIGTERM→SIGKILL within ~10s.Observed directly on a running instance: walking
/procduring normal use showed multipleclaudeCLI subprocesses alive simultaneously — one with--resume=<uuid>and one without — i.e. a new subprocess per turn rather than one long-lived process per conversation.claude_agent_sdk's ownClaudeSDKClient.query()docstring documents the intended usage as one long-lived client across multiplequery()calls, withset_model()/set_permission_mode()to change things mid-conversation.Suggested fix
Cache the connected client per Claude session id — cptr already threads
session_idthroughresume_stateon every call — and reuse it across turns, disconnecting only on error, on a workspace/cwd change (which can't be applied to a live process), or after an idle timeout.Known trade-off, which is why this is filed as a problem statement rather than a PR
system_promptis a CLI launch flag fixed atconnect()time; there is no way to update it on a live client. So on a cache hit the per-turn dynamic system-prompt scaffolding (memory recall, conversation-summary / plan-mode / voice-mode injections) stops being refreshed.Conversation content is unaffected — cptr only ever sends
latest_user_text()per turn and relies on the CLI's own resumed session for history — so this touches prompt scaffolding only. But it does need a real answer from upstream (re-inject the scaffolding as a user-turn preamble? accept staleness? reconnect only when the scaffolding actually changed?) rather than a decision made in a patch.I have run the caching approach locally and it behaves as described, including surviving background agents across turn boundaries. Glad to turn it into a PR if you have a preference on how to handle the
system_promptquestion.@tjbck commented on GitHub (Jul 31, 2026):
Should be addressed!