diff --git a/Cargo.toml b/Cargo.toml index 105470c1..22cc91a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ unstable = [ "unstable_session_model", "unstable_session_resume", "unstable_session_usage", + "unstable_message_id", ] unstable_cancel_request = [] unstable_session_fork = [] @@ -30,6 +31,7 @@ unstable_session_list = [] unstable_session_model = [] unstable_session_resume = [] unstable_session_usage = [] +unstable_message_id = [] [[bin]] name = "generate" diff --git a/src/agent.rs b/src/agent.rs index 1c5d671b..134b9e5c 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -1950,6 +1950,18 @@ impl HttpHeader { pub struct PromptRequest { /// The ID of the session to send this user message to pub session_id: SessionId, + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// A client-generated unique identifier for this user message. + /// + /// If provided, the Agent SHOULD echo this value as `userMessageId` in the + /// [`PromptResponse`] to confirm it was recorded. + /// Both clients and agents MUST use UUID format for message IDs. + #[cfg(feature = "unstable_message_id")] + #[serde(skip_serializing_if = "Option::is_none")] + pub message_id: Option, /// The blocks of content that compose the user's message. /// /// As a baseline, the Agent MUST support [`ContentBlock::Text`] and [`ContentBlock::ResourceLink`], @@ -1978,11 +1990,29 @@ impl PromptRequest { pub fn new(session_id: impl Into, prompt: Vec) -> Self { Self { session_id: session_id.into(), + #[cfg(feature = "unstable_message_id")] + message_id: None, prompt, meta: None, } } + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// A client-generated unique identifier for this user message. + /// + /// If provided, the Agent SHOULD echo this value as `userMessageId` in the + /// [`PromptResponse`] to confirm it was recorded. + /// Both clients and agents MUST use UUID format for message IDs. + #[cfg(feature = "unstable_message_id")] + #[must_use] + pub fn message_id(mut self, message_id: impl IntoOption) -> Self { + self.message_id = message_id.into_option(); + self + } + /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -2003,6 +2033,18 @@ impl PromptRequest { #[serde(rename_all = "camelCase")] #[non_exhaustive] pub struct PromptResponse { + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// The acknowledged user message ID. + /// + /// If the client provided a `messageId` in the [`PromptRequest`], the agent echoes it here + /// to confirm it was recorded. If the client did not provide one, the agent MAY assign one + /// and return it here. Absence of this field indicates the agent did not record a message ID. + #[cfg(feature = "unstable_message_id")] + #[serde(skip_serializing_if = "Option::is_none")] + pub user_message_id: Option, /// Indicates why the agent stopped processing the turn. pub stop_reason: StopReason, /// **UNSTABLE** @@ -2026,6 +2068,8 @@ impl PromptResponse { #[must_use] pub fn new(stop_reason: StopReason) -> Self { Self { + #[cfg(feature = "unstable_message_id")] + user_message_id: None, stop_reason, #[cfg(feature = "unstable_session_usage")] usage: None, @@ -2033,6 +2077,22 @@ impl PromptResponse { } } + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// The acknowledged user message ID. + /// + /// If the client provided a `messageId` in the [`PromptRequest`], the agent echoes it here + /// to confirm it was recorded. If the client did not provide one, the agent MAY assign one + /// and return it here. Absence of this field indicates the agent did not record a message ID. + #[cfg(feature = "unstable_message_id")] + #[must_use] + pub fn user_message_id(mut self, user_message_id: impl IntoOption) -> Self { + self.user_message_id = user_message_id.into_option(); + self + } + /// **UNSTABLE** /// /// This capability is not part of the spec yet, and may be removed or changed at any point. diff --git a/src/client.rs b/src/client.rs index dada5581..a5f19f1b 100644 --- a/src/client.rs +++ b/src/client.rs @@ -330,6 +330,18 @@ impl Cost { pub struct ContentChunk { /// A single item of content pub content: ContentBlock, + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// A unique identifier for the message this chunk belongs to. + /// + /// All chunks belonging to the same message share the same `messageId`. + /// A change in `messageId` indicates a new message has started. + /// Both clients and agents MUST use UUID format for message IDs. + #[cfg(feature = "unstable_message_id")] + #[serde(skip_serializing_if = "Option::is_none")] + pub message_id: Option, /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -344,10 +356,28 @@ impl ContentChunk { pub fn new(content: ContentBlock) -> Self { Self { content, + #[cfg(feature = "unstable_message_id")] + message_id: None, meta: None, } } + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// A unique identifier for the message this chunk belongs to. + /// + /// All chunks belonging to the same message share the same `messageId`. + /// A change in `messageId` indicates a new message has started. + /// Both clients and agents MUST use UUID format for message IDs. + #[cfg(feature = "unstable_message_id")] + #[must_use] + pub fn message_id(mut self, message_id: impl IntoOption) -> Self { + self.message_id = message_id.into_option(); + self + } + /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. diff --git a/src/rpc.rs b/src/rpc.rs index 973af7f2..eb2bdc10 100644 --- a/src/rpc.rs +++ b/src/rpc.rs @@ -436,6 +436,8 @@ fn test_notification_wire_format() { text: "Hello".to_string(), meta: None, }), + #[cfg(feature = "unstable_message_id")] + message_id: None, meta: None, }), meta: None,