Skip to content

feat: disk cache for profile/config LLM generation (closes #20)#32

Merged
PRATHAMESH75 merged 2 commits into
mainfrom
feat/20-llm-response-cache
Jun 21, 2026
Merged

feat: disk cache for profile/config LLM generation (closes #20)#32
PRATHAMESH75 merged 2 commits into
mainfrom
feat/20-llm-response-cache

Conversation

@PRATHAMESH75

Copy link
Copy Markdown
Owner

Summary

Closes #20. Adds a content-addressed disk cache so re-running a campaign on the same entities skips redundant, expensive profile/config generation calls.

Stacked on #31 (feat/15-per-task-model-fallback), which is stacked on #30. Merge order: #30#31#20. Bases auto-retarget as each merges.

Changes

  • app/utils/llm_cache.pyLLMResponseCache: namespaced, keyed by SHA-256 of the request material (model + system + prompt), one JSON file per entry under <cache_dir>/<namespace>/. Best-effort I/O (any error → cache miss), optional TTL, enable flag, atomic writes via os.replace.
  • config.pyLLM_CACHE_ENABLED (default on), LLM_CACHE_DIR (default backend/uploads/llm_cache), LLM_CACHE_TTL (0 = no expiry).
  • Wiring — checks the cache before the LLM call and stores on success in oasis_profile_generator._generate_profile_with_llm and simulation_config_generator._call_llm_with_retry. Only genuine LLM results are cached (never rule-based fallbacks); keying on model+prompt means prompt/model changes invalidate naturally.
  • .env.example — documented the new vars.

Testing

  • New tests/test_llm_cache.py (9 tests): set/get round-trip, distinct-material isolation, order-independent keys, disabled no-op, TTL=0 never-expires, TTL expiry, namespace isolation, corrupt-entry-as-miss, hash stability.
  • Full backend suite: 49 passed.

Notes

  • Caching is on by default per the issue's intent. Disable with LLM_CACHE_ENABLED=false.

🤖 Generated with Claude Code

Re-running a campaign on the same entities re-issues identical, expensive
profile- and config-generation LLM calls. Add a content-addressed disk cache so
identical requests skip the model.

- app/utils/llm_cache.py: LLMResponseCache — namespaced, keyed by a SHA-256 of
  the request material (model + system + prompt), one JSON file per entry under
  <cache_dir>/<namespace>/. Best-effort I/O (any error degrades to a miss),
  optional TTL, and an enable flag.
- Config: LLM_CACHE_ENABLED (default on), LLM_CACHE_DIR, LLM_CACHE_TTL.
- Wired into the two generation choke points: oasis _generate_profile_with_llm
  and simulation_config _call_llm_with_retry check the cache before calling and
  store on success (genuine LLM results only — never rule-based fallbacks).
  Keying on model+prompt means a prompt or model change invalidates naturally.
- Documented env vars in .env.example.
- tests/test_llm_cache.py: hit/miss, order-independent keys, disabled no-op,
  TTL expiry, namespace isolation, corrupt-entry-as-miss.

Stacked on the #15 branch (shared config.py + generator changes).

Co-Authored-By: PRATHAMESH75 <prathamesh290504@gmail.com>
@PRATHAMESH75 PRATHAMESH75 changed the base branch from feat/15-per-task-model-fallback to main June 21, 2026 03:43
@PRATHAMESH75 PRATHAMESH75 merged commit e357195 into main Jun 21, 2026
2 checks passed
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.

LLM response caching for profile/config generation

1 participant