gitdataai/libs/queue/types.rs

233 lines
7.2 KiB
Rust

//! Message types shared between producer and worker.
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RoomMessageEnvelope {
pub id: Uuid,
pub dedup_key: Option<String>,
pub room_id: Uuid,
pub sender_type: String,
pub sender_id: Option<Uuid>,
/// AI model ID — set when sender_type = "ai", used for display name lookups.
pub model_id: Option<Uuid>,
pub thread_id: Option<Uuid>,
pub in_reply_to: Option<Uuid>,
pub content: String,
pub content_type: String,
/// Accumulated AI reasoning/thinking text.
#[serde(skip_serializing_if = "Option::is_none")]
pub thinking_content: Option<String>,
pub send_at: DateTime<Utc>,
pub seq: i64,
/// Pre-resolved display name for the sender (e.g. AI model name).
#[serde(skip_serializing_if = "Option::is_none")]
pub display_name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RoomMessageEvent {
pub id: Uuid,
pub room_id: Uuid,
pub sender_type: String,
pub sender_id: Option<Uuid>,
pub thread_id: Option<Uuid>,
pub in_reply_to: Option<Uuid>,
pub content: String,
pub content_type: String,
/// Accumulated AI reasoning/thinking text.
#[serde(skip_serializing_if = "Option::is_none")]
pub thinking_content: Option<String>,
pub send_at: DateTime<Utc>,
pub seq: i64,
pub display_name: Option<String>,
/// Present when this event carries reaction updates for the message.
#[serde(skip_serializing_if = "Option::is_none")]
pub reactions: Option<Vec<ReactionGroup>>,
/// Target message ID for reaction update events.
#[serde(skip_serializing_if = "Option::is_none")]
pub message_id: Option<Uuid>,
}
/// Typing indicator event — broadcast to all room members.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TypingEvent {
pub room_id: Uuid,
pub user_id: Uuid,
pub username: String,
pub avatar_url: Option<String>,
/// "start" or "stop"
pub action: String,
/// Sender type: "user" or "ai". Defaults to "user" if absent.
#[serde(skip_serializing_if = "Option::is_none")]
pub sender_type: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReactionGroup {
pub emoji: String,
pub count: i32,
pub reacted_by_me: bool,
/// Stored as strings (UUIDs) to match the frontend's `users: string[]` type.
pub users: Vec<String>,
}
impl From<RoomMessageEnvelope> for RoomMessageEvent {
fn from(e: RoomMessageEnvelope) -> Self {
Self {
id: e.id,
room_id: e.room_id,
sender_type: e.sender_type,
sender_id: e.sender_id,
thread_id: e.thread_id,
in_reply_to: e.in_reply_to,
content: e.content,
content_type: e.content_type,
thinking_content: e.thinking_content,
send_at: e.send_at,
seq: e.seq,
display_name: e.display_name,
reactions: None,
message_id: None,
}
}
}
impl From<RoomMessageEvent> for RoomMessageEnvelope {
fn from(e: RoomMessageEvent) -> Self {
Self {
id: e.id,
dedup_key: None,
room_id: e.room_id,
sender_type: e.sender_type,
sender_id: e.sender_id,
model_id: None,
thread_id: e.thread_id,
in_reply_to: e.in_reply_to,
content: e.content,
content_type: e.content_type,
thinking_content: e.thinking_content,
send_at: e.send_at,
seq: e.seq,
display_name: e.display_name,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProjectRoomEvent {
pub event_type: String,
pub project_id: Uuid,
pub room_id: Option<Uuid>,
pub category_id: Option<Uuid>,
pub message_id: Option<Uuid>,
pub seq: Option<i64>,
pub timestamp: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RoomMessageStreamChunkEvent {
pub message_id: Uuid,
pub room_id: Uuid,
/// Monotonically increasing sequence number for ordering within this stream.
#[serde(default)]
pub seq: u64,
pub content: String,
pub done: bool,
pub error: Option<String>,
/// Human-readable AI model name (e.g. "Claude 3.5 Sonnet") for display.
pub display_name: Option<String>,
/// What kind of content this chunk contains: "thinking", "answer", "tool_call", "tool_result".
pub chunk_type: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmailEnvelope {
pub id: Uuid,
pub to: String,
pub subject: String,
pub body: String,
pub created_at: DateTime<Utc>,
}
/// Agent task event published via NATS core to notify WebSocket clients.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentTaskEvent {
/// Task ID
pub task_id: i64,
/// Project this task belongs to.
pub project_id: Uuid,
/// Parent task ID (null for root tasks).
pub parent_id: Option<i64>,
/// Event type: started | progress | done | failed | child_done
pub event: String,
/// Human-readable progress/status text.
pub message: Option<String>,
/// Task output (only on done event).
pub output: Option<String>,
/// Error message (only on failed event).
pub error: Option<String>,
/// Current status.
pub status: String,
/// Timestamp.
pub timestamp: DateTime<Utc>,
}
/// Chat message event — broadcast via NATS JetStream for persistence + multi-viewer support.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatMessageEvent {
pub message_id: Uuid,
pub conversation_id: Uuid,
pub project_id: Option<Uuid>,
pub sender_id: Uuid,
pub role: String,
pub content: String,
pub model: Option<String>,
pub input_tokens: Option<i32>,
pub output_tokens: Option<i32>,
pub timestamp: DateTime<Utc>,
}
/// Chat stream chunk event — broadcast via NATS JetStream for real-time multi-viewer streaming.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatStreamChunkEvent {
pub conversation_id: Uuid,
pub message_id: Uuid,
pub seq: u64,
pub content: String,
pub done: bool,
pub error: Option<String>,
pub chunk_type: Option<String>,
pub model_name: Option<String>,
}
/// Sub-agent stream chunk event — published to dedicated NATS subject `chat.subagent.chunk.{conversation_id}.{children_id}`.
/// Frontend subscribes to this subject via the sub-agent SSE endpoint using children_id.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubAgentStreamChunkEvent {
pub conversation_id: Uuid,
pub children_id: String,
pub seq: u64,
pub content: String,
pub done: bool,
pub error: Option<String>,
pub chunk_type: Option<String>,
pub role: String,
pub task: String,
}
/// Sub-agent session record — persisted after sub-agent completes.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubAgentSessionRecord {
pub conversation_id: Uuid,
pub children_id: String,
pub role: String,
pub task: String,
pub output: String,
pub input_tokens: i64,
pub output_tokens: i64,
pub created_at: DateTime<Utc>,
}