oclaw/tests/test_plan_agent_v2_gateway_dryrun.py
oliver 420abac9f1 refactor: root-package imports (svc/runtime/interfaces) and fix PYTHONPATH
- Rename platform/ to svc/ to avoid shadowing stdlib platform.
- Replace from oclaw.* with from svc/runtime/interfaces; update -m CLI paths.
- tests/conftest: prepend repo root to sys.path (no parent-folder package name).
- CI: paths and offline_eval script under repo root.
- Ops scripts: PYTHONPATH must be repo root for python -m runtime.* (fixes gateway/WhatsApp sidecar startup).
- Fix default oclaw.json path in tabular/file attachment limits; stabilize attachment test config.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-13 14:51:17 +08:00

142 lines
4.5 KiB
Python

from __future__ import annotations
from pathlib import Path
from svc.persistence.sqlite_store import SqliteStore
from runtime.gateway import OclawGatewayResult
from runtime.plan_agent_v2 import (
build_shadow_gateway_result,
evaluate_gateway_expert_turn_shadow,
legacy_gateway_result_keys,
)
from runtime.types import StandardMessage
def _msg(text: str) -> StandardMessage:
return StandardMessage(
session_id="sess-dryrun",
tenant_id="tenant-1",
user_id="user-1",
role="user",
channel="chat",
text=text,
attachments=[],
metadata={},
)
def test_gateway_shadow_stays_off_without_force_or_flag(tmp_path: Path) -> None:
store = SqliteStore(str(tmp_path / "ops.sqlite"))
out = evaluate_gateway_expert_turn_shadow(
store=store,
msg=_msg("实现一个功能"),
lang="zh",
interaction_mode="expert",
requested_specialist="generalist",
base_system_prompt="base-system",
force_flag=False,
)
assert out.used_v2 is False
assert out.decision is None
def test_gateway_shadow_force_path_matches_legacy_shape(tmp_path: Path) -> None:
store = SqliteStore(str(tmp_path / "ops.sqlite"))
store.set_setting("AIA_EXPERT_PLAN_FILE_DIR", str(tmp_path / "plans"))
out = evaluate_gateway_expert_turn_shadow(
store=store,
msg=_msg("请先给计划"),
lang="zh",
interaction_mode="expert",
requested_specialist="generalist",
base_system_prompt="base-system",
force_flag=True,
)
assert out.used_v2 is True
assert out.decision is not None
shadow_row = build_shadow_gateway_result(
decision=out.decision,
run_id="run-1",
trace_id="trace-1",
elapsed_ms=9,
requested_specialist="generalist",
)
assert set(shadow_row.keys()) == legacy_gateway_result_keys()
baseline = OclawGatewayResult(run_id="run-1", reply_text="", trace_id="trace-1", elapsed_ms=9)
assert shadow_row["mode"] == baseline.mode
assert shadow_row["task_id"] == baseline.task_id
assert shadow_row["dynamic_agent_used"] == baseline.dynamic_agent_used
assert shadow_row["relay_pointer_count"] == baseline.relay_pointer_count
def test_gateway_shadow_confirm_path_builds_compatible_result(tmp_path: Path) -> None:
store = SqliteStore(str(tmp_path / "ops.sqlite"))
store.set_setting("AIA_EXPERT_PLAN_FILE_DIR", str(tmp_path / "plans"))
# Enter plan
first = evaluate_gateway_expert_turn_shadow(
store=store,
msg=_msg("我要改造一下"),
lang="zh",
interaction_mode="expert",
requested_specialist="generalist",
base_system_prompt="base-system",
force_flag=True,
)
assert first.used_v2 is True
assert first.decision is not None
assert first.decision.action == "run_agent"
assert "base-system" in str(first.decision.system_prompt_override or "")
# Confirm plan
second = evaluate_gateway_expert_turn_shadow(
store=store,
msg=_msg("确认"),
lang="zh",
interaction_mode="expert",
requested_specialist="generalist",
base_system_prompt="base-system",
force_flag=True,
)
assert second.used_v2 is True
assert second.decision is not None
assert second.decision.action == "stay_plan"
assert "切换到 agent 模式" in str(second.decision.reply_text or "")
row = build_shadow_gateway_result(
decision=second.decision,
run_id="run-2",
trace_id="trace-2",
elapsed_ms=12,
requested_specialist="generalist",
)
assert row["interaction_mode"] == "expert"
assert str(row["dispatch_reason"]).startswith("plan_agent_v2:")
def test_gateway_shadow_skips_v2_when_metadata_plan_agent_version_v1(tmp_path: Path) -> None:
store = SqliteStore(str(tmp_path / "ops.sqlite"))
store.set_setting("AIA_EXPERT_PLAN_FILE_DIR", str(tmp_path / "plans"))
out = evaluate_gateway_expert_turn_shadow(
store=store,
msg=StandardMessage(
session_id="sess-dryrun",
tenant_id="tenant-1",
user_id="user-1",
role="user",
channel="chat",
text="请先给计划",
attachments=[],
metadata={"plan_agent_version": "v1"},
),
lang="zh",
interaction_mode="expert",
requested_specialist="generalist",
base_system_prompt="base-system",
force_flag=True,
)
assert out.used_v2 is False
assert out.decision is None