mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-23 05:05:24 -04:00
feat(agent): add manage_bg_jobs tool to inspect and kill background bash jobs (#4577)
Detached bash jobs (#!bg) could be launched and auto-reported on completion, but the agent had no way to act on a running one: no on-demand output read and no kill (it blocked until the 1h max-runtime). bg_jobs had the pieces (_read_output, list_for_session, internal _kill) but none was exposed. Adds: - bg_jobs.kill(job_id): tears down the process tree, marks the job killed, and sets followed_up so the monitor does not also auto-continue a deliberate kill. - manage_bg_jobs registry tool with actions list / output / kill, scoped to the chat that launched the job (cross-session access reads as not found). - Wiring: TOOL_HANDLERS/TAGS, function schema, RAG index + keyword hints, parser name map, dispatch (threads session_id via _direct_fallback). Gated like bash (NON_ADMIN_BLOCKED_TOOLS; plan-mode mutator). - agent_loop: background-job intent regex maps to the files domain (and the tool joins _DOMAIN_TOOL_MAP[files]) so short commands like 'kill that job' are not dropped by the low-signal gate that skips tool retrieval. - bg launch message tells the model to call manage_bg_jobs itself for check/stop rather than printing raw tool syntax to the user. Tests: tests/test_bg_job_tools.py (kill semantics, per-chat scoping, actions, and the intent classifier).
This commit is contained in:
committed by
GitHub
parent
39a802bea2
commit
cdae9879f2
+14
-2
@@ -471,6 +471,8 @@ async def _direct_fallback(
|
||||
tool: str,
|
||||
content: str,
|
||||
progress_cb: Optional[Callable[[Dict], Awaitable[None]]] = None,
|
||||
session_id: Optional[str] = None,
|
||||
owner: Optional[str] = None,
|
||||
) -> Optional[Dict]:
|
||||
_subproc_env = {
|
||||
**os.environ,
|
||||
@@ -484,6 +486,8 @@ async def _direct_fallback(
|
||||
ctx = {
|
||||
"progress_cb": progress_cb,
|
||||
"subproc_env": _subproc_env,
|
||||
"session_id": session_id,
|
||||
"owner": owner,
|
||||
}
|
||||
|
||||
from src.agent_tools import TOOL_HANDLERS
|
||||
@@ -731,10 +735,13 @@ async def _execute_tool_block_impl(
|
||||
desc = f"bash (background): {short}"
|
||||
result = {
|
||||
"output": (
|
||||
f"Started background job `{rec['id']}`. It is running detached — "
|
||||
f"Started background job `{rec['id']}`. It is running detached; "
|
||||
f"do NOT wait for it or poll it. You will be automatically re-invoked "
|
||||
f"with its full output when it finishes. Continue with other work, or "
|
||||
f"end your turn now and resume when the result arrives."
|
||||
f"end your turn now and resume when the result arrives. If the user "
|
||||
f"later asks to check progress or stop it, call the manage_bg_jobs "
|
||||
f"tool yourself (output or kill); do not tell them to run a tool "
|
||||
f"command, and do not surface raw tool syntax in your reply."
|
||||
),
|
||||
"exit_code": 0,
|
||||
"bg_job_id": rec["id"],
|
||||
@@ -755,6 +762,11 @@ async def _execute_tool_block_impl(
|
||||
desc = f"{tool}: {first_line}"
|
||||
result = await _direct_fallback(tool, content, progress_cb=progress_cb) \
|
||||
or {"error": f"{tool}: execution failed", "exit_code": 1}
|
||||
elif tool == "manage_bg_jobs":
|
||||
# Inspect/kill detached `bash` jobs; needs session_id to scope to chat.
|
||||
desc = f"manage_bg_jobs: {content.split(chr(10))[0][:80]}"
|
||||
result = await _direct_fallback(tool, content, session_id=session_id, owner=owner) \
|
||||
or {"error": "manage_bg_jobs: execution failed", "exit_code": 1}
|
||||
elif tool in ("create_document", "update_document", "edit_document",
|
||||
"suggest_document", "manage_documents"):
|
||||
desc = f"{tool}: {content.split(chr(10))[0][:80]}"
|
||||
|
||||
Reference in New Issue
Block a user