use std::sync::Arc;
use elph_ai::env_api_key_auth;
use elph_ai::{AuthContext, BoxFuture, Context, CreateModelsOptions, InMemoryCredentialStore, Message, UserContent};
struct PrefixedEnv;
impl AuthContext for PrefixedEnv {
fn env<'a>(&'a self, name: &'a str) -> BoxFuture<'a, Option<String>> {
let name = name.to_string();
Box::pin(async move {
let prefixed = format!("CUSTOM_{name}");
std::env::var(&prefixed).ok().or_else(|| std::env::var(&name).ok())
})
}
fn file_exists<'a>(&'a self, _path: &'a str) -> BoxFuture<'a, bool> {
Box::pin(async { false })
}
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let models = elph_ai::builtin_models(Some(CreateModelsOptions {
credentials: Some(Arc::new(InMemoryCredentialStore::new())),
auth_context: Some(Arc::new(PrefixedEnv)),
}));
let key_auth = env_api_key_auth("OpenCode Key", vec!["CUSTOM_OPENCODE_API_KEY", "OPENCODE_API_KEY"]);
println!("Auth name: {}", key_auth.name);
let model = match models.get_model("opencode", "big-pickle") {
Some(m) => m,
None => anyhow::bail!("opencode/big-pickle not found"),
};
let auth = models.get_auth(&model).await?;
match &auth {
Some(a) => println!("Auth source: {}", a.source.as_deref().unwrap_or("store")),
None => println!("No auth — set OPENCODE_API_KEY"),
}
let env_ctx = PrefixedEnv;
let home = env_ctx.env("HOME").await.unwrap_or_else(|| "?".into());
println!("HOME via PrefixedEnv: {home}");
let context = Context {
system_prompt: Some("Reply in one sentence.".into()),
messages: vec![Message::User {
content: UserContent::Text("What is a lifetime in Rust?".into()),
timestamp: chrono::Utc::now().timestamp_millis(),
}],
tools: None,
};
let message = models.complete(&model, &context, None).await;
match &message.error_message {
Some(e) => println!("Chat unavailable: {e}"),
None => {
for block in &message.content {
if let elph_ai::AssistantContentBlock::Text(t) = block {
println!("Answer: {}", t.text);
}
}
}
}
Ok(())
}