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