serve/lib.rs
1//! # serve (experimental)
2//!
3//! An agent framework in the style of [Topcoat], with hosting modelled on
4//! [eve], built on the `everruns` runtime. It is part of the
5//! [Everruns](https://everruns.com) ecosystem.
6//!
7//! > **Experimental.** serve is a proof of concept. Every API here may change
8//! > or disappear; it is published as `everruns-serve` but not covered by
9//! > the everruns stability policy.
10//!
11//! ```no_run
12//! use serve::prelude::*;
13//!
14//! /// Rolls dice for board-game nights.
15//! #[agent]
16//! fn assistant() -> Agent {
17//! Agent::builder()
18//! .model("anthropic/claude-sonnet-5")
19//! .instructions("Roll dice when asked.")
20//! .build()
21//! }
22//!
23//! /// Roll one die with the given number of sides.
24//! #[tool]
25//! async fn roll_dice(cx: &Cx, sides: u32) -> Result<u32> {
26//! cx.progress(format!("rolling a d{sides}")).await;
27//! Ok(sides)
28//! }
29//!
30//! #[tokio::main]
31//! async fn main() -> serve::Result {
32//! serve::start(App::builder().discover().build()).await
33//! }
34//! ```
35//!
36//! A real app also calls `serve::assets!()` once and embeds `agent/**` with
37//! `serve_build::embed()` in `build.rs`, so prompts and skills can live in
38//! Markdown files (see `md!`).
39//!
40//! The pieces:
41//!
42//! - **Attribute macros** ([`agent`], [`tool`], [`channel`], [`schedule`],
43//! [`connection`], [`eval`]) register items at link time.
44//! - **[`App::builder().discover()`](AppBuilder::discover)** collects them,
45//! validates the file-layout conventions, and resolves `agent/**` assets
46//! embedded by `serve-build`.
47//! - **[`Manifest`]** is what the build declares and the host provides:
48//! schedules, channel routes, secrets, the sandbox, model strings.
49//! - **[`Cx`]** is the one context type: the tool call (session, turn, call
50//! id, progress), connections, secrets, starting sessions.
51//! - **[`start`]** runs the binary as `dev`, `start`, `manifest`, `eval` or
52//! `deploy`, serving everywhere the same `/v1` wire API, a subset of the
53//! everruns server's session API (so the everruns SDK can drive it).
54//!
55//! [Topcoat]: https://github.com/tokio-rs/topcoat
56//! [eve]: https://vercel.com/docs/eve
57
58#![cfg_attr(test, allow(clippy::unwrap_used, clippy::expect_used))]
59
60// Lets the macros' `::serve::…` paths resolve in this crate's own tests.
61extern crate self as serve;
62
63#[cfg(feature = "a2a")]
64mod a2a;
65#[cfg(feature = "ag-ui")]
66mod ag_ui;
67mod agent;
68mod app;
69mod channel;
70mod cli;
71mod config;
72mod connection;
73mod cx;
74mod eval;
75mod gateway;
76mod host;
77mod hosting;
78mod manifest;
79mod registry;
80mod scheduler;
81mod server;
82mod store;
83#[cfg(test)]
84mod wire_tests;
85
86pub use agent::{Agent, AgentBuilder, Instructions, Markdown};
87pub use app::{App, AppBuilder, Mode};
88pub use channel::{Channel, ChannelEvent, Inbound, Slack, Webhook};
89pub use cli::start;
90pub use config::{AppConfig, SandboxKind};
91pub use connection::{McpServer, Secret};
92pub use cx::{Cx, DeliveryTarget, StartSession};
93pub use eval::{EvalCx, EvalReport, EvalResult, OnApproval, TurnCheck, TurnRecord};
94pub use hosting::{MicroVm, Server, ServerBuilder, data_dir};
95pub use manifest::Manifest;
96
97pub use serve_macros::{agent, channel, connection, eval, schedule, tool};
98
99/// Simulated models for running agents offline, re-exported from `everruns`.
100pub mod sim {
101 pub use everruns::{LlmSimConfig, OnExhausted, SimToolCall, SimTurn};
102
103 /// A scripted simulator that replays `turns` for every user message: tool
104 /// calls first, then the reply. Loops, so each message sees the same
105 /// script. Used when no model gateway is configured.
106 pub fn script(turns: impl IntoIterator<Item = SimTurn>) -> LlmSimConfig {
107 LlmSimConfig::scripted(turns.into_iter().collect()).with_on_exhausted(OnExhausted::Loop)
108 }
109
110 /// A scripted tool call for [`script`].
111 pub fn call(name: impl Into<String>, arguments: serde_json::Value) -> SimTurn {
112 SimTurn::ToolCalls(vec![SimToolCall {
113 name: name.into(),
114 arguments,
115 id: None,
116 }])
117 }
118
119 /// A scripted assistant reply for [`script`].
120 pub fn reply(text: impl Into<String>) -> SimTurn {
121 SimTurn::Assistant(text.into())
122 }
123}
124
125/// The error type used across serve. Anything `std::error::Error` converts
126/// into it with `?`.
127pub type Error = anyhow::Error;
128
129/// `Result` with serve's [`Error`]. `-> Result` alone means `Result<()>`.
130pub type Result<T = (), E = Error> = std::result::Result<T, E>;
131
132/// Everything an application file usually imports.
133pub mod prelude {
134 pub use crate::{
135 Agent, App, Channel, Cx, DeliveryTarget, EvalCx, McpServer, Result, Secret, Slack, Webhook,
136 agent, channel, connection, eval, md, schedule, tool,
137 };
138 pub use anyhow::{anyhow, bail, ensure};
139 pub use serde::{Deserialize, Serialize};
140 pub use serde_json::json;
141}
142
143/// Include the assets `serve_build::embed()` generated for this crate.
144///
145/// Call once, at the crate root. Without it `agent/**` files are not in the
146/// binary and `discover()` reports them missing.
147#[macro_export]
148macro_rules! assets {
149 () => {
150 include!(concat!(env!("OUT_DIR"), "/serve_assets.rs"));
151 $crate::__private::inventory::submit! {
152 $crate::__private::AppInfoRegistration {
153 name: env!("CARGO_PKG_NAME"),
154 version: env!("CARGO_PKG_VERSION"),
155 }
156 }
157 };
158}
159
160/// Embed a Markdown file from this crate's `agent/` directory.
161///
162/// The text is compiled in (so a missing file is a build error), and in `dev`
163/// mode it is re-read from disk on every new session, so prompt edits
164/// hot-reload without a rebuild.
165#[macro_export]
166macro_rules! md {
167 ($path:literal) => {
168 $crate::Markdown::__embedded(
169 $path,
170 include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/agent/", $path)),
171 concat!(env!("CARGO_MANIFEST_DIR"), "/agent/", $path),
172 )
173 };
174}
175
176/// Runtime support for macro expansions. Not an API.
177#[doc(hidden)]
178pub mod __private {
179 pub use crate::registry::*;
180 pub use futures::future::BoxFuture;
181 pub use inventory;
182 pub use schemars;
183 pub use serde;
184 pub use serde_json::Value;
185}