Skip to main content

codetether_agent/rlm/
mod.rs

1//! Recursive Language Model (RLM) processing
2//!
3//! Handles large contexts that exceed model context windows by:
4//! 1. Loading context into a REPL environment as a variable
5//! 2. Having the LLM write code to analyze it
6//! 3. Supporting recursive sub-LM calls for semantic analysis
7//!
8//! Based on "Recursive Language Models" (Zhang et al. 2025)
9
10pub mod chunker;
11pub mod context_trace;
12pub mod oracle;
13pub mod repl;
14pub mod router;
15pub mod tools;
16
17pub use chunker::{Chunk, ChunkOptions, ContentType, RlmChunker};
18pub use context_trace::{ContextTrace, ContextEvent};
19pub use oracle::{
20    AstPayload, AstResult, FinalPayload, GeneratedQuery, GrepMatch, GrepOracle, GrepPayload,
21    OracleResult, QueryTemplate, SemanticPayload, TemplateKind,
22    TraceValidator, TreeSitterOracle, ValidatedTrace, VerificationMethod,
23};
24pub use repl::{ReplRuntime, RlmAnalysisResult, RlmExecutor, RlmRepl, SubQuery};
25pub use router::{RlmRouter, RoutingContext, RoutingResult};
26pub use tools::{RlmToolResult, dispatch_tool_call, rlm_tool_definitions};
27
28use serde::{Deserialize, Serialize};
29
30/// RLM processing statistics
31#[derive(Debug, Clone, Default, Serialize, Deserialize)]
32pub struct RlmStats {
33    pub input_tokens: usize,
34    pub output_tokens: usize,
35    pub iterations: usize,
36    pub subcalls: usize,
37    pub elapsed_ms: u64,
38    pub compression_ratio: f64,
39}
40
41/// RLM processing result
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct RlmResult {
44    pub processed: String,
45    pub stats: RlmStats,
46    pub success: bool,
47    pub error: Option<String>,
48}
49
50/// RLM configuration
51#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct RlmConfig {
53    /// Mode: "auto", "off", or "always"
54    #[serde(default = "default_mode")]
55    pub mode: String,
56
57    /// Threshold ratio of context window to trigger RLM (0.0-1.0)
58    #[serde(default = "default_threshold")]
59    pub threshold: f64,
60
61    /// Maximum iterations for RLM processing
62    #[serde(default = "default_max_iterations")]
63    pub max_iterations: usize,
64
65    /// Maximum recursive sub-calls
66    #[serde(default = "default_max_subcalls")]
67    pub max_subcalls: usize,
68
69    /// Preferred runtime: "rust", "bun", or "python"
70    #[serde(default = "default_runtime")]
71    pub runtime: String,
72
73    /// Model reference for root processing (provider:model)
74    pub root_model: Option<String>,
75
76    /// Model reference for subcalls (provider:model)
77    pub subcall_model: Option<String>,
78}
79
80fn default_mode() -> String {
81    "auto".to_string()
82}
83
84fn default_threshold() -> f64 {
85    0.35
86}
87
88fn default_max_iterations() -> usize {
89    15
90}
91
92fn default_max_subcalls() -> usize {
93    50
94}
95
96fn default_runtime() -> String {
97    "rust".to_string()
98}
99
100impl Default for RlmConfig {
101    fn default() -> Self {
102        Self {
103            mode: default_mode(),
104            threshold: default_threshold(),
105            max_iterations: default_max_iterations(),
106            max_subcalls: default_max_subcalls(),
107            runtime: default_runtime(),
108            root_model: None,
109            subcall_model: None,
110        }
111    }
112}