1use serde::{Deserialize, Serialize};
4
5pub const DEFAULT_MODEL: &str = "anthropic/claude-sonnet-4-20250514";
7pub const OPENROUTER_BASE_URL: &str = "https://openrouter.ai/api/v1";
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
17pub enum ApiMode {
18 ChatCompletions,
19 AnthropicMessages,
20 CodexResponses,
21}
22
23impl ApiMode {
24 pub fn detect(base_url: &str, model: &str) -> Self {
26 if base_url.contains("api.anthropic.com") {
27 ApiMode::AnthropicMessages
28 } else if base_url.contains("api.openai.com") && model.contains("codex") {
29 ApiMode::CodexResponses
30 } else {
31 ApiMode::ChatCompletions
32 }
33 }
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
38#[serde(rename_all = "lowercase")]
39pub enum Platform {
40 #[default]
41 Cli,
42 Telegram,
43 Discord,
44 Slack,
45 Whatsapp,
46 Feishu,
47 Wecom,
48 Signal,
49 Email,
50 Matrix,
51 Mattermost,
52 DingTalk,
53 Sms,
54 Webhook,
55 Api,
56 HomeAssistant,
57 Acp,
58 Cron,
60}
61
62impl std::fmt::Display for Platform {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 let s = match self {
65 Platform::Cli => "cli",
66 Platform::Telegram => "telegram",
67 Platform::Discord => "discord",
68 Platform::Slack => "slack",
69 Platform::Whatsapp => "whatsapp",
70 Platform::Feishu => "feishu",
71 Platform::Wecom => "wecom",
72 Platform::Signal => "signal",
73 Platform::Email => "email",
74 Platform::Matrix => "matrix",
75 Platform::Mattermost => "mattermost",
76 Platform::DingTalk => "dingtalk",
77 Platform::Sms => "sms",
78 Platform::Webhook => "webhook",
79 Platform::Api => "api",
80 Platform::HomeAssistant => "homeassistant",
81 Platform::Acp => "acp",
82 Platform::Cron => "cron",
83 };
84 write!(f, "{s}")
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn api_mode_detect_anthropic() {
94 assert_eq!(
95 ApiMode::detect("https://api.anthropic.com/v1", "claude-4"),
96 ApiMode::AnthropicMessages
97 );
98 }
99
100 #[test]
101 fn api_mode_detect_codex() {
102 assert_eq!(
103 ApiMode::detect("https://api.openai.com/v1", "codex-mini"),
104 ApiMode::CodexResponses
105 );
106 }
107
108 #[test]
109 fn api_mode_detect_default() {
110 assert_eq!(
111 ApiMode::detect("https://openrouter.ai/api/v1", "anthropic/claude-4"),
112 ApiMode::ChatCompletions
113 );
114 }
115
116 #[test]
117 fn platform_display() {
118 assert_eq!(format!("{}", Platform::Cli), "cli");
119 assert_eq!(format!("{}", Platform::Telegram), "telegram");
120 }
121
122 #[test]
123 fn platform_serde_roundtrip() {
124 for p in [
125 Platform::Cli,
126 Platform::Telegram,
127 Platform::Discord,
128 Platform::Slack,
129 Platform::Feishu,
130 Platform::Wecom,
131 ] {
132 let json = serde_json::to_string(&p).expect("serialize");
133 let deser: Platform = serde_json::from_str(&json).expect("deserialize");
134 assert_eq!(p, deser);
135 }
136 }
137}