Skip to main content

conversation_api/
thread.rs

1use crate::{ConversationMessage, PendingInteraction};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
5#[serde(rename_all = "snake_case")]
6pub enum ThreadState {
7    Active,
8    Archived,
9}
10
11#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
12#[serde(rename_all = "snake_case")]
13pub enum ThreadArchiveReason {
14    IdleTimeout,
15    UserRequested,
16    Replaced,
17}
18
19/// Durable cause of this thread's creation, assigned by the conversation owner.
20/// This is independent of turn admission: model preparation may fail after creation.
21#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
22#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
23pub enum ThreadOrigin {
24    Turn {
25        #[serde(rename = "requestId")]
26        request_id: String,
27    },
28    Operation {
29        #[serde(rename = "operationId")]
30        operation_id: String,
31    },
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
35#[serde(rename_all = "camelCase")]
36pub struct ThreadSummary {
37    pub thread_id: String,
38    /// Absent only for threads persisted before origin tracking was introduced.
39    #[serde(default, skip_serializing_if = "Option::is_none")]
40    pub origin: Option<ThreadOrigin>,
41    pub title: String,
42    pub state: ThreadState,
43    pub created_at: String,
44    pub updated_at: String,
45    pub archived_at: Option<String>,
46    #[serde(default, skip_serializing_if = "Option::is_none")]
47    pub archive_reason: Option<ThreadArchiveReason>,
48    pub purge_after: Option<String>,
49}
50
51#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
52#[serde(rename_all = "camelCase")]
53pub struct ThreadCatalog {
54    pub catalog_version: u64,
55    #[serde(default)]
56    pub active_thread_id: Option<String>,
57    #[serde(default)]
58    pub threads: Vec<ThreadSummary>,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
62#[serde(rename_all = "camelCase")]
63pub struct QueuedMessage {
64    pub request_id: String,
65    pub thread_id: String,
66    #[serde(default, skip_serializing_if = "Option::is_none")]
67    pub author_user_id: Option<String>,
68    pub content: crate::MessageContent,
69    pub created_at: String,
70}
71
72#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
73#[serde(rename_all = "camelCase")]
74pub struct ConversationQueue {
75    pub queue_version: u64,
76    #[serde(default)]
77    pub items: Vec<QueuedMessage>,
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
81#[serde(rename_all = "camelCase")]
82pub struct ActiveRun {
83    pub request_id: String,
84    pub started_at: String,
85}
86
87#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
88#[serde(rename_all = "snake_case")]
89pub enum RunStatus {
90    Completed,
91    InteractionRequired,
92    Interrupted,
93    AgentFailed,
94    SystemFailed,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
98#[serde(rename_all = "snake_case")]
99pub enum FailureSource {
100    LlmProvider,
101    AgentRuntime,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
105#[serde(rename_all = "camelCase")]
106pub struct RunFailure {
107    pub source: FailureSource,
108    /// Same catalog member as [`RunOutcome::error_code`].
109    pub code: String,
110    pub message: String,
111}
112
113#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
114#[serde(rename_all = "camelCase")]
115pub struct RunOutcome {
116    pub request_id: String,
117    pub status: RunStatus,
118    /// Catalog member from [`crate::RunErrorCode`] when the run did not complete.
119    #[serde(default, skip_serializing_if = "Option::is_none")]
120    pub error_code: Option<String>,
121    #[serde(default, skip_serializing_if = "Option::is_none")]
122    pub failure: Option<RunFailure>,
123    /// User-visible sentence for this settlement. Hosts write it once; clients display it.
124    #[serde(default, skip_serializing_if = "Option::is_none")]
125    pub message: Option<String>,
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
129#[serde(rename_all = "camelCase")]
130pub struct ThreadSnapshot {
131    pub version: u64,
132    pub messages: Vec<ConversationMessage>,
133    pub active_run: Option<ActiveRun>,
134    pub pending_interaction: Option<PendingInteraction>,
135    pub run_outcomes: Vec<RunOutcome>,
136}