From 14ccd32cee91c825aa4d204f60fd0021de182b34 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Sat, 11 Apr 2026 17:16:11 -0700 Subject: [PATCH] refactor(terminal): remove check_interval parameter (#8001) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The check_interval parameter on terminal_tool sent periodic output updates to the gateway chat, but these were display-only — the agent couldn't see or act on them. This added schema bloat and introduced a bug where notify_on_complete=True was silently dropped when check_interval was also set (the not-check_interval guard skipped fast-watcher registration, and the check_interval watcher dict was missing the notify_on_complete key). Removing check_interval entirely: - Eliminates the notify_on_complete interaction bug - Reduces tool schema size (one fewer parameter for the model) - Simplifies the watcher registration path - notify_on_complete (agent wake-on-completion) still works - watch_patterns (output alerting) still works - process(action='poll') covers manual status checking Closes #7947 (root cause eliminated rather than patched). --- AGENTS.md | 5 ++- cli-config.yaml.example | 2 +- tests/tools/test_code_execution.py | 2 +- tools/code_execution_tool.py | 2 +- tools/terminal_tool.py | 43 +------------------ .../user-guide/features/code-execution.md | 2 +- 6 files changed, 8 insertions(+), 48 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 8045c3d21..8f227968e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -351,8 +351,9 @@ Cache-breaking forces dramatically higher costs. The ONLY time we alter context ### Background Process Notifications (Gateway) -When `terminal(background=true, check_interval=...)` is used, the gateway runs a watcher that -pushes status updates to the user's chat. Control verbosity with `display.background_process_notifications` +When `terminal(background=true, notify_on_complete=true)` is used, the gateway runs a watcher that +detects process completion and triggers a new agent turn. Control verbosity of background process +messages with `display.background_process_notifications` in config.yaml (or `HERMES_BACKGROUND_NOTIFICATIONS` env var): - `all` — running-output updates + final message (default) diff --git a/cli-config.yaml.example b/cli-config.yaml.example index 31d829de0..c9e6645bb 100644 --- a/cli-config.yaml.example +++ b/cli-config.yaml.example @@ -787,7 +787,7 @@ display: # Background process notifications (gateway/messaging only). # Controls how chatty the process watcher is when you use - # terminal(background=true, check_interval=...) from Telegram/Discord/etc. + # terminal(background=true, notify_on_complete=true) from Telegram/Discord/etc. # off: No watcher messages at all # result: Only the final completion message # error: Only the final message when exit code != 0 diff --git a/tests/tools/test_code_execution.py b/tests/tools/test_code_execution.py index e015e5d42..a269218c2 100644 --- a/tests/tools/test_code_execution.py +++ b/tests/tools/test_code_execution.py @@ -380,7 +380,7 @@ class TestStubSchemaDrift(unittest.TestCase): # Parameters that are internal (injected by the handler, not user-facing) _INTERNAL_PARAMS = {"task_id", "user_task"} # Parameters intentionally blocked in the sandbox - _BLOCKED_TERMINAL_PARAMS = {"background", "check_interval", "pty", "notify_on_complete"} + _BLOCKED_TERMINAL_PARAMS = {"background", "pty", "notify_on_complete"} def test_stubs_cover_all_schema_params(self): """Every user-facing parameter in the real schema must appear in the diff --git a/tools/code_execution_tool.py b/tools/code_execution_tool.py index d6c561e2c..8b5f79455 100644 --- a/tools/code_execution_tool.py +++ b/tools/code_execution_tool.py @@ -301,7 +301,7 @@ def _call(tool_name, args): # --------------------------------------------------------------------------- # Terminal parameters that must not be used from ephemeral sandbox scripts -_TERMINAL_BLOCKED_PARAMS = {"background", "check_interval", "pty", "notify_on_complete", "watch_patterns"} +_TERMINAL_BLOCKED_PARAMS = {"background", "pty", "notify_on_complete", "watch_patterns"} def _rpc_server_loop( diff --git a/tools/terminal_tool.py b/tools/terminal_tool.py index f0cbff0f4..3dfa786e1 100644 --- a/tools/terminal_tool.py +++ b/tools/terminal_tool.py @@ -1137,7 +1137,6 @@ def terminal_tool( task_id: Optional[str] = None, force: bool = False, workdir: Optional[str] = None, - check_interval: Optional[int] = None, pty: bool = False, notify_on_complete: bool = False, watch_patterns: Optional[List[str]] = None, @@ -1152,7 +1151,6 @@ def terminal_tool( task_id: Unique identifier for environment isolation (optional) force: If True, skip dangerous command check (use after user confirms) workdir: Working directory for this command (optional, uses session cwd if not set) - check_interval: Seconds between auto-checks for background processes (gateway only, min 30) pty: If True, use pseudo-terminal for interactive CLI tools (local backend only) notify_on_complete: If True and background=True, auto-notify the agent when the process exits watch_patterns: List of strings to watch for in background output; triggers notification on match @@ -1424,7 +1422,7 @@ def terminal_tool( # turn. CLI mode uses the completion_queue directly. from gateway.session_context import get_session_env as _gse _gw_platform = _gse("HERMES_SESSION_PLATFORM", "") - if _gw_platform and not check_interval: + if _gw_platform: _gw_chat_id = _gse("HERMES_SESSION_CHAT_ID", "") _gw_thread_id = _gse("HERMES_SESSION_THREAD_ID", "") _gw_user_id = _gse("HERMES_SESSION_USER_ID", "") @@ -1452,39 +1450,6 @@ def terminal_tool( proc_session.watch_patterns = list(watch_patterns) result_data["watch_patterns"] = proc_session.watch_patterns - # Register check_interval watcher (gateway picks this up after agent run) - if check_interval and background: - effective_interval = max(30, check_interval) - if check_interval < 30: - result_data["check_interval_note"] = ( - f"Requested {check_interval}s raised to minimum 30s" - ) - from gateway.session_context import get_session_env as _gse2 - watcher_platform = _gse2("HERMES_SESSION_PLATFORM", "") - watcher_chat_id = _gse2("HERMES_SESSION_CHAT_ID", "") - watcher_thread_id = _gse2("HERMES_SESSION_THREAD_ID", "") - watcher_user_id = _gse2("HERMES_SESSION_USER_ID", "") - watcher_user_name = _gse2("HERMES_SESSION_USER_NAME", "") - - # Store on session for checkpoint persistence - proc_session.watcher_platform = watcher_platform - proc_session.watcher_chat_id = watcher_chat_id - proc_session.watcher_user_id = watcher_user_id - proc_session.watcher_user_name = watcher_user_name - proc_session.watcher_thread_id = watcher_thread_id - proc_session.watcher_interval = effective_interval - - process_registry.pending_watchers.append({ - "session_id": proc_session.id, - "check_interval": effective_interval, - "session_key": session_key, - "platform": watcher_platform, - "chat_id": watcher_chat_id, - "user_id": watcher_user_id, - "user_name": watcher_user_name, - "thread_id": watcher_thread_id, - }) - return json.dumps(result_data, ensure_ascii=False) except Exception as e: return json.dumps({ @@ -1767,11 +1732,6 @@ TERMINAL_SCHEMA = { "type": "string", "description": "Working directory for this command (absolute path). Defaults to the session working directory." }, - "check_interval": { - "type": "integer", - "description": "Seconds between automatic status checks for background processes (gateway/messaging only, minimum 30). When set, I'll proactively report progress.", - "minimum": 30 - }, "pty": { "type": "boolean", "description": "Run in pseudo-terminal (PTY) mode for interactive CLI tools like Codex, Claude Code, or Python REPL. Only works with local and SSH backends. Default: false.", @@ -1800,7 +1760,6 @@ def _handle_terminal(args, **kw): timeout=args.get("timeout"), task_id=kw.get("task_id"), workdir=args.get("workdir"), - check_interval=args.get("check_interval"), pty=args.get("pty", False), notify_on_complete=args.get("notify_on_complete", False), watch_patterns=args.get("watch_patterns"), diff --git a/website/docs/user-guide/features/code-execution.md b/website/docs/user-guide/features/code-execution.md index 01ee86207..53668da90 100644 --- a/website/docs/user-guide/features/code-execution.md +++ b/website/docs/user-guide/features/code-execution.md @@ -153,7 +153,7 @@ When your script calls a function like `web_search("query")`: 3. The result is sent back over the socket 4. The function returns the parsed result -This means tool calls inside scripts behave identically to normal tool calls — same rate limits, same error handling, same capabilities. The only restriction is that `terminal()` is foreground-only (no `background`, `pty`, or `check_interval` parameters). +This means tool calls inside scripts behave identically to normal tool calls — same rate limits, same error handling, same capabilities. The only restriction is that `terminal()` is foreground-only (no `background` or `pty` parameters). ## Error Handling