Skip to main content

mlua_swarm/middleware/
project_name_alias.rs

1//! `ProjectNameAliasMiddleware` — a `SpawnerLayer` that propagates a
2//! task-level project alias.
3//!
4//! When `Blueprint.metadata.project_name_alias` is `Some(_)`, `service::
5//! linker::link` places this layer on the stack. Just before spawn it
6//! inserts the literal value into `Ctx.meta.runtime` under the
7//! `project_name_alias` key.
8//!
9//! Downstream Operator / spawner code (for example `mlua-swarm-server`'s
10//! `Operator::execute`) reads it via
11//! `ctx.meta.runtime.get("project_name_alias")` and splices it into the
12//! Spawn directive prompt body, handing MainAI the discipline "run
13//! `mcp__lds__session_create(root=..., alias=<this>)` and inject
14//! `LDS Session Alias: <this>` into every SubAgent dispatch prompt". The
15//! authoritative discipline lives in `docs/project-name-alias.md`, the
16//! public doc.
17//!
18//! Same shape as `AgentResolver` / `ResolverMiddleware`: a thin layer that
19//! does not touch engine state.
20
21use crate::core::ctx::Ctx;
22use crate::core::engine::Engine;
23use crate::middleware::SpawnerLayer;
24use crate::types::{CapToken, TaskId};
25use crate::worker::adapter::{SpawnError, SpawnerAdapter};
26use crate::worker::Worker;
27use async_trait::async_trait;
28use serde_json::Value;
29use std::sync::Arc;
30
31/// Key under `ctx.meta.runtime` that downstream Operator code reads with
32/// `get`.
33pub const PROJECT_NAME_ALIAS_KEY: &str = "project_name_alias";
34
35/// `SpawnerLayer` that drops the received alias into `ctx` just before spawn.
36pub struct ProjectNameAliasMiddleware {
37    alias: String,
38}
39
40impl ProjectNameAliasMiddleware {
41    /// Wraps a project alias string to inject on every spawn.
42    pub fn new(alias: impl Into<String>) -> Self {
43        Self {
44            alias: alias.into(),
45        }
46    }
47}
48
49impl SpawnerLayer for ProjectNameAliasMiddleware {
50    fn wrap(&self, inner: Arc<dyn SpawnerAdapter>) -> Arc<dyn SpawnerAdapter> {
51        Arc::new(ProjectNameAliasWrapped {
52            inner,
53            alias: self.alias.clone(),
54        })
55    }
56}
57
58struct ProjectNameAliasWrapped {
59    inner: Arc<dyn SpawnerAdapter>,
60    alias: String,
61}
62
63#[async_trait]
64impl SpawnerAdapter for ProjectNameAliasWrapped {
65    async fn spawn(
66        &self,
67        engine: &Engine,
68        ctx: &Ctx,
69        task_id: TaskId,
70        attempt: u32,
71        token: CapToken,
72    ) -> Result<Box<dyn Worker>, SpawnError> {
73        let mut new_ctx = ctx.clone();
74        new_ctx.meta.runtime.insert(
75            PROJECT_NAME_ALIAS_KEY.to_string(),
76            Value::String(self.alias.clone()),
77        );
78        self.inner
79            .spawn(engine, &new_ctx, task_id, attempt, token)
80            .await
81    }
82}