#![cfg_attr(docsrs, feature(doc_cfg))]
pub mod adapter;
pub mod adapters;
#[allow(
dead_code,
reason = "constructors are consumed by the next server integration checkpoint"
)]
pub mod codec;
#[allow(
dead_code,
reason = "codec probes are consumed by the next server integration checkpoint"
)]
pub mod codecs;
pub(crate) use codecs::anthropic;
#[cfg(feature = "proxy-daemon")]
pub mod daemon;
pub mod error;
pub mod inspection;
pub mod principal;
pub mod server;
#[allow(
dead_code,
reason = "finite registry is integrated by the serialized P3/P4 checkpoints"
)]
pub(crate) mod session_registry;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;
use adapters::AnthropicAdapter;
use gaze::{DictionaryBundle, LocaleChain, LocaleTag, Pipeline};
pub use adapter::{
AdapterContract, CoveragePolicy, FormatPolicy, HeaderPolicy, PiiSurface, ProtocolContract,
ProviderAdapter, RedirectPolicy, RoutePolicy, SessionPolicy, SessionRegistryConfig,
SessionRegistryConfigError, SseEvent, SurfaceSyntax,
};
pub use codec::{
BodyCodec, CodecError, CodecErrorCode, CodecLimits, CodecPhase, OpaqueCarrierLocation,
OpaqueCarrierScheme, OutputProvenance, ProvedRequestBody, ProvedResponseBody,
RequestPseudonymizer, RequestTransformContext, ResponseResidualValidator,
ResponseTransformContext, WireFormat,
};
pub use codecs::anthropic::{
AnthropicMessagesCodec, ANTHROPIC_PROXY_ERROR_FRAME, ANTHROPIC_PROXY_PING_FRAME,
};
pub use error::{
DirectProxyError, HeaderRejectionReason, ProxyError, ProxyErrorCode, ProxyErrorPhase,
};
pub use inspection::{install_proxy_inspection_v1, ProxyInspectionProducerV1};
pub use principal::{
AuthenticatedPrincipal, ListenerScope, LocalAuthCredential, PeerScope, PrincipalContext,
PrincipalResolveError, PrincipalResolver, ProcessLocalLoopbackResolver,
TlsClientCertificateHash, MAX_AUTHENTICATED_PRINCIPAL_BYTES, MAX_LOCAL_AUTH_CREDENTIAL_BYTES,
};
pub use server::{
classify_upstream_status, parse_request_stream_format, serve, serve_with_listener,
validate_declared_body, validate_direct_response_head, DirectResponseHead, HealthSnapshot,
DIRECT_PROXY_ERROR_FRAME, DIRECT_PROXY_PING_FRAME,
};
#[derive(Clone)]
#[non_exhaustive]
pub struct ProxyConfig {
pub bind: SocketAddr,
pub adapters: Vec<Arc<dyn ProviderAdapter>>,
pub session_ttl: Duration,
pub body_limit_bytes: u64,
pub(crate) locale_chain: LocaleChain,
pub(crate) dictionaries: DictionaryBundle,
pub(crate) direct_anthropic: Option<Arc<AnthropicAdapter>>,
pub(crate) inspection: Option<Arc<ProxyInspectionProducerV1>>,
}
impl ProxyConfig {
pub fn new(bind: SocketAddr, adapters: Vec<Arc<dyn ProviderAdapter>>) -> Self {
Self {
bind,
adapters,
session_ttl: Duration::from_secs(30 * 60),
body_limit_bytes: 2 * 1024 * 1024,
locale_chain: default_locale_chain(),
dictionaries: DictionaryBundle::default(),
direct_anthropic: None,
inspection: None,
}
}
#[must_use]
pub fn anthropic_direct(bind: SocketAddr, adapter: AnthropicAdapter) -> Self {
let adapter = Arc::new(adapter);
let dynamic: Arc<dyn ProviderAdapter> = adapter.clone();
Self {
bind,
adapters: vec![dynamic],
session_ttl: Duration::from_secs(30 * 60),
body_limit_bytes: 2 * 1024 * 1024,
locale_chain: default_locale_chain(),
dictionaries: DictionaryBundle::default(),
direct_anthropic: Some(adapter),
inspection: None,
}
}
#[must_use]
pub fn with_locale_chain(mut self, locale_chain: LocaleChain) -> Self {
self.locale_chain = locale_chain;
self
}
#[must_use]
pub fn locale_chain(&self) -> &[LocaleTag] {
self.locale_chain.as_slice()
}
#[must_use]
pub fn with_dictionaries(mut self, dictionaries: DictionaryBundle) -> Self {
self.dictionaries = dictionaries;
self
}
#[must_use]
pub fn dictionaries(&self) -> &DictionaryBundle {
&self.dictionaries
}
#[must_use]
pub fn with_inspection(mut self, inspection: ProxyInspectionProducerV1) -> Self {
self.inspection = Some(Arc::new(inspection));
self
}
}
fn default_locale_chain() -> LocaleChain {
LocaleChain::from_tags(vec![LocaleTag::Global])
}
pub async fn serve_foreground(
config: ProxyConfig,
pipeline: Arc<Pipeline>,
) -> Result<(), ProxyError> {
serve(config, pipeline).await
}