Skip to main content

greentic_runner_host/runner/
mod.rs

1pub mod adapt_events_email;
2pub mod adapt_timer;
3pub mod agent_node;
4pub mod component_invoker;
5pub mod contract_cache;
6pub mod contract_introspection;
7pub mod dispatch_listener;
8pub mod engine;
9pub mod flow_adapter;
10pub mod graph_node;
11pub mod i18n;
12pub mod invocation;
13#[cfg(feature = "knowledge-chronicle")]
14pub mod knowledge_corpus;
15#[cfg(feature = "knowledge-chronicle")]
16pub mod knowledge_mount;
17#[cfg(feature = "long-term-chronicle")]
18pub mod long_term_memory;
19pub mod mcp_node;
20#[cfg(feature = "agentic-worker")]
21pub mod mcp_warm_listener;
22pub mod mocks;
23pub mod operator;
24pub mod remote_dispatch;
25pub mod runtime_session_resumer;
26pub mod schema_validator;
27pub mod templating;
28
29use std::net::SocketAddr;
30use std::sync::Arc;
31
32use anyhow::Result;
33use axum::routing::{get, post};
34use axum::{Router, serve};
35use tokio::net::TcpListener;
36
37use crate::host::RunnerHost;
38use crate::http::{self, admin, auth::AdminAuth, health::HealthState};
39use crate::routing::TenantRouting;
40use crate::runtime::ActivePacks;
41use crate::sql::SqlGateway;
42use crate::watcher::PackReloadHandle;
43
44pub struct HostServer {
45    addr: SocketAddr,
46    router: Router,
47    _state: ServerState,
48}
49
50impl HostServer {
51    pub fn new(
52        port: u16,
53        active: Arc<ActivePacks>,
54        routing: TenantRouting,
55        health: Arc<HealthState>,
56        reload: Option<PackReloadHandle>,
57        admin: AdminAuth,
58        host: Arc<RunnerHost>,
59    ) -> Result<Self> {
60        Self::with_sql(port, active, routing, health, reload, admin, host, None)
61    }
62
63    /// Like [`HostServer::new`] but wires an optional [`SqlGateway`] into the
64    /// server state.  When `sql_gateway` is `None` the server uses an empty
65    /// gateway that returns 404/401 for all `/sql` routes — safe by default.
66    // Builder param set mirrors the existing fields plus `host`; a config-struct
67    // refactor is deferred. See B0 plan.
68    #[allow(clippy::too_many_arguments)]
69    pub fn with_sql(
70        port: u16,
71        active: Arc<ActivePacks>,
72        routing: TenantRouting,
73        health: Arc<HealthState>,
74        reload: Option<PackReloadHandle>,
75        admin: AdminAuth,
76        host: Arc<RunnerHost>,
77        sql_gateway: Option<SqlGateway>,
78    ) -> Result<Self> {
79        let addr = SocketAddr::from(([0, 0, 0, 0], port));
80        let sql = sql_gateway
81            .unwrap_or_else(|| SqlGateway::new(std::collections::HashMap::new(), String::new()));
82        let state = ServerState {
83            active,
84            routing,
85            health,
86            reload,
87            admin,
88            host,
89            sql,
90        };
91        let router = Router::new()
92            .route("/operator/op/invoke", post(operator::invoke))
93            .route("/healthz", get(http::health::handler))
94            .route("/admin/packs/status", get(admin::status))
95            .route("/admin/packs/reload", post(admin::reload))
96            .route("/agent/chat", post(crate::http::agent_chat::agent_chat))
97            .route(
98                "/sql/{conn}/schema",
99                get(crate::sql::routes::schema_handler),
100            )
101            .route("/sql/{conn}/query", post(crate::sql::routes::query_handler))
102            .with_state(state.clone());
103        Ok(Self {
104            addr,
105            router,
106            _state: state,
107        })
108    }
109
110    pub async fn serve(self) -> Result<()> {
111        tracing::info!(addr = %self.addr, "starting host server");
112        let listener = TcpListener::bind(self.addr).await?;
113        serve(
114            listener,
115            self.router
116                .into_make_service_with_connect_info::<SocketAddr>(),
117        )
118        .await?;
119        Ok(())
120    }
121}
122
123#[derive(Clone)]
124pub struct ServerState {
125    pub active: Arc<ActivePacks>,
126    pub routing: TenantRouting,
127    pub health: Arc<HealthState>,
128    pub reload: Option<PackReloadHandle>,
129    pub admin: AdminAuth,
130    /// The runner host instance used by the `POST /agent/chat` handler to
131    /// dispatch activity turns to loaded worker packs.
132    pub host: Arc<RunnerHost>,
133    /// SQL gateway for `/sql/{conn}/schema` and `/sql/{conn}/query`.
134    /// Defaults to an empty gateway (returns 404/401 for all connections)
135    /// when no SQL connections are configured.
136    pub sql: SqlGateway,
137}
138
139impl axum::extract::FromRef<ServerState> for SqlGateway {
140    fn from_ref(state: &ServerState) -> Self {
141        state.sql.clone()
142    }
143}