use std::pin::Pin;
use std::sync::Arc;
use anyhow::Result;
use futures::Stream;
use oxi_ai::{
Api, AssistantMessage, ContentBlock, Context, Message, Model, Provider, ProviderEvent,
StopReason, StreamOptions, StreamResult, TextContent, Usage,
};
use oxi_sdk::prelude::*;
use oxi_sdk::{AgentGroup, GroupStrategy};
struct MockProvider;
impl Provider for MockProvider {
fn stream<'a>(
&'a self,
_model: &'a Model,
context: &'a Context,
_options: Option<StreamOptions>,
) -> Pin<Box<dyn Future<Output = StreamResult> + Send + 'a>> {
Box::pin(async move {
let last_msg = context
.messages
.iter()
.rev()
.find_map(|m| match m {
Message::User(u) => u.content.as_str().map(str::to_string),
_ => None,
})
.unwrap_or_else(|| "mock response".to_string());
let mut msg = AssistantMessage::new(Api::OpenAiCompletions, "mock", "mock/model");
msg.content
.push(ContentBlock::Text(TextContent::new(&last_msg)));
msg.stop_reason = StopReason::Stop;
msg.usage = Usage {
input: 100,
output: 50,
cache_read: 0,
cache_write: 0,
total_tokens: 150,
cost: Default::default(),
};
let partial = std::sync::Arc::new(msg.clone());
let events: Vec<ProviderEvent> = vec![
ProviderEvent::Start {
partial: partial.clone(),
},
ProviderEvent::TextDelta {
content_index: 0,
delta: last_msg,
partial,
},
ProviderEvent::Done {
reason: StopReason::Stop,
message: msg,
},
];
Ok(Box::pin(futures::stream::iter(events))
as Pin<Box<dyn Stream<Item = ProviderEvent> + Send>>)
})
}
}
fn mock_model() -> Model {
Model::new(
"model",
"Mock",
Api::OpenAiCompletions,
"mock",
"http://localhost",
)
}
#[tokio::main]
async fn main() -> Result<()> {
let oxi = OxiBuilder::new()
.provider("mock", MockProvider)
.model(mock_model())
.build();
let config = AgentConfig {
model_id: "mock/model".into(),
..Default::default()
};
let reviewer = oxi
.agent(config.clone())
.system_prompt("You are a code reviewer. Review briefly.")
.build()?;
let tester = oxi
.agent(config)
.system_prompt("You are a test engineer. Suggest tests briefly.")
.build()?;
let group = AgentGroup::new(GroupStrategy::Parallel { max_concurrency: 2 })
.agent(Arc::new(reviewer))
.agent(Arc::new(tester));
let result = group
.run("Analyze a hypothetical REST API for issues.".into())
.await?;
println!(
"Results ({} agents, {} ms):",
result.results.len(),
result.total_duration_ms
);
for output in &result.results {
let preview = &output.content[..output.content.len().min(120)];
println!(
" {} [{}]: {}",
output.name,
if output.success { "OK" } else { "FAIL" },
preview
);
}
Ok(())
}