Skip to main content

scv_protocol/
attachment.rs

1//! Files that travel with a turn or a reply.
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use crate::CHAT_ATTACH_TOOL;
7
8/// A file a client attaches to its turn, already saved on the daemon's host,
9/// such as a photo or document a chat user sent.
10#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
11pub struct Attachment {
12    /// `image`, `audio`, `video`, `file`, or `sticker`.
13    pub kind: String,
14    /// Absolute path of a regular file on the daemon's host.
15    pub path: String,
16    /// The name the sender gave it; empty when the platform has none.
17    #[serde(default, skip_serializing_if = "String::is_empty")]
18    pub name: String,
19    /// MIME type, such as `image/png`; empty when unknown.
20    #[serde(default, skip_serializing_if = "String::is_empty")]
21    pub mime: String,
22    /// Size in bytes.
23    pub size: u64,
24    /// What a voice message said, when the platform transcribed it.
25    #[serde(default, skip_serializing_if = "Option::is_none")]
26    pub transcript: Option<String>,
27}
28
29/// A file the model attached to its reply with [`CHAT_ATTACH_TOOL`], as the
30/// tool's successful `tool.completed` output reports it.
31#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
32pub struct ReplyAttachment {
33    /// Absolute, symlink-free path of the file the tool checked.
34    pub path: String,
35    /// The name to show the recipient.
36    pub name: String,
37    /// MIME type, such as `application/pdf`; empty when unknown.
38    #[serde(default, skip_serializing_if = "String::is_empty")]
39    pub mime: String,
40    /// Size in bytes.
41    pub size: u64,
42    /// Text sent with the file, if any.
43    #[serde(default, skip_serializing_if = "String::is_empty")]
44    pub caption: String,
45}
46
47/// The attachment a successful [`CHAT_ATTACH_TOOL`] call reports: its output
48/// is `{"attached": {...}, ...}`. Anything else is `None`.
49pub fn reply_attachment(tool: &str, success: bool, output: &str) -> Option<ReplyAttachment> {
50    if tool != CHAT_ATTACH_TOOL || !success {
51        return None;
52    }
53    let value: Value = serde_json::from_str(output).ok()?;
54    serde_json::from_value(value.get("attached")?.clone()).ok()
55}