mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-08 23:33:16 +08:00
Soften short-intent gates and add tool-result refs plus MCP wire invalidate.
Prefer report tools without hard-hiding CLI, keep soft CLI budgets, store compact+result_ref for the model, and clear frozen wire after MCP sync. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
3785e78a72
commit
605751b6a6
13 changed files with 636 additions and 65 deletions
|
|
@ -5,9 +5,9 @@ from runtime.application.gateway.ops_short_intent import (
|
|||
filter_tool_specs_for_ops_short_intent,
|
||||
is_ops_short_intent_suppressed_tool,
|
||||
maybe_ops_short_intent_system_hint,
|
||||
ops_short_intent_cli_soft_budgets,
|
||||
)
|
||||
from runtime.tools.base import ToolSpec
|
||||
from runtime.tools.tool_error_hints import enrich_exec_managed_ne_error, enrich_get_managed_ne_error
|
||||
|
||||
|
||||
def test_detect_ops_short_intent_english_field() -> None:
|
||||
|
|
@ -20,18 +20,19 @@ def test_detect_ops_short_intent_english_field() -> None:
|
|||
assert detect_ops_short_intent("hello there how are you doing today with something else") is None
|
||||
|
||||
|
||||
def test_ops_short_intent_suppresses_inventory_cli_tools() -> None:
|
||||
assert is_ops_short_intent_suppressed_tool("mcp__netx__listCliTargets", intent="fiber_cut")
|
||||
assert is_ops_short_intent_suppressed_tool("mcp__netx__execManagedNe", intent="offline")
|
||||
def test_ops_short_intent_suppresses_diy_xlsx_shell_only() -> None:
|
||||
assert is_ops_short_intent_suppressed_tool("run_command", intent="excel_export")
|
||||
assert is_ops_short_intent_suppressed_tool("write_xlsx", intent="fiber_cut")
|
||||
assert is_ops_short_intent_suppressed_tool("write_xlsx", intent="excel_export")
|
||||
# Soft preference: CLI/inventory stay available for device confirmation.
|
||||
assert not is_ops_short_intent_suppressed_tool("mcp__netx__listCliTargets", intent="fiber_cut")
|
||||
assert not is_ops_short_intent_suppressed_tool("mcp__netx__execManagedNe", intent="offline")
|
||||
assert not is_ops_short_intent_suppressed_tool("ume_alarm_xlsx_report", intent="fiber_cut")
|
||||
assert not is_ops_short_intent_suppressed_tool("mcp__netx__queryUmeAlarmsRaw", intent="alarm_tally")
|
||||
assert not is_ops_short_intent_suppressed_tool("mcp__netx__execManagedNe", intent="continue")
|
||||
|
||||
|
||||
def test_filter_tool_specs_for_ops_short_intent_keeps_report_path() -> None:
|
||||
def test_filter_tool_specs_for_ops_short_intent_keeps_cli_and_report() -> None:
|
||||
def _spec(name: str) -> ToolSpec:
|
||||
return ToolSpec(
|
||||
name=name,
|
||||
|
|
@ -52,20 +53,33 @@ def test_filter_tool_specs_for_ops_short_intent_keeps_report_path() -> None:
|
|||
names = {t.name for t in kept}
|
||||
assert "ume_alarm_xlsx_report" in names
|
||||
assert "mcp__netx__aggregateUmeAlarms" in names
|
||||
assert "mcp__netx__listCliTargets" in names
|
||||
assert "mcp__netx__execManagedNe" in names
|
||||
assert "write_xlsx" not in names
|
||||
assert "mcp__netx__listCliTargets" not in names
|
||||
assert "mcp__netx__execManagedNe" not in names
|
||||
assert "run_command" not in names
|
||||
assert len(filter_tool_specs_for_ops_short_intent(tools, intent="continue")) == len(tools)
|
||||
|
||||
|
||||
def test_ops_short_intent_cli_soft_budgets() -> None:
|
||||
soft = ops_short_intent_cli_soft_budgets("fiber_cut")
|
||||
assert soft is not None
|
||||
assert int(soft["single"]) <= 2
|
||||
assert int(soft["batch"]) == 1
|
||||
assert ops_short_intent_cli_soft_budgets("continue") is None
|
||||
assert ops_short_intent_cli_soft_budgets(None) is None
|
||||
|
||||
|
||||
def test_ops_short_intent_hint_english_default() -> None:
|
||||
hint = maybe_ops_short_intent_system_hint(text="LOS on these sites", lang="en")
|
||||
assert "fiber" in hint.lower() or "LOS" in hint
|
||||
assert "ume_alarm_xlsx_report" in hint
|
||||
assert "soft budget" in hint.lower() or "targets" in hint.lower()
|
||||
assert "断纤" not in hint
|
||||
|
||||
|
||||
from runtime.tools.tool_error_hints import enrich_exec_managed_ne_error, enrich_get_managed_ne_error
|
||||
|
||||
|
||||
def test_enrich_exec_timeout() -> None:
|
||||
out = enrich_exec_managed_ne_error(
|
||||
{"ok": False, "error_code": "tool_timeout_or_failed", "error": "timeout"}
|
||||
|
|
|
|||
47
tests/test_tool_result_ref.py
Normal file
47
tests/test_tool_result_ref.py
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from runtime.chat.tool_result_store import (
|
||||
attach_result_ref,
|
||||
load_tool_result_blob,
|
||||
save_tool_result_blob,
|
||||
)
|
||||
from runtime.tools.public.fetch_tool_result_tool import fetch_tool_result_tool
|
||||
|
||||
|
||||
def test_save_and_fetch_tool_result_blob(monkeypatch, tmp_path: Path) -> None:
|
||||
monkeypatch.setattr("runtime.chat.tool_result_store.attachments_dir", lambda: tmp_path)
|
||||
big = {"ok": True, "rows": ["x" * 100 for _ in range(80)]}
|
||||
ref = save_tool_result_blob(session_id="sess-1", tool_call_id="tc1", result=big)
|
||||
assert ref and ref.startswith("tr:")
|
||||
loaded = load_tool_result_blob(ref, session_id="sess-1")
|
||||
assert loaded["ok"] is True
|
||||
assert loaded["result"]["ok"] is True
|
||||
assert loaded["truncated"] is False
|
||||
|
||||
|
||||
def test_attach_result_ref_adds_fetch_hint() -> None:
|
||||
out = attach_result_ref({"ok": True, "_truncated_for_llm": True, "preview": "p"}, result_ref="tr:abcd")
|
||||
assert out["result_ref"] == "tr:abcd"
|
||||
assert out["fetch_tool"] == "fetch_tool_result"
|
||||
assert "fetch_tool_result" in str(out.get("hint") or "")
|
||||
|
||||
|
||||
def test_fetch_tool_result_public_tool(monkeypatch, tmp_path: Path) -> None:
|
||||
monkeypatch.setattr("runtime.chat.tool_result_store.attachments_dir", lambda: tmp_path)
|
||||
ref = save_tool_result_blob(
|
||||
session_id="sess-2",
|
||||
tool_call_id="tc2",
|
||||
result={"ok": True, "data": "hello" * 2000},
|
||||
force=True,
|
||||
)
|
||||
assert ref
|
||||
monkeypatch.setattr(
|
||||
"runtime.tools.public.fetch_tool_result_tool.current_tool_lane_sessions",
|
||||
lambda: (None, "sess-2"),
|
||||
)
|
||||
tool = fetch_tool_result_tool()
|
||||
out = tool.handler({"result_ref": ref})
|
||||
assert out["ok"] is True
|
||||
assert out["result_ref"] == ref
|
||||
|
|
@ -10,6 +10,14 @@ class _DummyStore:
|
|||
def get_setting(self, key: str) -> str:
|
||||
return str(self.settings.get(key, ""))
|
||||
|
||||
def list_mcp_servers(self, *, enabled_only: bool = False):
|
||||
del enabled_only
|
||||
return []
|
||||
|
||||
def list_mcp_server_tools(self, *, server_id: str):
|
||||
del server_id
|
||||
return []
|
||||
|
||||
|
||||
def test_tool_wire_freeze_default_on(monkeypatch) -> None:
|
||||
monkeypatch.setattr(dl, "_prepare_llm_tools", lambda **kwargs: [])
|
||||
|
|
@ -52,3 +60,35 @@ def test_warm_tool_wire_cache_clears_frozen_stale_entries(monkeypatch) -> None:
|
|||
st = dl.tool_wire_freeze_status(store=store)
|
||||
assert st["frozen"] is True
|
||||
assert st["last_warm_count"] == 2
|
||||
|
||||
|
||||
def test_invalidate_tool_wire_cache_clears_freeze(monkeypatch) -> None:
|
||||
monkeypatch.setattr(dl, "_prepare_llm_tools", lambda **kwargs: [])
|
||||
store = _DummyStore({"AIA_TOOL_WIRE_FROZEN_ON_STARTUP": "1"})
|
||||
_ = dl.warm_tool_wire_cache(store=store, tools=object(), base_url="", roles=["generalist"])
|
||||
assert dl.tool_wire_freeze_status(store=store)["frozen"] is True
|
||||
out = dl.invalidate_tool_wire_cache(reason="test")
|
||||
assert out["ok"] is True
|
||||
assert dl.tool_wire_freeze_status(store=store)["frozen"] is False
|
||||
|
||||
|
||||
def test_mcp_tools_fingerprint_changes_with_catalog() -> None:
|
||||
class _Store(_DummyStore):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.tools = [{"tool_name": "a"}]
|
||||
|
||||
def list_mcp_servers(self, *, enabled_only: bool = False):
|
||||
del enabled_only
|
||||
return [{"server_id": "netx"}]
|
||||
|
||||
def list_mcp_server_tools(self, *, server_id: str):
|
||||
del server_id
|
||||
return list(self.tools)
|
||||
|
||||
store = _Store()
|
||||
fp1 = dl._mcp_tools_fingerprint(store)
|
||||
store.tools = [{"tool_name": "a"}, {"tool_name": "b"}]
|
||||
fp2 = dl._mcp_tools_fingerprint(store)
|
||||
assert fp1 != fp2
|
||||
assert fp1 != "x"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue