greentic_runner_host/runner/
mod.rs1pub 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 #[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 pub host: Arc<RunnerHost>,
133 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}