Skip to content

Commit 17aa394

Browse files
authored
feat: introduce Op:UserTurn (#2329)
This introduces `Op::UserTurn`, which makes it possible to override many of the fields that were set when the `Session` was originally created when creating a new conversation turn. This is one way we could support changing things like `model` or `cwd` in the middle of the conversation, though we may want to consider making each field optional, or alternatively having a separate `Op` that mutates the `TurnContext` associated with a `submission_loop()`. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/2329). * #2345 * __->__ #2329 * #2343 * #2340 * #2338
1 parent 13ed67c commit 17aa394

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

codex-rs/core/src/codex.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ use crate::exec::process_exec_tool_call;
5555
use crate::exec_env::create_env;
5656
use crate::mcp_connection_manager::McpConnectionManager;
5757
use crate::mcp_tool_call::handle_mcp_tool_call;
58+
use crate::model_family::find_family_for_model;
5859
use crate::models::ContentItem;
5960
use crate::models::FunctionCallOutputPayload;
6061
use crate::models::LocalShellAction;
@@ -1001,6 +1002,64 @@ async fn submission_loop(
10011002
sess.set_task(task);
10021003
}
10031004
}
1005+
Op::UserTurn {
1006+
items,
1007+
cwd,
1008+
approval_policy,
1009+
sandbox_policy,
1010+
model,
1011+
effort,
1012+
summary,
1013+
} => {
1014+
// attempt to inject input into current task
1015+
if let Err(items) = sess.inject_input(items) {
1016+
// Derive a fresh TurnContext for this turn using the provided overrides.
1017+
let provider = turn_context.client.get_provider();
1018+
1019+
// Derive a model family for the requested model; fall back to the session's.
1020+
let model_family = find_family_for_model(&model)
1021+
.unwrap_or_else(|| config.model_family.clone());
1022+
1023+
// Create a per‑turn Config clone with the requested model/family.
1024+
let mut per_turn_config = (*config).clone();
1025+
per_turn_config.model = model.clone();
1026+
per_turn_config.model_family = model_family.clone();
1027+
1028+
// Build a new client with per‑turn reasoning settings.
1029+
// Reuse the same provider and session id; auth defaults to env/API key.
1030+
let client = ModelClient::new(
1031+
Arc::new(per_turn_config),
1032+
None,
1033+
provider,
1034+
effort,
1035+
summary,
1036+
sess.session_id,
1037+
);
1038+
1039+
let fresh_turn_context = TurnContext {
1040+
client,
1041+
tools_config: ToolsConfig::new(
1042+
&model_family,
1043+
approval_policy,
1044+
sandbox_policy.clone(),
1045+
config.include_plan_tool,
1046+
config.include_apply_patch_tool,
1047+
),
1048+
user_instructions: turn_context.user_instructions.clone(),
1049+
base_instructions: turn_context.base_instructions.clone(),
1050+
approval_policy,
1051+
sandbox_policy,
1052+
shell_environment_policy: turn_context.shell_environment_policy.clone(),
1053+
cwd,
1054+
disable_response_storage: turn_context.disable_response_storage,
1055+
};
1056+
1057+
// no current task, spawn a new one with the per‑turn context
1058+
let task =
1059+
AgentTask::spawn(sess.clone(), Arc::new(fresh_turn_context), sub.id, items);
1060+
sess.set_task(task);
1061+
}
1062+
}
10041063
Op::ExecApproval { id, decision } => match decision {
10051064
ReviewDecision::Abort => {
10061065
sess.abort();

codex-rs/core/src/protocol.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ use serde_bytes::ByteBuf;
1717
use strum_macros::Display;
1818
use uuid::Uuid;
1919

20+
use crate::config_types::ReasoningEffort as ReasoningEffortConfig;
21+
use crate::config_types::ReasoningSummary as ReasoningSummaryConfig;
2022
use crate::message_history::HistoryEntry;
2123
use crate::parse_command::ParsedCommand;
2224
use crate::plan_tool::UpdatePlanArgs;
@@ -46,6 +48,33 @@ pub enum Op {
4648
items: Vec<InputItem>,
4749
},
4850

51+
/// Similar to [`Op::UserInput`], but contains additional context required
52+
/// for a turn of a [`crate::codex_conversation::CodexConversation`].
53+
UserTurn {
54+
/// User input items, see `InputItem`
55+
items: Vec<InputItem>,
56+
57+
/// `cwd` to use with the [`SandboxPolicy`] and potentially tool calls
58+
/// such as `local_shell`.
59+
cwd: PathBuf,
60+
61+
/// Policy to use for command approval.
62+
approval_policy: AskForApproval,
63+
64+
/// Policy to use for tool calls such as `local_shell`.
65+
sandbox_policy: SandboxPolicy,
66+
67+
/// Must be a valid model slug for the [`crate::client::ModelClient`]
68+
/// associated with this conversation.
69+
model: String,
70+
71+
/// Will only be honored if the model is configured to use reasoning.
72+
effort: ReasoningEffortConfig,
73+
74+
/// Will only be honored if the model is configured to use reasoning.
75+
summary: ReasoningSummaryConfig,
76+
},
77+
4978
/// Approve a command execution
5079
ExecApproval {
5180
/// The id of the submission we are approving

0 commit comments

Comments
 (0)