pub struct AppState {Show 14 fields
pub storage: Arc<dyn StorageAdapter>,
pub config: Arc<ServerConfig>,
pub auth: Arc<dyn AuthVerifier>,
pub indexing: Arc<dyn IndexingStore>,
pub connector_configs: Arc<dyn ConnectorConfigStore>,
pub settings: Arc<dyn SettingsStore>,
pub tool_provider: Option<Arc<dyn ToolProvider>>,
pub widget_auth: Arc<dyn WidgetAuthProvider>,
pub backplane: Arc<dyn Backplane>,
pub chat_provider: Option<Arc<dyn LlmProvider>>,
pub gateway_key_resolver: Arc<dyn GatewayKeyResolver>,
pub shutdown: CancellationToken,
pub serve_widget: bool,
pub widget_token: Option<String>,
/* private fields */
}Expand description
Shared, cloneable application state handed to every WebSocket connection + every admin HTTP request.
Fields§
§storage: Arc<dyn StorageAdapter>The single storage seam (conversations / participants / messages / sessions / checkpoints / knowledge).
config: Arc<ServerConfig>Resolved server configuration (gateway, model, limits).
auth: Arc<dyn AuthVerifier>The configured auth verifier (jwt / smoo / none). Used by the admin API’s
require_role extractor to turn a bearer token into a Principal.
indexing: Arc<dyn IndexingStore>Indexing-run status store, surfaced by GET /admin/indexing/runs.
connector_configs: Arc<dyn ConnectorConfigStore>Connector-configuration store, CRUD’d by the admin write API
(/admin/connectors). Org-scoped; holds an auth_ref (secret name), not
the secret itself.
settings: Arc<dyn SettingsStore>Per-org agent settings store, read/written by /admin/settings.
tool_provider: Option<Arc<dyn ToolProvider>>Host tool-injection seam. When Some, the runner asks this provider
for EXTRA tools and merges them into every turn’s ToolRegistry
alongside the built-ins. Defaults to None (built-ins only); a host
installs one via with_tools to contribute its own
per-org tool catalog without forking the runner.
widget_auth: Arc<dyn WidgetAuthProvider>Embeddable-widget auth hook: resolves an agent’s origin-allowlist +
public-key policy for <smooth-agent-chat> connections. Defaults to
PermissiveWidgetAuth (no enforcement) until a host installs a real
provider via with_widget_auth.
backplane: Arc<dyn Backplane>Connection backplane: per-pod sink registry + cross-pod event delivery.
Defaults to InMemoryBackplane (single-process); a host installs a
Redis/NATS impl via with_backplane to scale out
and to let non-AI publishers push realtime events to connected clients.
chat_provider: Option<Arc<dyn LlmProvider>>Test-only injected LLM surface. When Some, every send_message turn
runs the engine against this provider (a
MockLlmClient)
instead of building a live gateway client from config — exactly the
ServerState(chat_client=mock) seam the Python reference uses to drive the
scenario-parity corpus deterministically offline. None in production
(a live client is built from the gateway config), so the /ws path is
byte-for-byte unchanged for real deployments. Installed via
with_chat_provider.
gateway_key_resolver: Arc<dyn GatewayKeyResolver>Per-org LLM gateway-key resolver: maps a turn’s org_id to the gateway
key it should bill/scope to. Defaults to EnvGatewayKeyResolver (the
single SMOOAI_GATEWAY_KEY for every org — unchanged local behavior); a
multi-tenant host installs a per-org resolver via
with_gateway_key_resolver so each
tenant’s usage is attributed to its own key. The per-turn LLM-config build
falls back to the env key whenever the resolver returns None.
shutdown: CancellationTokenGraceful-shutdown signal, shared across every per-connection clone of this
state. On SIGTERM/ctrl_c the serve loop cancels this token; each
connection’s reader loop selects on CancellationToken::cancelled so it
finishes its in-flight turn, exits, and detaches from the Backplane —
no in-flight turn dropped, no stale registry entry left behind. A fresh
token from new is never cancelled, so the /ws path and
tests are unaffected until a run/serve path wires the signal.
serve_widget: boolWhen true, the router mounts the embedded widget host page at / and
the widget bundle at /chat-widget.iife.js. Off by default (the
K8s/Lambda flavors never serve the widget); the local flavor opts in via
with_widget.
widget_token: Option<String>The auth token injected into the served widget host page (same-origin), so
the embedded widget connects to this server’s /ws?token=…. None ⇒ no
token injected (a no-auth local server).
Implementations§
Source§impl AppState
impl AppState
Sourcepub fn new(storage: Arc<dyn StorageAdapter>, config: ServerConfig) -> Self
pub fn new(storage: Arc<dyn StorageAdapter>, config: ServerConfig) -> Self
Construct shared state over a storage adapter and config.
Defaults the admin-API collaborators: a NoAuthVerifier (overridden via
with_auth) and an empty InMemoryIndexingStore
(overridden via with_indexing). The /ws path
uses none of these, so existing callers are unaffected.
Sourcepub fn with_auth(self, auth: Arc<dyn AuthVerifier>) -> Self
pub fn with_auth(self, auth: Arc<dyn AuthVerifier>) -> Self
Install the configured auth verifier (builder).
Sourcepub fn with_indexing(self, indexing: Arc<dyn IndexingStore>) -> Self
pub fn with_indexing(self, indexing: Arc<dyn IndexingStore>) -> Self
Install the indexing store (builder).
Sourcepub fn with_connector_configs(
self,
store: Arc<dyn ConnectorConfigStore>,
) -> Self
pub fn with_connector_configs( self, store: Arc<dyn ConnectorConfigStore>, ) -> Self
Install the connector-configuration store (builder).
Sourcepub fn with_settings(self, store: Arc<dyn SettingsStore>) -> Self
pub fn with_settings(self, store: Arc<dyn SettingsStore>) -> Self
Install the agent-settings store (builder).
Sourcepub fn with_tools(self, provider: Arc<dyn ToolProvider>) -> Self
pub fn with_tools(self, provider: Arc<dyn ToolProvider>) -> Self
Install a host ToolProvider (builder). The runner merges the
provider’s per-turn tools into every turn’s registry alongside the
built-ins. Without this, the registry is exactly the built-ins, so the
default/local flavor is unaffected.
Sourcepub fn with_widget(self, token: Option<String>) -> Self
pub fn with_widget(self, token: Option<String>) -> Self
Serve the embedded official widget (host page at /, bundle at
/chat-widget.iife.js), injecting token into the page so the widget
connects to this server’s /ws?token=… (builder). The local deployment
flavor opts in; other flavors never mount the widget routes.
Sourcepub fn with_widget_auth(self, provider: Arc<dyn WidgetAuthProvider>) -> Self
pub fn with_widget_auth(self, provider: Arc<dyn WidgetAuthProvider>) -> Self
Install the embeddable-widget auth provider (builder). A host backs this with its agent store so embed origins + public keys are enforced.
Sourcepub fn with_backplane(self, backplane: Arc<dyn Backplane>) -> Self
pub fn with_backplane(self, backplane: Arc<dyn Backplane>) -> Self
Install the connection backplane (builder). A host installs a Redis/NATS
impl to scale the WS service horizontally and to let other services push
realtime events to connected clients via Backplane::publish.
Sourcepub fn with_chat_provider(self, provider: Arc<dyn LlmProvider>) -> Self
pub fn with_chat_provider(self, provider: Arc<dyn LlmProvider>) -> Self
Install a test-injected LLM provider (builder). Every send_message turn
then runs the engine against this provider instead of a live gateway
client — the MockLlmClient
seam the scenario-parity corpus drives. Production never calls this, so the
live path is unchanged. See chat_provider.
Sourcepub fn with_gateway_key_resolver(
self,
resolver: Arc<dyn GatewayKeyResolver>,
) -> Self
pub fn with_gateway_key_resolver( self, resolver: Arc<dyn GatewayKeyResolver>, ) -> Self
Install a per-org gateway-key resolver (builder). A multi-tenant host
installs a resolver backed by its per-org key store (e.g. one LiteLLM
virtual key per tenant) so each org’s turns are billed/scoped to its own
key. The per-turn LLM-config build falls back to the env key whenever the
resolver returns None, so a resolver covering only some orgs is safe.
Leaving this unset keeps the default EnvGatewayKeyResolver (single env
key for every org — unchanged local behavior).
Sourcepub fn with_shutdown(self, shutdown: CancellationToken) -> Self
pub fn with_shutdown(self, shutdown: CancellationToken) -> Self
Install the graceful-shutdown signal (builder). The serve loop owns a
clone of this token and cancels it on SIGTERM/ctrl_c; every per-connection
clone observes the cancellation and drains. Defaulted to a fresh token in
new, so this is only needed when a caller wants to drive
shutdown from its own token.
Sourcepub fn insert_session(&self, session: Session)
pub fn insert_session(&self, session: Session)
Register a freshly created session.
Sourcepub fn get_session(&self, session_id: &str) -> Option<Session>
pub fn get_session(&self, session_id: &str) -> Option<Session>
Look up a session by id.
Sourcepub fn record_document_set(
&self,
org_id: impl Into<String>,
set: impl Into<String>,
)
pub fn record_document_set( &self, org_id: impl Into<String>, set: impl Into<String>, )
Record that a document was added to a named document set within an org
(increments its count). Used by seeding + the ingest path so
GET /admin/document-sets can report set names + counts despite the
in-memory backend dropping document metadata. Org-scoped so org A’s sets
are never reported to an org-B caller.
Sourcepub fn document_sets(&self, org_id: &str) -> Vec<(String, usize)>
pub fn document_sets(&self, org_id: &str) -> Vec<(String, usize)>
Snapshot one org’s document-set registry as (name, count) pairs,
sorted by name for a stable response. Never returns another org’s sets.
Sourcepub fn record_connector(
&self,
org_id: impl Into<String>,
name: impl Into<String>,
)
pub fn record_connector( &self, org_id: impl Into<String>, name: impl Into<String>, )
Record a connector (within an org) whose indexing runs should be listed
(idempotent). Org-scoped so a same-named connector in two orgs records
separately and GET /admin/indexing/runs only lists the caller’s org’s.
Sourcepub fn connectors(&self, org_id: &str) -> Vec<String>
pub fn connectors(&self, org_id: &str) -> Vec<String>
Snapshot one org’s recorded connector names (sorted, stable). Never returns another org’s connectors.
Sourcepub fn register_confirmation(
&self,
session_id: impl Into<String>,
responder: UnboundedSender<HumanResponse>,
)
pub fn register_confirmation( &self, session_id: impl Into<String>, responder: UnboundedSender<HumanResponse>, )
Register a parked turn’s HumanResponse sender for session_id, so a
later confirm_tool_action can resume it. Any prior pending sender for
the same session is replaced (one outstanding confirmation per session).
Called by the runner’s confirmation bridge when a write tool emits a
HumanRequest::Confirm.
Sourcepub fn take_confirmation(
&self,
session_id: &str,
) -> Option<UnboundedSender<HumanResponse>>
pub fn take_confirmation( &self, session_id: &str, ) -> Option<UnboundedSender<HumanResponse>>
Take (remove + return) the pending HumanResponse sender for
session_id, if a turn is parked on a confirmation. Returns None when
no turn awaits confirmation for that session (the common case). Taking it
out — rather than cloning — guarantees a single confirmation resolves a
single parked tool call, and a duplicate confirm_tool_action is a no-op.
Sourcepub fn clear_confirmation(&self, session_id: &str)
pub fn clear_confirmation(&self, session_id: &str)
Drop any pending confirmation registered for session_id without
resolving it. Called when a parked turn ends (the bridge task finishes)
so a stale sender can’t linger and mis-route a later confirmation.
Trait Implementations§
Source§impl<const MIN: u8> FromRequestParts<AppState> for RequireRole<MIN>
impl<const MIN: u8> FromRequestParts<AppState> for RequireRole<MIN>
Auto Trait Implementations§
impl !RefUnwindSafe for AppState
impl !UnwindSafe for AppState
impl Freeze for AppState
impl Send for AppState
impl Sync for AppState
impl Unpin for AppState
impl UnsafeUnpin for AppState
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
Source§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request