Skip to main content

greentic_types/
messaging.rs

1//! Generic channel messaging envelope shared across providers.
2
3use alloc::{collections::BTreeMap, string::String, vec::Vec};
4
5#[cfg(feature = "schemars")]
6use schemars::JsonSchema;
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use crate::{ReplyScope, TenantCtx};
11
12/// Message actor (sender/initiator).
13#[derive(Clone, Debug, PartialEq, Eq)]
14#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
15#[cfg_attr(feature = "schemars", derive(JsonSchema))]
16pub struct Actor {
17    /// Actor identifier in provider space (e.g., slack user id, webex person id).
18    pub id: String,
19    /// Optional actor kind (e.g. "user", "bot", "system").
20    #[cfg_attr(
21        feature = "serde",
22        serde(default, skip_serializing_if = "Option::is_none")
23    )]
24    pub kind: Option<String>,
25}
26
27/// Outbound destination for egress providers.
28#[derive(Clone, Debug, PartialEq, Eq)]
29#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
30#[cfg_attr(feature = "schemars", derive(JsonSchema))]
31pub struct Destination {
32    /// Destination identifier (provider specific; may be composite e.g. "teamId:channelId").
33    pub id: String,
34    /// Optional destination kind (e.g. "chat", "room", "user", "channel", "email", "phone").
35    #[cfg_attr(
36        feature = "serde",
37        serde(default, skip_serializing_if = "Option::is_none")
38    )]
39    pub kind: Option<String>,
40}
41
42/// Collection of metadata entries associated with a channel message.
43pub type MessageMetadata = BTreeMap<String, String>;
44
45/// Generic attachment referenced by a channel message.
46#[derive(Clone, Debug, PartialEq, Eq)]
47#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
48#[cfg_attr(feature = "schemars", derive(JsonSchema))]
49pub struct Attachment {
50    /// MIME type of the attachment (for example `image/png`).
51    pub mime_type: String,
52    /// URL pointing at the attachment payload.
53    pub url: String,
54    /// Optional display name for the attachment.
55    #[cfg_attr(
56        feature = "serde",
57        serde(default, skip_serializing_if = "Option::is_none")
58    )]
59    pub name: Option<String>,
60    /// Optional attachment size in bytes.
61    #[cfg_attr(
62        feature = "serde",
63        serde(default, skip_serializing_if = "Option::is_none")
64    )]
65    pub size_bytes: Option<u64>,
66}
67
68/// Envelope for channel messages exchanged with adapters.
69///
70/// NOTE: Intentionally not `#[non_exhaustive]` — consumers construct this
71/// type directly via struct literals (see greentic-messaging-providers, etc).
72/// Adding a new field is a coordinated breaking change that requires a minor
73/// version bump and synchronized updates across consumer submodules.
74#[derive(Clone, Debug, PartialEq, Eq)]
75#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
76#[cfg_attr(feature = "schemars", derive(JsonSchema))]
77pub struct ChannelMessageEnvelope {
78    /// Stable identifier for the message.
79    pub id: String,
80    /// Tenant context propagated with the message.
81    pub tenant: TenantCtx,
82    /// Abstract channel identifier or type.
83    pub channel: String,
84    /// Conversation or thread identifier.
85    pub session_id: String,
86    /// Optional reply scope that can be used for resumption.
87    #[cfg_attr(
88        feature = "serde",
89        serde(default, skip_serializing_if = "Option::is_none")
90    )]
91    pub reply_scope: Option<ReplyScope>,
92    /// Optional actor (sender/initiator) associated with the message (primarily ingress).
93    #[cfg_attr(
94        feature = "serde",
95        serde(default, skip_serializing_if = "Option::is_none")
96    )]
97    pub from: Option<Actor>,
98    /// Outbound destinations for egress. Empty means “unspecified” and may be satisfied by provider config defaults.
99    #[cfg_attr(
100        feature = "serde",
101        serde(default, skip_serializing_if = "Vec::is_empty")
102    )]
103    pub to: Vec<Destination>,
104    /// Optional correlation identifier used by outbound adapters.
105    #[cfg_attr(
106        feature = "serde",
107        serde(default, skip_serializing_if = "Option::is_none")
108    )]
109    pub correlation_id: Option<String>,
110    /// Optional text content.
111    #[cfg_attr(
112        feature = "serde",
113        serde(default, skip_serializing_if = "Option::is_none")
114    )]
115    pub text: Option<String>,
116    /// Attachments included with the message.
117    #[cfg_attr(
118        feature = "serde",
119        serde(default, skip_serializing_if = "Vec::is_empty")
120    )]
121    pub attachments: Vec<Attachment>,
122    /// Free-form metadata for adapters and flows.
123    #[cfg_attr(feature = "serde", serde(default))]
124    pub metadata: MessageMetadata,
125    /// Structured provider-agnostic and provider-native extension data.
126    ///
127    /// Use well-known keys from [`extensions::ext_keys`] to avoid typos.
128    /// Values are typed JSON (`serde_json::Value`) — no re-serialization
129    /// needed at provider boundaries.
130    #[cfg_attr(
131        feature = "serde",
132        serde(default, skip_serializing_if = "BTreeMap::is_empty")
133    )]
134    pub extensions: alloc::collections::BTreeMap<String, serde_json::Value>,
135}
136
137pub mod extensions;
138pub mod rendering;
139pub mod universal_dto;