use std::time::Duration;
use futures::StreamExt;
use sparrow::provider::{Brain, BrainEvent, BrainRequest, ContentBlock, Msg, PromptCacheConfig};
fn tiny_request() -> BrainRequest {
BrainRequest {
system: Some("You are a test probe. Reply with exactly one word.".into()),
messages: vec![Msg {
role: "user".into(),
content: vec![ContentBlock::Text {
text: "Say the single word: pong".into(),
}],
}],
tools: vec![],
max_tokens: 16,
temperature: 0.0,
stop: vec![],
cache: PromptCacheConfig::disabled(),
}
}
async fn assert_streams_text(provider: &str, brain: impl Brain) {
let stream = tokio::time::timeout(Duration::from_secs(45), brain.complete(tiny_request()))
.await
.unwrap_or_else(|_| panic!("{provider}: complete() timed out"))
.unwrap_or_else(|e| panic!("{provider}: complete() failed: {e}"));
let mut stream = stream;
let mut got_text = false;
let consume = async {
while let Some(ev) = stream.next().await {
if let BrainEvent::TextDelta(t) = ev
&& !t.trim().is_empty()
{
got_text = true;
}
}
};
tokio::time::timeout(Duration::from_secs(45), consume)
.await
.unwrap_or_else(|_| panic!("{provider}: stream did not complete in time"));
assert!(
got_text,
"{provider}: expected at least one non-empty text token"
);
}
fn skip(provider: &str, env_var: &str) {
eprintln!("[skip] {provider}: {env_var} not set — set it to run this smoke test");
}
#[tokio::test]
async fn anthropic_streams_text_when_keyed() {
let Ok(key) = std::env::var("ANTHROPIC_API_KEY") else {
return skip("anthropic", "ANTHROPIC_API_KEY");
};
let model = std::env::var("SPARROW_SMOKE_ANTHROPIC_MODEL")
.unwrap_or_else(|_| "claude-haiku-4-5-20251001".into());
let brain = sparrow::provider::anthropic::AnthropicAdapter::new(&model, key, None);
assert_streams_text("anthropic", brain).await;
}
#[tokio::test]
async fn openai_streams_text_when_keyed() {
let Ok(key) = std::env::var("OPENAI_API_KEY") else {
return skip("openai", "OPENAI_API_KEY");
};
let model =
std::env::var("SPARROW_SMOKE_OPENAI_MODEL").unwrap_or_else(|_| "gpt-4o-mini".into());
let brain = sparrow::provider::openai_compat::OpenAICompatAdapter::new(
&model,
key,
"https://api.openai.com/v1",
);
assert_streams_text("openai", brain).await;
}
#[tokio::test]
async fn groq_streams_text_when_keyed() {
let Ok(key) = std::env::var("GROQ_API_KEY") else {
return skip("groq", "GROQ_API_KEY");
};
let model =
std::env::var("SPARROW_SMOKE_GROQ_MODEL").unwrap_or_else(|_| "llama-3.1-8b-instant".into());
let brain = sparrow::provider::openai_compat::OpenAICompatAdapter::new(
&model,
key,
"https://api.groq.com/openai/v1",
);
assert_streams_text("groq", brain).await;
}