#![cfg_attr(
not(any(
feature = "deploy",
feature = "admin",
feature = "agents",
feature = "evaluate",
feature = "context",
feature = "workspace",
feature = "gateway",
feature = "model",
feature = "trace",
feature = "runtime-identity"
)),
allow(dead_code, unused_variables)
)]
use std::time::Duration;
#[cfg(feature = "admin")]
mod admin;
#[cfg(feature = "agents")]
mod agent;
#[cfg(feature = "context")]
mod compression;
#[cfg(feature = "context")]
mod context;
#[cfg(feature = "deploy")]
mod deploy;
#[cfg(feature = "workspace")]
mod environment;
#[cfg(feature = "evaluate")]
mod evaluate;
#[cfg(feature = "gateway")]
mod gateway;
#[cfg(feature = "model")]
mod model;
mod operation;
#[cfg(feature = "runtime-identity")]
mod runtime_identity;
#[cfg(feature = "trace")]
mod trace;
mod transport;
mod transport_body;
mod transport_support;
#[cfg(feature = "workspace")]
mod workspace;
#[cfg(feature = "admin")]
pub use admin::AdminClient;
#[cfg(feature = "agents")]
pub use agent::AgentClient;
#[cfg(feature = "context")]
pub use agent_context_contract as context_contract;
#[cfg(feature = "agents")]
pub use agent_registry_contract as agent_contract;
#[cfg(feature = "runtime-identity")]
pub use agent_runtime_identity_contract as runtime_identity_contract;
#[cfg(feature = "trace")]
pub use agent_trace_contract as trace_contract;
#[cfg(feature = "workspace")]
pub use agent_workspace_contract as workspace_contract;
#[cfg(feature = "context")]
#[deprecated(note = "prompt compression belongs to runtime/context assembly")]
pub use compression::{ContextCompressionConfig, compress_context};
#[cfg(feature = "context")]
pub use context::ContextClient;
#[cfg(feature = "deploy")]
pub use deploy::DeployClient;
#[cfg(feature = "workspace")]
pub use environment::EnvironmentClient;
#[cfg(feature = "evaluate")]
pub use evaluate::EvaluateClient;
#[cfg(feature = "gateway")]
pub use gateway::{DelegationLeaseCredentials, GatewayClient, GatewayExchangeCredentials};
#[cfg(feature = "gateway")]
pub use infra_api_gateway_contract as gateway_contract;
#[cfg(feature = "model")]
pub use model::{ModelClient, ModelStream};
pub use operation::{
CancellationToken, OperationHandle, OperationObservation, OperationPoller, OperationProgress,
WaitOptions,
};
#[cfg(feature = "runtime-identity")]
pub use runtime_identity::RuntimeIdentityClient;
#[cfg(feature = "trace")]
pub use trace::TraceClient;
pub use transport::{
BearerCredential, CallOptions, ClientOptions, CredentialError, CredentialsProvider,
InfraClientError, NoopTelemetry, RetryPolicy, StaticCredentials, TelemetryEvent,
TelemetryObserver, TelemetryPhase,
};
#[cfg(feature = "workspace")]
pub use workspace::WorkspaceClient;
use reqwest::Client;
use transport::ServiceEndpoint;
#[derive(Clone, Debug)]
pub struct InfraClient {
#[cfg(feature = "admin")]
admin: AdminClient,
#[cfg(feature = "agents")]
agents: AgentClient,
#[cfg(feature = "deploy")]
deploy: DeployClient,
#[cfg(feature = "evaluate")]
evaluate: EvaluateClient,
#[cfg(feature = "gateway")]
gateway: GatewayClient,
#[cfg(feature = "model")]
model: ModelClient,
#[cfg(feature = "context")]
context: ContextClient,
#[cfg(feature = "trace")]
trace: TraceClient,
#[cfg(feature = "workspace")]
workspace: WorkspaceClient,
#[cfg(feature = "workspace")]
environment: EnvironmentClient,
#[cfg(feature = "runtime-identity")]
runtime_identity: RuntimeIdentityClient,
}
impl InfraClient {
pub fn builder(gateway_base_url: impl Into<String>) -> InfraClientBuilder {
InfraClientBuilder::new(gateway_base_url)
}
pub fn new(gateway_base_url: impl Into<String>) -> Result<Self, InfraClientError> {
Self::builder(gateway_base_url).build()
}
pub fn local() -> Result<Self, InfraClientError> {
Self::new("http://127.0.0.1:5200")
}
#[cfg(feature = "admin")]
pub fn admin(&self) -> &AdminClient {
&self.admin
}
#[cfg(feature = "agents")]
pub fn agents(&self) -> &AgentClient {
&self.agents
}
#[cfg(feature = "deploy")]
pub fn deploy(&self) -> &DeployClient {
&self.deploy
}
#[cfg(feature = "evaluate")]
pub fn evaluate(&self) -> &EvaluateClient {
&self.evaluate
}
#[cfg(feature = "context")]
pub fn context(&self) -> &ContextClient {
&self.context
}
#[cfg(feature = "workspace")]
pub fn workspace(&self) -> &WorkspaceClient {
&self.workspace
}
#[cfg(feature = "workspace")]
pub fn environment(&self) -> &EnvironmentClient {
&self.environment
}
#[cfg(feature = "gateway")]
pub fn gateway(&self) -> &GatewayClient {
&self.gateway
}
#[cfg(feature = "model")]
pub fn model(&self) -> &ModelClient {
&self.model
}
#[cfg(feature = "trace")]
pub fn trace(&self) -> &TraceClient {
&self.trace
}
#[cfg(feature = "runtime-identity")]
pub fn runtime_identity(&self) -> &RuntimeIdentityClient {
&self.runtime_identity
}
}
fn build_http_client(options: &ClientOptions) -> Result<Client, InfraClientError> {
if options.connect_timeout.is_zero() || options.connect_timeout > Duration::from_secs(60) {
return Err(InfraClientError::InvalidOptions {
message: "connect_timeout must be within 1ns..=60s".into(),
});
}
if options.request_timeout.is_zero() || options.request_timeout > Duration::from_secs(600) {
return Err(InfraClientError::InvalidOptions {
message: "request_timeout must be within 1ns..=600s".into(),
});
}
if !(1..=1024).contains(&options.max_idle_connections_per_host) {
return Err(InfraClientError::InvalidOptions {
message: "max_idle_connections_per_host must be within 1..=1024".into(),
});
}
if options.pool_idle_timeout.is_zero() || options.pool_idle_timeout > Duration::from_secs(600) {
return Err(InfraClientError::InvalidOptions {
message: "pool_idle_timeout must be within 1ns..=600s".into(),
});
}
if !(1..=1024 * 1024 * 1024).contains(&options.max_response_bytes) {
return Err(InfraClientError::InvalidOptions {
message: "max_response_bytes must be within 1 byte..=1 GiB".into(),
});
}
if !(1..=8).contains(&options.retry.max_attempts)
|| options.retry.base_delay > options.retry.max_delay
|| options.retry.max_delay > Duration::from_secs(30)
{
return Err(InfraClientError::InvalidOptions {
message: "retry requires 1..=8 attempts and 0 <= base_delay <= max_delay <= 30s".into(),
});
}
if options.user_agent.is_empty()
|| options.user_agent.len() > 256
|| reqwest::header::HeaderValue::from_str(&options.user_agent).is_err()
{
return Err(InfraClientError::InvalidOptions {
message: "user_agent must be a valid 1..=256 byte HTTP header value".into(),
});
}
Client::builder()
.connect_timeout(options.connect_timeout)
.timeout(options.request_timeout)
.pool_idle_timeout(options.pool_idle_timeout)
.pool_max_idle_per_host(options.max_idle_connections_per_host)
.redirect(reqwest::redirect::Policy::none())
.build()
.map_err(InfraClientError::ClientBuild)
}
#[derive(Debug, Clone)]
pub struct InfraClientBuilder {
gateway: ServiceEndpoint,
credentials: Option<std::sync::Arc<dyn CredentialsProvider>>,
options: ClientOptions,
}
impl InfraClientBuilder {
pub fn new(gateway_base_url: impl Into<String>) -> Self {
Self {
gateway: ServiceEndpoint::new(gateway_base_url),
credentials: None,
options: ClientOptions::default(),
}
}
pub fn options(mut self, options: ClientOptions) -> Self {
self.options = options;
self
}
pub fn credentials(mut self, provider: std::sync::Arc<dyn CredentialsProvider>) -> Self {
self.credentials = Some(provider);
self
}
pub fn request_timeout(mut self, timeout: std::time::Duration) -> Self {
self.options.request_timeout = timeout;
self
}
pub fn max_response_bytes(mut self, limit: usize) -> Self {
self.options.max_response_bytes = limit;
self
}
pub fn retry_policy(mut self, retry: RetryPolicy) -> Self {
self.options.retry = retry;
self
}
pub fn user_agent(mut self, user_agent: impl Into<String>) -> Self {
self.options.user_agent = user_agent.into();
self
}
pub fn telemetry(mut self, telemetry: std::sync::Arc<dyn TelemetryObserver>) -> Self {
self.options.telemetry = telemetry;
self
}
pub fn trusted_mesh_http(mut self, trusted: bool) -> Self {
self.options.trusted_mesh_http = trusted;
self
}
pub fn build(self) -> Result<InfraClient, InfraClientError> {
let http = build_http_client(&self.options)?;
let endpoint = endpoint_with_credentials(self.gateway, &self.credentials);
Ok(InfraClient {
#[cfg(feature = "admin")]
admin: AdminClient::new_with_endpoint(
http.clone(),
endpoint.clone(),
self.options.clone(),
),
#[cfg(feature = "agents")]
agents: AgentClient::new_with_endpoint(
http.clone(),
endpoint.clone(),
self.options.clone(),
),
#[cfg(feature = "deploy")]
deploy: DeployClient::new_with_endpoint(
http.clone(),
endpoint.clone(),
self.options.clone(),
),
#[cfg(feature = "evaluate")]
evaluate: EvaluateClient::new_with_endpoint(
http.clone(),
endpoint.clone(),
self.options.clone(),
),
#[cfg(feature = "gateway")]
gateway: GatewayClient::new_with_endpoint(
http.clone(),
endpoint.clone(),
self.options.clone(),
),
#[cfg(feature = "model")]
model: ModelClient::new_with_endpoint(
http.clone(),
endpoint.clone(),
self.options.clone(),
),
#[cfg(feature = "context")]
context: ContextClient::new_with_endpoint(
http.clone(),
endpoint.clone(),
self.options.clone(),
),
#[cfg(feature = "trace")]
trace: TraceClient::new_with_endpoint(
http.clone(),
endpoint.clone(),
self.options.clone(),
),
#[cfg(feature = "workspace")]
workspace: WorkspaceClient::new_with_endpoint(
http.clone(),
endpoint.clone(),
self.options.clone(),
),
#[cfg(feature = "workspace")]
environment: EnvironmentClient::new_with_endpoint(
http.clone(),
endpoint.clone(),
self.options.clone(),
),
#[cfg(feature = "runtime-identity")]
runtime_identity: RuntimeIdentityClient::new_with_endpoint(
http,
endpoint,
self.options,
),
})
}
}
fn endpoint_with_credentials(
mut endpoint: ServiceEndpoint,
credentials: &Option<std::sync::Arc<dyn CredentialsProvider>>,
) -> ServiceEndpoint {
if let Some(credentials) = credentials {
endpoint.credentials = Some(credentials.clone());
}
endpoint
}