mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
skills: make backend plugin skills invocable without an executor (#27387)
## Why #27198 made the extension-owned `codex_apps` MCP connection the hosted plugin runtime, but its `mcp/skill` resources still bypassed the skills extension. App-server could list and read those resources through generic MCP APIs, but a thread with no selected environment did not expose them in the model's skills catalog or load their `SKILL.md` through `$skill`. Hosted skills should stay remote while using the same typed catalog, source authority, deduplication, bounded contextual catalog, and selected-skill prompt injection as host and executor skills. They should not be downloaded or exposed as ambient filesystem paths. ## What changed - Add a session-scoped `McpResourceClient` over the replaceable MCP connection manager so resource list/read calls follow startup and refresh replacements. - Add a `BackendSkillProvider` that pages `codex_apps` resources, accepts bounded and validated `mcp/skill` entries, and reads a selected skill's `SKILL.md` through the same MCP connection. - Register the remote provider in app-server and include it in the skills catalog even when a thread has no selected capability roots or executor. - Contribute hosted skill metadata through the bounded `AvailableSkillsInstructions` developer-context path, exclude remote entries from per-turn catalog injection, and classify `<skills>` messages as contextual developer content so rollback can trim and rebuild them correctly. ## Testing - Extend the app-server MCP resource integration test with `environments: []` to exercise two-page discovery, filter a non-`mcp/skill` resource, verify the escaped developer catalog entry and user-role `<skill>` fragment containing the fetched `SKILL.md`, and preserve generic MCP resource reads. - Add core event-mapping coverage that classifies `<skills>` developer messages as contextual history.
This commit is contained in:
26 files changed
+877
-116
No files matched your search
@@ -1,9 +1,12 @@
|
||||
use codex_core::config::Config;
|
||||
use codex_protocol::capabilities::SelectedCapabilityRoot;
|
||||
use std::future::Future;
|
||||
use std::sync::Mutex;
|
||||
use tokio::sync::OnceCell;
|
||||
|
||||
use crate::catalog::SkillCatalog;
|
||||
use crate::catalog::SkillCatalogEntry;
|
||||
use crate::catalog::SkillProviderError;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct SkillsExtensionConfig {
|
||||
@@ -24,6 +27,7 @@ impl SkillsExtensionConfig {
|
||||
pub(crate) struct SkillsThreadState {
|
||||
config: Mutex<SkillsExtensionConfig>,
|
||||
selected_roots: Vec<SelectedCapabilityRoot>,
|
||||
orchestrator_catalog: OnceCell<SkillCatalog>,
|
||||
}
|
||||
|
||||
impl SkillsThreadState {
|
||||
@@ -34,6 +38,7 @@ impl SkillsThreadState {
|
||||
Self {
|
||||
config: Mutex::new(config),
|
||||
selected_roots,
|
||||
orchestrator_catalog: OnceCell::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +59,16 @@ impl SkillsThreadState {
|
||||
pub(crate) fn selected_roots(&self) -> &[SelectedCapabilityRoot] {
|
||||
&self.selected_roots
|
||||
}
|
||||
|
||||
pub(crate) async fn orchestrator_catalog_snapshot(
|
||||
&self,
|
||||
initialize: impl Future<Output = Result<SkillCatalog, SkillProviderError>> + Send,
|
||||
) -> Result<SkillCatalog, SkillProviderError> {
|
||||
self.orchestrator_catalog
|
||||
.get_or_try_init(|| initialize)
|
||||
.await
|
||||
.cloned()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
|
||||
Reference in new issue
Block a user