Rig (Rust)
Rig is a Rust framework for building large language model (LLM) and agent applications.
Rig emits tracing spans for agent, completion, and tool operations. The
Logfire Rust SDK installs the subscriber and OpenTelemetry exporter
that send those native spans to Logfire.
[dependencies]
logfire = "0.11"
rig-agent = "0.41"
rig-core = "0.41"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
Configure Logfire before building the agent, then give the agent a real Rig Tool:
use logfire::config::SendToLogfire;
use rig_agent::{
client::AgentClientExt,
completion::Prompt,
tool::{Tool, ToolContext},
};
use rig_core::providers::openai;
use serde::Deserialize;
use std::{
convert::Infallible,
sync::{Arc, Mutex},
};
#[derive(Deserialize)]
struct IncidentInput {
incident_id: String,
}
#[derive(Clone)]
struct LookupIncident(Arc<Mutex<Vec<String>>>);
impl Tool for LookupIncident {
const NAME: &'static str = "lookup_incident";
type Args = IncidentInput;
type Output = String;
type Error = Infallible;
fn description(&self) -> String {
"Look up the current status and owner of an incident by ID.".into()
}
fn parameters(&self) -> serde_json::Value {
serde_json::json!({
"type": "object",
"properties": { "incident_id": { "type": "string" } },
"required": ["incident_id"]
})
}
async fn call(
&self,
_context: &mut ToolContext,
args: Self::Args,
) -> Result<Self::Output, Self::Error> {
self.0.lock().unwrap().push(args.incident_id.clone());
Ok(format!(
"{} is resolved; owner=platform-observability",
args.incident_id
))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Requires LOGFIRE_TOKEN and installs the global tracing subscriber and exporter.
let logfire = logfire::configure()
.send_to_logfire(SendToLogfire::Yes)
.finish()?;
let guard = logfire.shutdown_guard();
let client = openai::CompletionsClient::builder()
.api_key(std::env::var("OPENAI_API_KEY")?)
.build()?;
let tool_calls = Arc::new(Mutex::new(Vec::new()));
let agent = client
.agent("gpt-4o-mini")
.name("Incident agent")
.preamble("Use the supplied tool to verify incidents before answering.")
// Native Rig opt-in for prompt, response, and tool content on GenAI spans.
.record_content_telemetry(true)
.default_max_turns(3)
.tool(LookupIncident(tool_calls.clone()))
.build();
let answer = agent
.prompt(
"Call lookup_incident exactly once with incident_id incident-42, then report the status and owner.",
)
.await?;
if tool_calls.lock().unwrap().as_slice() != ["incident-42"] {
return Err("the agent did not execute lookup_incident exactly once".into());
}
println!("{answer}");
guard.shutdown()?; // flushes spans before exit
Ok(())
}
Run LOGFIRE_TOKEN=<write-token> OPENAI_API_KEY=<key> cargo run in your terminal. The program fails unless the
native Rig agent executes lookup_incident. In Logfire, the trace contains Rig’s agent, completion, and tool
spans. Because record_content_telemetry(true) is enabled, the completion spans also contain
gen_ai.input.messages and gen_ai.output.messages, and tool spans contain the arguments and results. The
Logfire SDK does not add a synthetic agent wrapper. Rig runs also appear in the specialized Agents view; the
support matrix shows which columns each view populates.
For an EU-region project, use its EU write token. The Logfire Rust SDK infers the data region from the token.
Managed prompts are authored and versioned in Prompt Management. The dedicated prompt-fetching SDK helpers are currently available in the Python and TypeScript SDKs. From Rust, consume managed variables over the language-agnostic OpenFeature Remote Evaluation Protocol (OFREP) HTTP API, or resolve the prompt in a small Python or TypeScript sidecar and pass the rendered text into the Rig agent.