Skip to main content

soma_provider_adapters/
manifest_file.rs

1//! Generic manifest -> concrete-provider dispatch, factored out of Soma's
2//! drop-in provider directory loader
3//! (`FileProviderSource::provider_for_catalog`, now in
4//! `crates/soma/application/src/providers/filesystem.rs`). Given an
5//! already-parsed, already-validated `ProviderManifest` and the file it came
6//! from, builds the matching adapter for its declared `ProviderKind`.
7//!
8//! The directory scan, fingerprinting, and Soma-specific manifest policy
9//! (reserved CLI command names, `SOMA_`/`LAB_` env-prefix denial) stay in
10//! `crates/soma/application` — see the PR10 deviation notes for why that
11//! orchestration did not move here.
12
13use std::path::PathBuf;
14
15use soma_provider_core::{Provider, ProviderCatalog, ProviderKind};
16
17/// Builds the concrete adapter for `catalog`'s declared kind.
18///
19/// `env_prefix` is the product's env-namespace (e.g. `"SOMA"`), forwarded to
20/// the ai-sdk and python adapters' `EnvRequirement` resolution.
21///
22/// Returns `None` when the crate was not built with the feature that owns
23/// `catalog`'s kind. Every `ProviderKind` has a matching adapter here,
24/// feature-gated per plan section 3.9 ("Do not over-split") so a consumer
25/// only pays for the runtimes it actually drop-in-loads.
26#[allow(unused_variables)]
27pub fn build_provider(
28    path: PathBuf,
29    catalog: ProviderCatalog,
30    env_prefix: &str,
31) -> Option<std::sync::Arc<dyn Provider>> {
32    match catalog.provider.kind {
33        #[cfg(feature = "openapi")]
34        ProviderKind::Openapi => Some(crate::openapi::OpenApiProvider::arc(catalog)),
35        #[cfg(not(feature = "openapi"))]
36        ProviderKind::Openapi => None,
37
38        #[cfg(feature = "gateway")]
39        ProviderKind::Mcp => Some(crate::gateway::UpstreamMcpProvider::arc(catalog)),
40        #[cfg(not(feature = "gateway"))]
41        ProviderKind::Mcp => None,
42
43        #[cfg(feature = "ai-sdk")]
44        ProviderKind::AiSdk => Some(crate::ai_sdk::AiSdkProvider::arc(path, catalog, env_prefix)),
45        #[cfg(not(feature = "ai-sdk"))]
46        ProviderKind::AiSdk => None,
47
48        #[cfg(feature = "wasm")]
49        ProviderKind::Wasm => Some(crate::wasm::WasmProvider::arc(path, catalog)),
50        #[cfg(not(feature = "wasm"))]
51        ProviderKind::Wasm => None,
52
53        #[cfg(feature = "python")]
54        ProviderKind::Python | ProviderKind::Langchain | ProviderKind::Llamaindex => Some(
55            crate::python::PythonProvider::arc(path, catalog, env_prefix),
56        ),
57        #[cfg(not(feature = "python"))]
58        ProviderKind::Python | ProviderKind::Langchain | ProviderKind::Llamaindex => None,
59
60        #[cfg(feature = "static-echo")]
61        ProviderKind::StaticRust => {
62            Some(crate::static_rust::StaticEchoProvider::arc(path, catalog))
63        }
64        #[cfg(not(feature = "static-echo"))]
65        ProviderKind::StaticRust => None,
66    }
67}
68
69#[cfg(test)]
70#[path = "manifest_file_tests.rs"]
71mod tests;