pub struct AiConfig {
pub providers: Vec<AiProvider>,
pub models: BTreeMap<String, AiModel>,
pub pricing: BTreeMap<String, AiPricing>,
pub governance: Option<AiGovernance>,
pub logging: Option<AiLogging>,
pub guardrails: Option<AiGuardrails>,
pub semantic_cache: Option<SemanticCacheConfig>,
pub routing_policies: BTreeMap<String, AiRoutingPolicy>,
pub experiments: Option<AiExperiments>,
pub mcp: Option<AiMcpConfig>,
pub a2a: Option<A2aConfig>,
pub unknown_model_policy: Option<UnknownModelPolicy>,
}Expand description
The ai: top-level block (DW-075). Absent: no AI surface. Present:
validation requires at least one provider and at least one model —
an ai: block that can never serve a model is an authoring error,
not a silently inert config.
Fields§
§providers: Vec<AiProvider>The provider pool. Each entry names an upstream that carries the
transport and the adapter kind that carries the wire translation.
models: BTreeMap<String, AiModel>Model alias table: the model value a client puts in its request
body maps to the provider that serves it and the provider’s own
model identifier. The alias is echoed back to the client; the
provider_model never leaves the gateway.
pricing: BTreeMap<String, AiPricing>Per-model pricing table (DW-079): the key is the PROVIDER MODEL
identifier (the actual model the provider charges for, e.g.
gpt-4o-mini), NOT the client-facing alias. Costs are integer
micro-USD per 1 000 tokens (1 000 000 micro-USD = $1.00 — no
floating-point money). Spend = usage x price, aggregated per
key/team/model (DW-079). Absent (the default): no pricing, so
cost attribution records zero cost (the budget cost window and
the spend store stay live but inert until prices are declared).
governance: Option<AiGovernance>Model governance (DW-084): per-team (policy) model allowlists and the shadow-audit switch. Absent (the default): no governance — every consumer may call every configured alias, and no governance audit events are recorded.
logging: Option<AiLogging>Prompt/response logging (DW-081): opt-in capture of the
canonical prompt and response with PII redaction, sampling,
and retention. Absent (the default): no capture — privacy-first
(no prompt or response text is ever stored). When present and
enabled: true, a redaction pass scrubs PII/secrets before
storage, sample_rate controls volume, and retention_secs
ages records out. Per-consumer ai_logging overrides respect
tenant preference (see crate::config::Consumer::ai_logging).
guardrails: Option<AiGuardrails>Guardrails (DW-082): prompt-injection heuristics, PII
detection, banned-content filters, and output schema
enforcement as a middleware chain on the AI proxy action.
Absent (the default): no guardrails — every prompt and
response passes through uninspected. When present, each rule
inspects the prompt (before the provider call) and/or the
response (after), and blocks, redacts, or logs per its
action. Policy-scoped rules apply only to consumers
attaching a listed policy; an empty policies list applies
to all. Schema enforcement uses the unconditional jsonschema
dependency and works in every build.
semantic_cache: Option<SemanticCacheConfig>Semantic cache (DW-083 ai.semantic_cache): an
embedding-similarity cache for AI prompts. A paraphrased
prompt within the cosine-similarity threshold returns the
cached response with no provider call and no token spend.
Uses an external embedding service (OpenAI-compatible
/v1/embeddings API) and a pure-Rust HNSW ANN index
(hnsw_rs). Feature-gated behind the semantic_cache cargo
feature; without it the config is accepted but the cache is a
no-op. Absent (the default): no semantic cache.
routing_policies: BTreeMap<String, AiRoutingPolicy>Routing policies (DW-085 ai.routing_policies): named
within-request escalation or latency-vs-cost selection plans,
keyed by name. A model alias declares routing_policy: <name>
to be served by one; the policy is evaluated per request (a
FallbackChain policy may call an external classifier service;
a LatencyCost policy picks deterministically at compile time).
Absent (the default): no routing policies.
experiments: Option<AiExperiments>Prompt experimentation (DW-086 ai.experiments): prompt
versioning, A/B model comparison, regression evals, and
feedback ingestion. Absent (the default): no experiments.
mcp: Option<AiMcpConfig>MCP gateway (DW-087 ai.mcp): turns dwara into an MCP
(Model Context Protocol) server/router. Configured tools are
exposed over JSON-RPC 2.0 on a reserved HTTP path (default
/mcp); the gateway proxies tool calls to upstream HTTP
endpoints with authN/authZ, manages agent sessions in the
state store, and correlates tool calls in analytics. Absent
(the default): no MCP surface (the /mcp path returns 404).
a2a: Option<A2aConfig>A2A (agent-to-agent) protocol support (DW-114 ai.a2a):
configures remote A2A agents that the gateway can route chat
requests to. Each agent names an upstream (the transport) and
an Agent Card (discovery doc, file path or inline JSON). The
adapter translates a canonical chat request into an A2A
task-submit body; the task lifecycle is STUBBED pending spec
freeze. Compiled into every build (no cargo feature). Absent
(the default): no A2A surface.
unknown_model_policy: Option<UnknownModelPolicy>Unknown-model pricing policy (DW-AI-03
ai.unknown_model_policy): what to do when a provider model
has no entry in ai.pricing. Absent (the default): allow
(cost 0, fail-open — the original behavior). fail_closed
rejects the response with 403 ai_unknown_model_pricing;
alert proceeds with cost 0 but logs a WARN and increments
the dwara_ai_unknown_pricing_total{model} metric.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for AiConfig
impl<'de> Deserialize<'de> for AiConfig
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl JsonSchema for AiConfig
impl JsonSchema for AiConfig
Source§fn schema_id() -> Cow<'static, str>
fn schema_id() -> Cow<'static, str>
Source§fn json_schema(generator: &mut SchemaGenerator) -> Schema
fn json_schema(generator: &mut SchemaGenerator) -> Schema
Source§fn inline_schema() -> bool
fn inline_schema() -> bool
$ref keyword. Read moreimpl StructuralPartialEq for AiConfig
Auto Trait Implementations§
impl Freeze for AiConfig
impl RefUnwindSafe for AiConfig
impl Send for AiConfig
impl Sync for AiConfig
impl Unpin for AiConfig
impl UnwindSafe for AiConfig
Blanket Implementations§
§impl<T> AnyExt for T
impl<T> AnyExt for T
§fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
T behind reference§fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
T behind mutable reference§fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
T behind Rc pointer§fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
T behind Arc pointer§fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>where
T: Any,
fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>where
T: Any,
T behind Box pointer§fn downcast_move<T>(this: Self) -> Option<T>
fn downcast_move<T>(this: Self) -> Option<T>
Self to T,
useful only in generic context as a workaround for specializationSource§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
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
impl<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
fn coerce_rc_to(self: Rc<X>) -> Rc<T>
fn coerce_box_to(self: Box<X>) -> Box<T>
fn coerce_ref_to(&self) -> &T
fn coerce_mut_to(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§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 more