#![cfg(all(feature = "comms", any(unix, windows)))]
use serde::{Deserialize, Serialize};
use super::mode::AgentsMode;
use crate::comms::cursor::Cursor;
use crate::comms::ids::{AgentId, ThreadId};
use crate::comms::model::{AgentRecord, Thread};
use crate::comms::protocol::SeqMeta;
#[derive(Debug, Clone, Deserialize, Serialize, schemars::JsonSchema)]
pub struct AgentsParams {
pub mode: AgentsMode,
#[serde(default)]
pub thread: Option<ThreadId>,
#[serde(default)]
pub member: Option<AgentId>,
#[serde(default)]
pub members: Option<Vec<AgentId>>,
#[serde(default, alias = "id")]
pub message_id: Option<String>,
#[serde(default)]
pub message_ids: Option<Vec<String>>,
#[serde(default)]
pub to_seq: Option<u64>,
#[serde(default)]
pub subject: Option<String>,
#[serde(default)]
pub subject_contains: Option<String>,
#[serde(default)]
pub path: Option<String>,
#[serde(default)]
pub body: Option<String>,
#[serde(default)]
pub tags: Option<Vec<String>>,
#[serde(default)]
pub reply_to: Option<String>,
#[serde(default)]
pub idempotency_key: Option<String>,
#[serde(default)]
pub include_archived: Option<bool>,
#[serde(default)]
pub mark_read: Option<bool>,
#[serde(default)]
pub cursor: Option<String>,
#[serde(default)]
pub limit: Option<u32>,
#[serde(default)]
pub since_hours: Option<u32>,
#[serde(default)]
pub timeout_secs: Option<u32>,
#[serde(default)]
pub name: Option<String>,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub version: Option<String>,
#[serde(default)]
pub skills: Option<Vec<String>>,
#[serde(default)]
pub apply: Option<bool>,
#[serde(default)]
pub message_ttl_hours: Option<u32>,
#[serde(default)]
pub thread_idle_hours: Option<u32>,
#[serde(default)]
pub thread_retention_hours: Option<u32>,
#[serde(default)]
pub agent_ttl_hours: Option<u32>,
#[serde(default)]
pub claim_ttl_hours: Option<u32>,
#[serde(default)]
pub as_agent: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize, schemars::JsonSchema)]
pub struct AgentRegisterParams {
#[serde(default)]
pub name: String,
#[serde(default)]
pub description: String,
#[serde(default)]
pub version: String,
#[serde(default)]
pub skills: Vec<String>,
#[serde(default)]
pub as_agent: Option<String>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct AgentRegisterResponse {
pub agent_id: String,
pub registered: bool,
}
#[derive(Debug, Clone, Deserialize, Serialize, schemars::JsonSchema)]
pub struct AgentListParams {
#[serde(default)]
pub thread: Option<ThreadId>,
#[serde(default)]
pub as_agent: Option<String>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct AgentSummary {
pub agent_id: String,
pub name: String,
pub description: String,
pub version: String,
pub skills: Vec<String>,
pub first_seen: i64,
pub last_seen: i64,
}
impl AgentSummary {
pub(crate) fn from_record(record: &AgentRecord) -> Self {
Self {
agent_id: record.agent_id.as_str().to_string(),
name: record.card.name.clone(),
description: record.card.description.clone(),
version: record.card.version.clone(),
skills: record.card.skills.clone(),
first_seen: record.first_seen,
last_seen: record.last_seen,
}
}
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct AgentListResponse {
pub total: usize,
pub agents: Vec<AgentSummary>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct ThreadSummary {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub subject: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub path: Option<String>,
pub members: Vec<String>,
pub creator: String,
pub active: bool,
pub created_at: i64,
pub last_activity_micros: i64,
pub stale: bool,
}
pub(crate) const STALE_AFTER_HOURS: i64 = 168;
impl ThreadSummary {
pub(crate) fn from_thread(thread: &Thread, now_micros: i64) -> Self {
let last = thread.last_activity;
let window_micros = STALE_AFTER_HOURS * 3_600_000_000;
let stale = last == 0 || (now_micros - last) > window_micros;
Self {
id: thread.id.as_str().to_string(),
subject: thread.subject.clone(),
path: thread.path.clone(),
members: thread.members.iter().map(|m| m.as_str().to_string()).collect(),
creator: thread.creator.as_str().to_string(),
active: thread.active,
created_at: thread.created_at,
last_activity_micros: last,
stale,
}
}
}
#[derive(Debug, Clone, Default, Deserialize, Serialize, schemars::JsonSchema)]
pub struct ThreadStartParams {
#[serde(default)]
pub subject: Option<String>,
#[serde(default)]
pub path: Option<String>,
#[serde(default)]
pub members: Vec<AgentId>,
#[serde(default)]
pub as_agent: Option<String>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct ThreadStartResponse {
pub thread: ThreadSummary,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize, schemars::JsonSchema)]
pub struct ThreadListParams {
#[serde(default)]
pub subject_contains: Option<String>,
#[serde(default)]
pub include_archived: bool,
#[serde(default)]
pub as_agent: Option<String>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct ThreadListResponse {
pub total: usize,
pub threads: Vec<ThreadSummary>,
}
#[derive(Debug, Clone, Deserialize, Serialize, schemars::JsonSchema)]
pub struct ThreadJoinParams {
pub thread: ThreadId,
#[serde(default)]
pub as_agent: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize, schemars::JsonSchema)]
pub struct ThreadLeaveParams {
pub thread: ThreadId,
#[serde(default)]
pub as_agent: Option<String>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct ThreadMembershipResponse {
pub thread: String,
#[serde(skip_serializing_if = "std::ops::Not::not")]
pub joined: bool,
#[serde(skip_serializing_if = "std::ops::Not::not")]
pub left: bool,
}
#[derive(Debug, Clone, Deserialize, Serialize, schemars::JsonSchema)]
pub struct ThreadMembersParams {
pub thread: ThreadId,
#[serde(default)]
pub as_agent: Option<String>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct ThreadMembersResponse {
pub thread: String,
pub members: Vec<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize, schemars::JsonSchema)]
pub struct ThreadMemberParams {
pub thread: ThreadId,
pub member: AgentId,
#[serde(default)]
pub as_agent: Option<String>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct ThreadMemberChangeResponse {
pub thread: String,
pub member: String,
#[serde(skip_serializing_if = "std::ops::Not::not")]
pub added: bool,
#[serde(skip_serializing_if = "std::ops::Not::not")]
pub removed: bool,
}
#[derive(Debug, Clone, Deserialize, Serialize, schemars::JsonSchema)]
pub struct ThreadArchiveParams {
pub thread: ThreadId,
#[serde(default)]
pub as_agent: Option<String>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct ThreadArchiveResponse {
pub thread: String,
pub archived: bool,
}
#[derive(Debug, Clone, Deserialize, Serialize, schemars::JsonSchema)]
pub struct ThreadPostParams {
pub thread: ThreadId,
pub subject: String,
#[serde(default)]
pub body: Option<String>,
#[serde(default)]
pub tags: Option<Vec<String>>,
#[serde(default)]
pub reply_to: Option<String>,
#[serde(default)]
pub idempotency_key: Option<String>,
#[serde(default)]
pub as_agent: Option<String>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct ThreadPostResponse {
pub message_id: String,
}
#[derive(Debug, Clone, Deserialize, Serialize, schemars::JsonSchema)]
pub struct ThreadHistoryParams {
pub thread: ThreadId,
#[serde(default)]
pub cursor: Option<String>,
#[serde(default)]
pub limit: Option<u32>,
#[serde(default)]
pub since_hours: Option<u32>,
#[serde(default)]
pub as_agent: Option<String>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct MessageFrontMatter {
pub message_ref: String,
pub id: String,
pub thread: String,
pub from: String,
pub subject: String,
pub ts_micros: i64,
pub age_secs: i64,
pub tags: Vec<String>,
pub reply_to: Option<String>,
pub seq: u64,
pub body_len: u32,
pub body_sha: String,
}
impl MessageFrontMatter {
pub(crate) fn from_seq_meta(sm: &SeqMeta, now_micros: i64) -> Self {
let meta = &sm.meta;
Self {
message_ref: crate::comms::model::message_reference(&meta.id),
id: meta.id.clone(),
thread: meta.thread.as_str().to_string(),
from: meta.from.as_str().to_string(),
subject: meta.subject.clone(),
ts_micros: meta.ts_micros,
age_secs: ((now_micros - meta.ts_micros) / 1_000_000).max(0),
tags: meta.tags.clone(),
reply_to: meta.reply_to.clone(),
seq: sm.seq,
body_len: meta.body_len,
body_sha: meta.body_sha.clone(),
}
}
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct ThreadHistoryResponse {
pub total: usize,
pub messages: Vec<MessageFrontMatter>,
#[serde(skip_serializing_if = "Option::is_none")]
pub next_cursor: Option<Cursor>,
}
#[derive(Debug, Clone, Deserialize, Serialize, schemars::JsonSchema)]
pub struct MessageGetParams {
pub message_id: String,
#[serde(default)]
pub as_agent: Option<String>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct MessageGetResponse {
pub message_id: String,
pub found: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub body: Option<String>,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize, schemars::JsonSchema)]
pub struct InboxReadParams {
#[serde(default)]
pub cursor: Option<String>,
#[serde(default)]
pub limit: Option<u32>,
#[serde(default)]
pub mark_read: bool,
#[serde(default)]
pub since_hours: Option<u32>,
#[serde(default)]
pub as_agent: Option<String>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct InboxReadResponse {
pub total: usize,
pub unread: u32,
pub messages: Vec<MessageFrontMatter>,
#[serde(skip_serializing_if = "Option::is_none")]
pub next_cursor: Option<Cursor>,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize, schemars::JsonSchema)]
pub struct InboxAckParams {
#[serde(default)]
pub message_ids: Vec<String>,
#[serde(default)]
pub thread: Option<ThreadId>,
#[serde(default)]
pub to_seq: Option<u64>,
#[serde(default)]
pub as_agent: Option<String>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct CursorAdvance {
pub thread: String,
pub seq: u64,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct InboxAckResponse {
pub acked: usize,
pub cursors_advanced: Vec<CursorAdvance>,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize, schemars::JsonSchema)]
pub struct InboxWaitParams {
#[serde(default)]
pub timeout_secs: Option<u32>,
#[serde(default)]
pub thread: Option<ThreadId>,
#[serde(default)]
pub since_hours: Option<u32>,
#[serde(default)]
pub cursor: Option<String>,
#[serde(default)]
pub as_agent: Option<String>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub(crate) struct InboxWaitResponse {
pub timed_out: bool,
pub total: usize,
pub unread: u32,
pub messages: Vec<MessageFrontMatter>,
#[serde(skip_serializing_if = "Option::is_none")]
pub next_cursor: Option<Cursor>,
}