Skip to main content

hivemind/adapters/
kilo.rs

1//! Kilo adapter - OpenCode-compatible runtime wrapper.
2
3use super::opencode::{OpenCodeAdapter, OpenCodeConfig};
4use super::runtime::{
5    AdapterConfig, ExecutionInput, ExecutionReport, InteractiveAdapterEvent,
6    InteractiveExecutionResult, RuntimeAdapter, RuntimeError,
7};
8use std::path::PathBuf;
9use std::time::Duration;
10use uuid::Uuid;
11
12/// Kilo adapter configuration.
13#[derive(Debug, Clone)]
14pub struct KiloConfig {
15    /// Base adapter config.
16    pub base: AdapterConfig,
17    /// Optional model identifier.
18    pub model: Option<String>,
19    /// Whether to enable verbose output.
20    pub verbose: bool,
21}
22
23impl KiloConfig {
24    /// Creates a new Kilo config.
25    pub fn new(binary_path: PathBuf) -> Self {
26        Self {
27            base: AdapterConfig::new("kilo", binary_path).with_timeout(Duration::from_secs(600)),
28            model: None,
29            verbose: false,
30        }
31    }
32
33    /// Sets the model.
34    #[must_use]
35    pub fn with_model(mut self, model: impl Into<String>) -> Self {
36        self.model = Some(model.into());
37        self
38    }
39
40    /// Enables verbose mode.
41    #[must_use]
42    pub fn with_verbose(mut self, verbose: bool) -> Self {
43        self.verbose = verbose;
44        self
45    }
46}
47
48impl Default for KiloConfig {
49    fn default() -> Self {
50        Self::new(PathBuf::from("kilo"))
51    }
52}
53
54/// Kilo runtime adapter.
55pub struct KiloAdapter {
56    inner: OpenCodeAdapter,
57}
58
59impl KiloAdapter {
60    /// Creates a new adapter.
61    pub fn new(config: KiloConfig) -> Self {
62        let mut inner = OpenCodeConfig::new(config.base.binary_path);
63        inner.base.name = "kilo".to_string();
64        inner.base.args = config.base.args;
65        inner.base.env = config.base.env;
66        inner.base.timeout = config.base.timeout;
67        inner.model = config.model;
68        inner.verbose = config.verbose;
69        Self {
70            inner: OpenCodeAdapter::new(inner),
71        }
72    }
73
74    /// Creates an adapter with defaults.
75    pub fn with_defaults() -> Self {
76        Self::new(KiloConfig::default())
77    }
78
79    pub fn execute_interactive<F>(
80        &mut self,
81        input: &ExecutionInput,
82        on_event: F,
83    ) -> Result<InteractiveExecutionResult, RuntimeError>
84    where
85        F: FnMut(InteractiveAdapterEvent) -> std::result::Result<(), String>,
86    {
87        self.inner.execute_interactive(input, on_event)
88    }
89}
90
91impl RuntimeAdapter for KiloAdapter {
92    fn name(&self) -> &str {
93        self.inner.name()
94    }
95
96    fn initialize(&mut self) -> Result<(), RuntimeError> {
97        self.inner.initialize()
98    }
99
100    fn prepare(&mut self, task_id: Uuid, worktree: &std::path::Path) -> Result<(), RuntimeError> {
101        self.inner.prepare(task_id, worktree)
102    }
103
104    fn execute(&mut self, input: ExecutionInput) -> Result<ExecutionReport, RuntimeError> {
105        self.inner.execute(input)
106    }
107
108    fn terminate(&mut self) -> Result<(), RuntimeError> {
109        self.inner.terminate()
110    }
111
112    fn config(&self) -> &AdapterConfig {
113        self.inner.config()
114    }
115}