fix(ci): add rag eval CI gates and prompt-size budget tests (#1033)#1040
Conversation
|
@claude review this PR. |
|
TL;DR: the direction is right (run 🔴 Description ↔ implementation mismatchesThe PR body claims things that aren't in the diff:
🔴 Workflow won't run on fork PRs
Also: the runner label 🟡 Integration test skip condition is wrong
Skip on 🟡 90s timeout will flake and the assertion order hides real failures
🟡 Silent fallback in
|
|
@claude you can review the PR again |
|
Re-review: real progress — most of the previous review is addressed. Three items from the prior pass are still open, and the new commits introduce one fresh thing worth a look. Recommend changes before merge. ✅ Resolved since last pass
🔴 Still open1. Fork-PR secret handling — unchanged. 2. Description ↔ implementation mismatch — partly unresolved. PR body still says the integration test "drives 3. "Prompt-size budget tests" is in the title and body, but no such test is in the diff. 🟡 New since last passPDF fixture size still off. Generated PDF content is generic. The synthetic paragraph ( 🟢 Minor
Suggested path forward
The core machinery (eval-comparison exit codes, time-regression bucket, integration test skip logic) is in good shape. Once items 1–3 land, this is mergeable. cc @kovtcharov-amd for the fork-PR secret-strategy call (architectural). |
…ent fallback, exit code
…2e path, prompt budget
59a45f2 to
eb9803b
Compare
eb9803b to
d44a629
Compare
|
@claude check out the new changes |
|
Re-review: good progress on items 1–3 from last pass, but the PDF regeneration didn't actually take, and the new fork-PR gate has a comparison bug that means it almost certainly doesn't behave the way you intended. Recommend one more pass before merge. ✅ Resolved since last pass
🔴 Still open1. PDF fixture is still 282 KB, not 1.5 MB. Commit c.save() # writes complete PDF
...
if size >= target_bytes:
os.replace(temp_path, path)
break
c = canvas.Canvas(temp_path, pagesize=letter) # truncates temp_path — starts over
section += 1
2. Fork-PR gate compares an object to a string — likely always-on or always-off. if: ${{ github.event.pull_request.head.repo.owner != github.repository_owner }}
github.event.pull_request.head.repo.full_name == github.repositoryUse that pattern (or 3. Workflow 🟡 Minor
Suggested path forward
Once those three land, this is mergeable. The core machinery (eval comparison exit codes, time-regression bucket, dual |
…on self-hosted runner
|
@claude you can look at it again |
|
Re-review: the two big items from last pass (PDF size, fork-PR gate comparison) are correctly fixed. Two issues remain — one blocking the workflow from actually running, one stray artifact. ✅ Resolved since last pass
🔴 Still open1. Venv is created but never activated in the eval step. - name: Install dependencies in isolated venv
run: |
python -m venv .venv-eval
source .venv-eval/bin/activate # only lives for THIS step
pip install -e .[dev]
- name: Run eval rag_quality compare
run: |
gaia eval agent --category rag_quality --compare ... # PATH no longer has the venvEach GHA
Without this, the gate never actually runs. Worth triggering once via 2. Stray nested PDF committed by accident. 🟢 Minor
Suggested path forward
Once those land, this is mergeable. cc @kovtcharov-amd for sign-off on the self-hosted runner label. |
|
@claude recheck it I just made some changes |
|
@kovtcharov and @kovtcharov-amd you can check out this PR when you're free |
|
Re-review: both blocking items from the last pass are correctly fixed. This is mergeable from my side. ✅ Resolved since last pass
🟢 Optional follow-up (non-blocking)
Final state of the gateThe core machinery is solid: dual integration tests ( cc @kovtcharov-amd for sign-off on the self-hosted runner label and the optional |
## Why this matters v0.18.0 ships agent memory v2 (hybrid-search second brain with LLM extraction and observability dashboard), ChatAgent split into three composable agents (Chat/FileIO/DocumentQA), parallel tool calls, and a Telegram adapter scaffold — plus fixes the RAG-on-PDF timeout with Gemma 4 that broke document Q&A since v0.17.6 and adds CI gates that enforce RAG quality baselines on every future PR. Full notes: `docs/releases/v0.18.0.mdx`. ## What's New - **Agent memory v2** ([amd#606](amd#606)) — Hybrid semantic + keyword search, LLM extraction, observability dashboard via SSE streaming ([amd#1032](amd#1032)). Per-user isolation enforced; extraction runs async so it doesn't add latency. - **ChatAgent split** ([amd#979](amd#979)) — `ChatAgent`, `FileIOAgent`, and `DocumentQAAgent` replace the monolithic class; each composable via `tools=`. Backward-compatible shim preserved. - **Parallel tool calls** ([amd#946](amd#946)) — Multiple `tool_calls` from a single LLM turn are executed concurrently, cutting round-trips for multi-tool workflows. - **Telegram adapter scaffold, Phase 0** ([amd#951](amd#951)) — `gaia telegram start|stop|status`, per-user session isolation, `[telegram]` extras. Phase 1 (message handling + allowed-users gate) tracked in [amd#889](amd#889). - **Connectors: per-MCP toggle + single-writer enforcement** ([amd#1018](amd#1018), [amd#998](amd#998)) — Disable individual MCP servers without removing them; concurrent writes serialised with actionable errors on contention. - **File navigation, web browsing, and write security** ([amd#495](amd#495)) — `FileSearchToolsMixin`, web browsing tool, and scratchpad mixin in `KNOWN_TOOLS`; write tools check `allowed_paths` before dispatch. - **Email UI and policy alerts** ([amd#995](amd#995), [amd#1039](amd#1039), [amd#952](amd#952)) — Pre-scan triage card, in-chat Connect, policy alert cards, and durable receipts for confirmation-gated actions. ## Bug Fixes - **RAG-on-PDF timeouts on Gemma 4** ([amd#1034](amd#1034), closes [amd#1030](amd#1030)) — Prompt-size budget check added at composition time; CI gates enforce it on every PR ([amd#1040](amd#1040)). - **Envelope-level parse failure crashed SD recovery** ([amd#1047](amd#1047), closes [amd#1023](amd#1023)) — Falls through to a clean recovery path with step-1 context preserved. - **Windows-path tool args corrupted** ([amd#1027](amd#1027)) — Backslash normalisation now happens after argument parsing. - **Blender `send_command` hung** ([amd#1026](amd#1026), closes [amd#1022](amd#1022)) — Read timeout applied to persistent-connection servers. - **`gaia chat init` in post-install banner** ([amd#1029](amd#1029), closes [amd#1024](amd#1024)) — Replaced with the correct `gaia init`. - **Keyring treated as required** ([amd#1028](amd#1028)) — Import guarded; optional on systems without `keyring`. - **electron-builder URLs stale** ([amd#953](amd#953)) — Three doc/installer files updated to current download paths. ## Tooling & Docs - **RAG eval CI gates** ([amd#1040](amd#1040), closes [amd#1033](amd#1033)) — RAG quality baselines + prompt-size budget enforced on every PR. - **Fork-PR authors now receive Claude review** ([amd#932](amd#932)) — `allowed_non_write_users: "*"` with prompt-injection mitigations documented. - **Eval runs mandated before merging** ([amd#1036](amd#1036)) — `CLAUDE.md` requires `gaia eval agent` for LLM-affecting changes. - **GAIA website** ([amd#369](amd#369)) — [amd-gaia.ai](https://amd-gaia.ai) live. - **Custom agent guide reorganised** ([amd#997](amd#997)), Lemonade PPA docs ([amd#801](amd#801)), broken Lemonade CLI URL fixed ([amd#996](amd#996)), WhatsApp adapter evaluation spec ([amd#950](amd#950)). ## Release checklist - [x] `util/validate_release_notes.py docs/releases/v0.18.0.mdx --tag v0.18.0` passes - [x] `src/gaia/version.py` → `0.18.0` - [x] `src/gaia/apps/webui/package.json` → `0.18.0` - [x] Navbar label in `docs/docs.json` → `v0.18.0 · Lemonade 10.2.0` - [x] All 28 commits in range (v0.17.6..HEAD) are represented in the notes - [ ] Review from @kovtcharov-amd addressed
Summary
Adds the missing CI gates that would have caught the #1030 ChatAgent prompt-bloat regression before it reached users: a GHA workflow that runs the
rag_qualityeval scorecard on every relevant PR, a real-world PDF corpus entry, a safety-handbook scenario, and an end-to-end CLI integration test.Why
The #1030 regression (52 K-char system prompt hanging
gaia chat --index <pdf>for ~10 minutes on Gemma 4 E4B) slipped through every CI gate because therag_qualityeval scorecard was never actually run in CI only smoke-tested manually. No workflow measured prompt size, wall-clock time, or exercised the realgaia chat --index <pdf> --query "..."invocation against a live Lemonade. This PR closes those gaps so the same class of bug cannot ship again.Linked issue
Closes #1033
Changes
.github/workflows/test_eval_rag.yml— runsgaia eval agent --category rag_quality --compareon every PR touchingsrc/gaia/agents/**,src/gaia/llm/**,src/gaia/rag/**,src/gaia/eval/**, oreval/scenarios/**; fails on score regression >0.5 or duration >2× baseline; usesconcurrency: group: lemonade-evalto serialize against the self-hosted runner per CLAUDE.mdeval/corpus/documents/safety_handbook_cc0.txt— CC0 public-domain safety document (~1.5 MB, text-heavy, mixed sections) mirroring the [Bug]: 1.4MB file indexed no response to queries in the UI #1030 user's repro content shapeeval/scenarios/safety_handbook_water.yaml— scenario asking "what does the document say about water?" against the corpus entry above; the literal [Bug]: 1.4MB file indexed no response to queries in the UI #1030 repro generalizedtests/integration/test_chat_rag_pdf_e2e.py— drivesgaia chat --index <small.pdf> --query "..."against a real Lemonade on the self-hosted runner; asserts response within 90 s and non-empty output; skips loudly (not silently) when runner is unavailableTest plan
python util/lint.py --allpassespytest tests/unit/passestest_eval_rag.ymlworkflow manually viaworkflow_dispatchconfirm it runs the scorecard and exits 0 against current baselinetest_eval_rag.ymlfailstime.sleep(60)in a tool confirm the duration gate fails the workflowpytest tests/integration/test_chat_rag_pdf_e2e.pyon the self-hosted runner confirm it returns within 90 s with non-empty outputChecklist
Closes #1033).python util/lint.py --all,pytest tests/unit/).