feat(agent): materialize a project map at task start - #3405
feat(agent): materialize a project map at task start#3405kovtcharov-amd wants to merge 2 commits into
Conversation
The flagship opened every task blind — it guessed directory names, guessed which commands existed, and guessed which shell it was talking to, and each wrong guess cost a full round trip to learn something one orientation pass establishes once. It now gets a 600-token block in the system prompt naming the project root, the directory shape two levels deep, the likely entry points, which commands are installed (and which are not), the three platform differences that change command syntax, and whether the semantic code index is built. The binary half extends the existing day-0 system-context probe rather than adding a second one: `probe_binaries` is now the single PATH probe, shared by `collect_system_info` and the map, and `DEV_TOOL_PROBES` widens the seven desktop-app markers to the developer toolchain. `index_codebase` gains its first automatic trigger. When the root satisfies `is_code_repository` — a VCS directory or a recognised manifest, non-recursive — and no index exists, the map starts one in a background thread and says so in the prompt. `GAIA_PROJECT_MAP_AUTO_INDEX=0` turns it off. Budget is 600 tokens, 1.8% of the 32K NPU window, enforced by `render_project_map` on every render and pinned by a test against a 200-directory repository. The map is cached per root and invalidated by a fingerprint over the top-level listing, manifest contents, VCS head and PATH. (cherry picked from commit 23573da)
… itself Review follow-ups on the task-start project map, each a bug a user would have hit: - The index line parsed the whole code-index metadata — every chunk's text — on every prompt composition, several times a turn. `CodeIndexSDK.is_indexed` answers the same question with two `exists()` calls. - A background index that died left the prompt saying "building now" for the rest of the session, so the model kept waiting for something that would never arrive. The trigger is now a four-state machine and inspects the tool's JSON, which is how `index_codebase` reports a refusal rather than raising. - The map told the model `run_shell_command` accepts `uv`, `npm` and `python`. It accepts none of them. Installed-and-allowlisted, installed-but-refused, and not-installed are now three separate lines — and the whole section is omitted for an agent that has no shell tool. - In dev mode the daemon launches the agent sidecar from the GAIA checkout, so the working directory resolved to GAIA's own source and it would have background-indexed itself. `is_agent_own_source` rejects that; an explicit `GAIA_PROJECT_ROOT` is exempt. - Listing `ProjectMapMixin` after the base agent silently disabled the index trigger while the prompt still rendered. `__init_subclass__` now raises. Also: the root resolves once per session so the map and the code index cannot describe two different trees, and the day-0 memory fact that duplicated `git`/`node`/`docker` (and carried an `except Exception: pass`) is gone — `DEV_TOOL_PROBES` feeds the map, which is all #3379 asked for. (cherry picked from commit 76d7849)
Skill audit
✅ All audited skills cleared the tier they claim. Per-finding detail is withheld here on purpose. Read it in the Security > Code scanning tab, or download the |
Request changesThe agent now opens a task knowing the repo's shape, entry points and installed commands instead of learning them one failed tool call at a time. The design is tight — a stated 600-token ceiling that's actually enforced and tested, a testable "is this a repository" predicate, and a class-definition guard that turns the one silent way to mis-wire it into a loud The map silently disappears for anyone who installs GAIA into their own project's virtualenv. The check that stops the agent from mapping its own source tree asks "is this directory an ancestor of the A project root that goes away mid-session takes the whole turn with it. The root is resolved once when the agent is built, then walked at the start of every task with no error handling. Delete, rename or unmount that directory and every subsequent query dies on a raw filesystem error. The prompt-rendering path already treats a failing map as droppable-with-a-warning; the task-start path should do the same. Orientation is a convenience — it should never be able to fail a query. An eval comparison is still owed. This adds a system-prompt fragment and touches prompt assembly, which is exactly the class of change the repo requires Real-world evidenceAn evidence bundle ran and is unusually honest about what it does and doesn't cover. Two surfaces were genuinely exercised on the CI runner: $ printf 'y\n' | gaia memory bootstrap --system
[system:software] Installed applications: Chrome, Firefox, git, Node.js, Docker, npm
✅ Stored 12 system context item(s).
exit=0
$ curl -s -X POST -w "\nHTTP %{http_code}\n" http://127.0.0.1:4200/api/memory/refresh-system-context
{"stored":12,"skipped":false}
HTTP 200That covers the refactor that routes the old per-tool The feature itself was not exercised. The bundle says so plainly: So: the evidence supports the refactor, and it neither supports nor contradicts the two bugs above — both were found by reading, and neither is something this lane could have caught. My verdict rests on static review for the map itself. 🔍 Technical detailsIssues🟡
The docstring already states the real condition — "the daemon launches the agent sidecar with its working directory set to the GAIA checkout in dev mode". Only a source/editable checkout qualifies; an editable install still points 🟡 An unreadable project root fails the turn, not just the map (
Note the asymmetry: the rendering path is already safe, because 🟡 Eval comparison missing for a prompt-surface change
Nits
Strengths
|
The agent started every task blind to the project it was in. It did not know the directory shape, where the entry points were, or which programs were actually installed — so it guessed, and a meaningful share of its wasted steps were those guesses coming back as "no such file" or "command not found". It now gets a short, bounded orientation at the start of a task instead of discovering the same facts one failure at a time.
Closes #3379.
Test plan
python -m pytest tests/unit/test_project_map.py -q— 64 tests covering the budget, the repository predicate, caching and invalidationNotes for the reviewer
system_contextprobe rather than adding a second one. That probe already collected machine-level facts — OS, CPU, installed applications — but is opt-in, off by default, and lands in memory rather than the prompt. The genuinely new part is project shape and a per-task trigger.index_codebasea trigger. That tool has been composed on the flagship all along with nothing ever calling it automatically.A red
rag_quality + context_retention + tool_selectioncheck is expected on every PR right now — #3341, fixed by #3403, which has to merge before other branches see it.