gemini_adk_fluent_rs/lib.rs
1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![warn(unreachable_pub)]
3#![forbid(unsafe_code)]
4#![warn(missing_docs)]
5//! # gemini-adk-fluent-rs
6//!
7//! Fluent developer experience layer for the Gemini Live agent stack.
8//! This is the highest-level crate in the workspace, providing a builder API,
9//! operator algebra, and composition modules that sit on top of
10//! [`gemini_adk_rs`] (agent runtime) and [`gemini_genai_rs`] (wire protocol).
11//!
12//! ## Module Organization
13//!
14//! | Module | Purpose |
15//! |--------|---------|
16//! | [`builder`] | Copy-on-write immutable `AgentBuilder` for declarative agent configuration |
17//! | [`compose`] | The eight-namespace operator algebra — `S` state, `C` context, `T` tools, `P` prompts, `M` middleware, `A` artifacts, `E` evaluation, `G` guards |
18//! | [`live`] | `Live` session builder — callback-driven full-duplex event handling |
19//! | [`live_builders`] | Phase and watcher sub-builders for `Live` |
20//! | [`operators`] | `>> | * /` combinators for composing agents |
21//! | [`patterns`] | Pre-built composition patterns for common use cases |
22//! | [`voice`] | Microphone/speaker plumbing; `talk()` needs the `voice-io` feature |
23//! | [`testing`] | Contract checks, data-flow inference, mock harnesses |
24//!
25//! ## Quick Start
26//!
27//! Text generation is on by default (feature `gemini-llm`); set
28//! `GEMINI_API_KEY` and ask a question:
29//!
30//! ```no_run
31//! use gemini_adk_fluent_rs::prelude::*;
32//! use std::sync::Arc;
33//!
34//! # async fn run() -> Result<(), Box<dyn std::error::Error>> {
35//! let llm = Arc::new(GeminiLlm::new(GeminiLlmParams::default()));
36//! let agent = AgentBuilder::new("assistant")
37//! .instruction("You are a concise assistant.")
38//! .build(llm)?;
39//! let state = State::new();
40//! state.set("input", "Say hello in one sentence.")?;
41//! println!("{}", agent.run(&state).await?);
42//!
43//! // Voice: microphone in, speakers out, barge-in handled — `.talk()` exists
44//! // only with the `voice-io` feature (Linux: libasound2-dev).
45//! let handle = Live::builder()
46//! .instruction("You are a helpful concierge.")
47//! .greeting("Greet the caller.")
48//! .connect_from_env()
49//! .await?;
50//! # let _ = handle;
51//! # Ok(())
52//! # }
53//! ```
54//!
55//! ## Relationship to Other Crates
56//!
57//! - **`gemini-genai-rs`** (L0): wire protocol, transport, types — re-exported as [`gemini_genai_rs`]
58//! - **`gemini-adk-rs`** (L1): agent runtime, tools, sessions — re-exported as [`gemini_adk_rs`]
59//! - **`gemini-adk-fluent-rs`** (L2): this crate — the builder API and composition algebra
60
61pub mod a2a;
62pub mod builder;
63pub mod compose;
64pub mod conversation;
65pub mod flow_macros;
66pub mod handoff;
67pub mod live;
68pub mod live_builders;
69pub mod motifs;
70pub mod operators;
71pub mod patterns;
72pub mod policy;
73pub mod primitives;
74pub mod simulation;
75pub mod spec;
76pub mod telephony;
77pub mod testing;
78pub mod voice;
79
80pub use gemini_adk_rs;
81pub use gemini_genai_rs;
82
83// ---------------------------------------------------------------------------
84// Curated submodule homes (the prelude is a kernel, not an everything-glob).
85//
86// The kernel `prelude` (below) re-exports only the ~30 types a typical app
87// touches. Everything else lives in these focused, discoverable modules so
88// `use gemini_adk_fluent_rs::prelude::*` stays small and the rest is one
89// `use gemini_adk_fluent_rs::{live, text, tools, …}` away. Import from the
90// highest-level crate you need.
91// ---------------------------------------------------------------------------
92
93/// Text-agent runtime and combinators (carved out of the kernel `prelude`).
94///
95/// `LlmTextAgent`, the sequential/parallel/loop/fallback/route/race/timeout/map
96/// combinators, and the `TextAgent` trait.
97pub mod text {
98 pub use gemini_adk_rs::text::*;
99}
100
101/// Tool definitions, dispatch, toolsets, the confirmation flow, and frames.
102pub mod tools {
103 pub use gemini_adk_rs::confirmation::*;
104 pub use gemini_adk_rs::extract::{Recognizer, RecordExtractor};
105 pub use gemini_adk_rs::frame::{
106 ConfirmPolicy, FrameSpec, SlotRecognizer, SlotSpec, SlotValidator,
107 };
108 pub use gemini_adk_rs::tool::*;
109 pub use gemini_adk_rs::toolset::*;
110}
111
112/// LLM abstraction: params, requests/responses, and the registry.
113pub mod llm {
114 pub use gemini_adk_rs::llm::*;
115}
116
117/// Concurrent typed state: `State`, `PrefixedState`, `StateKey`, prefix scopes.
118pub mod state {
119 pub use gemini_adk_rs::state::*;
120}
121
122/// Governed-conversation flow primitives: `Flow`, `Step`, `Guard`, `FlowMonitor`.
123pub mod flow {
124 pub use gemini_adk_rs::flow::*;
125}
126
127/// Agent builders, the L1 [`Agent`](gemini_adk_rs::agent::Agent) trait, and
128/// the operator/pattern combinators.
129pub mod agents {
130 pub use crate::builder::*;
131 pub use crate::operators::*;
132 pub use crate::patterns::*;
133 #[doc(inline)]
134 pub use gemini_adk_rs::agent::Agent;
135 pub use gemini_adk_rs::agent_session::*;
136 pub use gemini_adk_rs::orchestration::{self, AgentMode, Resolver, call_agent, provenance};
137}
138
139/// L0 wire-protocol types for raw WebSocket access.
140pub mod wire {
141 pub use gemini_genai_rs::prelude::*;
142}
143
144/// Clone multiple bindings for use in `move` closures, reducing Arc/clone boilerplate.
145///
146/// # Example
147///
148/// ```
149/// use gemini_adk_fluent_rs::let_clone;
150/// use std::sync::Arc;
151///
152/// let state = Arc::new(42);
153/// let writer = Arc::new("hello");
154///
155/// let_clone!(state, writer);
156/// let task = move || format!("{state} {writer}");
157/// assert_eq!(task(), "42 hello");
158/// ```
159#[macro_export]
160macro_rules! let_clone {
161 ($($name:ident),+ $(,)?) => {
162 $(let $name = $name.clone();)+
163 };
164}
165
166/// The kernel prelude — the names a typical application touches.
167///
168/// Deliberately a kernel, not an everything-glob. Anything not here lives in
169/// a focused submodule and is one import away:
170///
171/// | Need | Import |
172/// |------|--------|
173/// | Full Live control plane (persistence, repair, steering, transcripts, contracts) | `use gemini_adk_fluent_rs::live::*;` |
174/// | Text-agent runtime details | `use gemini_adk_fluent_rs::text::*;` |
175/// | Toolsets, confirmation, frames | `use gemini_adk_fluent_rs::tools::*;` |
176/// | State prefixes / `SlotEvidence` | `use gemini_adk_fluent_rs::state::*;` |
177/// | Full flow vocabulary (`CompiledFlow`, `StepAction`, `Violation`, …) | `use gemini_adk_fluent_rs::flow::*;` |
178/// | `Agent` trait + operator/pattern internals | `use gemini_adk_fluent_rs::agents::*;` |
179/// | Conversation compiler internals (`ResolverRegistry`, `StageSpec`, `OverlaySpec`, …) | `use gemini_adk_fluent_rs::conversation::*;` (`Conversation`, `ConversationSpec`, `CompiledConversation` are in the prelude) |
180/// | Serializable scenarios (`Scenario`, `SimStep`) | `use gemini_adk_fluent_rs::simulation::*;` (`Sim` is in the prelude) |
181/// | A2A, motifs, policy, testing, orchestration, credentials, run_config | the same-named module, e.g. `use gemini_adk_fluent_rs::policy::*;` |
182/// | Raw L0 wire types | `use gemini_adk_fluent_rs::wire::*;` |
183pub mod prelude {
184 // ── Voice I/O: `.talk()` on a connected handle (feature `voice-io`) ──
185 #[cfg(feature = "voice-io")]
186 pub use crate::voice::Talk;
187
188 // ── Builders, composition algebra, operators, patterns (headline DX) ──
189 pub use crate::builder::*;
190 pub use crate::compose::{A, C, Ctx, E, G, M, P, S, T};
191 pub use crate::live::Live;
192 // Dynamic instructions (ADK instruction-provider pattern) + tool media.
193 pub use crate::operators::*;
194 pub use crate::patterns::*;
195 pub use gemini_adk_rs::instruction::InstructionProvider;
196 #[cfg(feature = "templates")]
197 pub use gemini_adk_rs::instruction::TemplateInstruction;
198 pub use gemini_adk_rs::tool::media as tool_media;
199 // Build-time validation DX (contract checking, data-flow inference, harness).
200 pub use crate::testing::{
201 AgentHarness, ContractViolation, DataFlowEdge, LiveViolation, check_contracts, check_live,
202 diagnose, infer_data_flow,
203 };
204
205 // The L1 `Agent` trait (`name()` + `run_live()`); the L2 builder is
206 // `AgentBuilder`, so the two names never collide.
207 #[doc(inline)]
208 pub use gemini_adk_rs::agent::Agent;
209
210 // ── Errors ──
211 pub use gemini_adk_rs::error::{AgentError, AgentResult, ConfigError, ToolError};
212
213 // ── Governed flow (core vocabulary; full set in `crate::flow`) ──
214 pub use gemini_adk_rs::flow::{Enforcement, Flow, FlowMonitor, Guard, Verdict};
215
216 // ── Conversations and the model-free simulator ──
217 // The authoring model above `Flow` and the deterministic driver that runs
218 // it without a model. They are the flagship of the crate, so they live on
219 // the same import line as `Live`; the compiler internals stay in
220 // `crate::conversation` and the serializable `Scenario` in
221 // `crate::simulation`.
222 pub use crate::conversation::{
223 CompiledConversation, Conversation, ConversationSpec, RepairPolicy, VoiceTiming,
224 };
225 pub use crate::simulation::Sim;
226
227 // ── State (prefix scopes + `SlotEvidence` in `crate::state`) ──
228 pub use gemini_adk_rs::state::{State, StateKey};
229
230 // ── LLM (core; request/response/registry in `crate::text`) ──
231 pub use gemini_adk_rs::llm::{BaseLlm, GeminiLlm, GeminiLlmParams, LlmError};
232
233 // ── Tools ──
234 pub use gemini_adk_rs::tool::{
235 SimpleTool, ToolContext, ToolDispatcher, ToolFunction, ToolPolicy, TypedTool,
236 };
237 // The `#[tool]` attribute macro — turns an `async fn` into a registrable tool.
238 pub use gemini_adk_rs::tool;
239 // Brings in both the `Extract` struct and the `#[derive(Extract)]` macro.
240 pub use gemini_adk_rs::Extract;
241 // The `#[derive(Frame)]` macro.
242 pub use gemini_adk_rs::Frame;
243
244 // ── Callback contexts (used in `M::` hooks) ──
245 // `ToolContext` in the prelude is what a tool receives
246 // (`gemini_adk_rs::tool::ToolContext`); the `InvocationContext` wrapper of
247 // the same name stays at `gemini_adk_rs::context::ToolContext`.
248 pub use gemini_adk_rs::context::CallbackContext;
249
250 // ── Common Live session types (full control plane in `crate::live`) ──
251 pub use gemini_adk_rs::live::{
252 ContextDelivery, EventCallbacks, ExtractionTrigger, FsPersistence, LiveHandle,
253 LlmExtractor, MemoryPersistence, PersistenceError, RepairConfig, SessionPersistence,
254 SoftTurnDetector, SteeringMode, TranscriptBuffer, TranscriptTurn, TurnExtractor,
255 };
256
257 // ── Text-agent combinators (runtime details in `crate::text`) ──
258 pub use gemini_adk_rs::text::{
259 Chat, DispatchTextAgent, FallbackTextAgent, FnTextAgent, JoinTextAgent, LlmTextAgent,
260 LoopTextAgent, MapOverTextAgent, ParallelTextAgent, RaceTextAgent, RouteRule,
261 RouteTextAgent, RunEvent, RunRequest, RunResult, SequentialTextAgent, TapTextAgent,
262 TaskRegistry, TextAgent, TimeoutTextAgent,
263 };
264
265 // ── L0 wire types an application names (the rest: `crate::wire`) ──
266 pub use gemini_genai_rs::prelude::{
267 ActivityHandling, ApiEndpoint, AudioFormat, AudioTranscriptionConfig,
268 AutomaticActivityDetection, AvatarConfig, Blob, Content, FinishReason, FunctionCall,
269 FunctionCallingBehavior, FunctionDeclaration, FunctionResponse, FunctionResponseScheduling,
270 GenerationConfig, HarmBlockThreshold, HarmCategory, Modality, ModelId, Part, Role,
271 SafetySetting, Sensitivity, ServerMessage, SessionConfig, SessionEvent, SpeechConfig,
272 ThinkingConfig, Tool, TurnCoverage, UsageMetadata, Voice,
273 };
274
275 // `while let Some(event) = agent.stream(..).next().await` needs this trait.
276 pub use futures_util::StreamExt;
277}