Skip to main content

tinyagents/
lib.rs

1//! # TinyAgents — a recursive language-model (RLM) harness for Rust
2//!
3//! TinyAgents is a typed, durable runtime where **language models call models,
4//! agents call agents, and graphs run graphs** — and where a model can author,
5//! compile, and run the very workflow it is standing inside, all as inspectable,
6//! checkpointed, policy-checked Rust.
7//!
8//! The "recursive" framing is the through-line of the whole crate, not a
9//! footnote. It is architected around the execution model described in
10//! "Recursive Language Models" (Alex L. Zhang, Tim Kraska, Omar Khattab, MIT
11//! CSAIL, 2025; <https://arxiv.org/abs/2512.24601>): rather than stuffing
12//! everything into one context window, a model treats long context as an
13//! external *environment* it interacts with through a REPL — examining,
14//! decomposing, and recursively calling sub-models over snippets. TinyAgents
15//! brings that idea to Rust as a production-shaped harness (sub-model /
16//! sub-agent / sub-graph calls as functions, persistent session values, depth
17//! tracking, and trajectory/event logging). It is *inspired by and architected
18//! around* the RLM execution model, not a reimplementation of the paper's
19//! benchmarks.
20//!
21//! ## The five surfaces
22//!
23//! 1. **Harness** ([`harness`]) — provider-neutral model calls, typed tools,
24//!    middleware, structured output, streaming, usage/cost, retry/limits, cache,
25//!    memory/embeddings, sub-agents, steering, and a testkit.
26//! 2. **Graph runtime** ([`graph`]) — LangGraph-style durable typed state
27//!    graphs: [`START`]/[`END`], nodes, conditional routing, [`Command`]s,
28//!    fan-out, reducers/channels, [`Checkpoint`]s, [`Interrupt`]s, subgraphs,
29//!    streaming, topology export, and per-thread productivity primitives — a
30//!    durable [`ThreadGoal`] with graph-native continuation and a
31//!    [`TaskBoard`] kanban — exposed as harness tools.
32//! 3. **Registry** ([`registry`]) — a named capability catalog (models, tools,
33//!    agents, graphs, stores, middleware, policy) that `.rag`/`.ragsh` bind by
34//!    name.
35//! 4. **Expressive language `.rag`** ([`language`]) — a declarative,
36//!    side-effect-free blueprint format that compiles (lexer → parser →
37//!    compiler) into the same graph/harness runtime; the safe boundary for
38//!    agent-authored plans.
39//! 5. **REPL language `.ragsh`** ([`repl`]) — imperative, capability-bound
40//!    interactive orchestration; the RLM/CodeAct loop surface.
41//!
42//! ## The recursion story
43//!
44//! Both `.rag` and `.ragsh` lower into the *same* [`graph`] + [`harness`] types
45//! as hand-written Rust — a language whose programs are the runtime that
46//! interprets them. A harness agent can be exposed *as a tool* to another agent
47//! ([`SubAgent`], [`SubAgentTool`], [`SubAgentSession`]), so orchestration is
48//! just a model calling a model; the runtime tracks parent/child run lineage and
49//! enforces a recursion cap ([`TinyAgentsError::SubAgentDepth`]). At the deepest
50//! level a model can emit a `.rag` blueprint that compiles through the same
51//! registry-bound path as a human-authored file and runs on the same runtime the
52//! model is already executing in (see `examples/openai_self_blueprint.rs`).
53//!
54//! ## Provider features
55//!
56//! Hosted and local providers (OpenAI plus the OpenAI-compatible endpoints for
57//! Anthropic, Ollama, DeepSeek, Groq, xAI, OpenRouter, Together, and Mistral)
58//! are compiled in unconditionally alongside the offline, deterministic
59//! [`harness::providers::MockModel`]. Three Cargo features gate optional,
60//! heavier dependencies instead: `sqlite` (embedded SQLite checkpointer,
61//! [`graph::checkpoint::SqliteCheckpointer`]), `repl` (embedded Rhai engine
62//! powering the `.ragsh` session runtime, [`repl::session`]), and `rlm` (the
63//! recursive-language-model runtime: a driver model writes code cells run in
64//! a sandboxed interpreter — embedded Rhai or an external Python/JavaScript
65//! process — whose only host surface is capability calls back into the
66//! registry).
67//!
68//! ## Crate-root re-exports
69//!
70//! For discoverability the most-used types from each surface are re-exported at
71//! the crate root, grouped below by surface ([`error`], [`registry`],
72//! [`language`], [`harness`], and [`graph`]).
73
74pub mod error;
75pub mod graph;
76pub mod harness;
77pub mod language;
78pub mod registry;
79pub mod repl;
80#[cfg(feature = "rlm")]
81pub mod rlm;
82
83// --- Error: the crate-wide error type and `Result` alias ---
84pub use error::{Result, TinyAgentsError};
85
86// --- Registry: named capability catalog (.rag/.ragsh binding by name) ---
87pub use registry::{
88    AliasBinding, CapabilityRegistry, ComponentId, ComponentKind, ComponentMetadata,
89    DiagnosticSeverity, ModelCapabilities, ModelCatalog, ModelCatalogEntry, ModelCatalogSnapshot,
90    ModelCatalogSource, ModelPricing, ModelRouter, RegistryDiagnostic, RegistrySnapshot,
91    WorkloadRoute,
92};
93
94// --- Language: registry → blueprint binding façade ---
95// The strict, registry-backed entry points the REPL and orchestrators use to
96// turn `.rag`/`.ragsh` source into validated blueprints. `compile_source` runs
97// parse -> compile -> registry-bind in one call.
98pub use language::capability_resolver::{
99    CapabilityResolver, bind_capabilities, bind_capabilities_with_registry,
100};
101pub use language::compiler::{compile, compile_source, compile_with_provenance};
102// `Resolver` is the registry-backed binding gate: it resolves every reference in
103// a `.rag` plan (file-backed or model-generated) against the registry, producing
104// spanned diagnostics for unknown/disallowed capabilities. `resolve_source` is
105// the recommended parse -> resolve -> lower façade.
106pub use language::resolver::{Resolver, resolve_source};
107pub use language::types::{
108    Blueprint, BlueprintProvenance, ChannelSpec, CommandSpec, EdgeSpan, EdgeSpec, IoFieldSpec,
109    JoinSpec, NamedSpan, NodeSpec, Origin, Routing, SendSpec,
110};
111// `blueprint_diff` produces a structured, human-readable `BlueprintDiff` of two
112// compiled blueprints — the basis for generated-workflow review and the REPL
113// `graph_diff` builtin. `testkit` holds deterministic compile/assert helpers.
114pub use language::diff::{BlueprintDiff, ChannelDiff, FieldChange, NodeDiff, blueprint_diff};
115pub use language::testkit;
116
117// --- Language: diagnostics, spans, and the source map ---
118// Structured, source-aware errors for `.rag`: a `Diagnostic` (with `Severity`
119// and labelled spans) rendered against a `SourceFile`/`SourceMap` with caret
120// underlines.
121pub use language::diagnostic::{Diagnostic, Label, Severity};
122pub use language::source::{SourceFile, SourceId, SourceMap};
123pub use language::span::Span;
124
125// --- Harness: embeddings + retrieval ---
126pub use harness::embeddings::{
127    EmbeddingModel, InMemoryVectorStore, MockEmbeddingModel, Retriever, ScoredDoc, VectorStore,
128    cosine_similarity,
129};
130
131// --- Harness: first-class sub-agents (agent-calling-agent composition) ---
132pub use harness::subagent::{SubAgent, SubAgentSession, SubAgentTool};
133
134// --- Harness: orchestrator → sub-agent steering ---
135pub use harness::steering::{
136    SteeringCommand, SteeringCommandKind, SteeringHandle, SteeringOutcome, SteeringPolicy,
137};
138
139// --- Cooperative run cancellation ---
140pub use harness::cancel::CancellationToken;
141
142// --- Workspace isolation / sandbox hooks ---
143pub use harness::workspace::{SharedRootWorkspace, WorkspaceDescriptor, WorkspaceIsolation};
144
145// --- Harness: durable observability (journals, status stores, sinks) ---
146pub use harness::observability::{
147    AgentCallLatency, AgentLatencyMetrics, AgentObservation, FanOutSink, HarnessEventJournal,
148    HarnessStatusStore, InMemoryEventJournal, InMemoryStatusStore, JournalSink, JsonlSink,
149    RedactingSink, StoreEventJournal,
150};
151pub use harness::observability::{
152    LangfuseAuth, LangfuseClient, LangfuseScore, LangfuseScoreValue, LangfuseTraceConfig,
153};
154
155// --- Graph: durable execution model (LangGraph-style) ---
156// Re-exported with explicit names so the durable API is discoverable at the
157// crate root. The `harness::stream::StreamMode` and `graph::stream::StreamMode`
158// types intentionally stay behind their module paths to avoid a name clash.
159#[cfg(feature = "sqlite")]
160pub use graph::SqliteCheckpointer;
161pub use graph::{
162    BarrierArrivals, Checkpoint, CheckpointConfig, CheckpointMetadata, CheckpointSource,
163    CheckpointTuple, Checkpointer, ChildRun, ChildRunSink, ClosureReducer, ClosureStateReducer,
164    Command, CompiledGraph, DurabilityMode, END, FileCheckpointer, ForkId, GraphBuilder,
165    GraphDefaults, GraphEvent, GraphExecution, GraphInput, GraphRunStatus, InMemoryCheckpointer,
166    Interrupt, NodeContext, NodeResult, PendingActivation, RecursionFrame, RecursionPolicy,
167    RecursionStack, Reducer, ResumeTarget, Route, RouteTarget, RunTree, START, StateReducer,
168    StateSnapshot,
169};
170
171// --- Graph: sub-agent nodes (delegate a graph step to a registered agent) ---
172pub use graph::{
173    HarnessAgent, HarnessSubAgent, SubAgentBudget, SubAgentInput, SubAgentNode, SubAgentOutput,
174    SubAgentPolicy, subagent_node,
175};
176
177// --- Graph: channel-per-field state model (additive; see state-channels.md) ---
178// An opt-in alternative to the monolithic State + StateReducer path: state is
179// split into independently-merged named channels.
180pub use graph::{
181    Barrier, BinaryAggregate, Channel, ChannelSet, ChannelState, ChannelUpdate, Delta, Ephemeral,
182    LastValue, Messages, NamedBarrier, Topic, Untracked,
183};
184
185// --- Graph: durable observability (journals, status stores, journaling sink) ---
186// Names are graph-prefixed so they never collide with the harness observability
187// re-exports above.
188pub use graph::{
189    GraphEventJournal, GraphHealthSummary, GraphLangfuseExporter, GraphLatencyMetrics,
190    GraphNodeHealth, GraphNodeLatency, GraphObservation, GraphStatusStore, GraphStepLatency,
191    InMemoryGraphEventJournal, InMemoryGraphStatusStore, JournalGraphSink, SpanMetadataFn,
192    StoreGraphEventJournal,
193};
194
195// --- Graph: orchestration tools (ordinary harness Tool implementations) ---
196pub use graph::{
197    InMemoryTaskStore, JsonlTaskStore, OrchestrationControlOutcome, OrchestrationTaskFilter,
198    OrchestrationTaskKind, OrchestrationTaskRecord, OrchestrationTaskResult, OrchestrationTaskSpec,
199    OrchestrationTaskStatus, OrchestrationTool, OrchestrationToolKind, SteeringRegistry, TaskStore,
200    orchestration_tool_schema, orchestration_tool_schemas, orchestration_tools,
201    orchestration_tools_with_steering, register_orchestration_tools,
202};
203
204// --- Graph: per-thread goal (durable objective + graph-native continuation) ---
205// `goal_store` is the programmatic CRUD surface (get/set/complete/account_usage);
206// the tools and continuation helpers are re-exported flat for discoverability.
207pub use graph::goals::store as goal_store;
208pub use graph::{
209    GoalProgress, GoalTool, GoalToolKind, ThreadGoal, ThreadGoalStatus, TurnOutcome,
210    active_goal_context_block, goal_gate_node, goal_tools, note_user_turn, register_goal_tools,
211    run_continuation_tick,
212};
213
214// --- Graph: per-thread task board (kanban todos) ---
215// `todo_store` is the programmatic CRUD surface (add/edit/claim_card/...); the
216// tool and data model are re-exported flat for discoverability.
217pub use graph::todos::store as todo_store;
218pub use graph::{
219    CardPatch, TaskApprovalMode, TaskBoard, TaskBoardCard, TaskCardStatus, TodoTool, TodosSnapshot,
220    normalise_board, parse_status, register_todo_tools, render_markdown, todo_tools,
221};
222
223// --- Graph: parallel map/reduce helper ---
224pub use graph::parallel::{
225    FailurePolicy, ItemOutcome, ParallelOptions, ParallelOutcome, map_reduce,
226};
227
228// --- Graph: export / visualization ---
229// Topology types are surfaced at the crate root; the `to_json`/`to_mermaid`
230// free functions stay behind `graph::export::` to avoid generic-name clashes.
231pub use graph::{
232    ChannelInfo, ConditionalEdgeInfo, EdgeInfo, GraphPolicySummary, GraphTopology, NodeInfo,
233    NodePolicySummary, RouteInfo, ValidationReport, WaitingEdgeInfo,
234};
235
236// --- Graph: testkit (deterministic node doubles + run assertions) ---
237// The fluent `assert_graph` builder and node-double constructors stay behind
238// `graph::testkit::` (and are re-exported here) so downstream crates can test
239// graphs without a live model. Names are graph-test specific to avoid clashing
240// with the harness `testkit`.
241pub use graph::testkit::{
242    GraphAssertions, GraphEventRecorder, GraphRun, RetryCountingNode, StreamCollector,
243    assert_graph, failing_node, fanout_node, interrupting_node, noop_node, run_recorded,
244    scripted_route_node, scripted_update_node, subagent_fake_node, subgraph_test_node,
245};
246
247// --- REPL language `.ragsh` Rhai session runtime (feature = "repl") ---
248// The imperative orchestration surface. Gated behind the `repl` feature so the
249// default build does not pull in the embedded Rhai engine. `ReplSession` here is
250// the scripting session from `repl::session`; the line-oriented command session
251// remains available as `repl::ReplSession`.
252#[cfg(feature = "repl")]
253pub use repl::session::{
254    LanguageCompiler, ReplCallKind, ReplCallRecord, ReplCancelFlag, ReplCapabilities, ReplPolicy,
255    ReplResult, ReplSession, ReplValue, ReplVariables,
256};
257
258// --- RLM runtime (feature = "rlm") ---
259// The recursive-language-model surface: a driver model writes code cells that
260// run in a sandboxed interpreter (embedded Rhai or an external Python/Node
261// process) whose only host surface is capability calls (`llm`, `tool`,
262// `agent`) back into the registry. Config-driven end to end (`RlmConfig`).
263#[cfg(feature = "rlm")]
264pub use rlm::{
265    CellOutcome, HostCall, InterpreterSpec, RlmCallKind, RlmCallRecord, RlmCancelFlag, RlmConfig,
266    RlmHost, RlmHostApi, RlmInterpreter, RlmOutcome, RlmPolicy, RlmRunner, RlmSession, RlmStep,
267    RlmStopReason, RlmTemplate, TemplateSpec,
268};