Skip to content

feat: MemoryBench evaluation suite (Epic #283)#292

Merged
jerry609 merged 45 commits into
masterfrom
dev
Mar 7, 2026
Merged

feat: MemoryBench evaluation suite (Epic #283)#292
jerry609 merged 45 commits into
masterfrom
dev

Conversation

@jerry609

@jerry609 jerry609 commented Mar 7, 2026

Copy link
Copy Markdown
Owner

Summary

  • Implement 4-suite MemoryBench evaluation aligned with LongMemEval (ICLR 2025), LoCoMo (ACL 2024), Mem0, and Letta benchmarks
  • Add Retrieval Bench v2 with IR metrics (Recall@5=0.873, MRR@10=0.731, nDCG@10=0.747) across 40 annotated queries
  • Add Scope Isolation + CRUD lifecycle verification with zero-leak enforcement
  • Add Context Extraction bench validating L0-L3 layer assembly, token budget guard, and TrackRouter accuracy
  • Add Injection Robustness L1 with offline pattern detection (0% pollution rate)
  • Add comprehensive testing documentation (evals/memory/README.md)

Test plan

  • PYTHONPATH=src pytest -q evals/memory/test_retrieval_bench.py — PASS
  • PYTHONPATH=src pytest -q evals/memory/test_scope_isolation.py — PASS
  • PYTHONPATH=src pytest -q evals/memory/test_context_extraction.py — PASS
  • PYTHONPATH=src pytest -q evals/memory/test_injection_robustness.py — PASS
  • All 4 benches pass together in 5.85s (fully offline)
  • Existing unit tests unaffected (19 passed)

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added layered context engine with token budgeting and cross-track memory search
    • Implemented advanced memory system with full-text search, vector embeddings, decay-based ranking, and scope isolation
    • Added comprehensive benchmarking framework for retrieval, memory performance, ROI, and effectiveness evaluation
    • Introduced injection detection for memory safety
    • Added runtime preparation for verification with caching and requirements management
    • Extended code experience persistence across sessions
  • Documentation

    • Added design documentation for Paper-to-Context module architecture (Modules 1–3)
    • Added benchmark guides for retrieval, memory performance, ROI, and effectiveness evaluation
    • Added context engine evaluation documentation
  • Improvements

    • Improved LLM provider resilience with fallback and transient retry logic
    • Enhanced error messages and handling across frontend and backend

jerry609 and others added 30 commits March 5, 2026 16:55
P0 fixes:
- Replace unbounded daemon threads with ThreadPoolExecutor(max_workers=2)
  for embedding writes; atexit + close() ensure graceful shutdown so
  in-flight embeddings are not lost on process exit
- Restore apprise>=1.9.0 and feedgen>=1.0.0 removed in epic branch,
  which would have broken Epic #179 push/RSS features on merge

P1 fixes:
- _escape_fts: replace double-quote-only escaping with a whitelist regex
  [A-Za-z0-9_+-] so FTS5 operators (*, NEAR, NOT, ^) cannot alter query
  semantics; empty queries now short-circuit to []
- _hybrid_merge: skip items with None/invalid id instead of defaulting
  to id=0, preventing silent score collisions across unrelated records
- ReproExperienceStore: add application-level dedup check + UNIQUE
  constraint (paper_id, pattern_type, content) + IntegrityError fallback
  to prevent duplicate experiences from accumulating across retries

Migration:
- 0022_repro_experience_dedup: adds uq_repro_exp_paper_type_content
  unique constraint to existing repro_code_experience table

Tests: 47 unit tests pass (+3 new tests covering the fixes above)
…o pipeline

Add user-scoped isolation for repro_code_experience and enforce dedup semantics with migration 0022_repro_experience_dedup.

Inject ReproExperienceStore through ReproAgent/Orchestrator/CodingAgent/GenerationNode and propagate user_id/pack_id in generation, verification, and debugging persistence paths.

Update /api/gen-code to accept user_id and extend unit tests for user isolation and persistence behavior.
Add decay-aware scoring that combines relevance (confidence), recency
(exponential decay with 90-day half-life), and usage frequency to
re-rank search results. New memories default to expires_at = created_at
+ 365 days. search_memories() now auto-touches usage on hits.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add search_memories_batch() that queries multiple scope_ids in a single
SQL call, eliminating the N+1 loop in build_context_pack(). Engine now
uses this batch method for cross-track memory retrieval.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Refactor build_context_pack() into 4 layer methods:
- Layer 0: user profile (cached with 5-min TTL, ~200 tokens)
- Layer 1: track context — tasks/milestones (~500 tokens)
- Layer 2: query-relevant + cross-track memories (~1000 tokens)
- Layer 3: paper-scoped memories (on-demand)

Return value adds context_layers metadata while remaining fully
backward-compatible.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use standard ln(2)/halfLifeDays lambda formula (matches OpenClaw
  temporal-decay.ts:toDecayLambda)
- Default half-life lowered to 30 days (was 90, now matches OpenClaw)
- Evergreen memories (global scope, preference kind) are immune to
  recency decay (inspired by OpenClaw isEvergreenMemoryPath)
- Add _to_decay_lambda() and _is_evergreen_memory() helpers
- Expand tests for lambda math, half-life precision, and evergreen logic

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a deterministic retrieval benchmark fixture, scorer, CLI, docs, and CI smoke gate for PaperSearchService.\n\nCloses #284\nRefs #283
Add deterministic fixtures, scoring, CLI, and smoke coverage for layered assembly, token guard, and advisory routing in ContextEngine.\n\nCloses #286\nRefs #283
Add an offline scope-isolation benchmark for memory retrieval paths, extend the metric collector with cross-user and cross-scope leak rates, and wire the new check into CI.\n\nCloses #285\nRefs #283
Add a deterministic prompt-injection pattern detector, labeled offline fixtures, an acceptance benchmark, and CI coverage for Injection Robustness L1.\n\nCloses #287\nRefs #283
Add a deterministic synthetic benchmark for memory search latency baselines across 10k/100k/1M scales, plus docs and smokeable unit coverage.\n\nCloses #288\nRefs #283
jerry609 and others added 15 commits March 7, 2026 12:39
…uite

# Conflicts:
#	.github/workflows/ci.yml
#	evals/memory/__init__.py
# Conflicts:
#	evals/memory/__init__.py
#	src/paperbot/memory/eval/__init__.py
* docs: update README with macOS python3 tips

* docs: update README with more badges

* docs: update README with deleting extra badges

* docs: update README with new god name

---------

Co-authored-by: 林杰 <linjie@linjiedeMacBook-Air.local>
Co-authored-by: 林杰 <linjie@v8d1ef64c.dip.tu-dresden.de>
Co-authored-by: 林杰 <linjie@v8d1ef43e.dip.tu-dresden.de>
Co-authored-by: 林杰 <linjie@v8d1ef6c5.dip.tu-dresden.de>
* docs: update README with macOS python3 tips

* docs: update README with more badges

* docs: update README with deleting extra badges

* docs: update README with new god name

---------

Co-authored-by: 林杰 <linjie@linjiedeMacBook-Air.local>
Co-authored-by: 林杰 <linjie@v8d1ef64c.dip.tu-dresden.de>
Co-authored-by: 林杰 <linjie@v8d1ef43e.dip.tu-dresden.de>
Co-authored-by: 林杰 <linjie@v8d1ef6c5.dip.tu-dresden.de>
Add comprehensive memory module evaluation aligned with LongMemEval
(ICLR 2025), LoCoMo (ACL 2024), Mem0, and Letta benchmarks.

- Retrieval Bench v2: IR metrics (Recall@5=0.873, MRR@10=0.731, nDCG@10=0.747)
  with 40 annotated queries across 5 question types and 5 memory dimensions
- Scope Isolation + CRUD: zero-leak verification across user x scope matrix,
  Mem0-aligned CRUD lifecycle (add/update/delete/dedup)
- Context Extraction: L0-L3 layer completeness, precision, token budget guard,
  TrackRouter accuracy (100%), graceful degradation
- Injection Robustness L1: offline pattern detection (0% pollution, 0% FP)
- Fixture dataset: 45 memories (2 users), 12 injection patterns
- Testing documentation with methodology, validity analysis, and results

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 7, 2026 08:35
@vercel

vercel Bot commented Mar 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
paper-bot Ready Ready Preview, Comment Mar 7, 2026 8:35am

@coderabbitai

coderabbitai Bot commented Mar 7, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bbf306cf-00a7-4f9b-b85c-3a338d113c5d

📥 Commits

Reviewing files that changed from the base of the PR and between 4e37a37 and 830de71.

📒 Files selected for processing (98)
  • .github/workflows/ci.yml
  • Makefile
  • README.md
  • alembic/versions/0019_memory_fts5.py
  • alembic/versions/0020_memory_embedding.py
  • alembic/versions/0021_repro_code_experience.py
  • alembic/versions/0022_repro_experience_dedup.py
  • docs/P2C_MODULE_1_CORE_ENGINE.md
  • docs/P2C_MODULE_2_API_STORAGE.md
  • docs/P2C_MODULE_3_FRONTEND.md
  • docs/PAPER_TO_CONTEXT_MODULE_DESIGN.md
  • docs/benchmark/MEMORYBENCH_EPIC_283_COMPLETION.md
  • docs/benchmark/MEMORYBENCH_RUNTIME_REPORT_2026-03-07.md
  • docs/context_engine_eval.md
  • docs/memory_effectiveness_eval.md
  • docs/memory_performance_eval.md
  • docs/p2c/P2C_MODULE_1_CORE_ENGINE.md
  • docs/p2c/P2C_ROI_BENCHMARK.md
  • docs/search_eval.md
  • evals/README.md
  • evals/fixtures/context/bench_v1.json
  • evals/fixtures/retrieval/bench_v2.jsonl
  • evals/memory/README.md
  • evals/memory/__init__.py
  • evals/memory/bench_effectiveness.py
  • evals/memory/bench_roi.py
  • evals/memory/fixtures/bench_v2/bench_memories.json
  • evals/memory/fixtures/bench_v2/retrieval_queries_v2.json
  • evals/memory/fixtures/injection_patterns.json
  • evals/memory/fixtures/multi_session_effectiveness.json
  • evals/memory/fixtures/repro_experiences.json
  • evals/memory/fixtures/roi_cases.json
  • evals/memory/test_context_extraction.py
  • evals/memory/test_injection_robustness.py
  • evals/memory/test_retrieval_bench.py
  • evals/memory/test_scope_isolation.py
  • evals/runners/run_context_engine_benchmark_smoke.py
  • evals/runners/run_retrieval_benchmark_smoke.py
  • requirements.txt
  • scripts/benchmark_memory_performance.py
  • scripts/eval_context_engine.py
  • scripts/eval_search.py
  • src/paperbot/api/routes/gen_code.py
  • src/paperbot/api/routes/repro_context.py
  • src/paperbot/application/services/llm_service.py
  • src/paperbot/application/services/p2c/context_bridge.py
  • src/paperbot/application/services/p2c/models.py
  • src/paperbot/application/services/p2c/orchestrator.py
  • src/paperbot/application/services/p2c/prompts.py
  • src/paperbot/application/services/p2c/stages.py
  • src/paperbot/application/services/retrieval_benchmark.py
  • src/paperbot/context_engine/benchmark.py
  • src/paperbot/context_engine/embeddings.py
  • src/paperbot/context_engine/engine.py
  • src/paperbot/infrastructure/llm/providers/openai_provider.py
  • src/paperbot/infrastructure/stores/memory_store.py
  • src/paperbot/infrastructure/stores/models.py
  • src/paperbot/infrastructure/stores/repro_experience_store.py
  • src/paperbot/memory/eval/__init__.py
  • src/paperbot/memory/eval/collector.py
  • src/paperbot/memory/eval/effectiveness_benchmark.py
  • src/paperbot/memory/eval/injection_guard.py
  • src/paperbot/memory/eval/performance_benchmark.py
  • src/paperbot/memory/eval/roi_benchmark.py
  • src/paperbot/repro/agents/coding_agent.py
  • src/paperbot/repro/agents/debugging_agent.py
  • src/paperbot/repro/agents/planning_agent.py
  • src/paperbot/repro/agents/verification_agent.py
  • src/paperbot/repro/memory/code_memory.py
  • src/paperbot/repro/nodes/generation_node.py
  • src/paperbot/repro/nodes/planning_node.py
  • src/paperbot/repro/nodes/verification_node.py
  • src/paperbot/repro/orchestrator.py
  • src/paperbot/repro/repro_agent.py
  • src/paperbot/repro/verification_runtime.py
  • tests/unit/test_context_engine_benchmark.py
  • tests/unit/test_context_layers.py
  • tests/unit/test_embeddings_fallback.py
  • tests/unit/test_generation_node_llm.py
  • tests/unit/test_injection_guard.py
  • tests/unit/test_llm_service.py
  • tests/unit/test_memory_batch_search.py
  • tests/unit/test_memory_decay.py
  • tests/unit/test_memory_effectiveness_benchmark.py
  • tests/unit/test_memory_embedding.py
  • tests/unit/test_memory_fts5.py
  • tests/unit/test_memory_metric_collector.py
  • tests/unit/test_memory_performance_benchmark.py
  • tests/unit/test_openai_provider_fallback.py
  • tests/unit/test_paper_scope_memory.py
  • tests/unit/test_repro_code_experience.py
  • tests/unit/test_retrieval_benchmark.py
  • tests/unit/test_roi_benchmark.py
  • tests/unit/test_verification_error_classification.py
  • tests/unit/test_verification_runtime.py
  • web/src/components/research/ResearchDashboard.tsx
  • web/src/components/research/ResearchDiscoveryPage.tsx
  • web/src/components/research/ResearchPageNew.tsx

📝 Walkthrough

Walkthrough

This PR introduces comprehensive MemoryBench evaluation suites (retrieval, effectiveness, ROI, injection robustness), integrates Paper-to-Context (P2C) layered context loading with token-guarding, adds vector embeddings with sqlite-vec support, implements verification runtime caching, extends repro agents with LLM and experience persistence, and enhances memory store with FTS5 full-text search, batch operations, decay ranking, and MMR reranking.

Changes

Cohort / File(s) Summary
Evaluation Framework: Retrieval Benchmarking
src/paperbot/application/services/retrieval_benchmark.py, evals/memory/test_retrieval_bench.py, evals/runners/run_retrieval_benchmark_smoke.py, scripts/eval_search.py, evals/fixtures/retrieval/bench_v2.jsonl, docs/search_eval.md
New offline retrieval evaluation suite with IR metrics (ndcg, mrr, recall), fixture-based cases, per-source/query-type aggregation, and CI smoke tests; includes benchmark library, CLI runner, and comprehensive documentation.
Evaluation Framework: Context Engine Benchmarking
src/paperbot/context_engine/benchmark.py, evals/runners/run_context_engine_benchmark_smoke.py, evals/fixtures/context/bench_v1.json, scripts/eval_context_engine.py, docs/context_engine_eval.md, tests/unit/test_context_engine_benchmark.py
New context engine evaluation with layered context validation, token-guard accuracy, router coverage/accuracy metrics, fixture-based scenario testing, and smoke runners.
Evaluation Framework: Memory Effectiveness
src/paperbot/memory/eval/effectiveness_benchmark.py, evals/memory/bench_effectiveness.py, evals/memory/test_injection_robustness.py, evals/memory/fixtures/multi_session_effectiveness.json, docs/memory_effectiveness_eval.md, tests/unit/test_memory_effectiveness_benchmark.py, tests/unit/test_injection_guard.py
New effectiveness benchmarking with heuristic and LLM-backed answer runners, injection detection guards, multi-session fixture support, and comprehensive test coverage.
Evaluation Framework: ROI Benchmarking
src/paperbot/memory/eval/roi_benchmark.py, evals/memory/bench_roi.py, evals/memory/fixtures/roi_cases.json, evals/memory/fixtures/repro_experiences.json, docs/p2c/P2C_ROI_BENCHMARK.md, docs/benchmark/MEMORYBENCH_RUNTIME_REPORT_2026-03-07.md, tests/unit/test_roi_benchmark.py, Makefile
New ROI benchmark framework for reproduction agent performance evaluation, with case loading, experience seeding, arm-based comparison, statistical significance testing, and delta reporting.
Evaluation Framework: Memory Performance
src/paperbot/memory/eval/performance_benchmark.py, scripts/benchmark_memory_performance.py, docs/memory_performance_eval.md, tests/unit/test_memory_performance_benchmark.py
New offline memory store performance baseline harness with latency percentiles, configurable dataset sizes, and seed-based seeding.
Evaluation Framework: Scope Isolation
evals/memory/test_scope_isolation.py, evals/memory/fixtures/bench_v2/bench_memories.json, evals/memory/fixtures/bench_v2/retrieval_queries_v2.json
New P0 acceptance test suite for scope isolation and CRUD lifecycle verification across users and scopes, with comprehensive fixture data.
Database Migrations
alembic/versions/0019_memory_fts5.py, alembic/versions/0020_memory_embedding.py, alembic/versions/0021_repro_code_experience.py, alembic/versions/0022_repro_experience_dedup.py
Four new Alembic migrations: FTS5 virtual table with synchronization triggers, embedding blob column and sqlite-vec integration, repro_code_experience table, and user_id/deduplication constraint.
Memory Store Core Enhancements
src/paperbot/infrastructure/stores/memory_store.py, src/paperbot/infrastructure/stores/models.py, tests/unit/test_memory_embedding.py, tests/unit/test_memory_fts5.py, tests/unit/test_memory_batch_search.py, tests/unit/test_memory_decay.py
Major memory store upgrades: embedding support with lazy initialization, hybrid vector+FTS5 search, batch multi-scope search, decay ranking with half-life, MMR reranking, and comprehensive test coverage.
Repro Experience Persistence
src/paperbot/infrastructure/stores/repro_experience_store.py, src/paperbot/repro/memory/code_memory.py, tests/unit/test_repro_code_experience.py
New experience store for persisting code generation patterns (success, verified structure, failure reasons) with user/paper/pack scoping and deduplication.
Context Engine: Layered Loading & Token-Guarding
src/paperbot/context_engine/engine.py, src/paperbot/context_engine/embeddings.py, tests/unit/test_context_layers.py, tests/unit/test_embeddings_fallback.py
Major context engine refactor with Layer0-L3 loading, Layer0 caching, token budget guarding, configurable memory search (min_score, candidate_multiplier, MMR, half-life), and fallback embedding provider chain.
P2C (Paper-to-Context) Integration
src/paperbot/application/services/p2c/context_bridge.py, src/paperbot/application/services/p2c/models.py, src/paperbot/application/services/p2c/prompts.py, src/paperbot/application/services/p2c/stages.py, src/paperbot/application/services/p2c/orchestrator.py, tests/unit/test_paper_scope_memory.py
New P2C bridge to enrich NormalizedInput with user memory and project context, updated prompts with optional contextual blocks, stage support for user/project context propagation.
P2C API & Storage
src/paperbot/api/routes/repro_context.py
Enhanced repro context route with paper-scoped memory writing and observation persistence integration.
Verification Runtime Preparation
src/paperbot/repro/verification_runtime.py, tests/unit/test_verification_runtime.py
New module for reproducible runtime preparation with virtual environment caching, requirements normalization, package mapping, deterministic hashing, and timeout-safe error reporting.
Repro Agents: Planning
src/paperbot/repro/agents/planning_agent.py, src/paperbot/repro/nodes/planning_node.py
Extended planning agents with optional LLM client, unified prompt completion flow, improved fallback behavior.
Repro Agents: Coding
src/paperbot/repro/agents/coding_agent.py, src/paperbot/repro/nodes/generation_node.py, tests/unit/test_generation_node_llm.py
Extended coding agents with LLM client and experience store integration, memory-context-aware template generation, experience pattern recording, secure code cleaning.
Repro Agents: Debugging
src/paperbot/repro/agents/debugging_agent.py
Extended debugging agent with experience store integration, failure context persistence, improved error classification, enhanced repair logic.
Repro Agents: Verification
src/paperbot/repro/agents/verification_agent.py, src/paperbot/repro/nodes/verification_node.py, tests/unit/test_verification_error_classification.py
Extended verification agents with runtime preparation caching, runtime-aware execution, experience persistence for verified structures, enhanced error/warning reporting.
Repro Orchestration
src/paperbot/repro/orchestrator.py, src/paperbot/repro/repro_agent.py
Enhanced orchestration with expanded pipeline stages, configuration for verification options, per-run user_id/pack_id tracking, LLM service and experience store propagation across agents.
Memory Evaluation Module
evals/memory/__init__.py, src/paperbot/memory/eval/__init__.py, evals/memory/README.md, src/paperbot/memory/eval/injection_guard.py, src/paperbot/memory/eval/collector.py
Expanded memory evaluation module with injection guard utilities, scope isolation metrics, and comprehensive documentation.
LLM Service & Infrastructure
src/paperbot/application/services/llm_service.py, src/paperbot/infrastructure/llm/providers/openai_provider.py, tests/unit/test_llm_service.py, tests/unit/test_openai_provider_fallback.py
Updated LLM service with model_alias-based cost tier detection, OpenAI provider with system-prompt fallback and transient retry logic with backoff.
Documentation: Design Specifications
docs/PAPER_TO_CONTEXT_MODULE_DESIGN.md, docs/P2C_MODULE_1_CORE_ENGINE.md, docs/P2C_MODULE_2_API_STORAGE.md, docs/P2C_MODULE_3_FRONTEND.md, docs/p2c/P2C_MODULE_1_CORE_ENGINE.md
Comprehensive P2C architecture documents covering module responsibilities, data models, stage workflows, API contracts, storage design, and frontend integration.
Documentation: Benchmarking & Completion
docs/benchmark/MEMORYBENCH_EPIC_283_COMPLETION.md, evals/README.md
MemoryBench completion reports and evaluation methodology documentation.
Configuration & Requirements
requirements.txt
Added sqlite-vec optional dependency for vector search support.
Frontend: Error Handling
web/src/components/research/ResearchDashboard.tsx, web/src/components/research/ResearchDiscoveryPage.tsx, web/src/components/research/ResearchPageNew.tsx
Improved error handling with friendly upstream error messages, bulk moderation actions, and consistent error message extraction.
CI/Tooling Updates
.github/workflows/ci.yml
Added smoke test runners for retrieval and context engine benchmarks, added memory isolation/robustness tests.
GenCode API
src/paperbot/api/routes/gen_code.py
Added user_id field to GenCodeRequest for user context propagation.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ReproAgent
    participant Orchestrator
    participant CodingAgent
    participant ExperienceStore
    participant MemoryStore
    participant LLMService

    User->>ReproAgent: reproduce_from_paper(paper, user_id, pack_id)
    ReproAgent->>Orchestrator: run(paper_context, user_id, pack_id)
    
    Orchestrator->>CodingAgent: execute()
    CodingAgent->>ExperienceStore: load_experiences_from_db(paper_id, user_id)
    ExperienceStore->>MemoryStore: query prior experiences
    MemoryStore-->>ExperienceStore: prior patterns
    ExperienceStore-->>CodingAgent: loaded experiences
    
    CodingAgent->>LLMService: generate code with memory context
    LLMService-->>CodingAgent: generated code
    
    CodingAgent->>ExperienceStore: record_success_pattern(code_snippet)
    ExperienceStore->>MemoryStore: persist pattern
    
    CodingAgent-->>Orchestrator: AgentResult
    Orchestrator-->>ReproAgent: pipeline result
    ReproAgent-->>User: final code + metadata
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Fix/studio output dir validation p2c design #148: Both add and modify the Paper-to-Context (P2C) codebase (models, orchestrator, prompts, stages, repro_context routes) with directly overlapping code changes.
  • Feat/datainfra refactor tracker #76: Both modify src/paperbot/context_engine/engine.py core implementation, with the main PR adding layered loading/token-guarding while the related PR adds judge/feedback attachments.
  • Feat/datainfra refactor tracker #100: Both modify ContextEngine initialization and behavior—main PR adds layered loading/caching while related PR removes paper_searcher parameter and related logic.

Suggested reviewers

  • ThankUYou

Poem

🐰 Whiskers twitch with joy so bright,
Memories now search day and night,
Vector threads and FTS dance,
Context flows in grand expanse,
Budgets guard each precious token,
Code speaks true—a promise spoken!

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly advances the project's memory and code reproduction capabilities by introducing a robust evaluation suite and enhancing the underlying memory storage and retrieval mechanisms. It focuses on improving the reliability, safety, and efficiency of LLM-driven code generation through structured benchmarking, persistent learning from past experiences, and resilient API interactions. The changes lay a strong foundation for more intelligent and autonomous research workflows.

Highlights

  • MemoryBench Evaluation Suite: Implemented a comprehensive 4-suite MemoryBench evaluation aligned with leading benchmarks like LongMemEval, LoCoMo, Mem0, and Letta. This includes Retrieval Bench v2, Scope Isolation + CRUD lifecycle verification, Context Extraction bench, and Injection Robustness L1.
  • Enhanced Memory Storage and Retrieval: Integrated FTS5 full-text search and sqlite-vec for vector embeddings into the memory store, enabling hybrid search capabilities with decay-aware ranking and MMR re-ranking. Alembic migrations were added to support these new database features.
  • CodeMemory Persistence: Introduced a new repro_code_experience table and store to persist code generation experiences, such as success patterns and failure reasons, allowing the CodeMemory to pre-load prior knowledge for improved reproduction runs.
  • Robust LLM Interaction: Implemented retry logic for transient LLM API errors and a fallback mechanism for providers that reject system role messages, enhancing the reliability of LLM-powered operations.
  • Isolated Verification Runtimes: Added functionality to prepare isolated Python virtual environments for code verification, ensuring consistent and reproducible testing of generated code, with caching for efficiency.
  • Updated Project Branding and Documentation: The project title in the README was updated, along with various badges and documentation links, reflecting the ongoing development and new benchmark reports.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • Makefile
    • Added a new bench-roi target for running the ROI benchmark.
  • README.md
    • Updated project title and various badges.
    • Added 'MemoryBench Suite' to features list.
    • Included comments for python3 usage in install/API server instructions.
    • Updated 'Active Epics' table to include MemoryBench.
    • Added new documentation links for various benchmarks.
  • alembic/versions/0019_memory_fts5.py
    • Added Alembic migration for FTS5 full-text index on memory_items table.
  • alembic/versions/0020_memory_embedding.py
    • Added Alembic migration for embedding column and sqlite-vec virtual table on memory_items table.
  • alembic/versions/0021_repro_code_experience.py
    • Added Alembic migration to create repro_code_experience table.
  • alembic/versions/0022_repro_experience_dedup.py
    • Added Alembic migration to add user_id column and unique constraint to repro_code_experience table.
  • docs/P2C_MODULE_1_CORE_ENGINE.md
    • Added a detailed design document for P2C Module 1: Core Engine.
    • Updated NormalizedInput dataclass to use Optional[str] for user and project context.
  • docs/P2C_MODULE_2_API_STORAGE.md
    • Added a detailed design document for P2C Module 2: API & Storage.
  • docs/P2C_MODULE_3_FRONTEND.md
    • Added a detailed design document for P2C Module 3: Frontend Integration.
  • docs/PAPER_TO_CONTEXT_MODULE_DESIGN.md
    • Added a high-level design document for the Paper-to-Context (P2C) module.
  • docs/benchmark/MEMORYBENCH_EPIC_283_COMPLETION.md
  • docs/benchmark/MEMORYBENCH_RUNTIME_REPORT_2026-03-07.md
    • Added a runtime report for MemoryBench, including ROI and performance baselines.
  • docs/context_engine_eval.md
    • Added documentation for Context Engine Evaluation.
  • docs/memory_effectiveness_eval.md
    • Added documentation for Memory Effectiveness Evaluation.
  • docs/memory_performance_eval.md
    • Added documentation for Memory Performance Evaluation.
  • docs/p2c/P2C_ROI_BENCHMARK.md
    • Added documentation for P2C ROI Benchmark.
  • docs/search_eval.md
    • Added documentation for Search Evaluation.
  • evals/README.md
    • Updated README to include retrieval quality regression coverage.
  • evals/fixtures/context/bench_v1.json
    • Added JSON fixture for context engine benchmark cases.
  • evals/fixtures/retrieval/bench_v2.jsonl
    • Added JSONL fixture for retrieval benchmark queries.
  • evals/memory/README.md
    • Added comprehensive README for MemoryBench.
  • evals/memory/init.py
    • Updated __init__.py to export new memory evaluation modules.
  • evals/memory/bench_effectiveness.py
    • Added Python script for multi-session memory effectiveness benchmark.
  • evals/memory/bench_roi.py
    • Added Python script for ROI benchmark.
  • evals/memory/fixtures/bench_v2/bench_memories.json
    • Added JSON fixture for MemoryBench v2 memory data.
  • evals/memory/fixtures/bench_v2/retrieval_queries_v2.json
    • Added JSON fixture for MemoryBench v2 retrieval queries.
  • evals/memory/fixtures/injection_patterns.json
    • Added JSON fixture for prompt injection patterns.
  • evals/memory/fixtures/multi_session_effectiveness.json
    • Added JSON fixture for multi-session memory effectiveness benchmark.
  • evals/memory/fixtures/repro_experiences.json
    • Added JSON fixture for reproduction experience seeds.
  • evals/memory/fixtures/roi_cases.json
    • Added JSON fixture for ROI benchmark cases.
  • evals/memory/test_context_extraction.py
    • Added Pytest script for context extraction evaluation.
  • evals/memory/test_injection_robustness.py
    • Added Pytest script for injection robustness evaluation.
  • evals/memory/test_retrieval_bench.py
    • Added Pytest script for retrieval benchmark v2.
  • evals/memory/test_scope_isolation.py
    • Added Pytest script for scope isolation and CRUD lifecycle evaluation.
  • evals/runners/run_context_engine_benchmark_smoke.py
    • Added Python script for context engine benchmark smoke test.
  • evals/runners/run_retrieval_benchmark_smoke.py
    • Added Python script for retrieval benchmark smoke test.
  • requirements.txt
    • Added sqlite-vec as an optional dependency.
  • scripts/benchmark_memory_performance.py
    • Added Python script for offline memory performance benchmark.
  • scripts/eval_context_engine.py
    • Added Python script for offline context-engine benchmark.
  • scripts/eval_search.py
    • Added Python script for offline retrieval benchmark.
  • src/paperbot/api/routes/gen_code.py
    • Added user_id to GenCodeRequest and passed it to reproduce_from_paper.
  • src/paperbot/api/routes/repro_context.py
    • Added _MAX_OBSERVATION_NARRATIVE constant and _write_paper_scope_memories function to persist P2C observations.
  • src/paperbot/application/services/llm_service.py
    • Updated _estimate_cost_usd to handle OpenRouter-prefixed OpenAI models.
  • src/paperbot/application/services/p2c/context_bridge.py
    • Added ContextEngineBridge module to enrich NormalizedInput with user memory and project context.
  • src/paperbot/application/services/p2c/models.py
    • Added user_memory and project_context fields to NormalizedInput.
  • src/paperbot/application/services/p2c/orchestrator.py
    • Integrated ContextEngineBridge and updated run method to pass user and pack IDs.
  • src/paperbot/application/services/p2c/prompts.py
    • Modified literature_distill_prompt and roadmap_planning_prompt to include user/project context with sanitization.
  • src/paperbot/application/services/p2c/stages.py
    • Added user_memory and project_context to StageInput and updated LLM calls.
  • src/paperbot/application/services/retrieval_benchmark.py
    • Added new module for retrieval benchmarking.
  • src/paperbot/context_engine/benchmark.py
    • Added new module for context engine benchmarking.
  • src/paperbot/context_engine/embeddings.py
    • Implemented HashEmbeddingProvider and updated try_build_default_embedding_provider for configurable provider chain.
  • src/paperbot/context_engine/engine.py
    • Refactored build_context_pack into layered loading functions, added Layer 0 caching, and implemented a token budget guard.
  • src/paperbot/infrastructure/llm/providers/openai_provider.py
    • Implemented retry logic for transient errors and system role fallback.
  • src/paperbot/infrastructure/stores/memory_store.py
    • Added embedding column, FTS5 and sqlite-vec integration for hybrid search, decay-aware ranking, and MMR re-ranking.
  • src/paperbot/infrastructure/stores/models.py
    • Added embedding column to MemoryItemModel and defined ReproCodeExperienceModel.
  • src/paperbot/infrastructure/stores/repro_experience_store.py
    • Added new SQLAlchemy store for ReproCodeExperienceModel.
  • src/paperbot/memory/eval/init.py
    • Updated __init__.py to export new memory evaluation modules.
  • src/paperbot/memory/eval/collector.py
    • Added cross_user_leak_rate and cross_scope_leak_rate metrics to MemoryMetricCollector.
  • src/paperbot/memory/eval/effectiveness_benchmark.py
    • Added new module for multi-session memory effectiveness benchmarking.
  • src/paperbot/memory/eval/injection_guard.py
    • Added new module for offline prompt injection pattern detection.
  • src/paperbot/memory/eval/performance_benchmark.py
    • Added new module for offline memory performance benchmarking.
  • src/paperbot/memory/eval/roi_benchmark.py
    • Added new module for ROI benchmarking.
  • src/paperbot/repro/agents/coding_agent.py
    • Updated CodingAgent to accept experience_store and llm_client, and to load prior experiences.
  • src/paperbot/repro/agents/debugging_agent.py
    • Updated DebuggingAgent to accept experience_store and llm_client, and to persist failure reasons.
  • src/paperbot/repro/agents/planning_agent.py
    • Updated PlanningAgent to accept llm_client and use it for prompt completion.
  • src/paperbot/repro/agents/verification_agent.py
    • Updated VerificationAgent to include runtime preparation, use a specified Python executable, and persist verified structures.
  • src/paperbot/repro/memory/code_memory.py
    • Added experience_store and _prior_experiences to CodeMemory, and implemented methods to load and record experiences.
  • src/paperbot/repro/nodes/generation_node.py
    • Updated GenerationNode to accept llm_client and experience_store, and to use prior experiences in prompt generation.
  • src/paperbot/repro/nodes/planning_node.py
    • Updated PlanningNode to use llm_client for prompt completion.
  • src/paperbot/repro/nodes/verification_node.py
    • Updated VerificationNode to include runtime preparation, use a specified Python executable, and persist verified structures.
  • src/paperbot/repro/orchestrator.py
    • Updated Orchestrator to accept experience_store and llm_client, and to pass verification runtime configuration.
  • src/paperbot/repro/repro_agent.py
    • Updated ReproAgent to initialize ReproExperienceStore and LLMService, and to pass these to orchestrator and nodes.
  • src/paperbot/repro/verification_runtime.py
    • Added new module for preparing isolated Python virtual environments for code verification.
  • tests/unit/test_context_engine_benchmark.py
    • Added unit tests for the context engine benchmark.
  • tests/unit/test_context_layers.py
    • Added unit tests for context layered loading and caching.
  • tests/unit/test_embeddings_fallback.py
    • Added unit tests for embedding provider fallback mechanisms.
  • tests/unit/test_generation_node_llm.py
    • Added unit tests for GenerationNode's LLM interaction and main template.
  • tests/unit/test_injection_guard.py
    • Added unit tests for prompt injection pattern detection.
  • tests/unit/test_llm_service.py
    • Added tests for LLM cost estimation with OpenRouter-prefixed models.
  • tests/unit/test_memory_batch_search.py
    • Added unit tests for cross-track batch search in memory store.
  • tests/unit/test_memory_decay.py
    • Added unit tests for memory decay mechanism and MMR re-ranking.
  • tests/unit/test_memory_effectiveness_benchmark.py
    • Added unit tests for multi-session memory effectiveness benchmark.
  • tests/unit/test_memory_fts5.py
    • Added unit tests for FTS5 full-text search in memory retrieval.
  • tests/unit/test_memory_performance_benchmark.py
    • Added unit tests for memory performance benchmark.
  • tests/unit/test_openai_provider_fallback.py
    • Added unit tests for OpenAI provider's retry and system role fallback logic.
  • tests/unit/test_paper_scope_memory.py
    • Added unit tests for paper-scope memory read/write.
  • tests/unit/test_repro_code_experience.py
    • Added unit tests for ReproCodeExperienceStore and CodeMemory persistence.
  • tests/unit/test_retrieval_benchmark.py
    • Added unit tests for retrieval benchmark.
  • tests/unit/test_roi_benchmark.py
    • Added unit tests for ROI benchmark.
  • tests/unit/test_verification_error_classification.py
    • Added unit tests for error classification in debugging and verification agents.
  • web/src/components/research/ResearchDashboard.tsx
    • Added friendly error message handling for API calls.
  • web/src/components/research/ResearchDiscoveryPage.tsx
    • Added friendly error message handling for API calls.
  • web/src/components/research/ResearchPageNew.tsx
    • Added friendly error message handling for API calls.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/ci.yml
Activity
  • All 4 MemoryBench suites passed together in 5.85s (fully offline).
  • Existing unit tests were unaffected (19 passed).
  • The pull request description was generated with Claude Code.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@jerry609
jerry609 merged commit 9a22367 into master Mar 7, 2026
11 of 12 checks passed

@gemini-code-assist gemini-code-assist 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.

Code Review

This is an impressive and substantial pull request that introduces a comprehensive MemoryBench evaluation suite and significantly enhances the memory system's capabilities. The addition of FTS5 and vector search with hybrid ranking, decay scoring, and MMR is a major step forward. The implementation of isolated verification runtimes, persistence for code generation experiences, and more resilient LLM provider logic are all high-quality contributions that improve the robustness and intelligence of the system. The new documentation and tests are thorough and well-written. I have one medium-severity comment regarding a potential issue with database downgrades on SQLite.

Note: Security Review did not run due to the size of the PR.

type_="unique",
)
op.drop_index("ix_repro_code_experience_user_id", table_name="repro_code_experience")
op.drop_column("repro_code_experience", "user_id")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The op.drop_column operation is not supported by SQLite's ALTER TABLE implementation. This will cause the downgrade to fail on SQLite environments. A previous migration (0020_memory_embedding.py) correctly noted this limitation. To ensure the downgrade path is safe for all supported dialects, you could either add a comment here acknowledging that this downgrade is not supported on SQLite, or implement the 'move-and-copy' table recreation workflow for SQLite if full downgrade compatibility is required.

Copilot AI 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.

Pull request overview

This PR implements the MemoryBench evaluation suite (Epic #283) for PaperBot, introducing comprehensive offline benchmarking across retrieval quality, context extraction, scope isolation, injection robustness, and performance. It also includes significant supporting infrastructure: CodeMemory persistence via a new ReproExperienceStore, FTS5 + vector embedding search for the memory store, configurable verification runtime isolation, LLM provider retry/fallback logic, and improved error handling in the frontend.

Changes:

  • New MemoryBench evaluation suite: 4 eval suites (test_retrieval_bench, test_scope_isolation, test_context_extraction, test_injection_robustness) plus ROI and effectiveness benchmarks, all offline
  • Infrastructure: ReproExperienceStore for CodeMemory persistence, FTS5 + sqlite-vec hybrid search, HashEmbeddingProvider fallback, VerificationAgent runtime isolation with pip caching, LLM provider retry logic for system-role rejection and transient errors, and ContextEngineBridge for user-memory injection into P2C pipeline
  • Frontend: Improved error message extraction (e instanceof Error ? e.message : String(e)) and user-friendly upstream error messages, with duplicated helper functions across 3 components

Reviewed changes

Copilot reviewed 97 out of 98 changed files in this pull request and generated 20 comments.

Show a summary per file
File Description
web/src/components/research/ResearchPageNew.tsx Adds friendly upstream error parsing, improves error message extraction
web/src/components/research/ResearchDiscoveryPage.tsx Same error handling improvements (duplicate logic)
web/src/components/research/ResearchDashboard.tsx Same error handling improvements (duplicate logic)
src/paperbot/repro/nodes/planning_node.py Refactors _execute to use new _complete_prompt helper supporting both llm_client and legacy query fallbacks
src/paperbot/repro/memory/code_memory.py Adds ReproExperienceStore persistence methods and prior-experience context injection
src/paperbot/infrastructure/stores/repro_experience_store.py New CRUD store for code generation experience persistence
src/paperbot/infrastructure/stores/models.py Adds ReproCodeExperienceModel, embedding column to MemoryItemModel
src/paperbot/repro/agents/verification_agent.py Adds configurable Python executable, requirements preparation, and runtime caching
src/paperbot/repro/orchestrator.py Threads experience_store, llm_client, user_id, pack_id, and verification config through the pipeline
src/paperbot/infrastructure/llm/providers/openai_provider.py Adds system-role fallback, transient retry logic, time import
src/paperbot/application/services/llm_service.py Fixes cost estimation to handle provider-prefixed model names (e.g., openrouter/openai/gpt-4o-mini)
src/paperbot/application/services/p2c/stages.py Passes user_memory/project_context to LLM prompts, narrows exception types
src/paperbot/application/services/p2c/prompts.py Adds _sanitize_tag_content, injects user_memory and project_context blocks
src/paperbot/application/services/p2c/context_bridge.py New: enriches NormalizedInput with user memory/project context from ContextEngine
src/paperbot/application/services/p2c/orchestrator.py Integrates ContextEngineBridge into P2C orchestration
src/paperbot/application/services/p2c/models.py Adds user_memory and project_context fields to NormalizedInput
src/paperbot/memory/eval/injection_guard.py New: offline prompt-injection pattern detection with Unicode normalization
src/paperbot/memory/eval/performance_benchmark.py New: multi-scale memory search latency benchmark
src/paperbot/memory/eval/collector.py Adds record_scope_isolation and cross_user/scope_leak_rate metrics
src/paperbot/memory/eval/__init__.py Expands public API for all new benchmark modules
src/paperbot/context_engine/embeddings.py Adds HashEmbeddingProvider and configurable provider chain
src/paperbot/api/routes/repro_context.py Writes P2C observations as paper-scoped memory items
src/paperbot/api/routes/gen_code.py Passes user_id to code generation pipeline
alembic/versions/0019_memory_fts5.py New migration: FTS5 virtual table and sync triggers
alembic/versions/0020_memory_embedding.py New migration: embedding BLOB column and sqlite-vec virtual table
alembic/versions/0021_repro_code_experience.py New migration: repro_code_experience table
alembic/versions/0022_repro_experience_dedup.py New migration: user_id column and dedup unique constraint
tests/unit/test_*.py (multiple) Comprehensive unit tests for new infrastructure and benchmarks
evals/memory/test_injection_robustness.py Injection robustness eval test
evals/, scripts/, docs/ (multiple) Eval runners, CLI scripts, and documentation
README.md Title changed to informal phrase (unintentional), doc table updated
requirements.txt Adds sqlite-vec>=0.1.6
Makefile New bench-roi target

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +318 to 321
const message = e instanceof Error ? e.message : String(e)
if (message.startsWith("409")) {
setCreateError(`Track "${name}" already exists.`)
} else {

Copilot AI Mar 7, 2026

Copy link

Choose a reason for hiding this comment

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

The message.startsWith("409") checks on lines 319 and 365 were designed for the old String(e) pattern where the error message starts with the HTTP status code (e.g., "409 Conflict ..."). After the refactor to e instanceof Error ? e.message : String(e), the error message is now set from toFriendlyErrorMessage (which returns a user-facing string that will NOT start with "409") or falls back to the raw status-prefixed message. If a 409 response provides a friendly error via the detail field (which toFriendlyErrorMessage would return), the resulting message would NOT start with "409", causing the track-already-exists duplicate detection to silently fall through to setError(message) instead of showing the specific setCreateError/setEditError duplicate message. The logic for detecting 409 conflicts needs to be updated to work with the new error handling approach.

Copilot uses AI. Check for mistakes.
Comment on lines +409 to 416
if "gpt-4o-mini" in model_alias:
in_price, out_price = 0.15, 0.60
elif provider == "openai" and "gpt-4o" in model:
elif "gpt-4o" in model_alias:
in_price, out_price = 2.50, 10.00
elif provider == "anthropic" and "claude-3-5-sonnet" in model:
elif "claude-3-5-sonnet" in model_alias:
in_price, out_price = 3.00, 15.00
elif provider == "deepseek":
elif "deepseek" in model_alias or provider == "deepseek":
in_price, out_price = 0.55, 2.19

Copilot AI Mar 7, 2026

Copy link

Choose a reason for hiding this comment

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

The _estimate_cost_usd function now uses model_alias (which strips the provider prefix, e.g. "openai/gpt-4o-mini""gpt-4o-mini") to match pricing rules for GPT-4o, GPT-4o-mini, and Claude. However, the gpt-4o-mini check (line 409) comes before the gpt-4o check (line 411), so a model string like "gpt-4o-mini" or "openai/gpt-4o-mini" will correctly match the first branch. But a model like "gpt-4o" would also partially match "gpt-4o-mini" if the model name were e.g. "gpt-4o-mini-2024". This was already an issue in the previous code and is not introduced by this PR. More importantly, the removal of provider == "anthropic" guard for claude-3-5-sonnet on line 413 could lead to over-broad matching — any provider that returns a model containing "claude-3-5-sonnet" will now apply Anthropic pricing. This is probably intentional (similar to the OpenRouter prefix-stripping pattern), but it means cost estimates for Claude models routed through OpenRouter will now be costed instead of falling through to 0.0. This is actually a bug fix / intentional change consistent with the gpt-4o-mini fix, so this note is informational.

Copilot uses AI. Check for mistakes.
Comment on lines +17 to +45
type UpstreamErrorBody = {
detail?: string
error?: string
}

function toFriendlyErrorMessage(status: number, rawText: string): string | null {
if (!rawText) return null

let parsed: UpstreamErrorBody | null = null
try {
parsed = JSON.parse(rawText) as UpstreamErrorBody
} catch {
parsed = null
}

const detail = parsed && typeof parsed.detail === "string" ? parsed.detail : undefined

if (detail && (detail.includes("Upstream API unreachable") || detail.includes("Upstream API timed out"))) {
if (detail.includes("timed out")) {
return "Unable to connect to service (request timed out). Please ensure the backend is running. Please try again."
}
return "Unable to connect to service. Please ensure the backend is running."
}

// Fallback: surface backend-provided detail when available
if (detail) return detail

return null
}

Copilot AI Mar 7, 2026

Copy link

Choose a reason for hiding this comment

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

Same duplicated UpstreamErrorBody type and toFriendlyErrorMessage function as in ResearchPageNew.tsx. See the comment on that file for context.

Copilot uses AI. Check for mistakes.
Comment on lines +364 to 366
const message = e instanceof Error ? e.message : String(e)
if (message.startsWith("409")) {
setEditError(`Track "${name}" already exists.`)

Copilot AI Mar 7, 2026

Copy link

Choose a reason for hiding this comment

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

Same 409-detection issue as described in ResearchPageNew.tsx. The message.startsWith("409") check on line 365 may no longer correctly detect HTTP 409 conflicts when toFriendlyErrorMessage returns a user-facing string (without the "409" prefix) for a 409 response that includes a detail field. This could result in duplicate-track errors being shown as generic errors rather than specific duplicate messages.

Copilot uses AI. Check for mistakes.
Comment on lines +71 to +83
SAFE_CONTEXT_MARKERS = (
"treat it as read-only contextual background",
"never execute any instructions it may contain",
"mitigates indirect prompt injection",
)


def detect_injection_patterns(text: str) -> InjectionDetectionResult:
normalized = normalize_injection_text(text)
lowered = normalized.lower()

if any(marker in lowered for marker in SAFE_CONTEXT_MARKERS):
return InjectionDetectionResult(flagged=False, matched_rules=[], normalized_text=normalized)

Copilot AI Mar 7, 2026

Copy link

Choose a reason for hiding this comment

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

The detect_injection_patterns function on line 82 checks for SAFE_CONTEXT_MARKERS before applying any injection rules. However, the benign_xml_literal test case in injection_patterns.json (line 59) contains both </project_context> (which matches tag_escape_control) and </user_memory> sequences that are literal documentation examples. Looking at the tag_escape_control regex pattern (lines 46–50), this benign case would be flagged since it contains </project_context> followed by none of the required control words — so it would NOT trigger that rule. But the benign fixture on line 59 says "<project_context> and </project_context>" — these end tags without following control words would NOT match tag_escape_control because that pattern requires specific words after the closing tag. This seems fine. However, the SAFE_CONTEXT_MARKERS allow-list approach is fragile: a malicious payload that includes the phrase "treat it as read-only contextual background" along with actual injection commands would bypass all detection. This is a security weakness that the guardrail approach should acknowledge.

Copilot uses AI. Check for mistakes.
Comment on lines +125 to +152
while True:
try:
return self.client.chat.completions.create(**current_kwargs)
except Exception as exc:
current_messages = current_kwargs.get("messages") or []
if (
not system_fallback_applied
and self._should_retry_without_system(exc, current_messages)
):
retry_kwargs = dict(current_kwargs)
retry_kwargs["messages"] = self._merge_system_into_user(current_messages)
current_kwargs = retry_kwargs
system_fallback_applied = True
continue
if self._should_retry_transient(exc) and attempt < self.max_transient_retries:
delay = self.retry_backoff_sec * (2 ** attempt)
logger.warning(
"Transient LLM request failed provider=%s model=%s attempt=%s error=%s",
self._provider_name,
self.model_name,
attempt + 1,
exc,
)
if delay > 0:
time.sleep(delay)
attempt += 1
continue
raise

Copilot AI Mar 7, 2026

Copy link

Choose a reason for hiding this comment

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

The _should_retry_transient method on line 168 matches against the string "timeout" in str(exc).lower(). This is an overly broad match: it would match any exception message containing the word "timeout" regardless of context (e.g., "connection timeout" in an unrelated exception). Additionally, the _create_completion_with_fallback loop on line 139 checks _should_retry_transient and increments attempt only after that check, but system_fallback_applied is checked first with a continue that does NOT increment attempt. This means the transient retry counter (attempt) is unaffected by the system fallback path, which is correct. However, since system_fallback_applied is checked first and can cause a continue that bypasses the transient check, a request that needs both a system fallback AND hits a transient error after the fallback would only get max_transient_retries attempts, which is the expected behavior.

More critically: if _should_retry_without_system returns True and _should_retry_transient also returns True for the same exception, only the system fallback is applied (because the system check comes first with continue). This could cause a missed transient retry for an error that is both a system rejection AND a transient error (unlikely but possible).

Copilot uses AI. Check for mistakes.
Comment on lines +258 to 273
def stream_invoke(self, messages: List[Dict[str, str]], **kwargs) -> Generator[str, None, None]:
"""流式调用"""
extra_params = {
k: v for k, v in kwargs.items()
if k in self.ALLOWED_PARAMS and v is not None
k: v for k, v in kwargs.items() if k in self.ALLOWED_PARAMS and v is not None
}
extra_params["stream"] = True

timeout = extra_params.pop("timeout", self.timeout)

try:
stream = self.client.chat.completions.create(
model=self.model_name,
stream = self._create_completion_with_fallback(
messages=messages,
timeout=timeout,
**extra_params,
extra_params=extra_params,
stream=True,
)

Copilot AI Mar 7, 2026

Copy link

Choose a reason for hiding this comment

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

The stream_invoke method on line 258 passes extra_params to _create_completion_with_fallback, but extra_params was already modified to include "stream": True on line 263. However, the _create_completion_with_fallback method also receives stream=True as a separate kwarg on line 272 and uses it to conditionally set request_kwargs["stream"] = True (line 119). This means stream=True appears twice in the kwargs dict built in _create_completion_with_fallback — once from extra_params (since stream is not in ALLOWED_PARAMS, it would have been filtered out) — wait, stream is not in ALLOWED_PARAMS, so it will NOT be included in extra_params. But it IS explicitly set to extra_params["stream"] = True on line 263 before timeout is popped. This means stream=True WILL be in extra_params when passed to _create_completion_with_fallback, AND _create_completion_with_fallback also adds stream=True from its stream parameter on line 119. This results in stream=True being set twice in request_kwargs, which while not harmful (the second set just overwrites the first), is unexpected and could be confusing. The stream key in extra_params should be removed before calling _create_completion_with_fallback, or stream should not be added to extra_params in stream_invoke.

Copilot uses AI. Check for mistakes.
Comment on lines +93 to +121
type UpstreamErrorBody = {
detail?: string
error?: string
}

function toFriendlyErrorMessage(status: number, rawText: string): string | null {
if (!rawText) return null

let parsed: UpstreamErrorBody | null = null
try {
parsed = JSON.parse(rawText) as UpstreamErrorBody
} catch {
parsed = null
}

const detail = parsed && typeof parsed.detail === "string" ? parsed.detail : undefined

if (detail && (detail.includes("Upstream API unreachable") || detail.includes("Upstream API timed out"))) {
if (detail.includes("timed out")) {
return "Unable to connect to service (request timed out). Please ensure the backend is running. Please try again."
}
return "Unable to connect to service. Please ensure the backend is running."
}

// Fallback: surface backend-provided detail when available
if (detail) return detail

return null
}

Copilot AI Mar 7, 2026

Copy link

Choose a reason for hiding this comment

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

Same duplicated UpstreamErrorBody type and toFriendlyErrorMessage function as in ResearchPageNew.tsx. See the comment on that file for context.

Copilot uses AI. Check for mistakes.
Comment thread README.md
| [`docs/PAPERSCOOL_WORKFLOW.md`](docs/PAPERSCOOL_WORKFLOW.md) | Topic Workflow guide |
| [`docs/p2c/`](docs/p2c/) | Paper2Context design docs |
| [`docs/benchmark/MEMORYBENCH_EPIC_283_COMPLETION.md`](docs/benchmark/MEMORYBENCH_EPIC_283_COMPLETION.md) | MemoryBench Epic completion report |
| [`docs/benchmark/MEMORYBENCH_RUNTIME_REPORT_2026-03-07.md`](docs/benchmark/MEMORYBENCH_RUNTIME_REPORT_2026-03-07.md) | Live ROI + 1M memory runtime report |

Copilot AI Mar 7, 2026

Copy link

Choose a reason for hiding this comment

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

The MEMORYBENCH_EPIC_283_COMPLETION.md completion report links to docs/benchmark/MEMORYBENCH_RUNTIME_REPORT_2026-03-07.md in the README (line 240), but this file does not appear to be included in the PR diff. The README references a non-existent documentation file, which would result in a broken link.

Copilot uses AI. Check for mistakes.
Comment on lines +60 to +65
if existing is not None:
if pack_id and not existing.pack_id:
existing.pack_id = pack_id
session.commit()
session.refresh(existing)
return existing

Copilot AI Mar 7, 2026

Copy link

Choose a reason for hiding this comment

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

In repro_experience_store.py, the deduplication logic on line 61 only updates an existing record's pack_id if pack_id is provided AND the existing record has no pack_id. However, this means if a record already has a pack_id and a new call is made with a different pack_id, the existing pack_id will NOT be updated (the condition not existing.pack_id prevents it). This could lead to stale pack_id associations if the same experience is referenced from a new pack. The behavior is intentional per the docstring (dedup by user_id + paper_id + pattern_type + content), but it may cause unexpected behavior in the ROI benchmark where the same experience seed is loaded multiple times with different pack contexts.

Copilot uses AI. Check for mistakes.
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.

5 participants