chimera_opencode/
backend.rs1use bon::Builder;
2
3use chimera_core::*;
4
5use crate::config::{OpenCodeConfig, OpenCodeProvider};
6use crate::session::OpenCodeSession;
7
8#[derive(Debug, Builder)]
9pub struct OpenCodeBackend {
10 #[builder(into)]
11 pub(crate) api_key: Option<String>,
12
13 pub(crate) provider: Option<OpenCodeProvider>,
14}
15
16impl OpenCodeBackend {
17 pub fn from_env() -> Self {
19 let api_key = std::env::var("OPENCODE_ZEN_KEY")
20 .ok()
21 .or_else(|| std::env::var("OPENCODE_API_KEY").ok());
22 Self {
23 api_key,
24 provider: None,
25 }
26 }
27}
28
29impl Backend for OpenCodeBackend {
30 type Config = OpenCodeConfig;
31 type Session = OpenCodeSession;
32
33 fn name(&self) -> &'static str {
34 "opencode"
35 }
36
37 async fn session(&self, config: SessionConfig<OpenCodeConfig>) -> Result<OpenCodeSession> {
38 let api_key = config
39 .backend
40 .api_key
41 .clone()
42 .or_else(|| self.api_key.clone());
43 let provider = self
44 .provider
45 .clone()
46 .unwrap_or_else(|| config.backend.provider.clone());
47
48 Ok(OpenCodeSession::new(api_key, provider, config))
49 }
50
51 async fn resume(
52 &self,
53 session_id: &str,
54 config: SessionConfig<OpenCodeConfig>,
55 ) -> Result<OpenCodeSession> {
56 let api_key = config
57 .backend
58 .api_key
59 .clone()
60 .or_else(|| self.api_key.clone());
61 let provider = self
62 .provider
63 .clone()
64 .unwrap_or_else(|| config.backend.provider.clone());
65
66 Ok(OpenCodeSession::new(api_key, provider, config).with_session_id(session_id.to_owned()))
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn backend_name() {
76 let backend = OpenCodeBackend::builder().build();
77 assert_eq!(backend.name(), "opencode");
78 }
79
80 #[tokio::test]
81 async fn session_merges_api_key() {
82 let backend = OpenCodeBackend::builder().api_key("backend-key").build();
83 let config = SessionConfig::builder()
84 .backend(OpenCodeConfig::default())
85 .build();
86
87 let session = backend.session(config).await.unwrap();
88 assert_eq!(session.api_key(), Some("backend-key"));
89 }
90
91 #[tokio::test]
92 async fn session_config_overrides_backend_key() {
93 let backend = OpenCodeBackend::builder().api_key("backend-key").build();
94 let config = SessionConfig::builder()
95 .backend(OpenCodeConfig::builder().api_key("session-key").build())
96 .build();
97
98 let session = backend.session(config).await.unwrap();
99 assert_eq!(session.api_key(), Some("session-key"));
100 }
101
102 #[tokio::test]
103 async fn resume_sets_session_id() {
104 let backend = OpenCodeBackend::builder().build();
105 let config = SessionConfig::builder()
106 .backend(OpenCodeConfig::default())
107 .build();
108
109 let session = backend.resume("sess-abc", config).await.unwrap();
110 assert_eq!(session.session_id(), Some("sess-abc"));
111 }
112}