"""Unit tests for event dataclass wire serialization."""
import pytest
from navi.core.events import (
AIHelperTokensUsed,
CompressionStarted,
ContextCompressed,
PlanReady,
PlanningDebugData,
PlanningStatus,
ProfileSwitched,
StreamEnd,
StreamStopped,
SubagentComplete,
TextDelta,
ThinkingDelta,
ThinkingEnd,
ToolEvent,
ToolStarted,
TurnThinking,
)
class TestToolStarted:
def test_to_wire(self):
ev = ToolStarted(tool_name="fs", arguments={"action": "read"})
assert ev.to_wire() == {
"type": "tool_started",
"tool": "fs",
"args": {"action": "read"},
"is_subagent": False,
"tool_call_id": "",
}
def test_to_wire_subagent(self):
ev = ToolStarted(tool_name="spawn_agent", arguments={}, is_subagent=True)
assert ev.to_wire()["is_subagent"] is True
class TestToolEvent:
def test_to_wire(self):
ev = ToolEvent(
tool_name="fs",
arguments={"path": "/tmp"},
result="file contents",
success=True,
metadata={"size": 42},
)
assert ev.to_wire() == {
"type": "tool_call",
"tool": "fs",
"args": {"path": "/tmp"},
"result": "file contents",
"success": True,
"is_subagent": False,
"metadata": {"size": 42},
"tool_call_id": "",
}
class TestTextDelta:
def test_to_wire(self):
assert TextDelta(delta="hello").to_wire() == {"type": "stream_delta", "delta": "hello"}
class TestThinkingDelta:
def test_to_wire(self):
assert ThinkingDelta(delta="hmm").to_wire() == {"type": "thinking_delta", "delta": "hmm"}
class TestThinkingEnd:
def test_to_wire(self):
assert ThinkingEnd().to_wire() == {"type": "thinking_end"}
class TestStreamEnd:
def test_to_wire(self):
ev = StreamEnd(
full_content="done",
context_tokens=150,
max_context_tokens=8192,
elapsed_seconds=1.5,
tool_call_count=2,
token_count=150,
)
wire = ev.to_wire()
assert wire["type"] == "stream_end"
assert wire["content"] == "done"
assert wire["context_tokens"] == 150
assert wire["tool_call_count"] == 2
class TestStreamStopped:
def test_to_wire(self):
assert StreamStopped().to_wire() == {"type": "stream_stopped"}
class TestContextCompressed:
def test_to_wire(self):
ev = ContextCompressed(messages_before=10, messages_after=3, summary="summary text")
wire = ev.to_wire()
assert wire["type"] == "context_compressed"
assert wire["messages_before"] == 10
assert wire["messages_after"] == 3
assert wire["summary"] == "summary text"
assert wire["context_tokens"] is None
class TestProfileSwitched:
def test_to_wire(self):
ev = ProfileSwitched(profile_id="dev", profile_name="Developer")
assert ev.to_wire() == {
"type": "profile_switched",
"profile_id": "dev",
"profile_name": "Developer",
}
class TestPlanningStatus:
def test_to_wire(self):
ev = PlanningStatus(phase=1, label="Working on it...")
assert ev.to_wire() == {
"type": "planning_status",
"phase": 1,
"label": "Working on it...",
"is_subagent": False,
}
class TestPlanReady:
def test_to_wire(self):
ev = PlanReady(plan="1. Do thing")
wire = ev.to_wire()
assert wire["type"] == "plan_ready"
assert wire["plan"] == "1. Do thing"
assert wire["is_subagent"] is False
class TestTurnThinking:
def test_to_wire(self):
ev = TurnThinking(thinking="reasoning...", is_subagent=True)
wire = ev.to_wire()
assert wire["type"] == "turn_thinking"
assert wire["thinking"] == "reasoning..."
assert wire["is_subagent"] is True
class TestCompressionStarted:
def test_to_wire(self):
ev = CompressionStarted(context_tokens=5000, max_context_tokens=8192)
wire = ev.to_wire()
assert wire["type"] == "compression_started"
assert wire["context_tokens"] == 5000
assert wire["max_context_tokens"] == 8192
class TestInternalEvents:
"""Internal events must NOT serialize to the wire."""
def test_subagent_complete(self):
assert SubagentComplete(token_count=42).to_wire() is None
def test_planning_debug_data(self):
assert PlanningDebugData(log={"phases": {}}).to_wire() is None
def test_ai_helper_tokens_used(self):
ev = AIHelperTokensUsed(prompt_tokens=10, completion_tokens=20)
assert ev.to_wire() is None
assert ev.total == 30