Skip to content
Prompty

Rust

Prompty for Rust requires Rust ≥ 1.85 (edition 2024) and an async runtime (Tokio).

Terminal window
# Core runtime
cargo add prompty
# Add a provider (pick one or more)
cargo add prompty-openai # OpenAI
cargo add prompty-foundry # Azure OpenAI / Foundry
cargo add prompty-anthropic # Anthropic Claude
Crate Description crates.io
prompty Core pipeline, types, registry, tracing crates.io
prompty-openai OpenAI executor & processor crates.io
prompty-foundry Azure OpenAI / Foundry executor & processor crates.io
prompty-anthropic Anthropic Claude executor & processor crates.io

The core prompty crate has optional features:

Feature What it enables
otel OpenTelemetry tracing backend (opentelemetry, opentelemetry_sdk, opentelemetry-stdout)

The prompty-foundry crate has:

Feature What it enables
entra_id Azure Entra ID (AAD) authentication via azure_identity
Terminal window
# Enable OpenTelemetry tracing
cargo add prompty --features otel
# Enable Entra ID authentication for Foundry
cargo add prompty-foundry --features entra_id
use prompty;
use prompty_openai;
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. Register providers (once at startup)
prompty::register_defaults();
prompty_openai::register();
// 2. Load and invoke
let result = prompty::invoke_from_path(
"greeting.prompty",
Some(&json!({ "userName": "Jane" })),
).await?;
println!("{result}");
Ok(())
}
// Load a .prompty file into a typed Prompty object
let agent = prompty::load("chat.prompty")?;
println!("{}", agent.name); // "chat"
println!("{}", agent.model.id); // "gpt-4o"
println!("{:?}", agent.instructions); // Some("the markdown body")
// Async loading (non-blocking file I/O)
let agent = prompty::load_async("chat.prompty").await?;
// Load from a string (no file needed)
let agent = prompty::load_from_string(raw_content, ".")?;
use serde_json::json;
let agent = prompty::load("chat.prompty")?;
let inputs = json!({ "q": "Hi" });
// Render template + parse role markers → Vec<Message>
let messages = prompty::prepare(&agent, Some(&inputs)).await?;
// Execute LLM + process response → serde_json::Value
let result = prompty::run(&agent, &messages).await?;
// One-shot: prepare + run
let result = prompty::invoke_agent(&agent, Some(&inputs)).await?;
// Load from path + invoke in one call
let result = prompty::invoke_from_path("chat.prompty", Some(&inputs)).await?;

Rust’s Prompty runtime is async-only — all pipeline functions are async fn and require a Tokio runtime. This is idiomatic for Rust I/O and network operations.

#[tokio::main]
async fn main() {
let result = prompty::invoke_from_path("chat.prompty", None).await.unwrap();
}

The turn() function runs an agent loop — the LLM can call tools, and the runtime executes them automatically until it produces a final response.

use prompty::{TurnOptions, Steering, AgentEvent};
use serde_json::json;
use std::sync::Arc;
// Register tool handlers
prompty::register_tool_handler("get_weather", |args| {
Box::pin(async move {
let city = args["city"].as_str().unwrap_or("unknown");
Ok(json!(format!("72°F and sunny in {city}")))
})
});
let agent = prompty::load("agent.prompty")?;
let options = TurnOptions {
max_iterations: Some(10),
max_llm_retries: Some(3),
events: Some(Arc::new(|event: AgentEvent| {
println!("Event: {event:?}");
})),
..Default::default()
};
let result = prompty::turn(
&agent,
Some(&json!({ "question": "What's the weather in Seattle?" })),
Some(options),
).await?;

The agent loop includes built-in resilience:

  • Resilient JSON parsing — recovers from malformed tool arguments (markdown fences, trailing commas)
  • Tool error safety — both exceptions and panic!s are caught via catch_unwind and fed back to the LLM
  • LLM call retry — transient failures are retried with exponential backoff; InvokerError::ExecuteRetryExhausted carries the full conversation for resumption
  • Cancellation — respects cancel token during backoff sleep via tokio::select!

Pre-register named connections for production use:

use serde_json::json;
// Register a named connection
prompty::register_connection("my-openai", json!({
"kind": "key",
"apiKey": std::env::var("OPENAI_API_KEY").unwrap(),
}));
// .prompty files can reference it:
// connection:
// kind: reference
// name: my-openai
use prompty::{Tracer, PromptyTracer, console_tracer, trace_async};
// Register a file-based tracer (writes .tracy JSON files)
let pt = PromptyTracer::new("./traces");
Tracer::register("json", pt.tracer());
// Register the console tracer
Tracer::register("console", console_tracer);
// Trace custom async functions
let result = trace_async("my_pipeline", json!({"query": q}), async {
prompty::invoke_from_path("search.prompty", Some(&inputs)).await
}).await?;
Provider Crate Registration Key Auth
OpenAI prompty-openai openai API key
Azure OpenAI / Foundry prompty-foundry foundry API key or Entra ID
Anthropic prompty-anthropic anthropic API key

Register providers at startup — once registered, any .prompty file with a matching provider value will use that executor and processor:

prompty::register_defaults(); // renderers + parser
prompty_openai::register(); // "openai" executor + processor
prompty_foundry::register(); // "foundry" executor + processor
prompty_anthropic::register(); // "anthropic" executor + processor

Prompty resolves ${env:VAR} references in .prompty frontmatter from the process environment. Set them before loading:

Terminal window
export OPENAI_API_KEY=sk-your-key-here
export AZURE_OPENAI_ENDPOINT=https://myresource.openai.azure.com/
export AZURE_OPENAI_API_KEY=abc123
export ANTHROPIC_API_KEY=sk-ant-your-key-here

The Rust runtime covers the core Prompty pipeline comprehensively but has some gaps compared to the Python and TypeScript runtimes:

Feature Status Notes
Chat completions ✅ All providers
Streaming ✅ PromptyStream with tracing
Agent loop / turn() ✅ Events, cancellation, guardrails, steering
Structured output ✅ outputs → response_format
Tracing ✅ .tracy, console, OpenTelemetry
Custom providers ✅ Implement Executor + Processor traits
Embeddings API ❌ apiType: embedding not yet supported
Images API ❌ apiType: image not yet supported
Responses API ❌ OpenAI Responses API not yet supported
MCP tools ❌ MCP tool kind not yet supported
OpenAPI tools ❌ OpenAPI tool kind not yet supported

These features are planned for future releases. Contributions welcome!