mirror of
https://github.com/openai/codex.git
synced 2026-10-20 00:18:49 +00:00
Share additional tool declarations across response item clones (#54945)
## Why Cloning `ResponseItem::AdditionalTools` deep-copies its tool declarations for history and request copies. ## What changed Store `tools` in an `Arc<[serde_json::Value]>` so clones share immutable declarations. Update constructors and existing test fixtures to use the shared representation. GitOrigin-RevId: eb8831774afb45fe8431a796f34ae9d1243e884a
This commit is contained in:
@@ -2880,7 +2880,7 @@ async fn spawn_agent_can_fork_parent_thread_history_with_sanitized_items() {
|
||||
let tool_declarations = ResponseItem::AdditionalTools {
|
||||
id: None,
|
||||
role: "developer".to_string(),
|
||||
tools: vec![serde_json::json!({"type": "function", "name": "parent_tool"})],
|
||||
tools: Arc::from([serde_json::json!({"type": "function", "name": "parent_tool"})]),
|
||||
};
|
||||
let tool_state = serde_json::json!({"top_level_tools": {"function:parent_tool": "hash"}})
|
||||
.as_object()
|
||||
@@ -3286,7 +3286,7 @@ async fn spawn_agent_fork_strips_parent_usage_hints_from_compacted_history(marke
|
||||
let tool_declarations = ResponseItem::AdditionalTools {
|
||||
id: None,
|
||||
role: "developer".to_string(),
|
||||
tools: vec![serde_json::json!({"type": "function", "name": "compacted_tool"})],
|
||||
tools: Arc::from([serde_json::json!({"type": "function", "name": "compacted_tool"})]),
|
||||
};
|
||||
let tools_update = ContextualUserFragment::into(IncrementalToolsHint(
|
||||
codex_prompts::ResolvedIncrementalToolMessages::default().tool_update_hint,
|
||||
@@ -3865,7 +3865,7 @@ async fn spawn_agent_full_fork_legacy_compaction_rebuilds_child_instructions_onc
|
||||
rollout_items.push(rollout_response_item(ResponseItem::AdditionalTools {
|
||||
id: None,
|
||||
role: "developer".to_string(),
|
||||
tools: vec![serde_json::json!({"type": "function", "name": "parent_tool"})],
|
||||
tools: Arc::from([serde_json::json!({"type": "function", "name": "parent_tool"})]),
|
||||
}));
|
||||
rollout_items.push(RolloutItem::TurnContext(
|
||||
turn_context.to_turn_context_item(),
|
||||
|
||||
@@ -986,7 +986,7 @@ impl ModelClient {
|
||||
Uuid::new_v5(&prefix_namespace, &serde_json::to_vec(&tools)?),
|
||||
)),
|
||||
role: "developer".to_string(),
|
||||
tools,
|
||||
tools: Arc::from(tools),
|
||||
});
|
||||
}
|
||||
None
|
||||
|
||||
@@ -213,7 +213,7 @@ impl WorldStateSection for TopLevelToolsState {
|
||||
ResponseItem::AdditionalTools {
|
||||
id: None,
|
||||
role: "developer".to_string(),
|
||||
tools,
|
||||
tools: Arc::from(tools),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ fn item(tools: Vec<Value>) -> ResponseItem {
|
||||
ResponseItem::AdditionalTools {
|
||||
id: None,
|
||||
role: "developer".to_string(),
|
||||
tools,
|
||||
tools: Arc::from(tools),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use pretty_assertions::assert_ne;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde_json::json;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
struct TestSection {
|
||||
@@ -443,9 +444,9 @@ impl WorldStateSection for MixedOutputSection {
|
||||
content: WorldStateUpdateContent::Item(Box::new(ResponseItem::AdditionalTools {
|
||||
id: None,
|
||||
role: "developer".to_string(),
|
||||
tools: vec![
|
||||
tools: Arc::from([
|
||||
json!({"type": "function", "name": "example", "description": self.0.to_string()}),
|
||||
],
|
||||
]),
|
||||
})),
|
||||
},
|
||||
WorldStateUpdate {
|
||||
@@ -457,7 +458,7 @@ impl WorldStateSection for MixedOutputSection {
|
||||
content: WorldStateUpdateContent::Item(Box::new(ResponseItem::AdditionalTools {
|
||||
id: None,
|
||||
role: "developer".to_string(),
|
||||
tools: vec![json!({"type": "function", "name": "context_tool"})],
|
||||
tools: Arc::from([json!({"type": "function", "name": "context_tool"})]),
|
||||
})),
|
||||
},
|
||||
WorldStateUpdate::fragment(TestFragment("after tools".to_string())),
|
||||
@@ -481,13 +482,13 @@ fn mixed_output_preserves_order_and_restores_its_snapshot() {
|
||||
ResponseItem::AdditionalTools {
|
||||
id: None,
|
||||
role: "developer".to_string(),
|
||||
tools: vec![json!({"type": "function", "name": "example", "description": "2"})],
|
||||
tools: Arc::from([json!({"type": "function", "name": "example", "description": "2"})]),
|
||||
},
|
||||
ContextualUserFragment::into(TestFragment("prefix instructions".to_string())),
|
||||
ResponseItem::AdditionalTools {
|
||||
id: None,
|
||||
role: "developer".to_string(),
|
||||
tools: vec![json!({"type": "function", "name": "context_tool"})],
|
||||
tools: Arc::from([json!({"type": "function", "name": "context_tool"})]),
|
||||
},
|
||||
ContextualUserFragment::into(TestFragment("after tools".to_string())),
|
||||
];
|
||||
|
||||
@@ -8,6 +8,7 @@ use codex_protocol::models::InternalChatMessageMetadataPassthrough;
|
||||
use codex_protocol::models::input_text;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::json;
|
||||
use std::sync::Arc;
|
||||
|
||||
struct TestFragment {
|
||||
role: &'static str,
|
||||
@@ -76,7 +77,7 @@ fn additional_tools() -> ResponseItem {
|
||||
ResponseItem::AdditionalTools {
|
||||
id: None,
|
||||
role: "developer".to_string(),
|
||||
tools: vec![json!({"type": "function", "name": "lookup", "parameters": {}})],
|
||||
tools: Arc::from([json!({"type": "function", "name": "lookup", "parameters": {}})]),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -365,7 +365,7 @@ fn assign_missing_response_item_ids_assigns_additional_tools_ids() {
|
||||
let items = Cow::Owned(vec![ResponseItem::AdditionalTools {
|
||||
id: None,
|
||||
role: "developer".to_string(),
|
||||
tools: Vec::new(),
|
||||
tools: Arc::from([]),
|
||||
}]);
|
||||
|
||||
let items = Session::assign_missing_response_item_ids(items);
|
||||
|
||||
@@ -77,7 +77,7 @@ fn additional_tools(name: &str) -> ResponseItem {
|
||||
ResponseItem::AdditionalTools {
|
||||
id: None,
|
||||
role: "developer".to_string(),
|
||||
tools: vec![json!({"type": "function", "name": name})],
|
||||
tools: Arc::from([json!({"type": "function", "name": name})]),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ impl LunaSampler {
|
||||
ResponseItemEnvelope::new(ResponseItem::AdditionalTools {
|
||||
id: None,
|
||||
role: "developer".to_owned(),
|
||||
tools: Vec::new(),
|
||||
tools: Arc::from([]),
|
||||
}),
|
||||
ResponseItemEnvelope::new(ResponseItem::from(request.instructions.clone())),
|
||||
];
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use codex_utils_image::PromptImageMode;
|
||||
use codex_utils_image::data_url_from_bytes;
|
||||
@@ -1055,7 +1056,8 @@ pub enum ResponseItem {
|
||||
id: Option<ResponseItemId>,
|
||||
role: String,
|
||||
#[ts(type = "unknown[]")]
|
||||
tools: Vec<serde_json::Value>,
|
||||
// Share immutable declarations across history and request copies.
|
||||
tools: Arc<[serde_json::Value]>,
|
||||
},
|
||||
Message {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
@@ -2807,7 +2809,7 @@ mod tests {
|
||||
let mut additional_tools = ResponseItem::AdditionalTools {
|
||||
id: None,
|
||||
role: "developer".to_string(),
|
||||
tools: Vec::new(),
|
||||
tools: Arc::from([]),
|
||||
};
|
||||
additional_tools.set_id(Some(ResponseItemId::with_suffix("at", "test")));
|
||||
assert_eq!(
|
||||
|
||||
@@ -638,14 +638,14 @@ async fn recorder_preserves_additional_tools_in_both_history_modes() -> std::io:
|
||||
ResponseItem::AdditionalTools {
|
||||
id: None,
|
||||
role: "developer".to_string(),
|
||||
tools: vec![serde_json::json!({
|
||||
tools: Arc::from([serde_json::json!({
|
||||
"type": "namespace",
|
||||
"name": "functions",
|
||||
"description": "Available tools.",
|
||||
"tools": [{"type": "function", "name": "lookup",
|
||||
"description": "Look up a value.",
|
||||
"parameters": {"type": "object", "properties": {}}}]
|
||||
})],
|
||||
})]),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user