mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
standalone websearch extension (#23823)
## Summary Add the extension-backed standalone `web.run` tool so Codex can call the standalone search endpoint through the `codex-api` search client and return its encrypted output to Responses. - gate the new tool behind `standalone_web_search` - install the extension in the app-server thread registry and hide hosted `web_search` when standalone search is enabled for OpenAI providers so the two paths stay mutually exclusive - build search context from persisted history using a small tail heuristic: previous user message, assistant text between the last two user turns capped at about 1k tokens, and current user message ## Test Plan - `cargo test -p codex-web-search-extension` - `cargo test -p codex-api` - `cargo test -p codex-core hosted_tools_follow_provider_auth_model_and_config_gates`
This commit is contained in:
committed by
GitHub
Unverified
parent
aad59a0916
commit
a22706dfae
@@ -8,6 +8,7 @@ mod image_detail;
|
||||
mod json_schema;
|
||||
mod mcp_tool;
|
||||
mod request_plugin_install;
|
||||
mod response_history;
|
||||
mod responses_api;
|
||||
mod tool_call;
|
||||
mod tool_config;
|
||||
@@ -45,6 +46,8 @@ pub use request_plugin_install::RequestPluginInstallResult;
|
||||
pub use request_plugin_install::all_requested_connectors_picked_up;
|
||||
pub use request_plugin_install::build_request_plugin_install_elicitation_request;
|
||||
pub use request_plugin_install::verified_connector_install_completed;
|
||||
pub use response_history::retain_tail_from_last_n_user_messages;
|
||||
pub use response_history::truncate_assistant_output_text_to_token_budget;
|
||||
pub use responses_api::FreeformTool;
|
||||
pub use responses_api::FreeformToolFormat;
|
||||
pub use responses_api::LoadableToolSpec;
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
use codex_protocol::models::ContentItem;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_utils_output_truncation::TruncationPolicy;
|
||||
use codex_utils_output_truncation::approx_token_count;
|
||||
use codex_utils_output_truncation::truncate_text;
|
||||
|
||||
/// Retains items from the earliest of the last `user_message_count` user
|
||||
/// messages through the latest user message.
|
||||
pub fn retain_tail_from_last_n_user_messages(
|
||||
items: &mut Vec<ResponseItem>,
|
||||
user_message_count: usize,
|
||||
) {
|
||||
if user_message_count == 0 {
|
||||
items.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(latest_user_idx) = items.iter().rposition(ResponseItem::is_user_message) else {
|
||||
items.clear();
|
||||
return;
|
||||
};
|
||||
items.truncate(latest_user_idx + 1);
|
||||
|
||||
let earliest_retained_user_idx = items
|
||||
.iter()
|
||||
.enumerate()
|
||||
.rev()
|
||||
.filter(|(_, item)| item.is_user_message())
|
||||
.take(user_message_count)
|
||||
.last()
|
||||
.map(|(idx, _)| idx)
|
||||
.unwrap_or(latest_user_idx);
|
||||
items.drain(..earliest_retained_user_idx);
|
||||
}
|
||||
|
||||
/// Truncates assistant output text to a shared token budget across items.
|
||||
pub fn truncate_assistant_output_text_to_token_budget(
|
||||
items: &mut Vec<ResponseItem>,
|
||||
max_tokens: usize,
|
||||
) {
|
||||
let mut remaining_budget = max_tokens;
|
||||
|
||||
items.retain_mut(|item| {
|
||||
let ResponseItem::Message { role, content, .. } = item else {
|
||||
return true;
|
||||
};
|
||||
if role != "assistant" {
|
||||
return true;
|
||||
}
|
||||
|
||||
content.retain_mut(|content_item| {
|
||||
let ContentItem::OutputText { text } = content_item else {
|
||||
return true;
|
||||
};
|
||||
if remaining_budget == 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let token_count = approx_token_count(text);
|
||||
if token_count <= remaining_budget {
|
||||
remaining_budget = remaining_budget.saturating_sub(token_count);
|
||||
return true;
|
||||
}
|
||||
|
||||
*text = truncate_text(text, TruncationPolicy::Tokens(remaining_budget));
|
||||
remaining_budget = 0;
|
||||
true
|
||||
});
|
||||
!content.is_empty()
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use codex_protocol::models::ContentItem;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_utils_output_truncation::TruncationPolicy;
|
||||
use codex_utils_output_truncation::truncate_text;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::retain_tail_from_last_n_user_messages;
|
||||
use super::truncate_assistant_output_text_to_token_budget;
|
||||
|
||||
fn message(role: &str, text: &str) -> ResponseItem {
|
||||
ResponseItem::Message {
|
||||
id: None,
|
||||
role: role.to_string(),
|
||||
content: vec![if role == "assistant" {
|
||||
ContentItem::OutputText {
|
||||
text: text.to_string(),
|
||||
}
|
||||
} else {
|
||||
ContentItem::InputText {
|
||||
text: text.to_string(),
|
||||
}
|
||||
}],
|
||||
phase: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn retains_tail_through_latest_user_message() {
|
||||
let mut items = vec![
|
||||
message("system", "system"),
|
||||
message("user", "old user"),
|
||||
message("assistant", "old assistant"),
|
||||
message("user", "previous user"),
|
||||
message("assistant", "previous assistant"),
|
||||
message("user", "current user"),
|
||||
message("assistant", "later assistant"),
|
||||
];
|
||||
|
||||
retain_tail_from_last_n_user_messages(&mut items, /*user_message_count*/ 2);
|
||||
|
||||
assert_eq!(
|
||||
items,
|
||||
vec![
|
||||
message("user", "previous user"),
|
||||
message("assistant", "previous assistant"),
|
||||
message("user", "current user"),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn truncates_assistant_output_text_across_items() {
|
||||
let long_assistant = "a".repeat(16);
|
||||
let mut items = vec![
|
||||
message("user", "previous user"),
|
||||
message("assistant", &long_assistant),
|
||||
message("assistant", "after budget"),
|
||||
message("user", "current user"),
|
||||
];
|
||||
|
||||
truncate_assistant_output_text_to_token_budget(&mut items, /*max_tokens*/ 2);
|
||||
|
||||
assert_eq!(
|
||||
items,
|
||||
vec![
|
||||
message("user", "previous user"),
|
||||
message(
|
||||
"assistant",
|
||||
&truncate_text(&long_assistant, TruncationPolicy::Tokens(2)),
|
||||
),
|
||||
message("user", "current user"),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user