fix(context): dedupe subdirectory hints by content digest and skip backup/vendor dirs - #72448
fix(context): dedupe subdirectory hints by content digest and skip backup/vendor dirs#72448BKStock wants to merge 1 commit into
Conversation
…ckup/vendor dirs SubdirectoryHintTracker re-injected identical context files whenever the same AGENTS.md was reachable through more than one path. Symlinked shared workspaces, hardlinks, and timestamped backup copies all alias a single file, so a normal session could ship the same 8KB of instructions two or three times. Nothing deduped it and nothing excluded directories that only ever hold copies. Two changes: * Track a sha256 of every injected hint body. Repeat content is skipped, and the working directory's own context file is seeded at construction so the copy prompt_builder already loaded at startup is never sent again. * Skip directories that hold copies rather than authoritative context (backups, node_modules, venv, site-packages, .git, .Trash, vendor, caches). Screening is relative to working_dir, so a project that legitimately lives under vendor/ keeps discovering its own subdirectory hints. Measured on a real session that touched a symlinked shared workspace: 3 injections / ~24,000 chars before, 1 injection / 8,112 chars after. 14 new tests cover symlink aliasing, byte-identical copies, working-dir seeding, distinct content still being injected, each excluded directory name, excluded ancestors, and the working-dir-inside-excluded-name case.
teknium1
left a comment
There was a problem hiding this comment.
Thanks for targeting a real context-bloat path: current main only remembers visited directories in agent/subdirectory_hints.py:72-74, while both executor paths append tracker output to tool results (agent/tool_executor.py:1210-1217, 1884-1889).
Problems
- The new working-directory seed is unconditional, but project context is only built when
skip_context_filesis false (agent/system_prompt.py:482-498). It can therefore suppress an identical subdirectory hint that was never injected. It also does not match startup precedence:.hermes.mdis selected before AGENTS.md (agent/prompt_builder.py:2169-2175). - The
vendorandthird_partyexclusions suppress all descendant hints below those names. That changes the documented hierarchical discovery behavior for an owned nested component; the PR only tests the separate case where the working directory itself is insidevendor.
Suggested changes
- Seed only the actual startup-selected context source, and only when context-file injection is enabled; cover
skip_context_filesand.hermes.mdprecedence. - Narrow or qualify the broad directory-name exclusions and cover an owned project nested beneath
vendor.
Automated hermes-sweeper review.
| ``prompt_builder`` already loads the working directory's context file at | ||
| startup. Seeding its digest here means the same content reached through | ||
| a different path (a symlink farm, a shared workspace) is recognised as a | ||
| duplicate instead of being sent a second time. |
There was a problem hiding this comment.
This seed is unconditional, but agent/system_prompt.py:482-498 skips project-context injection when skip_context_files=True; in that mode an identical subdirectory hint has not already been delivered and must not be suppressed. It also needs to follow the .hermes.md-first startup precedence in agent/prompt_builder.py:2169-2175.
| ".git", ".hg", ".svn", | ||
| ".Trash", ".cache", ".tox", ".mypy_cache", ".pytest_cache", | ||
| "site-packages", "dist-packages", | ||
| "backups", "backup", ".backups", |
There was a problem hiding this comment.
vendor is not reliably a copy-only directory: this suppresses project/vendor/component/AGENTS.md even when the agent is working in that owned nested component. The current exemption only covers a working directory already inside vendor; please preserve or explicitly scope discovery for nested projects.
|
Thanks @BKStock — the gap you fixed is not only still open on current main, we CONFIRMED THE LIVE SYMPTOM in our own triage sessions today (the same .worktrees/*/AGENTS.md injected multiple times per session). Salvaged with your authorship in #77787: both groups ported (vendor-dir skip + sha256 digest dedupe), your dead outside-workdir branch dropped since main now rejects those paths earlier (f4953bc), tests merged into main's existing file, both mechanisms mutation-checked. Closing in favor of the salvage. |
Problem
SubdirectoryHintTrackerdedupes by directory, never by content. The sameAGENTS.mdreachable through more than one path is injected once per path.This is not hypothetical — three common setups alias a single file:
backups/2026-07-27/AGENTS.md)There is also no exclusion list, so directories that only ever hold copies —
backups/,node_modules/,venv/,site-packages/,.git/,.Trash/,vendor/— are scanned like real project directories. Taking a backup of a context file permanently inflates every subsequent session.Measured on a session that touched a symlinked workspace plus a backup directory: 3 injections, ~24,000 chars, all three byte-identical.
Change
Content digest. Every injected hint body is recorded as a sha256. Repeat content is skipped regardless of the path it arrived through. The working directory's own context file is seeded at construction, so the copy
prompt_builderalready loaded at startup is recognised as a duplicate rather than sent a second time.Excluded directories. A frozenset of directory names that hold copies rather than authoritative context. Screening is relative to
working_dir, so a project that legitimately lives undervendor/keeps discovering its own subdirectory hints — only segments below the working dir are checked.Same session after the change: 1 injection, 8,112 chars.
Tests
14 added (18 → 32), covering:
155 passed, 1 skippedacrosstest_subdirectory_hints.py+test_prompt_builder.py.