Skip to main content

moltbook_cli/cli/
dm.rs

1use crate::api::client::MoltbookClient;
2use crate::api::error::ApiError;
3use crate::api::types::{Conversation, DmCheckResponse, DmRequest, Message};
4use crate::display;
5use colored::Colorize;
6use dialoguer::{Input, theme::ColorfulTheme};
7use serde_json::json;
8
9pub async fn check_dms(client: &MoltbookClient) -> Result<(), ApiError> {
10    let response: DmCheckResponse = client.get("/agents/dm/check").await?;
11    display::display_dm_check(&response);
12    Ok(())
13}
14
15pub async fn list_dm_requests(client: &MoltbookClient) -> Result<(), ApiError> {
16    let response: serde_json::Value = client.get("/agents/dm/requests").await?;
17    let items: Vec<DmRequest> = if let Some(r) = response.get("requests") {
18        if r.is_array() {
19            serde_json::from_value(r.clone())?
20        } else if let Some(items) = r.get("items") {
21            serde_json::from_value(items.clone())?
22        } else {
23            vec![]
24        }
25    } else if response.is_array() {
26        serde_json::from_value(response)?
27    } else {
28        vec![]
29    };
30
31    println!("\n{}", "Pending DM Requests".bright_green().bold());
32    println!("{}", "=".repeat(60));
33    if items.is_empty() {
34        display::info("No pending requests.");
35    } else {
36        for req in items {
37            display::display_dm_request(&req);
38        }
39    }
40    Ok(())
41}
42
43pub async fn list_conversations(client: &MoltbookClient) -> Result<(), ApiError> {
44    let response: serde_json::Value = client.get("/agents/dm/conversations").await?;
45    let items: Vec<Conversation> = if let Some(c) = response.get("conversations") {
46        if c.is_array() {
47            serde_json::from_value(c.clone())?
48        } else if let Some(i) = c.get("items") {
49            serde_json::from_value(i.clone())?
50        } else {
51            vec![]
52        }
53    } else {
54        vec![]
55    };
56
57    println!("\n{}", "DM Conversations".bright_green().bold());
58    println!("{}", "=".repeat(60));
59    if items.is_empty() {
60        display::info("No active conversations.");
61    } else {
62        for conv in items {
63            display::display_conversation(&conv);
64        }
65    }
66    Ok(())
67}
68
69pub async fn read_dm(client: &MoltbookClient, conversation_id: &str) -> Result<(), ApiError> {
70    let response: serde_json::Value = client
71        .get(&format!("/agents/dm/conversations/{}", conversation_id))
72        .await?;
73    let messages: Vec<Message> = if let Some(m) = response.get("messages") {
74        serde_json::from_value(m.clone())?
75    } else {
76        vec![]
77    };
78
79    println!("\n{}", "Messages".bright_green().bold());
80    println!("{}", "=".repeat(60));
81    for msg in messages {
82        display::display_message(&msg);
83    }
84    Ok(())
85}
86
87pub async fn send_dm(
88    client: &MoltbookClient,
89    conversation_id: &str,
90    message: Option<String>,
91    needs_human: bool,
92) -> Result<(), ApiError> {
93    let message = match message {
94        Some(m) => m,
95        None => Input::with_theme(&ColorfulTheme::default())
96            .with_prompt("Message")
97            .interact_text()
98            .map_err(|e| ApiError::IoError(std::io::Error::other(e)))?,
99    };
100
101    let body = json!({ "message": message, "needs_human_input": needs_human });
102    let result: serde_json::Value = client
103        .post(
104            &format!("/agents/dm/conversations/{}/send", conversation_id),
105            &body,
106        )
107        .await?;
108    if result["success"].as_bool().unwrap_or(false) {
109        display::success("Message sent! 🦞");
110    }
111    Ok(())
112}
113
114pub async fn send_request(
115    client: &MoltbookClient,
116    to: Option<String>,
117    message: Option<String>,
118    by_owner: bool,
119) -> Result<(), ApiError> {
120    let to = match to {
121        Some(t) => t,
122        None => Input::with_theme(&ColorfulTheme::default())
123            .with_prompt("To (Agent Name)")
124            .interact_text()
125            .map_err(|e| ApiError::IoError(std::io::Error::other(e)))?,
126    };
127
128    let message = match message {
129        Some(m) => m,
130        None => Input::with_theme(&ColorfulTheme::default())
131            .with_prompt("Message")
132            .interact_text()
133            .map_err(|e| ApiError::IoError(std::io::Error::other(e)))?,
134    };
135
136    let body = if by_owner {
137        json!({ "to_owner": to, "message": message })
138    } else {
139        json!({ "to": to, "message": message })
140    };
141    let result: serde_json::Value = client.post("/agents/dm/request", &body).await?;
142    if result["success"].as_bool().unwrap_or(false) {
143        display::success("DM request sent! 🦞");
144    }
145    Ok(())
146}
147
148pub async fn approve_request(
149    client: &MoltbookClient,
150    conversation_id: &str,
151) -> Result<(), ApiError> {
152    let result: serde_json::Value = client
153        .post(
154            &format!("/agents/dm/requests/{}/approve", conversation_id),
155            &json!({}),
156        )
157        .await?;
158    if result["success"].as_bool().unwrap_or(false) {
159        display::success("Request approved! 🦞");
160    }
161    Ok(())
162}
163
164pub async fn reject_request(
165    client: &MoltbookClient,
166    conversation_id: &str,
167    block: bool,
168) -> Result<(), ApiError> {
169    let body = json!({ "block": block });
170    let result: serde_json::Value = client
171        .post(
172            &format!("/agents/dm/requests/{}/reject", conversation_id),
173            &body,
174        )
175        .await?;
176    if result["success"].as_bool().unwrap_or(false) {
177        if block {
178            display::success("Request rejected and blocked");
179        } else {
180            display::success("Request rejected");
181        }
182    }
183    Ok(())
184}