Skip to main content

localharness/
lib.rs

1//! # localharness — Rust-native agent SDK for Gemini
2//!
3//! Build production agents with streaming text, custom tools, safety
4//! policies, and background triggers — all from a single `cargo add`,
5//! zero external binaries.
6//!
7//! ## Quick start
8//!
9//! ```rust,no_run
10//! use localharness::{Agent, GeminiAgentConfig};
11//!
12//! # async fn run() -> localharness::Result<()> {
13//! let cfg = GeminiAgentConfig::new(std::env::var("GEMINI_API_KEY").unwrap())
14//!     .with_system_instructions("You are a concise code reviewer.");
15//!
16//! let agent = Agent::start_gemini(cfg).await?;
17//! let response = agent.chat("What is 2+2?").await?;
18//! println!("{}", response.text().await?);
19//! agent.shutdown().await?;
20//! # Ok(())
21//! # }
22//! ```
23//!
24//! ## Layers
25//!
26//! | Layer | Type | Purpose |
27//! |-------|------|---------|
28//! | 1 | [`Agent`] | High-level facade: connect, chat, shutdown. |
29//! | 2 | [`Conversation`] / [`ChatResponse`] | Stateful session, multi-cursor streams. |
30//! | 3 | [`connections::Connection`] | Transport abstraction. |
31//! | aux | [`Filesystem`] | What the 6 fs-shaped built-in tools call into; swap the impl to target OPFS, an in-memory FS, etc. |
32//!
33//! [`Agent`]: agent::Agent
34//! [`Conversation`]: conversation::Conversation
35//! [`ChatResponse`]: conversation::ChatResponse
36//! [`connections::Connection`]: connections::Connection
37//! [`Filesystem`]: filesystem::Filesystem
38
39// On wasm32 the upper architecture (Agent → Conversation → Connection)
40// is temporarily gated behind `native` because its trait bounds require
41// `Send` futures, which reqwest's browser fetch can't satisfy. The wasm
42// surface exposes `error`, `content`, `types`, and the low-level
43// `backends::gemini::api::GeminiClient` so a web demo can drive the
44// Gemini REST API directly. Lifting the gate is M2.5: thread a
45// `MaybeSend` shim through the Tool/Connection/Hook traits.
46pub mod agent;
47pub mod backends;
48pub mod connections;
49pub mod content;
50pub mod conversation;
51pub mod error;
52pub mod filesystem;
53pub(crate) mod runtime;
54pub mod hooks;
55pub mod policy;
56pub mod tools;
57pub mod triggers;
58pub mod types;
59
60// The browser-resident IDE. Gated on the `browser-app` feature AND a
61// wasm target, so a native `cargo add localharness` never compiles it.
62#[cfg(all(feature = "browser-app", target_arch = "wasm32"))]
63mod app;
64
65// M6 spike: in-browser secp256k1 keypair via alloy's local signer.
66// Pure-compute (no HTTP, no JS deps), so it builds on every target.
67#[cfg(feature = "wallet")]
68pub mod wallet;
69
70// JSON-RPC client for the `LocalharnessRegistry` diamond on Tempo
71// Moderato. Read-only views (`check_name`, `owner_of_name`,
72// `tba_of_name`, `list_owned_tokens`) work on every target;
73// `claim_name` signs with a `k256` key (needs the wallet feature)
74// and uses `tokio::time::sleep` on native / `setTimeout` on wasm to
75// poll the receipt. The diamond's address is baked in as
76// `registry::REGISTRY_ADDRESS`; the RPC URL is `registry::RPC_URL`.
77#[cfg(feature = "wallet")]
78pub mod registry;
79
80// Tempo Transaction encoder (tx type 0x76). Implements Tempo's native
81// account-abstraction tx format so users can pay fees in $LH instead
82// of native and so a project-controlled fee_payer can sponsor user
83// txs without users holding any balance. Wire format per
84// docs.tempo.xyz/protocol/transactions/spec-tempo-transaction.
85#[cfg(feature = "wallet")]
86pub mod tempo_tx;
87
88pub use agent::{Agent, AgentConfig, GeminiAgentConfig};
89pub use backends::gemini::{
90    decode_transcript_bytes, GeminiBackendConfig, GeminiConnection, GeminiConnectionStrategy,
91};
92#[cfg(feature = "native")]
93pub use backends::mcp::{McpBridge, McpClient, McpToolDecl};
94pub use connections::{Connection, ConnectionStrategy};
95pub use content::{Content, Media, MediaKind, Part};
96pub use conversation::{ChatCursor, ChatResponse, Conversation};
97pub use error::{Error, Result};
98pub use filesystem::{DirEntry, EntryKind, Filesystem, Metadata, SharedFilesystem, WalkEntry};
99#[cfg(feature = "native")]
100pub use filesystem::NativeFilesystem;
101pub use hooks::{
102    HookContext, HookRunner, OnSessionEndHook, OnSessionStartHook, OperationContext,
103    PostToolCallHook, PostTurnHook, PreToolCallDecideHook, PreTurnHook, SessionContext,
104    TurnContext,
105};
106pub use policy::{
107    allow_all, deny_all, enforce, evaluate, is_path_in_workspace, secure_normalize_path,
108    workspace_only, AskUserHandler, Decision, Policy, Predicate,
109};
110pub use tools::{ClosureTool, Tool, ToolContext, ToolRunner};
111pub use triggers::{every, Trigger, TriggerContext, TriggerRunner};
112pub use types::{
113    BuiltinTool, CapabilitiesConfig, GeminiConfig, GenerationConfig, HookResult, ModelConfig,
114    ModelEntry, Step, StepSource, StepStatus, StepTarget, StepType, StreamChunk,
115    SystemInstructions, ThinkingLevel, ToolCall, ToolResult, TranscriptEntry, TranscriptRole,
116    TriggerDelivery, UsageMetadata,
117};