mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] [3/4] Activate endpoint plugin recommendations (#27704)
Summary\n- Await endpoint recommendation selection while constructing each authenticated turn, removing the first-turn cache race.\n- Snapshot and filter endpoint candidates once per turn, then use that same set for the bounded contextual user fragment, tool exposure, and exact install validation.\n- Keep recommendation selection ephemeral: do not persist recommendation state in or gate resumed threads on prior context.\n- Hide the legacy list tool in endpoint mode and preserve legacy discovery unchanged when the endpoint is disabled or unavailable.\n- Keep remote plugin and connector app identities out of model-visible context and attach them only to Codex-owned elicitation metadata.\n\nStack\n- 3/4, based on #28400.\n- Endpoint client and cache: #28399.\n- Generalized suggestion presentation: #28400.\n- Install-schema follow-up: #28403.\n\nValidation\n- \n- \n- \n- \n- Full : 2,649 passed and 88 environment-dependent tests failed because this sandbox cannot write , nest Seatbelt, or locate auxiliary test binaries.
This commit is contained in:
@@ -130,8 +130,8 @@ impl RequestPluginInstallHandler {
|
||||
ToolSuggestPresentation::ListTool => format!(
|
||||
"the discoverable tools returned by {LIST_AVAILABLE_PLUGINS_TO_INSTALL_TOOL_NAME}"
|
||||
),
|
||||
ToolSuggestPresentation::DeveloperContext => {
|
||||
"the developer recommendations".to_string()
|
||||
ToolSuggestPresentation::RecommendationContext => {
|
||||
"the <recommended_plugins> list".to_string()
|
||||
}
|
||||
};
|
||||
FunctionCallError::RespondToModel(format!(
|
||||
|
||||
@@ -39,8 +39,8 @@ pub(crate) fn create_request_plugin_install_tool(
|
||||
ToolSuggestPresentation::ListTool => format!(
|
||||
"# Request plugin/connector install\n\nUse this tool only after `{LIST_AVAILABLE_PLUGINS_TO_INSTALL_TOOL_NAME}` returns a plugin or connector that exactly matches the user's explicit request.\n\nDo not use it for adjacent capabilities, broad recommendations, or tools that merely seem useful. Pass the returned `tool_type` through directly, and pass the returned `id` as `tool_id`.\n\nIMPORTANT: DO NOT call this tool in parallel with other tools."
|
||||
),
|
||||
ToolSuggestPresentation::DeveloperContext =>
|
||||
"# Suggest a recommended plugin installation\n\nSuggest installing a plugin from the developer `<recommended_plugins>` list when it would help with the user's current request. Briefly explain why in `suggest_reason`.".to_string(),
|
||||
ToolSuggestPresentation::RecommendationContext =>
|
||||
"# Suggest a recommended plugin installation\n\nSuggest installing a plugin from the `<recommended_plugins>` list when it would help with the user's current request. Briefly explain why in `suggest_reason`.".to_string(),
|
||||
};
|
||||
|
||||
ToolSpec::Function(ResponsesApiTool {
|
||||
@@ -126,15 +126,15 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn developer_recommendations_change_only_the_description() {
|
||||
fn recommendation_context_changes_only_the_description() {
|
||||
let mut expected = create_request_plugin_install_tool(ToolSuggestPresentation::ListTool);
|
||||
let recommendations =
|
||||
create_request_plugin_install_tool(ToolSuggestPresentation::DeveloperContext);
|
||||
create_request_plugin_install_tool(ToolSuggestPresentation::RecommendationContext);
|
||||
|
||||
let ToolSpec::Function(expected_function) = &mut expected else {
|
||||
panic!("expected function tool specs");
|
||||
};
|
||||
expected_function.description = "# Suggest a recommended plugin installation\n\nSuggest installing a plugin from the developer `<recommended_plugins>` list when it would help with the user's current request. Briefly explain why in `suggest_reason`.".to_string();
|
||||
expected_function.description = "# Suggest a recommended plugin installation\n\nSuggest installing a plugin from the `<recommended_plugins>` list when it would help with the user's current request. Briefly explain why in `suggest_reason`.".to_string();
|
||||
|
||||
assert_eq!(recommendations, expected);
|
||||
}
|
||||
|
||||
@@ -48,8 +48,7 @@ pub(crate) struct ToolRouterParams<'a> {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub(crate) enum ToolSuggestPresentation {
|
||||
ListTool,
|
||||
#[allow(dead_code)]
|
||||
DeveloperContext,
|
||||
RecommendationContext,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
||||
@@ -883,7 +883,7 @@ async fn request_plugin_install_requires_all_discovery_features() {
|
||||
None,
|
||||
Some(ToolSuggestCandidates {
|
||||
tools: Vec::new(),
|
||||
presentation: ToolSuggestPresentation::DeveloperContext,
|
||||
presentation: ToolSuggestPresentation::RecommendationContext,
|
||||
}),
|
||||
] {
|
||||
let plan = probe_with(
|
||||
@@ -959,7 +959,7 @@ async fn request_plugin_install_description_refers_to_recommended_plugins_hint()
|
||||
},
|
||||
ToolPlanInputs {
|
||||
tool_suggest_candidates: Some(plugin_candidates(
|
||||
ToolSuggestPresentation::DeveloperContext,
|
||||
ToolSuggestPresentation::RecommendationContext,
|
||||
)),
|
||||
..ToolPlanInputs::default()
|
||||
},
|
||||
@@ -973,7 +973,7 @@ async fn request_plugin_install_description_refers_to_recommended_plugins_hint()
|
||||
else {
|
||||
panic!("expected request_plugin_install function spec");
|
||||
};
|
||||
assert!(request_description.contains("developer `<recommended_plugins>` list"));
|
||||
assert!(request_description.contains("the `<recommended_plugins>` list"));
|
||||
assert!(!request_description.contains("list_available_plugins_to_install"));
|
||||
assert!(!request_description.contains("github"));
|
||||
plan.assert_visible_lacks(&["list_available_plugins_to_install"]);
|
||||
|
||||
Reference in New Issue
Block a user