Skip to main content

ferro_ai/
lib.rs

1//! # ferro-ai
2//!
3//! AI structured classification and confirmation primitives for the Ferro framework.
4//!
5//! ## Classification
6//!
7//! Provider-abstracted wrapper for LLM structured JSON output with configurable
8//! schema, model selection, confidence threshold, and retry behavior.
9//!
10//! ```rust,ignore
11//! use ferro_ai::{Classifier, ClassifierConfig, AnthropicProvider};
12//! use serde::Deserialize;
13//! use std::sync::Arc;
14//!
15//! #[derive(Deserialize)]
16//! struct CommandIntent {
17//!     action: String,
18//!     confidence: f64,
19//! }
20//!
21//! let provider = AnthropicProvider::from_env().unwrap();
22//! let classifier = Classifier::<CommandIntent>::new(
23//!     Arc::new(provider),
24//!     ClassifierConfig::default(),
25//! );
26//! ```
27//!
28//! ## Confirmation
29//!
30//! State machine for gating destructive actions behind explicit user confirmation
31//! with configurable TTL expiry and event-driven observability.
32//!
33//! ```rust,ignore
34//! use ferro_ai::{InMemoryConfirmationStore, ConfirmationStore};
35//! use std::time::Duration;
36//!
37//! let store = InMemoryConfirmationStore::new();
38//! let payload = serde_json::json!({"action": "delete_user", "user_id": 42});
39//!
40//! store.request_confirmation("confirm-delete-42", payload, Duration::from_secs(60)).await?;
41//! let confirmed = store.confirm("confirm-delete-42").await?;
42//! ```
43
44#[cfg(any(feature = "llm", feature = "classifier-trait"))]
45pub mod classifier;
46#[cfg(feature = "llm")]
47pub mod client;
48#[cfg(feature = "llm")]
49pub mod complete;
50#[cfg(feature = "llm")]
51pub mod config;
52pub mod confirmation;
53#[cfg(feature = "llm")]
54pub mod embed;
55pub mod error;
56#[cfg(feature = "llm")]
57pub mod schema;
58#[cfg(feature = "llm")]
59pub mod similarity;
60#[cfg(feature = "llm")]
61pub mod tools;
62
63#[cfg(feature = "pgvector")]
64pub mod pgvector;
65
66#[cfg(feature = "llm")]
67pub use classifier::anthropic::AnthropicProvider;
68// ClassificationProvider, ClassifierConfig, Classifier, and ClassificationResult are
69// reqwest-free; available under `classifier-trait` (replay/CI) or `llm` (live path).
70#[cfg(any(feature = "llm", feature = "classifier-trait"))]
71pub use classifier::provider::ClassificationProvider;
72#[cfg(any(feature = "llm", feature = "classifier-trait"))]
73pub use classifier::{ClassificationResult, Classifier, ClassifierConfig};
74#[cfg(feature = "llm")]
75pub use client::{
76    AnthropicClient, CompletionRequest, CompletionResponse, LlmClient, OllamaClient, OpenAiClient,
77    TokenStream, ToolChoice, ToolRequest, ToolUseBlock,
78};
79#[cfg(feature = "llm")]
80pub use complete::{complete, complete_with, CompleteOptions};
81#[cfg(feature = "llm")]
82pub use config::AiConfig;
83// Confirmation re-exports — always available (reqwest-free).
84pub use confirmation::events::ConfirmationExpired;
85pub use confirmation::store::InMemoryConfirmationStore;
86pub use confirmation::{ConfirmationStore, PendingActionInfo};
87#[cfg(feature = "llm")]
88pub use embed::embed;
89pub use error::Error;
90#[cfg(feature = "llm")]
91pub use schema::for_structured_output;
92#[cfg(feature = "llm")]
93pub use similarity::cosine_similarity;
94#[cfg(feature = "llm")]
95pub use tools::{make_handler, ToolDef, ToolError, ToolRegistry};
96
97#[cfg(feature = "pgvector")]
98pub use pgvector::{Neighbor, PgVectorStore};
99
100/// Process-wide mutex that serializes env-var mutation across all test modules.
101///
102/// Tests that read or write `FERRO_AI_*` environment variables must hold this
103/// lock for the duration of the test to prevent cross-module interference.
104/// Per-module `static ENV_LOCK` instances are insufficient because each module
105/// gets its own mutex instance; only a crate-level mutex serializes across modules.
106#[cfg(test)]
107pub static ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());