Skip to main content

highflame_shield/
lib.rs

1//! # highflame-shield
2//!
3//! Async Rust SDK for the [highflame-shield](https://highflame.ai) guardrails service.
4//!
5//! ## Quick start
6//!
7//! ```no_run
8//! use highflame_shield::{ShieldClient, ShieldClientOptions, ShieldRequest};
9//!
10//! #[tokio::main]
11//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
12//!     let client = ShieldClient::new(
13//!         ShieldClientOptions::new(std::env::var("HIGHFLAME_API_KEY")?),
14//!     );
15//!
16//!     let resp = client
17//!         .guard_prompt("Hello world", None, None)
18//!         .await?;
19//!
20//!     println!("decision: {}", resp.decision);
21//!     assert!(resp.allowed());
22//!     Ok(())
23//! }
24//! ```
25//!
26//! ## Service-key flow
27//!
28//! Keys that start with `hf_sk` are automatically exchanged for a short-lived
29//! RS256 JWT.  The JWT is cached and transparently refreshed 60 s before expiry.
30//! Concurrent callers serialise behind a single [`tokio::sync::Mutex`] so only
31//! one exchange is ever in-flight.
32//!
33//! ```no_run
34//! use highflame_shield::{ShieldClient, ShieldClientOptions};
35//!
36//! # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
37//! let client = ShieldClient::new(
38//!     ShieldClientOptions::new("hf_sk_my_service_key")
39//!         .token_url("https://studio.api-dev.highflame.dev/api/cli-auth/token")
40//!         .base_url("https://shield.api-dev.highflame.dev"),
41//! );
42//!
43//! // First call exchanges the key for a JWT automatically.
44//! let resp = client.guard_prompt("test", None, None).await?;
45//! println!("{}", resp.decision);
46//! # Ok(()) }
47//! ```
48//!
49//! ## SSE streaming
50//!
51//! ```no_run
52//! use futures_util::{pin_mut, StreamExt as _};
53//! use highflame_shield::{ShieldClient, ShieldClientOptions, ShieldRequest};
54//!
55//! # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
56//! let client = ShieldClient::new(ShieldClientOptions::new("my-jwt"));
57//! let req = ShieldRequest {
58//!     content: "Hello".to_string(),
59//!     content_type: "prompt".to_string(),
60//!     action: "process_prompt".to_string(),
61//!     ..Default::default()
62//! };
63//!
64//! // `stream()` returns an `impl Stream` that is not `Unpin` — pin it before
65//! // iterating so `StreamExt::next()` can take a mutable reference.
66//! let stream = client.stream(&req).await?;
67//! pin_mut!(stream);
68//! while let Some(event) = stream.next().await {
69//!     let ev = event?;
70//!     println!("event: {} data: {:?}", ev.r#type, ev.data);
71//! }
72//! # Ok(()) }
73//! ```
74
75pub mod error;
76pub mod stream;
77pub mod types;
78
79mod client;
80
81// ── Public re-exports ─────────────────────────────────────────────────────────
82
83pub use client::{ShieldClient, ShieldClientOptions};
84pub use error::ShieldError;
85pub use stream::ShieldStreamEvent;
86pub use types::{
87    DetectorInfo, DetectorResult, DeterminingPolicy, FileContext, HealthResponse,
88    ListDetectorsResponse, McpContext, ModelContext, RootCause, SessionDelta, ShieldRequest,
89    ShieldResponse, ToolContext, TokenResponse,
90};