#![allow(
clippy::todo,
clippy::unimplemented,
clippy::panic,
clippy::unwrap_used,
clippy::expect_used,
clippy::missing_errors_doc,
clippy::missing_panics_doc,
clippy::doc_markdown,
clippy::needless_pass_by_value,
clippy::too_many_arguments,
clippy::unused_async,
clippy::diverging_sub_expression,
clippy::no_effect_underscore_binding,
clippy::let_unit_value,
clippy::used_underscore_binding,
clippy::let_underscore_untyped,
clippy::struct_field_names,
clippy::manual_let_else,
clippy::map_unwrap_or,
clippy::redundant_pub_crate,
dead_code,
unreachable_code,
unused_assignments,
unused_mut,
unused_imports,
unused_variables
)]
use std::collections::HashMap;
use arcp::error::ARCPError;
use arcp::messages::Capabilities;
use arcp::transport::MemoryTransport;
use arcp::{ARCPClient, Envelope, ErrorCode};
use serde_json::json;
type Client = ARCPClient<MemoryTransport>;
const PEERS: &[&str] = &[
"anthropic-haiku",
"anthropic-sonnet",
"openai-4o",
"groq-llama",
];
const COST_CEILING_USD_PER_MTOK: f64 = 8.0;
const LATENCY_CEILING_MS: u32 = 800;
fn fallback_chain(class: &str) -> &'static [&'static str] {
match class {
"cheap_fast" => &["groq-llama", "anthropic-haiku", "openai-4o"],
"balanced" => &["anthropic-sonnet", "openai-4o", "anthropic-haiku"],
"deep" => &["anthropic-sonnet"],
_ => &[],
}
}
#[derive(Debug, Clone, Copy)]
struct Profile {
cost_per_mtok: f64,
p50_latency_ms: u32,
}
fn profile_from(_caps: &Capabilities) -> Profile {
todo!()
}
fn candidate_chain(profiles: &HashMap<&str, Profile>, class: &str) -> Vec<&'static str> {
fallback_chain(class)
.iter()
.copied()
.filter(|name| {
profiles.get(name).is_some_and(|p| {
p.cost_per_mtok <= COST_CEILING_USD_PER_MTOK
&& p.p50_latency_ms <= LATENCY_CEILING_MS
})
})
.collect()
}
const fn is_retryable(code: ErrorCode) -> bool {
matches!(
code,
ErrorCode::ResourceExhausted
| ErrorCode::Unavailable
| ErrorCode::DeadlineExceeded
| ErrorCode::Aborted
)
}
async fn invoke_with_fallback(
_clients: &HashMap<&str, Client>,
chain: &[&str],
_tool: &str,
_arguments: serde_json::Value,
_trace_id: &str,
) -> Result<Envelope, ARCPError> {
let mut last: Option<ARCPError> = None;
for _name in chain {
let reply: Result<Envelope, ARCPError> = todo!();
match reply {
Ok(env) => return Ok(env),
Err(exc) => {
let code = exc.code();
last = Some(exc);
if is_retryable(code) {
continue;
}
return Err(last.expect("set above"));
}
}
}
Err(last.unwrap_or_else(|| ARCPError::Unavailable {
detail: "no peers available".into(),
}))
}
#[derive(Debug, Default)]
struct Usage {
tokens_in: u64,
tokens_out: u64,
cost_usd: f64,
by_peer: HashMap<String, f64>,
}
fn consume_metric(_env: &Envelope, _totals: &mut HashMap<String, Usage>) {
todo!()
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut clients: HashMap<&str, Client> = HashMap::new();
let mut profiles: HashMap<&str, Profile> = HashMap::new();
for name in PEERS {
let client: Client = todo!(); let caps: Capabilities = todo!(); profiles.insert(name, profile_from(&caps));
clients.insert(name, client);
}
let trace_id = "trace_<uuid>";
let chain = candidate_chain(&profiles, "balanced");
let _reply = invoke_with_fallback(
&clients,
&chain,
"chat.completion",
json!({"prompt": "Hello", "tenant": "acme-corp"}),
trace_id,
)
.await?;
println!("invoked balanced chain across {} peers", chain.len());
Ok(())
}