Skip to main content

harn_cli/commands/run/
llm_mock.rs

1use std::path::PathBuf;
2
3#[derive(Clone, Debug, Default, PartialEq, Eq)]
4pub enum CliLlmMockMode {
5    #[default]
6    Off,
7    Replay {
8        fixture_path: PathBuf,
9    },
10    Record {
11        fixture_path: PathBuf,
12    },
13}
14
15pub fn install_cli_llm_mock_mode(mode: &CliLlmMockMode) -> Result<(), String> {
16    match mode {
17        CliLlmMockMode::Off => {
18            harn_vm::llm::clear_cli_llm_mock_mode();
19            Ok(())
20        }
21        CliLlmMockMode::Replay { fixture_path } => {
22            let text = std::fs::read_to_string(fixture_path)
23                .map_err(|error| format!("failed to read {}: {error}", fixture_path.display()))?;
24            let fixture = harn_vm::llm::parse_llm_mocks_jsonl(&text).map_err(|error| {
25                format!(
26                    "invalid LLM mock fixture in {}: {error}",
27                    fixture_path.display()
28                )
29            })?;
30            crate::skill_loader::emit_loader_warnings(&fixture.warnings);
31            harn_vm::llm::clear_cli_llm_mock_mode();
32            harn_vm::llm::install_cli_llm_mock_fixture(fixture);
33            Ok(())
34        }
35        CliLlmMockMode::Record { .. } => {
36            harn_vm::llm::clear_cli_llm_mock_mode();
37            harn_vm::llm::enable_cli_llm_mock_recording();
38            Ok(())
39        }
40    }
41}
42
43pub fn persist_cli_llm_mock_recording(mode: &CliLlmMockMode) -> Result<(), String> {
44    let CliLlmMockMode::Record { fixture_path } = mode else {
45        harn_vm::llm::clear_cli_llm_mock_mode();
46        return Ok(());
47    };
48    let body = harn_vm::llm::serialize_llm_mock_fixture(harn_vm::llm::take_cli_llm_recordings())?;
49    let result = harn_vm::atomic_io::atomic_write(fixture_path, body.as_bytes())
50        .map_err(|error| format!("failed to write {}: {error}", fixture_path.display()));
51    harn_vm::llm::clear_cli_llm_mock_mode();
52    result
53}