You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Proposal: Accept Custom Tool Outputs From Headless Clients
Background
We embed the Codex runtime inside non-interactive tooling to orchestrate automated code edits and test runs. The Codex service dutifully emits PatchApplyBegin/End, ExecCommand*, and eventually TaskComplete, but the client has no public hook to acknowledge the tool calls. The protocol already defines ResponseInputItem::CustomToolCallOutput / FunctionCallOutputPayload, yet codex_core::CodexConversation only accepts plain InputItems (user text, images). Consequently:
The sandbox keeps retrying the patch (PatchApplyBegin loops indefinitely) because it never receives the custom_tool_call_output payload it expects.
Multi-step workflows (“apply patch → exec tests → apply follow-up patch”) are impossible outside of the interactive Codex UI/CLI.
Automations have to panic out once the first agent message arrives, breaking the turn while the server still believes the tool call is pending.
You can reproduce this today by running codex exec --experimental-json and observing the patch events: every apply_patch request is re-issued until you abort.
Proposed API surface
Expose a minimal way to submit tool results back to the running turn:
Protocol: Add a new submission variant so clients can emit ResponseInputItems.
diff --git a/codex-rs/protocol/src/protocol.rs b/codex-rs/protocol/src/protocol.rs
--- a/codex-rs/protocol/src/protocol.rs
+++ b/codex-rs/protocol/src/protocol.rs
@@
-use crate::models::{ContentItem,ResponseItem};
+usecrate::models::{ContentItem,ResponseItem,ResponseInputItem};
@@
- /// Request to shut down codex instance.
- Shutdown,
+ /// Request to shut down codex instance.
+ Shutdown,
+
+ /// Supply tool results (e.g. custom tool call / exec outputs) that the
+ /// model should consume on the next turn.
+ ClientResponseItems{
+ items:Vec<ResponseInputItem>,
+ },
Server: Enqueue those items alongside other pending input so the next call to run_turn sees them.
diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs
--- a/codex-rs/core/src/codex.rs
+++ b/codex-rs/core/src/codex.rs
@@
match sub.op{Op::Interrupt => {
sess.interrupt_task().await;}
+ Op::ClientResponseItems{ items } => {
+ letmut active = sess.active_turn.lock().await;
+ ifletSome(at) = active.as_mut(){
+ letmut ts = at.turn_state.lock().await;
+ for item in items {
+ ts.push_pending_input(item);
+ }
+ }else{
+ warn!("ClientResponseItems received without an active turn; dropping");
+ }
+ }Op::OverrideTurnContext{
cwd,
approval_policy,
sandbox_policy,
(This reuses the existing TurnState::push_pending_input machinery that run_task already consumes.)
Optionally surface a convenience on CodexConversation, e.g.:
Headless automation (CLI wrappers, CI bots) needs to acknowledge tool calls for Codex to stop retrying. Without this, every apply_patch / exec loops until timeout.
Multi-step flows (apply patch ➝ run tests ➝ apply follow-up) simply do not work outside of the official UI. The agent keeps waiting for tool results that the SDK cannot send.
Service stability suffers: Codex logs a stream of redundant tool requests, the client races to abort, and the turn ends in a semi-failed state.
For example, when our utility applies a patch we currently see:
We had to add a “break after N repeats” guard just to avoid infinite loops—clearly not the desired handshake.
Who benefits
Any consumer running Codex headlessly (SDKs, CLI wrappers, CI systems) needs this acknowledgement path to orchestrate tool usage without a human-in-the-loop.
Concrete request
Add the ClientResponseItems submission and the corresponding server handler.
Thanks for considering—this small hook unblocks automated tooling to be built using the vanilla fork of Codex!
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Proposal: Accept Custom Tool Outputs From Headless Clients
Background
We embed the Codex runtime inside non-interactive tooling to orchestrate automated code edits and test runs. The Codex service dutifully emits PatchApplyBegin/End, ExecCommand*, and eventually TaskComplete, but the client has no public hook to acknowledge the tool calls. The protocol already defines ResponseInputItem::CustomToolCallOutput / FunctionCallOutputPayload, yet codex_core::CodexConversation only accepts plain InputItems (user text, images). Consequently:
You can reproduce this today by running codex exec --experimental-json and observing the patch events: every apply_patch request is re-issued until you abort.
Proposed API surface
Expose a minimal way to submit tool results back to the running turn:
(This reuses the existing TurnState::push_pending_input machinery that run_task already consumes.)
Why this matters
For example, when our utility applies a patch we currently see:
We had to add a “break after N repeats” guard just to avoid infinite loops—clearly not the desired handshake.
Who benefits
Any consumer running Codex headlessly (SDKs, CLI wrappers, CI systems) needs this acknowledgement path to orchestrate tool usage without a human-in-the-loop.
Concrete request
Thanks for considering—this small hook unblocks automated tooling to be built using the vanilla fork of Codex!
Beta Was this translation helpful? Give feedback.
All reactions