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