request_tool: non-catalog names never raise the install card

Fast-fail with a shell steer before any prompt; docstring names the closed catalog
and stops citing semgrep (pip/brew, deliberately unmanaged) as an example.
This commit is contained in:
Rohit C Prasad
2026-08-20 22:14:02 -07:00
parent 3fc782edd7
commit 1e564d56eb
4 changed files with 62 additions and 7 deletions
+17
View File
@@ -1132,6 +1132,23 @@ class TurnEngine:
"your report which checks were degraded."
),
}
elif _toolchain.describe(name) is None:
# Not in the pinned catalog: no card at all (owner-hit 2026-08-20 — agents
# routed ordinary brew/pip installs through the install card, which could
# only fail after approval). The agent has a shell with its own approval
# flow; steer it there instead of at the user.
catalog = ", ".join(sorted(_toolchain.MANAGED))
result = {
"installed": False,
"error": (
f"'{name}' is not in the pinned tool catalog ({catalog})."
),
"guidance": (
"Install it yourself with the shell (brew/pip/…, subject to the "
"normal command approval), or continue without it and say in your "
"report which checks were degraded."
),
}
else:
# The prompt must say up front whether WE can install this (pinned build for
# this platform) — a card that offers Install for a tool we can't fetch turns
+14
View File
@@ -2073,6 +2073,20 @@ def create_app(manager: SessionManager) -> FastAPI:
"""
name = str(args.get("name", "")).strip()
info = toolchain.describe(name)
if not info:
# Not in the pinned catalog: never show an install card that can only
# end in "no pinned build" AFTER approval (owner-hit 2026-08-20 — agents
# routed ordinary brew/pip installs through the card). Steer to the
# shell, which has its own approval flow.
return {
"installed": False,
"error": (
f"'{name}' is not in the pinned tool catalog "
f"({', '.join(sorted(toolchain.MANAGED))}). Install it yourself "
"with the shell (brew/pip/…, subject to the normal command "
"approval), or proceed without it and note the gap."
),
}
item = manager.inbox.add_tool_request(
session_id,
f"Install {name}?" if name else "Install a tool?",
+7 -2
View File
@@ -17,8 +17,13 @@ from aisuite.agents import ToolMetadata, tool
def request_tool_tool() -> object:
def request_tool(name: str, reason: str) -> dict:
"""Ask the user to install a command-line tool you need but can't find on this
machine (e.g. `gitleaks`, `osv-scanner`, `semgrep`).
"""Ask the user to install one of the PINNED catalog tools you need but can't find
on this machine. The catalog is a small closed set currently `gitleaks`,
`trivy`, `osv-scanner` installed at a pinned, checksum-verified version.
For ANY other missing CLI (semgrep, jq, kubectl, ) do NOT use this tool: install
it yourself with the shell (brew/pip/), which goes through the normal command
approval, or proceed without it.
Keep `reason` to ONE sentence: which check needs the tool. The prompt the user
sees already explains what the install is (pinned version, publisher, checksum)
+24 -5
View File
@@ -118,7 +118,7 @@ async def test_decline_recheck_finds_a_copy_the_user_installed_themselves(tmp_pa
async def test_event_tells_the_truth_about_installability(tmp_path, monkeypatch):
"""Owner-hit 2026-08-14: the card offered Install for a tool with no pinned build —
the surface guessed because the event said nothing. The event must carry the
registry's verdict, and no metadata means NO."""
registry's verdict for catalog tools."""
from coworker import toolchain
monkeypatch.setattr(toolchain, "_platform_key", lambda: "darwin_arm64")
@@ -133,10 +133,29 @@ async def test_event_tells_the_truth_about_installability(tmp_path, monkeypatch)
assert data["summary"]
assert data["source"] == "github.com/gitleaks"
events = await _run(_engine(tmp_path, requester, tool="not-a-managed-tool"))
data = [e for e in events if e.type is EventType.TOOL_REQUESTED][0].data
assert data["installable"] is False
assert data["version"] == "" and data["summary"] == ""
@pytest.mark.asyncio
async def test_non_catalog_tool_gets_no_card_and_a_shell_steer(tmp_path, monkeypatch):
"""Owner-hit 2026-08-20: agents routed ordinary brew/pip installs through the
install card, which could only fail AFTER the user approved. A non-catalog name
must produce NO prompt at all just a result steering the agent to the shell."""
from coworker import toolchain
monkeypatch.setattr(toolchain, "_platform_key", lambda: "darwin_arm64")
called = []
async def requester(args, tool_call_id=None):
called.append(args)
return {"installed": False, "reason": "declined"}
engine = _engine(tmp_path, requester, tool="semgrep")
events = await _run(engine)
assert not [e for e in events if e.type is EventType.TOOL_REQUESTED]
assert called == [] # the user was never asked
tool_msg = [m for m in engine.messages if m.get("role") == "tool"][-1]
body = str(tool_msg["content"])
assert "not in the pinned tool catalog" in body
assert "shell" in body and "gitleaks" in body # the catalog is named
@pytest.mark.asyncio