perf: reduce typing lag with multiple agents on large repos#255
perf: reduce typing lag with multiple agents on large repos#255
Conversation
Addresses input lag when many AI agents are active simultaneously on repositories spanning 100k+ files by reducing unnecessary React re-renders, capping file tree traversal, and scaling git polling with session count. - Add anyChanged guard in useBatchedSessionUpdates flush to preserve referential identity when no sessions were actually modified, avoiding ~7 unnecessary re-renders/sec during agent streaming - Cap file tree traversal at 50k entries in useAtMentionCompletion and useTabCompletion to prevent main thread blocking on huge repos - Skip fuzzy matching entirely for empty @mention filter (just typed @), and add early exit after 50 exact substring matches to avoid exhaustive search through 100k+ files - Scale git polling interval dynamically based on git session count (30s for 1-3, 45s for 4-7, 60s for 8-12, 90s for 13+) to reduce sustained CPU/IO load from parallel git status processes
Code Review: Performance Optimizations for Large RepositoriesThis is an excellent performance-focused PR that addresses real bottlenecks when working with multiple agents on large repositories. The changes are well-documented, focused, and follow the codebase's performance best practices outlined in CLAUDE-PERFORMANCE.md. ✅ Strengths1. Excellent Documentation
2. Smart OptimizationsuseBatchedSessionUpdates (src/renderer/hooks/session/useBatchedSessionUpdates.ts:166-171)
useAtMentionCompletion (src/renderer/hooks/input/useAtMentionCompletion.ts:167-188)
useGitStatusPolling (src/renderer/hooks/git/useGitStatusPolling.ts:99-116)
3. Consistent with Codebase Patterns
🔍 Suggestions & Questions1. useGitStatusPolling: Interval Restart LogicFile: The interval restart effect has a potential timing issue: useEffect(() => {
const newScaledInterval = getScaledPollInterval(pollInterval, gitSessionCount);
if (newScaledInterval !== prevScaledIntervalRef.current) {
prevScaledIntervalRef.current = newScaledInterval;
// Restart with new interval if currently polling
if (intervalRef.current) {
stopPolling();
if (isActiveRef.current && (!pauseWhenHidden || !document.hidden)) {
startPolling();
}
}
}
}, [gitSessionCount, pollInterval, stopPolling, startPolling, pauseWhenHidden]);Issue: When Recommendation: Pass the new interval directly or ensure the ref is updated before calling useEffect(() => {
const newScaledInterval = getScaledPollInterval(pollInterval, gitSessionCount);
if (newScaledInterval !== prevScaledIntervalRef.current) {
prevScaledIntervalRef.current = newScaledInterval;
if (intervalRef.current) {
stopPolling();
// Poll immediately and restart with new interval
pollGitStatus();
const scaledInterval = newScaledInterval;
intervalRef.current = setInterval(() => {
const now = Date.now();
const timeSinceLastActivity = now - lastActivityRef.current;
if (timeSinceLastActivity < inactivityTimeout) {
pollGitStatus();
} else {
isActiveRef.current = false;
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
}
}, scaledInterval);
}
}
}, [gitSessionCount, pollInterval, stopPolling, pollGitStatus, inactivityTimeout, pauseWhenHidden]);Or alternatively, update the 2. useAtMentionCompletion: Early Exit ThresholdFile: const EARLY_EXIT_EXACT_MATCH_THRESHOLD = 50;Question: Was 50 chosen empirically? For repos with 100k+ files, stopping after 50 exact matches might miss better matches later in the file list. Consideration: The current implementation uses breadth-first traversal which "naturally prioritizes shallower (more relevant) files" (line 25), but the file tree order depends on the directory structure and might not always correlate with relevance. Recommendation: Consider:
3. Numeric Separator ConsistencyMinor style point - the code uses numeric separators inconsistently:
While this is fine, you might want to use separators consistently for large numbers throughout:
This is very minor and not a blocker. 🧪 Test CoverageThe codebase has existing tests for these hooks:
Recommendation: Add test cases for:
These tests would help prevent regressions and document expected behavior. 🔒 Security ConsiderationsNo security concerns identified. All changes are performance optimizations without external input handling or privilege escalation. 🚀 Performance ImpactThe PR description claims significant improvements:
Recommendation: Consider adding performance metrics tracking:
This could be added as a follow-up using the existing performance metrics infrastructure ( 📝 Final VerdictApprove with minor suggestions. The PR delivers meaningful performance improvements for large repositories with multiple agents. The code quality is high, documentation is excellent, and changes are well-scoped. The suggestions above are minor refinements that don't block approval. Recommended next steps:
Great work! 🎉 |
- Explicitly set gitSessionCountRef in the polling restart effect to make the data-flow self-documenting (ref is already current from render-phase assignment, but being explicit eliminates ambiguity) - Expand EARLY_EXIT_EXACT_MATCH_THRESHOLD comment explaining why 50 was chosen (3x margin over MAX_SUGGESTION_RESULTS, exact matches get +50 bonus in fuzzyMatchWithScore) - Export getScaledPollInterval for direct unit testing - Add test coverage for all new optimizations: - File tree traversal cap (60k node tree capped at 50k) - Empty filter fast path (skips fuzzy matching, returns sorted) - Early exit behavior with exact substring matches - Git polling interval scaling across all thresholds - Custom interval bypass (user-configured intervals not scaled) - Tab completion file tree cap Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
PR Review: Performance Optimizations for Large ReposSummaryThis PR delivers well-targeted performance improvements addressing input lag with multiple active AI agents on large repositories. The changes are thoughtful, well-tested, and follow the project's performance best practices documented in CLAUDE-PERFORMANCE.md. ✅ Strengths1. Excellent Problem IdentificationThe PR addresses real performance bottlenecks:
2. Well-Chosen OptimizationsuseBatchedSessionUpdates (line 166-171): let anyChanged = false;
const next = prev.map((session) => {
const acc = updates.get(session.id);
if (!acc) return session;
anyChanged = true;
// ...
});
return anyChanged ? next : prev;
useAtMentionCompletion (line 172-190): if (!filter) {
// Skip fuzzy matching entirely for empty filter
// Returns sorted results directly
}
useGitStatusPolling (line 99-104, 106-116):
3. Comprehensive Test CoverageAll optimizations have corresponding tests:
The tests are well-structured and verify both correctness and edge cases. 4. Documentation Quality
🔍 Code Quality ObservationsMinor Suggestions
🛡️ Security & Correctness
⚡ Performance ConsiderationsVerified Performance Improvements:
Potential Future Optimizations (out of scope for this PR):
📊 Test CoverageStrengths:
Suggestions for Future Enhancement:
🔧 Best Practices ComplianceThis PR follows Maestro's documented patterns: ✅ Matches CLAUDE-PERFORMANCE.md guidelines:
✅ Code quality:
📝 Documentation UpdatesThe PR description is excellent and would serve well as a changelog entry. Consider adding a note to CLAUDE-PERFORMANCE.md about:
Final VerdictRecommendation: Approve and Merge ✅ This PR demonstrates excellent engineering:
The optimizations are particularly valuable for users working with large monorepos and multiple simultaneous AI agents—exactly the use case where Maestro shines. Suggested Next Steps:
Great work on this PR! The attention to detail in both implementation and testing is commendable. 🎉 |
Addresses input lag when many AI agents are active simultaneously on repositories spanning 100k+ files by reducing unnecessary React re-renders, capping file tree traversal, and scaling git polling with session count.