"""Regression: event factory shapes (UI relies on these field names).""" from api.analyses.types import Finding from api.runtime import events def test_run_start_shape(): e = events.run_start("why?") assert e == {"type": "run_start", "question": "why?"} def test_run_end_shape(): assert events.run_end(answer="42") == {"type": "run_end", "answer": "42", "error": None} assert events.run_end(error="boom") == {"type": "run_end", "answer": "", "error": "boom"} def test_plan_ready_shape(): e = events.plan_ready("rat", [{"analysis": "x", "args": {}, "why": ""}]) assert e["type"] == "plan_ready" assert e["rationale"] == "rat" assert isinstance(e["steps"], list) def test_analysis_start_shape(): e = events.analysis_start("direct_answer", {"q": "?"}, "fits") assert e == { "type": "analysis_start", "analysis": "direct_answer", "args": {"q": "?"}, "why": "fits", } def test_analysis_end_uses_finding(): f = Finding(analysis="direct_answer", summary="ok", rows=[{"a": 1}], sql=["SELECT 1"]) e = events.analysis_end("direct_answer", f) assert e["type"] == "analysis_end" assert e["analysis"] == "direct_answer" assert e["summary"] == "ok" assert e["error"] is None assert e["row_count"] == 1 def test_tool_call_shapes(): s = events.tool_call_start("text_to_sql", input={"q": "?"}) assert s == {"type": "tool_call_start", "tool": "text_to_sql", "input": {"q": "?"}} e = events.tool_call_end("text_to_sql", output={"sql": "..."}) assert e == {"type": "tool_call_end", "tool": "text_to_sql", "output": {"sql": "..."}, "error": None} def test_synth_start_shape(): assert events.synth_start() == {"type": "synth_start"} def test_sse_format_round_trip(): payload = events.tool_call_start("t", input={"x": 1}) formatted = events.sse_format(payload) assert formatted.startswith("event: tool_call_start\n") assert "data: " in formatted assert formatted.endswith("\n\n")