mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-04-25 16:36:21 +02:00
Update tests for agent-orchestrator (#745)
Add 96 tests covering the orchestrator's aggregation, provenance, routing, and explainability parsing. These verify the supervisor fan-out/fan-in lifecycle, the new RDF provenance types (Decomposition, Finding, Plan, StepResult, Synthesis), and their round-trip through the wire format. Unit tests (84): - Aggregator: register, record completion, peek, build synthesis, cleanup - Provenance triple builders: types, provenance links, goals/steps, labels - Explainability parsing: from_triples dispatch, field extraction for all new entity types, precedence over existing types - PatternBase: is_subagent detection, emit_subagent_completion message shape - Completion dispatch: detection logic, full aggregator integration flow, synthesis request not re-intercepted as completion - MetaRouter: task type identification, pattern selection, valid_patterns constraints, fallback on LLM error or unknown response Contract tests (12): - Orchestration fields on AgentRequest round-trip correctly - subagent-completion and synthesise step types in request history - Plan steps with status and dependencies - Provenance triple builder → wire format → from_triples round-trip for all five new entity types
This commit is contained in:
parent
7b734148b3
commit
816a8cfcf6
8 changed files with 1517 additions and 0 deletions
144
tests/unit/test_agent/test_pattern_base_subagent.py
Normal file
144
tests/unit/test_agent/test_pattern_base_subagent.py
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
"""
|
||||
Unit tests for PatternBase subagent helpers — is_subagent() and
|
||||
emit_subagent_completion().
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import MagicMock, AsyncMock
|
||||
from dataclasses import dataclass
|
||||
|
||||
from trustgraph.schema import AgentRequest
|
||||
|
||||
from trustgraph.agent.orchestrator.pattern_base import PatternBase
|
||||
|
||||
|
||||
@dataclass
|
||||
class MockProcessor:
|
||||
"""Minimal processor mock for PatternBase."""
|
||||
pass
|
||||
|
||||
|
||||
def _make_request(**kwargs):
|
||||
defaults = dict(
|
||||
question="Test question",
|
||||
user="testuser",
|
||||
collection="default",
|
||||
)
|
||||
defaults.update(kwargs)
|
||||
return AgentRequest(**defaults)
|
||||
|
||||
|
||||
def _make_pattern():
|
||||
return PatternBase(MockProcessor())
|
||||
|
||||
|
||||
class TestIsSubagent:
|
||||
|
||||
def test_returns_true_when_correlation_id_set(self):
|
||||
pattern = _make_pattern()
|
||||
request = _make_request(correlation_id="corr-123")
|
||||
assert pattern.is_subagent(request) is True
|
||||
|
||||
def test_returns_false_when_correlation_id_empty(self):
|
||||
pattern = _make_pattern()
|
||||
request = _make_request(correlation_id="")
|
||||
assert pattern.is_subagent(request) is False
|
||||
|
||||
def test_returns_false_when_correlation_id_missing(self):
|
||||
pattern = _make_pattern()
|
||||
request = _make_request()
|
||||
assert pattern.is_subagent(request) is False
|
||||
|
||||
|
||||
class TestEmitSubagentCompletion:
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_calls_next_with_completion_request(self):
|
||||
pattern = _make_pattern()
|
||||
request = _make_request(
|
||||
correlation_id="corr-123",
|
||||
parent_session_id="parent-sess",
|
||||
subagent_goal="What is X?",
|
||||
expected_siblings=4,
|
||||
)
|
||||
next_fn = AsyncMock()
|
||||
|
||||
await pattern.emit_subagent_completion(
|
||||
request, next_fn, "The answer is Y",
|
||||
)
|
||||
|
||||
next_fn.assert_called_once()
|
||||
completion_req = next_fn.call_args[0][0]
|
||||
assert isinstance(completion_req, AgentRequest)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_completion_has_correct_step_type(self):
|
||||
pattern = _make_pattern()
|
||||
request = _make_request(
|
||||
correlation_id="corr-123",
|
||||
subagent_goal="What is X?",
|
||||
)
|
||||
next_fn = AsyncMock()
|
||||
|
||||
await pattern.emit_subagent_completion(
|
||||
request, next_fn, "answer text",
|
||||
)
|
||||
|
||||
completion_req = next_fn.call_args[0][0]
|
||||
assert len(completion_req.history) == 1
|
||||
step = completion_req.history[0]
|
||||
assert step.step_type == "subagent-completion"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_completion_carries_answer_in_observation(self):
|
||||
pattern = _make_pattern()
|
||||
request = _make_request(
|
||||
correlation_id="corr-123",
|
||||
subagent_goal="What is X?",
|
||||
)
|
||||
next_fn = AsyncMock()
|
||||
|
||||
await pattern.emit_subagent_completion(
|
||||
request, next_fn, "The answer is Y",
|
||||
)
|
||||
|
||||
completion_req = next_fn.call_args[0][0]
|
||||
step = completion_req.history[0]
|
||||
assert step.observation == "The answer is Y"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_completion_preserves_correlation_fields(self):
|
||||
pattern = _make_pattern()
|
||||
request = _make_request(
|
||||
correlation_id="corr-123",
|
||||
parent_session_id="parent-sess",
|
||||
subagent_goal="What is X?",
|
||||
expected_siblings=4,
|
||||
)
|
||||
next_fn = AsyncMock()
|
||||
|
||||
await pattern.emit_subagent_completion(
|
||||
request, next_fn, "answer",
|
||||
)
|
||||
|
||||
completion_req = next_fn.call_args[0][0]
|
||||
assert completion_req.correlation_id == "corr-123"
|
||||
assert completion_req.parent_session_id == "parent-sess"
|
||||
assert completion_req.subagent_goal == "What is X?"
|
||||
assert completion_req.expected_siblings == 4
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_completion_has_empty_pattern(self):
|
||||
pattern = _make_pattern()
|
||||
request = _make_request(
|
||||
correlation_id="corr-123",
|
||||
subagent_goal="goal",
|
||||
)
|
||||
next_fn = AsyncMock()
|
||||
|
||||
await pattern.emit_subagent_completion(
|
||||
request, next_fn, "answer",
|
||||
)
|
||||
|
||||
completion_req = next_fn.call_args[0][0]
|
||||
assert completion_req.pattern == ""
|
||||
Loading…
Add table
Add a link
Reference in a new issue