use crate::core::ctx::Ctx;
use crate::core::engine::Engine;
use crate::middleware::SpawnerLayer;
use crate::types::{CapToken, TaskId};
use crate::worker::adapter::{SpawnError, SpawnerAdapter};
use crate::worker::Worker;
use async_trait::async_trait;
use std::sync::Arc;
pub trait AgentResolver: Send + Sync + 'static {
fn resolve(&self, agent_hint: &str, ctx: &Ctx) -> String;
}
pub struct FnResolver<F>(
) -> String`.
pub F,
);
impl<F> AgentResolver for FnResolver<F>
where
F: Fn(&str, &Ctx) -> String + Send + Sync + 'static,
{
fn resolve(&self, hint: &str, ctx: &Ctx) -> String {
(self.0)(hint, ctx)
}
}
pub struct ResolverMiddleware {
resolver: Arc<dyn AgentResolver>,
}
impl ResolverMiddleware {
pub fn new(resolver: Arc<dyn AgentResolver>) -> Self {
Self { resolver }
}
pub fn from_fn<F>(f: F) -> Self
where
F: Fn(&str, &Ctx) -> String + Send + Sync + 'static,
{
Self {
resolver: Arc::new(FnResolver(f)),
}
}
}
impl SpawnerLayer for ResolverMiddleware {
fn wrap(&self, inner: Arc<dyn SpawnerAdapter>) -> Arc<dyn SpawnerAdapter> {
Arc::new(ResolverWrapped {
inner,
resolver: self.resolver.clone(),
})
}
}
struct ResolverWrapped {
inner: Arc<dyn SpawnerAdapter>,
resolver: Arc<dyn AgentResolver>,
}
#[async_trait]
impl SpawnerAdapter for ResolverWrapped {
async fn spawn(
&self,
engine: &Engine,
ctx: &Ctx,
task_id: TaskId,
attempt: u32,
token: CapToken,
) -> Result<Box<dyn Worker>, SpawnError> {
let resolved = self.resolver.resolve(&ctx.agent, ctx);
if resolved == ctx.agent {
self.inner.spawn(engine, ctx, task_id, attempt, token).await
} else {
let mut new_ctx = ctx.clone();
new_ctx.agent = resolved;
self.inner
.spawn(engine, &new_ctx, task_id, attempt, token)
.await
}
}
}