Enforce report-first short intents and async large execManagedNe batches.

Block CLI/inventory until ume_alarm_xlsx_report (or aggregate) succeeds, and return job_id for big NE batches via get_ne_exec_job.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-08-12 22:17:16 +08:00
parent 366bc2a320
commit 4827278a9c
11 changed files with 695 additions and 34 deletions

View file

@ -73,7 +73,7 @@ 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 "FIRST" in hint or "first" in hint.lower()
assert "断纤" not in hint

View file

@ -0,0 +1,110 @@
from __future__ import annotations
import time
from pathlib import Path
from runtime.chat.ops_report_first_guard import (
maybe_block_cli_before_report,
report_first_block_payload,
)
from svc.jobs.ne_exec_jobs import (
count_exec_ne_targets,
get_ne_exec_job,
should_run_exec_managed_ne_async,
start_ne_exec_job,
strip_async_flag,
)
def test_report_first_blocks_cli_before_report() -> None:
blocked = maybe_block_cli_before_report(
tool_name="mcp__netx__execManagedNe",
intent="fiber_cut",
store=None,
session_id="",
turn_uuid="",
lang="en",
local_report_ok=False,
)
assert blocked is not None
assert blocked["error_code"] == "report_first_required"
assert blocked["next_tool"] == "ume_alarm_xlsx_report"
def test_report_first_allows_after_local_ok() -> None:
assert (
maybe_block_cli_before_report(
tool_name="mcp__netx__listCliTargets",
intent="offline",
store=None,
session_id="s",
turn_uuid="t",
local_report_ok=True,
)
is None
)
def test_report_first_ignores_non_report_intents() -> None:
assert (
maybe_block_cli_before_report(
tool_name="mcp__netx__execManagedNe",
intent="continue",
store=None,
session_id="",
turn_uuid="",
local_report_ok=False,
)
is None
)
def test_report_first_payload_zh() -> None:
out = report_first_block_payload(intent="fiber_cut", lang="zh")
assert "ume_alarm_xlsx_report" in out["hint"]
assert out["example"].get("mode") == "fiber_cut"
def test_should_async_by_ne_count(monkeypatch) -> None:
monkeypatch.setenv("AIA_EXEC_MANAGED_NE_ASYNC_MIN_NES", "4")
assert not should_run_exec_managed_ne_async({"ume_ne_ids": ["a", "b", "c"], "commands": ["show"]})
assert should_run_exec_managed_ne_async({"ume_ne_ids": ["a", "b", "c", "d"], "commands": ["show"]})
assert should_run_exec_managed_ne_async({"async": True, "ume_ne_id": "x", "commands": ["show"]})
assert not should_run_exec_managed_ne_async(
{"async": False, "ume_ne_ids": ["a", "b", "c", "d", "e"], "commands": ["show"]}
)
def test_count_and_strip_async() -> None:
assert count_exec_ne_targets({"targets": [{"ume_ne_id": "1", "commands": ["a"]}, {"ne_id": "2", "commands": ["b"]}]}) == 2
assert "async" not in strip_async_flag({"async": True, "commands": ["x"]})
def test_ne_exec_job_roundtrip(tmp_path: Path, monkeypatch) -> None:
monkeypatch.setenv("AIA_NE_EXEC_JOB_DIR", str(tmp_path))
def _runner() -> dict:
time.sleep(0.05)
return {"ok": True, "data": {"results": [1]}}
ack = start_ne_exec_job(
tool_name="mcp__netx__execManagedNe",
arguments={"ume_ne_ids": ["a", "b", "c", "d"], "commands": ["show version"]},
runner=_runner,
session_id="sess",
)
assert ack["ok"] is True
assert ack["async"] is True
jid = ack["job_id"]
deadline = time.time() + 2.0
status = ""
while time.time() < deadline:
polled = get_ne_exec_job(jid)
status = str(polled.get("status") or "")
if status in {"succeeded", "failed", "timeout"}:
break
time.sleep(0.05)
assert status == "succeeded"
done = get_ne_exec_job(jid)
assert done["terminal"] is True
assert done["result"]["ok"] is True