Quick Start
Install behest, configure a provider, and run your first agent turn in under five minutes.
Quick Start
This page walks through the minimum steps to get a working agent turn on the screen. By the end you will have:
- a
Cargo.tomlwithbehestand theopenaifeature, - a configured
ProviderRegistrycontaining an OpenAI chat adapter, - a runnable
AgentRuntime::runthat completes one user turn.
1. Add the dependency
cargo new hello-behest
cd hello-behest
In Cargo.toml:
[dependencies]
behest = { version = "0.4", features = ["openai"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
async-trait = "0.1"
serde_json = "1"
2. Configure a provider
The shortest path is AgentConfig::builder().with_env("BEHEST"). It looks for a TOML file pointed to by BEHEST_CONFIG and merges env vars prefixed with BEHEST__.
export BEHEST__PROVIDERS__OPENAI__API_KEY="sk-…"
export BEHEST__PROVIDERS__OPENAI__BASE_URL="https://api.openai.com/v1"
hello-behest/behest.toml:
[providers.openai]
type = "openai"
base_url = "https://api.openai.com/v1"
api_key = "env:OPENAI_API_KEY"
[providers.openai.chat]
model = "gpt-4o-mini"
The env:VAR_NAME indirection is resolved at load time; the literal string "env:…" never reaches the HTTP client.
3. Build and run
use behest::prelude::*;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = AgentConfig::builder()
.with_file("behest.toml")?
.with_env("BEHEST")?
.build()?;
let runtime = config.into_runtime().await?;
let request = RunRequest {
session_id: None,
run_id: None,
provider: ProviderId::new("openai"),
model: ModelName::new("gpt-4o-mini"),
input: "Say hello in exactly five words.".to_string(),
metadata: serde_json::Value::Null,
tool_choice: ToolChoice::Auto,
client_request_id: None,
};
let output = runtime.run(request).await?;
println!("{}", output.final_message);
Ok(())
}
4. Stream the response
The default run returns a RunOutput after the entire turn completes. To observe intermediate model events, use run_stream or subscribe to the RuntimeInvocation channel.
use futures::StreamExt;
let mut stream = runtime.run_stream(request).await?;
while let Some(event) = stream.next().await {
match event? {
AgentEvent::TextDelta { delta, .. } => print!("{delta}"),
AgentEvent::TurnCompleted { .. } => break,
_ => {}
}
}
5. Inspect what happened
Every run emits a sequence of AgentEvent values, persisted by the RuntimeEventStore and replayable through the RuntimeSubscriptionHub.
let events = runtime.run_events(run_id).await?;
for e in events {
println!("{:?}", e);
}
Where next
- Feature Flags — turn on storage, queue, RAG backends.
- Examples — full runnable examples covering tools, RAG, sessions, and streaming.
- Core Abstractions — once your first turn works, learn the composable substrate.
- Agent Runtime — the streaming-first FSM that drives every turn.