Skip to main content

mlua_swarm/worker/
baseline.rs

1//! Baseline agent — the canonical `RustFn` worker for bootstrap and
2//! smoke tests.
3//!
4//! The library-layer source of truth that structurally removes the
5//! pattern of each binary (server / MCP adapter / one-shot runner) inlining
6//! its own "let's just wire up a quick echo" duplicate. Same shape as
7//! `enhance/blueprint.rs`:
8//!
9//! - Export the agent name as a **role-literal const** ([`AG_IDENTITY`]).
10//!   The naming reflects the function itself — an identity /
11//!   passthrough of `ctx` — and deliberately avoids demo / echo
12//!   framing.
13//! - Bake **the real implementation** ([`extend_with_baseline`]). Not a
14//!   false-positive fake — a straightforward passthrough that returns
15//!   the input prompt in the value field, so callers can build smoke
16//!   tests around "the baseline agent exists".
17//! - **A builder** ([`extend_with_baseline`]) that adds the RustFn to
18//!   an existing `RustFnInProcessSpawnerFactory`. Same shape as
19//!   `enhance::blueprint::extend_factory`.
20//!
21//! ## Usage
22//!
23//! ```ignore
24//! use mlua_swarm_engine_core::baseline::{extend_with_baseline, AG_IDENTITY};
25//! use mlua_swarm_engine_core::RustFnInProcessSpawnerFactory;
26//!
27//! let factory = extend_with_baseline(RustFnInProcessSpawnerFactory::new());
28//! // The factory now has a RustFn registered under fn_id = AG_IDENTITY ("identity").
29//! ```
30//!
31//! Blueprint flows reference it as `spec: {"fn_id": baseline::AG_IDENTITY}`
32//! (or the literal `"identity"`).
33
34use crate::blueprint::compiler::RustFnInProcessSpawnerFactory;
35use crate::worker::adapter::WorkerResult;
36use serde_json::json;
37
38/// The baseline `RustFn` agent name — `"identity"`.
39///
40/// Role: a passthrough worker that echoes the input prompt into
41/// `value`. The logical id referenced from both the flow's `Step.ref`
42/// and the agent spec's `fn_id`.
43pub const AG_IDENTITY: &str = "identity";
44
45/// Builder that adds the baseline `RustFn` to a base factory.
46///
47/// Only one worker exists today ([`AG_IDENTITY`]); if additional
48/// baseline axes appear, they will be collected here.
49pub fn extend_with_baseline(base: RustFnInProcessSpawnerFactory) -> RustFnInProcessSpawnerFactory {
50    base.register_fn(AG_IDENTITY, |inv| async move {
51        Ok(WorkerResult {
52            value: json!({
53                "by": "baseline-identity",
54                "agent": inv.agent,
55                "echoed": inv.prompt,
56            }),
57            ok: true,
58            stats: None,
59        }
60        .ensure_worker_kind("rust_fn"))
61    })
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67    use crate::blueprint::compiler::{SpawnerFactory, SpawnerFactoryKind};
68    use crate::blueprint::{AgentDef, AgentKind};
69    use serde_json::json;
70
71    #[test]
72    fn ag_identity_is_stable_literal() {
73        assert_eq!(AG_IDENTITY, "identity");
74    }
75
76    #[test]
77    fn extend_with_baseline_builds_identity_adapter() {
78        let factory = extend_with_baseline(RustFnInProcessSpawnerFactory::new());
79        assert_eq!(
80            <RustFnInProcessSpawnerFactory as SpawnerFactoryKind>::KIND,
81            AgentKind::RustFn
82        );
83        let agent_def = AgentDef {
84            name: "id".into(),
85            kind: AgentKind::RustFn,
86            spec: json!({ "fn_id": AG_IDENTITY }),
87            profile: None,
88            meta: None,
89            runner: None,
90            runner_ref: None,
91            verdict: None,
92        };
93        factory
94            .build(&agent_def, None)
95            .expect("AG_IDENTITY fn must be registered for AgentDef build");
96    }
97}