Skip to main content

codewhale_config/route/
descriptor.rs

1//! Provider descriptors over the existing built-in provider registry (#3084).
2//!
3//! A [`ProviderDescriptor`] is a thin, route-facing view over the static
4//! [`provider::Provider`] trait objects already in [`crate::provider`]. It
5//! surfaces only the transport facts route resolution needs (id, base URL,
6//! default wire model, env vars, protocol) without duplicating the registry.
7//!
8//! Because a descriptor holds a `&'static dyn Provider`, it is intentionally
9//! NOT `Serialize`/`PartialEq`-derivable. Never embed a [`ProviderDescriptor`]
10//! inside a `Serialize` struct; serialize the resolved facts instead.
11
12use crate::ProviderKind;
13use crate::provider::{self, Provider, WirePolicy};
14
15use super::RequestProtocol;
16use super::ids::{ProviderId, WireModelId};
17
18/// Route-facing view of a built-in provider's transport facts.
19///
20/// Holds a trait object, so it is deliberately not serializable/comparable.
21#[derive(Clone, Copy)]
22pub struct ProviderDescriptor {
23    /// The provider kind this descriptor describes.
24    pub kind: ProviderKind,
25    /// Backing static provider metadata entry.
26    pub inner: &'static dyn Provider,
27}
28
29impl ProviderDescriptor {
30    /// Build a descriptor for a known provider kind.
31    #[must_use]
32    pub fn for_kind(kind: ProviderKind) -> Self {
33        Self {
34            kind,
35            inner: provider::provider_for_kind(kind),
36        }
37    }
38
39    /// Canonical provider id.
40    #[must_use]
41    pub fn id(&self) -> ProviderId {
42        ProviderId::from(self.inner.id())
43    }
44
45    /// Default base URL when no override is present.
46    #[must_use]
47    pub fn default_base_url(&self) -> &'static str {
48        self.inner.default_base_url()
49    }
50
51    /// Default wire model id when no model is selected.
52    #[must_use]
53    pub fn default_wire_model(&self) -> WireModelId {
54        WireModelId::from(self.inner.default_model())
55    }
56
57    /// Environment variable candidates for this provider's API key.
58    #[must_use]
59    pub fn env_vars(&self) -> &'static [&'static str] {
60        self.inner.env_vars()
61    }
62
63    /// Policy used to select this provider's wire protocol.
64    #[must_use]
65    pub fn wire_policy(&self) -> WirePolicy {
66        self.inner.wire_policy()
67    }
68
69    /// Resolve the concrete protocol for an offering endpoint key.
70    #[must_use]
71    pub fn protocol_for_endpoint(&self, endpoint_key: &str) -> Option<RequestProtocol> {
72        self.wire_policy().resolve(endpoint_key)
73    }
74}
75
76impl std::fmt::Debug for ProviderDescriptor {
77    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78        f.debug_struct("ProviderDescriptor")
79            .field("kind", &self.kind)
80            .field("id", &self.inner.id())
81            .field("wire_policy", &self.inner.wire_policy())
82            .finish()
83    }
84}
85
86/// A concrete endpoint's transport facts.
87///
88/// Unlike [`ProviderDescriptor`], this owns plain data and is safe to embed in
89/// serializable route output (see [`super::candidate::ResolvedEndpoint`]).
90#[derive(Debug, Clone)]
91pub struct EndpointDescriptor {
92    /// Stable endpoint key (e.g. `"chat"`, `"responses"`).
93    pub endpoint_key: String,
94    /// Wire protocol spoken at this endpoint.
95    pub protocol: RequestProtocol,
96    /// Default base URL for this endpoint.
97    pub default_base_url: String,
98    /// Whether streaming is supported.
99    pub streaming: bool,
100}