Implement v1 skills extension prompt injection (#26167)

## Why

The skills extension needs a real turn-time path before host, executor,
or remote skills can be routed through it. The previous code was mostly
a placeholder catalog/provider sketch, so there was no bounded
available-skills fragment, no source-owned `SKILL.md` read, and no place
for warnings or per-turn selection state to live.

This PR makes `ext/skills` the authority-preserving flow for listing
candidate skills and injecting only explicitly selected main prompts,
without adding more of that logic to `codex-core`.

## What changed

- Expands catalog entries with `main_prompt`, display path, short
description, dependency metadata, enabled/prompt visibility flags, and
authority/package-aware read requests.
- Replaces the placeholder `providers/*` modules with
`SkillProviderSource` and `SkillProviders`, routing list/read/search
calls by source kind and surfacing provider failures as warnings.
- Adds bounded available-skills rendering and `SKILL.md` main-prompt
truncation before the fragments enter model context.
- Resolves explicit skill selections from structured `UserInput::Skill`,
skill-file mentions, `skill://...` paths, and plain `$skill` text
mentions, then reads selected prompts through their owning provider.
- Stores mutable per-thread skills config and per-turn
catalog/selection/warning state.
- Adds `install_with_providers` so tests and future host wiring can
supply concrete providers.

## Testing

- Not run locally.
- Added `codex-rs/ext/skills/tests/skills_extension.rs` coverage for
available-catalog injection, selected prompt injection through the
owning provider, and prompt-hidden skills that remain invokable.
This commit is contained in:
jif authored and GitHub committed 2026-06-03 16:24:16 +02:00
1 parent c9ae0f48a1
commit 96d2d2f68c
15 files changed
+1001 -335

No files matched your search

+9 -12
View File
@@ -1,4 +1,5 @@
use std::future::Future;
use std::pin::Pin;
use crate::catalog::SkillAuthority;
use crate::catalog::SkillCatalog;
@@ -13,12 +14,14 @@ pub struct SkillListQuery {
pub turn_id: String,
pub executor_authorities: Vec<SkillAuthority>,
pub include_host_skills: bool,
pub include_bundled_skills: bool,
pub include_remote_skills: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SkillReadRequest {
pub authority: SkillAuthority,
pub package: SkillPackageId,
pub resource: SkillResourceId,
}
@@ -29,24 +32,18 @@ pub struct SkillSearchRequest {
pub query: String,
}
pub type SkillProviderFuture<'a, T> =
Pin<Box<dyn Future<Output = SkillProviderResult<T>> + Send + 'a>>;
/// Source-specific skill catalog and resource access.
///
/// Implementations must preserve authority boundaries: a resource listed by a
/// provider must be read or searched through the same provider/authority rather
/// than converted into an ambient local path.
pub trait SkillProvider: Send + Sync {
fn list(
&self,
query: SkillListQuery,
) -> impl Future<Output = SkillProviderResult<SkillCatalog>> + Send;
fn list(&self, query: SkillListQuery) -> SkillProviderFuture<'_, SkillCatalog>;
fn read(
&self,
request: SkillReadRequest,
) -> impl Future<Output = SkillProviderResult<SkillReadResult>> + Send;
fn read(&self, request: SkillReadRequest) -> SkillProviderFuture<'_, SkillReadResult>;
fn search(
&self,
request: SkillSearchRequest,
) -> impl Future<Output = SkillProviderResult<SkillSearchResult>> + Send;
fn search(&self, request: SkillSearchRequest) -> SkillProviderFuture<'_, SkillSearchResult>;
}