Files
codex/codex-rs/tools/src/request_plugin_install.rs
Matthew Zeng f88701f5c8 [tool_suggest] More prompt polishes. (#20566)
Tool suggest still misfires when model needs tool_search, updating the
prompts to further disambiguate it:

- [x] rename it from `tool_suggest` to `request_plugin_install`
- [x] rephrase "suggestion" to "install" in the tool descriptions.
- [x] disambiguate "the tool" vs "the plugin/connector". 

Tested with the Codex App and verified it still works.
2026-05-02 04:22:12 +00:00

130 lines
3.9 KiB
Rust

use std::collections::BTreeMap;
use codex_app_server_protocol::AppInfo;
use codex_app_server_protocol::McpElicitationObjectType;
use codex_app_server_protocol::McpElicitationSchema;
use codex_app_server_protocol::McpServerElicitationRequest;
use codex_app_server_protocol::McpServerElicitationRequestParams;
use serde::Deserialize;
use serde::Serialize;
use serde_json::json;
use crate::DiscoverableTool;
use crate::DiscoverableToolAction;
use crate::DiscoverableToolType;
pub const REQUEST_PLUGIN_INSTALL_APPROVAL_KIND_VALUE: &str = "tool_suggestion";
pub const REQUEST_PLUGIN_INSTALL_PERSIST_KEY: &str = "persist";
pub const REQUEST_PLUGIN_INSTALL_PERSIST_ALWAYS_VALUE: &str = "always";
#[derive(Debug, Deserialize)]
pub struct RequestPluginInstallArgs {
pub tool_type: DiscoverableToolType,
pub action_type: DiscoverableToolAction,
pub tool_id: String,
pub suggest_reason: String,
}
#[derive(Debug, Serialize, PartialEq, Eq)]
pub struct RequestPluginInstallResult {
pub completed: bool,
pub user_confirmed: bool,
pub tool_type: DiscoverableToolType,
pub action_type: DiscoverableToolAction,
pub tool_id: String,
pub tool_name: String,
pub suggest_reason: String,
}
#[derive(Debug, Serialize, PartialEq, Eq)]
pub struct RequestPluginInstallMeta<'a> {
pub codex_approval_kind: &'static str,
pub persist: &'static str,
pub tool_type: DiscoverableToolType,
pub suggest_type: DiscoverableToolAction,
pub suggest_reason: &'a str,
pub tool_id: &'a str,
pub tool_name: &'a str,
#[serde(skip_serializing_if = "Option::is_none")]
pub install_url: Option<&'a str>,
}
pub fn build_request_plugin_install_elicitation_request(
server_name: &str,
thread_id: String,
turn_id: String,
args: &RequestPluginInstallArgs,
suggest_reason: &str,
tool: &DiscoverableTool,
) -> McpServerElicitationRequestParams {
let tool_name = tool.name().to_string();
let install_url = tool.install_url().map(ToString::to_string);
let message = suggest_reason.to_string();
McpServerElicitationRequestParams {
thread_id,
turn_id: Some(turn_id),
server_name: server_name.to_string(),
request: McpServerElicitationRequest::Form {
meta: Some(json!(build_request_plugin_install_meta(
args.tool_type,
args.action_type,
suggest_reason,
tool.id(),
tool_name.as_str(),
install_url.as_deref(),
))),
message,
requested_schema: McpElicitationSchema {
schema_uri: None,
type_: McpElicitationObjectType::Object,
properties: BTreeMap::new(),
required: None,
},
},
}
}
pub fn all_requested_connectors_picked_up(
expected_connector_ids: &[String],
accessible_connectors: &[AppInfo],
) -> bool {
expected_connector_ids.iter().all(|connector_id| {
verified_connector_install_completed(connector_id, accessible_connectors)
})
}
pub fn verified_connector_install_completed(
tool_id: &str,
accessible_connectors: &[AppInfo],
) -> bool {
accessible_connectors
.iter()
.find(|connector| connector.id == tool_id)
.is_some_and(|connector| connector.is_accessible)
}
fn build_request_plugin_install_meta<'a>(
tool_type: DiscoverableToolType,
action_type: DiscoverableToolAction,
suggest_reason: &'a str,
tool_id: &'a str,
tool_name: &'a str,
install_url: Option<&'a str>,
) -> RequestPluginInstallMeta<'a> {
RequestPluginInstallMeta {
codex_approval_kind: REQUEST_PLUGIN_INSTALL_APPROVAL_KIND_VALUE,
persist: REQUEST_PLUGIN_INSTALL_PERSIST_ALWAYS_VALUE,
tool_type,
suggest_type: action_type,
suggest_reason,
tool_id,
tool_name,
install_url,
}
}
#[cfg(test)]
#[path = "request_plugin_install_tests.rs"]
mod tests;