1use serde::{Deserialize, Serialize};
3
4use crate::schema::{IsoDateTime, NonEmptyString, RunxSchema};
5use crate::{
6 CredentialDeliveryMode, CredentialDeliveryObservation, CredentialDeliveryPurpose, Reference,
7};
8
9pub const THREAD_OUTBOX_PROVIDER_PROTOCOL_VERSION: &str = "runx.thread_outbox_provider.v1";
10
11#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
14pub enum ThreadOutboxProviderProtocolVersion {
15 #[serde(rename = "runx.thread_outbox_provider.v1")]
16 V1,
17}
18
19#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
20pub enum ThreadOutboxProviderManifestSchema {
21 #[serde(rename = "runx.thread_outbox_provider.manifest.v1")]
22 V1,
23}
24
25#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
26pub enum ThreadOutboxProviderPushSchema {
27 #[serde(rename = "runx.thread_outbox_provider.push.v1")]
28 V1,
29}
30
31#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
32pub enum ThreadOutboxProviderFetchSchema {
33 #[serde(rename = "runx.thread_outbox_provider.fetch.v1")]
34 V1,
35}
36
37#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
38pub enum ThreadOutboxProviderObservationSchema {
39 #[serde(rename = "runx.thread_outbox_provider.observation.v1")]
40 V1,
41}
42
43#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
44#[serde(rename_all = "snake_case")]
45pub enum ThreadOutboxProviderOperation {
46 Push,
47 Fetch,
48}
49
50#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
51#[serde(rename_all = "snake_case")]
52pub enum ThreadOutboxProviderTransportKind {
53 Process,
54}
55
56#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
57#[serde(rename_all = "snake_case")]
58pub enum ThreadOutboxProviderPayloadFormat {
59 Markdown,
60 PlainText,
61 Json,
62}
63
64#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
65#[serde(rename_all = "snake_case")]
66pub enum ThreadOutboxProviderObservationStatus {
67 Accepted,
68 Skipped,
69 Failed,
70}
71
72#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
73#[serde(rename_all = "snake_case")]
74pub enum ThreadOutboxProviderIdempotencyStatus {
75 Created,
76 Replayed,
77 Skipped,
78 Failed,
79}
80
81#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
82#[serde(deny_unknown_fields)]
83pub struct ThreadOutboxProviderTransport {
84 pub kind: ThreadOutboxProviderTransportKind,
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub command: Option<NonEmptyString>,
87 #[serde(skip_serializing_if = "Option::is_none")]
88 pub args: Option<Vec<String>>,
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub endpoint: Option<NonEmptyString>,
91}
92
93#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
94#[serde(deny_unknown_fields)]
95pub struct ThreadOutboxProviderCredentialNeed {
96 pub provider: NonEmptyString,
97 pub purpose: CredentialDeliveryPurpose,
98 pub profile_id: NonEmptyString,
99 pub delivery_mode: CredentialDeliveryMode,
100 pub required: bool,
101 #[serde(skip_serializing_if = "Option::is_none")]
102 pub scope_refs: Option<Vec<Reference>>,
103}
104
105#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
106#[serde(deny_unknown_fields)]
107pub struct ThreadOutboxProviderReceiptCapabilities {
108 pub idempotent_push: bool,
109 pub readback: bool,
110 pub stable_provider_event_hash: bool,
111}
112
113#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
114#[serde(deny_unknown_fields)]
115pub struct ThreadOutboxProviderRedactionCapabilities {
116 pub redacts_credentials: bool,
117 pub redacts_provider_payloads: bool,
118 pub supports_redaction_refs: bool,
119}
120
121#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
122#[serde(deny_unknown_fields)]
123#[runx_schema(id = "runx.thread_outbox_provider.manifest.v1")]
124pub struct ThreadOutboxProviderManifest {
125 pub schema: ThreadOutboxProviderManifestSchema,
126 pub protocol_version: ThreadOutboxProviderProtocolVersion,
127 pub adapter_id: NonEmptyString,
128 pub provider: NonEmptyString,
129 pub name: NonEmptyString,
130 pub version: NonEmptyString,
131 pub supported_operations: Vec<ThreadOutboxProviderOperation>,
132 pub transport: ThreadOutboxProviderTransport,
133 #[serde(skip_serializing_if = "Option::is_none")]
134 pub credential_needs: Option<Vec<ThreadOutboxProviderCredentialNeed>>,
135 pub receipt_capabilities: ThreadOutboxProviderReceiptCapabilities,
136 pub redaction_capabilities: ThreadOutboxProviderRedactionCapabilities,
137}
138
139#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
140#[serde(deny_unknown_fields)]
141pub struct ThreadOutboxProviderThreadLocator {
142 pub provider: NonEmptyString,
143 pub thread_ref: Reference,
144 pub locator: NonEmptyString,
145}
146
147#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
148#[serde(deny_unknown_fields)]
149pub struct ThreadOutboxProviderLocator {
150 pub provider: NonEmptyString,
151 pub locator: NonEmptyString,
152 #[serde(skip_serializing_if = "Option::is_none")]
153 pub provider_ref: Option<Reference>,
154}
155
156#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
157#[serde(deny_unknown_fields)]
158pub struct ThreadOutboxProviderIdempotency {
159 pub key: NonEmptyString,
160 #[serde(skip_serializing_if = "Option::is_none")]
161 pub content_hash: Option<NonEmptyString>,
162}
163
164#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
165#[serde(deny_unknown_fields)]
166pub struct ThreadOutboxProviderIdempotencyObservation {
167 pub key: NonEmptyString,
168 pub status: ThreadOutboxProviderIdempotencyStatus,
169 #[serde(skip_serializing_if = "Option::is_none")]
170 pub original_observation_ref: Option<Reference>,
171}
172
173#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
174#[serde(deny_unknown_fields)]
175pub struct ThreadOutboxProviderRenderedPayload {
176 pub format: ThreadOutboxProviderPayloadFormat,
177 pub body: NonEmptyString,
178 #[serde(skip_serializing_if = "Option::is_none")]
179 pub body_sha256: Option<NonEmptyString>,
180 #[serde(skip_serializing_if = "Option::is_none")]
181 pub redaction_refs: Option<Vec<Reference>>,
182}
183
184#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
185#[serde(deny_unknown_fields)]
186pub struct ThreadOutboxProviderCredentialProfile {
187 pub provider: NonEmptyString,
188 pub purpose: CredentialDeliveryPurpose,
189 pub profile_id: NonEmptyString,
190 pub delivery_mode: CredentialDeliveryMode,
191 pub credential_refs: Vec<Reference>,
192}
193
194#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
195#[serde(deny_unknown_fields)]
196pub struct ThreadOutboxProviderReceiptContext {
197 pub harness_ref: Reference,
198 pub host_ref: Reference,
199 #[serde(skip_serializing_if = "Option::is_none")]
200 pub authority_proof_refs: Option<Vec<Reference>>,
201 #[serde(skip_serializing_if = "Option::is_none")]
202 pub scope_refs: Option<Vec<Reference>>,
203}
204
205#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
206#[serde(deny_unknown_fields)]
207#[runx_schema(id = "runx.thread_outbox_provider.push.v1")]
208pub struct ThreadOutboxProviderPush {
209 pub schema: ThreadOutboxProviderPushSchema,
210 pub protocol_version: ThreadOutboxProviderProtocolVersion,
211 pub push_id: NonEmptyString,
212 pub adapter_id: NonEmptyString,
213 pub provider: NonEmptyString,
214 pub outbox_entry_id: NonEmptyString,
215 pub thread_locator: ThreadOutboxProviderThreadLocator,
216 pub idempotency: ThreadOutboxProviderIdempotency,
217 pub payload: ThreadOutboxProviderRenderedPayload,
218 pub provider_profile: ThreadOutboxProviderCredentialProfile,
219 pub credential_delivery_refs: Vec<Reference>,
220 pub receipt_context: ThreadOutboxProviderReceiptContext,
221 pub requested_at: IsoDateTime,
222}
223
224#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
225#[serde(untagged)]
226pub enum ThreadOutboxProviderFetchTarget {
227 Thread(ThreadOutboxProviderFetchThreadTarget),
228 Provider(ThreadOutboxProviderFetchProviderTarget),
229}
230
231#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
232#[serde(deny_unknown_fields)]
233pub struct ThreadOutboxProviderFetchThreadTarget {
234 pub thread_locator: ThreadOutboxProviderThreadLocator,
235}
236
237#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
238#[serde(deny_unknown_fields)]
239pub struct ThreadOutboxProviderFetchProviderTarget {
240 pub provider_locator: ThreadOutboxProviderLocator,
241}
242
243#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
244#[serde(deny_unknown_fields)]
245#[runx_schema(id = "runx.thread_outbox_provider.fetch.v1")]
246pub struct ThreadOutboxProviderFetch {
247 pub schema: ThreadOutboxProviderFetchSchema,
248 pub protocol_version: ThreadOutboxProviderProtocolVersion,
249 pub fetch_id: NonEmptyString,
250 pub adapter_id: NonEmptyString,
251 pub provider: NonEmptyString,
252 pub target: ThreadOutboxProviderFetchTarget,
253 #[serde(skip_serializing_if = "Option::is_none")]
254 pub readback_cursor: Option<NonEmptyString>,
255 pub idempotency: ThreadOutboxProviderIdempotency,
256 pub provider_profile: ThreadOutboxProviderCredentialProfile,
257 pub credential_delivery_refs: Vec<Reference>,
258 pub receipt_context: ThreadOutboxProviderReceiptContext,
259 pub requested_at: IsoDateTime,
260}
261
262#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
263#[serde(deny_unknown_fields)]
264pub struct ThreadOutboxProviderReadbackSummary {
265 pub item_count: u64,
266 #[serde(skip_serializing_if = "Option::is_none")]
267 pub cursor: Option<NonEmptyString>,
268 #[serde(skip_serializing_if = "Option::is_none")]
269 pub latest_provider_event_id_hash: Option<NonEmptyString>,
270}
271
272#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
273#[serde(deny_unknown_fields)]
274pub struct ThreadOutboxProviderError {
275 pub code: NonEmptyString,
276 pub message: NonEmptyString,
277 pub retryable: bool,
278}
279
280#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
281#[serde(deny_unknown_fields)]
282#[runx_schema(id = "runx.thread_outbox_provider.observation.v1")]
283pub struct ThreadOutboxProviderObservation {
284 pub schema: ThreadOutboxProviderObservationSchema,
285 pub protocol_version: ThreadOutboxProviderProtocolVersion,
286 pub observation_id: NonEmptyString,
287 pub adapter_id: NonEmptyString,
288 pub provider: NonEmptyString,
289 pub operation: ThreadOutboxProviderOperation,
290 pub request_id: NonEmptyString,
291 pub status: ThreadOutboxProviderObservationStatus,
292 pub idempotency: ThreadOutboxProviderIdempotencyObservation,
293 #[serde(skip_serializing_if = "Option::is_none")]
294 pub provider_locator: Option<ThreadOutboxProviderLocator>,
295 #[serde(skip_serializing_if = "Option::is_none")]
296 pub provider_event_id_hash: Option<NonEmptyString>,
297 #[serde(skip_serializing_if = "Option::is_none")]
298 pub readback_summary: Option<ThreadOutboxProviderReadbackSummary>,
299 #[serde(skip_serializing_if = "Option::is_none")]
300 pub delivery_observations: Option<Vec<CredentialDeliveryObservation>>,
301 #[serde(skip_serializing_if = "Option::is_none")]
302 pub redaction_refs: Option<Vec<Reference>>,
303 #[serde(skip_serializing_if = "Option::is_none")]
304 pub errors: Option<Vec<ThreadOutboxProviderError>>,
305 pub observed_at: IsoDateTime,
306}