use serde::{Deserialize, Serialize};
use serde_json;
use crate::session::SessionMode;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum ClientMessage {
#[serde(rename = "session.create", rename_all = "camelCase")]
SessionCreate {
id: String,
name: String,
workdir: String,
},
#[serde(rename = "session.list", rename_all = "camelCase")]
SessionList { id: String },
#[serde(rename = "models.list", rename_all = "camelCase")]
ModelsList { id: String },
#[serde(rename = "session.attach", rename_all = "camelCase")]
SessionAttach { id: String, session_id: String },
#[serde(rename = "session.detach", rename_all = "camelCase")]
SessionDetach { id: String, session_id: String },
#[serde(rename = "session.send", rename_all = "camelCase")]
SessionSend {
id: String,
session_id: String,
text: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
attachments: Option<Vec<Attachment>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
priority: Option<SendPriority>,
},
#[serde(rename = "session.interrupt", rename_all = "camelCase")]
SessionInterrupt { id: String, session_id: String },
#[serde(rename = "session.approve", rename_all = "camelCase")]
SessionApprove {
id: String,
session_id: String,
approval_id: String,
approved: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
updated_input: Option<serde_json::Value>,
},
#[serde(rename = "session.destroy", rename_all = "camelCase")]
SessionDestroy { id: String, session_id: String },
#[serde(rename = "session.set_mode", rename_all = "camelCase")]
SessionSetMode {
id: String,
session_id: String,
mode: SessionMode,
#[serde(default, skip_serializing_if = "Option::is_none")]
max_turns: Option<u32>,
},
#[serde(rename = "session.pin", rename_all = "camelCase")]
SessionPin {
id: String,
session_id: String,
path: String,
},
#[serde(rename = "session.unpin", rename_all = "camelCase")]
SessionUnpin {
id: String,
session_id: String,
path: String,
},
#[serde(rename = "session.rotate", rename_all = "camelCase")]
SessionRotate { id: String, session_id: String },
#[serde(rename = "session.search", rename_all = "camelCase")]
SessionSearch {
id: String,
query: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
scope: Option<SearchScope>,
#[serde(default, skip_serializing_if = "Option::is_none")]
workdir: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
limit: Option<u32>,
},
#[serde(rename = "session.set_model", rename_all = "camelCase")]
SessionSetModel {
id: String,
session_id: String,
model: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
fallback_model: Option<Option<String>>,
},
#[serde(rename = "session.rename", rename_all = "camelCase")]
SessionRename {
id: String,
session_id: String,
name: String,
},
#[serde(rename = "claude.config", rename_all = "camelCase")]
ClaudeConfig { id: String, session_id: String },
#[serde(rename = "session.export", rename_all = "camelCase")]
SessionExport {
id: String,
session_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
include_memory: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
include_pinned_files: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
alias_override: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
to_file: Option<bool>,
},
#[serde(rename = "session.import", rename_all = "camelCase")]
SessionImport {
id: String,
source: SessionImportSource,
target_workdir: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
name_override: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
write_pinned_files: Option<bool>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase")]
pub enum SessionImportSource {
Inline { bundle: serde_json::Value },
File { path: String },
}
impl ClientMessage {
#[must_use]
pub fn request_id(&self) -> &str {
match self {
Self::SessionCreate { id, .. }
| Self::SessionList { id }
| Self::ModelsList { id }
| Self::SessionAttach { id, .. }
| Self::SessionDetach { id, .. }
| Self::SessionSend { id, .. }
| Self::SessionInterrupt { id, .. }
| Self::SessionApprove { id, .. }
| Self::SessionDestroy { id, .. }
| Self::SessionSetMode { id, .. }
| Self::SessionPin { id, .. }
| Self::SessionUnpin { id, .. }
| Self::SessionRotate { id, .. }
| Self::SessionSearch { id, .. }
| Self::SessionSetModel { id, .. }
| Self::SessionRename { id, .. }
| Self::ClaudeConfig { id, .. }
| Self::SessionExport { id, .. }
| Self::SessionImport { id, .. } => id,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Attachment {
pub path: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub content: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub mime_type: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub data: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SendPriority {
Now,
Next,
Later,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SearchScope {
Workspace,
All,
}