use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AgentMember {
pub agent_id: String,
pub name: String,
pub agent_type: String,
pub model: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub prompt: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub color: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub plan_mode_required: Option<bool>,
pub joined_at: u64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tmux_pane_id: Option<String>,
pub cwd: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub subscriptions: Vec<serde_json::Value>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub backend_type: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub is_active: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub last_active: Option<u64>,
#[serde(flatten)]
pub unknown_fields: HashMap<String, serde_json::Value>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_agent_member_roundtrip_team_lead() {
let json = r#"{
"agentId": "team-lead@test-team",
"name": "team-lead",
"agentType": "general-purpose",
"model": "claude-haiku-4-5-20251001",
"joinedAt": 1770765919076,
"tmuxPaneId": "",
"cwd": "/Users/randlee/Documents/github/test",
"subscriptions": []
}"#;
let member: AgentMember = serde_json::from_str(json).unwrap();
assert_eq!(member.agent_id, "team-lead@test-team");
assert_eq!(member.name, "team-lead");
assert_eq!(member.agent_type, "general-purpose");
assert_eq!(member.model, "claude-haiku-4-5-20251001");
assert_eq!(member.joined_at, 1770765919076);
assert_eq!(member.cwd, "/Users/randlee/Documents/github/test");
assert!(member.prompt.is_none());
assert!(member.color.is_none());
assert!(member.subscriptions.is_empty());
let serialized = serde_json::to_string(&member).unwrap();
let reparsed: AgentMember = serde_json::from_str(&serialized).unwrap();
assert_eq!(member.agent_id, reparsed.agent_id);
}
#[test]
fn test_agent_member_roundtrip_spawned_agent() {
let json = r#"{
"agentId": "haiku-poet-1@test-team",
"name": "haiku-poet-1",
"agentType": "general-purpose",
"model": "claude-opus-4-6",
"prompt": "You are a creative haiku poet.",
"color": "blue",
"planModeRequired": false,
"joinedAt": 1770772206905,
"tmuxPaneId": "%14",
"cwd": "/Users/randlee/Documents/github/test",
"subscriptions": [],
"backendType": "tmux",
"isActive": false
}"#;
let member: AgentMember = serde_json::from_str(json).unwrap();
assert_eq!(member.agent_id, "haiku-poet-1@test-team");
assert_eq!(member.name, "haiku-poet-1");
assert_eq!(member.prompt, Some("You are a creative haiku poet.".to_string()));
assert_eq!(member.color, Some("blue".to_string()));
assert_eq!(member.plan_mode_required, Some(false));
assert_eq!(member.tmux_pane_id, Some("%14".to_string()));
assert_eq!(member.backend_type, Some("tmux".to_string()));
assert_eq!(member.is_active, Some(false));
let serialized = serde_json::to_string(&member).unwrap();
let reparsed: AgentMember = serde_json::from_str(&serialized).unwrap();
assert_eq!(member.prompt, reparsed.prompt);
assert_eq!(member.color, reparsed.color);
}
#[test]
fn test_agent_member_roundtrip_with_unknown_fields() {
let json = r#"{
"agentId": "test-agent@test-team",
"name": "test-agent",
"agentType": "general-purpose",
"model": "claude-sonnet-4-5-20250929",
"joinedAt": 1770765919076,
"cwd": "/test",
"unknownField": "value",
"futureFeature": {"nested": "data"}
}"#;
let member: AgentMember = serde_json::from_str(json).unwrap();
assert_eq!(member.agent_id, "test-agent@test-team");
assert_eq!(member.unknown_fields.len(), 2);
assert!(member.unknown_fields.contains_key("unknownField"));
assert!(member.unknown_fields.contains_key("futureFeature"));
let serialized = serde_json::to_string(&member).unwrap();
let reparsed: AgentMember = serde_json::from_str(&serialized).unwrap();
assert_eq!(member.unknown_fields.len(), reparsed.unknown_fields.len());
assert_eq!(
member.unknown_fields.get("unknownField"),
reparsed.unknown_fields.get("unknownField")
);
}
#[test]
fn test_agent_member_missing_optional_fields() {
let json = r#"{
"agentId": "test@team",
"name": "test",
"agentType": "general-purpose",
"model": "claude-opus-4-6",
"joinedAt": 1770765919076,
"cwd": "/test"
}"#;
let member: AgentMember = serde_json::from_str(json).unwrap();
assert!(member.prompt.is_none());
assert!(member.color.is_none());
assert!(member.plan_mode_required.is_none());
assert!(member.tmux_pane_id.is_none());
assert!(member.backend_type.is_none());
assert!(member.is_active.is_none());
assert!(member.subscriptions.is_empty());
}
}