Skip to main content

context69_contracts/
tasks.rs

1use chrono::{DateTime, Utc};
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4use utoipa::{IntoParams, ToSchema};
5use uuid::Uuid;
6
7use crate::{
8    GroupResponse, ImportLibraryFileFromUrlRequest, LibraryFileUploadMetadata,
9    UpsertLibraryTextRequest,
10};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, JsonSchema)]
13#[serde(rename_all = "snake_case")]
14pub enum TaskKind {
15    SourceSync,
16    TextBatch,
17    FileBatch,
18    UrlBatch,
19    DeleteBatch,
20    Translation,
21    VectorRebuild,
22}
23
24impl TaskKind {
25    pub fn as_str(self) -> &'static str {
26        match self {
27            Self::SourceSync => "source_sync",
28            Self::TextBatch => "text_batch",
29            Self::FileBatch => "file_batch",
30            Self::UrlBatch => "url_batch",
31            Self::DeleteBatch => "delete_batch",
32            Self::Translation => "translation",
33            Self::VectorRebuild => "vector_rebuild",
34        }
35    }
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, JsonSchema)]
39#[serde(rename_all = "snake_case")]
40pub enum TaskStatus {
41    Queued,
42    Running,
43    Waiting,
44    Succeeded,
45    Failed,
46    Cancelled,
47}
48
49impl TaskStatus {
50    pub fn as_str(self) -> &'static str {
51        match self {
52            Self::Queued => "queued",
53            Self::Running => "running",
54            Self::Waiting => "waiting",
55            Self::Succeeded => "succeeded",
56            Self::Failed => "failed",
57            Self::Cancelled => "cancelled",
58        }
59    }
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, JsonSchema)]
63#[serde(rename_all = "snake_case")]
64pub enum TaskItemStatus {
65    Queued,
66    Running,
67    Waiting,
68    Succeeded,
69    Failed,
70    Cancelled,
71}
72
73impl TaskItemStatus {
74    pub fn as_str(self) -> &'static str {
75        match self {
76            Self::Queued => "queued",
77            Self::Running => "running",
78            Self::Waiting => "waiting",
79            Self::Succeeded => "succeeded",
80            Self::Failed => "failed",
81            Self::Cancelled => "cancelled",
82        }
83    }
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
87pub struct TaskRef {
88    pub task_id: Uuid,
89    #[serde(default)]
90    pub item_ids: Vec<Uuid>,
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
94pub struct TaskProgress {
95    pub total: i64,
96    pub queued: i64,
97    pub running: i64,
98    pub waiting: i64,
99    pub succeeded: i64,
100    pub failed: i64,
101    pub cancelled: i64,
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, JsonSchema)]
105#[serde(rename_all = "snake_case")]
106pub enum TaskOrigin {
107    Manual,
108    Rerun,
109}
110
111impl TaskOrigin {
112    pub fn as_str(self) -> &'static str {
113        match self {
114            Self::Manual => "manual",
115            Self::Rerun => "rerun",
116        }
117    }
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
121pub struct TaskResponse {
122    pub task_id: Uuid,
123    pub kind: TaskKind,
124    pub status: TaskStatus,
125    pub origin: TaskOrigin,
126    pub group_path: Option<String>,
127    pub source_key: Option<String>,
128    pub stage: Option<String>,
129    pub waiting_reason: Option<String>,
130    pub dependency_key: Option<String>,
131    pub progress: TaskProgress,
132    pub failure_stage: Option<String>,
133    pub error_summary: Option<String>,
134    pub eta_seconds: Option<i64>,
135    pub created_at: DateTime<Utc>,
136    pub started_at: Option<DateTime<Utc>>,
137    pub finished_at: Option<DateTime<Utc>>,
138    pub updated_at: DateTime<Utc>,
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
142pub struct TaskItemResponse {
143    pub item_id: Uuid,
144    pub ordinal: i32,
145    pub status: TaskItemStatus,
146    pub resource_id: Option<String>,
147    pub file_id: Option<Uuid>,
148    pub stage: Option<String>,
149    pub waiting_reason: Option<String>,
150    pub dependency_key: Option<String>,
151    pub next_attempt_at: Option<DateTime<Utc>>,
152    pub failure_stage: Option<String>,
153    pub error_message: Option<String>,
154    pub attempt_count: i32,
155    pub retryable: bool,
156    pub created_at: DateTime<Utc>,
157    pub started_at: Option<DateTime<Utc>>,
158    pub finished_at: Option<DateTime<Utc>>,
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize, IntoParams, ToSchema)]
162#[into_params(parameter_in = Query)]
163pub struct TaskListQuery {
164    #[serde(default = "default_page")]
165    pub page: u32,
166    #[serde(default = "default_page_size")]
167    pub page_size: u32,
168    #[serde(default)]
169    pub query: Option<String>,
170    #[serde(default)]
171    pub kind: Option<TaskKind>,
172    #[serde(default)]
173    pub status: Option<TaskStatus>,
174    #[serde(default)]
175    pub stage: Option<String>,
176    #[serde(default)]
177    pub waiting_reason: Option<String>,
178    #[serde(default)]
179    pub dependency_key: Option<String>,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
183pub struct TaskPageResponse {
184    pub items: Vec<TaskResponse>,
185    pub pagination: crate::Pagination,
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
189pub struct TaskItemsResponse {
190    pub items: Vec<TaskItemResponse>,
191    pub next_cursor: Option<String>,
192}
193
194#[derive(Debug, Clone, Serialize, Deserialize, IntoParams, ToSchema)]
195#[into_params(parameter_in = Query)]
196pub struct TaskItemsQuery {
197    #[serde(default = "default_item_limit")]
198    pub limit: u32,
199    #[serde(default)]
200    pub cursor: Option<String>,
201}
202
203#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
204pub struct ScopeSpec {
205    pub group_path: String,
206    pub name: String,
207    pub visibility: crate::Visibility,
208    #[serde(default)]
209    pub kind: Option<crate::GroupKind>,
210    #[serde(default)]
211    pub metadata_indexes: Vec<ScopeMetadataIndex>,
212}
213
214#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
215pub struct ScopeMetadataIndex {
216    pub source_key: String,
217    #[serde(flatten)]
218    pub definition: crate::CreateMetadataIndexRequest,
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
222pub struct EnsureScopeResponse {
223    pub group: GroupResponse,
224    pub metadata_indexes: Vec<crate::MetadataIndexResponse>,
225}
226
227#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
228pub struct TextBatchRequest {
229    pub items: Vec<UpsertLibraryTextRequest>,
230}
231
232#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
233pub struct UrlBatchRequest {
234    pub items: Vec<ImportLibraryFileFromUrlRequest>,
235}
236
237#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
238pub struct DeleteBatchRequest {
239    pub items: Vec<crate::DocumentKey>,
240}
241
242#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
243pub struct FileBatchItem {
244    pub filename: String,
245    pub media_type: String,
246    pub content_base64: String,
247    #[serde(default, skip_serializing_if = "Option::is_none")]
248    pub declared_sha256: Option<String>,
249    #[serde(default)]
250    pub folder_id: Option<Uuid>,
251    #[serde(default)]
252    pub metadata: Option<LibraryFileUploadMetadata>,
253    #[serde(default)]
254    pub translation: Option<crate::TranslationDirective>,
255}
256
257#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
258pub struct FileBatchRequest {
259    pub items: Vec<FileBatchItem>,
260}
261
262#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
263#[serde(tag = "kind", rename_all = "snake_case")]
264pub enum TaskSubmitRequest {
265    /// Re-process existing library files that already have a file id.
266    RetryFileBatch {
267        #[serde(default)]
268        group_path: Option<String>,
269        items: Vec<FileRetryItem>,
270    },
271    /// Ingest file contents uploaded inline as base64.
272    FileBatch {
273        #[serde(default)]
274        group_path: Option<String>,
275        items: Vec<FileBatchItem>,
276    },
277    TextBatch {
278        #[serde(default)]
279        group_path: Option<String>,
280        items: Vec<UpsertLibraryTextRequest>,
281    },
282    UrlBatch {
283        #[serde(default)]
284        group_path: Option<String>,
285        items: Vec<ImportLibraryFileFromUrlRequest>,
286    },
287    DeleteBatch {
288        #[serde(default)]
289        group_path: Option<String>,
290        items: Vec<crate::DocumentKey>,
291    },
292    SourceSync {
293        #[serde(default)]
294        group_path: Option<String>,
295        source_key: String,
296    },
297    TranslationBatch {
298        #[serde(default)]
299        group_path: Option<String>,
300        items: Vec<TranslationSubmitItem>,
301    },
302    VectorRebuild,
303}
304
305#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
306pub struct FileRetryItem {
307    pub file_id: Uuid,
308}
309
310#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
311pub struct TranslationSubmitItem {
312    pub document_id: i64,
313    #[serde(default)]
314    pub target_locales: Vec<String>,
315}
316
317#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
318pub struct TaskRetryResponse {
319    pub task: TaskRef,
320    pub retried_items: i64,
321}
322
323#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
324pub struct RerunTaskResponse {
325    pub task: TaskRef,
326}
327
328#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, JsonSchema)]
329#[serde(rename_all = "snake_case")]
330pub enum TaskPurgeMode {
331    Expired,
332    AllTerminal,
333}
334
335#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
336pub struct TaskMaintenanceSettings {
337    pub cleanup_enabled: bool,
338    pub retention_days: i64,
339    pub updated_at: DateTime<Utc>,
340}
341
342#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
343pub struct TaskMaintenanceStats {
344    pub total: i64,
345    pub queued: i64,
346    pub running: i64,
347    pub waiting: i64,
348    pub succeeded: i64,
349    pub failed: i64,
350    pub cancelled: i64,
351    pub active: i64,
352    pub expired_terminal: i64,
353}
354
355#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
356pub struct TaskMaintenanceOverview {
357    pub settings: TaskMaintenanceSettings,
358    pub stats: TaskMaintenanceStats,
359}
360
361#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
362pub struct UpdateTaskMaintenanceSettingsRequest {
363    pub cleanup_enabled: bool,
364    pub retention_days: i64,
365}
366
367#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
368pub struct CancelActiveTasksResponse {
369    pub cancelled_tasks: i64,
370}
371
372#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
373pub struct PurgeTasksRequest {
374    pub mode: TaskPurgeMode,
375}
376
377#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
378pub struct PurgeTasksResponse {
379    pub deleted_tasks: i64,
380}
381
382fn default_page() -> u32 {
383    1
384}
385
386fn default_page_size() -> u32 {
387    50
388}
389
390fn default_item_limit() -> u32 {
391    100
392}