mirror of
https://github.com/openai/codex.git
synced 2026-06-01 19:02:59 +00:00
v3
This commit is contained in:
14
codex-rs/ext/extension-api/notes.md
Normal file
14
codex-rs/ext/extension-api/notes.md
Normal file
@@ -0,0 +1,14 @@
|
||||
Everything becomes a good contributor design, which contributors do we need?
|
||||
|
||||
git attribution Context
|
||||
memories Context + Tool + Output
|
||||
guardian Context + Request
|
||||
goal Tool + Runtime
|
||||
image generation Tool + Output
|
||||
skills Context + Turn
|
||||
personality Context
|
||||
plugins / apps / connectors Context + Turn
|
||||
shell snapshot Runtime
|
||||
web search Tool
|
||||
AGENTS.md Context (Runtime too only if you want eager refresh/cache behavior)
|
||||
future sandboxing probably Request + Runtime
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
mod prompt;
|
||||
mod tool;
|
||||
mod session_lifecycle;
|
||||
|
||||
pub use prompt::PromptFragment;
|
||||
pub use prompt::PromptSlot;
|
||||
@@ -14,33 +15,41 @@ pub use tool::ToolCallError;
|
||||
pub use tool::ToolContribution;
|
||||
pub use tool::ToolHandler;
|
||||
|
||||
/// Extension contribution that adds prompt fragments during prompt assembly.
|
||||
/// Arguably, can become async
|
||||
pub trait ContextContributor<C>: Send + Sync {
|
||||
fn contribute(&self, context: &C) -> Vec<PromptFragment>; // TODO use existing fragments ofc
|
||||
}
|
||||
|
||||
/// Extension contribution that exposes native tools owned by a feature.
|
||||
pub trait ToolContributor<C>: Send + Sync {
|
||||
/// Returns the native tools visible for the supplied runtime context.
|
||||
fn tools(&self, context: &C) -> Vec<ToolContribution<C>>;
|
||||
}
|
||||
|
||||
/// Analyze or perform computation on the output. Works only if the post-processing pipeline is ordered
|
||||
pub type OutputContributionFuture<'a> = std::pin::Pin<Box<dyn Future<Output = Result<(), String>> + Send + 'a>>;
|
||||
pub trait OutputContributor<C, O>: Send + Sync {
|
||||
fn contribute<'a>(
|
||||
&'a self,
|
||||
context: &'a C,
|
||||
output: &'a mut O,
|
||||
) -> OutputContributionFuture<'a>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TODO: WIP
|
||||
/// Extension contribution that can claim approval requests for a runtime context.
|
||||
///
|
||||
/// Implementations should make only the routing decision here. The host keeps
|
||||
/// ownership of executing the chosen review flow and translating its result
|
||||
/// back into the surrounding runtime.
|
||||
/// (ideally we can replace it by a session lifecycle thing or a request contributor?)
|
||||
pub trait ApprovalInterceptorContributor<C>: Send + Sync {
|
||||
/// Returns whether this contributor should intercept approvals in `context`.
|
||||
fn intercepts_approvals(&self, context: &C) -> bool;
|
||||
}
|
||||
|
||||
/// Extension contribution that adds prompt fragments during prompt assembly.
|
||||
///
|
||||
/// Implementations should inspect only their feature-owned slice of the
|
||||
/// current runtime context and describe the prompt content exposed for that
|
||||
/// invocation. The host remains responsible for ordering fragments and
|
||||
/// assembling prompt items.
|
||||
pub trait PromptContributor<C>: Send + Sync {
|
||||
fn contribute(&self, context: &C) -> Vec<PromptFragment>;
|
||||
}
|
||||
|
||||
/// Extension contribution that exposes native tools owned by a feature.
|
||||
///
|
||||
/// Implementations should inspect only their feature-owned slice of the
|
||||
/// current runtime context and return the tools exposed for that invocation.
|
||||
/// The host remains responsible for mounting those tools and adapting calls
|
||||
/// into its runtime.
|
||||
pub trait ToolContributor<C>: Send + Sync {
|
||||
/// Returns the native tools visible for the supplied runtime context.
|
||||
fn tools(&self, context: &C) -> Vec<ToolContribution<C>>;
|
||||
}
|
||||
pub trait SessionLifecycleContributor<S, T>: Send + Sync {
|
||||
fn on_lifecycle_event(
|
||||
&self,
|
||||
event: session_lifecycle::Event<'_, S, T>,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
pub enum Event<'a, S, T> {
|
||||
SessionStarted(&'a S),
|
||||
TurnStarted(&'a T),
|
||||
TurnFinished { turn: &'a T, outcome: String }, // Make outcome better?!
|
||||
SessionStopping(&'a S),
|
||||
}
|
||||
@@ -12,7 +12,7 @@ mod extension;
|
||||
mod registry;
|
||||
|
||||
pub use contributors::ApprovalInterceptorContributor;
|
||||
pub use contributors::PromptContributor;
|
||||
pub use contributors::ContextContributor;
|
||||
pub use contributors::PromptFragment;
|
||||
pub use contributors::PromptSlot;
|
||||
pub use contributors::ToolCallError;
|
||||
|
||||
@@ -2,21 +2,21 @@ use std::sync::Arc;
|
||||
|
||||
use crate::ApprovalInterceptorContributor;
|
||||
use crate::CodexExtension;
|
||||
use crate::PromptContributor;
|
||||
use crate::ContextContributor;
|
||||
use crate::ToolContributor;
|
||||
|
||||
/// Mutable registry used while extensions install their typed contributions.
|
||||
pub struct ExtensionRegistryBuilder<C> {
|
||||
approval_interceptor_contributors: Vec<Arc<dyn ApprovalInterceptorContributor<C>>>,
|
||||
prompt_contributors: Vec<Arc<dyn PromptContributor<C>>>,
|
||||
context_contributors: Vec<Arc<dyn ContextContributor<C>>>,
|
||||
tool_contributors: Vec<Arc<dyn ToolContributor<C>>>,
|
||||
approval_interceptor_contributors: Vec<Arc<dyn ApprovalInterceptorContributor<C>>>,
|
||||
}
|
||||
|
||||
impl<C> Default for ExtensionRegistryBuilder<C> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
approval_interceptor_contributors: Vec::new(),
|
||||
prompt_contributors: Vec::new(),
|
||||
context_contributors: Vec::new(),
|
||||
tool_contributors: Vec::new(),
|
||||
}
|
||||
}
|
||||
@@ -55,8 +55,8 @@ impl<C> ExtensionRegistryBuilder<C> {
|
||||
}
|
||||
|
||||
/// Registers one prompt contributor.
|
||||
pub fn prompt_contributor(&mut self, contributor: Arc<dyn PromptContributor<C>>) {
|
||||
self.prompt_contributors.push(contributor);
|
||||
pub fn prompt_contributor(&mut self, contributor: Arc<dyn ContextContributor<C>>) {
|
||||
self.context_contributors.push(contributor);
|
||||
}
|
||||
|
||||
/// Registers one native tool contributor.
|
||||
@@ -68,7 +68,7 @@ impl<C> ExtensionRegistryBuilder<C> {
|
||||
pub fn build(self) -> ExtensionRegistry<C> {
|
||||
ExtensionRegistry {
|
||||
approval_interceptor_contributors: self.approval_interceptor_contributors,
|
||||
prompt_contributors: self.prompt_contributors,
|
||||
prompt_contributors: self.context_contributors,
|
||||
tool_contributors: self.tool_contributors,
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ impl<C> ExtensionRegistryBuilder<C> {
|
||||
/// Immutable typed registry produced after extensions are installed.
|
||||
pub struct ExtensionRegistry<C> {
|
||||
approval_interceptor_contributors: Vec<Arc<dyn ApprovalInterceptorContributor<C>>>,
|
||||
prompt_contributors: Vec<Arc<dyn PromptContributor<C>>>,
|
||||
prompt_contributors: Vec<Arc<dyn ContextContributor<C>>>,
|
||||
tool_contributors: Vec<Arc<dyn ToolContributor<C>>>,
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ impl<C> ExtensionRegistry<C> {
|
||||
}
|
||||
|
||||
/// Returns the registered prompt contributors.
|
||||
pub fn prompt_contributors(&self) -> &[Arc<dyn PromptContributor<C>>] {
|
||||
pub fn prompt_contributors(&self) -> &[Arc<dyn ContextContributor<C>>] {
|
||||
&self.prompt_contributors
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use codex_extension_api::CodexExtension;
|
||||
use codex_extension_api::ContextContributor;
|
||||
use codex_extension_api::ExtensionRegistryBuilder;
|
||||
use codex_extension_api::PromptContributor;
|
||||
use codex_extension_api::PromptFragment;
|
||||
|
||||
const DEFAULT_ATTRIBUTION_VALUE: &str = "Codex <noreply@openai.com>";
|
||||
@@ -39,7 +39,7 @@ impl GitAttributionExtension {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GitAttributionContext> PromptContributor<C> for GitAttributionExtension {
|
||||
impl<C: GitAttributionContext> ContextContributor<C> for GitAttributionExtension {
|
||||
fn contribute(&self, context: &C) -> Vec<PromptFragment> {
|
||||
self.instruction(context)
|
||||
.map(PromptFragment::developer_capability)
|
||||
|
||||
@@ -6,8 +6,8 @@ use std::sync::Arc;
|
||||
|
||||
use codex_extension_api::ApprovalInterceptorContributor;
|
||||
use codex_extension_api::CodexExtension;
|
||||
use codex_extension_api::ContextContributor;
|
||||
use codex_extension_api::ExtensionRegistryBuilder;
|
||||
use codex_extension_api::PromptContributor;
|
||||
use codex_extension_api::PromptFragment;
|
||||
|
||||
/// Runtime facts needed to expose Guardian surfaces.
|
||||
@@ -53,7 +53,7 @@ impl<C: GuardianContext> ApprovalInterceptorContributor<C> for GuardianExtension
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GuardianContext> PromptContributor<C> for GuardianExtension {
|
||||
impl<C: GuardianContext> ContextContributor<C> for GuardianExtension {
|
||||
fn contribute(&self, context: &C) -> Vec<PromptFragment> {
|
||||
self.policy_prompt(context)
|
||||
.map(PromptFragment::separate_developer)
|
||||
|
||||
8
codex-rs/ext/memories/src/ctx.rs
Normal file
8
codex-rs/ext/memories/src/ctx.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
/// Runtime facts needed to decide whether read-memory surfaces are visible.
|
||||
///
|
||||
/// Hosts should expose the current effective values for the thread being
|
||||
/// assembled. The extension owns the policy that combines those values.
|
||||
pub trait MemoriesContext {
|
||||
fn memory_tool_enabled(&self) -> bool;
|
||||
fn use_memories(&self) -> bool;
|
||||
}
|
||||
@@ -2,14 +2,16 @@
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
pub mod ctx;
|
||||
mod list_tool;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::ctx::MemoriesContext;
|
||||
use codex_extension_api::CodexExtension;
|
||||
use codex_extension_api::ContextContributor;
|
||||
use codex_extension_api::ExtensionRegistryBuilder;
|
||||
use codex_extension_api::PromptContributor;
|
||||
use codex_extension_api::PromptFragment;
|
||||
use codex_extension_api::ToolContribution;
|
||||
use codex_extension_api::ToolContributor;
|
||||
@@ -18,15 +20,6 @@ use codex_memories_read::memory_root;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use list_tool::ListMemoriesTool;
|
||||
|
||||
/// Runtime facts needed to decide whether read-memory surfaces are visible.
|
||||
///
|
||||
/// Hosts should expose the current effective values for the thread being
|
||||
/// assembled. The extension owns the policy that combines those values.
|
||||
pub trait MemoriesContext {
|
||||
fn memory_tool_enabled(&self) -> bool;
|
||||
fn use_memories(&self) -> bool;
|
||||
}
|
||||
|
||||
/// Extension that contributes memories read surfaces.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MemoriesExtension {
|
||||
@@ -34,6 +27,36 @@ pub struct MemoriesExtension {
|
||||
list_tool: Arc<ListMemoriesTool>,
|
||||
}
|
||||
|
||||
impl<C: MemoriesContext + Send + Sync + 'static> ToolContributor<C> for MemoriesExtension {
|
||||
fn tools(&self, context: &C) -> Vec<ToolContribution<C>> {
|
||||
if !self.is_read_surface_enabled(context) {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
vec![self.list_tool.contribution()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: MemoriesContext> ContextContributor<C> for MemoriesExtension {
|
||||
fn contribute(&self, context: &C) -> Vec<PromptFragment> {
|
||||
if !self.is_read_surface_enabled(context) {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
self.read_prompt()
|
||||
.map(PromptFragment::developer_policy)
|
||||
.into_iter()
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: MemoriesContext + Send + Sync + 'static> CodexExtension<C> for MemoriesExtension {
|
||||
fn install(self: Arc<Self>, registry: &mut ExtensionRegistryBuilder<C>) {
|
||||
registry.tool_contributor(self.clone());
|
||||
registry.prompt_contributor(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl MemoriesExtension {
|
||||
fn new(read_prompt: Option<String>, memories_root: impl Into<PathBuf>) -> Self {
|
||||
Self {
|
||||
@@ -70,37 +93,7 @@ impl MemoriesExtension {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: MemoriesContext + Send + Sync + 'static> ToolContributor<C> for MemoriesExtension {
|
||||
fn tools(&self, context: &C) -> Vec<ToolContribution<C>> {
|
||||
if !self.is_read_surface_enabled(context) {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
vec![self.list_tool.contribution()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: MemoriesContext> PromptContributor<C> for MemoriesExtension {
|
||||
fn contribute(&self, context: &C) -> Vec<PromptFragment> {
|
||||
if !self.is_read_surface_enabled(context) {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
self.read_prompt()
|
||||
.map(PromptFragment::developer_policy)
|
||||
.into_iter()
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: MemoriesContext + Send + Sync + 'static> CodexExtension<C> for MemoriesExtension {
|
||||
fn install(self: Arc<Self>, registry: &mut ExtensionRegistryBuilder<C>) {
|
||||
registry.tool_contributor(self.clone());
|
||||
registry.prompt_contributor(self);
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a shared memories extension using the live memories read prompt.
|
||||
/// todo Other builder pattern...
|
||||
pub async fn extension(codex_home: &AbsolutePathBuf) -> Arc<MemoriesExtension> {
|
||||
Arc::new(MemoriesExtension::from_codex_home(codex_home).await)
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use codex_extension_api::CodexExtension;
|
||||
use codex_extension_api::ContextContributor;
|
||||
use codex_extension_api::ExtensionRegistryBuilder;
|
||||
use codex_extension_api::PromptContributor;
|
||||
use codex_extension_api::PromptFragment;
|
||||
|
||||
/// Which kind of agent should receive a MultiAgentV2 usage hint.
|
||||
@@ -53,7 +53,7 @@ impl MultiAgentV2Extension {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: MultiAgentV2Context> PromptContributor<C> for MultiAgentV2Extension {
|
||||
impl<C: MultiAgentV2Context> ContextContributor<C> for MultiAgentV2Extension {
|
||||
fn contribute(&self, context: &C) -> Vec<PromptFragment> {
|
||||
self.usage_hint_text(context)
|
||||
.map(PromptFragment::separate_developer)
|
||||
|
||||
Reference in New Issue
Block a user