ag_ui/input.rs
1//! The request body an agent receives to start or resume a run.
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use crate::context::Context;
7use crate::ids::{RunId, ThreadId};
8use crate::message::Message;
9use crate::outcome::ResumeEntry;
10use crate::tool::Tool;
11
12/// Everything an agent needs for one run.
13///
14/// This is the body of the AG-UI run request, and it is also embedded verbatim
15/// in [`RunStartedEvent::input`](crate::event::RunStartedEvent::input) so a
16/// recorded stream can be replayed without the original request.
17#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
18#[serde(rename_all = "camelCase")]
19#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
20#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
21pub struct RunAgentInput {
22 /// The conversation this run belongs to.
23 pub thread_id: ThreadId,
24 /// This run's id, echoed on every lifecycle event.
25 pub run_id: RunId,
26 /// The run that spawned this one, for nested / delegated agents.
27 #[serde(default, skip_serializing_if = "Option::is_none")]
28 pub parent_run_id: Option<RunId>,
29 /// Shared state, mutated by the agent through `STATE_SNAPSHOT` and
30 /// `STATE_DELTA`. Free-form JSON, opaque to the protocol.
31 #[serde(default)]
32 pub state: Value,
33 /// Conversation history, oldest first.
34 pub messages: Vec<Message>,
35 /// Tools the client is offering for this run.
36 pub tools: Vec<Tool>,
37 /// Ambient context entries.
38 pub context: Vec<Context>,
39 /// Arbitrary passthrough properties, opaque to the protocol.
40 #[serde(default)]
41 pub forwarded_props: Value,
42 /// Answers to the interrupts a previous run paused on. Present only when
43 /// resuming — see [`crate::outcome`].
44 #[serde(default, skip_serializing_if = "Option::is_none")]
45 pub resume: Option<Vec<ResumeEntry>>,
46}
47
48impl RunAgentInput {
49 /// Builds an input with only the two required identifiers set.
50 pub fn new(thread_id: impl Into<ThreadId>, run_id: impl Into<RunId>) -> Self {
51 Self {
52 thread_id: thread_id.into(),
53 run_id: run_id.into(),
54 ..Default::default()
55 }
56 }
57
58 /// Whether this request resumes a paused run.
59 pub fn is_resume(&self) -> bool {
60 self.resume.as_ref().is_some_and(|r| !r.is_empty())
61 }
62}