mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Remove async-trait from extension contributors (#27383)
## Why
Extension contributors are registered behind `dyn Trait` objects, so
native `async fn`/RPITIT methods would make these traits
non-object-safe. Spell out the boxed, `Send` future contract directly so
`extension-api` no longer needs `async-trait` while retaining the
existing runtime model.
## What changed
- add a shared `ExtensionFuture` alias and use it for asynchronous
contributor methods
- migrate production and test implementations to return `Box::pin(async
move { ... })`
- remove `async-trait` dependencies where they are no longer used,
keeping it dev-only where unrelated test executors still require it
## Behavior
No behavior change is intended. Contributor futures remain boxed,
`Send`, dynamically dispatched, and lazily executed; cancellation and
callback ordering stay unchanged.
## Testing
- `just test -p codex-extension-api` (11 passed)
- affected extension crates (64 passed)
- targeted `codex-core` contributor tests (14 passed)
- `just fmt`
- `just bazel-lock-update`
- `just bazel-lock-check`
A broad local `codex-core` run compiled successfully but encountered
unrelated sandbox and missing test-binary fixture failures; CI will run
the full checks.
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
@@ -9,6 +7,7 @@ use codex_extension_api::ContextContributor;
|
||||
use codex_extension_api::ContextualUserFragment;
|
||||
use codex_extension_api::ExtensionData;
|
||||
use codex_extension_api::ExtensionEventSink;
|
||||
use codex_extension_api::ExtensionFuture;
|
||||
use codex_extension_api::ExtensionRegistryBuilder;
|
||||
use codex_extension_api::PromptFragment;
|
||||
use codex_extension_api::ThreadLifecycleContributor;
|
||||
@@ -37,32 +36,32 @@ impl ContextContributor for AllContributors {
|
||||
&'a self,
|
||||
_session_store: &'a ExtensionData,
|
||||
_thread_store: &'a ExtensionData,
|
||||
) -> Pin<Box<dyn Future<Output = Vec<PromptFragment>> + Send + 'a>> {
|
||||
) -> ExtensionFuture<'a, Vec<PromptFragment>> {
|
||||
Box::pin(std::future::ready(Vec::new()))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ThreadLifecycleContributor<()> for AllContributors {}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl TurnLifecycleContributor for AllContributors {}
|
||||
|
||||
impl ConfigContributor<()> for AllContributors {}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl TokenUsageContributor for AllContributors {}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl TurnInputContributor for AllContributors {
|
||||
async fn contribute(
|
||||
&self,
|
||||
_input: TurnInputContext,
|
||||
_session_store: &ExtensionData,
|
||||
_thread_store: &ExtensionData,
|
||||
_turn_store: &ExtensionData,
|
||||
) -> Vec<Box<dyn ContextualUserFragment + Send>> {
|
||||
Vec::new()
|
||||
fn contribute<'a>(
|
||||
&'a self,
|
||||
input: TurnInputContext,
|
||||
_session_store: &'a ExtensionData,
|
||||
_thread_store: &'a ExtensionData,
|
||||
_turn_store: &'a ExtensionData,
|
||||
) -> ExtensionFuture<'a, Vec<Box<dyn ContextualUserFragment + Send>>> {
|
||||
Box::pin(async move {
|
||||
let _self = self;
|
||||
let _input = input;
|
||||
Vec::new()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,27 +77,31 @@ impl ToolContributor for AllContributors {
|
||||
|
||||
impl ToolLifecycleContributor for AllContributors {}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl TurnItemContributor for AllContributors {
|
||||
async fn contribute(
|
||||
&self,
|
||||
_thread_store: &ExtensionData,
|
||||
_turn_store: &ExtensionData,
|
||||
_item: &mut TurnItem,
|
||||
) -> Result<(), String> {
|
||||
Ok(())
|
||||
fn contribute<'a>(
|
||||
&'a self,
|
||||
_thread_store: &'a ExtensionData,
|
||||
_turn_store: &'a ExtensionData,
|
||||
_item: &'a mut TurnItem,
|
||||
) -> ExtensionFuture<'a, Result<(), String>> {
|
||||
Box::pin(async move {
|
||||
let _self = self;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ApprovalReviewContributor for AllContributors {
|
||||
async fn contribute(
|
||||
&self,
|
||||
_session_store: &ExtensionData,
|
||||
_thread_store: &ExtensionData,
|
||||
_prompt: &str,
|
||||
) -> Option<ReviewDecision> {
|
||||
Some(ReviewDecision::ApprovedForSession)
|
||||
fn contribute<'a>(
|
||||
&'a self,
|
||||
_session_store: &'a ExtensionData,
|
||||
_thread_store: &'a ExtensionData,
|
||||
_prompt: &'a str,
|
||||
) -> ExtensionFuture<'a, Option<ReviewDecision>> {
|
||||
Box::pin(async move {
|
||||
let _self = self;
|
||||
Some(ReviewDecision::ApprovedForSession)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +149,7 @@ impl ContextContributor for NamedContextContributor {
|
||||
&'a self,
|
||||
_session_store: &'a ExtensionData,
|
||||
_thread_store: &'a ExtensionData,
|
||||
) -> Pin<Box<dyn Future<Output = Vec<PromptFragment>> + Send + 'a>> {
|
||||
) -> ExtensionFuture<'a, Vec<PromptFragment>> {
|
||||
Box::pin(std::future::ready(vec![PromptFragment::developer_policy(
|
||||
self.0,
|
||||
)]))
|
||||
@@ -158,19 +161,20 @@ struct RecordingTurnItemContributor {
|
||||
calls: Arc<Mutex<Vec<&'static str>>>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl TurnItemContributor for RecordingTurnItemContributor {
|
||||
async fn contribute(
|
||||
&self,
|
||||
_thread_store: &ExtensionData,
|
||||
_turn_store: &ExtensionData,
|
||||
_item: &mut TurnItem,
|
||||
) -> Result<(), String> {
|
||||
self.calls
|
||||
.lock()
|
||||
.unwrap_or_else(|error| panic!("turn item calls lock poisoned: {error}"))
|
||||
.push(self.name);
|
||||
Ok(())
|
||||
fn contribute<'a>(
|
||||
&'a self,
|
||||
_thread_store: &'a ExtensionData,
|
||||
_turn_store: &'a ExtensionData,
|
||||
_item: &'a mut TurnItem,
|
||||
) -> ExtensionFuture<'a, Result<(), String>> {
|
||||
Box::pin(async move {
|
||||
self.calls
|
||||
.lock()
|
||||
.unwrap_or_else(|error| panic!("turn item calls lock poisoned: {error}"))
|
||||
.push(self.name);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,24 +240,25 @@ struct RecordingApprovalContributor {
|
||||
calls: Arc<Mutex<Vec<ApprovalCall>>>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ApprovalReviewContributor for RecordingApprovalContributor {
|
||||
async fn contribute(
|
||||
&self,
|
||||
session_store: &ExtensionData,
|
||||
thread_store: &ExtensionData,
|
||||
prompt: &str,
|
||||
) -> Option<ReviewDecision> {
|
||||
self.calls
|
||||
.lock()
|
||||
.unwrap_or_else(|error| panic!("approval calls lock poisoned: {error}"))
|
||||
.push(ApprovalCall {
|
||||
contributor: self.name,
|
||||
session_id: session_store.level_id().to_string(),
|
||||
thread_id: thread_store.level_id().to_string(),
|
||||
prompt: prompt.to_string(),
|
||||
});
|
||||
self.decision.clone()
|
||||
fn contribute<'a>(
|
||||
&'a self,
|
||||
session_store: &'a ExtensionData,
|
||||
thread_store: &'a ExtensionData,
|
||||
prompt: &'a str,
|
||||
) -> ExtensionFuture<'a, Option<ReviewDecision>> {
|
||||
Box::pin(async move {
|
||||
self.calls
|
||||
.lock()
|
||||
.unwrap_or_else(|error| panic!("approval calls lock poisoned: {error}"))
|
||||
.push(ApprovalCall {
|
||||
contributor: self.name,
|
||||
session_id: session_store.level_id().to_string(),
|
||||
thread_id: thread_store.level_id().to_string(),
|
||||
prompt: prompt.to_string(),
|
||||
});
|
||||
self.decision.clone()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user