Skip to main content

ito_core/harness/
opencode.rs

1use super::streaming_cli::run_streaming_cli;
2use super::types::{Harness, HarnessName, HarnessRunConfig, HarnessRunResult};
3use miette::Result;
4
5#[derive(Debug, Default)]
6/// Harness implementation that executes the `opencode` CLI.
7pub struct OpencodeHarness;
8
9impl Harness for OpencodeHarness {
10    /// The harness identifier for this implementation.
11    ///
12    /// # Examples
13    ///
14    /// ```
15    /// use ito_core::harness::{Harness, HarnessName, OpencodeHarness};
16    ///
17    /// let h = OpencodeHarness::default();
18    /// assert_eq!(h.name(), HarnessName::OPENCODE);
19    /// ```
20    fn name(&self) -> HarnessName {
21        HarnessName::OPENCODE
22    }
23
24    /// Run the opencode CLI with the provided harness configuration and stream its output.
25    ///
26    /// The command invoked is `opencode run` with an optional `-m <model>` flag when `config.model` is set,
27    /// followed by the prompt from `config.prompt`.
28    ///
29    /// # Returns
30    ///
31    /// A `HarnessRunResult` describing the outcome of the CLI run.
32    ///
33    /// # Examples
34    ///
35    /// ```ignore
36    /// let mut harness = OpencodeHarness::default();
37    /// let config = HarnessRunConfig { prompt: "Generate a Rust function".into(), model: None, ..Default::default() };
38    /// let result = harness.run(&config).unwrap();
39    /// // Inspect `result` for run details
40    /// ```
41    fn run(&mut self, config: &HarnessRunConfig) -> Result<HarnessRunResult> {
42        let mut args = vec!["run".to_string()];
43        if let Some(model) = config.model.as_deref() {
44            args.push("-m".to_string());
45            args.push(model.to_string());
46        }
47        args.push(config.prompt.clone());
48
49        run_streaming_cli("opencode", &args, config)
50    }
51
52    /// Stops the harness. This implementation is a no-op because `run` completes synchronously.
53    ///
54    /// # Examples
55    ///
56    /// ```
57    /// use ito_core::harness::{Harness, OpencodeHarness};
58    ///
59    /// let mut h = OpencodeHarness::default();
60    /// h.stop();
61    /// ```
62    fn stop(&mut self) {
63        // No-op: `run` is synchronous.
64    }
65
66    /// Indicates whether the harness produces streaming output.
67    ///
68    /// # Examples
69    ///
70    /// ```
71    /// use ito_core::harness::{Harness, OpencodeHarness};
72    ///
73    /// let h = OpencodeHarness::default();
74    /// assert!(h.streams_output());
75    /// ```
76    fn streams_output(&self) -> bool {
77        true
78    }
79}