use xynthe::prelude::*;
use async_trait::async_trait;
use std::sync::Arc;
struct WeatherCapability {
name: String,
api_key: Option<String>,
}
impl WeatherCapability {
fn new() -> Self {
Self {
name: "weather_api".to_string(),
api_key: None,
}
}
}
#[async_trait]
impl Capability for WeatherCapability {
fn name(&self) -> &str {
&self.name
}
fn describe(&self) -> CapabilityContract {
CapabilityContract::new()
.with_precondition("location_specified")
.with_precondition("valid_city_or_coords")
.with_effect("returns_weather_data")
.with_effect("network_request_made")
.with_failure_mode("api_unreachable")
.with_failure_mode("invalid_location")
.with_failure_mode("rate_limit_exceeded")
.build()
}
fn check_precondition(&self, precondition: &str, state: &StructuredContent) -> bool {
match precondition {
"location_specified" => {
if let Some(obj) = state.as_json() {
return obj.get("location").is_some();
}
false
}
"valid_city_or_coords" => {
if let Some(obj) = state.as_json() {
return obj.get("location").is_some();
}
false
}
_ => false,
}
}
async fn invoke(&self, input: StructuredContent) -> Result<CapabilityResult> {
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
if let Some(obj) = input.as_json() {
let location = obj.get("location").and_then(|v| v.as_str()).unwrap_or("unknown");
let weather_data = serde_json::json!({
"location": location,
"temperature": 72,
"unit": "fahrenheit",
"condition": "sunny",
"humidity": 65
});
Ok(CapabilityResult::success(StructuredContent::json(weather_data)))
} else {
Err(Error::CapabilityExecutionFailed("Invalid input format".into()))
}
}
fn simulate(&self, input: &StructuredContent) -> Result<CapabilityResult> {
Ok(CapabilityResult::success(StructuredContent::json(
serde_json::json!({
"simulated": true,
"location": input.as_json().and_then(|j| j.get("location")),
})
)))
}
async fn reflect(&self, traces: &[CapabilityTrace]) -> Result<StructuredContent> {
let avg_duration = traces.iter()
.filter(|t| t.metadata.success)
.map(|t| t.metadata.duration_ms as f64)
.sum::<f64>()
/ traces.len().max(1) as f64;
let success_rate = traces.iter()
.filter(|t| t.metadata.success)
.count() as f64
/ traces.len().max(1) as f64;
let reflection = serde_json::json!({
"reflection": "Weather API performance analysis",
"traces_analyzed": traces.len(),
"success_rate": success_rate,
"avg_duration_ms": avg_duration,
"recommendation": if success_rate > 0.9 {
"Maintain current API configuration"
} else {
"Investigate error patterns and improve reliability"
}
});
Ok(StructuredContent::json(reflection))
}
}
struct CalculatorCapability {
name: String,
}
impl CalculatorCapability {
fn new() -> Self {
Self {
name: "calculator".to_string(),
}
}
}
#[async_trait]
impl Capability for CalculatorCapability {
fn name(&self) -> &str {
&self.name
}
fn describe(&self) -> CapabilityContract {
CapabilityContract::new()
.with_precondition("valid_expression")
.with_effect("computes_result")
.with_effect("pure_computation")
.with_failure_mode("invalid_syntax")
.with_failure_mode("division_by_zero")
.build()
}
fn check_precondition(&self, precondition: &str, state: &StructuredContent) -> bool {
match precondition {
"valid_expression" => {
state.as_json()
.and_then(|j| j.get("expression"))
.is_some()
}
_ => false,
}
}
async fn invoke(&self, input: StructuredContent) -> Result<CapabilityResult> {
if let Some(obj) = input.as_json() {
if let Some(expr) = obj.get("expression").and_then(|v| v.as_str()) {
if expr.contains("+") {
let parts: Vec<f64> = expr.split("+").filter_map(|s| s.trim().parse().ok()).collect();
let sum: f64 = parts.iter().sum();
return Ok(CapabilityResult::success(StructuredContent::json(
serde_json::json!({ "result": sum, "operation": "addition" })
));
}
}
}
Err(Error::CapabilityExecutionFailed("Unsupported expression".into()))
}
}
#[tokio::main]
async fn main() -> Result<()> {
println!("=== Xynthe Capability Bindings Example ===\n");
println!("1. Initializing capability registry...");
let registry = Arc::new(CapabilityRegistry::new());
println!(" ✓ Registry created\n");
println!("2. Registering capabilities...");
let weather_cap = Arc::new(WeatherCapability::new()) as Arc<dyn Capability>;
registry.register(weather_cap.clone()).await?;
println!(" ✓ Weather API capability registered");
let calc_cap = Arc::new(CalculatorCapability::new()) as Arc<dyn Capability>;
registry.register(calc_cap.clone()).await?;
println!(" ✓ Calculator capability registered\n");
println!("3. Listing registered capabilities:");
let capabilities = registry.list().await;
for (idx, cap_name) in capabilities.iter().enumerate() {
let cap = registry.get(cap_name).await?;
println!(" {}. {}", idx + 1, cap.name());
}
println!();
println!("4. Inspecting capability contracts...");
for cap_name in &capabilities {
let cap = registry.get(cap_name).await?;
let contract = cap.describe();
println!(" Capability: {}", cap.name());
println!(" Preconditions: {:?}", contract.preconditions);
println!(" Effects: {:?}", contract.effects);
println!(" Failure modes: {:?}", contract.failure_modes);
println!();
}
println!("5. Invoking Weather API capability...");
let weather_input = StructuredContent::json(serde_json::json!({
"location": "San Francisco, CA"
}));
let weather_cap = registry.get("weather_api").await?;
if weather_cap.can_invoke(&weather_input) {
let result = registry.invoke("weather_api", weather_input).await?;
if result.is_success() {
println!(" ✓ Weather API invocation successful");
println!(" Result: {:?}\n", result.data().as_json());
}
} else {
println!(" ✗ Preconditions not met\n");
}
println!("6. Invoking Calculator capability...");
let calc_input = StructuredContent::json(serde_json::json!({
"expression": "15 + 27"
}));
let calc_cap = registry.get("calculator").await?;
if calc_cap.can_invoke(&calc_input) {
let result = registry.invoke("calculator", calc_input).await?;
if result.is_success() {
println!(" ✓ Calculator invocation successful");
println!(" Result: {:?}\n", result.data().as_json());
}
}
println!("7. Simulating capability execution (no side effects)...");
let weather_cap = registry.get("weather_api").await?;
let sim_result = weather_cap.simulate(&StructuredContent::json(
serde_json::json!({ "location": "New York, NY" })
))?;
println!(" Simulation result: {:?}\n", sim_result.data().as_json());
println!("8. Reflecting on execution traces...");
let traces = registry.traces().await;
if !traces.is_empty() {
let reflection = weather_cap.reflect(&traces).await?;
println!(" Reflection analysis:");
println!(" {:?}\n", reflection.as_json());
}
println!("9. Verifying trace recording...");
println!(" Total traces recorded: {}\n", traces.len());
for (idx, trace) in traces.iter().enumerate() {
println!(" Trace {}: {}", idx + 1, trace.capability_name);
println!(" Success: {}", trace.success);
println!(" Duration: {} ms", trace.metadata.duration_ms);
}
println!("\n=== Capability Bindings Example Completed ===\n");
println!("Safety features demonstrated:");
println!(" ✓ Precondition checking");
println!(" ✓ Capability contracts");
println!(" ✓ Failure mode definitions");
println!(" ✓ Simulation support");
println!(" ✓ Reflection and learning");
println!(" ✓ Immutable trace recording");
Ok(())
}