1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
6#[serde(rename_all = "snake_case")]
7pub enum TaskStatus {
8 Backlog,
9 Todo,
10 InProgress,
11 Review,
12 Blocked,
13 Done,
14 Cancelled,
15 Handoff,
16}
17
18impl TaskStatus {
19 pub fn as_str(&self) -> &'static str {
20 match self {
21 TaskStatus::Backlog => "backlog",
22 TaskStatus::Todo => "todo",
23 TaskStatus::InProgress => "in_progress",
24 TaskStatus::Review => "review",
25 TaskStatus::Blocked => "blocked",
26 TaskStatus::Done => "done",
27 TaskStatus::Cancelled => "cancelled",
28 TaskStatus::Handoff => "handoff",
29 }
30 }
31
32 #[allow(clippy::should_implement_trait)]
33 pub fn from_str(s: &str) -> Option<Self> {
34 match s {
35 "backlog" => Some(TaskStatus::Backlog),
36 "todo" => Some(TaskStatus::Todo),
37 "in_progress" => Some(TaskStatus::InProgress),
38 "review" => Some(TaskStatus::Review),
39 "blocked" => Some(TaskStatus::Blocked),
40 "done" => Some(TaskStatus::Done),
41 "cancelled" => Some(TaskStatus::Cancelled),
42 "handoff" => Some(TaskStatus::Handoff),
43 _ => None,
44 }
45 }
46
47 pub fn valid_transitions(&self) -> Vec<TaskStatus> {
48 match self {
49 TaskStatus::Backlog => vec![
50 TaskStatus::Todo,
51 TaskStatus::InProgress,
52 TaskStatus::Cancelled,
53 ],
54 TaskStatus::Todo => vec![
55 TaskStatus::InProgress,
56 TaskStatus::Blocked,
57 TaskStatus::Cancelled,
58 ],
59 TaskStatus::InProgress => vec![
60 TaskStatus::Review,
61 TaskStatus::Done,
62 TaskStatus::Blocked,
63 TaskStatus::Cancelled,
64 TaskStatus::Handoff,
65 ],
66 TaskStatus::Review => vec![TaskStatus::Done, TaskStatus::InProgress],
67 TaskStatus::Blocked => vec![
68 TaskStatus::Todo,
69 TaskStatus::InProgress,
70 TaskStatus::Cancelled,
71 ],
72 TaskStatus::Done => vec![],
73 TaskStatus::Cancelled => vec![],
74 TaskStatus::Handoff => vec![TaskStatus::InProgress],
75 }
76 }
77
78 pub fn can_transition_to(&self, target: &TaskStatus) -> bool {
79 self.valid_transitions().contains(target)
80 }
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
84#[serde(rename_all = "snake_case")]
85pub enum Priority {
86 Critical,
87 High,
88 Medium,
89 Low,
90}
91
92impl Priority {
93 pub fn as_str(&self) -> &'static str {
94 match self {
95 Priority::Critical => "critical",
96 Priority::High => "high",
97 Priority::Medium => "medium",
98 Priority::Low => "low",
99 }
100 }
101
102 #[allow(clippy::should_implement_trait)]
103 pub fn from_str(s: &str) -> Option<Self> {
104 match s {
105 "critical" => Some(Priority::Critical),
106 "high" => Some(Priority::High),
107 "medium" => Some(Priority::Medium),
108 "low" => Some(Priority::Low),
109 _ => None,
110 }
111 }
112
113 pub fn sort_order(&self) -> i32 {
114 match self {
115 Priority::Critical => 0,
116 Priority::High => 1,
117 Priority::Medium => 2,
118 Priority::Low => 3,
119 }
120 }
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct Project {
127 pub id: String,
128 pub name: String,
129 pub description: Option<String>,
130 pub status: String,
131 pub repo_url: Option<String>,
132 pub default_branch: Option<String>,
133 pub created_at: String,
134 pub updated_at: String,
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct Task {
139 pub id: String,
140 pub project_id: String,
141 pub title: String,
142 pub description: Option<String>,
143 pub status: String,
144 pub priority: String,
145 pub assignee_type: Option<String>,
146 pub assignee_id: Option<String>,
147 pub context: Option<serde_json::Value>,
148 pub output: Option<serde_json::Value>,
149 pub tags: Vec<String>,
150 pub due_date: Option<String>,
151 pub reviewer_type: Option<String>,
152 pub reviewer_id: Option<String>,
153 pub status_history: Vec<StatusHistoryEntry>,
154 pub artifacts: Vec<TaskArtifact>,
155 pub scheduled_at: Option<String>,
157 pub recurrence_rule: Option<serde_json::Value>,
159 pub recurrence_parent_id: Option<String>,
161 pub dependencies: Vec<String>,
163 pub has_open_questions: bool,
165 pub started_review_at: Option<String>,
167 pub created_by: String,
168 pub created_at: String,
169 pub updated_at: String,
170 #[serde(default, skip_serializing_if = "Vec::is_empty")]
171 pub activities: Vec<TaskActivity>,
172}
173
174#[derive(Debug, Clone, Serialize, Deserialize)]
175pub struct StatusHistoryEntry {
176 pub status: String,
177 pub agent_id: Option<String>,
178 pub agent_type: Option<String>,
179 pub timestamp: String,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct TaskActivity {
184 pub id: String,
185 pub task_id: String,
186 pub author_type: String,
187 pub author_id: String,
188 pub content: String,
189 pub activity_type: String,
190 pub metadata: Option<serde_json::Value>,
191 pub created_at: String,
192}
193
194#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct Agent {
196 pub id: String,
197 pub name: String,
198 #[serde(skip_serializing)]
199 pub api_key_hash: String,
200 pub skills: Vec<String>,
201 pub description: Option<String>,
202 pub status: String,
203 pub max_concurrent_tasks: i64,
204 pub current_task_count: i64,
205 pub review_task_count: i64,
207 pub webhook_url: Option<String>,
208 pub webhook_events: Option<Vec<String>>,
210 pub config: Option<serde_json::Value>,
211 pub model: Option<String>,
212 pub provider: Option<String>,
213 pub cost_tier: Option<String>,
214 pub capabilities: Vec<String>,
215 pub seniority: String,
217 pub role: String,
219 pub stale_timeout: i64,
221 pub last_seen_at: Option<String>,
222 pub created_at: String,
223 pub owner_id: Option<String>,
225 pub tags: Vec<String>,
227}
228
229#[derive(Debug, Deserialize)]
232pub struct CreateProject {
233 pub name: String,
234 pub description: Option<String>,
235 pub repo_url: Option<String>,
236 pub default_branch: Option<String>,
237}
238
239#[derive(Debug, Deserialize)]
240pub struct UpdateProject {
241 pub name: Option<String>,
242 pub description: Option<String>,
243 pub status: Option<String>,
244 pub repo_url: Option<String>,
245 pub default_branch: Option<String>,
246}
247
248#[derive(Debug, Deserialize)]
249pub struct CreateTask {
250 pub title: String,
251 pub description: Option<String>,
252 pub priority: Option<String>,
253 pub tags: Option<Vec<String>>,
254 pub context: Option<serde_json::Value>,
255 pub output: Option<serde_json::Value>,
256 pub due_date: Option<String>,
257 pub assignee_type: Option<String>,
258 pub assignee_id: Option<String>,
259 pub scheduled_at: Option<String>,
261 pub recurrence_rule: Option<serde_json::Value>,
263}
264
265#[derive(Debug, Deserialize)]
266pub struct UpdateTask {
267 pub title: Option<String>,
268 pub description: Option<String>,
269 pub status: Option<String>,
270 pub priority: Option<String>,
271 pub tags: Option<Vec<String>>,
272 pub context: Option<serde_json::Value>,
273 pub output: Option<serde_json::Value>,
274 pub due_date: Option<String>,
275 pub assignee_type: Option<String>,
276 pub assignee_id: Option<String>,
277 pub reviewer_type: Option<String>,
278 pub reviewer_id: Option<String>,
279 pub scheduled_at: Option<String>,
281 pub recurrence_rule: Option<serde_json::Value>,
283}
284
285#[derive(Debug, Deserialize)]
287pub struct AddDependenciesRequest {
288 pub depends_on: Vec<String>,
289}
290
291#[derive(Debug, Serialize)]
293pub struct ScheduledTaskEntry {
294 pub id: String,
295 pub title: String,
296 pub status: String,
297 pub priority: String,
298 pub scheduled_at: String,
299 pub assignee_id: Option<String>,
300}
301
302#[derive(Debug, Deserialize)]
303pub struct CreateAgent {
304 pub name: String,
305 pub skills: Option<Vec<String>>,
306 pub model: Option<String>,
307 pub provider: Option<String>,
308 pub cost_tier: Option<String>,
309 pub capabilities: Option<Vec<String>>,
310 pub seniority: Option<String>,
311 pub role: Option<String>,
312 pub owner_id: Option<String>,
313}
314
315impl CreateAgent {
316 pub fn new(name: impl Into<String>) -> Self {
318 Self {
319 name: name.into(),
320 skills: None,
321 model: None,
322 provider: None,
323 cost_tier: None,
324 capabilities: None,
325 seniority: None,
326 role: None,
327 owner_id: None,
328 }
329 }
330
331 pub fn with_skills(mut self, skills: Vec<String>) -> Self {
332 self.skills = Some(skills);
333 self
334 }
335
336 pub fn with_seniority(mut self, seniority: impl Into<String>) -> Self {
337 self.seniority = Some(seniority.into());
338 self
339 }
340
341 pub fn with_role(mut self, role: impl Into<String>) -> Self {
342 self.role = Some(role.into());
343 self
344 }
345
346 pub fn with_capabilities(mut self, capabilities: Vec<String>) -> Self {
347 self.capabilities = Some(capabilities);
348 self
349 }
350}
351
352#[derive(Debug, Deserialize)]
353pub struct RegisterAgentRequest {
354 pub name: String,
355 pub skills: Option<Vec<String>>,
356 pub setup_token: String,
357 pub model: Option<String>,
358 pub provider: Option<String>,
359 pub cost_tier: Option<String>,
360 pub capabilities: Option<Vec<String>>,
361 pub owner_id: Option<String>,
362}
363
364#[derive(Debug, Deserialize)]
365pub struct CreateActivity {
366 pub content: String,
367 pub activity_type: Option<String>,
368 pub metadata: Option<serde_json::Value>,
369}
370
371#[derive(Debug, Deserialize)]
372pub struct TaskFilters {
373 pub project_id: Option<String>,
374 pub status: Option<String>,
375 pub priority: Option<String>,
376 pub assignee_id: Option<String>,
377 pub tag: Option<String>,
378}
379
380#[derive(Debug, Deserialize)]
381pub struct BatchStatusUpdate {
382 pub updates: Vec<BatchStatusItem>,
383}
384
385#[derive(Debug, Deserialize)]
386pub struct BatchStatusItem {
387 pub task_id: String,
388 pub status: String,
389}
390
391#[derive(Debug, Serialize)]
392pub struct BatchResult {
393 pub succeeded: Vec<String>,
394 pub failed: Vec<BatchError>,
395}
396
397#[derive(Debug, Serialize)]
398pub struct BatchError {
399 pub task_id: String,
400 pub error: String,
401}
402
403#[derive(Debug, Serialize)]
404pub struct DashboardStats {
405 pub tasks_by_status: std::collections::HashMap<String, i64>,
406 pub total_tasks: i64,
407 pub active_agents: i64,
408 pub total_projects: i64,
409 pub recent_activity: Vec<TaskActivity>,
410}
411
412#[derive(Debug, Serialize)]
413pub struct ProjectWithStats {
414 pub project: Project,
415 pub task_count: i64,
416 pub tasks_by_status: std::collections::HashMap<String, i64>,
417}
418
419#[derive(Debug, Serialize)]
420pub struct AgentCreated {
421 pub agent: Agent,
422 pub api_key: String,
423}
424
425#[derive(Debug, Deserialize)]
426pub struct CompleteRequest {
427 pub summary: Option<String>,
428 pub output: Option<serde_json::Value>,
429}
430
431#[derive(Debug, Deserialize)]
432pub struct SubmitReviewRequest {
433 pub summary: Option<String>,
435 pub reviewer_id: Option<String>,
437}
438
439#[derive(Debug, Deserialize)]
440pub struct BlockRequest {
441 pub reason: Option<String>,
442}
443
444#[derive(Debug, Deserialize)]
445pub struct NextTaskQuery {
446 pub skills: Option<String>,
447}
448
449#[derive(Debug, Clone)]
452pub enum Identity {
453 AgentIdentity {
457 id: String,
458 name: String,
459 tenant_id: Option<String>,
460 },
461 Human {
464 id: String,
465 tenant_id: Option<String>,
466 },
467 Anonymous,
468}
469
470impl Identity {
471 pub fn author_type(&self) -> &'static str {
472 match self {
473 Identity::AgentIdentity { .. } => "agent",
474 Identity::Human { .. } => "human",
475 Identity::Anonymous => "system",
476 }
477 }
478
479 pub fn author_id(&self) -> &str {
480 match self {
481 Identity::AgentIdentity { id, .. } => id,
482 Identity::Human { id, .. } => id,
483 Identity::Anonymous => "system",
484 }
485 }
486
487 pub fn display_name(&self) -> &str {
488 match self {
489 Identity::AgentIdentity { name, .. } => name,
490 Identity::Human { id, .. } => id,
491 Identity::Anonymous => "system",
492 }
493 }
494
495 pub fn tenant_id(&self) -> Option<&str> {
499 match self {
500 Identity::AgentIdentity { tenant_id, .. } => tenant_id.as_deref(),
501 Identity::Human { tenant_id, .. } => tenant_id.as_deref(),
502 Identity::Anonymous => None,
503 }
504 }
505}
506
507#[derive(Debug, Deserialize)]
510pub struct UpdateAgent {
511 pub description: Option<String>,
512 pub skills: Option<Vec<String>>,
513 pub max_concurrent_tasks: Option<i64>,
514 pub webhook_url: Option<String>,
515 pub webhook_events: Option<Vec<String>>,
517 pub config: Option<serde_json::Value>,
518 pub model: Option<String>,
519 pub provider: Option<String>,
520 pub cost_tier: Option<String>,
521 pub capabilities: Option<Vec<String>>,
522 pub seniority: Option<String>,
523 pub role: Option<String>,
524 pub stale_timeout: Option<i64>,
526 pub tags: Option<Vec<String>>,
528}
529
530#[derive(Debug, Deserialize)]
531pub struct AssignRequest {
532 pub agent_id: String,
533}
534
535#[derive(Debug, Deserialize)]
536pub struct HandoffRequest {
537 pub to_agent_id: String,
538 pub summary: Option<String>,
539}
540
541#[derive(Debug, Deserialize)]
542pub struct ApproveRequest {
543 pub comment: Option<String>,
544}
545
546#[derive(Debug, Deserialize)]
547pub struct RequestChangesRequest {
548 pub comment: String,
549}
550
551pub const VALID_CATEGORIES: &[&str] =
555 &["architecture", "pattern", "gotcha", "decision", "reference"];
556
557#[derive(Debug, Clone, Serialize, Deserialize)]
558pub struct KnowledgeEntry {
559 pub id: String,
560 pub project_id: String,
561 pub key: String,
562 pub title: String,
563 pub content: String,
564 pub metadata: Option<serde_json::Value>,
565 pub tags: Vec<String>,
567 pub category: Option<String>,
569 pub created_by_type: String,
570 pub created_by_id: String,
571 pub updated_at: String,
572 pub created_at: String,
573}
574
575#[derive(Debug, Deserialize)]
576pub struct UpsertKnowledge {
577 pub title: String,
578 pub content: String,
579 pub metadata: Option<serde_json::Value>,
580 pub tags: Option<Vec<String>>,
582 pub category: Option<String>,
584}
585
586#[derive(Debug, Deserialize)]
587pub struct KnowledgeSearchQuery {
588 pub q: Option<String>,
589 pub prefix: Option<String>,
590 pub tags: Option<String>,
592 pub category: Option<String>,
594}
595
596pub const VALID_ARTIFACT_TYPES: &[&str] = &["url", "text", "json", "file"];
599
600#[derive(Debug, Clone, Serialize, Deserialize)]
601pub struct TaskArtifact {
602 pub id: String,
603 pub task_id: String,
604 pub name: String,
605 pub artifact_type: String,
606 pub value: String,
607 pub created_by_type: String,
608 pub created_by_id: String,
609 pub created_at: String,
610}
611
612#[derive(Debug, Deserialize)]
613pub struct CreateArtifact {
614 pub name: String,
615 pub artifact_type: String,
616 pub value: String,
617}
618
619#[derive(Debug, Deserialize)]
620pub struct UpdateArtifact {
621 pub name: Option<String>,
623 pub value: Option<String>,
625}
626
627#[derive(Debug, Clone, Serialize, Deserialize)]
630pub struct WebhookLogEntry {
631 pub id: String,
632 pub agent_id: String,
633 pub event_type: String,
634 pub payload: serde_json::Value,
635 pub status: String,
636 pub attempts: i64,
637 pub last_attempt_at: Option<String>,
638 pub created_at: String,
639}
640
641#[derive(Debug, Clone, Serialize, Deserialize)]
644pub struct Notification {
645 pub id: i64,
646 pub agent_id: String,
647 pub event_id: Option<i64>,
648 pub event_type: String,
649 pub title: String,
650 pub body: Option<String>,
651 pub read: bool,
652 pub webhook_status: Option<String>,
654 pub created_at: String,
655}
656
657#[derive(Debug, Clone)]
659pub struct PendingNotifWebhook {
660 pub agent_id: String,
661 pub notification_id: i64,
662 pub event_type: String,
663 pub title: String,
664 pub body: Option<String>,
665}
666
667#[derive(Debug, Deserialize)]
668pub struct NotificationQuery {
669 pub unread: Option<bool>,
670}
671
672#[derive(Debug, Serialize)]
675pub struct PulseResponse {
676 pub active_tasks: Vec<PulseTask>,
677 pub blocked_tasks: Vec<PulseTask>,
678 pub pending_review: Vec<PulseTask>,
679 pub recently_completed: Vec<PulseTask>,
680 pub unread_events: i64,
681 pub agents: Vec<PulseAgent>,
682 pub recent_knowledge_updates: Vec<PulseKnowledge>,
683 pub blocked_by_deps: i64,
685}
686
687#[derive(Debug, Serialize)]
688pub struct PulseTask {
689 pub id: String,
690 pub title: String,
691 pub status: String,
692 pub priority: String,
693 pub assignee_name: Option<String>,
694 pub reviewer_name: Option<String>,
695 pub tags: Vec<String>,
696 pub updated_at: String,
697}
698
699#[derive(Debug, Serialize)]
700pub struct PulseAgent {
701 pub id: String,
702 pub name: String,
703 pub status: String,
704 pub seniority: String,
705 pub role: String,
706 pub current_task: Option<String>,
707 pub last_seen_at: Option<String>,
708}
709
710#[derive(Debug, Serialize)]
711pub struct PulseKnowledge {
712 pub key: String,
713 pub title: String,
714 pub category: Option<String>,
715 pub updated_at: String,
716}
717
718#[derive(Debug, Deserialize)]
719pub struct AgentQuery {
720 pub capability: Option<String>,
721 pub seniority: Option<String>,
722}
723
724#[derive(Debug, Deserialize)]
725pub struct AgentMatchQuery {
726 pub capability: Option<String>,
727 pub seniority: Option<String>,
728 pub role: Option<String>,
729}
730
731#[derive(Debug, Clone, Serialize, Deserialize)]
733pub struct AssignStrategy {
734 pub strategy: String,
735 pub capabilities: Option<Vec<String>>,
736 pub seniority: Option<String>,
737 pub role: Option<String>,
738 pub agent_id: Option<String>,
739}
740
741#[derive(Debug, Clone)]
744pub struct CapabilityTarget {
745 pub target_type: String,
746 pub target_id: String,
747}
748
749#[derive(Debug, Clone, Serialize, Deserialize)]
752pub struct TaskQuestion {
753 pub id: String,
754 pub task_id: String,
755 pub question: String,
756 pub question_type: String,
757 pub context: Option<String>,
758 pub asked_by_type: String,
759 pub asked_by_id: String,
760 pub target_type: Option<String>,
761 pub target_id: Option<String>,
762 pub required_capability: Option<String>,
763 pub status: String,
764 pub blocking: bool,
765 pub resolved_by_type: Option<String>,
766 pub resolved_by_id: Option<String>,
767 pub resolution: Option<String>,
768 pub created_at: String,
769 pub resolved_at: Option<String>,
770}
771
772#[derive(Debug, Deserialize)]
773pub struct CreateQuestion {
774 pub question: String,
775 pub question_type: Option<String>,
776 pub context: Option<String>,
777 pub target_type: Option<String>,
778 pub target_id: Option<String>,
779 pub required_capability: Option<String>,
780 pub blocking: Option<bool>,
781}
782
783#[derive(Debug, Deserialize)]
784pub struct ResolveQuestion {
785 pub resolution: String,
786}
787
788#[derive(Debug, Deserialize)]
789pub struct QuestionQuery {
790 pub status: Option<String>,
791 pub unrouted: Option<bool>,
792}
793
794#[derive(Debug, Clone, Serialize, Deserialize)]
795pub struct QuestionReply {
796 pub id: String,
797 pub question_id: String,
798 pub author_type: String,
799 pub author_id: String,
800 pub body: String,
801 pub is_resolution: bool,
802 pub created_at: String,
803}
804
805#[derive(Debug, Deserialize)]
806pub struct CreateReply {
807 pub body: String,
808 pub is_resolution: Option<bool>,
809}
810
811#[derive(Debug, Deserialize)]
812pub struct DismissQuestion {
813 pub reason: String,
814}
815
816#[derive(Debug, Deserialize)]
817pub struct AssignQuestion {
818 pub target_type: String,
819 pub target_id: String,
820}
821
822#[derive(Debug, Serialize)]
825pub struct InboxItem {
826 pub id: String,
827 pub item_type: String,
828 pub title: String,
829 pub status: Option<String>,
830 pub priority: Option<String>,
831 pub action: String,
832 pub action_hint: String,
833 pub project_id: Option<String>,
834 pub tags: Vec<String>,
835 pub updated_at: Option<String>,
836 pub metadata: Option<serde_json::Value>,
837}
838
839#[derive(Debug, Serialize)]
840pub struct InboxCapacity {
841 pub max_concurrent_tasks: i64,
842 pub current_active_tasks: i64,
843 pub has_capacity: bool,
844}
845
846#[derive(Debug, Serialize)]
847pub struct AgentInbox {
848 pub summary: String,
849 pub todo_tasks: Vec<InboxItem>,
850 pub in_progress_tasks: Vec<InboxItem>,
851 pub review_tasks: Vec<InboxItem>,
852 pub blocked_tasks: Vec<InboxItem>,
853 pub handoff_tasks: Vec<InboxItem>,
854 pub open_questions: Vec<InboxItem>,
855 pub unread_notifications: Vec<InboxItem>,
856 pub capacity: InboxCapacity,
857}
858
859#[derive(Debug, Serialize, Deserialize, Clone)]
862pub struct WebhookTrigger {
863 pub id: String,
864 pub project_id: String,
865 pub name: String,
866 pub action_type: String,
867 pub action_config: serde_json::Value,
868 pub enabled: bool,
869 #[serde(default)]
870 pub ip_allowlist: Vec<String>,
871 pub created_at: String,
872 pub updated_at: String,
873}
874
875#[derive(Debug, Serialize)]
877pub struct TriggerCreatedResponse {
878 pub trigger: WebhookTrigger,
879 pub secret: String,
880}
881
882#[derive(Debug, Deserialize)]
883pub struct CreateTriggerRequest {
884 pub name: String,
885 pub action_type: String,
886 pub action_config: serde_json::Value,
887}
888
889#[derive(Debug, Deserialize)]
890pub struct UpdateTriggerRequest {
891 pub name: Option<String>,
892 pub action_type: Option<String>,
893 pub action_config: Option<serde_json::Value>,
894 pub enabled: Option<bool>,
895 pub ip_allowlist: Option<Vec<String>>,
896}
897
898#[derive(Debug, Serialize, Deserialize)]
899pub struct WebhookTriggerLog {
900 pub id: String,
901 pub trigger_id: String,
902 pub received_at: String,
903 pub status: String,
904 pub payload: Option<serde_json::Value>,
905 pub result: Option<serde_json::Value>,
906 pub error: Option<String>,
907}