Skip to main content

rullama_a2a/
streaming.rs

1//! Streaming event types for A2A.
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use uuid::Uuid;
6
7use crate::task::{Task, TaskStatus};
8use crate::types::{Artifact, Message};
9
10/// Event notifying a change in task status.
11#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
12pub struct TaskStatusUpdateEvent {
13    /// Task identifier.
14    #[serde(rename = "taskId")]
15    pub task_id: String,
16    /// Context identifier.
17    #[serde(rename = "contextId")]
18    pub context_id: String,
19    /// New task status.
20    pub status: TaskStatus,
21    /// Trace ID for cross-system correlation. Matches the `trace_id` stamped by
22    /// the originating `TaskAgent` and carried in `AuditEvent.metadata["trace_id"]`.
23    #[serde(rename = "traceId", skip_serializing_if = "Option::is_none")]
24    pub trace_id: Option<Uuid>,
25    /// Monotonically increasing sequence number within the trace.
26    /// Allows receivers to detect and reorder out-of-order events.
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub sequence: Option<u64>,
29    /// Optional metadata.
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub metadata: Option<HashMap<String, serde_json::Value>>,
32}
33
34/// Event notifying an artifact update.
35#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
36pub struct TaskArtifactUpdateEvent {
37    /// Task identifier.
38    #[serde(rename = "taskId")]
39    pub task_id: String,
40    /// Context identifier.
41    #[serde(rename = "contextId")]
42    pub context_id: String,
43    /// The artifact.
44    pub artifact: Artifact,
45    /// Index of this artifact within the task's artifact list.
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub index: Option<u32>,
48    /// If true, append to previously sent artifact with same ID.
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub append: Option<bool>,
51    /// If true, this is the final chunk.
52    #[serde(rename = "lastChunk", skip_serializing_if = "Option::is_none")]
53    pub last_chunk: Option<bool>,
54    /// Trace ID for cross-system correlation.
55    #[serde(rename = "traceId", skip_serializing_if = "Option::is_none")]
56    pub trace_id: Option<Uuid>,
57    /// Monotonically increasing sequence number within the trace.
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub sequence: Option<u64>,
60    /// Optional metadata.
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub metadata: Option<HashMap<String, serde_json::Value>>,
63}
64
65/// Wrapper-based stream response (exactly one field should be set).
66#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
67pub struct StreamResponse {
68    /// Full task snapshot.
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub task: Option<Task>,
71    /// Agent message.
72    #[serde(skip_serializing_if = "Option::is_none")]
73    pub message: Option<Message>,
74    /// Task status change.
75    #[serde(skip_serializing_if = "Option::is_none", rename = "statusUpdate")]
76    pub status_update: Option<TaskStatusUpdateEvent>,
77    /// Artifact update.
78    #[serde(skip_serializing_if = "Option::is_none", rename = "artifactUpdate")]
79    pub artifact_update: Option<TaskArtifactUpdateEvent>,
80}
81
82/// Response for `message/send` — wrapper-based (exactly one field should be set).
83#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
84pub struct SendMessageResponse {
85    /// A task was created or updated.
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub task: Option<Task>,
88    /// A direct message response.
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub message: Option<Message>,
91}