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}