Skip to main content

oino_settings/
types.rs

1//! Typed setting values and defaults.
2
3use serde::{Deserialize, Serialize};
4
5/// Runtime-setting defaults plus the Oino keys of runtime §10.2.
6pub mod defaults {
7    /// `compaction.enabled`.
8    pub const COMPACTION_ENABLED: bool = true;
9    /// `compaction.reserveTokens`.
10    pub const COMPACTION_RESERVE_TOKENS: u64 = 16_384;
11    /// `compaction.keepRecentTokens`.
12    pub const COMPACTION_KEEP_RECENT_TOKENS: u64 = 20_000;
13    /// `branchSummary.reserveTokens`.
14    pub const BRANCH_SUMMARY_RESERVE_TOKENS: u64 = 16_384;
15    /// `branchSummary.skipPrompt`.
16    pub const BRANCH_SUMMARY_SKIP_PROMPT: bool = false;
17    /// `retry.enabled`.
18    pub const RETRY_ENABLED: bool = true;
19    /// `retry.maxRetries`.
20    pub const RETRY_MAX_RETRIES: u64 = 3;
21    /// `retry.baseDelayMs`.
22    pub const RETRY_BASE_DELAY_MS: u64 = 2_000;
23    /// `retry.maxAgentDelayMs` (default `DEFAULT_MAX_AGENT_RETRY_DELAY_MS`).
24    pub const RETRY_MAX_AGENT_DELAY_MS: u64 = 60_000;
25    /// `retry.provider.maxRetryDelayMs`.
26    pub const RETRY_PROVIDER_MAX_RETRY_DELAY_MS: u64 = 60_000;
27    /// `httpIdleTimeoutMs`.
28    pub const HTTP_IDLE_TIMEOUT_MS: u64 = 300_000;
29    /// `showCacheMissNotices`.
30    pub const SHOW_CACHE_MISS_NOTICES: bool = false;
31    /// `enableSkillCommands`.
32    pub const ENABLE_SKILL_COMMANDS: bool = true;
33    /// `images.autoResize`.
34    pub const IMAGES_AUTO_RESIZE: bool = true;
35    /// `images.blockImages`.
36    pub const IMAGES_BLOCK_IMAGES: bool = false;
37    /// Runtime default thinking level when `defaultThinkingLevel` is unset.
38    pub const THINKING_LEVEL: oino_ai::ThinkingLevel = oino_ai::ThinkingLevel::Medium;
39    /// `serve.bind`.
40    pub const SERVE_BIND: &str = "127.0.0.1:7420";
41    /// `serve.tls`.
42    pub const SERVE_TLS: bool = true;
43    /// `serve.allowRemote`.
44    pub const SERVE_ALLOW_REMOTE: bool = false;
45}
46
47/// Steering / follow-up queue delivery (`steeringMode`, `followUpMode`).
48#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
49pub enum QueueMode {
50    /// Deliver every queued message at once.
51    #[serde(rename = "all")]
52    All,
53    /// Deliver one queued message per turn (default).
54    #[default]
55    #[serde(rename = "one-at-a-time")]
56    OneAtATime,
57}
58
59/// `cacheWarming` profile (global only).
60#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
61#[serde(rename_all = "lowercase")]
62pub enum CacheWarmingMode {
63    /// Never warm.
64    Off,
65    /// Warm while streaming (default).
66    #[default]
67    Streaming,
68    /// Also warm between agent runs.
69    Idle,
70}
71
72/// `defaultProjectTrust` (global only).
73#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
74#[serde(rename_all = "lowercase")]
75pub enum ProjectTrustDefault {
76    /// Ask interactively; non-interactive modes treat it as untrusted (default).
77    #[default]
78    Ask,
79    /// Trust every project.
80    Always,
81    /// Trust no project.
82    Never,
83}
84
85/// `ui.density`: transcript density for render specs (Oino key).
86#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
87#[serde(rename_all = "lowercase")]
88pub enum UiDensity {
89    /// Minimal transcript.
90    Simple,
91    /// Default transcript.
92    #[default]
93    Regular,
94    /// Everything visible.
95    Advanced,
96}
97
98/// Resolved compaction settings.
99#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
100#[serde(rename_all = "camelCase")]
101pub struct CompactionSettings {
102    /// Auto-compaction on/off.
103    pub enabled: bool,
104    /// Tokens reserved for the prompt and response.
105    pub reserve_tokens: u64,
106    /// Recent tokens kept verbatim.
107    pub keep_recent_tokens: u64,
108}
109
110/// Resolved branch summary settings.
111#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
112#[serde(rename_all = "camelCase")]
113pub struct BranchSummarySettings {
114    /// Tokens reserved for the prompt and response.
115    pub reserve_tokens: u64,
116    /// Skip the "Summarize branch?" prompt.
117    pub skip_prompt: bool,
118}
119
120/// Resolved agent-level retry settings.
121#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
122#[serde(rename_all = "camelCase")]
123pub struct RetrySettings {
124    /// Auto-retry on/off.
125    pub enabled: bool,
126    /// Maximum attempts.
127    pub max_retries: u64,
128    /// Exponential backoff base delay.
129    pub base_delay_ms: u64,
130    /// Upper bound for one agent-level delay.
131    pub max_agent_delay_ms: u64,
132}
133
134/// Resolved provider/SDK retry settings.
135#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
136#[serde(rename_all = "camelCase")]
137pub struct ProviderRetrySettings {
138    /// Request timeout, when configured.
139    #[serde(default, skip_serializing_if = "Option::is_none")]
140    pub timeout_ms: Option<u64>,
141    /// Provider retry attempts, when configured.
142    #[serde(default, skip_serializing_if = "Option::is_none")]
143    pub max_retries: Option<u64>,
144    /// Maximum server-requested delay before failing.
145    pub max_retry_delay_ms: u64,
146}
147
148/// Resolved image settings (`images.*`).
149#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
150#[serde(rename_all = "camelCase")]
151pub struct ImageSettings {
152    /// Resize images to 2000x2000 maximum.
153    pub auto_resize: bool,
154    /// Never send images to providers.
155    pub block_images: bool,
156}
157
158/// Resolved `serve.*` settings (Oino key, modes §5).
159#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
160#[serde(rename_all = "camelCase")]
161pub struct ServeSettings {
162    /// Listen address.
163    pub bind: String,
164    /// Serve TLS.
165    pub tls: bool,
166    /// Accept non-loopback clients.
167    pub allow_remote: bool,
168}
169
170/// A `packages[]` entry: a source string or a filtered object.
171#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
172#[serde(untagged)]
173pub enum PackageSource {
174    /// Load every resource of the package.
175    Source(String),
176    /// Load a filtered subset.
177    Filtered(FilteredPackageSource),
178}
179
180impl PackageSource {
181    /// The package source string.
182    #[must_use]
183    pub fn source(&self) -> &str {
184        match self {
185            Self::Source(source) => source,
186            Self::Filtered(filtered) => &filtered.source,
187        }
188    }
189}
190
191/// Object form of [`PackageSource`].
192#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
193pub struct FilteredPackageSource {
194    /// Package source.
195    pub source: String,
196    /// When `false`, start empty and apply only explicit patterns.
197    #[serde(default, skip_serializing_if = "Option::is_none")]
198    pub autoload: Option<bool>,
199    /// Extension patterns.
200    #[serde(default, skip_serializing_if = "Option::is_none")]
201    pub extensions: Option<Vec<String>>,
202    /// Skill patterns.
203    #[serde(default, skip_serializing_if = "Option::is_none")]
204    pub skills: Option<Vec<String>>,
205    /// Prompt template patterns.
206    #[serde(default, skip_serializing_if = "Option::is_none")]
207    pub prompts: Option<Vec<String>>,
208    /// Theme patterns.
209    #[serde(default, skip_serializing_if = "Option::is_none")]
210    pub themes: Option<Vec<String>>,
211}
212
213/// Resource arrays of settings (`extensions`, `skills`, `prompts`, `themes`).
214#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
215#[serde(rename_all = "lowercase")]
216pub enum ResourceKind {
217    /// `extensions`.
218    Extensions,
219    /// `skills`.
220    Skills,
221    /// `prompts`.
222    Prompts,
223    /// `themes`.
224    Themes,
225}
226
227impl ResourceKind {
228    /// Every kind in `RESOURCE_TYPES` order.
229    pub const ALL: [Self; 4] = [Self::Extensions, Self::Skills, Self::Prompts, Self::Themes];
230
231    /// The settings key, which is also the conventional directory name.
232    #[must_use]
233    pub const fn key(self) -> &'static str {
234        match self {
235            Self::Extensions => "extensions",
236            Self::Skills => "skills",
237            Self::Prompts => "prompts",
238            Self::Themes => "themes",
239        }
240    }
241}
242
243/// Parse a JSON string value into one of the enums above (`None` for anything else).
244pub(crate) fn parse_enum<T: serde::de::DeserializeOwned>(value: &serde_json::Value) -> Option<T> {
245    value
246        .is_string()
247        .then(|| serde_json::from_value(value.clone()).ok())
248        .flatten()
249}