Roo-Code's experimental features system allows users to enable cutting-edge capabilities before they're officially released as stable features. This technical guide documents the implementation details, usage patterns, and advanced considerations for each experimental feature.
Experimental features in Roo-Code are controlled through a configuration system defined in src/shared/experiments.ts. The architecture follows a feature flag pattern:
// Feature IDs are defined as constants
export const EXPERIMENT_IDS = {
DIFF_STRATEGY: "experimentalDiffStrategy",
SEARCH_AND_REPLACE: "search_and_replace",
INSERT_BLOCK: "insert_content",
POWER_STEERING: "powerSteering",
MULTI_SEARCH_AND_REPLACE: "multi_search_and_replace",
} as const
// Each experiment has a configuration
export const experimentConfigsMap: Record<ExperimentKey, ExperimentConfig> = {
DIFF_STRATEGY: {
name: "Use experimental unified diff strategy",
description: "Enable the experimental unified diff strategy...",
enabled: false,
},
// Other experiments...
}Features are checked at runtime using the isEnabled function:
export const experiments = {
get: (id: ExperimentKey): ExperimentConfig | undefined => {
return experimentConfigsMap[id]
},
isEnabled: (experimentsConfig: Record<ExperimentId, boolean>, id: ExperimentId): boolean => {
return experimentsConfig[id] ?? experimentDefault[id]
},
}ID: experimentalDiffStrategy
The experimental unified diff strategy (NewUnifiedDiffStrategy) is a more sophisticated approach to applying code changes compared to the standard Search/Replace strategy. This implementation is found in src/core/diff/strategies/new-unified/index.ts.
- Hunk Parsing: Breaks a unified diff into "hunks" (chunks of changes with context)
- Fuzzy Matching: Uses context lines to find the best location for changes even when exact matches aren't found
- Recursive Splitting: Can break large hunks into smaller ones when matching fails
- Adaptive Context: Dynamically adjusts the amount of context to optimize matching
// Core algorithm for parsing unified diffs
private parseUnifiedDiff(diff: string): Diff {
const MAX_CONTEXT_LINES = 6 // Number of context lines to keep
const lines = diff.split("\n")
const hunks: Hunk[] = []
// Implementation details...
}- Sub-hunk Matching: If a full hunk fails to match, the strategy tries splitting it into smaller sub-hunks
- Confidence Scoring: Uses similarity metrics to ensure changes are applied correctly
- Enhanced Error Reporting: Provides detailed diagnostics when matches fail
- Indentation Preservation: Automatically preserves code indentation patterns
- Typically requires 2-3x more processing time than standard strategy
- Better handling of large files with many changes
- More resilient to minor file differences
-
Confidence Threshold: The strategy uses a confidence threshold (default: 0.8 or 80%) for matching:
constructor(confidenceThreshold: number = 1) { this.confidenceThreshold = Math.max(confidenceThreshold, 0.8) }
-
Context Analysis: The system analyzes context-to-change ratios to provide smarter errors:
const contextLines = hunk.changes.filter((c) => c.type === "context").length const totalLines = hunk.changes.length const contextRatio = contextLines / totalLines
-
Error Diagnostics: Provides detailed error information including search strategy, context ratio, and matching confidence.
When this feature is enabled, the diff strategy selection in getDiffStrategy() returns a NewUnifiedDiffStrategy instance instead of the default:
export function getDiffStrategy(
model: string,
fuzzyMatchThreshold?: number,
experimentalDiffStrategy: boolean = false,
): DiffStrategy {
if (experimentalDiffStrategy) {
return new NewUnifiedDiffStrategy(fuzzyMatchThreshold)
}
return new SearchReplaceDiffStrategy(fuzzyMatchThreshold)
}ID: search_and_replace
The Search and Replace tool provides a more powerful alternative to the basic diff strategy, allowing for matching and replacing text with support for fuzzy matching and multi-line changes. This is implemented in src/core/diff/strategies/search-replace.ts.
-
Similarity Calculation: Uses Levenshtein distance for fuzzy matching:
function getSimilarity(original: string, search: string): number { // Calculate Levenshtein distance const dist = distance(normalizedOriginal, normalizedSearch) // Calculate similarity ratio return 1 - dist / maxLength }
-
Middle-Out Search Algorithm: Searches from the middle of the file outward for better performance:
const midPoint = Math.floor((searchStartIndex + searchEndIndex) / 2) let leftIndex = midPoint let rightIndex = midPoint + 1 // Search outward from the middle within bounds while (leftIndex >= searchStartIndex || rightIndex <= searchEndIndex - searchLines.length) { // Search logic... }
-
Indentation Preservation: Sophisticated algorithm to maintain code formatting:
// Calculate the relative indentation level const searchBaseLevel = searchBaseIndent.length const currentLevel = currentIndent.length const relativeLevel = currentLevel - searchBaseLevel // Determine final indentation const finalIndent = relativeLevel < 0 ? matchedIndent.slice(0, Math.max(0, matchedIndent.length + relativeLevel)) : matchedIndent + currentIndent.slice(searchBaseLevel)
- Fuzzy Matching: Configurable similarity threshold for finding content
- Line Range Targeting: Can target specific line ranges for replacement
- Format Preservation: Maintains code formatting and indentation
- Detailed Diagnostics: Provides comprehensive error information
-
Optimal Threshold: The fuzzy threshold determines how similar content must be for a match:
this.fuzzyThreshold = fuzzyThreshold ?? 1.0 // Default to exact matching
-
Buffer Lines: Controls how many lines of context to consider:
this.bufferLines = bufferLines ?? BUFFER_LINES // Default: 20
-
Line Endings: Automatically detects and preserves line endings:
const lineEnding = originalContent.includes("\r\n") ? "\r\n" : "\n"
The tool is exposed to the LLM with specific format requirements:
<<<<<<< SEARCH
[exact content to find including whitespace]
=======
[new content to replace with]
>>>>>>> REPLACE
ID: insert_content
The Insert Content tool provides a way to add new content at specific line positions without modifying existing content. This is particularly useful for adding new functions, import statements, or documentation. The core implementation is in src/core/diff/insert-groups.ts.
-
InsertGroup Interface: Defines the structure for insertions:
export interface InsertGroup { index: number // Line number where content should be inserted elements: string[] // Array of lines to insert }
-
Insertion Algorithm: Sorts and applies insertions in order:
export function insertGroups(original: string[], insertGroups: InsertGroup[]): string[] { // Sort groups by index to maintain order insertGroups.sort((a, b) => a.index - b.index) let result: string[] = [] let lastIndex = 0 insertGroups.forEach(({ index, elements }) => { // Add elements from original array up to insertion point result.push(...original.slice(lastIndex, index)) // Add the group of elements result.push(...elements) lastIndex = index }) // Add remaining elements from original array result.push(...original.slice(lastIndex)) return result }
- Multiple Insertions: Can handle multiple insertion points in a single operation
- Line-Based Positioning: Targets specific line numbers
- Order Preservation: Maintains correct order when multiple insertions affect the same area
- Original Content Preservation: Doesn't modify existing content, only adds new content
- Line Indexing: Uses 0-based indexing internally but exposes as 1-based to users
- Insertion Order: Sorting ensures consistent results regardless of input order
- Empty File Handling: Works correctly with empty files or insertions at the start/end
The insert content tool integrates with other parts of the system:
- Tool Description: Exposed to the LLM with appropriate guidance
- Permissions System: Can be restricted by mode permissions
- Error Handling: Validation for line numbers and file existence
ID: powerSteering
Power Steering mode enhances the LLM's adherence to role definitions and instructions by including additional context in system prompts. This is particularly useful for complex tasks that require strict adherence to guidelines.
- Enhanced Role Reminders: Includes more frequent references to the current mode's role definition
- Instruction Reinforcement: Repeats key instructions more frequently
- Context Window Optimization: Balances added context with available token space
- Token Usage: Increases token consumption due to repeated context
- Performance Impact: May affect response speed due to larger prompts
- Model Behavior: Generally leads to more consistent but potentially more verbose responses
Power Steering is most beneficial for:
- Complex collaborative projects with strict guidelines
- Regulated domains with compliance requirements
- Situations where deviation from instructions would be problematic
ID: multi_search_and_replace
The Multi-Block Search and Replace feature extends the capabilities of the standard search and replace functionality by allowing multiple code blocks to be updated in a single operation. This is particularly valuable for making consistent changes across different parts of a file.
- Block Identification: Identifies multiple distinct blocks within a file that need changes
- Parallel Processing: Processes multiple search/replace operations simultaneously
- Change Coordination: Ensures changes don't conflict with each other
- Context Preservation: Maintains proper context around each modified block
// Implementation example for processing multiple blocks
function processMultipleBlocks(
originalContent: string,
blocks: SearchReplaceBlock[]
): { content: string; changes: ChangeDetails[] } {
// Sort blocks by position to process from bottom to top
// (avoids offset issues when multiple blocks change)
const sortedBlocks = [...blocks].sort((a, b) =>
b.startLine - a.startLine
)
let content = originalContent
const changes = []
// Process each block independently
for (const block of sortedBlocks) {
const result = processSearchReplaceBlock(content, block)
content = result.content
changes.push(result.change)
}
return { content, changes }
}- Consistent Updates: Apply the same pattern changes across multiple locations
- Bulk Operations: Apply different changes to multiple blocks in one operation
- Conflict Resolution: Smart handling of potentially overlapping changes
- Atomic Updates: All changes succeed or fail together, preventing partial updates
- Reduces the number of separate operations needed for multi-block files
- Typically 2-3x faster than applying individual changes for files with multiple change points
- More deterministic results compared to sequential modifications
-
Block Ordering: Changes are applied from bottom to top to preserve line numbering:
// Sort to process changes from bottom to top blocks.sort((a, b) => b.startPosition - a.startPosition)
-
Conflict Detection: The system detects and prevents conflicting changes:
function detectConflicts(blocks: SearchReplaceBlock[]): boolean { // Check for overlapping blocks for (let i = 0; i < blocks.length; i++) { for (let j = i + 1; j < blocks.length; j++) { if (blocksOverlap(blocks[i], blocks[j])) { return true } } } return false }
-
Error Handling: If any block fails to apply, the entire operation is rolled back:
try { // Process all blocks for (const block of blocks) { applyChange(block) } commitChanges() } catch (error) { rollbackChanges() throw new MultiBlockError("Failed to apply multi-block changes", error) }
The multi-block tool provides a more powerful interface for complex file modifications:
<search_and_replace>
<path>src/component.tsx</path>
<operations>[
{
"search": "function Component() {",
"replace": "function Component(props: ComponentProps) {",
"start_line": 10,
"end_line": 10
},
{
"search": "return <div>",
"replace": "return <div className={props.className}>",
"start_line": 15,
"end_line": 15
}
]</operations>
</search_and_replace>
The experiment system uses a combination of runtime checks and configuration persistence:
-
State Management: Flags are stored in VSCode's globalState
-
UI Representation: Each flag has a corresponding UI element in settings
-
Runtime Access: Accessed via the experiments object:
if (experiments.isEnabled(experimentsConfig, EXPERIMENT_IDS.DIFF_STRATEGY)) { // Use experimental feature } else { // Use standard implementation }
| Feature | CPU Impact | Memory Impact | Token Usage Impact |
|---|---|---|---|
| Unified Diff Strategy | Medium-High | Medium | Low |
| Search and Replace | Medium | Low | Low |
| Insert Content | Low | Low | Low |
| Power Steering | Low | Low | High |
| Multi-Block Search and Replace | Medium | Medium | Low |
Each experimental feature includes enhanced error reporting:
- Contextual Diagnostics: Provides information about the specific failure
- Troubleshooting Guidance: Suggests possible solutions
- Debug Information: Includes technical details for diagnosis
Example from unified diff strategy:
let errorMsg = `Failed to find a matching location in the file (${Math.floor(
confidence * 100,
)}% confidence, needs ${Math.floor(this.confidenceThreshold * 100)}%)\n\n`
errorMsg += "Debug Info:\n"
errorMsg += `- Search Strategy Used: ${strategy}\n`
errorMsg += `- Context Lines: ${contextLines} out of ${totalLines} total lines (${Math.floor(
contextRatio * 100,
)}%)\n`The experimental features can be used together for enhanced capabilities:
// Example of using unified diff with power steering
if (experiments.isEnabled(experimentsConfig, EXPERIMENT_IDS.DIFF_STRATEGY) &&
experiments.isEnabled(experimentsConfig, EXPERIMENT_IDS.POWER_STEERING)) {
// Enhanced instruction adherence with improved diff handling
}Create project-specific experimental feature configurations:
// .vscode/settings.json
{
"roo-cline.experiments": {
"experimentalDiffStrategy": true,
"insert_content": true,
"search_and_replace": false,
"powerSteering": false
}
}Activate features only for specific tasks:
// Activate experimental feature for specific file types
if (filePath.endsWith('.ts') &&
experiments.isEnabled(experimentsConfig, EXPERIMENT_IDS.SEARCH_AND_REPLACE)) {
// Use experimental search and replace for TypeScript files
}-
Unified Diff Strategy: Enable when working with large files or complex code changes that require precise matching. Most beneficial for refactoring operations affecting multiple areas of a file.
-
Search and Replace: Enable when you need to perform systematic replacements across files, such as updating API calls, renaming variables consistently, or modifying code patterns.
-
Insert Content: Enable when adding new functions, methods, imports, or documentation blocks to files without modifying existing content. Particularly useful for codebase extension.
-
Power Steering: Enable when working on tasks that require strict adherence to guidelines, such as regulated code, security-sensitive implementations, or team projects with strict conventions.
-
Multi-Block Search and Replace: Enable when performing refactorings that require coordinated changes to multiple parts of a file. Especially valuable for updating component signatures, changing function parameters, or implementing consistent API changes throughout a file.
-
Power Steering: Enable when working on tasks that require strict adherence to guidelines, such as regulated code, security-sensitive implementations, or team projects with strict conventions.
- Incremental Testing: Start with small, isolated changes to evaluate feature behavior
- Backup Critical Files: Create backups before applying changes to important files
- Review Results Carefully: Closely examine the results of each operation
- Comparative Testing: Compare results with and without the experimental feature
- Performance Issues: If you notice significant slowdowns or increased latency
- Unexpected Results: If changes aren't being applied as expected
- Token Consumption: If you're concerned about token usage (especially for Power Steering)
- Before Updates: Disable experimental features before updating Roo-Code to avoid conflicts
Experimental features follow this general progression:
- Experimental Phase: Initial implementation with feature flag
- Refinement Phase: Improvements based on user feedback
- Stabilization Phase: Bug fixes and performance optimization
- General Availability: Removal of feature flag, included in standard features
Current development priorities:
- Unified Diff Strategy 2.0: Enhanced context recognition and improved performance
- Insert Content Extensions: Template-based insertions and smart positioning
- Multi-File Search and Replace: Apply consistent changes across multiple files
- Multi-Block Search and Replace Enhancements: Improved conflict resolution and visual diffing
- Adaptive Power Steering: Context-aware instruction emphasis
Experimental features provide early access to advanced capabilities in Roo-Code. By understanding their technical implementation and appropriate use cases, you can leverage these features to enhance your workflow while being mindful of their limitations and performance impacts.