mirror of
https://github.com/openai/codex.git
synced 2026-02-02 06:57:03 +00:00
Compare commits
3 Commits
delete-op-
...
remove/doc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
200f07f1ec | ||
|
|
737654923f | ||
|
|
a9a56081d0 |
@@ -15,8 +15,8 @@ You can also install via Homebrew (`brew install --cask codex`) or download a pl
|
||||
|
||||
## Documentation quickstart
|
||||
|
||||
- First run with Codex? Start with [`docs/getting-started.md`](../docs/getting-started.md) (links to the walkthrough for prompts, keyboard shortcuts, and session management).
|
||||
- Want deeper control? See [`docs/config.md`](../docs/config.md) and [`docs/install.md`](../docs/install.md).
|
||||
- First run with Codex? Start with the [Getting Started guide](https://developers.openai.com/codex) (links to the walkthrough for prompts, keyboard shortcuts, and session management).
|
||||
- Want deeper control? See [Configuration documentation](https://developers.openai.com/codex/config-advanced/).
|
||||
|
||||
## What's new in the Rust CLI
|
||||
|
||||
@@ -24,13 +24,13 @@ The Rust implementation is now the maintained Codex CLI and serves as the defaul
|
||||
|
||||
### Config
|
||||
|
||||
Codex supports a rich set of configuration options. Note that the Rust CLI uses `config.toml` instead of `config.json`. See [`docs/config.md`](../docs/config.md) for details.
|
||||
Codex supports a rich set of configuration options. Note that the Rust CLI uses `config.toml` instead of `config.json`. See [Configuration documentation](https://developers.openai.com/codex/config-advanced/) for details.
|
||||
|
||||
### Model Context Protocol Support
|
||||
|
||||
#### MCP client
|
||||
|
||||
Codex CLI functions as an MCP client that allows the Codex CLI and IDE extension to connect to MCP servers on startup. See the [`configuration documentation`](../docs/config.md#connecting-to-mcp-servers) for details.
|
||||
Codex CLI functions as an MCP client that allows the Codex CLI and IDE extension to connect to MCP servers on startup. See the [configuration documentation](https://developers.openai.com/codex/config-advanced/) for details.
|
||||
|
||||
#### MCP server (experimental)
|
||||
|
||||
@@ -46,7 +46,7 @@ Use `codex mcp` to add/list/get/remove MCP server launchers defined in `config.t
|
||||
|
||||
### Notifications
|
||||
|
||||
You can enable notifications by configuring a script that is run whenever the agent finishes a turn. The [notify documentation](../docs/config.md#notify) includes a detailed example that explains how to get desktop notifications via [terminal-notifier](https://github.com/julienXX/terminal-notifier) on macOS. When Codex detects that it is running under WSL 2 inside Windows Terminal (`WT_SESSION` is set), the TUI automatically falls back to native Windows toast notifications so approval prompts and completed turns surface even though Windows Terminal does not implement OSC 9.
|
||||
You can enable notifications by configuring a script that is run whenever the agent finishes a turn. The [notify documentation](https://developers.openai.com/codex/config-advanced/#notifications) includes a detailed example that explains how to get desktop notifications via [terminal-notifier](https://github.com/julienXX/terminal-notifier) on macOS. When Codex detects that it is running under WSL 2 inside Windows Terminal (`WT_SESSION` is set), the TUI automatically falls back to native Windows toast notifications so approval prompts and completed turns surface even though Windows Terminal does not implement OSC 9.
|
||||
|
||||
### `codex exec` to run Codex programmatically/non-interactively
|
||||
|
||||
|
||||
@@ -3605,7 +3605,10 @@ impl CodexMessageProcessor {
|
||||
|
||||
// Submit user input to the conversation.
|
||||
let _ = conversation
|
||||
.submit_user_turn_with_defaults(mapped_items, None)
|
||||
.submit(Op::UserInput {
|
||||
items: mapped_items,
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await;
|
||||
|
||||
// Acknowledge with an empty result.
|
||||
@@ -3654,7 +3657,6 @@ impl CodexMessageProcessor {
|
||||
|
||||
let _ = conversation
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: mapped_items,
|
||||
cwd,
|
||||
approval_policy,
|
||||
@@ -3869,35 +3871,36 @@ impl CodexMessageProcessor {
|
||||
.map(V2UserInput::into_core)
|
||||
.collect();
|
||||
|
||||
// Start the turn by submitting the user input with the thread's current defaults,
|
||||
// overridden by any per-turn parameters.
|
||||
let snapshot = thread.config_snapshot().await;
|
||||
let cwd = params.cwd.unwrap_or(snapshot.cwd);
|
||||
let approval_policy = params
|
||||
.approval_policy
|
||||
.map(AskForApproval::to_core)
|
||||
.unwrap_or(snapshot.approval_policy);
|
||||
let sandbox_policy = params
|
||||
.sandbox_policy
|
||||
.map(|policy| policy.to_core())
|
||||
.unwrap_or(snapshot.sandbox_policy);
|
||||
let model = params.model.unwrap_or(snapshot.model);
|
||||
let effort = params.effort.or(snapshot.reasoning_effort);
|
||||
let summary = params.summary.unwrap_or(snapshot.reasoning_summary);
|
||||
let personality = params.personality.or(snapshot.personality);
|
||||
let has_any_overrides = params.cwd.is_some()
|
||||
|| params.approval_policy.is_some()
|
||||
|| params.sandbox_policy.is_some()
|
||||
|| params.model.is_some()
|
||||
|| params.effort.is_some()
|
||||
|| params.summary.is_some()
|
||||
|| params.collaboration_mode.is_some()
|
||||
|| params.personality.is_some();
|
||||
|
||||
// If any overrides are provided, update the session turn context first.
|
||||
if has_any_overrides {
|
||||
let _ = thread
|
||||
.submit(Op::OverrideTurnContext {
|
||||
cwd: params.cwd,
|
||||
approval_policy: params.approval_policy.map(AskForApproval::to_core),
|
||||
sandbox_policy: params.sandbox_policy.map(|p| p.to_core()),
|
||||
model: params.model,
|
||||
effort: params.effort.map(Some),
|
||||
summary: params.summary,
|
||||
collaboration_mode: params.collaboration_mode,
|
||||
personality: params.personality,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
// Start the turn by submitting the user input. Return its submission id as turn_id.
|
||||
let turn_id = thread
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
.submit(Op::UserInput {
|
||||
items: mapped_items,
|
||||
cwd,
|
||||
approval_policy,
|
||||
sandbox_policy,
|
||||
model,
|
||||
effort,
|
||||
summary,
|
||||
final_output_json_schema: params.output_schema,
|
||||
collaboration_mode: params.collaboration_mode,
|
||||
personality,
|
||||
})
|
||||
.await;
|
||||
|
||||
|
||||
@@ -2,5 +2,4 @@
|
||||
|
||||
This file has moved. Please see the latest configuration documentation here:
|
||||
|
||||
- Full config docs: [docs/config.md](../docs/config.md)
|
||||
- MCP servers section: [docs/config.md#connecting-to-mcp-servers](../docs/config.md#connecting-to-mcp-servers)
|
||||
- Configuration documentation: https://developers.openai.com/codex/config-advanced/
|
||||
|
||||
@@ -72,26 +72,19 @@ impl AgentControl {
|
||||
prompt: String,
|
||||
) -> CodexResult<String> {
|
||||
let state = self.upgrade()?;
|
||||
let thread = state.get_thread(agent_id).await?;
|
||||
let snapshot = thread.config_snapshot().await;
|
||||
let op = Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: prompt,
|
||||
// Agent control prompts are plain text with no UI text elements.
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
cwd: snapshot.cwd,
|
||||
approval_policy: snapshot.approval_policy,
|
||||
sandbox_policy: snapshot.sandbox_policy,
|
||||
model: snapshot.model,
|
||||
effort: snapshot.reasoning_effort,
|
||||
summary: snapshot.reasoning_summary,
|
||||
final_output_json_schema: None,
|
||||
collaboration_mode: None,
|
||||
personality: snapshot.personality,
|
||||
};
|
||||
let result = state.send_op(agent_id, op).await;
|
||||
let result = state
|
||||
.send_op(
|
||||
agent_id,
|
||||
Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: prompt,
|
||||
// Agent control prompts are plain text with no UI text elements.
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
final_output_json_schema: None,
|
||||
},
|
||||
)
|
||||
.await;
|
||||
if matches!(result, Err(CodexErr::InternalAgentDied)) {
|
||||
let _ = state.remove_thread(&agent_id).await;
|
||||
self.state.release_spawned_thread(agent_id);
|
||||
@@ -354,8 +347,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn send_prompt_submits_user_message() {
|
||||
let harness = AgentControlHarness::new().await;
|
||||
let (thread_id, thread) = harness.start_thread().await;
|
||||
let snapshot = thread.config_snapshot().await;
|
||||
let (thread_id, _thread) = harness.start_thread().await;
|
||||
|
||||
let submission_id = harness
|
||||
.control
|
||||
@@ -365,21 +357,12 @@ mod tests {
|
||||
assert!(!submission_id.is_empty());
|
||||
let expected = (
|
||||
thread_id,
|
||||
Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello from tests".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
cwd: snapshot.cwd,
|
||||
approval_policy: snapshot.approval_policy,
|
||||
sandbox_policy: snapshot.sandbox_policy,
|
||||
model: snapshot.model,
|
||||
effort: snapshot.reasoning_effort,
|
||||
summary: snapshot.reasoning_summary,
|
||||
final_output_json_schema: None,
|
||||
collaboration_mode: None,
|
||||
personality: snapshot.personality,
|
||||
},
|
||||
);
|
||||
let captured = harness
|
||||
@@ -398,29 +381,19 @@ mod tests {
|
||||
.spawn_agent(harness.config.clone(), "spawned".to_string(), None)
|
||||
.await
|
||||
.expect("spawn_agent should succeed");
|
||||
let thread = harness
|
||||
let _thread = harness
|
||||
.manager
|
||||
.get_thread(thread_id)
|
||||
.await
|
||||
.expect("thread should be registered");
|
||||
let snapshot = thread.config_snapshot().await;
|
||||
let expected = (
|
||||
thread_id,
|
||||
Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "spawned".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
cwd: snapshot.cwd,
|
||||
approval_policy: snapshot.approval_policy,
|
||||
sandbox_policy: snapshot.sandbox_policy,
|
||||
model: snapshot.model,
|
||||
effort: snapshot.reasoning_effort,
|
||||
summary: snapshot.reasoning_summary,
|
||||
final_output_json_schema: None,
|
||||
collaboration_mode: None,
|
||||
personality: snapshot.personality,
|
||||
},
|
||||
);
|
||||
let captured = harness
|
||||
|
||||
@@ -521,7 +521,6 @@ impl SessionConfiguration {
|
||||
sandbox_policy: self.sandbox_policy.get().clone(),
|
||||
cwd: self.cwd.clone(),
|
||||
reasoning_effort: self.collaboration_mode.reasoning_effort(),
|
||||
reasoning_summary: self.model_reasoning_summary,
|
||||
personality: self.personality,
|
||||
session_source: self.session_source.clone(),
|
||||
}
|
||||
@@ -733,7 +732,7 @@ impl Session {
|
||||
None
|
||||
} else {
|
||||
Some(format!(
|
||||
"Enable it with `--enable {canonical}` or `[features].{canonical}` in config.toml. See https://github.com/openai/codex/blob/main/docs/config.md#feature-flags for details."
|
||||
"Enable it with `--enable {canonical}` or `[features].{canonical}` in config.toml. See https://developers.openai.com/codex/config-advanced/ for details."
|
||||
))
|
||||
};
|
||||
post_session_configured_events.push(Event {
|
||||
@@ -2176,8 +2175,9 @@ async fn submission_loop(sess: Arc<Session>, config: Arc<Config>, rx_sub: Receiv
|
||||
)
|
||||
.await;
|
||||
}
|
||||
Op::UserTurn { .. } => {
|
||||
handlers::user_turn(&sess, sub.id.clone(), sub.op, &mut previous_context).await;
|
||||
Op::UserInput { .. } | Op::UserTurn { .. } => {
|
||||
handlers::user_input_or_turn(&sess, sub.id.clone(), sub.op, &mut previous_context)
|
||||
.await;
|
||||
}
|
||||
Op::ExecApproval { id, decision } => {
|
||||
handlers::exec_approval(&sess, id, decision).await;
|
||||
@@ -2343,83 +2343,59 @@ mod handlers {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn user_turn(
|
||||
pub async fn user_input_or_turn(
|
||||
sess: &Arc<Session>,
|
||||
sub_id: String,
|
||||
op: Op,
|
||||
previous_context: &mut Option<Arc<TurnContext>>,
|
||||
) {
|
||||
let Op::UserTurn {
|
||||
use_thread_defaults,
|
||||
cwd,
|
||||
approval_policy,
|
||||
sandbox_policy,
|
||||
model,
|
||||
effort,
|
||||
summary,
|
||||
final_output_json_schema,
|
||||
items,
|
||||
collaboration_mode,
|
||||
personality,
|
||||
} = op
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
let snapshot = if use_thread_defaults {
|
||||
let state = sess.state.lock().await;
|
||||
Some(state.session_configuration.thread_config_snapshot())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let (cwd, approval_policy, sandbox_policy, model, effort, summary, snapshot_personality) =
|
||||
if let Some(snapshot) = snapshot {
|
||||
let (items, updates) = match op {
|
||||
Op::UserTurn {
|
||||
cwd,
|
||||
approval_policy,
|
||||
sandbox_policy,
|
||||
model,
|
||||
effort,
|
||||
summary,
|
||||
final_output_json_schema,
|
||||
items,
|
||||
collaboration_mode,
|
||||
personality,
|
||||
} => {
|
||||
let collaboration_mode = collaboration_mode.or_else(|| {
|
||||
Some(CollaborationMode {
|
||||
mode: ModeKind::Custom,
|
||||
settings: Settings {
|
||||
model: model.clone(),
|
||||
reasoning_effort: effort,
|
||||
developer_instructions: None,
|
||||
},
|
||||
})
|
||||
});
|
||||
(
|
||||
snapshot.cwd,
|
||||
snapshot.approval_policy,
|
||||
snapshot.sandbox_policy,
|
||||
snapshot.model,
|
||||
snapshot.reasoning_effort,
|
||||
snapshot.reasoning_summary,
|
||||
snapshot.personality,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
cwd,
|
||||
approval_policy,
|
||||
sandbox_policy,
|
||||
model,
|
||||
effort,
|
||||
summary,
|
||||
None,
|
||||
)
|
||||
};
|
||||
let personality = if use_thread_defaults {
|
||||
personality.or(snapshot_personality)
|
||||
} else {
|
||||
personality
|
||||
};
|
||||
let collaboration_mode = if use_thread_defaults {
|
||||
collaboration_mode
|
||||
} else {
|
||||
collaboration_mode.or_else(|| {
|
||||
Some(CollaborationMode {
|
||||
mode: ModeKind::Custom,
|
||||
settings: Settings {
|
||||
model: model.clone(),
|
||||
reasoning_effort: effort,
|
||||
developer_instructions: None,
|
||||
items,
|
||||
SessionSettingsUpdate {
|
||||
cwd: Some(cwd),
|
||||
approval_policy: Some(approval_policy),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
collaboration_mode,
|
||||
reasoning_summary: Some(summary),
|
||||
final_output_json_schema: Some(final_output_json_schema),
|
||||
personality,
|
||||
},
|
||||
})
|
||||
})
|
||||
};
|
||||
let updates = SessionSettingsUpdate {
|
||||
cwd: Some(cwd),
|
||||
approval_policy: Some(approval_policy),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
collaboration_mode,
|
||||
reasoning_summary: Some(summary),
|
||||
final_output_json_schema: Some(final_output_json_schema),
|
||||
personality,
|
||||
)
|
||||
}
|
||||
Op::UserInput {
|
||||
items,
|
||||
final_output_json_schema,
|
||||
} => (
|
||||
items,
|
||||
SessionSettingsUpdate {
|
||||
final_output_json_schema: Some(final_output_json_schema),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let previous_collaboration_mode = sess
|
||||
|
||||
@@ -126,19 +126,9 @@ pub(crate) async fn run_codex_thread_one_shot(
|
||||
.await?;
|
||||
|
||||
// Send the initial input to kick off the one-shot turn.
|
||||
let snapshot = io.thread_config_snapshot().await;
|
||||
io.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
io.submit(Op::UserInput {
|
||||
items: input,
|
||||
cwd: snapshot.cwd,
|
||||
approval_policy: snapshot.approval_policy,
|
||||
sandbox_policy: snapshot.sandbox_policy,
|
||||
model: snapshot.model,
|
||||
effort: snapshot.reasoning_effort,
|
||||
summary: snapshot.reasoning_summary,
|
||||
final_output_json_schema: None,
|
||||
collaboration_mode: None,
|
||||
personality: snapshot.personality,
|
||||
})
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -5,13 +5,10 @@ use crate::protocol::Event;
|
||||
use crate::protocol::Op;
|
||||
use crate::protocol::Submission;
|
||||
use codex_protocol::config_types::Personality;
|
||||
use codex_protocol::config_types::ReasoningSummary;
|
||||
use codex_protocol::openai_models::ReasoningEffort;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
use codex_protocol::protocol::SessionSource;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use serde_json::Value;
|
||||
use std::path::PathBuf;
|
||||
use tokio::sync::watch;
|
||||
|
||||
@@ -23,7 +20,6 @@ pub struct ThreadConfigSnapshot {
|
||||
pub sandbox_policy: SandboxPolicy,
|
||||
pub cwd: PathBuf,
|
||||
pub reasoning_effort: Option<ReasoningEffort>,
|
||||
pub reasoning_summary: ReasoningSummary,
|
||||
pub personality: Option<Personality>,
|
||||
pub session_source: SessionSource,
|
||||
}
|
||||
@@ -71,38 +67,4 @@ impl CodexThread {
|
||||
pub async fn config_snapshot(&self) -> ThreadConfigSnapshot {
|
||||
self.codex.thread_config_snapshot().await
|
||||
}
|
||||
|
||||
/// Build a user turn using the thread's current default settings.
|
||||
pub async fn user_turn_with_defaults(
|
||||
&self,
|
||||
items: Vec<UserInput>,
|
||||
final_output_json_schema: Option<Value>,
|
||||
) -> Op {
|
||||
let snapshot = self.config_snapshot().await;
|
||||
Op::UserTurn {
|
||||
use_thread_defaults: true,
|
||||
items,
|
||||
cwd: snapshot.cwd,
|
||||
approval_policy: snapshot.approval_policy,
|
||||
sandbox_policy: snapshot.sandbox_policy,
|
||||
model: snapshot.model,
|
||||
effort: snapshot.reasoning_effort,
|
||||
summary: snapshot.reasoning_summary,
|
||||
final_output_json_schema,
|
||||
collaboration_mode: None,
|
||||
personality: snapshot.personality,
|
||||
}
|
||||
}
|
||||
|
||||
/// Submit a user turn using the thread's current default settings.
|
||||
pub async fn submit_user_turn_with_defaults(
|
||||
&self,
|
||||
items: Vec<UserInput>,
|
||||
final_output_json_schema: Option<Value>,
|
||||
) -> CodexResult<String> {
|
||||
let op = self
|
||||
.user_turn_with_defaults(items, final_output_json_schema)
|
||||
.await;
|
||||
self.submit(op).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -889,7 +889,7 @@ mod tests {
|
||||
.collect();
|
||||
assert_eq!(ops_for_agent.len(), 2);
|
||||
assert!(matches!(ops_for_agent[0], Op::Interrupt));
|
||||
assert!(matches!(ops_for_agent[1], Op::UserTurn { .. }));
|
||||
assert!(matches!(ops_for_agent[1], Op::UserInput { .. }));
|
||||
|
||||
let _ = thread
|
||||
.thread
|
||||
|
||||
@@ -268,7 +268,6 @@ impl TestCodex {
|
||||
let session_model = self.session_configured.model.clone();
|
||||
self.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: prompt.into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -45,13 +45,13 @@ async fn interrupt_long_running_tool_emits_turn_aborted() {
|
||||
|
||||
// Kick off a turn that triggers the function call.
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "start sleep".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -99,13 +99,13 @@ async fn interrupt_tool_records_history_entries() {
|
||||
let codex = Arc::clone(&fixture.codex);
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "start history recording".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -117,13 +117,13 @@ async fn interrupt_tool_records_history_entries() {
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnAborted(_))).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "follow up".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -197,13 +197,13 @@ async fn interrupt_persists_turn_aborted_marker_in_next_request() {
|
||||
let codex = Arc::clone(&fixture.codex);
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "start interrupt marker".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -215,13 +215,13 @@ async fn interrupt_persists_turn_aborted_marker_in_next_request() {
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnAborted(_))).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "follow up".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -300,7 +300,6 @@ async fn apply_patch_cli_move_without_content_change_has_no_turn_diff(
|
||||
let model = test.session_configured.model.clone();
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "rename without content change".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -890,7 +889,6 @@ async fn apply_patch_shell_command_heredoc_with_cd_emits_turn_diff() -> Result<(
|
||||
let model = test.session_configured.model.clone();
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "apply via shell heredoc with cd".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -971,7 +969,6 @@ async fn apply_patch_shell_command_failure_propagates_error_and_skips_diff() ->
|
||||
let model = test.session_configured.model.clone();
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "apply patch via shell".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1122,7 +1119,6 @@ async fn apply_patch_emits_turn_diff_event_with_unified_diff(
|
||||
let model = test.session_configured.model.clone();
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "emit diff".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1186,7 +1182,6 @@ async fn apply_patch_turn_diff_for_rename_with_content_change(
|
||||
let model = test.session_configured.model.clone();
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "rename with change".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1258,7 +1253,6 @@ async fn apply_patch_aggregates_diff_across_multiple_tool_calls() -> Result<()>
|
||||
let model = test.session_configured.model.clone();
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "aggregate diffs".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1330,7 +1324,6 @@ async fn apply_patch_aggregates_diff_preserves_success_after_failure() -> Result
|
||||
let model = test.session_configured.model.clone();
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "apply patch twice with failure".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -490,7 +490,6 @@ async fn submit_turn(
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: prompt.into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -294,13 +294,13 @@ async fn resume_includes_initial_messages_and_sends_prior_items() {
|
||||
|
||||
// 2) Submit new input; the request body must include the prior items, then initial context, then new user input.
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
@@ -393,13 +393,13 @@ async fn includes_conversation_id_and_model_headers_in_request() {
|
||||
.expect("create new conversation");
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -447,13 +447,13 @@ async fn includes_base_instructions_override_in_request() {
|
||||
.thread;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -504,13 +504,13 @@ async fn chatgpt_auth_sends_correct_request() {
|
||||
.expect("create new conversation");
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -597,13 +597,13 @@ async fn prefers_apikey_when_config_prefers_apikey_even_with_chatgpt_tokens() {
|
||||
.expect("create new conversation");
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -639,13 +639,13 @@ async fn includes_user_instructions_message_in_request() {
|
||||
.thread;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -719,13 +719,13 @@ async fn skills_append_to_instructions() {
|
||||
.thread;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -772,13 +772,13 @@ async fn includes_configured_effort_in_request() -> anyhow::Result<()> {
|
||||
.await?;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -810,13 +810,13 @@ async fn includes_no_effort_in_request() -> anyhow::Result<()> {
|
||||
.await?;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -846,13 +846,13 @@ async fn includes_default_reasoning_effort_in_request_when_defined_by_model_info
|
||||
let TestCodex { codex, .. } = test_codex().with_model("gpt-5.1").build(&server).await?;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -899,7 +899,6 @@ async fn user_turn_collaboration_mode_overrides_model_and_effort() -> anyhow::Re
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -945,13 +944,13 @@ async fn configured_reasoning_summary_is_sent() -> anyhow::Result<()> {
|
||||
.await?;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -985,13 +984,13 @@ async fn reasoning_summary_is_omitted_when_disabled() -> anyhow::Result<()> {
|
||||
.await?;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -1019,13 +1018,13 @@ async fn includes_default_verbosity_in_request() -> anyhow::Result<()> {
|
||||
let TestCodex { codex, .. } = test_codex().with_model("gpt-5.1").build(&server).await?;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -1060,13 +1059,13 @@ async fn configured_verbosity_not_sent_for_models_without_support() -> anyhow::R
|
||||
.await?;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -1100,13 +1099,13 @@ async fn configured_verbosity_is_sent() -> anyhow::Result<()> {
|
||||
.await?;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -1156,13 +1155,13 @@ async fn includes_developer_instructions_message_in_request() {
|
||||
.thread;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -1407,13 +1406,13 @@ async fn token_count_includes_rate_limits_snapshot() {
|
||||
.thread;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -1566,13 +1565,13 @@ async fn usage_limit_error_emits_rate_limit_event() -> anyhow::Result<()> {
|
||||
});
|
||||
|
||||
let submission_id = codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.expect("submission should succeed while emitting usage limit error events");
|
||||
|
||||
@@ -1637,25 +1636,25 @@ async fn context_window_error_sets_total_tokens_to_model_window() -> anyhow::Res
|
||||
.await?;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "seed turn".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "trigger context window".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
let token_event = wait_for_event(&codex, |event| {
|
||||
@@ -1770,13 +1769,13 @@ async fn azure_overrides_assign_properties_used_for_responses_url() {
|
||||
.thread;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -1854,13 +1853,13 @@ async fn env_var_overrides_loaded_auth() {
|
||||
.thread;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -1929,39 +1928,39 @@ async fn history_dedupes_streamed_and_final_messages_across_turns() {
|
||||
|
||||
// Turn 1: user sends U1; wait for completion.
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "U1".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
// Turn 2: user sends U2; wait for completion.
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "U2".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
// Turn 3: user sends U3; wait for completion.
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "U3".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -70,13 +70,13 @@ async fn no_collaboration_instructions_by_default() -> Result<()> {
|
||||
let test = test_codex().build(&server).await?;
|
||||
|
||||
test.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -113,13 +113,13 @@ async fn user_input_includes_collaboration_instructions_after_override() -> Resu
|
||||
.await?;
|
||||
|
||||
test.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -144,7 +144,6 @@ async fn collaboration_instructions_added_on_user_turn() -> Result<()> {
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -196,7 +195,6 @@ async fn override_then_user_turn_uses_updated_collaboration_instructions() -> Re
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -250,7 +248,6 @@ async fn user_turn_overrides_collaboration_instructions_after_override() -> Resu
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -304,13 +301,13 @@ async fn collaboration_mode_update_emits_new_instruction_message() -> Result<()>
|
||||
.await?;
|
||||
|
||||
test.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -328,13 +325,13 @@ async fn collaboration_mode_update_emits_new_instruction_message() -> Result<()>
|
||||
.await?;
|
||||
|
||||
test.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -373,13 +370,13 @@ async fn collaboration_mode_update_noop_does_not_append() -> Result<()> {
|
||||
.await?;
|
||||
|
||||
test.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -397,13 +394,13 @@ async fn collaboration_mode_update_noop_does_not_append() -> Result<()> {
|
||||
.await?;
|
||||
|
||||
test.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -449,26 +446,26 @@ async fn resume_replays_collaboration_instructions() -> Result<()> {
|
||||
|
||||
initial
|
||||
.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&initial.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
let resumed = builder.resume(&server, home, rollout_path).await?;
|
||||
resumed
|
||||
.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "after resume".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&resumed.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -503,13 +500,13 @@ async fn empty_collaboration_instructions_are_ignored() -> Result<()> {
|
||||
.await?;
|
||||
|
||||
test.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
|
||||
@@ -158,13 +158,13 @@ async fn summarize_context_three_requests_and_instructions() {
|
||||
|
||||
// 1) Normal user input – should hit server once.
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello world".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
@@ -180,13 +180,13 @@ async fn summarize_context_three_requests_and_instructions() {
|
||||
|
||||
// 3) Next user input – third hit; history should include only the summary.
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: THIRD_USER_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
@@ -574,13 +574,13 @@ async fn multiple_auto_compact_per_task_runs_after_token_limit_hit() {
|
||||
|
||||
// Start the conversation with the user message
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.expect("submit user input");
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
@@ -1051,39 +1051,39 @@ async fn auto_compact_runs_after_token_limit_hit() {
|
||||
let codex = thread_manager.start_thread(config).await.unwrap().thread;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: FIRST_AUTO_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: SECOND_AUTO_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: POST_AUTO_USER_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -1284,7 +1284,6 @@ async fn auto_compact_runs_after_resume_when_token_usage_is_over_limit() {
|
||||
resumed
|
||||
.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: follow_up_user.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1396,37 +1395,37 @@ async fn auto_compact_persists_rollout_entries() {
|
||||
} = thread_manager.start_thread(config).await.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: FIRST_AUTO_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: SECOND_AUTO_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: POST_AUTO_USER_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
@@ -1513,13 +1512,13 @@ async fn manual_compact_retries_after_context_window_error() {
|
||||
.thread;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "first turn".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
@@ -1647,13 +1646,13 @@ async fn manual_compact_twice_preserves_latest_user_messages() {
|
||||
.thread;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: first_user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
@@ -1662,13 +1661,13 @@ async fn manual_compact_twice_preserves_latest_user_messages() {
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: second_user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
@@ -1677,13 +1676,13 @@ async fn manual_compact_twice_preserves_latest_user_messages() {
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: final_user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
@@ -1858,13 +1857,13 @@ async fn auto_compact_allows_multiple_attempts_when_interleaved_with_other_turn_
|
||||
let mut auto_compact_lifecycle_events = Vec::new();
|
||||
for user in [MULTI_AUTO_MSG, follow_up_user, final_user] {
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: user.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -1972,26 +1971,26 @@ async fn auto_compact_triggers_after_function_call_over_95_percent_usage() {
|
||||
.thread;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: FUNCTION_CALL_LIMIT_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
wait_for_event(&codex, |msg| matches!(msg, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: follow_up_user.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -2104,13 +2103,13 @@ async fn auto_compact_counts_encrypted_reasoning_before_last_user() {
|
||||
.enumerate()
|
||||
{
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: user.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
@@ -2221,13 +2220,13 @@ async fn auto_compact_runs_when_reasoning_header_clears_between_turns() {
|
||||
|
||||
for user in [first_user, second_user, third_user] {
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: user.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -71,13 +71,13 @@ async fn remote_compact_replaces_history_for_followups() -> Result<()> {
|
||||
.await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello remote compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -85,13 +85,13 @@ async fn remote_compact_replaces_history_for_followups() -> Result<()> {
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "after compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -193,13 +193,13 @@ async fn remote_compact_runs_automatically() -> Result<()> {
|
||||
.await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello remote compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
let message = wait_for_event_match(&codex, |ev| match ev {
|
||||
EventMsg::ContextCompacted(_) => Some(true),
|
||||
@@ -274,13 +274,13 @@ async fn remote_compact_persists_replacement_history_in_rollout() -> Result<()>
|
||||
.await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "needs compaction".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
|
||||
@@ -987,13 +987,13 @@ async fn start_test_conversation(
|
||||
|
||||
async fn user_turn(conversation: &Arc<CodexThread>, text: &str) {
|
||||
conversation
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: text.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.expect("submit user turn");
|
||||
wait_for_event(conversation, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -49,7 +49,7 @@ async fn emits_deprecation_notice_for_legacy_feature_flag() -> anyhow::Result<()
|
||||
assert_eq!(
|
||||
details.as_deref(),
|
||||
Some(
|
||||
"Enable it with `--enable unified_exec` or `[features].unified_exec` in config.toml. See https://github.com/openai/codex/blob/main/docs/config.md#feature-flags for details."
|
||||
"Enable it with `--enable unified_exec` or `[features].unified_exec` in config.toml. See https://developers.openai.com/codex/config-advanced/ for details."
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
@@ -70,7 +70,6 @@ async fn execpolicy_blocks_shell_invocation() -> Result<()> {
|
||||
let session_model = test.session_configured.model.clone();
|
||||
test.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "run shell command".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -5,6 +5,7 @@ use codex_core::ThreadManager;
|
||||
use codex_core::built_in_model_providers;
|
||||
use codex_core::parse_turn_item;
|
||||
use codex_core::protocol::EventMsg;
|
||||
use codex_core::protocol::Op;
|
||||
use codex_core::protocol::RolloutItem;
|
||||
use codex_core::protocol::RolloutLine;
|
||||
use codex_protocol::items::TurnItem;
|
||||
@@ -66,13 +67,13 @@ async fn fork_thread_twice_drops_to_first_message() {
|
||||
// Send three user messages; wait for three completed turns.
|
||||
for text in ["first", "second", "third"] {
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: text.to_string(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let _ = wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -111,7 +111,6 @@ async fn copy_paste_local_image_persists_rollout_request_shape() -> anyhow::Resu
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![
|
||||
UserInput::LocalImage {
|
||||
path: abs_path.clone(),
|
||||
@@ -193,7 +192,6 @@ async fn drag_drop_image_persists_rollout_request_shape() -> anyhow::Result<()>
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![
|
||||
UserInput::Image {
|
||||
image_url: image_url.clone(),
|
||||
|
||||
@@ -4,6 +4,7 @@ use anyhow::Ok;
|
||||
use codex_core::protocol::EventMsg;
|
||||
use codex_core::protocol::ItemCompletedEvent;
|
||||
use codex_core::protocol::ItemStartedEvent;
|
||||
use codex_core::protocol::Op;
|
||||
use codex_protocol::items::TurnItem;
|
||||
use codex_protocol::user_input::ByteRange;
|
||||
use codex_protocol::user_input::TextElement;
|
||||
@@ -49,7 +50,10 @@ async fn user_message_item_is_emitted() -> anyhow::Result<()> {
|
||||
};
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(vec![expected_input.clone()], None)
|
||||
.submit(Op::UserInput {
|
||||
items: vec![expected_input.clone()],
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
let started_item = wait_for_event_match(&codex, |ev| match ev {
|
||||
@@ -99,13 +103,13 @@ async fn assistant_message_item_is_emitted() -> anyhow::Result<()> {
|
||||
mount_sse_once(&server, first_response).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "please summarize results".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
let started = wait_for_event_match(&codex, |ev| match ev {
|
||||
@@ -157,13 +161,13 @@ async fn reasoning_item_is_emitted() -> anyhow::Result<()> {
|
||||
mount_sse_once(&server, first_response).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "explain your reasoning".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
let started = wait_for_event_match(&codex, |ev| match ev {
|
||||
@@ -217,13 +221,13 @@ async fn web_search_item_is_emitted() -> anyhow::Result<()> {
|
||||
mount_sse_once(&server, first_response).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "find the weather".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
let started = wait_for_event_match(&codex, |ev| match ev {
|
||||
@@ -271,13 +275,13 @@ async fn agent_message_content_delta_has_item_metadata() -> anyhow::Result<()> {
|
||||
mount_sse_once(&server, stream).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "please stream text".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
let (started_turn_id, started_item) = wait_for_event_match(&codex, |ev| match ev {
|
||||
@@ -338,13 +342,13 @@ async fn reasoning_content_delta_has_item_metadata() -> anyhow::Result<()> {
|
||||
mount_sse_once(&server, stream).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "reason through it".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
let reasoning_item = wait_for_event_match(&codex, |ev| match ev {
|
||||
@@ -397,13 +401,13 @@ async fn reasoning_raw_content_delta_respects_flag() -> anyhow::Result<()> {
|
||||
mount_sse_once(&server, stream).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "show raw reasoning".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
let reasoning_item = wait_for_event_match(&codex, |ev| match ev {
|
||||
|
||||
@@ -74,7 +74,6 @@ async fn codex_returns_json_result(model: String) -> anyhow::Result<()> {
|
||||
// 1) Normal user input – should hit server once.
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello world".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -87,7 +87,6 @@ async fn renews_cache_ttl_on_matching_models_etag() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hi".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -98,7 +98,6 @@ async fn refresh_models_on_models_etag_mismatch_and_avoid_duplicate_models_fetch
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "please run a tool".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -42,13 +42,13 @@ async fn responses_api_emits_api_request_event() {
|
||||
let TestCodex { codex, .. } = test_codex().build(&server).await.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -85,13 +85,13 @@ async fn process_sse_emits_tracing_for_output_item() {
|
||||
let TestCodex { codex, .. } = test_codex().build(&server).await.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -125,13 +125,13 @@ async fn process_sse_emits_failed_event_on_parse_error() {
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -166,13 +166,13 @@ async fn process_sse_records_failed_event_when_stream_closes_without_completed()
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -227,13 +227,13 @@ async fn process_sse_failed_event_records_response_error_message() {
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -286,13 +286,13 @@ async fn process_sse_failed_event_logs_parse_error() {
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -332,13 +332,13 @@ async fn process_sse_failed_event_logs_missing_error() {
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -387,13 +387,13 @@ async fn process_sse_failed_event_logs_response_completed_parse_error() {
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -439,13 +439,13 @@ async fn process_sse_emits_completed_telemetry() {
|
||||
let TestCodex { codex, .. } = test_codex().build(&server).await.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -508,13 +508,13 @@ async fn handle_responses_span_records_response_kind_and_tool_name() {
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -574,13 +574,13 @@ async fn record_responses_sets_span_fields_for_response_events() {
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -655,13 +655,13 @@ async fn handle_response_item_records_tool_result_for_custom_tool_call() {
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -724,13 +724,13 @@ async fn handle_response_item_records_tool_result_for_function_call() {
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -803,13 +803,13 @@ async fn handle_response_item_records_tool_result_for_local_shell_missing_ids()
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -866,13 +866,13 @@ async fn handle_response_item_records_tool_result_for_local_shell_call() {
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -972,13 +972,13 @@ async fn handle_container_exec_autoapprove_from_config_records_tool_decision() {
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -1022,13 +1022,13 @@ async fn handle_container_exec_user_approved_records_tool_decision() {
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "approved".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -1082,13 +1082,13 @@ async fn handle_container_exec_user_approved_for_session_records_tool_decision()
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "persist".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -1142,13 +1142,13 @@ async fn handle_sandbox_error_user_approves_retry_records_tool_decision() {
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "retry".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -1202,13 +1202,13 @@ async fn handle_container_exec_user_denies_records_tool_decision() {
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "deny".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -1262,13 +1262,13 @@ async fn handle_sandbox_error_user_approves_for_session_records_tool_decision()
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "persist".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -1323,13 +1323,13 @@ async fn handle_sandbox_error_user_denies_records_tool_decision() {
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "deny".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use codex_core::protocol::EventMsg;
|
||||
use codex_core::protocol::Op;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use core_test_support::responses;
|
||||
use core_test_support::responses::ev_completed;
|
||||
@@ -96,13 +97,13 @@ async fn injected_user_input_triggers_follow_up_request_with_deltas() {
|
||||
.codex;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "first prompt".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -112,13 +113,13 @@ async fn injected_user_input_triggers_follow_up_request_with_deltas() {
|
||||
.await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "second prompt".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -58,13 +58,13 @@ async fn permissions_message_sent_once_on_start() -> Result<()> {
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
test.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -91,13 +91,13 @@ async fn permissions_message_added_on_override_change() -> Result<()> {
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
test.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -115,13 +115,13 @@ async fn permissions_message_added_on_override_change() -> Result<()> {
|
||||
.await?;
|
||||
|
||||
test.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -154,24 +154,24 @@ async fn permissions_message_not_added_when_no_change() -> Result<()> {
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
test.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
test.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -211,13 +211,13 @@ async fn resume_replays_permissions_messages() -> Result<()> {
|
||||
|
||||
initial
|
||||
.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&initial.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -237,26 +237,26 @@ async fn resume_replays_permissions_messages() -> Result<()> {
|
||||
|
||||
initial
|
||||
.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&initial.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
let resumed = builder.resume(&server, home, rollout_path).await?;
|
||||
resumed
|
||||
.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "after resume".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&resumed.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -293,13 +293,13 @@ async fn resume_and_fork_append_permissions_messages() -> Result<()> {
|
||||
|
||||
initial
|
||||
.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&initial.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -319,13 +319,13 @@ async fn resume_and_fork_append_permissions_messages() -> Result<()> {
|
||||
|
||||
initial
|
||||
.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&initial.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -340,13 +340,13 @@ async fn resume_and_fork_append_permissions_messages() -> Result<()> {
|
||||
let resumed = builder.resume(&server, home, rollout_path.clone()).await?;
|
||||
resumed
|
||||
.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "after resume".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&resumed.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -368,13 +368,13 @@ async fn resume_and_fork_append_permissions_messages() -> Result<()> {
|
||||
.await?;
|
||||
forked
|
||||
.thread
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "after fork".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&forked.thread, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -416,13 +416,13 @@ async fn permissions_message_includes_writable_roots() -> Result<()> {
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
test.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
|
||||
@@ -85,7 +85,6 @@ async fn user_turn_personality_none_does_not_add_update_message() -> anyhow::Res
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -132,7 +131,6 @@ async fn config_personality_some_sets_instructions_template() -> anyhow::Result<
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -189,7 +187,6 @@ async fn user_turn_personality_some_adds_update_message() -> anyhow::Result<()>
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -223,7 +220,6 @@ async fn user_turn_personality_some_adds_update_message() -> anyhow::Result<()>
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -343,7 +339,6 @@ async fn user_turn_personality_remote_model_template_includes_update_message() -
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -377,7 +372,6 @@ async fn user_turn_personality_remote_model_template_includes_update_message() -
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -110,24 +110,24 @@ async fn prompt_tools_are_consistent_across_requests() -> anyhow::Result<()> {
|
||||
.base_instructions;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -186,24 +186,24 @@ async fn codex_mini_latest_tools() -> anyhow::Result<()> {
|
||||
.await?;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
@@ -250,24 +250,24 @@ async fn prefixes_context_and_instructions_once_and_consistently_across_requests
|
||||
.await?;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -328,13 +328,13 @@ async fn overrides_turn_context_but_keeps_cached_prefix_and_key_constant() -> an
|
||||
|
||||
// First turn
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -360,13 +360,13 @@ async fn overrides_turn_context_but_keeps_cached_prefix_and_key_constant() -> an
|
||||
|
||||
// Second turn after overrides
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -436,13 +436,13 @@ async fn override_before_first_turn_emits_environment_context() -> anyhow::Resul
|
||||
.await?;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "first message".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
@@ -556,13 +556,13 @@ async fn per_turn_overrides_keep_cached_prefix_and_key_constant() -> anyhow::Res
|
||||
|
||||
// First turn
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -577,7 +577,6 @@ async fn per_turn_overrides_keep_cached_prefix_and_key_constant() -> anyhow::Res
|
||||
};
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -673,7 +672,6 @@ async fn send_user_turn_with_no_changes_does_not_send_environment_context() -> a
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -693,7 +691,6 @@ async fn send_user_turn_with_no_changes_does_not_send_environment_context() -> a
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -775,7 +772,6 @@ async fn send_user_turn_with_changes_sends_environment_context() -> anyhow::Resu
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -795,7 +791,6 @@ async fn send_user_turn_with_changes_sends_environment_context() -> anyhow::Resu
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use anyhow::Result;
|
||||
use codex_core::protocol::EventMsg;
|
||||
use codex_core::protocol::Op;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use core_test_support::responses::ev_response_created;
|
||||
use core_test_support::responses::mount_sse_once;
|
||||
@@ -39,13 +40,13 @@ async fn quota_exceeded_emits_single_error_event() -> Result<()> {
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
test.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "quota?".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -167,7 +167,6 @@ async fn remote_models_remote_model_uses_unified_exec() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "run call".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -378,7 +377,6 @@ async fn remote_models_apply_remote_base_instructions() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello remote".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use codex_core::CodexAuth;
|
||||
use codex_core::features::Feature;
|
||||
use codex_core::protocol::EventMsg;
|
||||
use codex_core::protocol::Op;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use core_test_support::responses::ev_completed;
|
||||
use core_test_support::responses::ev_response_created;
|
||||
@@ -35,13 +36,13 @@ async fn request_body_is_zstd_compressed_for_codex_backend_when_enabled() -> any
|
||||
let codex = builder.build(&server).await?.codex;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "compress me".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
// Wait until the task completes so the request definitely hit the server.
|
||||
@@ -79,13 +80,13 @@ async fn request_body_is_not_compressed_for_api_key_auth_even_when_enabled() ->
|
||||
let codex = builder.build(&server).await?.codex;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "do not compress".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -123,7 +123,6 @@ async fn request_user_input_round_trip_resolves_pending() -> anyhow::Result<()>
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "please confirm".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -245,7 +244,6 @@ where
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "please confirm".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use anyhow::Result;
|
||||
use codex_core::protocol::EventMsg;
|
||||
use codex_core::protocol::Op;
|
||||
use codex_protocol::user_input::ByteRange;
|
||||
use codex_protocol::user_input::TextElement;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
@@ -44,13 +45,13 @@ async fn resume_includes_initial_messages_from_rollout_events() -> Result<()> {
|
||||
)];
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "Record some messages".into(),
|
||||
text_elements: text_elements.clone(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
wait_for_event(&codex, |event| matches!(event, EventMsg::TurnComplete(_))).await;
|
||||
@@ -103,13 +104,13 @@ async fn resume_includes_initial_messages_from_reasoning_events() -> Result<()>
|
||||
mount_sse_once(&server, initial_sse).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "Record reasoning messages".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
wait_for_event(&codex, |event| matches!(event, EventMsg::TurnComplete(_))).await;
|
||||
@@ -164,13 +165,13 @@ async fn resume_switches_models_preserves_base_instructions() -> Result<()> {
|
||||
let initial_mock = mount_sse_once(&server, initial_sse).await;
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "Record initial instructions".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&codex, |event| matches!(event, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -194,13 +195,13 @@ async fn resume_switches_models_preserves_base_instructions() -> Result<()> {
|
||||
let resumed = resume_builder.resume(&server, home, rollout_path).await?;
|
||||
resumed
|
||||
.codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "Resume with different model".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&resumed.codex, |event| {
|
||||
matches!(event, EventMsg::TurnComplete(_))
|
||||
|
||||
@@ -705,13 +705,13 @@ async fn review_history_surfaces_in_parent_session() {
|
||||
// 2) Continue in the parent session; request input must not include any review items.
|
||||
let followup = "back to parent".to_string();
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: followup.clone(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let _complete = wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
@@ -108,7 +108,6 @@ async fn stdio_server_round_trip() -> anyhow::Result<()> {
|
||||
fixture
|
||||
.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "call the rmcp echo tool".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -250,7 +249,6 @@ async fn stdio_image_responses_round_trip() -> anyhow::Result<()> {
|
||||
fixture
|
||||
.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "call the rmcp image tool".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -450,7 +448,6 @@ async fn stdio_image_completions_round_trip() -> anyhow::Result<()> {
|
||||
fixture
|
||||
.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "call the rmcp image tool".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -598,7 +595,6 @@ async fn stdio_server_propagates_whitelisted_env_vars() -> anyhow::Result<()> {
|
||||
fixture
|
||||
.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "call the rmcp echo tool".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -757,7 +753,6 @@ async fn streamable_http_tool_call_round_trip() -> anyhow::Result<()> {
|
||||
fixture
|
||||
.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "call the rmcp streamable http echo tool".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -948,7 +943,6 @@ async fn streamable_http_with_oauth_round_trip() -> anyhow::Result<()> {
|
||||
fixture
|
||||
.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "call the rmcp streamable http oauth echo tool".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -89,7 +89,6 @@ async fn run_snapshot_command(command: &str) -> Result<SnapshotRun> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "run unified exec with shell snapshot".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -164,7 +163,6 @@ async fn run_shell_command_snapshot(command: &str) -> Result<SnapshotRun> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "run shell_command with shell snapshot".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -300,7 +298,6 @@ async fn shell_command_snapshot_still_intercepts_apply_patch() -> Result<()> {
|
||||
let model = test.session_configured.model.clone();
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "apply patch via shell_command with snapshot".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -61,7 +61,6 @@ async fn user_turn_includes_skill_instructions() -> Result<()> {
|
||||
let session_model = test.session_configured.model.clone();
|
||||
test.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![
|
||||
UserInput::Text {
|
||||
text: "please use $demo".to_string(),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use codex_core::ModelProviderInfo;
|
||||
use codex_core::WireApi;
|
||||
use codex_core::protocol::EventMsg;
|
||||
use codex_core::protocol::Op;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use core_test_support::load_sse_fixture_with_id;
|
||||
use core_test_support::skip_if_no_network;
|
||||
@@ -84,13 +85,13 @@ async fn continue_after_stream_error() {
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "first message".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -103,13 +104,13 @@ async fn continue_after_stream_error() {
|
||||
// mock server SSE stream. If the agent failed to clear the running task on
|
||||
// error above, this submission would be rejected/queued indefinitely.
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "follow up".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
use codex_core::ModelProviderInfo;
|
||||
use codex_core::WireApi;
|
||||
use codex_core::protocol::EventMsg;
|
||||
use codex_core::protocol::Op;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use core_test_support::load_sse_fixture;
|
||||
use core_test_support::load_sse_fixture_with_id;
|
||||
@@ -91,13 +92,13 @@ async fn retries_on_early_close() {
|
||||
.unwrap();
|
||||
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -79,7 +79,6 @@ async fn shell_tool_executes_command_and_streams_output() -> anyhow::Result<()>
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "please run the shell command".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -149,7 +148,6 @@ async fn update_plan_tool_emits_plan_update_event() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "please update the plan".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -229,7 +227,6 @@ async fn update_plan_tool_rejects_malformed_payload() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "please update the plan".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -321,7 +318,6 @@ async fn apply_patch_tool_executes_and_emits_patch_events() -> anyhow::Result<()
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "please apply a patch".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -421,7 +417,6 @@ async fn apply_patch_reports_parse_diagnostics() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "please apply a patch".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -36,7 +36,6 @@ async fn run_turn(test: &TestCodex, prompt: &str) -> anyhow::Result<()> {
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: prompt.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -355,7 +354,6 @@ async fn shell_tools_start_before_response_completed_when_stream_delayed() -> an
|
||||
let session_model = test.session_configured.model.clone();
|
||||
test.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "stream delayed completion".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -538,7 +538,6 @@ async fn mcp_image_output_preserves_image_and_no_text_summary() -> Result<()> {
|
||||
fixture
|
||||
.codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "call the rmcp image tool".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -198,7 +198,6 @@ async fn unified_exec_intercepts_apply_patch_exec_command() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "apply patch via unified exec".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -328,7 +327,6 @@ async fn unified_exec_emits_exec_command_begin_event() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "emit begin event".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -407,7 +405,6 @@ async fn unified_exec_resolves_relative_workdir() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "run relative workdir test".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -489,7 +486,6 @@ async fn unified_exec_respects_workdir_override() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "run workdir test".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -583,7 +579,6 @@ async fn unified_exec_emits_exec_command_end_event() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "emit end event".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -659,7 +654,6 @@ async fn unified_exec_emits_output_delta_for_exec_command() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "emit delta".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -736,7 +730,6 @@ async fn unified_exec_full_lifecycle_with_background_end_event() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "exercise full unified exec lifecycle".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -867,7 +860,6 @@ async fn unified_exec_emits_terminal_interaction_for_write_stdin() -> Result<()>
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "stdin delta".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1005,7 +997,6 @@ async fn unified_exec_terminal_interaction_captures_delayed_output() -> Result<(
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "delayed terminal interaction output".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1166,7 +1157,6 @@ async fn unified_exec_emits_one_begin_and_one_end_event() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "check poll event behavior".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1265,7 +1255,6 @@ async fn exec_command_reports_chunk_and_exit_metadata() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "run metadata test".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1384,7 +1373,6 @@ async fn unified_exec_defaults_to_pipe() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "check default pipe mode".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1475,7 +1463,6 @@ async fn unified_exec_can_enable_tty() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "check tty enabled".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1557,7 +1544,6 @@ async fn unified_exec_respects_early_exit_notifications() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "watch early exit timing".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1689,7 +1675,6 @@ async fn write_stdin_returns_exit_metadata_and_clears_session() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "test write_stdin exit behavior".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1858,7 +1843,6 @@ async fn unified_exec_emits_end_event_when_session_dies_via_stdin() -> Result<()
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "end on exit".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1936,7 +1920,6 @@ async fn unified_exec_closes_long_running_session_at_turn_end() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "close unified exec processes on turn end".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2059,7 +2042,6 @@ async fn unified_exec_reuses_session_via_stdin() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "run unified exec".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2195,7 +2177,6 @@ PY
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "exercise lag handling".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2310,7 +2291,6 @@ async fn unified_exec_timeout_and_followup_poll() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "check timeout".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2407,7 +2387,6 @@ PY
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "summarize large output".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2489,7 +2468,6 @@ async fn unified_exec_runs_under_sandbox() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "summarize large output".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2595,7 +2573,6 @@ async fn unified_exec_python_prompt_under_seatbelt() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "start python under seatbelt".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2691,7 +2668,6 @@ async fn unified_exec_runs_on_all_platforms() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "summarize large output".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2827,7 +2803,6 @@ async fn unified_exec_prunes_exited_sessions_first() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "fill session cache".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
use codex_core::protocol::EventMsg;
|
||||
use codex_core::protocol::Op;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use core_test_support::fs_wait;
|
||||
use core_test_support::responses;
|
||||
@@ -56,13 +57,13 @@ echo -n "${@: -1}" > $(dirname "${0}")/notify.txt"#,
|
||||
|
||||
// 1) Normal user input – should hit server once.
|
||||
codex
|
||||
.submit_user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello world".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
|
||||
@@ -78,7 +78,6 @@ async fn user_turn_with_local_image_attaches_image() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::LocalImage {
|
||||
path: abs_path.clone(),
|
||||
}],
|
||||
@@ -172,7 +171,6 @@ async fn view_image_tool_attaches_local_image() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "please add the screenshot".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -306,7 +304,6 @@ async fn view_image_tool_errors_when_path_is_directory() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "please attach the folder".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -382,7 +379,6 @@ async fn view_image_tool_placeholder_for_non_image_files() -> anyhow::Result<()>
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "please use the view_image tool to read the json file".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -477,7 +473,6 @@ async fn view_image_tool_errors_when_file_missing() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::Text {
|
||||
text: "please attach the missing image".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -562,7 +557,6 @@ async fn replaces_invalid_local_image_after_bad_request() -> anyhow::Result<()>
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items: vec![UserInput::LocalImage {
|
||||
path: abs_path.clone(),
|
||||
}],
|
||||
|
||||
@@ -23,7 +23,7 @@ These are entities exit on the codex backend. The intent of this section is to e
|
||||
3. `Task`
|
||||
- A `Task` is `Codex` executing work in response to user input.
|
||||
- `Session` has at most one `Task` running at a time.
|
||||
- Receiving `Op::UserTurn` starts a `Task`
|
||||
- Receiving `Op::UserTurn` starts a `Task` (`Op::UserInput` is legacy)
|
||||
- Consists of a series of `Turn`s
|
||||
- The `Task` executes to until:
|
||||
- The `Model` completes the task and there is no output to feed into an additional `Turn`
|
||||
@@ -66,6 +66,7 @@ For complete documentation of the `Op` and `EventMsg` variants, refer to [protoc
|
||||
|
||||
- `Op`
|
||||
- `Op::UserTurn` – Any input from the user to kick off a `Turn`
|
||||
- `Op::UserInput` – Legacy form of user input
|
||||
- `Op::Interrupt` – Interrupts a running turn
|
||||
- `Op::ExecApproval` – Approve or deny code execution
|
||||
- `Op::UserInputAnswer` – Provide answers for a `request_user_input` tool call
|
||||
|
||||
@@ -466,7 +466,6 @@ pub async fn run_main(cli: Cli, codex_linux_sandbox_exe: Option<PathBuf>) -> any
|
||||
} => {
|
||||
let task_id = thread
|
||||
.submit(Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items,
|
||||
cwd: default_cwd,
|
||||
approval_policy: default_approval_policy,
|
||||
|
||||
@@ -18,6 +18,7 @@ use codex_core::protocol::ApplyPatchApprovalRequestEvent;
|
||||
use codex_core::protocol::Event;
|
||||
use codex_core::protocol::EventMsg;
|
||||
use codex_core::protocol::ExecApprovalRequestEvent;
|
||||
use codex_core::protocol::Op;
|
||||
use codex_core::protocol::Submission;
|
||||
use codex_core::protocol::TurnCompleteEvent;
|
||||
use codex_protocol::ThreadId;
|
||||
@@ -116,19 +117,16 @@ pub async fn run_codex_tool_session(
|
||||
.lock()
|
||||
.await
|
||||
.insert(id.clone(), thread_id);
|
||||
let op = thread
|
||||
.user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
let submission = Submission {
|
||||
id: sub_id.clone(),
|
||||
op: Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: initial_prompt.clone(),
|
||||
// MCP tool prompts are plain text with no UI element ranges.
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
let submission = Submission {
|
||||
id: sub_id.clone(),
|
||||
op,
|
||||
final_output_json_schema: None,
|
||||
},
|
||||
};
|
||||
|
||||
if let Err(e) = thread.submit_with_id(submission).await {
|
||||
@@ -166,17 +164,17 @@ pub async fn run_codex_tool_session_reply(
|
||||
.lock()
|
||||
.await
|
||||
.insert(request_id.clone(), thread_id);
|
||||
let op = thread
|
||||
.user_turn_with_defaults(
|
||||
vec![UserInput::Text {
|
||||
if let Err(e) = thread
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: prompt,
|
||||
// MCP tool prompts are plain text with no UI element ranges.
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
if let Err(e) = thread.submit(op).await {
|
||||
final_output_json_schema: None,
|
||||
})
|
||||
.await
|
||||
{
|
||||
tracing::error!("Failed to submit user input: {e}");
|
||||
let result = create_call_tool_result_with_thread_id(
|
||||
thread_id,
|
||||
|
||||
@@ -61,10 +61,6 @@ pub const COLLABORATION_MODE_OPEN_TAG: &str = "<collaboration_mode>";
|
||||
pub const COLLABORATION_MODE_CLOSE_TAG: &str = "</collaboration_mode>";
|
||||
pub const USER_MESSAGE_BEGIN: &str = "## My request for Codex:";
|
||||
|
||||
const fn is_false(value: &bool) -> bool {
|
||||
!*value
|
||||
}
|
||||
|
||||
/// Submission Queue Entry - requests from user
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
|
||||
pub struct Submission {
|
||||
@@ -91,13 +87,21 @@ pub enum Op {
|
||||
/// This server sends [`EventMsg::TurnAborted`] in response.
|
||||
Interrupt,
|
||||
|
||||
/// User input with full turn context.
|
||||
UserTurn {
|
||||
/// If true, defaults are computed at handling time from the session.
|
||||
/// When set, collaboration mode is only updated if explicitly provided.
|
||||
#[serde(default, skip_serializing_if = "is_false")]
|
||||
use_thread_defaults: bool,
|
||||
/// Legacy user input.
|
||||
///
|
||||
/// Prefer [`Op::UserTurn`] so the caller provides full turn context
|
||||
/// (cwd/approval/sandbox/model/etc.) for each turn.
|
||||
UserInput {
|
||||
/// User input items, see `InputItem`
|
||||
items: Vec<UserInput>,
|
||||
/// Optional JSON Schema used to constrain the final assistant message for this turn.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
final_output_json_schema: Option<Value>,
|
||||
},
|
||||
|
||||
/// Similar to [`Op::UserInput`], but contains additional context required
|
||||
/// for a turn of a [`crate::codex_thread::CodexThread`].
|
||||
UserTurn {
|
||||
/// User input items, see `InputItem`
|
||||
items: Vec<UserInput>,
|
||||
|
||||
@@ -139,7 +143,7 @@ pub enum Op {
|
||||
/// All fields are optional; when omitted, the existing value is preserved.
|
||||
/// This does not enqueue any input – it only updates defaults used for
|
||||
/// turns that rely on persistent session-level context (for example,
|
||||
/// [`Op::UserTurn`]).
|
||||
/// [`Op::UserInput`]).
|
||||
OverrideTurnContext {
|
||||
/// Updated `cwd` for sandbox/tool calls.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
@@ -2394,7 +2398,35 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user_turn_serialization_includes_final_output_json_schema_when_some() -> Result<()> {
|
||||
fn user_input_serialization_omits_final_output_json_schema_when_none() -> Result<()> {
|
||||
let op = Op::UserInput {
|
||||
items: Vec::new(),
|
||||
final_output_json_schema: None,
|
||||
};
|
||||
|
||||
let json_op = serde_json::to_value(op)?;
|
||||
assert_eq!(json_op, json!({ "type": "user_input", "items": [] }));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user_input_deserializes_without_final_output_json_schema_field() -> Result<()> {
|
||||
let op: Op = serde_json::from_value(json!({ "type": "user_input", "items": [] }))?;
|
||||
|
||||
assert_eq!(
|
||||
op,
|
||||
Op::UserInput {
|
||||
items: Vec::new(),
|
||||
final_output_json_schema: None,
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user_input_serialization_includes_final_output_json_schema_when_some() -> Result<()> {
|
||||
let schema = json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -2403,32 +2435,17 @@ mod tests {
|
||||
"required": ["answer"],
|
||||
"additionalProperties": false
|
||||
});
|
||||
let cwd = PathBuf::from("/tmp");
|
||||
let op = Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
let op = Op::UserInput {
|
||||
items: Vec::new(),
|
||||
cwd: cwd.clone(),
|
||||
approval_policy: AskForApproval::Never,
|
||||
sandbox_policy: SandboxPolicy::ReadOnly,
|
||||
model: "test-model".to_string(),
|
||||
effort: None,
|
||||
summary: ReasoningSummaryConfig::Auto,
|
||||
final_output_json_schema: Some(schema.clone()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
};
|
||||
|
||||
let json_op = serde_json::to_value(op)?;
|
||||
assert_eq!(
|
||||
json_op,
|
||||
json!({
|
||||
"type": "user_turn",
|
||||
"type": "user_input",
|
||||
"items": [],
|
||||
"cwd": cwd,
|
||||
"approval_policy": "never",
|
||||
"sandbox_policy": { "type": "read-only" },
|
||||
"model": "test-model",
|
||||
"summary": "auto",
|
||||
"final_output_json_schema": schema,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -2843,7 +2843,6 @@ impl ChatWidget {
|
||||
.model_personality
|
||||
.filter(|_| self.current_model_supports_personality());
|
||||
let op = Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
items,
|
||||
cwd: self.config.cwd.clone(),
|
||||
approval_policy: self.config.approval_policy.value(),
|
||||
|
||||
@@ -1220,7 +1220,6 @@ async fn submit_user_message_with_mode_sets_coding_collaboration_mode() {
|
||||
|
||||
match next_submit_op(&mut op_rx) {
|
||||
Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
collaboration_mode:
|
||||
Some(CollaborationMode {
|
||||
mode: ModeKind::Code,
|
||||
@@ -2244,7 +2243,6 @@ async fn collab_slash_command_opens_picker_and_updates_mode() {
|
||||
chat.handle_key_event(KeyEvent::from(KeyCode::Enter));
|
||||
match next_submit_op(&mut op_rx) {
|
||||
Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
collaboration_mode:
|
||||
Some(CollaborationMode {
|
||||
mode: ModeKind::Code,
|
||||
@@ -2263,7 +2261,6 @@ async fn collab_slash_command_opens_picker_and_updates_mode() {
|
||||
chat.handle_key_event(KeyEvent::from(KeyCode::Enter));
|
||||
match next_submit_op(&mut op_rx) {
|
||||
Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
collaboration_mode:
|
||||
Some(CollaborationMode {
|
||||
mode: ModeKind::Code,
|
||||
@@ -2401,7 +2398,6 @@ async fn collab_mode_is_not_sent_until_selected() {
|
||||
chat.handle_key_event(KeyEvent::from(KeyCode::Enter));
|
||||
match next_submit_op(&mut op_rx) {
|
||||
Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
collaboration_mode,
|
||||
personality: None,
|
||||
..
|
||||
@@ -2434,7 +2430,6 @@ async fn user_turn_includes_personality_from_config() {
|
||||
chat.handle_key_event(KeyEvent::from(KeyCode::Enter));
|
||||
match next_submit_op(&mut op_rx) {
|
||||
Op::UserTurn {
|
||||
use_thread_defaults: false,
|
||||
personality: Some(Personality::Friendly),
|
||||
..
|
||||
} => {}
|
||||
|
||||
Reference in New Issue
Block a user