191 lines
7.9 KiB
Python
191 lines
7.9 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
|
|
import pytest
|
|
|
|
from src.services.ai_agent_communication_learning_contract import (
|
|
load_latest_ai_agent_communication_learning_contract,
|
|
)
|
|
|
|
|
|
def test_load_latest_ai_agent_communication_learning_contract_reads_committed_snapshot():
|
|
data = load_latest_ai_agent_communication_learning_contract()
|
|
|
|
assert data["schema_version"] == "ai_agent_communication_learning_contract_v1"
|
|
assert data["program_status"]["overall_completion_percent"] == 35
|
|
assert data["program_status"]["read_only_mode"] is True
|
|
assert data["program_status"]["runtime_authority"] == "contract_only_no_runtime_worker"
|
|
assert data["communication_plane"]["message_bus"] == "Redis Streams"
|
|
assert data["communication_plane"]["stream_key_pattern"] == "aiops:agent:{session_id}"
|
|
assert data["communication_plane"]["frontend_redaction"]["operator_conversation_display_allowed"] is False
|
|
assert data["approval_boundaries"]["runtime_worker_allowed"] is False
|
|
assert data["approval_boundaries"]["db_migration_allowed"] is False
|
|
assert data["approval_boundaries"]["telegram_direct_send_allowed"] is False
|
|
assert data["approval_boundaries"]["production_route_change_allowed"] is False
|
|
assert data["rollups"]["agent_lane_count"] == 3
|
|
assert data["rollups"]["mcp_stack_count"] == len(data["mcp_stack"]) == 9
|
|
assert data["rollups"]["rag_layer_count"] == len(data["rag_memory_stack"]) == 3
|
|
assert data["rollups"]["learning_loop_count"] == len(data["learning_loops"]) == 5
|
|
assert data["rollups"]["intelligence_service_count"] == len(data["intelligence_services"]) == 7
|
|
assert data["rollups"]["optional_service_ids"] == ["langfuse", "phoenix", "qdrant", "milvus"]
|
|
assert {lane["agent_id"] for lane in data["agent_lanes"]} == {
|
|
"openclaw",
|
|
"hermes",
|
|
"nemotron",
|
|
}
|
|
|
|
|
|
def test_load_latest_ai_agent_communication_learning_contract_rejects_runtime_worker(tmp_path):
|
|
snapshot = _snapshot()
|
|
snapshot["approval_boundaries"]["runtime_worker_allowed"] = True
|
|
(tmp_path / "ai_agent_communication_learning_contract_2026-06-11.json").write_text(
|
|
json.dumps(snapshot),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
with pytest.raises(ValueError, match="approval boundaries"):
|
|
load_latest_ai_agent_communication_learning_contract(tmp_path)
|
|
|
|
|
|
def test_load_latest_ai_agent_communication_learning_contract_rejects_rollup_mismatch(tmp_path):
|
|
snapshot = _snapshot()
|
|
snapshot["rollups"]["mcp_stack_count"] = 99
|
|
(tmp_path / "ai_agent_communication_learning_contract_2026-06-11.json").write_text(
|
|
json.dumps(snapshot),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
with pytest.raises(ValueError, match="rollup counts"):
|
|
load_latest_ai_agent_communication_learning_contract(tmp_path)
|
|
|
|
|
|
def test_load_latest_ai_agent_communication_learning_contract_rejects_nemotron_route_change(tmp_path):
|
|
snapshot = _snapshot()
|
|
snapshot["agent_lanes"][2]["blocked_actions"] = ["secret_plaintext_read"]
|
|
(tmp_path / "ai_agent_communication_learning_contract_2026-06-11.json").write_text(
|
|
json.dumps(snapshot),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
with pytest.raises(ValueError, match="Nemotron"):
|
|
load_latest_ai_agent_communication_learning_contract(tmp_path)
|
|
|
|
|
|
def _snapshot() -> dict:
|
|
return {
|
|
"schema_version": "ai_agent_communication_learning_contract_v1",
|
|
"generated_at": "2026-06-11T20:40:00+08:00",
|
|
"program_status": {
|
|
"overall_completion_percent": 35,
|
|
"current_priority": "P2",
|
|
"current_task_id": "P2-401A",
|
|
"next_task_id": "P2-401B",
|
|
"read_only_mode": True,
|
|
"runtime_authority": "contract_only_no_runtime_worker",
|
|
},
|
|
"communication_plane": {
|
|
"message_bus": "Redis Streams",
|
|
"stream_key_pattern": "aiops:agent:{session_id}",
|
|
"session_table": "agent_sessions",
|
|
"event_tables": ["timeline_events"],
|
|
"turn_types": ["observe", "propose", "challenge", "review", "decide"],
|
|
"frontend_redaction": {
|
|
"operator_conversation_display_allowed": False,
|
|
"agent_private_reasoning_display_allowed": False,
|
|
},
|
|
},
|
|
"agent_lanes": [
|
|
{
|
|
"agent_id": "openclaw",
|
|
"display_name": "OpenClaw",
|
|
"primary_role": "生產仲裁",
|
|
"initiates": ["incident arbitration"],
|
|
"responds_to": ["Hermes evidence dossier"],
|
|
"writes_to": ["agent_sessions"],
|
|
"blocked_actions": ["secret_plaintext_read", "self_approval"],
|
|
},
|
|
{
|
|
"agent_id": "hermes",
|
|
"display_name": "Hermes",
|
|
"primary_role": "治理",
|
|
"initiates": ["knowledge review"],
|
|
"responds_to": ["OpenClaw evidence request"],
|
|
"writes_to": ["knowledge_entries"],
|
|
"blocked_actions": ["secret_plaintext_read", "production_write"],
|
|
},
|
|
{
|
|
"agent_id": "nemotron",
|
|
"display_name": "NemoTron",
|
|
"primary_role": "離線評估",
|
|
"initiates": ["replay scoring"],
|
|
"responds_to": ["OpenClaw offline evaluation request"],
|
|
"writes_to": ["agent_replay_results"],
|
|
"blocked_actions": ["secret_plaintext_read", "production_route_change"],
|
|
},
|
|
],
|
|
"mcp_stack": [_capability("mcp_gateway", "MCP Gateway", "openclaw", "existing")],
|
|
"rag_memory_stack": [
|
|
_capability("hot_session_memory", "Hot", "openclaw", "contract_defined"),
|
|
_capability("warm_rag_memory", "Warm", "hermes", "existing"),
|
|
_capability("cold_replay_archive", "Cold", "nemotron", "planned"),
|
|
],
|
|
"learning_loops": [_capability("incident_outcome_learning", "Incident", "openclaw", "planned")],
|
|
"intelligence_services": [
|
|
_capability("postgres_pgvector", "PostgreSQL + pgvector", "hermes", "preferred_default"),
|
|
_capability("langfuse", "Langfuse", "hermes", "optional_candidate"),
|
|
],
|
|
"rollout_tasks": [
|
|
{
|
|
"task_id": "P2-401A",
|
|
"priority": "P2",
|
|
"status": "ready_for_review",
|
|
"completion_percent": 100,
|
|
"owner_agent": "Hermes + OpenClaw",
|
|
"summary": "契約。",
|
|
"next_gate": "本地測試",
|
|
},
|
|
{
|
|
"task_id": "P2-401B",
|
|
"priority": "P2",
|
|
"status": "planned",
|
|
"completion_percent": 0,
|
|
"owner_agent": "OpenClaw",
|
|
"summary": "Migration。",
|
|
"next_gate": "DB migration approval gate",
|
|
},
|
|
],
|
|
"approval_boundaries": {
|
|
"runtime_worker_allowed": False,
|
|
"db_migration_allowed": False,
|
|
"telegram_direct_send_allowed": False,
|
|
"paid_external_service_allowed": False,
|
|
"secret_plaintext_allowed": False,
|
|
"autonomous_host_mutation_allowed": False,
|
|
"production_route_change_allowed": False,
|
|
"sdk_installation_allowed": False,
|
|
},
|
|
"rollups": {
|
|
"agent_lane_count": 3,
|
|
"mcp_stack_count": 1,
|
|
"rag_layer_count": 3,
|
|
"learning_loop_count": 1,
|
|
"intelligence_service_count": 2,
|
|
"rollout_task_count": 2,
|
|
"blocked_task_ids": ["P2-401B"],
|
|
"optional_service_ids": ["langfuse"],
|
|
},
|
|
}
|
|
|
|
|
|
def _capability(id_: str, display_name: str, owner: str, status: str) -> dict:
|
|
return {
|
|
"id": id_,
|
|
"display_name": display_name,
|
|
"primary_owner": owner,
|
|
"purpose": "測試用途。",
|
|
"storage_or_service": "test",
|
|
"status": status,
|
|
"approval_gate": "read_only_allowed",
|
|
}
|