[Feature] Incremental analysis caching, concurrent cronjob, and token-aware repo context - #23
Open
dwin-gharibi wants to merge 9 commits into
Conversation
…nore patterns and move them into ignore patterns file sepratly
…ports for ignore patterns
…especting changes, .gitignore files and more
…nto analyzer agent
…aching and repo context
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Scale-and-cost improvements to the analyzer and the GitLab cronjob so that
organization-wide, repeated documentation runs are cheaper and faster:
.gitignore,cap it for large monorepos, and detect languages.
No breaking changes; every new behavior is on a sensible default and can be turned off.
Motivation
The cronjob runs across an entire GitLab group on a schedule, and every invocation
previously re-analyzed each repository from scratch, processed projects strictly
sequentially, and injected the entire repository file tree into every one of the
five analyzer agents' prompts (recomputed per agent). On large repos this wastes
tokens/latency, and across an org it wastes a lot of both. This MR addresses the three
"scale & cost" gaps together because they share infrastructure (file enumeration).
Changes
D. Incremental analysis / caching
src/utils/cache.py: anAnalysisManifest(pydantic) plusload_manifest/write_manifest/is_up_to_date..ai/docs/.manifest.jsonrecording the repo fingerprint, analyzer version, the set of requested analyses,
and each output file's content hash.
cache hit, skips the entire analysis. Partial runs are intentionally not
cached, so a previously-failed analysis is retried on the next run.
correctly reflects uncommitted working-tree edits.
.ai/output, so writing theanalysis docs cannot self-invalidate the cache.
E. Parallel cronjob across projects
src/handlers/cronjob.py:handle()now collects applicable projects sequentially(cheap metadata filtering) and then runs the clone → analyze → merge-request pipeline
concurrently through the existing
WorkerPool, bounded by a newmax_project_workers(default
4,0= auto/CPU count).off the event loop with
asyncio.to_threadso projects genuinely overlap rather thanserializing behind each other's blocking calls.
pool and logged without stopping the others.
F. Token-aware repo context
src/utils/repo_context.py:build_repo_context()returns aRepoContext(structure string, languages, file count, truncation flag, file list, fingerprint).
It is built once per run and reused across all five agents (previously the full
tree was recomputed for each).
.gitignoreviagit ls-fileswhen the repo is a git checkout (fixesover-ignoring of legitimately-tracked directories such as
docs/,static/,public/). Falls back to a filtered directory walk with best-effort.gitignoreparsing for non-git repositories.
max_context_files, default1000) with a cleartruncation note, plus a hard character backstop, to protect the context window on
large monorepos.
context (e.g.
Primary languages: Python, YAML, Markdown).src/utils/ignore_patterns.py: the 100+ ignore-directory/extension constantswere moved out of
list_files.pyinto a single dependency-free source of truth(re-exported from
list_files.pyfor backward compatibility).New configuration & CLI flags
All values below are also exposed as CLI flags via the existing config-reflection
(
--flag-name) and documented inconfig_example.yaml.analyzerrespect_gitignoretrue.gitignorewhen building contextanalyzermax_context_files10000= unlimited)analyzercache_enabledtrueanalyzerforce_reanalysisfalse--force-reanalysis)cronjob.analyzemax_project_workers40= auto/CPU count)Testing
unittest, no new dependency):PYTHONPATH=src python -m unittest discover -s tests -t ..ai/docs must not invalidate the cache" property,.gitignorehandling beyond thehardcoded list, truncation, language detection, a repo living under an ignore-named
parent directory, full manifest validity matrix (fingerprint/version/missing/edited/
included-set/corrupt), and the analyzer cache-miss → hit → invalidate wiring.
ruff formatandruff checkclean acrosssrc/andtests/..git/.aiexcluded, languages detected, a real analyzer prompt rendered, and the cronjob worker
resolution verified — all without any LLM calls.
Backward compatibility
the context cap; caching is transparent and only skips genuinely-unchanged repos).
DEFAULT_IGNORED_DIRS/DEFAULT_IGNORED_EXTENSIONSremain importable fromagents.tools.dir_tool.list_files.Operational notes & caveats
max_project_workers × analyzer max_workers. Tune both together against providerrate limits; the existing 429 retry client backstops bursts. Parallel clones also
increase peak disk usage (Helm
ephemeral-storage).state, any new developer commit changes the fingerprint (correctly → re-analyze); the
cache mainly avoids redundant work when nothing changed.
.gitignorefallback is a pragmatic subset (no negation/anchoredpatterns); git repositories use real git semantics via
git ls-files.