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,
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, validate_declared_body,
66 validate_direct_response_head, DirectResponseHead, HealthSnapshot, DIRECT_PROXY_ERROR_FRAME,
67 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]
103 pub fn anthropic_direct(bind: SocketAddr, adapter: AnthropicAdapter) -> Self {
104 let adapter = Arc::new(adapter);
105 let dynamic: Arc<dyn ProviderAdapter> = adapter.clone();
106 Self {
107 bind,
108 adapters: vec![dynamic],
109 session_ttl: Duration::from_secs(30 * 60),
110 body_limit_bytes: 2 * 1024 * 1024,
111 locale_chain: default_locale_chain(),
112 dictionaries: DictionaryBundle::default(),
113 direct_anthropic: Some(adapter),
114 inspection: None,
115 }
116 }
117
118 #[must_use]
145 pub fn with_locale_chain(mut self, locale_chain: LocaleChain) -> Self {
146 self.locale_chain = locale_chain;
147 self
148 }
149
150 #[must_use]
152 pub fn locale_chain(&self) -> &[LocaleTag] {
153 self.locale_chain.as_slice()
154 }
155
156 #[must_use]
163 pub fn with_dictionaries(mut self, dictionaries: DictionaryBundle) -> Self {
164 self.dictionaries = dictionaries;
165 self
166 }
167
168 #[must_use]
170 pub fn dictionaries(&self) -> &DictionaryBundle {
171 &self.dictionaries
172 }
173
174 #[must_use]
180 pub fn with_inspection(mut self, inspection: ProxyInspectionProducerV1) -> Self {
181 self.inspection = Some(Arc::new(inspection));
182 self
183 }
184}
185
186fn default_locale_chain() -> LocaleChain {
193 LocaleChain::from_tags(vec![LocaleTag::Global])
194}
195
196pub async fn serve_foreground(
197 config: ProxyConfig,
198 pipeline: Arc<Pipeline>,
199) -> Result<(), ProxyError> {
200 serve(config, pipeline).await
201}