mermaid_cli/constants.rs
1//! Constants module to avoid magic numbers in the codebase
2
3// Network Configuration
4pub const DEFAULT_OLLAMA_PORT: u16 = 11434;
5
6// Timeouts
7pub const COMMAND_TIMEOUT_SECS: u64 = 30;
8pub const COMMAND_MAX_TIMEOUT_SECS: u64 = 300;
9
10// UI Configuration
11pub const UI_POLL_INTERVAL_MS: u64 = 50;
12pub const UI_MOUSE_SCROLL_LINES: u16 = 3;
13pub const UI_ERROR_LOG_MAX_SIZE: usize = 50;
14
15// Default Model Configuration
16pub const DEFAULT_TEMPERATURE: f32 = 0.7;
17pub const DEFAULT_MAX_TOKENS: usize = 4096;
18
19// Context Management
20/// Maximum context tokens for managed message history
21pub const MAX_CONTEXT_TOKENS: usize = 75_000;
22/// Tokens reserved for the model's response within the context window
23pub const CONTEXT_RESERVE_TOKENS: usize = 4_000;
24/// Auto-compact once the fully-enriched request reaches this percentage
25/// of the model's known context window.
26pub const COMPACTION_AUTO_THRESHOLD_PERCENT: u8 = 85;
27/// Default number of recent user turns preserved verbatim after compaction.
28pub const COMPACTION_TAIL_TURNS: usize = 2;
29/// Maximum estimated tokens to preserve as the recent tail.
30pub const COMPACTION_TAIL_TOKEN_BUDGET: usize = 8_000;
31/// Maximum characters of old tool output included in the summarization prompt.
32pub const COMPACTION_TOOL_OUTPUT_MAX_CHARS: usize = 2_000;
33/// Maximum tokens requested from the compaction summarizer.
34pub const COMPACTION_SUMMARY_MAX_TOKENS: usize = 8_000;
35/// Maximum estimated input tokens sent to the summarizer.
36pub const COMPACTION_SUMMARIZER_INPUT_TOKEN_BUDGET: usize = 64_000;
37/// Minimum response reserve when deciding whether the next request fits.
38pub const COMPACTION_MIN_RESPONSE_RESERVE_TOKENS: usize = 4_000;
39/// Maximum response reserve when deciding whether the next request fits.
40pub const COMPACTION_MAX_RESPONSE_RESERVE_TOKENS: usize = 20_000;
41/// Default cap on consecutive auto-compact-and-continue recoveries after a
42/// context-window truncation, before the run stops and shows the manual levers.
43/// The counter resets whenever the run makes progress; `0` means uncapped.
44pub const COMPACTION_MAX_TRUNCATION_RECOVERIES: u8 = 3;
45
46// Ollama auto-sizing
47// Mermaid probes an Ollama model's real context window (`/api/show`) and sizes
48// `num_ctx`/`num_predict` automatically so users never touch Ollama config. See
49// `src/models/adapters/ollama_sizing.rs`.
50/// Conservative `num_ctx` used when memory can't be detected (and as the auto
51/// fallback). Comfortably above the compaction response reserve so auto-compaction
52/// stays sane on the smaller probed window.
53pub const DEFAULT_OLLAMA_MAX_AUTO_NUM_CTX: usize = 32_768;
54/// Floor for the auto-fit `num_ctx` (never applied above the model's own max).
55/// Equal to Ollama's own default so flooring is never worse than today.
56pub const OLLAMA_MIN_AUTO_NUM_CTX: usize = 4_096;
57/// Auto-fit `num_ctx` is rounded down to a multiple of this for clean values.
58pub const OLLAMA_NUM_CTX_ROUNDING: usize = 1_024;
59/// Bytes per KV-cache element. fp16 (2 bytes); KV-cache quantization is not
60/// modeled yet (a later refinement).
61pub const OLLAMA_KV_DTYPE_BYTES: usize = 2;
62/// Fraction of the memory budget (VRAM, or system RAM when offload is allowed)
63/// usable for model weights + KV cache; the remainder is headroom for compute
64/// buffers and other processes.
65pub const OLLAMA_MEMORY_BUDGET_FRACTION: f64 = 0.85;
66/// Floor for `num_predict` so a small `num_ctx` can't starve the answer.
67pub const OLLAMA_MIN_NUM_PREDICT: usize = 512;
68/// Tokens held back from `num_ctx` when capping `num_predict`, so the prompt +
69/// output estimate doesn't bump exactly against the window.
70pub const OLLAMA_NUM_PREDICT_MARGIN: usize = 256;
71/// Wall-clock cap for the best-effort `nvidia-smi` VRAM probe. It returns in
72/// tens of ms normally; a wedged driver must not stall model dispatch.
73pub const NVIDIA_SMI_TIMEOUT_SECS: u64 = 3;
74/// Per-request timeout for the `/api/show` + `/api/tags` capability probe. The
75/// chat client has no global timeout (streaming), so the probe sets its own so a
76/// slow/hung Ollama never stalls the turn.
77pub const OLLAMA_PROBE_TIMEOUT_SECS: u64 = 3;
78/// How long a cached `/api/show` probe stays valid in `provider_probes`. Model
79/// dimensions are static per tag; the TTL just lets a re-pulled model under the
80/// same tag refresh.
81pub const OLLAMA_PROBE_TTL_DAYS: i64 = 30;
82
83// Web Content
84/// Maximum characters to keep when truncating fetched web content
85pub const WEB_CONTENT_MAX_CHARS: usize = 5_000;
86
87/// Aggregate cap on the formatted output of `execute_web_searches`.
88/// Per-result content is already truncated to `WEB_CONTENT_MAX_CHARS`, so
89/// at the default 5 results this caps the total at ~25 KB plus headers and
90/// the sources block. The aggregate cap protects against many-results-of-
91/// medium-size cases where individual truncation alone isn't enough.
92pub const WEB_SEARCH_AGGREGATE_MAX_CHARS: usize = 30_000;
93
94/// Maximum characters allowed in the streaming response buffer.
95/// Prevents unbounded memory growth from runaway model responses.
96pub const MAX_RESPONSE_CHARS: usize = 400_000;
97
98// Tool execution limits
99/// Maximum bytes of combined stdout/stderr captured from a single
100/// `execute_command` invocation. Past this the capture stops and a
101/// truncation marker is appended — prevents a chatty or newline-less
102/// command (`cat /dev/urandom`, `yes`) from exhausting memory.
103pub const MAX_TOOL_OUTPUT_BYTES: usize = 256 * 1024;
104/// Upper bound on the number of parallel tool calls a single streaming model
105/// response may accumulate. A delta whose `index` exceeds this is dropped
106/// rather than used to grow an allocation proportional to an untrusted
107/// integer (guards against a crafted stream OOM-ing the daemon).
108pub const MAX_TOOL_CALLS: usize = 256;
109
110// Bound-before-allocate frame caps (Cause 2)
111// Every one of these guards a buffer whose size is driven by an untrusted
112// peer (an MCP server, a daemon client, a model provider). They're sized
113// generously — well above any legitimate payload — because their only job is
114// to stop a peer that streams bytes *without* a delimiter from growing a
115// buffer without bound. A legitimate large payload is delimited and so is
116// never anywhere near these.
117/// Max bytes in a single MCP JSON-RPC line before the frame is dropped and the
118/// reader resyncs to the next newline. MCP tool results can be large (a server
119/// returning a file), hence the generous ceiling.
120pub const MAX_MCP_FRAME_BYTES: usize = 16 * 1024 * 1024;
121/// Max bytes in a single daemon control-command line. Commands are short JSON
122/// control messages; anything larger is malformed or hostile.
123pub const MAX_DAEMON_COMMAND_BYTES: usize = 1024 * 1024;
124/// Max bytes accumulated in an SSE reassembly buffer without a complete event
125/// boundary. A provider that streams bytes but never emits the `\n\n` event
126/// separator would otherwise grow the buffer unbounded.
127pub const MAX_SSE_BUFFER_BYTES: usize = 8 * 1024 * 1024;
128/// Max bytes buffered for one streaming tool call's arguments. Tool arguments
129/// (e.g. a file's contents for a `write_file`) can be large, so this is
130/// generous; past it we stop appending so a crafted stream can't grow the
131/// buffer without bound.
132pub const MAX_TOOL_ARG_BYTES: usize = 4 * 1024 * 1024;
133/// Max number of `queries[]` honored in a single `web_search` call, and of
134/// `paths[]` in a single `read_file` call. Bounds the fan-out a single tool
135/// call can request.
136pub const MAX_BATCH_TOOL_ITEMS: usize = 32;
137/// Max bytes read from an Ollama `web_search`/`web_fetch` HTTP response body
138/// before the read is aborted. The body is JSON we fully buffer to parse; this
139/// stops a compromised or misconfigured endpoint from returning a multi-GB
140/// body that `Response::json` would buffer unbounded.
141pub const MAX_WEB_BODY_BYTES: usize = 16 * 1024 * 1024;
142
143// UI Cache
144/// Maximum entries in the markdown parse cache before eviction
145pub const MARKDOWN_CACHE_MAX_ENTRIES: usize = 200;
146
147// Computer Use
148/// Maximum width for screenshots sent to models (pixels)
149pub const SCREENSHOT_MAX_WIDTH: u32 = 1280;
150
151// Computer-use timing — empirically tuned for typical GUI response.
152// Slow systems (high-load WMs, remote X displays) may need higher values;
153// the right place to make these tunable later is via env vars on
154// `app::Config`, alongside the rest of the configurable surface.
155/// Delay after `xdotool windowactivate --sync` so the window manager has
156/// time to actually move focus before the next action.
157pub const WINDOW_FOCUS_DELAY_MS: u64 = 200;
158/// Delay after a click for the window manager to process focus + UI update,
159/// before we take the auto-screenshot the model uses to decide its next move.
160pub const POST_CLICK_DELAY_MS: u64 = 500;
161/// Delay after typing for the target application to settle (validate input,
162/// re-render) before the auto-screenshot.
163pub const POST_TYPE_DELAY_MS: u64 = 500;
164/// Delay after a key press / shortcut for the target app to react before
165/// the auto-screenshot.
166pub const POST_KEY_DELAY_MS: u64 = 500;
167/// Delay between simulated keystrokes when typing text. The previous
168/// 12ms default lost characters on slow Electron / web targets; 25ms
169/// is a safer default that still types ~40 chars/sec.
170pub const TYPE_KEY_DELAY_MS: u64 = 25;
171/// Maximum scroll wheel ticks in a single `scroll` call. Clamps the
172/// model's `amount` parameter so a runaway model can't request a
173/// million ticks (would exceed `ARG_MAX` building xdotool argv).
174pub const MAX_SCROLL_AMOUNT: i32 = 100;
175/// Capacity of the per-screenshot metadata ring buffer in
176/// `computer_use`. Each call to `screenshot` registers metadata under
177/// a new id; older entries are LRU-evicted past this cap. Sized to
178/// cover any realistic agentic loop without unbounded growth.
179pub const SCREENSHOT_REGISTRY_CAPACITY: usize = 16;
180/// Maximum number of screenshot images retained in the per-call
181/// message history sent to the model. Older messages keep their text
182/// content (with a placeholder noting where the image was elided) so
183/// the model knows what was dropped from context.
184pub const MAX_RETAINED_SCREENSHOTS: usize = 3;
185/// Per-command wall-clock cap for the synchronous geometry/probe helpers
186/// (xdotool getactivewindow/getwindowgeometry, xrandr --query, the list_windows
187/// search). These return in tens of ms; a wedged display (dead X socket,
188/// detached SSH) must not hang the agent loop (#97).
189pub const COMPUTER_USE_CMD_TIMEOUT_SECS: u64 = 5;
190/// Wall-clock cap for the screenshot downscale step (ImageMagick `convert` /
191/// `ffmpeg`). Larger than the probe cap — re-encoding a 4K PNG is legitimately
192/// slower than a geometry query. On timeout we fall through to the next encoder,
193/// then to sending the full-resolution capture (#97).
194pub const SCREENSHOT_DOWNSCALE_TIMEOUT_SECS: u64 = 15;
195
196// Project instructions (Step 5h)
197/// Maximum bytes loaded from project instruction files before truncation. ~10k
198/// tokens at 4 chars/token. Files larger than this likely have
199/// repository-wide notes that don't all need to live in the system
200/// prompt; truncate with a marker so the user knows.
201pub const MAX_INSTRUCTIONS_BYTES: usize = 40_000;
202/// Marker appended to project-instruction content when it exceeds the
203/// byte cap. The model sees this so it knows context was elided.
204pub const INSTRUCTIONS_TRUNCATION_MARKER: &str =
205 "\n\n[Project instructions truncated - exceeds 10k token cap]";
206
207// Durable semantic memory (v0.10.0)
208/// Max bytes of the always-loaded memory INDEX (name + description + path per
209/// fact, all scopes). ~2k tokens at 4 chars/token. The index is terse; if it
210/// overflows, that's a signal to run `/consolidate-memory`.
211pub const MAX_MEMORY_INDEX_BYTES: usize = 8_000;
212/// Marker appended to the memory index when it exceeds the byte cap.
213pub const MEMORY_INDEX_TRUNCATION_MARKER: &str =
214 "\n\n[Memory index truncated - too many entries; run /consolidate-memory]";