mirror of
https://github.com/mcloh/Enterprise-MCP-Service-Bus.git
synced 2026-11-06 06:24:12 +00:00
M3 implementada e backlog atualizado
This commit is contained in:
105
RI/tests/unit/test_agent_runtime_handoff.py
Normal file
105
RI/tests/unit/test_agent_runtime_handoff.py
Normal file
@@ -0,0 +1,105 @@
|
||||
"""Agent-to-agent handoff (EP-12-T03, `could`, README.md §6.13, ADR-023)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from emcp_bus.agent_runtime.dispatcher import DispatchResult
|
||||
from emcp_bus.agent_runtime.handoff_graph import build_handoff_payload, execute_handoff
|
||||
from emcp_bus.orchestrator.nba_model import NBADecision
|
||||
|
||||
|
||||
def _nba(agent: str) -> NBADecision:
|
||||
return NBADecision(
|
||||
decision_id="dec-1",
|
||||
action="finance.invoice.get",
|
||||
capability_version="1.0.0",
|
||||
subject_ref="subject:abc123",
|
||||
channel="app",
|
||||
agent=agent,
|
||||
reason_codes=["ELIGIBLE"],
|
||||
policy_context={},
|
||||
expires_at=datetime(2026, 1, 1),
|
||||
)
|
||||
|
||||
|
||||
def test_build_handoff_payload_only_carries_declared_keys() -> None:
|
||||
nba = _nba("finance-specialist")
|
||||
full_context = {
|
||||
"customer_key": "cust-001",
|
||||
"conversation_history": ["a very long transcript..."],
|
||||
"internal_debug_state": {"secret": "irrelevant"},
|
||||
}
|
||||
|
||||
payload = build_handoff_payload(
|
||||
nba=nba,
|
||||
origin_agent="engagement-assistant",
|
||||
full_context=full_context,
|
||||
carry_keys=frozenset({"customer_key"}),
|
||||
)
|
||||
|
||||
assert payload.minimal_context == {"customer_key": "cust-001"}
|
||||
assert "conversation_history" not in payload.minimal_context
|
||||
assert "internal_debug_state" not in payload.minimal_context
|
||||
|
||||
|
||||
def test_build_handoff_payload_records_origin_and_target() -> None:
|
||||
nba = _nba("finance-specialist")
|
||||
|
||||
payload = build_handoff_payload(
|
||||
nba=nba, origin_agent="engagement-assistant", full_context={}, carry_keys=frozenset()
|
||||
)
|
||||
|
||||
assert payload.origin_agent == "engagement-assistant"
|
||||
assert payload.target_agent == "finance-specialist"
|
||||
assert payload.decision_id == nba.decision_id
|
||||
|
||||
|
||||
class _RecordingDispatcher:
|
||||
def __init__(self) -> None:
|
||||
self.calls: list[tuple[NBADecision, dict[str, Any]]] = []
|
||||
|
||||
async def dispatch(self, nba: NBADecision, *, arguments: dict[str, Any]) -> DispatchResult:
|
||||
self.calls.append((nba, arguments))
|
||||
return DispatchResult(
|
||||
decision_id=nba.decision_id, action=nba.action, status="allowed", structured_content={}
|
||||
)
|
||||
|
||||
|
||||
async def test_execute_handoff_dispatches_with_the_targets_own_nba_and_minimal_context() -> None:
|
||||
"""The dispatcher call carries `nba` (whose `.agent` is the *target*) --
|
||||
`AgentDispatcher.dispatch` (EP-12-T01) resolves that agent's own
|
||||
credential from scratch. Nothing here ever touches the origin agent's
|
||||
token."""
|
||||
nba = _nba("finance-specialist")
|
||||
payload = build_handoff_payload(
|
||||
nba=nba,
|
||||
origin_agent="engagement-assistant",
|
||||
full_context={"customer_key": "cust-001", "history": "..."},
|
||||
carry_keys=frozenset({"customer_key"}),
|
||||
)
|
||||
dispatcher = _RecordingDispatcher()
|
||||
|
||||
result = await execute_handoff(payload, nba, dispatcher=dispatcher)
|
||||
|
||||
assert result.status == "allowed"
|
||||
assert len(dispatcher.calls) == 1
|
||||
called_nba, called_arguments = dispatcher.calls[0]
|
||||
assert called_nba.agent == "finance-specialist"
|
||||
assert called_arguments == {"customer_key": "cust-001"}
|
||||
|
||||
|
||||
async def test_execute_handoff_rejects_a_mismatched_nba() -> None:
|
||||
nba_for_a_different_agent = _nba("some-other-agent")
|
||||
payload = build_handoff_payload(
|
||||
nba=_nba("finance-specialist"),
|
||||
origin_agent="engagement-assistant",
|
||||
full_context={},
|
||||
carry_keys=frozenset(),
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError, match="does not match"):
|
||||
await execute_handoff(payload, nba_for_a_different_agent, dispatcher=_RecordingDispatcher())
|
||||
Reference in New Issue
Block a user