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 ~40 types 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 (`Conversation`, `ConversationSpec`, …) | `use gemini_adk_fluent_rs::conversation::*;` |
180/// | A2A, motifs, policy, simulation, testing, orchestration, credentials, run_config | the same-named module, e.g. `use gemini_adk_fluent_rs::simulation::*;` |
181/// | Raw L0 wire types | `use gemini_adk_fluent_rs::wire::*;` |
182pub mod prelude {
183 // ── Voice I/O: `.talk()` on a connected handle (feature `voice-io`) ──
184 #[cfg(feature = "voice-io")]
185 pub use crate::voice::Talk;
186
187 // ── Builders, composition algebra, operators, patterns (headline DX) ──
188 pub use crate::builder::*;
189 pub use crate::compose::{A, C, Ctx, E, G, M, P, S, T};
190 pub use crate::live::Live;
191 // Dynamic instructions (ADK instruction-provider pattern) + tool media.
192 pub use crate::operators::*;
193 pub use crate::patterns::*;
194 pub use gemini_adk_rs::instruction::InstructionProvider;
195 #[cfg(feature = "templates")]
196 pub use gemini_adk_rs::instruction::TemplateInstruction;
197 pub use gemini_adk_rs::tool::media as tool_media;
198 // Build-time validation DX (contract checking, data-flow inference, harness).
199 pub use crate::testing::{
200 AgentHarness, ContractViolation, DataFlowEdge, LiveViolation, check_contracts, check_live,
201 diagnose, infer_data_flow,
202 };
203
204 // The L1 `Agent` trait (`name()` + `run_live()`); the L2 builder is
205 // `AgentBuilder`, so the two names never collide.
206 #[doc(inline)]
207 pub use gemini_adk_rs::agent::Agent;
208
209 // ── Errors ──
210 pub use gemini_adk_rs::error::{AgentError, AgentResult, ConfigError, ToolError};
211
212 // ── Governed flow (core vocabulary; full set in `crate::flow`) ──
213 pub use gemini_adk_rs::flow::{Enforcement, Flow, FlowMonitor, Guard, Verdict};
214
215 // ── State (prefix scopes + `SlotEvidence` in `crate::state`) ──
216 pub use gemini_adk_rs::state::{State, StateKey};
217
218 // ── LLM (core; request/response/registry in `crate::text`) ──
219 pub use gemini_adk_rs::llm::{BaseLlm, GeminiLlm, GeminiLlmParams};
220
221 // ── Tools ──
222 pub use gemini_adk_rs::tool::{
223 SimpleTool, ToolDispatcher, ToolFunction, ToolPolicy, TypedTool,
224 };
225 // The `#[tool]` attribute macro — turns an `async fn` into a registrable tool.
226 pub use gemini_adk_rs::tool;
227 // Brings in both the `Extract` struct and the `#[derive(Extract)]` macro.
228 pub use gemini_adk_rs::Extract;
229 // The `#[derive(Frame)]` macro.
230 pub use gemini_adk_rs::Frame;
231
232 // ── Callback contexts (used in `M::` hooks) ──
233 pub use gemini_adk_rs::context::{CallbackContext, ToolContext};
234
235 // ── Common Live session types (full control plane in `crate::live`) ──
236 pub use gemini_adk_rs::live::{
237 ContextDelivery, EventCallbacks, ExtractionTrigger, FsPersistence, LiveHandle,
238 LlmExtractor, MemoryPersistence, PersistenceError, RepairConfig, SessionPersistence,
239 SoftTurnDetector, SteeringMode, TranscriptBuffer, TranscriptTurn, TurnExtractor,
240 };
241
242 // ── Text-agent combinators (runtime details in `crate::text`) ──
243 pub use gemini_adk_rs::text::{
244 DispatchTextAgent, FallbackTextAgent, FnTextAgent, JoinTextAgent, LlmTextAgent,
245 LoopTextAgent, MapOverTextAgent, ParallelTextAgent, RaceTextAgent, RouteRule,
246 RouteTextAgent, SequentialTextAgent, TapTextAgent, TaskRegistry, TextAgent,
247 TimeoutTextAgent,
248 };
249
250 // ── L0 wire protocol (ModelId, Voice, Content, Part, Role, …) ──
251 pub use gemini_genai_rs::prelude::*;
252}