mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
a397b59887
## Summary - Simplify recommendation-context `request_plugin_install` arguments to `plugin_id` and `suggest_reason`. - Derive plugin type and install action from the matched candidate while preserving Codex-owned elicitation metadata. - Keep the legacy list-backed schema unchanged and accept resumed calls that still use `tool_id`. ## Stack - #28399 - #28400 - #27704 - This PR ## Validation - `just test -p codex-tools -p codex-core request_plugin_install` (25 passed) - `just fix -p codex-tools -p codex-core` - `just fmt` - `git diff --check`
133 lines
4.2 KiB
Rust
133 lines
4.2 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>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub remote_plugin_id: Option<&'a str>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub app_connector_ids: Option<&'a [String]>,
|
|
}
|
|
|
|
pub fn build_request_plugin_install_elicitation_request(
|
|
server_name: &str,
|
|
thread_id: String,
|
|
turn_id: String,
|
|
suggest_reason: &str,
|
|
tool: &DiscoverableTool,
|
|
) -> McpServerElicitationRequestParams {
|
|
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(
|
|
suggest_reason,
|
|
tool,
|
|
))),
|
|
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>(
|
|
suggest_reason: &'a str,
|
|
tool: &'a DiscoverableTool,
|
|
) -> RequestPluginInstallMeta<'a> {
|
|
let (tool_type, remote_plugin_id, app_connector_ids) = match tool {
|
|
DiscoverableTool::Connector(_) => (DiscoverableToolType::Connector, None, None),
|
|
DiscoverableTool::Plugin(plugin) => (
|
|
DiscoverableToolType::Plugin,
|
|
plugin.remote_plugin_id.as_deref(),
|
|
Some(plugin.app_connector_ids.as_slice()),
|
|
),
|
|
};
|
|
RequestPluginInstallMeta {
|
|
codex_approval_kind: REQUEST_PLUGIN_INSTALL_APPROVAL_KIND_VALUE,
|
|
persist: REQUEST_PLUGIN_INSTALL_PERSIST_ALWAYS_VALUE,
|
|
tool_type,
|
|
suggest_type: DiscoverableToolAction::Install,
|
|
suggest_reason,
|
|
tool_id: tool.id(),
|
|
tool_name: tool.name(),
|
|
install_url: tool.install_url(),
|
|
remote_plugin_id,
|
|
app_connector_ids,
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "request_plugin_install_tests.rs"]
|
|
mod tests;
|