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}