Skip to main content

liminal_server/agents/
station.rs

1//! Agent stations use the console's existing activity contract.
2
3use serde::Serialize;
4
5use super::records::{AgentHarness, AgentRecord};
6use crate::console::records::{Station, StationActivity, StationKind, StationState};
7
8/// Agent metadata extends the shared station shape without changing other
9/// station constructors or copying a working stream out of Lys.
10#[derive(Clone, Serialize)]
11pub struct AgentStation {
12    /// The shared station fields.
13    #[serde(flatten)]
14    pub station: Station,
15    /// The profile's harness label.
16    pub harness: AgentHarness,
17    /// The approved sentence stating the station's job.
18    pub purpose: String,
19    /// Subjects the live ticket listens to, in subject order.
20    pub stops: Vec<String>,
21}
22
23impl AgentStation {
24    /// The inbox is one activity accepting text as data.
25    #[must_use]
26    pub fn new(
27        record: &AgentRecord,
28        device: &str,
29        state: StationState,
30        stops: Vec<String>,
31    ) -> Self {
32        let inbox = format!("agents.{}.inbox", record.name);
33        Self { station: Station { id: inbox.clone(), name: record.name.clone(), device: device.into(),
34            kind: StationKind::Agent, state, subjects: Some(vec![inbox]), activities: Some(vec![StationActivity {
35                name: "inbox".into(),
36                input_schema_json: r#"{"additionalProperties":false,"properties":{"text":{"type":"string"}},"required":["text"],"type":"object"}"#.into(),
37                output_schema_json: "{}".into(),
38            }]) }, harness: record.harness, purpose: record.purpose.clone(), stops }
39    }
40}
41
42impl std::fmt::Debug for AgentStation {
43    fn fmt(&self, out: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44        out.debug_struct("AgentStation")
45            .field("harness", &self.harness)
46            .finish_non_exhaustive()
47    }
48}