trustgraph/tests/unit/test_agent/test_pattern_base_subagent.py
Cyber MacGeddon 85fc5d0f4a - test_aggregator.py (16 tests) — register_fanout,
record_completion, get_original_request,
  build_synthesis_request, cleanup_stale
- test_provenance_triples.py (19 tests) — all 5 triple builders:
  decomposition, finding, plan, step_result, synthesis —
  verifying types, provenance links, goals/steps, document
  references, labels
- test_explainability_parsing.py (21 tests) — from_triples
  dispatch for all new types, parsing of goals/steps/documents,
  precedence ordering, backwards compatibility with
  Analysis/Conclusion

File: test_aggregator.py
Tests: 16
Covers: register_fanout, record_completion, get_original_request,
  build_synthesis_request, cleanup_stale
────────────────────────────────────────
File: test_provenance_triples.py
Tests: 19
Covers: All 5 triple builders: types, provenance links, goals/steps,
documents,
  labels
────────────────────────────────────────
File: test_explainability_parsing.py
Tests: 21
Covers: from_triples dispatch, parsing for Decomposition, Finding, Plan,
  StepResult
────────────────────────────────────────
File: test_pattern_base_subagent.py
Tests: 8
Covers: is_subagent, emit_subagent_completion
────────────────────────────────────────
File: test_completion_dispatch.py
Tests: 6
Covers: Completion detection logic, full aggregator integration flow,
synthesis
  not re-intercepted
────────────────────────────────────────
File: test_orchestrator_contracts.py
Tests: 7
Covers: Orchestration fields roundtrip, subagent-completion step, synthesis
  step, plan step

Tests
2026-03-31 13:09:22 +01:00

144 lines
4.1 KiB
Python

"""
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 == ""