mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-18 04:40:45 +08:00
Cap run_command spam and force a usable finalize after tool-round limits.
Budget shell calls like CLI, and when rounds are exhausted inject a no-more-tools system nudge plus any user_facing_hint constraints into the final synthesis pass. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
28a5f2586c
commit
9d447b1c51
5 changed files with 186 additions and 27 deletions
|
|
@ -245,3 +245,49 @@ def test_exec_managed_ne_fail_budget(tmp_path: Path) -> None:
|
|||
blocked, _ = results["f3"]
|
||||
assert calls["n"] == 2
|
||||
assert blocked.get("error_code") == "cli_fail_budget_exceeded"
|
||||
|
||||
|
||||
def test_run_command_call_budget(tmp_path: Path) -> None:
|
||||
store = SqliteStore(str(tmp_path / "shell.sqlite"))
|
||||
sess = store.create_session("t")
|
||||
calls = {"n": 0}
|
||||
|
||||
def _handler(_args):
|
||||
calls["n"] += 1
|
||||
return {"ok": True, "stdout": "ok", "exit_code": 0}
|
||||
|
||||
reg = ToolRegistry(
|
||||
[
|
||||
ToolSpec(
|
||||
name="run_command",
|
||||
description="shell",
|
||||
parameters={"type": "object", "properties": {"command": {"type": "string"}}},
|
||||
handler=_handler,
|
||||
read_only=False,
|
||||
)
|
||||
]
|
||||
)
|
||||
ctx = ToolExecutionContext(
|
||||
store=store,
|
||||
tools=reg,
|
||||
session_id=sess.id,
|
||||
turn_uuid="turn-shell-budget",
|
||||
lang="en",
|
||||
)
|
||||
for i in range(5):
|
||||
ToolExecutor().execute_tool_uses(
|
||||
ctx=ctx,
|
||||
assistant_msg_id=i + 1,
|
||||
tool_uses=[LLMToolCall(id=f"s{i}", name="run_command", arguments={"command": f"echo {i}"})],
|
||||
signature_budget=2,
|
||||
)
|
||||
assert calls["n"] == 5
|
||||
_, results = ToolExecutor().execute_tool_uses(
|
||||
ctx=ctx,
|
||||
assistant_msg_id=99,
|
||||
tool_uses=[LLMToolCall(id="sX", name="run_command", arguments={"command": "echo x"})],
|
||||
signature_budget=2,
|
||||
)
|
||||
blocked, _ = results["sX"]
|
||||
assert calls["n"] == 5
|
||||
assert blocked.get("error_code") == "shell_call_budget_exceeded"
|
||||
|
|
|
|||
|
|
@ -42,6 +42,21 @@ def test_enrich_mcp_scope_sql() -> None:
|
|||
assert "ume_alarm_xlsx_report" in out["fallback_tools"]
|
||||
|
||||
|
||||
def test_build_finalize_system_suffix() -> None:
|
||||
from runtime.tools.tool_error_hints import build_finalize_system_suffix
|
||||
|
||||
en = build_finalize_system_suffix(
|
||||
lang="en",
|
||||
hit_tool_round_limit=True,
|
||||
user_facing_hints=["SQL query is not enabled for this bot token."],
|
||||
)
|
||||
assert "Tool-round limit" in en
|
||||
assert "SQL query is not enabled" in en
|
||||
assert "do NOT call" in en
|
||||
zh = build_finalize_system_suffix(lang="zh", hit_tool_round_limit=True)
|
||||
assert "工具轮次" in zh
|
||||
|
||||
|
||||
def test_enrich_exec_auth() -> None:
|
||||
from runtime.tools.tool_error_hints import enrich_exec_managed_ne_error
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue