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:
jif
2026-06-10 14:31:09 +02:00
committed by GitHub
parent ced1b8aa88
commit d2f6d23c6c
21 changed files with 736 additions and 597 deletions
+14 -8
View File
@@ -3,6 +3,7 @@ use std::sync::Arc;
use codex_core::config::Config;
use codex_extension_api::AgentSpawnFuture;
use codex_extension_api::AgentSpawner;
use codex_extension_api::ExtensionFuture;
use codex_extension_api::ExtensionRegistryBuilder;
use codex_extension_api::ThreadLifecycleContributor;
use codex_extension_api::ThreadStartInput;
@@ -47,18 +48,23 @@ impl GuardianThreadContext {
}
}
#[async_trait::async_trait]
impl<S> ThreadLifecycleContributor<Config> for GuardianExtension<S>
where
S: Send + Sync,
{
async fn on_thread_start(&self, input: ThreadStartInput<'_, Config>) {
let Ok(forked_from_thread_id) = ThreadId::from_string(input.thread_store.level_id()) else {
return;
};
input.thread_store.insert(GuardianThreadContext {
forked_from_thread_id,
});
fn on_thread_start<'a>(
&'a self,
input: ThreadStartInput<'a, Config>,
) -> ExtensionFuture<'a, ()> {
Box::pin(async move {
let Ok(forked_from_thread_id) = ThreadId::from_string(input.thread_store.level_id())
else {
return;
};
input.thread_store.insert(GuardianThreadContext {
forked_from_thread_id,
});
})
}
}