Skip to main content

systemprompt_models/agui/
payloads.rs

1//! Event payload types for the AG-UI streaming protocol.
2//!
3//! Each struct here is the body of one AG-UI event — run lifecycle
4//! (`RunStarted`/`RunFinished`/`RunError`), step boundaries, streaming text and
5//! tool-call deltas, state snapshots/deltas, and the [`CustomPayload`] envelope
6//! for application-defined events (artifacts, execution steps, loaded skills).
7//! Field casing follows the wire format via `rename_all = "camelCase"`.
8
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11use systemprompt_identifiers::{AiToolCallId, ContextId, MessageId, TaskId};
12
13use super::JsonPatchOperation;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
16#[serde(rename_all = "lowercase")]
17pub enum MessageRole {
18    User,
19    Assistant,
20    System,
21    Tool,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
25#[serde(rename_all = "camelCase")]
26pub struct RunStartedPayload {
27    pub thread_id: ContextId,
28    pub run_id: TaskId,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub input: Option<Value>,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
34#[serde(rename_all = "camelCase")]
35pub struct RunFinishedPayload {
36    pub thread_id: ContextId,
37    pub run_id: TaskId,
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub result: Option<Value>,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
43#[serde(rename_all = "camelCase")]
44pub struct RunErrorPayload {
45    pub message: String,
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub code: Option<String>,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
51#[serde(rename_all = "camelCase")]
52pub struct StepStartedPayload {
53    pub step_name: String,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize)]
57#[serde(rename_all = "camelCase")]
58pub struct StepFinishedPayload {
59    pub step_name: String,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
63#[serde(rename_all = "camelCase")]
64pub struct TextMessageStartPayload {
65    pub message_id: MessageId,
66    pub role: MessageRole,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
70#[serde(rename_all = "camelCase")]
71pub struct TextMessageContentPayload {
72    pub message_id: MessageId,
73    pub delta: String,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize)]
77#[serde(rename_all = "camelCase")]
78pub struct TextMessageEndPayload {
79    pub message_id: MessageId,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
83#[serde(rename_all = "camelCase")]
84pub struct ToolCallStartPayload {
85    pub tool_call_id: AiToolCallId,
86    pub tool_call_name: String,
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub parent_message_id: Option<MessageId>,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
92#[serde(rename_all = "camelCase")]
93pub struct ToolCallArgsPayload {
94    pub tool_call_id: AiToolCallId,
95    pub delta: String,
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
99#[serde(rename_all = "camelCase")]
100pub struct ToolCallEndPayload {
101    pub tool_call_id: AiToolCallId,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
105#[serde(rename_all = "camelCase")]
106pub struct ToolCallResultPayload {
107    pub message_id: MessageId,
108    pub tool_call_id: AiToolCallId,
109    pub content: Value,
110    pub role: MessageRole,
111}
112
113#[derive(Debug, Clone, Serialize, Deserialize)]
114#[serde(rename_all = "camelCase")]
115pub struct StateSnapshotPayload {
116    pub snapshot: Value,
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize)]
120#[serde(rename_all = "camelCase")]
121pub struct StateDeltaPayload {
122    pub delta: Vec<JsonPatchOperation>,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
126#[serde(rename_all = "camelCase")]
127pub struct MessagesSnapshotPayload {
128    pub messages: Vec<Value>,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize)]
132#[serde(rename_all = "camelCase")]
133pub struct ArtifactCustomPayload {
134    pub artifact: crate::a2a::Artifact,
135    pub task_id: TaskId,
136    pub context_id: ContextId,
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize)]
140#[serde(rename_all = "camelCase")]
141pub struct ExecutionStepCustomPayload {
142    pub step: crate::execution::ExecutionStep,
143    pub context_id: ContextId,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
147#[serde(rename_all = "camelCase")]
148pub struct SkillLoadedCustomPayload {
149    pub skill_id: systemprompt_identifiers::SkillId,
150    pub skill_name: String,
151    #[serde(skip_serializing_if = "Option::is_none")]
152    pub description: Option<String>,
153    #[serde(skip_serializing_if = "Option::is_none")]
154    pub task_id: Option<TaskId>,
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize)]
158#[serde(rename_all = "camelCase")]
159pub struct GenericCustomPayload {
160    pub name: String,
161    pub value: Value,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
165#[serde(tag = "name", content = "value", rename_all = "snake_case")]
166pub enum CustomPayload {
167    Artifact(Box<ArtifactCustomPayload>),
168    ExecutionStep(Box<ExecutionStepCustomPayload>),
169    SkillLoaded(SkillLoadedCustomPayload),
170    #[serde(untagged)]
171    Generic(GenericCustomPayload),
172}