chimera_opencode/
config.rs1use bon::Builder;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
6#[serde(rename_all = "snake_case")]
7#[non_exhaustive]
8#[derive(Default)]
9pub enum OpenCodeProvider {
10 #[default]
12 Zen,
13 Direct { base_url: String },
15}
16
17impl OpenCodeProvider {
18 pub fn base_url(&self) -> &str {
19 match self {
20 Self::Zen => "https://opencode.ai/zen/v1",
21 Self::Direct { base_url } => base_url.as_str(),
22 }
23 }
24}
25
26#[derive(Debug, Clone, Builder, Serialize, Deserialize)]
27pub struct OpenCodeConfig {
28 #[builder(into)]
30 pub api_key: Option<String>,
31
32 #[builder(default)]
34 pub provider: OpenCodeProvider,
35
36 pub timeout_secs: Option<u64>,
38
39 pub max_retries: Option<u32>,
41
42 pub max_tokens: Option<u32>,
44
45 pub temperature: Option<f32>,
47
48 #[builder(default = true)]
50 pub stream: bool,
51}
52
53impl Default for OpenCodeConfig {
54 fn default() -> Self {
55 Self {
56 api_key: None,
57 provider: OpenCodeProvider::default(),
58 timeout_secs: None,
59 max_retries: None,
60 max_tokens: None,
61 temperature: None,
62 stream: true,
63 }
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn config_defaults() {
73 let config = OpenCodeConfig::default();
74 assert!(config.api_key.is_none());
75 assert!(matches!(config.provider, OpenCodeProvider::Zen));
76 assert!(config.timeout_secs.is_none());
77 assert!(config.max_retries.is_none());
78 assert!(config.max_tokens.is_none());
79 assert!(config.temperature.is_none());
80 assert!(config.stream);
81 }
82
83 #[test]
84 fn config_builder() {
85 let config = OpenCodeConfig::builder()
86 .api_key("sk-test")
87 .provider(OpenCodeProvider::Direct {
88 base_url: "http://localhost:8080".into(),
89 })
90 .timeout_secs(60)
91 .max_retries(3)
92 .stream(false)
93 .build();
94
95 assert_eq!(config.api_key.as_deref(), Some("sk-test"));
96 assert_eq!(config.timeout_secs, Some(60));
97 assert_eq!(config.max_retries, Some(3));
98 assert!(!config.stream);
99 }
100
101 #[test]
102 fn provider_base_url_zen() {
103 let p = OpenCodeProvider::Zen;
104 assert_eq!(p.base_url(), "https://opencode.ai/zen/v1");
105 }
106
107 #[test]
108 fn provider_base_url_direct() {
109 let p = OpenCodeProvider::Direct {
110 base_url: "http://localhost:3000/v1".into(),
111 };
112 assert_eq!(p.base_url(), "http://localhost:3000/v1");
113 }
114
115 #[test]
116 fn config_serde_roundtrip() {
117 let config = OpenCodeConfig::builder()
118 .api_key("key")
119 .max_tokens(4096)
120 .build();
121
122 let json = serde_json::to_string(&config).unwrap();
123 let parsed: OpenCodeConfig = serde_json::from_str(&json).unwrap();
124 assert_eq!(parsed.api_key.as_deref(), Some("key"));
125 assert_eq!(parsed.max_tokens, Some(4096));
126 }
127}