# Open Responses mapping (llm_client -> Open Responses) This document maps the current `llm_client` event model to Open Responses items and streaming events. It focuses on output streaming; input items are noted where they are the closest semantic match. ## Legend - **OR item**: Open Responses item types used in `response.output`. - **OR event**: Open Responses streaming events (`response.*`). - **Note**: Gaps or required adaptation decisions. ## Response lifecycle / meta events | llm_client | Open Responses | Note | | ------------------------ | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | | `StatusEvent::Started` | `response.created`, `response.queued`, `response.in_progress` | OR has finer-grained lifecycle states; pick a subset or map Started -> `response.in_progress`. | | `StatusEvent::Completed` | `response.completed` | | | `StatusEvent::Failed` | `response.failed` | | | `StatusEvent::Cancelled` | (no direct event) | Could map to `response.incomplete` or `response.failed` depending on semantics. | | `UsageEvent` | `response.completed` payload usage | OR reports usage on the response object, not as a dedicated streaming event. | | `ErrorEvent` | `error` event | OR has a dedicated error streaming event. | | `PingEvent` | (no direct event) | OR does not define a heartbeat event. | ## Output block lifecycle ### Text block | llm_client | Open Responses | Note | | ------------------------------------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | `BlockStart { block_type: Text, metadata: Text }` | `response.output_item.added` with item type `message` (assistant) | OR output items are message/function_call/reasoning. This creates the message item. | | `BlockDelta { delta: Text(..) }` | `response.output_text.delta` | Text deltas map 1:1 to output text deltas. | | `BlockStop { block_type: Text }` | `response.output_text.done` + `response.content_part.done` + `response.output_item.done` | OR emits separate done events for content parts and items. | ### Tool use (function call) | llm_client | Open Responses | Note | | -------------------------------------------------------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | | `BlockStart { block_type: ToolUse, metadata: ToolUse { id, name } }` | `response.output_item.added` with item type `function_call` | OR uses `call_id` + `name` + `arguments` string. Map `id` -> `call_id`. | | `BlockDelta { delta: InputJson(..) }` | `response.function_call_arguments.delta` | OR spec does not explicitly require argument deltas; treat as OpenAI-compatible extension if adopted. | | `BlockStop { block_type: ToolUse }` | `response.function_call_arguments.done` + `response.output_item.done` | Item status can be set to `completed` or `incomplete`. | ### Tool result (function call output) | llm_client | Open Responses | Note | | ----------------------------------------------------------------------------- | ------------------------------------- | ---------------------------------------------------------------------------------------- | | `BlockStart { block_type: ToolResult, metadata: ToolResult { tool_use_id } }` | **Input item** `function_call_output` | OR treats tool results as input items, not output items. This is a request-side mapping. | | `BlockDelta` | (no direct output event) | OR does not stream tool output deltas as response events. | | `BlockStop` | (no direct output event) | Tool output lives on the next request as an input item. | ### Thinking / reasoning | llm_client | Open Responses | Note | | --------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `BlockStart { block_type: Thinking, metadata: Thinking }` | `response.output_item.added` with item type `reasoning` | OR models reasoning as a separate item type. | | `BlockDelta { delta: Thinking(..) }` | `response.reasoning.delta` | OR has dedicated reasoning delta events. | | `BlockStop { block_type: Thinking }` | `response.reasoning.done` | OR separates reasoning summary events (`response.reasoning_summary_*`) from reasoning deltas. Decide whether Thinking maps to full reasoning or summary only. | ## Stop reasons | llm_client `StopReason` | Open Responses | Note | | ----------------------- | ------------------------------------------------------------------------------ | ---------------------------------------------- | | `EndTurn` | `response.completed` + item status `completed` | | | `MaxTokens` | `response.incomplete` + item status `incomplete` | | | `StopSequence` | `response.completed` | | | `ToolUse` | `response.completed` for message item, followed by `function_call` output item | OR models tool call as a separate output item. | ## Gaps / open decisions - `PingEvent` has no OR equivalent. If needed, keep as internal only. - `Cancelled` status needs a policy: map to `response.incomplete` or `response.failed`. - OR has `response.refusal.delta` / `response.refusal.done`. `llm_client` has no refusal delta type; consider adding a new block or delta variant if needed. - OR splits _item_ and _content part_ lifecycles. `llm_client` currently has a single block lifecycle, so mapping should decide whether to synthesize `content_part.*` events or ignore them. - The OR specification does not state how `function_call.arguments` stream deltas; `response.function_call_arguments.*` should be treated as a compatible extension if required.