Skip to main content

runx_contracts/
thread_outbox_provider.rs

1//! Thread outbox provider contract types.
2use 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/// The const `protocol_version` discriminant shared by every thread-outbox
12/// provider frame.
13#[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}