mirror of
https://github.com/openai/codex.git
synced 2026-05-29 23:40:29 +00:00
v4
This commit is contained in:
16
codex-rs/Cargo.lock
generated
16
codex-rs/Cargo.lock
generated
@@ -2444,12 +2444,14 @@ dependencies = [
|
||||
"codex-core-skills",
|
||||
"codex-exec-server",
|
||||
"codex-execpolicy",
|
||||
"codex-extension-api",
|
||||
"codex-features",
|
||||
"codex-feedback",
|
||||
"codex-git-utils",
|
||||
"codex-hooks",
|
||||
"codex-login",
|
||||
"codex-mcp",
|
||||
"codex-memories",
|
||||
"codex-memories-read",
|
||||
"codex-model-provider",
|
||||
"codex-model-provider-info",
|
||||
@@ -2785,9 +2787,12 @@ name = "codex-extension-api"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"codex-git-attribution",
|
||||
"codex-guardian",
|
||||
"codex-memories",
|
||||
"codex-multi-agent-v2",
|
||||
"rmcp",
|
||||
"codex-tools",
|
||||
"serde_json",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2899,6 +2904,13 @@ dependencies = [
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-guardian"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"codex-extension-api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-hooks"
|
||||
version = "0.0.0"
|
||||
@@ -3091,6 +3103,8 @@ dependencies = [
|
||||
"codex-utils-absolute-path",
|
||||
"rmcp",
|
||||
"serde_json",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -46,6 +46,7 @@ members = [
|
||||
"execpolicy",
|
||||
"execpolicy-legacy",
|
||||
"ext/extension-api",
|
||||
"ext/guardian",
|
||||
"ext/git-attribution",
|
||||
"ext/memories",
|
||||
"ext/multi-agent-v2",
|
||||
@@ -168,6 +169,7 @@ codex-external-agent-migration = { path = "external-agent-migration" }
|
||||
codex-external-agent-sessions = { path = "external-agent-sessions" }
|
||||
codex-experimental-api-macros = { path = "codex-experimental-api-macros" }
|
||||
codex-features = { path = "features" }
|
||||
codex-guardian = { path = "ext/guardian" }
|
||||
codex-git-attribution = { path = "ext/git-attribution" }
|
||||
codex-memories = { path = "ext/memories" }
|
||||
codex-multi-agent-v2 = { path = "ext/multi-agent-v2" }
|
||||
|
||||
@@ -71,7 +71,7 @@ fn main() {
|
||||
mod ctx {
|
||||
use codex_git_attribution::GitAttributionContext;
|
||||
use codex_guardian::GuardianContext;
|
||||
use codex_memories::MemoriesContext;
|
||||
use codex_memories::ctx::MemoriesContext;
|
||||
use codex_multi_agent_v2::MultiAgentV2Context;
|
||||
use codex_multi_agent_v2::UsageHintAudience;
|
||||
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
//! vocabulary from one place, while each contribution family keeps its own
|
||||
//! supporting types nearby.
|
||||
|
||||
use std::future::Future;
|
||||
|
||||
mod prompt;
|
||||
mod tool;
|
||||
mod session_lifecycle;
|
||||
mod tool;
|
||||
|
||||
pub use prompt::PromptFragment;
|
||||
pub use prompt::PromptSlot;
|
||||
@@ -27,18 +29,19 @@ pub trait ToolContributor<C>: Send + Sync {
|
||||
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>>;
|
||||
/// Future returned by one ordered output contribution.
|
||||
pub type OutputContributionFuture<'a> =
|
||||
std::pin::Pin<Box<dyn Future<Output = Result<(), String>> + Send + 'a>>;
|
||||
|
||||
/// Ordered post-processing contribution for one completed output value.
|
||||
///
|
||||
/// Implementations may inspect or mutate `output`; hosts are expected to run
|
||||
/// contributors sequentially so each contributor observes the result of the
|
||||
/// previous one.
|
||||
pub trait OutputContributor<C, O>: Send + Sync {
|
||||
fn contribute<'a>(
|
||||
&'a self,
|
||||
context: &'a C,
|
||||
output: &'a mut O,
|
||||
) -> OutputContributionFuture<'a>;
|
||||
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.
|
||||
/// (ideally we can replace it by a session lifecycle thing or a request contributor?)
|
||||
@@ -52,4 +55,4 @@ pub trait SessionLifecycleContributor<S, T>: Send + Sync {
|
||||
&self,
|
||||
event: session_lifecycle::Event<'_, S, T>,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ mod registry;
|
||||
|
||||
pub use contributors::ApprovalInterceptorContributor;
|
||||
pub use contributors::ContextContributor;
|
||||
pub use contributors::OutputContributionFuture;
|
||||
pub use contributors::OutputContributor;
|
||||
pub use contributors::PromptFragment;
|
||||
pub use contributors::PromptSlot;
|
||||
pub use contributors::ToolCallError;
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
use std::any::Any;
|
||||
use std::any::TypeId;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::ApprovalInterceptorContributor;
|
||||
use crate::CodexExtension;
|
||||
use crate::ContextContributor;
|
||||
use crate::OutputContributor;
|
||||
use crate::ToolContributor;
|
||||
|
||||
/// Mutable registry used while extensions install their typed contributions.
|
||||
pub struct ExtensionRegistryBuilder<C> {
|
||||
context_contributors: Vec<Arc<dyn ContextContributor<C>>>,
|
||||
tool_contributors: Vec<Arc<dyn ToolContributor<C>>>,
|
||||
output_contributors: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
|
||||
approval_interceptor_contributors: Vec<Arc<dyn ApprovalInterceptorContributor<C>>>,
|
||||
}
|
||||
|
||||
@@ -18,6 +23,7 @@ impl<C> Default for ExtensionRegistryBuilder<C> {
|
||||
approval_interceptor_contributors: Vec::new(),
|
||||
context_contributors: Vec::new(),
|
||||
tool_contributors: Vec::new(),
|
||||
output_contributors: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,12 +70,30 @@ impl<C> ExtensionRegistryBuilder<C> {
|
||||
self.tool_contributors.push(contributor);
|
||||
}
|
||||
|
||||
/// Registers one ordered output contributor for output type `O`.
|
||||
pub fn output_contributor<O>(&mut self, contributor: Arc<dyn OutputContributor<C, O>>)
|
||||
where
|
||||
C: 'static,
|
||||
O: 'static,
|
||||
{
|
||||
let Some(contributors) = self
|
||||
.output_contributors
|
||||
.entry(TypeId::of::<O>())
|
||||
.or_insert_with(|| Box::new(Vec::<Arc<dyn OutputContributor<C, O>>>::new()))
|
||||
.downcast_mut::<Vec<Arc<dyn OutputContributor<C, O>>>>()
|
||||
else {
|
||||
unreachable!("output contributor bucket type must match its registered output type");
|
||||
};
|
||||
contributors.push(contributor);
|
||||
}
|
||||
|
||||
/// Finishes construction and returns the immutable registry.
|
||||
pub fn build(self) -> ExtensionRegistry<C> {
|
||||
ExtensionRegistry {
|
||||
approval_interceptor_contributors: self.approval_interceptor_contributors,
|
||||
prompt_contributors: self.context_contributors,
|
||||
tool_contributors: self.tool_contributors,
|
||||
output_contributors: self.output_contributors,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,6 +103,7 @@ pub struct ExtensionRegistry<C> {
|
||||
approval_interceptor_contributors: Vec<Arc<dyn ApprovalInterceptorContributor<C>>>,
|
||||
prompt_contributors: Vec<Arc<dyn ContextContributor<C>>>,
|
||||
tool_contributors: Vec<Arc<dyn ToolContributor<C>>>,
|
||||
output_contributors: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
|
||||
}
|
||||
|
||||
impl<C> ExtensionRegistry<C> {
|
||||
@@ -98,4 +123,19 @@ impl<C> ExtensionRegistry<C> {
|
||||
pub fn tool_contributors(&self) -> &[Arc<dyn ToolContributor<C>>] {
|
||||
&self.tool_contributors
|
||||
}
|
||||
|
||||
/// Returns the registered ordered output contributors for output type `O`.
|
||||
pub fn output_contributors<O>(&self) -> &[Arc<dyn OutputContributor<C, O>>]
|
||||
where
|
||||
C: 'static,
|
||||
O: 'static,
|
||||
{
|
||||
self.output_contributors
|
||||
.get(&TypeId::of::<O>())
|
||||
.and_then(|contributors| {
|
||||
contributors.downcast_ref::<Vec<Arc<dyn OutputContributor<C, O>>>>()
|
||||
})
|
||||
.map(Vec::as_slice)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,10 @@ workspace = true
|
||||
[dependencies]
|
||||
codex-extension-api = { workspace = true }
|
||||
codex-memories-read = { workspace = true }
|
||||
codex-protocol = { workspace = true }
|
||||
codex-tools = { workspace = true }
|
||||
codex-utils-absolute-path = { workspace = true }
|
||||
codex-utils-stream-parser = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
31
codex-rs/ext/memories/src/citation_output.rs
Normal file
31
codex-rs/ext/memories/src/citation_output.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
use codex_extension_api::OutputContributionFuture;
|
||||
use codex_extension_api::OutputContributor;
|
||||
use codex_memories_read::citations::parse_memory_citation;
|
||||
use codex_protocol::items::AgentMessageContent;
|
||||
use codex_protocol::items::TurnItem;
|
||||
use codex_utils_stream_parser::strip_citations;
|
||||
|
||||
use crate::MemoriesExtension;
|
||||
|
||||
impl<C> OutputContributor<C, TurnItem> for MemoriesExtension {
|
||||
fn contribute<'a>(
|
||||
&'a self,
|
||||
_context: &'a C,
|
||||
output: &'a mut TurnItem,
|
||||
) -> OutputContributionFuture<'a> {
|
||||
if let TurnItem::AgentMessage(agent_message) = output {
|
||||
let combined = agent_message
|
||||
.content
|
||||
.iter()
|
||||
.map(|entry| match entry {
|
||||
AgentMessageContent::Text { text } => text.as_str(),
|
||||
})
|
||||
.collect::<String>();
|
||||
let (visible_text, citations) = strip_citations(&combined);
|
||||
agent_message.content = vec![AgentMessageContent::Text { text: visible_text }];
|
||||
agent_message.memory_citation = parse_memory_citation(citations);
|
||||
}
|
||||
|
||||
Box::pin(std::future::ready(Ok(())))
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
mod citation_output;
|
||||
pub mod ctx;
|
||||
mod list_tool;
|
||||
|
||||
@@ -17,6 +18,7 @@ use codex_extension_api::ToolContribution;
|
||||
use codex_extension_api::ToolContributor;
|
||||
use codex_memories_read::build_memory_tool_developer_instructions;
|
||||
use codex_memories_read::memory_root;
|
||||
use codex_protocol::items::TurnItem;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use list_tool::ListMemoriesTool;
|
||||
|
||||
@@ -53,6 +55,7 @@ impl<C: MemoriesContext> ContextContributor<C> for MemoriesExtension {
|
||||
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.output_contributor::<TurnItem>(self.clone());
|
||||
registry.prompt_contributor(self);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user