Skip to content

fix(reasoner+eval): bound LLM reasoner requests; fix eval retrieval A/B path - #123

Open
njfio wants to merge 1 commit into
mainfrom
fix/llm-reasoner-bounds-eval-retrieval
Open

njfio wants to merge 1 commit into
mainfrom
fix/llm-reasoner-bounds-eval-retrieval

Conversation

@njfio

@njfio njfio commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Summary

The LLM write-path reasoner (LlmReasoner::http_chat_call) built its reqwest client with Client::new() (no timeout) and sent requests with no max_tokens. Found while running write-side eval experiments:

  • A slow / hung / drip-streaming endpoint blocked the write path indefinitely (reqwest waits forever without a timeout) — hard livelocks during ingest.
  • An un-capped local model could run away generating for tens of seconds per call, making bulk ingest impractical.

Reasoner fixes (src/memory/reasoning/llm.rs)

  • Per-request timeout — SYNAPTIC_LLM_TIMEOUT_SECS (default 90). On timeout the call errors and the reasoner fails open to its heuristic fallback, so ingest degrades rather than hangs.
  • max_tokens cap — SYNAPTIC_LLM_MAX_TOKENS (default 512). Bounds per-call latency; extraction/resolution replies are small JSON.

Eval harness fixes (tools/eval/src/bin/run_eval.rs)

  • --qtype NAME now drops conversations with no matching questions (previously only questions were filtered → every conversation still ingested; on the retrieval path, which spawns one task per conversation, this flooded the reasoner and wedged its HTTP client).
  • Retrieval path uses bounded ingest concurrency (RETRIEVAL_CONCURRENCY, default 2).
  • Retrieval path honors --exclude-superseded (bi-temporal A/B): ingest unchanged (KG marks supersessions), only retrieval drops superseded memories → recall@k of the two arms is directly comparable.

Testing

  • Release build green; cargo fmt --check clean.
  • 2-instance knowledge-update retrieval A/B completes; both arms R@10=1.0 on the oracle set (recall saturated — the bi-temporal effect is not a recall-level effect on oracle haystacks).

Supersedes #122 (needed a fresh branch to include the rustfmt fix, per the repo's PR-only ruleset).

🤖 Generated with Claude Code

…/B path

The LLM write-path reasoner (LlmReasoner::http_chat_call) built its reqwest
client with `Client::new()` (no timeout) and sent requests with no `max_tokens`.
A slow, hung, or runaway endpoint could therefore block the write path
indefinitely, or a local model could generate for tens of seconds per call,
making bulk ingest impractical. Add:
- a per-request timeout (SYNAPTIC_LLM_TIMEOUT_SECS, default 90); on timeout the
  call errors and the reasoner fails open to its heuristic fallback, so ingest
  degrades rather than hangs.
- a max_tokens cap (SYNAPTIC_LLM_MAX_TOKENS, default 512); extraction/resolution
  replies are small JSON, so this bounds per-call latency without truncating.

Eval harness (run_eval):
- `--qtype NAME` now drops conversations with no matching questions (previously
  only questions were filtered, so all conversations were still ingested — on
  the retrieval path that spawned one task per conversation this flooded the
  reasoner and wedged its HTTP client).
- retrieval path: bounded ingest concurrency (RETRIEVAL_CONCURRENCY, default 2)
  instead of one spawned task per conversation.
- retrieval path honors `--exclude-superseded` (bi-temporal A/B): ingest is
  unchanged (KG on marks supersessions), only retrieval drops superseded
  memories, so recall@k of the two arms is directly comparable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant