Skip to main content

sqlite_graphrag/constants/
limits.rs

1//! Length, size and count ceilings enforced on stored data.
2//!
3//! Split out of the former single-file `constants.rs` in v1.2.5;
4//! every item is re-exported by the parent module, so `crate::constants::X`
5//! resolves exactly as before.
6
7/// Maximum byte length for a memory `name` field in kebab-case.
8pub const MAX_MEMORY_NAME_LEN: usize = 80;
9
10/// Maximum byte length for an `ingest`-derived kebab-case name.
11///
12/// Stricter than `MAX_MEMORY_NAME_LEN` (80) to leave headroom for collision
13/// suffixes (`-2`, `-10`, ...) when multiple files derive to the same base.
14/// Used exclusively by `src/commands/ingest.rs`.
15pub const DERIVED_NAME_MAX_LEN: usize = 60;
16
17/// Maximum character length for a memory `description` field.
18pub const MAX_MEMORY_DESCRIPTION_LEN: usize = 500;
19
20/// Hard upper bound on memory `body` length in bytes.
21pub const MAX_MEMORY_BODY_LEN: usize = 512_000;
22
23/// Body character count above which the body is split into chunks.
24pub const MAX_BODY_CHARS_BEFORE_CHUNK: usize = 8_000;
25
26/// Maximum length, in characters, of an `entities.type` label.
27///
28/// v1.2.8 opened the entity vocabulary: `type` is now free text and the SQL
29/// `CHECK` that used to bound it is gone (V017). The only remaining guard is
30/// shape, and this is its size half — it exists so a runaway LLM completion
31/// cannot land a paragraph in a column meant to hold a word. Generous on
32/// purpose: the longest canonical kind is `issue_tracker` at 13 characters.
33pub const MAX_ENTITY_TYPE_LEN: usize = 64;
34
35/// Default upper bound on distinct entities persisted per memory.
36///
37/// Bumped from 30 → 50 in v1.0.43 to reduce semantic loss on rich documents.
38/// Configurable at runtime via XDG / runtime_config (not product env).
39pub const MAX_ENTITIES_PER_MEMORY: usize = 50;
40
41/// Resolves the per-memory entity cap (flag/XDG/`runtime_config`).
42///
43/// v1.0.43: makes the cap (default 50) configurable without product env.
44/// Stress tests showed inputs with 33-46 candidates being truncated at the old cap of 30.
45/// Values outside [1, 1000] fall back to the default.
46pub fn max_entities_per_memory() -> usize {
47    let n = crate::runtime_config::max_entities_per_memory(MAX_ENTITIES_PER_MEMORY);
48    if (1..=1_000).contains(&n) {
49        n
50    } else {
51        MAX_ENTITIES_PER_MEMORY
52    }
53}
54
55/// Upper bound on distinct relationships persisted per memory.
56pub const MAX_RELATIONSHIPS_PER_MEMORY: usize = 50;
57
58/// Resolves the per-memory relationship cap (flag/XDG/`runtime_config`).
59///
60/// v1.0.22: makes the cap (default 50) configurable without product env.
61/// Audit found that rich documents silently hit the cap; users with dense technical corpora
62/// can raise it via XDG. Values outside [1, 10000] fall back to the default.
63pub fn max_relationships_per_memory() -> usize {
64    let n = crate::runtime_config::max_relations_per_memory(MAX_RELATIONSHIPS_PER_MEMORY);
65    if (1..=10_000).contains(&n) {
66        n
67    } else {
68        MAX_RELATIONSHIPS_PER_MEMORY
69    }
70}
71
72/// Character length of the description preview shown in `list` output.
73pub const TEXT_DESCRIPTION_PREVIEW_LEN: usize = 100;
74
75/// Chunk size expressed in tokens for body splitting.
76pub const CHUNK_SIZE_TOKENS: usize = 400;
77
78/// Token overlap between consecutive chunks.
79pub const CHUNK_OVERLAP_TOKENS: usize = 50;
80
81/// Explicit operational guard for multi-chunk documents in `remember`.
82///
83/// The multi-chunk path uses serial embeddings to avoid ONNX memory amplification.
84/// This limit preserves a clear operational ceiling for agents and scripts.
85pub const REMEMBER_MAX_SAFE_MULTI_CHUNKS: usize = 512;
86
87/// Ceiling on chunks per controlled micro-batch in `remember`.
88///
89/// The `fastembed` runtime uses `BatchLongest` padding, so oversized batches amplify
90/// the cost of the longest chunk. This ceiling keeps batches small even when chunks are short.
91pub const REMEMBER_MAX_CONTROLLED_BATCH_CHUNKS: usize = 4;
92
93/// Maximum padded-token budget per controlled micro-batch in `remember`.
94///
95/// The budget uses `max_tokens_no_batch * batch_size`, approximating the real cost of
96/// `BatchLongest` padding. Values exceeding this fall back to smaller batches or serialisation.
97pub const REMEMBER_MAX_CONTROLLED_BATCH_PADDED_TOKENS: usize = 512;
98
99/// PRD-canonical regex that validates names and namespaces. Allows 1 char `[a-z0-9]`
100/// OR a 2-80 char string starting with a letter and ending with a letter/digit,
101/// containing only `[a-z0-9-]`. Rejects the `__` prefix (internal reserved).
102pub const NAME_SLUG_REGEX: &str = r"^[a-z][a-z0-9-]{0,78}[a-z0-9]$|^[a-z0-9]$";
103
104static NAME_SLUG_RE: std::sync::OnceLock<regex::Regex> = std::sync::OnceLock::new();
105
106/// Returns a reference to the compiled [`NAME_SLUG_REGEX`] pattern.
107/// Compiled once on first call, cached via `OnceLock`.
108// expect_used (audited v1.0.97): NAME_SLUG_REGEX is a const literal; a parse
109// failure would be a compile-reproducible bug, never a runtime condition.
110#[allow(clippy::expect_used)]
111pub fn name_slug_regex() -> &'static regex::Regex {
112    NAME_SLUG_RE.get_or_init(|| {
113        regex::Regex::new(NAME_SLUG_REGEX).expect("NAME_SLUG_REGEX is a valid pattern")
114    })
115}
116
117/// Default retention period (days) used by `purge` when `--retention-days` is omitted.
118pub const PURGE_RETENTION_DAYS_DEFAULT: u32 = 90;
119
120/// Maximum number of simultaneously active namespaces (deleted_at IS NULL). Exit 5 when exceeded.
121pub const MAX_NAMESPACES_ACTIVE: u32 = 100;
122
123/// Byte budget for one auto-split partition (sub-memory) in `ingest`
124/// (GAP-SG-04/07).
125///
126/// Chosen below the 127 KB body margin so each partition also stays under
127/// [`REMEMBER_MAX_SAFE_MULTI_CHUNKS`] chunks and [`crate::constants::EMBEDDING_REQUEST_MAX_TOKENS`]
128/// tokens, even for multibyte/CJK text (~1 cl100k token per UTF-8 char, so
129/// 80 KiB / 3 bytes-per-char yields about 27K tokens, below the 30K ceiling).
130pub const AUTOSPLIT_PARTITION_MAX_BYTES: usize = 80 * 1024;
131
132/// Degree above which `health` reports an entity as a super-hub.
133///
134/// A hub this wide makes graph traversal fan out badly, so the check exists to
135/// prompt a `prune-relations` or `merge-entities` pass.
136pub const HEALTH_SUPER_HUB_DEGREE_THRESHOLD: i64 = 50;
137
138/// How many super-hubs `health` names in its warning string.
139///
140/// This bounds the *sample* shown to a human. It must never bound the reported
141/// count, which is measured separately over the whole graph.
142pub const HEALTH_SUPER_HUB_SAMPLE_LIMIT: usize = 5;
143
144/// Character size of the body preview emitted in text/markdown formats.
145pub const TEXT_BODY_PREVIEW_LEN: usize = 200;