use serde::{Deserialize, Serialize};
use serde_json::Value;
use simple_agents_healing::streaming::StreamingParser;
use simple_agents_macros::PartialType;
#[derive(Debug, Clone, PartialType, Serialize, Deserialize)]
pub struct Character {
pub name: String,
pub age: u32,
pub class: String,
#[partial(default)]
pub abilities: Vec<String>,
#[partial(default)]
pub backstory: Option<String>,
}
fn main() {
println!("🌊 SimpleAgents - Streaming Partial Types Example\n");
let chunks = [
r#"{"name": "Aria"#,
r#", "age": 2"#,
r#"5, "class": "Mage""#,
r#", "abilities": ["Fireball","#,
r#" "Ice Shield", "Teleport"]"#,
r#", "backstory": "A mysterious"#,
r#" wizard from the north"#,
r#"}"#,
];
let mut parser = StreamingParser::new();
let mut partial_character = PartialCharacter::default();
println!("📥 Receiving streaming response...\n");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
for (i, chunk) in chunks.iter().enumerate() {
println!("Chunk {}: {}", i + 1, chunk);
parser.feed(chunk);
if let Some(current) = parser.try_parse() {
if let Some(name) = current.value.get("name").and_then(Value::as_str) {
partial_character.name = Some(name.to_string());
}
if let Some(age) = current.value.get("age").and_then(Value::as_u64) {
partial_character.age = Some(age as u32);
}
if let Some(class) = current.value.get("class").and_then(Value::as_str) {
partial_character.class = Some(class.to_string());
}
if let Some(abilities) = current.value.get("abilities").and_then(Value::as_array) {
let ability_strings: Vec<String> = abilities
.iter()
.filter_map(Value::as_str)
.map(String::from)
.collect();
if !ability_strings.is_empty() {
partial_character.abilities = Some(ability_strings);
}
}
if let Some(backstory_val) = current.value.get("backstory") {
if let Some(backstory) = backstory_val.as_str() {
partial_character.backstory = Some(Some(backstory.to_string()));
}
}
println!(" └─ Partial: {:?}", partial_character);
}
println!();
}
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
match parser.finalize() {
Ok(result) => {
println!("✅ Stream complete!");
println!(" Confidence: {:.2}", result.confidence);
println!(" Flags: {} transformations", result.flags.len());
match Character::from_partial(partial_character.clone()) {
Ok(character) => {
println!("\n📊 Complete Character:");
println!(" Name: {}", character.name);
println!(" Age: {}", character.age);
println!(" Class: {}", character.class);
println!(" Abilities: {:?}", character.abilities);
if let Some(backstory) = character.backstory {
println!(" Backstory: {}", backstory);
}
}
Err(e) => {
println!("❌ Failed to convert partial to complete: {}", e);
}
}
}
Err(e) => {
println!("❌ Stream error: {}", e);
}
}
println!("\n💡 Key Benefits:");
println!(" • Progressive data extraction as chunks arrive");
println!(" • Type-safe partial values (Option<T> for all fields)");
println!(" • Merge multiple chunks into single partial value");
println!(" • Convert to complete type when ready");
}