locode_engine/config.rs
1//! Static per-session configuration for the loop.
2
3use std::path::PathBuf;
4use std::time::Duration;
5
6use locode_host::InstructionsConfig;
7use locode_provider::{CacheHint, SamplingArgs};
8
9/// Everything the loop needs that isn't the provider, registry, preamble, or sink.
10#[derive(Debug, Clone)]
11pub struct EngineConfig {
12 /// The session identifier (stamped into the report + `Init`).
13 pub session_id: String,
14 /// The harness pack in use, e.g. `grok` (stamped into the report + `Init`).
15 pub harness: String,
16 /// The wire schema in use, e.g. `anthropic`/`mock` (the provider's `api_schema`).
17 pub api_schema: String,
18 /// The model id (for `Init`).
19 pub model: String,
20 /// The working directory handed to each tool call.
21 pub cwd: PathBuf,
22 /// The path-jail root (ADR-0008), handed to each `ToolCtx`.
23 pub workspace_root: PathBuf,
24 /// The max sample→dispatch turns before terminating with `MaxTurns`
25 /// (ADR-0005 amendment 2026-07-18). **`None` (the default) = unlimited** —
26 /// every studied harness defaults to no cap (Claude Code's `maxTurns?` is
27 /// enforced only when set; grok's `max_turns: Option<u32>` defaults `None`;
28 /// codex has no turn cap at all).
29 pub max_turns: Option<u32>,
30 /// Bounded loop-level resample budget on retryable provider errors (ADR-0007).
31 pub resample_retries: u32,
32 /// Base backoff between resamples; the nth retry waits `base * n`. Set to zero
33 /// in tests to avoid real sleeps.
34 pub resample_backoff: Duration,
35 /// Provider-neutral sampling knobs.
36 pub sampling_args: SamplingArgs,
37 /// Prompt-cache placement hint for the wire.
38 pub cache_hint: CacheHint,
39 /// Use the streaming sample path ([`locode_provider::Provider::stream`]) instead of
40 /// [`locode_provider::Provider::complete`] (ADR-0021). Default **false** — the headless one-shot
41 /// stays non-streaming; the TUI sets this, and headless can opt in via
42 /// `--stream` (Anthropic rejects non-streaming requests past ~10 min, so
43 /// streaming is required for unbounded output). Emits `Event::MessageDelta`s;
44 /// the final `Message` is still appended whole, so the trace can stay
45 /// whole-message by dropping the deltas (Q1).
46 pub streaming: bool,
47 /// Shared project-instruction loading (`AGENTS.md`, ADR-0023): discovered from `cwd`
48 /// and injected once per session as a `User` `<system-reminder>`. Default = enabled.
49 pub instructions: InstructionsConfig,
50}
51
52impl Default for EngineConfig {
53 fn default() -> Self {
54 Self {
55 session_id: String::new(),
56 harness: String::new(),
57 api_schema: String::new(),
58 model: String::new(),
59 cwd: PathBuf::from("."),
60 workspace_root: PathBuf::from("."),
61 max_turns: None,
62 resample_retries: 2,
63 resample_backoff: Duration::from_millis(500),
64 sampling_args: SamplingArgs::default(),
65 cache_hint: CacheHint::default(),
66 streaming: false,
67 instructions: InstructionsConfig::default(),
68 }
69 }
70}