Status: done
Implemented by subagent and locally verified with:
uv run pytest tests/test_openai_stream_parser.py tests/test_event_agent.py tests/test_debug_runtime.py
Result: 3 passed in 0.07s.
Evaluation note: the runtime currently streams message deltas to the caller but does not yet persist the aggregated assistant message into conversation history. Todo 3 should cover transcript persistence when wiring the WebSocket/API surface.
Implement the core domain/runtime loop that passes the existing Todo 1 tests without adding WebSocket, FastAPI routes, or UI.
This todo covers:
This todo does not cover:
src/agent_lab/domain/events.pysrc/agent_lab/domain/messages.pysrc/agent_lab/application/contracts.pysrc/agent_lab/application/event_agent.pysrc/agent_lab/application/runtime.pysrc/agent_lab/infrastructure/openai_compatible.pydocs/plans/todos.mdUse small Pydantic models for contracts that cross application boundaries and dataclasses for internal stream items. Keep tool handling intentionally simple:
ToolCallEvent.name is the ChatAgent tool name.ToolCallEvent.name as the tool identifier.handoff_note, that returns a JSON tool reply.DebugRuntime.run() is an async generator. It builds initial messages from system prompts, pre-messages, and the user message. It calls chat_client.stream_chat(), yields message deltas and events, sends events to EventAgent, appends the returned tool message, and calls ChatAgent again until no event is produced or max_event_loops is reached.
events.py and messages.py.contracts.py.EventAgent.handle().ChatCompletionStreamParser.feed() for OpenAI-compatible streamed chunks:
StreamItem.message_delta.index.finish_reason == "tool_calls", emit StreamItem.event for each completed tool call.StreamItem.usage.DebugRuntime.run() around the chat client protocol.uv run pytest tests/test_openai_stream_parser.py tests/test_event_agent.py tests/test_debug_runtime.py.Run:
uv run pytest tests/test_openai_stream_parser.py tests/test_event_agent.py tests/test_debug_runtime.py
Expected result: