feat(sse,tui): bump spec pin to v0.28.0 + AffectUpdate event (v0.11.0)
Spec pin moved 55101e9 (v0.19.0) → da93ca7 (v0.28.0); vendored conversation-api-spec.md + conversation_api.contract.md re-snapshotted from Worldtree at the new SHA. The only material delta consumed in this bump is Worldtree #204's affect_update SSE event surface. Wire layer (sse_client.py): - New AffectUpdate dataclass: sse_id / status / turn_id / snapshot (snapshot is None for status="scheduled") - Added to Event union + _envelope_for_type dispatch branch - Without this, ratatoskr would crash on any persona-enabled turn from a v0.28.0 server (unknown SSE event type → ValueError) TUI layer (tui.py): - AffectUpdate routes through the v0.10.0 audit pipeline only — one debug-pane line per arrival with dominant_emotion + PAD for status="current", lightweight status+turn_id for status="scheduled" - No transcript / tools / thinking pane writes — the persona UX shape (Persona TabPane vs sticky header line) is deferred to a separate bump pending operator direction Tests: 2 new wire-layer tests for current+scheduled parsing + 2 new presenter audit tests for routing and audit-line shape. Not yet consumed: GET /agents/{id}/persona_state endpoint (step 2 of the integration plan).
This commit is contained in:
@@ -682,6 +682,67 @@ class TestPresenterAuditLogging:
|
||||
assert state.text_delta_count == 1
|
||||
assert state.text_byte_count == len("hello world")
|
||||
|
||||
def test_affect_update_routes_to_audit_only(self) -> None:
|
||||
"""affect_update_routes_to_audit_only [v0.11.0]: AffectUpdate emits ONE
|
||||
debug-pane audit line (with dominant_emotion + PAD for status=current)
|
||||
and touches NO other pane (no transcript mount, no tools_log, no
|
||||
thinking_log). UX shape (persona pane / sticky header) is deferred.
|
||||
"""
|
||||
from ratatoskr.sse_client import AffectUpdate
|
||||
from ratatoskr.tui import TuiPresenterState
|
||||
|
||||
transcript = MagicMock()
|
||||
tools_log = MagicMock()
|
||||
thinking_log = MagicMock()
|
||||
debug_log = MagicMock()
|
||||
state = TuiPresenterState()
|
||||
snapshot = {
|
||||
"agent_id": "mimir",
|
||||
"pad": {"pleasure": 0.5, "arousal": 0.4, "dominance": 0.5},
|
||||
"dominant_emotion": "curiosity",
|
||||
}
|
||||
state.render(
|
||||
AffectUpdate(sse_id=SID, status="current", turn_id=42, snapshot=snapshot),
|
||||
transcript=transcript,
|
||||
tools_log=tools_log,
|
||||
debug_log=debug_log,
|
||||
thinking_log=thinking_log,
|
||||
raw=False,
|
||||
)
|
||||
assert debug_log.write.call_count == 1
|
||||
audit = _text_of(debug_log.write.call_args[0][0])
|
||||
assert "affectupdate" in audit
|
||||
assert "status=current" in audit
|
||||
assert "dominant_emotion='curiosity'" in audit
|
||||
assert "pad=(0.5,0.4,0.5)" in audit
|
||||
assert not transcript.mount.called
|
||||
assert not tools_log.write.called
|
||||
assert not thinking_log.write.called
|
||||
|
||||
def test_affect_update_scheduled_has_no_pad_detail(self) -> None:
|
||||
"""affect_update_scheduled_has_no_pad_detail [v0.11.0]: status=scheduled
|
||||
carries no snapshot — the audit line omits dominant_emotion / pad and
|
||||
contains only status + turn_id.
|
||||
"""
|
||||
from ratatoskr.sse_client import AffectUpdate
|
||||
from ratatoskr.tui import TuiPresenterState
|
||||
|
||||
debug_log = MagicMock()
|
||||
state = TuiPresenterState()
|
||||
state.render(
|
||||
AffectUpdate(sse_id=SID, status="scheduled", turn_id=42, snapshot=None),
|
||||
transcript=MagicMock(),
|
||||
tools_log=MagicMock(),
|
||||
debug_log=debug_log,
|
||||
thinking_log=MagicMock(),
|
||||
raw=False,
|
||||
)
|
||||
audit = _text_of(debug_log.write.call_args[0][0])
|
||||
assert "status=scheduled" in audit
|
||||
assert "turn_id=42" in audit
|
||||
assert "dominant_emotion" not in audit
|
||||
assert "pad=" not in audit
|
||||
|
||||
def test_done_emits_turn_summary_line(self) -> None:
|
||||
"""done_emits_turn_summary_line: when Done arrives the presenter
|
||||
emits a `turn_summary` line aggregating per-delta Text + Thinking
|
||||
|
||||
Reference in New Issue
Block a user