1use crate::map::HeaderMap;
4use crate::schema::HeaderSchema;
5use crate::schemas::{ClaudeCodeHeaders, ClineHeaders, CodexCliHeaders, CopilotCliHeaders, OpencodeHeaders};
6use crate::vars::TemplateVars;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub enum AgentKind {
10 Opencode,
11 CodexCli,
12 ClaudeCode,
13 Cline,
14 CopilotCli,
15}
16
17impl AgentKind {
18 pub fn from_agent_id(agent_id: &str) -> Option<Self> {
19 match agent_id {
20 "opencode" => Some(Self::Opencode),
21 "codex_exec" | "codex-tui" | "codex" | "codex-cli" => Some(Self::CodexCli),
22 "claude-cli" | "claude-code" => Some(Self::ClaudeCode),
23 "cline" => Some(Self::Cline),
24 "copilot" | "copilot-cli" => Some(Self::CopilotCli),
25 _ => None,
26 }
27 }
28
29 pub fn build_outbound(self, vars: &TemplateVars, inbound: &HeaderMap) -> HeaderMap {
30 match self {
31 Self::Opencode => OpencodeHeaders::build(vars, inbound).dump(),
32 Self::CodexCli => CodexCliHeaders::build(vars, inbound).dump(),
33 Self::ClaudeCode => ClaudeCodeHeaders::build(vars, inbound).dump(),
34 Self::Cline => ClineHeaders::build(vars, inbound).dump(),
35 Self::CopilotCli => CopilotCliHeaders::build(vars, inbound).dump(),
36 }
37 }
38}
39
40pub fn build_agent_headers(agent_id: &str, vars: &TemplateVars, inbound: &HeaderMap) -> HeaderMap {
41 AgentKind::from_agent_id(agent_id)
42 .map(|kind| kind.build_outbound(vars, inbound))
43 .unwrap_or_default()
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 #[test]
51 fn known_agents_round_trip() {
52 for (slug, expected) in [
53 ("opencode", AgentKind::Opencode),
54 ("codex-cli", AgentKind::CodexCli),
55 ("claude-code", AgentKind::ClaudeCode),
56 ("cline", AgentKind::Cline),
57 ("copilot-cli", AgentKind::CopilotCli),
58 ] {
59 assert_eq!(AgentKind::from_agent_id(slug), Some(expected));
60 }
61 }
62
63 #[test]
64 fn aliases_normalize() {
65 assert_eq!(AgentKind::from_agent_id("codex"), Some(AgentKind::CodexCli));
66 assert_eq!(AgentKind::from_agent_id("codex_exec"), Some(AgentKind::CodexCli));
67 assert_eq!(AgentKind::from_agent_id("claude-cli"), Some(AgentKind::ClaudeCode));
68 assert_eq!(AgentKind::from_agent_id("copilot"), Some(AgentKind::CopilotCli));
69 }
70
71 #[test]
72 fn unknown_agent_yields_empty_header_map() {
73 let out = build_agent_headers("anything", &TemplateVars::default(), &HeaderMap::new());
74 assert_eq!(out.len(), 0);
75 }
76
77 #[test]
78 fn build_outbound_for_known_agent_returns_nonempty_map() {
79 let vars = TemplateVars::default();
80 let inbound = HeaderMap::new();
81 for kind in [
82 AgentKind::Opencode,
83 AgentKind::CodexCli,
84 AgentKind::ClaudeCode,
85 AgentKind::Cline,
86 AgentKind::CopilotCli,
87 ] {
88 let out = kind.build_outbound(&vars, &inbound);
89 assert!(!out.is_empty(), "{kind:?} should build a non-empty HeaderMap");
90 }
91 }
92}