mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Represent dynamic tools with explicit namespaces internally (#27365)
Follow-up to #27356. ## Stack note This PR changes Codex's internal dynamic-tool shape while leaving `thread/start` unchanged. App-server therefore converts the existing per-tool input into explicit functions and namespaces before passing it to core. [#27371](https://github.com/openai/codex/pull/27371) updates `thread/start` to use the same explicit shape and removes this temporary conversion. ## Why Dynamic tools repeat namespace metadata on every function. Core should keep one explicit namespace with its member tools so descriptions and membership stay consistent across sessions and runtime planning. ## What changed - Represent dynamic tools as top-level functions or explicit namespaces in protocol and session state. - Read old flat rollout metadata and write the canonical hierarchy. - Flatten namespace members only when registering callable tools. - Keep `thread/start.dynamicTools` flat for now and normalize it at the app-server boundary. New builds can read old rollout metadata. Older builds cannot read newly written hierarchical metadata. ## Test plan - `just test -p codex-app-server thread_start_normalizes_legacy_dynamic_tools_into_model_request` - `just test -p codex-protocol session_meta_normalizes_legacy_dynamic_tools` - `just test -p codex-core resume_restores_dynamic_tools_from_rollout_with_sqlite_enabled` - `just test -p codex-core tool_search_returns_deferred_dynamic_tool_and_routes_follow_up_call` - `just test -p codex-core code_mode_can_call_hidden_dynamic_tools` - `just test -p codex-tools`
This commit is contained in:
committed by
GitHub
Unverified
parent
b3f6f70b68
commit
a292faae5a
@@ -2872,7 +2872,11 @@ 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")]
|
||||
#[serde(
|
||||
default,
|
||||
deserialize_with = "crate::dynamic_tools::deserialize_dynamic_tool_specs",
|
||||
skip_serializing_if = "Option::is_none"
|
||||
)]
|
||||
pub dynamic_tools: Option<Vec<DynamicToolSpec>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub memory_mode: Option<String>,
|
||||
@@ -4122,6 +4126,59 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn session_meta_normalizes_legacy_dynamic_tools() -> Result<()> {
|
||||
let mut value = serde_json::to_value(SessionMeta::default())?;
|
||||
value["dynamic_tools"] = json!([
|
||||
{
|
||||
"namespace": "legacy_app",
|
||||
"name": "lookup_ticket",
|
||||
"description": "Look up a ticket",
|
||||
"inputSchema": {"type": "object", "properties": {}},
|
||||
"exposeToContext": false
|
||||
},
|
||||
{
|
||||
"namespace": "legacy_app",
|
||||
"name": "update_ticket",
|
||||
"description": "Update a ticket",
|
||||
"inputSchema": {"type": "object", "properties": {}},
|
||||
"deferLoading": false,
|
||||
"exposeToContext": false
|
||||
}
|
||||
]);
|
||||
|
||||
let meta: SessionMeta = serde_json::from_value(value)?;
|
||||
|
||||
assert_eq!(
|
||||
meta.dynamic_tools,
|
||||
Some(vec![DynamicToolSpec::Namespace(
|
||||
crate::dynamic_tools::DynamicToolNamespaceSpec {
|
||||
name: "legacy_app".to_string(),
|
||||
description: String::new(),
|
||||
tools: vec![
|
||||
crate::dynamic_tools::DynamicToolNamespaceTool::Function(
|
||||
crate::dynamic_tools::DynamicToolFunctionSpec {
|
||||
name: "lookup_ticket".to_string(),
|
||||
description: "Look up a ticket".to_string(),
|
||||
input_schema: json!({"type": "object", "properties": {}}),
|
||||
defer_loading: true,
|
||||
},
|
||||
),
|
||||
crate::dynamic_tools::DynamicToolNamespaceTool::Function(
|
||||
crate::dynamic_tools::DynamicToolFunctionSpec {
|
||||
name: "update_ticket".to_string(),
|
||||
description: "Update a ticket".to_string(),
|
||||
input_schema: json!({"type": "object", "properties": {}}),
|
||||
defer_loading: false,
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
)])
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sorted_writable_roots(roots: Vec<WritableRoot>) -> Vec<(PathBuf, Vec<PathBuf>)> {
|
||||
let mut sorted_roots: Vec<(PathBuf, Vec<PathBuf>)> = roots
|
||||
.into_iter()
|
||||
|
||||
Reference in New Issue
Block a user