1use steer_core::{
8 app::conversation::{AppCommandType, CommandResponse as CoreCommandResponse, Message},
9 session::McpServerInfo,
10};
11use steer_tools::ToolCall;
12use time::OffsetDateTime;
13
14pub type RowId = String;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum NoticeLevel {
19 Error,
20 Warn,
21 Info,
22}
23
24#[derive(Debug, Clone)]
26pub enum ChatItemData {
27 Message(Message),
29
30 PendingToolCall {
32 id: RowId,
33 tool_call: ToolCall,
34 ts: OffsetDateTime,
35 },
36
37 SlashInput {
39 id: RowId,
40 raw: String,
41 ts: OffsetDateTime,
42 },
43
44 SystemNotice {
46 id: RowId,
47 level: NoticeLevel,
48 text: String,
49 ts: OffsetDateTime,
50 },
51
52 CoreCmdResponse {
54 id: RowId,
55 command: AppCommandType,
56 response: CoreCommandResponse,
57 ts: OffsetDateTime,
58 },
59
60 TuiCommandResponse {
62 id: RowId,
63 command: String,
64 response: TuiCommandResponse,
65 ts: OffsetDateTime,
66 },
67
68 InFlightOperation {
69 id: RowId,
70 operation_id: uuid::Uuid,
71 label: String,
72 ts: OffsetDateTime,
73 },
74}
75
76#[derive(Debug, Clone)]
77pub enum TuiCommandResponse {
78 Text(String),
79 Theme { name: String },
80 ListThemes(Vec<String>),
81 ListMcpServers(Vec<McpServerInfo>),
82}
83
84#[derive(Debug, Clone)]
85pub enum CommandResponse {
86 Core(CoreCommandResponse),
87 Tui(TuiCommandResponse),
88}
89impl From<CoreCommandResponse> for CommandResponse {
90 fn from(response: CoreCommandResponse) -> Self {
91 CommandResponse::Core(response)
92 }
93}
94impl From<TuiCommandResponse> for CommandResponse {
95 fn from(response: TuiCommandResponse) -> Self {
96 CommandResponse::Tui(response)
97 }
98}
99
100#[derive(Debug, Clone)]
101pub struct ChatItem {
102 pub parent_chat_item_id: Option<RowId>,
103 pub data: ChatItemData,
104}
105
106impl ChatItem {
107 pub fn id(&self) -> &str {
109 match &self.data {
110 ChatItemData::Message(row) => row.id(),
111 ChatItemData::PendingToolCall { id, .. } => id,
112 ChatItemData::SlashInput { id, .. } => id,
113 ChatItemData::CoreCmdResponse { id, .. } => id,
114 ChatItemData::SystemNotice { id, .. } => id,
115 ChatItemData::TuiCommandResponse { id, .. } => id,
116 ChatItemData::InFlightOperation { id, .. } => id,
117 }
118 }
119
120 pub fn timestamp(&self) -> OffsetDateTime {
122 match &self.data {
123 ChatItemData::Message(message) => {
124 OffsetDateTime::from_unix_timestamp(message.timestamp() as i64).unwrap()
125 }
126 ChatItemData::PendingToolCall { ts, .. } => *ts,
127 ChatItemData::SlashInput { ts, .. } => *ts,
128 ChatItemData::CoreCmdResponse { ts, .. } => *ts,
129 ChatItemData::SystemNotice { ts, .. } => *ts,
130 ChatItemData::TuiCommandResponse { ts, .. } => *ts,
131 ChatItemData::InFlightOperation { ts, .. } => *ts,
132 }
133 }
134
135 pub fn parent_message_id(&self) -> Option<&str> {
137 match &self.data {
138 ChatItemData::Message(msg) => msg.parent_message_id(),
139 _ => None,
140 }
141 }
142}
143
144pub fn generate_row_id() -> RowId {
145 ulid::Ulid::new().to_string()
146}