"""Chat orchestration: run the agent against a user turn, stream tokens, return cost.""" from typing import AsyncIterator from agents import Agent, Runner, SQLiteSession from openai.types.responses import ResponseTextDeltaEvent from .cost import CostBreakdown, cost_from_usage async def chat_turn( user_message: str, agent: Agent, session: SQLiteSession, max_turns: int = 8, ) -> AsyncIterator[tuple[str, CostBreakdown | None]]: """Run one user turn. Yields (accumulated_text, cost_or_None). Cost is None on every yield until the final one — the final yield contains the same accumulated text plus the run's cost breakdown. """ result = Runner.run_streamed( agent, user_message, session=session, max_turns=max_turns, ) text = "" async for event in result.stream_events(): if event.type == "raw_response_event" and isinstance( event.data, ResponseTextDeltaEvent ): text += event.data.delta yield text, None cost = cost_from_usage(result.context_wrapper.usage) yield text, cost