Expose conversation history to extension tools (#23963)

## Why

Extension tools that need conversation context should be able to read it
from the live tool invocation instead of reaching into thread
persistence themselves.

## What changed

- Add a `ConversationHistory` snapshot to extension `ToolCall`s and
populate it from the current raw in-memory response history.
- Expose all history items at this boundary so each extension can filter
and bound the subset it needs before consuming or forwarding it.
- Cover the adapter and registry dispatch paths and update existing
extension tests that construct `ToolCall` literals.

## Test plan

- `cargo test -p codex-tools`
- `cargo test -p codex-extension-api`
- `cargo test -p codex-goal-extension`
- `cargo test -p codex-memories-extension`
- `cargo test -p codex-core passes_turn_fields_to_extension_call`
- `cargo test -p codex-core
extension_tool_executors_are_model_visible_and_dispatchable`
This commit is contained in:
sayan-oai authored and GitHub committed 2026-05-22 01:11:47 +00:00
1 parent 0cec508148
commit 7e802b22f1
8 files changed
+70 -2

No files matched your search

+14
View File
@@ -11,6 +11,7 @@ use codex_extension_api::ResponsesApiTool;
use codex_extension_api::ToolCall as ExtensionToolCall;
use codex_extension_api::ToolExecutor;
use codex_protocol::dynamic_tools::DynamicToolSpec;
use codex_protocol::models::ContentItem;
use codex_protocol::models::FunctionCallOutputBody;
use codex_protocol::models::ResponseInputItem;
use codex_protocol::models::ResponseItem;
@@ -81,6 +82,7 @@ impl ToolExecutor<ExtensionToolCall> for ExtensionEchoExecutor {
Ok(Box::new(codex_tools::JsonToolOutput::new(json!({
"arguments": arguments,
"callId": call.call_id,
"conversationHistory": call.conversation_history.items(),
"ok": true,
}))))
}
@@ -327,6 +329,17 @@ fn mcp_tool_info(
async fn extension_tool_executors_are_model_visible_and_dispatchable() -> anyhow::Result<()> {
let (mut session, turn) = make_session_and_context().await;
session.services.extensions = extension_tool_test_registry();
let history_item = ResponseItem::Message {
id: None,
role: "user".to_string(),
content: vec![ContentItem::InputText {
text: "extension history".to_string(),
}],
phase: None,
};
session
.record_into_history(std::slice::from_ref(&history_item), &turn)
.await;
let router = ToolRouter::from_turn_context(
&turn,
@@ -384,6 +397,7 @@ async fn extension_tool_executors_are_model_visible_and_dispatchable() -> anyhow
json!({
"arguments": { "message": "hello" },
"callId": "call-extension",
"conversationHistory": [history_item],
"ok": true,
})
);