1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//! Wire types for the [AG-UI](https://docs.ag-ui.com) 1.0 protocol, part of
//! the [Everruns](https://everruns.com) ecosystem.
//!
//! AG-UI is the event protocol between an agent and the application that
//! renders it: the application posts a [`RunAgentInput`](crate::ag_ui::RunAgentInput), the agent answers
//! with a stream of [`Event`]s (usually over SSE).
//!
//! ```
//! use everruns_core::ag_ui::{Event, RunFinishedEvent, RunFinishedOutcome, RunStartedEvent};
//!
//! let started = Event::RunStarted(
//! RunStartedEvent::new("thread-1", "run-1").with_protocol_version(),
//! );
//! let finished = Event::RunFinished(
//! RunFinishedEvent::new("thread-1", "run-1").with_outcome(RunFinishedOutcome::Cancelled),
//! );
//!
//! assert_eq!(
//! serde_json::to_value(&started).unwrap(),
//! serde_json::json!({
//! "type": "RUN_STARTED",
//! "threadId": "thread-1",
//! "runId": "run-1",
//! "protocolVersion": "1.0",
//! }),
//! );
//! assert_eq!(
//! serde_json::to_value(&finished).unwrap()["outcome"],
//! serde_json::json!({ "type": "cancelled" }),
//! );
//! ```
//!
//! # Modules
//!
//! - The wire types, at this module’s root (feature `ag-ui`).
//! - [`consumer`](crate::ag_ui::consumer): the consumer side of the protocol. It decodes a
//! producer's events, enforces the 1.0 sequencing rules and assembles a
//! [`consumer::RunResult`](crate::ag_ui::consumer::RunResult); [`ResumeBuilder`](crate::ag_ui::ResumeBuilder) answers interrupts.
//! - `client` (feature `ag-ui-client`): an HTTP client that runs an AG-UI agent
//! over SSE and feeds the consumer.
//! - `projection` (feature `ag-ui-projection`): Everruns runtime events as an AG-UI run.
//!
//! # Contract
//!
//! - The types follow the pinned upstream schema in `spec/1.0/schema.json`;
//! the upstream fixture corpus in `spec/1.0/fixtures` is this crate's test
//! suite.
//! - **Absent means absent.** Optional fields serialize as omitted, never as
//! `null`, so everything this crate emits validates against the schema.
//! - **Tolerant on input.** Deserialization ignores unknown fields and reads a
//! historical whole-field `null` (`forwardedProps`, `parentMessageId`, ...)
//! as absent, which is how 1.0 consumers treat 0.x producers.
//! - Fields the schema leaves open (`result`, `payload`, `state`, tool
//! `parameters`) are [`serde_json::Value`]. The schema forbids `null` for
//! them, so leave them `None` rather than `Some(Value::Null)`.
// Decision: hand-written serde types rather than code generated from the
// schema. The schema leans on `allOf` + `unevaluatedProperties` and `const`
// discriminators that Rust generators turn into unidiomatic types, and the
// upstream fixtures plus schema validation of everything we serialize (see
// `tests/spec.rs`) catch drift as well as generation would.
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
/// The AG-UI protocol version these types implement.
pub const PROTOCOL_VERSION: &str = "1.0";
/// Open-by-key metadata carried by events, messages and interrupts.
///
/// Per key, last write wins and merges never recurse. The `ag-ui` key is
/// reserved for the protocol.
pub type Metadata = Map;
/// The upstream JSON Schema these types implement, verbatim.
pub const SCHEMA_JSON: &str = include_str!;