Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(agents): RAG-on-PDF timeouts on Gemma 4 (#1030)#1034

Merged
kovtcharov-amd merged 15 commits into
mainfrom
fix/rag-pdf-gemma-timeout-1030
May 11, 2026
Merged

fix(agents): RAG-on-PDF timeouts on Gemma 4 (#1030)#1034
kovtcharov-amd merged 15 commits into
mainfrom
fix/rag-pdf-gemma-timeout-1030

Conversation

@kovtcharov

Copy link
Copy Markdown
Collaborator

Why this matters

In plain English: when a user indexed a PDF in gaia chat and asked a question about it, GAIA would hang for ~10 minutes and then show "Couldn't reach the local LLM" — even though the LLM server was running fine. After this fix the same query returns a real cited answer in ~45–60 seconds, and on the rare occasions when a timeout does fire the user sees a useful "here's what to try" message instead of the misleading network-error wording.

Technically: the ChatAgent system prompt had grown to ~52 K chars / ~15 K tokens. With the default Gemma-4-E4B on Windows iGPU, prompt-processing for the first PLANNING call exceeded Lemonade's internal upstream timeout. Three layers of fix:

  1. Trim ChatAgent._get_system_prompt from ~52 K → ~10 K chars (5× reduction). All imperative directives preserved; only multi-paragraph examples and edge-case enumerations dropped. Full wire payload per request cut ~38 %.
  2. New LemonadeUpstreamTimeoutError distinguishes "Lemonade is up but the model call hung" from genuine network failure. retryable=False prevents silent retry against a hung backend; the user-facing message names concrete remediation steps (no smaller-model fallback).
  3. Base agent's generic catchall now surfaces typed Lemonade messages verbatim via _extract_lemonade_user_message. Walks __cause__ / __context__ with cycle protection — and that incidentally exposed a latent infinite-loop bug in _classify_chat_exception (would have hung the chat handler forever on any pathological exception graph), fixed in the same commit.

Also adds a SINGLE-DOC RESOLUTION (CRITICAL) rule so Gemma doesn't ask "which document?" when only one is indexed, and a user-facing doc entry under "Agent & SDK Issues".

Validation done

  • 2 326 unit tests pass, lint clean. 21 new tests in 2 new files: test_chat_system_prompt_budget.py pins prompt size per (profile × indexed-doc count) up to 100 docs; test_lemonade_error_classification.py covers the timeout-vs-network split plus cause-chain cycle protection.
  • 19 live PDF scenarios cleared, zero Timeout was reached errors. PDF sizes 1.4 MB → 43 MB; cold-start replay (model unloaded → first query) 44.5 s on Mac M-series; the literal bug-report query "what does the document say about water?" against a water-content doc returns a thorough cited 5-section answer in 45 s.
  • Live injected-timeout simulation confirms the typed user_message surfaces to the user verbatim, not wrapped in the misleading "Sorry, I ran into an unexpected problem. This might be a temporary issue — try again in a moment."

Test plan

  • pytest tests/unit/ tests/test_chat_agent.py -q --ignore=tests/unit/chat/ui → 2 326 pass
  • python util/lint.py --black --isort → ALL QUALITY CHECKS PASSED
  • Live cold-start replay (the canonical [Bug]: 1.4MB file indexed no response to queries in the UI #1030 case):
    curl -s -X POST http://localhost:13305/api/v1/unload \
      -H "Content-Type: application/json" \
      -d '{"model_name":"Gemma-4-E4B-it-GGUF"}'
    cat > ~/test_1030.md <<'XYZ'
    Employers must provide potable drinking water at all workplaces.
    Cooling tower water is NOT safe to drink.
    Wastewater must comply with the Clean Water Act.
    XYZ
    time gaia chat --index ~/test_1030.md --allowed-paths "$HOME" \
      --query "what does the document say about water?"
    rm ~/test_1030.md
    Expected: cited answer in ~45–60 s. Pre-fix: 10-min hang ending in CURL error: Timeout was reached.
  • Windows / iGPU validation (the hardware where the bug originally fired): repeat the cold-start replay; expect 1–3 min, no timeout.
  • Recommended before merging — formal rag_quality eval against baseline:
    gaia eval agent --category rag_quality --agent-type doc \
      --compare tests/fixtures/eval_baselines/gemma-4-e4b-d71cd914/scorecard_rag_quality.json

Related

Closes #1030.

)

ChatAgent system prompt had grown to ~52K chars (~15K tokens) of inlined
rules and multi-paragraph examples — large enough that prompt processing
on Windows iGPU exceeded Lemonade's internal upstream timeout when
running 'gaia chat --index <pdf> --query "..."' against the default
Gemma-4-E4B model. Users hit a ~10-minute hang followed by the
misleading "Couldn't reach the local LLM" error.

Three layers of fix:

1. Trim _get_system_prompt to ~10K chars (5x reduction). All imperative
   directives preserved; only multi-paragraph examples and
   eval-survival enumerations dropped. Wire payload per chat-completions
   request cut ~38% (~85K -> ~53K chars including the tools schema).
   New SINGLE-DOC RESOLUTION rule when exactly one document is
   indexed — names the file and orders an immediate query_specific_file
   so Gemma stops asking "which document?" with only one indexed.

2. New LemonadeUpstreamTimeoutError distinguishes "Lemonade is up but
   the model call hung" from genuine connectivity failure.
   retryable=False prevents silent retry against a hung backend.
   User-facing message names concrete remediation steps (wait + KV
   cache, gaia kill && lemonade-server serve, --max-chunks 2, close
   GPU apps); no smaller-model fallback. Both classifiers
   (response-payload and exception-string) handle the split.

3. Base agent's generic "Sorry, I ran into an unexpected problem"
   catchall now surfaces typed Lemonade messages verbatim via a new
   _extract_lemonade_user_message helper. Walks __cause__ / __context__
   with cycle protection.

Also fixes a latent infinite-loop bug in _classify_chat_exception
(_chat_helpers.py) that walked the cause chain without cycle protection
— would have hung the chat handler forever on any pathological
exception graph with a __cause__ loop. Found by the new cycle-test.

Validated:
  - 2326 unit tests pass, lint clean
  - 19 live PDF scenarios from 1.4MB to 43MB, zero "Timeout was reached"
  - Cold-start scenario (model unloaded -> first query): 44.5s on Mac
    M-series with full cited answer
  - Bug-report's literal "what does the document say about water?"
    query against a water-content doc: 45s thorough cited retrieval
  - Live injected-timeout simulation: typed user_message surfaces to
    user verbatim, no generic "try again" wrapper

User-facing documentation entry added at docs/reference/troubleshooting.mdx
under "Agent & SDK Issues".

Closes #1030.
@github-actions github-actions Bot added documentation Documentation changes llm LLM backend changes tests Test changes performance Performance-critical changes agents labels May 11, 2026
@kovtcharov kovtcharov self-assigned this May 11, 2026
@kovtcharov kovtcharov requested a review from itomek-amd May 11, 2026 08:38
In plain English: doc Q&A flows on a 1-2 MB PDF were busting the
32K window — `summarize_document` was building section prompts of
~35-50K tokens and getting back ContextOverflow errors. Bumping to
64K (Gemma 4 E4B supports up to 128K natively) gives doc-Q&A real
headroom while keeping memory pressure manageable on 16 GB iGPUs.

What changed:
- MODELS["gemma-4-e4b"].min_ctx_size: 32768 -> 65536
- AGENT_PROFILES["chat"|"rag"].min_ctx_size: 32768 -> 65536
- cli.py:agent_context_sizes["chat"|"rag"]: 32768 -> 65536
- Reload-retryable thresholds in lemonade.py + _chat_helpers.py +
  agent.py: bumped from 32768 to 65536 so the existing auto-reload
  path (LemonadeManager._try_reload_with_ctx) still triggers when
  the loaded ctx is below the new expected window.
- _ensure_model_loaded now distinguishes "Downloading model (first
  run, several minutes)" from "Loading model" so users on a fresh
  install see honest expectations instead of staring at a generic
  "Loading..." message for 5 minutes.
- New GAIA_CTX_SIZE env-var override so users on tight-memory
  hardware can dial back to 32K (or push up to 128K) without code
  changes. No silent fallback — explicit opt-in.

Memory tradeoff: Gemma 4 E4B Q4 weights ~5 GB, KV cache at 32K
~0.5 GB vs ~1 GB at 64K, ~2 GB at 128K. Total at 64K ~6 GB, fits
comfortably on 16 GB shared-memory iGPUs.

What this does NOT fix:
- summarize_document still builds whole-section prompts without
  splitting on ctx_size — at 64K the 35K and 50K segments now
  fit, but a 70K+ document section would still hit overflow. To
  be filed as a separate bug.
…FAISS (#1030)

In plain English: even after bumping the chat/RAG context window to 64K,
Gemma kept getting auto-loaded at 32K — so `summarize_document` and other
long-prompt paths still overflowed. Three coupled bugs were doing this:

1) `LemonadeStatus.loaded_models` was populated from `/api/v1/models`
   (the full catalog) instead of `/api/v1/health.all_models_loaded` (the
   models actually in memory). Downstream code that filters for "the
   loaded LLM" was picking `Gemma-3-4b-it-GGUF` — alphabetically first
   in the catalog, never actually loaded — every time it tried to
   reload at the new ctx. Fixed in get_status by sourcing loaded models
   from health and joining catalog metadata for label compatibility.

2) `_ensure_model_loaded` returned early on any model-name match without
   verifying ctx_size matched GAIA's expected window, and the
   non-streaming `chat_completions` path didn't call it at all. When
   the RAG SDK's embedder warm-up called `unload_model()` (no-arg →
   unloads everything), the next chat_completions request let Lemonade
   auto-load Gemma at its own 32K default, silently capping doc-Q&A
   below the bumped requirement. Both paths now ensure the model is
   loaded at the GAIA-expected ctx_size, reloading explicitly when the
   loaded entry is under-sized.

3) `_retrieve_chunks_from_file` rebuilt the per-file FAISS index on every
   query because `index_document`'s cache-load path never populated
   `self.file_indices[file_path]` — only the fresh-index path did. Every
   chat turn paid ~3s of avoidable embedding recompute. Pre-built on
   cache load now, mirroring the fresh-index path.

End-to-end: Gemma now actually stays at 64K through the chat flow
(verified via /health: `Gemma-4-E4B-it-GGUF: ctx_size=65536`). Cold-start
on the bug-report PDF dropped from ~1:42 to ~1:06 on Mac M-series. No
more `Per-file index not cached, rebuilding` warnings.
@github-actions github-actions Bot added the rag RAG system changes label May 11, 2026
Three failures on this PR's CI all trace back to changes in the earlier
#1030 commits.

- Lint (`Unit Tests` workflow): `initialize_lemonade_for_agent` used
  `log.info`/`log.warning` for the new GAIA_CTX_SIZE override branch but
  never bound `log = get_logger(__name__)` like every other helper in
  `cli.py` — pylint/flake8 caught it as an undefined name. Also drops the
  unused `import os` flake8 flagged in
  `tests/unit/connectors/test_disconnect_clears_grants.py`.

- Unit Tests: the rewritten `_ensure_model_loaded` now reloads any model
  whose `recipe_options.ctx_size` is below the GAIA expected window, but
  `test_skips_load_when_model_already_loaded` and the matching
  integration test still mocked bare `{"id": "model-a"}` entries with no
  recipe_options — so the new "loaded but under-sized" branch fired and
  the mock saw an extra `load_model` call. Mocks now carry
  `recipe_options.ctx_size=32768` so the no-op branch executes.

- Unit Tests (`test_code_index_sdk.py`): the new
  `test_chat_system_prompt_budget.py` was installing `MagicMock` into
  `sys.modules` for `faiss`/`numpy`/etc. at module import time and never
  cleaning up. On Linux CI faiss-cpu isn't part of the `[api]` extras,
  so downstream `test_code_index_sdk.py::TestCachePersistence` and
  `TestFailLoudly::test_ensure_index_loaded_raises_on_corrupt_faiss`
  imported the leftover MagicMock instead of a real (or absent) faiss
  module and silently took the wrong code path. The stubs now roll back
  after the one `gaia.agents.chat.agent` import that needs them.

- Windows CLI Tests: the self-hosted Windows runner's lemonade-server
  registry was wiped (likely a mid-May server upgrade), and the
  workflow only pre-pulled `Llama-3.2-3B-Instruct-Hybrid`. Every
  summarize-CLI test then died inside `LemonadeManager.ensure_ready`
  with "Load request for model_name=Gemma-4-E4B-it-GGUF not
  registered". Workflow now also pulls Gemma-4-E4B-it-GGUF (the GAIA
  default LemonadeManager preloads) so the runner is self-sufficient.
@github-actions github-actions Bot added the devops DevOps/infrastructure changes label May 11, 2026
The Windows summarize CLI tests started failing on this PR with
"Load request for model_name=Gemma-4-E4B-it-GGUF not registered with
Lemonade Server" even though main passed three days earlier. The
``install-lemonade`` composite action was explicitly designed to leave
the runner's existing Lemonade Server alone ("does NOT install a new
version to avoid conflicts") and only warn when versions differ — so
the ``stx`` runner stayed on an older Lemonade whose model catalog
predates the Gemma-4-E4B-it-GGUF entry GAIA now relies on for its
default model preload via ``LemonadeManager.ensure_ready``.

The action now compares installed vs ``src/gaia/version.LEMONADE_VERSION``
and, when the runner is strictly behind, downloads the matching
``lemonade.msi`` from the same lemonade-sdk GitHub release the
``gaia init`` flow uses (``installer/lemonade_installer.py:GITHUB_RELEASE_BASE``)
and runs ``msiexec /i ... /quiet /norestart``. If the runner is at or
ahead of the expected version, the action is still a no-op — we don't
downgrade. On MSI failure the tail of the install log is surfaced.

With the upgrade in place the workflow no longer needs an explicit
``lemonade-server pull Gemma-4-E4B-it-GGUF`` (it failed anyway on the
old catalog with ``PullError: Failed to install``); the comment on the
remaining Llama pull is updated to reflect the new flow.
Two follow-ups to the prior upgrade attempt:

The MSI ran (exit 0) and put v10.2.0 under
``C:\Program Files\Lemonade Server\bin``, but the action's
post-install search short-circuited on ``Get-Command lemonade-server``
which still resolved the older v8.2.2 ``lemonade-server.bat`` shim under
``LOCALAPPDATA\lemonade_server\bin\``. That left the shell pointing at
the stale binary, GAIA's default-model preload tried to load
Gemma-4-E4B-it-GGUF against v8.2.2's catalog, and the summarize CLI
tests died on "model_name=... not registered" all over again.

Find-LemonadeServer now scans the well-known install dirs FIRST
(including the new ``Program Files\Lemonade Server\bin``) so the MSI
binary wins, and Get-Command is a final fallback. A Refresh-EnvPath
helper re-reads HKLM/HKCU ``Path`` after MSI install so the freshly-
registered Program Files dir is visible to the rest of the step --
mirroring ``LemonadeInstaller.refresh_path_from_registry`` in the
gaia init flow.

Post-install verification is now strict: if the resolved version is
still below ``LEMONADE_VERSION`` we exit 1 with a list of every
``lemonade-server`` candidate on PATH, instead of warning and continuing
into doomed downstream tests.
…er shim

The v10.2.0 install renamed the main binary to ``LemonadeServer.exe``
(PascalCase) and left ``lemonade-server.exe`` as a deprecation shim that
prints ``WARNING: 'lemonade-server' is deprecated. Use 'LemonadeServer.exe'
to start the server`` and refuses ``--version`` queries -- so the action's
post-install version check returned an empty string and exited 1.

Find-LemonadeServer now does a two-pass scan: first for the new
``LemonadeServer.exe``, then a fallback for the legacy
``lemonade-server.exe`` / ``.bat`` names. Get-Command fallback was also
extended to try both names. Version detection now combines stdout/stderr
through ``cmd /c "...2>&1"`` and silences ``$ErrorActionPreference`` so a
non-zero exit from the deprecation shim no longer hides the version string
when one is present.

The SYSTEM-profile path (``C:\windows\system32\config\systemprofile\
AppData\Local\lemonade_server\bin``) is added to the search list -- that's
where the MSI placed the v10.2.0 install on this runner, and Get-Command
exposed it as a third candidate alongside the per-user .bats.
The v10.2.0 ``LemonadeServer.exe`` (the new canonical binary) emits no
console output on ``--version`` -- it's effectively a GUI launcher, not
a CLI. The legacy ``lemonade-server.exe`` shim emits a deprecation
warning. Either way, ``$LemonadeExe --version`` returns nothing
parseable and the post-install version check kept seeing an empty
string and exiting 1 even though the MSI install succeeded.

Get-LemonadeVersion now reads the PE file's embedded VersionInfo
(ProductVersion / FileVersion) via ``Get-Item .VersionInfo`` first --
that's the version the installer baked into the binary, no CLI
invocation needed. ``--version`` parsing is kept as a fallback for any
non-.exe path (the .bat shims) and for future binaries that decide to
support it.
v10.2.0's deprecation shim emits ``This command is deprecated. Use
'lemonade pull --help' instead.`` and exits non-zero for the legacy
``lemonade-server pull <model>`` form, which killed the workflow with
``Process completed with exit code 1`` before any tests ran.

``Start-Process -FilePath "lemonade-server" ... serve`` is left alone --
the shim still execs into the new server for the ``serve`` verb (the
last run confirmed the health endpoint came up at 13305) and
``Start-Process`` ignores the shim's exit code anyway.
Eval-driven optimization arc on top of the #1030 fix. rag_quality
pass rate goes from 5/7 (baseline avg 8.84) to 7/7 (avg 9.10), and
the two scenarios that previously couldn't even complete now pass
cleanly.

Five coupled fixes:

1) src/gaia/eval/runner.py — only pass `--bare` to `claude -p` when an
   explicit `ANTHROPIC_API_KEY` is in env. The flag is documented to
   restrict Anthropic auth strictly to `ANTHROPIC_API_KEY` /
   `apiKeyHelper`, so subscription users (Claude Code Max with a
   `claude /login` OAuth session) saw every eval fail-fast with
   "Not logged in · Please run /login" even though they were signed
   in. Conditional opt-in preserves the clean-subprocess isolation
   for API-key users.

2) src/gaia/eval/claude.py — when `ANTHROPIC_API_KEY` is missing,
   the error message now points users at `claude setup-token`
   (subscription path) first and `export ANTHROPIC_API_KEY` second,
   instead of demanding the env var without explaining alternatives.
   No behavior change for setups that already have the key.

3) src/gaia/mcp/servers/agent_ui_mcp.py — `send_message` payload now
   pins `model=Gemma-4-E4B-it-GGUF` instead of letting the UI fall
   back to its `default_model_name`. The UI's default was being
   overridden to `Qwen3.5-4B-GGUF` by a stale `custom_model` setting
   in some installs, which caused Lemonade to thrash between Qwen
   and Gemma on every eval turn. Pinning Gemma per-request stops the
   swap cycle and was the single change that turned the most-stuck
   scenario (`negation_handling`) from FAIL→TIMEOUT→PASS.

4) src/gaia/ui/_chat_helpers.py — extend `_classify_chat_exception`
   to recognise Lemonade HTTP 5xx (`status 5xx`, `Internal Server
   Error`, `Service Unavailable`, `Bad Gateway`, `Gateway Timeout`)
   as transient `LemonadeNetworkError` (retryable=True). Previously
   a Lemonade-side 503 during a model swap surfaced as the generic
   "trouble connecting to the language model" UI fallback with no
   retry; now the chat layer's existing retry-on-retryable path
   triggers a model reload + one retry, which usually recovers.

5) src/gaia/agents/chat/tools/rag_tools.py — omit the `page` key
   from chunk dicts when `extract_page_from_chunk` returns None
   (markdown / HTML / docs without page metadata). Agent was
   templating "According to <doc>, page null:" into citations,
   which the eval judge consistently docked on `personality` as a
   cosmetic artifact. Data-layer fix; the agent now naturally omits
   the page suffix when there's no value to fill in.

Plus one flake fix:

6) tests/unit/test_chat_system_prompt_budget.py — only stub
   `faiss`/`numpy`/`pypdf`/etc. when they CAN'T be imported in the
   current environment, and on cleanup also evict the GAIA modules
   that bound them (`gaia.rag.sdk`, `gaia.agents.chat.agent`,
   `gaia.agents.chat.tools.rag_tools`). Pre-fix, when the budget
   test ran first and `pypdf` was installed, the stub poisoned
   `gaia.rag.sdk`'s `pypdf` binding for the rest of the pytest
   session — and later `tests/unit/rag/test_pdf_extraction_errors.py`
   would mis-detect a blank PDF as encrypted because pypdf was now
   a MagicMock. Six tests flaked depending on collection order.

Validated:
  - rag_quality eval (claude-sonnet-4-6 judge over subscription):
    7/7 pass, 100% pass rate, avg 9.10/10 (was 5/7, 71%, avg 8.84)
  - `pytest tests/unit/ tests/test_chat_agent.py tests/test_eval.py
     --ignore=tests/unit/chat/ui` → 2495 pass, 0 fail, 27 skip
  - `util/lint.py --all` → pass (soft warnings unrelated to diff)
@github-actions github-actions Bot added mcp MCP integration changes eval Evaluation framework changes labels May 11, 2026
7/7 PASS, avg 9.08 — captures the post-optimization state from commit
95e4b37. Pass rate matches the prior d71cd91 baseline (also 7/7);
avg score is 0.35 below it but offset by clearing the two previously-
broken scenarios (negation_handling FAIL→PASS, table_extraction
TIMEOUT→PASS). Future PRs touching the LLM-affecting surface listed in
CLAUDE.md should --compare against this scorecard.

meta.json records the Lemonade pre-load step required to reproduce
cleanly (Lemonade auto-loaded Qwen3.5-4B without it, causing
swap-thrash timeouts).
@kovtcharov

Copy link
Copy Markdown
Collaborator Author
Screenshot 2026-05-11 at 12 19 00 PM

@kovtcharov

Copy link
Copy Markdown
Collaborator Author

perf_summary.md

…ade``

Four workflows + the shared start-lemonade.ps1 helper were still wired
for the v8.2.2 Lemonade CLI; running on the v10.2.0 server the
``install-lemonade`` action now upgrades to surfaced two new failures:

- ``lemonade-server serve --ctx-size N`` aborts before bind on v10.x
  with ``error: failed to start lemonade-server`` written to stderr.
  The flag is no longer accepted on serve; pin the ctx_size per-model
  via ``/api/v1/load`` instead (canonical v10.x path). Affected:
  ``test_api.yml``, ``test_rag.yml``, ``installer/scripts/start-lemonade.ps1``.

- ``lemonade-server pull <model>`` prints ``This command is deprecated.
  Use 'lemonade pull --help' instead.`` and exits non-zero. The
  ``lemonade`` CLI binary is the v10.x replacement. Affected:
  ``test_agent_sdk.yml``, ``installer/scripts/start-lemonade.ps1``.

start-lemonade.ps1 also now prefers ``LemonadeServer.exe`` (PascalCase
v10.x binary) over the legacy ``lemonade-server`` deprecation shim for
the ``serve`` invocation -- same pattern install-lemonade already uses
-- and resolves ``lemonade`` separately for pull, falling back to the
combined exe only when the new CLI isn't on PATH (compat with older
runners we haven't migrated yet).
@github-actions github-actions Bot added the installer Installer changes label May 11, 2026
…ver.exe

Previous attempt preferred ``LemonadeServer.exe`` for the serve
invocation thinking it was the new canonical binary, but on v10.2.0
that exe appears to be a tray/launcher with a different CLI shape:
``LemonadeServer.exe serve --port N --no-tray`` runs, produces zero
console output, and never binds the port -- the smoke test then times
out waiting on a health endpoint that never comes up.

The legacy ``lemonade-server`` shim, by contrast, still translates the
``serve --no-tray --port N`` arg shape correctly into a working server
on v10.2.0 -- ``test_gaia_cli_windows.yml`` uses exactly that
incantation against the same runner and passes. Same shim, same args,
same outcome: the server binds and answers /api/v1/health.

So pin the serve call to ``$lemonadeServerExe`` (the shim) and keep
``$lemonadeCli`` (the new ``lemonade`` binary) for pull operations.
``--ctx-size`` stays off the serve invocation (the shim still refuses
it on v10.x) and is set per-model on the /api/v1/load body.
@kovtcharov-amd kovtcharov-amd enabled auto-merge May 11, 2026 19:58
@kovtcharov-amd kovtcharov-amd added this pull request to the merge queue May 11, 2026
Merged via the queue into main with commit 241c0d9 May 11, 2026
51 checks passed
@kovtcharov-amd kovtcharov-amd deleted the fix/rag-pdf-gemma-timeout-1030 branch May 11, 2026 20:18
pull Bot pushed a commit to bhardwajRahul/gaia that referenced this pull request May 12, 2026
## Why this matters

Three process rules from the post-mortem on amd#1030 (the Gemma 4 RAG-PDF
timeout fixed in amd#1034):

1. **Run the agent eval when you change anything that affects how the
LLM behaves.** Don't skip it — the Claude Code subscription typically
already provides API access. amd#1030 is the canonical example of a bug the
eval would have caught in CI.
2. **Lead PR descriptions, commit messages, and bot reviews with the
change itself, no labelled preamble.** Recent auto-review comments
trended toward dense framework jargon non-engineers struggled to act on;
the rule now demands the finding up front, then technical detail, with
hard length caps.
3. **Keep code comments to one short line or skip them.**
Multi-paragraph "history of how we got here" blocks belong in the PR /
commit message, not inline. The new section quotes the verbose comment
from the amd#1030 fix as the canonical Bad example.

No behaviour change, no code change. CLAUDE.md gets the three rules; the
bot prompts in `.github/workflows/claude.yml` now defer to CLAUDE.md for
style and only carry the length caps inline.

## Test plan

- [ ] `python -c "import yaml;
yaml.safe_load(open('.github/workflows/claude.yml'))"` — YAML still
parses
- [ ] Read CLAUDE.md end-to-end and confirm the new rules read
coherently with the existing rules; no contradictions
- [ ] Confirm the bot prompts still describe the same review structure
(Summary → Issues → Strengths → Verdict) — the style rule is additive

## Merge order

CLAUDE.md's new "eval triggers" bullet references
`_extract_lemonade_user_message` (introduced by amd#1034). amd#1036 should
land **after** amd#1034 so that symbol resolves on main.

## Related

- amd#1030 — the bug that triggered this post-mortem
- amd#1034 — the bug fix
- amd#1033 — broader CI testing-gap follow-up
- amd#1037 — npm dependabot vulnerabilities investigation
@itomek itomek mentioned this pull request May 14, 2026
6 tasks
pull Bot pushed a commit to bhardwajRahul/gaia that referenced this pull request May 15, 2026
## 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents cli CLI changes devops DevOps/infrastructure changes documentation Documentation changes eval Evaluation framework changes installer Installer changes llm LLM backend changes mcp MCP integration changes performance Performance-critical changes rag RAG system changes tests Test changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: 1.4MB file indexed no response to queries in the UI

3 participants