mirror of
https://github.com/openai/codex.git
synced 2026-10-30 19:18:49 +00:00
Support standalone tool outputs in turn/start (#41002)
## What changed - Add an optional `toolOutput` to `turn/start` for starting or steering a turn with a named function-call output instead of user input. - Emit standalone outputs as `functionCallOutput` thread items, persist them in durable history, and include them in resumed threads. - Validate that tool outputs have a name, are not combined with nonempty `input`, satisfy the text-size limit, and use supported image URLs. ## Testing - Cover standalone tool-output notifications, model input, and resumed history in both legacy and paginated history modes. - Cover the text-size limit for structured tool output. GitOrigin-RevId: a1eeec7b9b7de67b1a1c5e829a54552b85ec118b
This commit is contained in:
@@ -604,6 +604,7 @@ impl ThreadHistoryBuilder {
|
||||
let should_upsert = match item {
|
||||
codex_protocol::items::TurnItem::Plan(plan) => !plan.text.is_empty(),
|
||||
codex_protocol::items::TurnItem::HookPrompt(_)
|
||||
| codex_protocol::items::TurnItem::FunctionCallOutput(_)
|
||||
| codex_protocol::items::TurnItem::CommandExecution(_)
|
||||
| codex_protocol::items::TurnItem::DynamicToolCall(_)
|
||||
| codex_protocol::items::TurnItem::CollabAgentToolCall(_)
|
||||
|
||||
@@ -34,6 +34,7 @@ use codex_protocol::items::McpToolCallStatus as CoreMcpToolCallStatus;
|
||||
use codex_protocol::items::TurnItem as CoreTurnItem;
|
||||
use codex_protocol::memory_citation::MemoryCitation as CoreMemoryCitation;
|
||||
use codex_protocol::memory_citation::MemoryCitationEntry as CoreMemoryCitationEntry;
|
||||
use codex_protocol::models::FunctionCallOutputBody;
|
||||
use codex_protocol::models::MessagePhase;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::openai_models::ReasoningEffort;
|
||||
@@ -257,6 +258,14 @@ pub enum ThreadItem {
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
FunctionCallOutput {
|
||||
id: String,
|
||||
name: String,
|
||||
namespace: Option<String>,
|
||||
output: FunctionCallOutputBody,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
/// EXPERIMENTAL - proposed plan item content. The completed plan item is
|
||||
/// authoritative and may not match the concatenation of `PlanDelta` text.
|
||||
Plan {
|
||||
@@ -429,6 +438,7 @@ impl ThreadItem {
|
||||
ThreadItem::UserMessage { id, .. }
|
||||
| ThreadItem::HookPrompt { id, .. }
|
||||
| ThreadItem::AgentMessage { id, .. }
|
||||
| ThreadItem::FunctionCallOutput { id, .. }
|
||||
| ThreadItem::Plan { id, .. }
|
||||
| ThreadItem::Reasoning { id, .. }
|
||||
| ThreadItem::CommandExecution { id, .. }
|
||||
@@ -873,6 +883,12 @@ impl From<CoreTurnItem> for ThreadItem {
|
||||
delivery: agent.delivery,
|
||||
}
|
||||
}
|
||||
CoreTurnItem::FunctionCallOutput(output) => ThreadItem::FunctionCallOutput {
|
||||
id: output.id,
|
||||
name: output.name,
|
||||
namespace: output.namespace,
|
||||
output: output.output,
|
||||
},
|
||||
CoreTurnItem::Plan(plan) => ThreadItem::Plan {
|
||||
id: plan.id,
|
||||
text: plan.text,
|
||||
|
||||
@@ -4724,6 +4724,7 @@ fn turn_start_params_preserve_explicit_null_service_tier() {
|
||||
client_user_message_id: None,
|
||||
input: vec![],
|
||||
turn_trigger: None,
|
||||
tool_output: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: None,
|
||||
environments: None,
|
||||
|
||||
@@ -9,6 +9,7 @@ use codex_protocol::config_types::CollaborationMode;
|
||||
use codex_protocol::config_types::MultiAgentMode;
|
||||
use codex_protocol::config_types::Personality;
|
||||
use codex_protocol::config_types::ReasoningSummary;
|
||||
use codex_protocol::models::FunctionCallOutputBody;
|
||||
use codex_protocol::models::ImageDetail;
|
||||
use codex_protocol::openai_models::ReasoningEffort;
|
||||
use codex_protocol::plan_tool::PlanItemArg as CorePlanItemArg;
|
||||
@@ -134,6 +135,15 @@ impl From<CyberAccessProgram> for CoreCyberAccessProgram {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct TurnToolOutput {
|
||||
pub name: String,
|
||||
pub namespace: Option<String>,
|
||||
pub output: FunctionCallOutputBody,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Default, Clone, PartialEq, JsonSchema, TS, ExperimentalApi,
|
||||
)]
|
||||
@@ -148,6 +158,8 @@ pub struct TurnStartParams {
|
||||
/// Ignored when this request steers an already-active turn.
|
||||
#[ts(optional = nullable)]
|
||||
pub turn_trigger: Option<String>,
|
||||
#[ts(optional = nullable)]
|
||||
pub tool_output: Option<Box<TurnToolOutput>>,
|
||||
/// Optional metadata to enrich Codex's ResponsesAPI turn metadata.
|
||||
///
|
||||
/// Entries are flattened into the JSON string sent as
|
||||
|
||||
Reference in New Issue
Block a user