Force forked agents to inherit parent model settings#16055
Force forked agents to inherit parent model settings#16055friel-openai wants to merge 11 commits into
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9b0bc4b161
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
8bbc644 to
3379d41
Compare
3379d41 to
fc08138
Compare
7d0d474 to
01c2cff
Compare
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
6b62601 to
e351cad
Compare
|
@jif-oai there are a few issues fixed in this PR:
I think your comment is primarily about the first, is that right? |
jif-oai
left a comment
There was a problem hiding this comment.
I agree this would be good to share more cache here but I don't think this PR fits at the right level.
I would suggest 3 different small PRs:
- Fully re-use the parent config in case of a fork + return a warning or error to the agent if it tries to set anything else
- Shared cache key, do a proper wiring that let us "override" the cache key for a given thread. That we fix at the creation of the thread and gets set directly into the API client
- Make the MCP tools listing stable. Either by definition or using a snapshot
| mcp_connection_manager: Arc::new(RwLock::new(McpConnectionManager::new_uninitialized( | ||
| &config.permissions.approval_policy, | ||
| ))), | ||
| mcp_connection_manager: session_configuration |
There was a problem hiding this comment.
We can't do this. MCP manager get replaced/modified if we have sandbox updates, elicitation, ...
In general, we can't share the manager without re-designing it
If I get it correctly, the only reason we do this is because we want a stability over built_tools. First, this shouldn't drift most of the time. Second, we should use a snapshot around it to fix the issue then
| let inherited_exec_policy = self | ||
| .inherited_exec_policy_for_source(&state, Some(&session_source), &config) | ||
| .await; | ||
| let inherited_prompt_cache_key = self |
There was a problem hiding this comment.
This resume path should not opportunistically inherit parent cache/MCP state from a live parent. SubAgentSource::ThreadSpawn does not persist whether this child was originally forked, so the same resumed agent will get parent-shared cache/MCP only when the parent is currently loaded, and isolated state otherwise... we can't have such non-determinism
| inherited_shell_snapshot: None, | ||
| user_shell_override: None, | ||
| inherited_exec_policy: Some(Arc::clone(&parent_session.services.exec_policy)), | ||
| inherited_prompt_cache_key: Some(parent_session.prompt_cache_key()), |
| @@ -770,6 +773,8 @@ impl ThreadManagerState { | |||
| metrics_service_name: Option<String>, | |||
| inherited_shell_snapshot: Option<Arc<ShellSnapshot>>, | |||
There was a problem hiding this comment.
this is a lot of optional inherited things. We should have a small builder pattern for the inherited things
| @@ -225,7 +225,11 @@ fn build_agent_shared_config(turn: &TurnContext) -> Result<Config, FunctionCallE | |||
| let mut config = (*base_config).clone(); | |||
There was a problem hiding this comment.
All of this should be cleared IMO
We should just re-use the full same config... otherwise this will become brittle over time
| config.model = Some(turn.model_info.slug.clone()); | ||
| config.model_provider = turn.provider.clone(); | ||
| config.model_reasoning_effort = turn.reasoning_effort; | ||
| // Forked children must preserve the spawning turn's effective model settings, including a |
There was a problem hiding this comment.
this code path is not only for forked agents
| pub(crate) inherited_shell_snapshot: Option<Arc<ShellSnapshot>>, | ||
| pub(crate) inherited_exec_policy: Option<Arc<ExecPolicyManager>>, | ||
| pub(crate) inherited_prompt_cache_key: Option<ThreadId>, | ||
| pub(crate) inherited_mcp_connection_manager: Option<Arc<RwLock<McpConnectionManager>>>, |
There was a problem hiding this comment.
Up Option of an Arc of RwLock looks like a code smell in Rust... there are better alternatives for hot swap shared references
| } | ||
|
|
||
| #[tokio::test] | ||
| async fn spawn_agent_fork_context_ignores_child_model_overrides() { |
There was a problem hiding this comment.
this test is kind of pointless IMO
A better test would be an integration test that makes sure the full context is the same at the API level
|
|
||
| let mut config = (*turn.config).clone(); | ||
| let mut role_provider = | ||
| built_in_model_providers(/* openai_base_url */ /*openai_base_url*/ None)["openai"].clone(); |
| args.reasoning_effort, | ||
| ) | ||
| .await?; | ||
| if !args.fork_context { |
There was a problem hiding this comment.
we should probably error to the model if it specify fork with a model and reasoning effort. Or at least emit a warning
## Summary When a `spawn_agent` call does a full-history fork, keep the parent's effective agent type and model configuration instead of applying child role/model overrides. This is the minimal config-inheritance slice of #16055. Prompt-cache key inheritance and MCP tool-surface stability are split into follow-up PRs. ## Design - Reject `agent_type`, `model`, and `reasoning_effort` for v1 `fork_context` spawns. - Reject `agent_type`, `model`, and `reasoning_effort` for v2 `fork_turns = "all"` spawns. - Keep v2 partial-history forks (`fork_turns = "N"`) configurable; requested model/reasoning overrides and role config still apply there. - Keep non-forked spawn behavior unchanged. ## Tests - `cargo +1.93.1 test -p codex-core spawn_agent_fork_context --lib` - `cargo +1.93.1 test -p codex-core multi_agent_v2_spawn_fork_turns --lib` - `cargo +1.93.1 test -p codex-core multi_agent_v2_spawn_partial_fork_turns_allows_agent_type_override --lib`
## Summary When a `spawn_agent` call does a full-history fork, keep the parent's effective agent type and model configuration instead of applying child role/model overrides. This is the minimal config-inheritance slice of openai#16055. Prompt-cache key inheritance and MCP tool-surface stability are split into follow-up PRs. ## Design - Reject `agent_type`, `model`, and `reasoning_effort` for v1 `fork_context` spawns. - Reject `agent_type`, `model`, and `reasoning_effort` for v2 `fork_turns = "all"` spawns. - Keep v2 partial-history forks (`fork_turns = "N"`) configurable; requested model/reasoning overrides and role config still apply there. - Keep non-forked spawn behavior unchanged. ## Tests - `cargo +1.93.1 test -p codex-core spawn_agent_fork_context --lib` - `cargo +1.93.1 test -p codex-core multi_agent_v2_spawn_fork_turns --lib` - `cargo +1.93.1 test -p codex-core multi_agent_v2_spawn_partial_fork_turns_allows_agent_type_override --lib`
## Summary When a `spawn_agent` call does a full-history fork, keep the parent's effective agent type and model configuration instead of applying child role/model overrides. This is the minimal config-inheritance slice of openai#16055. Prompt-cache key inheritance and MCP tool-surface stability are split into follow-up PRs. ## Design - Reject `agent_type`, `model`, and `reasoning_effort` for v1 `fork_context` spawns. - Reject `agent_type`, `model`, and `reasoning_effort` for v2 `fork_turns = "all"` spawns. - Keep v2 partial-history forks (`fork_turns = "N"`) configurable; requested model/reasoning overrides and role config still apply there. - Keep non-forked spawn behavior unchanged. ## Tests - `cargo +1.93.1 test -p codex-core spawn_agent_fork_context --lib` - `cargo +1.93.1 test -p codex-core multi_agent_v2_spawn_fork_turns --lib` - `cargo +1.93.1 test -p codex-core multi_agent_v2_spawn_partial_fork_turns_allows_agent_type_override --lib`
Summary
fork_context = true/fork_turns) ignore childmodelandreasoning_effortoverridesTest
cargo +1.93.1 test -p codex-core spawn_agent_fork_context_ignores_child_model_overrides --libcargo +1.93.1 test -p codex-core multi_agent_v2_spawn_fork_turns_ignores_child_model_overrides --libcargo +1.93.1 test -p codex-core spawn_agent_can_fork_parent_thread_history_with_sanitized_items --lib