| """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 |
|
|