Skip to content

Conversation

@pakrym-oai
Copy link
Collaborator

@pakrym-oai pakrym-oai commented Oct 23, 2025

Adds AgentMessageContentDelta, ReasoningContentDelta, ReasoningRawContentDelta item streaming events while maintaining compatibility for old events.

- Introduce AgentMessageContentDeltaEvent, ReasoningContentDeltaEvent, and ReasoningRawContentDeltaEvent with thread_id, turn_id, and item_id, emitted during streaming, alongside legacy events for compatibility.
- Refactor output delta handling to associate deltas with active items and emit item-specific delta events.
- Move legacy event emission via new HasLegacyEvent trait for simpler event compatibility.
- Update parse_agent_message to use
# Conflicts:
#	codex-rs/core/src/codex.rs
…egacy event for ItemStartedEvent

- Move `error_or_panic` from conversation_history.rs to util.rs and update all usage sites accordingly.
- Use `error_or_panic` in codex.rs to handle error conditions on various response events instead of directly logging with `error!`.
- Implement `HasLegacyEvent` for `ItemStartedEvent` in protocol.rs to emit a WebSearchBegin legacy event
@pakrym-oai pakrym-oai marked this pull request as ready for review October 24, 2025 02:47
Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +376 to +380
let item = ResponseItem::Message {
id: None,
role: "assistant".to_string(),
content: vec![],
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Emit stable IDs for streamed assistant items

When an assistant delta arrives in chat completions, append_assistant_text builds a ResponseItem::Message with id: None. Downstream, parse_turn_item assigns a fresh UUID whenever an item lacks an ID, so ItemStarted, AgentMessageContentDelta, and ItemCompleted events for the same streamed message use different generated IDs. Clients can’t correlate deltas with their corresponding completion and tests only pass because the mock SSE events already provide IDs. Assign a concrete ID when the item is first constructed and reuse it for all subsequent events so the identifier stays consistent.

Useful? React with 👍 / 👎.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems potentially legit feedback?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok so the feedback is legit but it always worked this way.

@pakrym-oai how big of a deal is this? either way, addressing this seems out of scope for this PR

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as we don't emit Item events with different item id (which I don't think we do based on active.id()) we should be good.

Copy link
Contributor

@owenlin0 owenlin0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overall lgtm! just a comment about the web search call


#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema)]
pub struct AgentMessageContentDeltaEvent {
pub thread_id: String,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decided to add these to all the events? nice!

Comment on lines +376 to +380
let item = ResponseItem::Message {
id: None,
role: "assistant".to_string(),
content: vec![],
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems potentially legit feedback?

.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
let ev = ResponseEvent::WebSearchCallBegin { call_id };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed we delete the WebSearchCall event in various places - what's the plan for that one?

Are we planning to support some translation of https://platform.openai.com/docs/api-reference/responses-streaming/response/web_search_call or just dropping it entirely?

My guess is Responses API does something like this for a web search call:

response.output_item.added
response.web_search_call.in_progress
response.web_search_call.searching
response.web_search_call.completed
response.output_item.done
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't actually need to handle web_search_call events specifically and we can emit EventMsg::WebSearchBegin and EventMsg::WebSearchEnd based on response.output_item.added response.output_item.done

Here's a trace of an actual request:

�[2m2025-10-24T16:10:55.257490Z�[0m �[35mTRACE�[0m SSE event: {"type":"response.output_item.added","sequence_number":203,"output_index":1,"item":{"id":"ws_0bb4a7dd4caece510168fba50f3a788190a16bcfee2fcef85a","type":"web_search_call","status":"in_progress"}}
�[2m2025-10-24T16:10:55.267924Z�[0m �[35mTRACE�[0m SSE event: {"type":"response.web_search_call.in_progress","sequence_number":204,"output_index":1,"item_id":"ws_0bb4a7dd4caece510168fba50f3a788190a16bcfee2fcef85a"}
�[2m2025-10-24T16:10:56.830551Z�[0m �[35mTRACE�[0m SSE event: {"type":"response.web_search_call.searching","sequence_number":205,"output_index":1,"item_id":"ws_0bb4a7dd4caece510168fba50f3a788190a16bcfee2fcef85a"}
�[2m2025-10-24T16:11:02.043478Z�[0m �[35mTRACE�[0m SSE event: {"type":"response.web_search_call.completed","sequence_number":206,"output_index":1,"item_id":"ws_0bb4a7dd4caece510168fba50f3a788190a16bcfee2fcef85a"}
�[2m2025-10-24T16:11:02.046008Z�[0m �[35mTRACE�[0m SSE event: {"type":"response.output_item.done","sequence_number":207,"output_index":1,"item":{"id":"ws_0bb4a7dd4caece510168fba50f3a788190a16bcfee2fcef85a","type":"web_search_call","status":"completed","action":{"type":"search","query":"top news headlines October 24, 2025 Reuters"}}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So Codex would do this client-side? i.e. Codex would inspect the output_item when it's added, and if it's a web search call, emit the EventMsg::WebSearchBegin event? I think that'd work but why not just translate the server events? Seems cleaner that way

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So Codex would do this client-side?
We already do this. see https://github.com/openai/codex/pull/5546/files#diff-6d2d1446867cf2e611597ebbf293689be55ad7cd32c1081cdab6de2358dccb91R539

If end goal is to have codex level item_starter/item_completed event and we can do it for all item types consistently by listening to item.added/item.completed from Responses API, why not do it? The end result is the same and the logic is simpler for us. We use the same code path for WebSearch, Agent Messages and Reasoning.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok sounds good. do we plan to keep exposing WebSearchCall events in the stable app-server API too?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, only ItemStarted with a WebSearch item type

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh i see, then it makes a lot of sense to do it client-side. ty for the explanation! 🚢

@owenlin0 owenlin0 force-pushed the pakrym/add-item-streaming-events branch 2 times, most recently from a08f260 to 8658848 Compare October 28, 2025 23:55
@owenlin0 owenlin0 enabled auto-merge (squash) October 29, 2025 21:54
EventMsg::ItemCompleted(ItemCompletedEvent {
item: TurnItem::AgentMessage(_),
..
}) => {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aibrahim-oai @pakrym-oai is this fix legit? trying to make sense of the review sub-codex delegation flow. codex helped me generate this fix, otherwise review_does_not_emit_agent_message_on_structured_output fails

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, reasonable

@owenlin0 owenlin0 merged commit 3429e82 into main Oct 29, 2025
25 checks passed
@owenlin0 owenlin0 deleted the pakrym/add-item-streaming-events branch October 29, 2025 22:33
@github-actions github-actions bot locked and limited conversation to collaborators Oct 29, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

3 participants