"""Pre-warm epicure_cache.json so demos never wait on the rate-limited server. Walks the calls the planner makes for a few example dishes and caches every result. Patient by design: it loops, skips already-cached calls, and backs off hard on rate limits, so it eventually fills the cache no matter how stingy the server is on a given day. Safe to re-run — it only fetches what's missing. python prewarm_cache.py """ import time from agent import dish_core, parse_pantry from epicure_client import EpicureMCP # (dish, pantry) pairs the live demo should be able to plan instantly. EXAMPLES = [ ("red lentil dal", "red lentil, cumin, coriander seed, turmeric, garlic, onion, ginger, " "tomato, lemon, yogurt, cinnamon"), ("chickpea curry", "chickpea, cumin, garlic, onion, ginger, tomato, coconut milk, " "cilantro, lemon, turmeric, garam masala"), ("pour-over coffee", "coffee, cardamom, cinnamon, milk, sugar, vanilla, orange, nutmeg"), ] HALLMARK = {"lentil": "tamarind", "chickpea": "tahini", "coffee": "cardamom"} def build_tasks(): tasks = [] # (tool, arguments) for dish, pantry in EXAMPLES: core = dish_core(dish)[0] for item in parse_pantry(pantry)[:10]: if item != core: tasks.append(("pairing_score", {"ingredient_a": core, "ingredient_b": item})) if core in HALLMARK: tasks.append(("neighbors", {"ingredient": HALLMARK[core], "top_k": 12})) return tasks def main(): mcp = EpicureMCP() tasks = build_tasks() print(f"{len(tasks)} calls to warm.") for rnd in range(8): remaining = [] for tool, args in tasks: key = tool + ":" + __import__("json").dumps(args, sort_keys=True) if key in mcp._cache: continue try: mcp.call_tool(tool, args) print(f" cached {tool} {list(args.values())[:2]}") time.sleep(1.0) except Exception as exc: print(f" defer {tool} {list(args.values())[:2]} ({type(exc).__name__})") remaining.append((tool, args)) time.sleep(5.0) warm = sum(1 for t, a in tasks if (t + ":" + __import__("json").dumps(a, sort_keys=True)) in mcp._cache) print(f"round {rnd}: {warm}/{len(tasks)} warm") if not remaining: break tasks = remaining time.sleep(15.0) # let the rate-limit window reset between rounds print(f"done — {len(mcp._cache)} cache entries at {mcp._cache_path}") if __name__ == "__main__": main()