1use steer_core::app::conversation::{AppCommandType, CommandResponse, Message};
8use steer_tools::ToolCall;
9use time::OffsetDateTime;
10
11pub type RowId = String;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum NoticeLevel {
16 Error,
17 Warn,
18 Info,
19}
20
21#[derive(Debug, Clone)]
23pub enum ChatItemData {
24 Message(Message),
26
27 PendingToolCall {
29 id: RowId,
30 tool_call: ToolCall,
31 ts: OffsetDateTime,
32 },
33
34 SlashInput {
36 id: RowId,
37 raw: String,
38 ts: OffsetDateTime,
39 },
40
41 SystemNotice {
43 id: RowId,
44 level: NoticeLevel,
45 text: String,
46 ts: OffsetDateTime,
47 },
48
49 CoreCmdResponse {
51 id: RowId,
52 cmd: AppCommandType,
53 resp: CommandResponse,
54 ts: OffsetDateTime,
55 },
56
57 TuiCommandResponse {
59 id: RowId,
60 command: String,
61 response: String,
62 ts: OffsetDateTime,
63 },
64
65 InFlightOperation {
66 id: RowId,
67 operation_id: uuid::Uuid,
68 label: String,
69 ts: OffsetDateTime,
70 },
71}
72
73#[derive(Debug, Clone)]
74pub struct ChatItem {
75 pub parent_chat_item_id: Option<RowId>,
76 pub data: ChatItemData,
77}
78
79impl ChatItem {
80 pub fn id(&self) -> &str {
82 match &self.data {
83 ChatItemData::Message(row) => row.id(),
84 ChatItemData::PendingToolCall { id, .. } => id,
85 ChatItemData::SlashInput { id, .. } => id,
86 ChatItemData::CoreCmdResponse { id, .. } => id,
87 ChatItemData::SystemNotice { id, .. } => id,
88 ChatItemData::TuiCommandResponse { id, .. } => id,
89 ChatItemData::InFlightOperation { id, .. } => id,
90 }
91 }
92
93 pub fn timestamp(&self) -> OffsetDateTime {
95 match &self.data {
96 ChatItemData::Message(message) => {
97 OffsetDateTime::from_unix_timestamp(message.timestamp() as i64).unwrap()
98 }
99 ChatItemData::PendingToolCall { ts, .. } => *ts,
100 ChatItemData::SlashInput { ts, .. } => *ts,
101 ChatItemData::CoreCmdResponse { ts, .. } => *ts,
102 ChatItemData::SystemNotice { ts, .. } => *ts,
103 ChatItemData::TuiCommandResponse { ts, .. } => *ts,
104 ChatItemData::InFlightOperation { ts, .. } => *ts,
105 }
106 }
107
108 pub fn parent_message_id(&self) -> Option<&str> {
110 match &self.data {
111 ChatItemData::Message(msg) => msg.parent_message_id(),
112 _ => None,
113 }
114 }
115}
116
117pub fn generate_row_id() -> RowId {
118 ulid::Ulid::new().to_string()
119}