mirror of
https://github.com/openai/codex.git
synced 2026-02-01 22:47:52 +00:00
[feat] persist dynamic tools in session rollout file (#10130)
Add dynamic tools to rollout file for persistence & read from rollout on
resume. Ran a real example and spotted the following in the rollout
file:
```
{"timestamp":"2026-01-29T01:27:57.468Z","type":"session_meta","payload":{"id":"019c075d-3f0b-77e3-894e-c1c159b04b1e","timestamp":"2026-01-29T01:27:57.451Z","...."dynamic_tools":[{"name":"demo_tool","description":"Demo dynamic tool","inputSchema":{"additionalProperties":false,"properties":{"city":{"type":"string"}},"required":["city"],"type":"object"}}],"git":{"commit_hash":"ebc573f15c01b8af158e060cfedd401f043e9dfa","branch":"dev/cc/dynamic-tools","repository_url":"https://github.com/openai/codex.git"}}}
```
This commit is contained in:
@@ -81,6 +81,7 @@ pub fn create_fake_rollout_with_source(
|
||||
source,
|
||||
model_provider: model_provider.map(str::to_string),
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
};
|
||||
let payload = serde_json::to_value(SessionMetaLine {
|
||||
meta,
|
||||
@@ -159,6 +160,7 @@ pub fn create_fake_rollout_with_text_elements(
|
||||
source: SessionSource::Cli,
|
||||
model_provider: model_provider.map(str::to_string),
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
};
|
||||
let payload = serde_json::to_value(SessionMetaLine {
|
||||
meta,
|
||||
|
||||
@@ -324,6 +324,12 @@ impl Codex {
|
||||
.clone()
|
||||
.or_else(|| conversation_history.get_base_instructions().map(|s| s.text))
|
||||
.unwrap_or_else(|| model_info.get_model_instructions(config.model_personality));
|
||||
// Respect explicit thread-start tools; fall back to persisted tools when resuming a thread.
|
||||
let dynamic_tools = if dynamic_tools.is_empty() {
|
||||
conversation_history.get_dynamic_tools().unwrap_or_default()
|
||||
} else {
|
||||
dynamic_tools
|
||||
};
|
||||
|
||||
// TODO (aibrahim): Consolidate config.model and config.model_reasoning_effort into config.collaboration_mode
|
||||
// to avoid extracting these fields separately and constructing CollaborationMode here.
|
||||
@@ -715,6 +721,7 @@ impl Session {
|
||||
BaseInstructions {
|
||||
text: session_configuration.base_instructions.clone(),
|
||||
},
|
||||
session_configuration.dynamic_tools.clone(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -303,6 +303,7 @@ mod tests {
|
||||
source: SessionSource::default(),
|
||||
model_provider: Some("openai".to_string()),
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
};
|
||||
let session_meta_line = SessionMetaLine {
|
||||
meta: session_meta,
|
||||
|
||||
@@ -7,6 +7,7 @@ use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::dynamic_tools::DynamicToolSpec;
|
||||
use codex_protocol::models::BaseInstructions;
|
||||
use serde_json::Value;
|
||||
use time::OffsetDateTime;
|
||||
@@ -68,6 +69,7 @@ pub enum RolloutRecorderParams {
|
||||
forked_from_id: Option<ThreadId>,
|
||||
source: SessionSource,
|
||||
base_instructions: BaseInstructions,
|
||||
dynamic_tools: Vec<DynamicToolSpec>,
|
||||
},
|
||||
Resume {
|
||||
path: PathBuf,
|
||||
@@ -91,12 +93,14 @@ impl RolloutRecorderParams {
|
||||
forked_from_id: Option<ThreadId>,
|
||||
source: SessionSource,
|
||||
base_instructions: BaseInstructions,
|
||||
dynamic_tools: Vec<DynamicToolSpec>,
|
||||
) -> Self {
|
||||
Self::Create {
|
||||
conversation_id,
|
||||
forked_from_id,
|
||||
source,
|
||||
base_instructions,
|
||||
dynamic_tools,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,6 +263,7 @@ impl RolloutRecorder {
|
||||
forked_from_id,
|
||||
source,
|
||||
base_instructions,
|
||||
dynamic_tools,
|
||||
} => {
|
||||
let LogFileInfo {
|
||||
file,
|
||||
@@ -288,6 +293,11 @@ impl RolloutRecorder {
|
||||
source,
|
||||
model_provider: Some(config.model_provider_id.clone()),
|
||||
base_instructions: Some(base_instructions),
|
||||
dynamic_tools: if dynamic_tools.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(dynamic_tools)
|
||||
},
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -873,6 +873,7 @@ async fn test_updated_at_uses_file_mtime() -> Result<()> {
|
||||
source: SessionSource::VSCode,
|
||||
model_provider: Some("test-provider".into()),
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
},
|
||||
git: None,
|
||||
}),
|
||||
|
||||
@@ -93,6 +93,7 @@ async fn backfill_scans_existing_rollouts() -> Result<()> {
|
||||
source: SessionSource::default(),
|
||||
model_provider: None,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
},
|
||||
git: None,
|
||||
};
|
||||
|
||||
@@ -20,6 +20,7 @@ use crate::config_types::WindowsSandboxLevel;
|
||||
use crate::custom_prompts::CustomPrompt;
|
||||
use crate::dynamic_tools::DynamicToolCallRequest;
|
||||
use crate::dynamic_tools::DynamicToolResponse;
|
||||
use crate::dynamic_tools::DynamicToolSpec;
|
||||
use crate::items::TurnItem;
|
||||
use crate::message_history::HistoryEntry;
|
||||
use crate::models::BaseInstructions;
|
||||
@@ -1513,6 +1514,22 @@ impl InitialHistory {
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_dynamic_tools(&self) -> Option<Vec<DynamicToolSpec>> {
|
||||
match self {
|
||||
InitialHistory::New => None,
|
||||
InitialHistory::Resumed(resumed) => {
|
||||
resumed.history.iter().find_map(|item| match item {
|
||||
RolloutItem::SessionMeta(meta_line) => meta_line.meta.dynamic_tools.clone(),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
InitialHistory::Forked(items) => items.iter().find_map(|item| match item {
|
||||
RolloutItem::SessionMeta(meta_line) => meta_line.meta.dynamic_tools.clone(),
|
||||
_ => None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn session_cwd_from_items(items: &[RolloutItem]) -> Option<PathBuf> {
|
||||
@@ -1599,6 +1616,8 @@ pub struct SessionMeta {
|
||||
/// but may be missing for older sessions. If not present, fall back to rendering the base_instructions
|
||||
/// from ModelsManager.
|
||||
pub base_instructions: Option<BaseInstructions>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_tools: Option<Vec<DynamicToolSpec>>,
|
||||
}
|
||||
|
||||
impl Default for SessionMeta {
|
||||
@@ -1613,6 +1632,7 @@ impl Default for SessionMeta {
|
||||
source: SessionSource::default(),
|
||||
model_provider: None,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user