from __future__ import annotations import unittest from agent_integration.client import OpenAgentEvent from agent_integration.events import AgentStreamNormalizer class AgentStreamNormalizerTests(unittest.TestCase): def test_live_langgraph_shape_exposes_only_visible_answer(self): normalizer = AgentStreamNormalizer() raw_events = [ OpenAgentEvent( event="metadata", data={"run_id": "run-001", "thread_id": "internal-thread"}, event_id="1", ), OpenAgentEvent( event="values", data={ "messages": [{"type": "human", "content": "hello"}], "thread_data": {"workspace_path": "/internal/secret/path"}, }, ), OpenAgentEvent( event="messages", data=[ { "type": "AIMessageChunk", "content": "", "additional_kwargs": {"reasoning_content": "INTERNAL_REASONING"}, }, {"langgraph_node": "model"}, ], ), OpenAgentEvent( event="messages", data=[ {"type": "AIMessageChunk", "content": "INTERNAL_TITLE"}, {"langgraph_node": "TitleMiddleware.after_model", "tags": ["middleware:title"]}, ], ), OpenAgentEvent( event="messages", data=[ {"type": "AIMessageChunk", "content": "连接"}, {"langgraph_node": "model"}, ], event_id="2", ), OpenAgentEvent( event="messages", data=[ {"type": "AIMessageChunk", "content": "成功"}, {"langgraph_node": "model"}, ], event_id="3", ), OpenAgentEvent( event="messages", data=[ { "type": "ai", "content": "连接成功", "additional_kwargs": {"reasoning_content": "INTERNAL_REASONING"}, }, {"langgraph_node": "model"}, ], ), OpenAgentEvent( event="values", data={ "messages": [ {"type": "human", "content": "hello"}, { "type": "ai", "content": "连接成功", "additional_kwargs": {"reasoning_content": "INTERNAL_REASONING"}, }, ], "thread_data": {"workspace_path": "/internal/secret/path"}, }, ), OpenAgentEvent( event="error", data={ "code": "open_agent_final_content_missing", "message": "Open agent run completed without final content", "retryable": True, "run_id": "run-001", "request_id": "request-001", "internal_trace": "DO_NOT_EXPOSE", }, ), OpenAgentEvent(event="end", data=None, event_id="4"), ] public_events = [] for event in raw_events: public_events.extend(normalizer.feed(event)) public_events.extend(normalizer.finish()) self.assertEqual( [event.event for event in public_events], [ "run.started", "message.delta", "message.delta", "message.completed", "run.warning", "run.end", ], ) self.assertEqual(public_events[0].data, {"run_id": "run-001"}) self.assertEqual(public_events[1].data, {"content": "连接"}) self.assertEqual(public_events[2].data, {"content": "成功"}) self.assertEqual( public_events[3].data, {"content": "连接成功", "streamed": True}, ) self.assertEqual(public_events[4].event, "run.warning") self.assertEqual(public_events[5].data["status"], "completed_with_warning") self.assertFalse(normalizer.fatal_error) self.assertEqual(normalizer.final_content, "连接成功") rendered = repr([event.to_dict() for event in public_events]) self.assertNotIn("INTERNAL_REASONING", rendered) self.assertNotIn("INTERNAL_TITLE", rendered) self.assertNotIn("secret/path", rendered) self.assertNotIn("DO_NOT_EXPOSE", rendered) def test_final_content_missing_without_visible_content_is_fatal(self): normalizer = AgentStreamNormalizer() normalizer.feed( OpenAgentEvent( event="error", data={ "code": "open_agent_final_content_missing", "message": "missing", "retryable": True, }, ) ) public_events = normalizer.feed(OpenAgentEvent(event="end", data=None)) self.assertTrue(normalizer.fatal_error) self.assertEqual([event.event for event in public_events], ["run.error", "run.end"]) self.assertEqual(public_events[-1].data["status"], "failed") def test_values_final_message_is_fallback_when_no_deltas_arrive(self): normalizer = AgentStreamNormalizer() normalizer.feed( OpenAgentEvent( event="values", data={"messages": [{"type": "ai", "content": "完整答案"}]}, ) ) public_events = normalizer.finish() self.assertEqual(public_events[0].event, "message.completed") self.assertEqual( public_events[0].data, {"content": "完整答案", "streamed": False}, ) self.assertFalse(normalizer.fatal_error) def test_documented_message_delta_shape_remains_supported(self): normalizer = AgentStreamNormalizer() public_events = normalizer.feed( OpenAgentEvent(event="message.delta", data={"content": "你"}) ) normalizer.feed( OpenAgentEvent(event="run.completed", data={"status": "completed"}) ) public_events.extend(normalizer.finish()) self.assertEqual(public_events[0].data, {"content": "你"}) self.assertEqual(public_events[1].data, {"content": "你", "streamed": True}) self.assertEqual(public_events[2].data["status"], "completed") if __name__ == "__main__": unittest.main(verbosity=2)