mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
fix(grok): auto-approve tool execution (--always-approve) so headless agents can call tools
Live smoke caught every grok agent (Main PM, pr-reviewer, dev, …) ending its run with stopReason=Cancelled and empty output the instant it reached for a tool. Root cause: headless `grok -p` cannot approve a tool call without `--always-approve` (grok's docs: required for unattended automation), and the per-role args didn't pass it — so no agent could call a gateway verb, an edit, or an MCP tool, and the run was cancelled. Add `--always-approve` to grok_cli_args_for_role (one place → every role, one-shot and interactive). Safety is unaffected: `--disallowed-tools` still removes tools and `--deny` still hard-blocks command patterns regardless of approval (a denied command returns a permission error and the agent recovers — verified live). Proven in the rebuilt image side-by-side: without the flag a tool call yields Cancelled/not-called; with the real rendered args it returns EndTurn and the MCP tool actually runs. (My earlier in-image tool-calling check passed `--always-approve` manually, which masked that the production args omitted it — fixed.)
This commit is contained in:
@@ -184,10 +184,18 @@ def grok_cli_args_for_role(
|
||||
) -> list[str]:
|
||||
"""The per-role ``grok -p`` flag tokens (excludes ``-p``/model/cwd).
|
||||
|
||||
Order: tool removal, web off, turn cap, deny rules, then effort. Each token is
|
||||
a separate list element so callers can splice them without shell quoting.
|
||||
Order: auto-approve, tool removal, web off, turn cap, deny rules, then effort.
|
||||
Each token is a separate list element so callers can splice them without shell
|
||||
quoting.
|
||||
"""
|
||||
args: list[str] = ["--disallowed-tools", _disallowed_tools(role)]
|
||||
# Auto-approve tool execution — REQUIRED for headless/unattended runs. Without
|
||||
# it, grok cannot approve any tool call in `grok -p` (no human to confirm) and
|
||||
# the run ends `Cancelled` the instant the agent reaches for a tool — every
|
||||
# gateway verb, edit, and MCP call. Safety still holds: `--disallowed-tools`
|
||||
# removes tools entirely and `--deny` hard-blocks command patterns regardless
|
||||
# of approval (a denied command returns a permission error, verified live).
|
||||
args: list[str] = ["--always-approve"]
|
||||
args += ["--disallowed-tools", _disallowed_tools(role)]
|
||||
# No direct web for any role (parity with the Claude path's tool set); the
|
||||
# roles that get web reach it through the gated roboco-search MCP server.
|
||||
args += ["--disable-web-search"]
|
||||
|
||||
@@ -113,6 +113,13 @@ def test_web_search_disabled_for_every_role() -> None:
|
||||
assert "--disable-web-search" in gc.grok_cli_args_for_role(role)
|
||||
|
||||
|
||||
def test_every_role_auto_approves_tools() -> None:
|
||||
# Headless `grok -p` cannot approve a tool call without this; without it the
|
||||
# run ends Cancelled the moment the agent calls a gateway verb / MCP tool.
|
||||
for role in ("developer", "prompter", "secretary", "main_pm", "pr_reviewer", "qa"):
|
||||
assert "--always-approve" in gc.grok_cli_args_for_role(role)
|
||||
|
||||
|
||||
def test_effort_is_fleet_override_only(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setenv("ROBOCO_GROK_REASONING_EFFORT", "high")
|
||||
args = gc.grok_cli_args("be-dev-1")
|
||||
|
||||
Reference in New Issue
Block a user