1#![cfg_attr(docsrs, feature(doc_cfg))]
2
3pub mod adapter;
10pub mod adapters;
11#[allow(
12 dead_code,
13 reason = "constructors are consumed by the next server integration checkpoint"
14)]
15pub mod codec;
16#[allow(
17 dead_code,
18 reason = "codec probes are consumed by the next server integration checkpoint"
19)]
20pub mod codecs;
21pub(crate) use codecs::anthropic;
22#[cfg(feature = "proxy-daemon")]
23pub mod daemon;
24pub mod error;
25pub mod inspection;
26pub mod principal;
27pub mod server;
28#[allow(
29 dead_code,
30 reason = "finite registry is integrated by the serialized P3/P4 checkpoints"
31)]
32pub(crate) mod session_registry;
33
34use std::net::SocketAddr;
35use std::sync::Arc;
36use std::time::Duration;
37
38use adapters::AnthropicAdapter;
39use gaze::{DictionaryBundle, LocaleChain, LocaleTag, Pipeline};
40
41pub use adapter::{
42 AdapterContract, CoveragePolicy, FormatPolicy, HeaderPolicy, PiiSurface, ProtocolContract,
43 ProviderAdapter, RedirectPolicy, RoutePolicy, SessionPolicy, SessionRegistryConfig,
44 SessionRegistryConfigError, SseEvent, SurfaceSyntax,
45};
46pub use codec::{
47 BodyCodec, CodecError, CodecErrorCode, CodecLimits, CodecPhase, OpaqueCarrierLocation,
48 OpaqueCarrierScheme, OutputProvenance, ProvedRequestBody, ProvedResponseBody,
49 RequestPseudonymizer, RequestTransformContext, ResponseResidualValidator,
50 ResponseTransformContext, WireFormat,
51};
52pub use codecs::anthropic::{
53 AnthropicMessagesCodec, ANTHROPIC_PROXY_ERROR_FRAME, ANTHROPIC_PROXY_PING_FRAME,
54};
55pub use error::{
56 DirectProxyError, HeaderRejectionReason, ProxyError, ProxyErrorCode, ProxyErrorPhase,
57};
58pub use inspection::{install_proxy_inspection_v1, ProxyInspectionProducerV1};
59pub use principal::{
60 AuthenticatedPrincipal, ListenerScope, LocalAuthCredential, PeerScope, PrincipalContext,
61 PrincipalResolveError, PrincipalResolver, ProcessLocalLoopbackResolver,
62 TlsClientCertificateHash, MAX_AUTHENTICATED_PRINCIPAL_BYTES, MAX_LOCAL_AUTH_CREDENTIAL_BYTES,
63};
64pub use server::{
65 classify_upstream_status, parse_request_stream_format, serve, serve_with_listener,
66 validate_declared_body, validate_direct_response_head, DirectResponseHead, HealthSnapshot,
67 DIRECT_PROXY_ERROR_FRAME, DIRECT_PROXY_PING_FRAME,
68};
69
70#[derive(Clone)]
71#[non_exhaustive]
72pub struct ProxyConfig {
73 pub bind: SocketAddr,
74 pub adapters: Vec<Arc<dyn ProviderAdapter>>,
75 pub session_ttl: Duration,
76 pub body_limit_bytes: u64,
77 pub(crate) locale_chain: LocaleChain,
78 pub(crate) dictionaries: DictionaryBundle,
79 pub(crate) direct_anthropic: Option<Arc<AnthropicAdapter>>,
80 pub(crate) inspection: Option<Arc<ProxyInspectionProducerV1>>,
81}
82
83impl ProxyConfig {
84 pub fn new(bind: SocketAddr, adapters: Vec<Arc<dyn ProviderAdapter>>) -> Self {
85 Self {
86 bind,
87 adapters,
88 session_ttl: Duration::from_secs(30 * 60),
89 body_limit_bytes: 2 * 1024 * 1024,
90 locale_chain: default_locale_chain(),
91 dictionaries: DictionaryBundle::default(),
92 direct_anthropic: None,
93 inspection: None,
94 }
95 }
96
97 #[must_use]
106 pub fn anthropic_direct(bind: SocketAddr, adapter: AnthropicAdapter) -> Self {
107 let adapter = Arc::new(adapter);
108 let dynamic: Arc<dyn ProviderAdapter> = adapter.clone();
109 Self {
110 bind,
111 adapters: vec![dynamic],
112 session_ttl: Duration::from_secs(30 * 60),
113 body_limit_bytes: 2 * 1024 * 1024,
114 locale_chain: default_locale_chain(),
115 dictionaries: DictionaryBundle::default(),
116 direct_anthropic: Some(adapter),
117 inspection: None,
118 }
119 }
120
121 #[must_use]
148 pub fn with_locale_chain(mut self, locale_chain: LocaleChain) -> Self {
149 self.locale_chain = locale_chain;
150 self
151 }
152
153 #[must_use]
155 pub fn locale_chain(&self) -> &[LocaleTag] {
156 self.locale_chain.as_slice()
157 }
158
159 #[must_use]
166 pub fn with_dictionaries(mut self, dictionaries: DictionaryBundle) -> Self {
167 self.dictionaries = dictionaries;
168 self
169 }
170
171 #[must_use]
173 pub fn dictionaries(&self) -> &DictionaryBundle {
174 &self.dictionaries
175 }
176
177 #[must_use]
183 pub fn with_inspection(mut self, inspection: ProxyInspectionProducerV1) -> Self {
184 self.inspection = Some(Arc::new(inspection));
185 self
186 }
187}
188
189fn default_locale_chain() -> LocaleChain {
196 LocaleChain::from_tags(vec![LocaleTag::Global])
197}
198
199pub async fn serve_foreground(
200 config: ProxyConfig,
201 pipeline: Arc<Pipeline>,
202) -> Result<(), ProxyError> {
203 serve(config, pipeline).await
204}