import json def _match_entry(entry: dict, text: str) -> bool: keys = entry.get("keys", []) if isinstance(keys, str): keys = [k.strip() for k in keys.split(",") if k.strip()] text_lower = text.lower() for key in keys: if key and key.lower() in text_lower: return True secondary = entry.get("secondary_keys", []) or entry.get("keysecondary", []) if isinstance(secondary, str): secondary = [k.strip() for k in secondary.split(",") if k.strip()] for key in secondary: if key and key.lower() in text_lower: return True return False def get_lorebook_context(lorebook_json: str, context: str | list, max_entries: int = 5) -> str: """Match lorebook entries against context. context can be a string or a list of message dicts (role/content). """ try: entries = json.loads(lorebook_json or "[]") except json.JSONDecodeError: return "" if isinstance(entries, dict): entries = list(entries.values()) if isinstance(context, list): text = " ".join(m.get("content", "") for m in context if m.get("role") in ("user", "assistant")) else: text = context matched = [] for entry in entries: if not entry.get("enabled", True): continue if _match_entry(entry, text): content = entry.get("content", "").strip() if content: name = entry.get("name", entry.get("comment", "Lore")) matched.append(f"[{name}]\n{content}") if not matched: return "" block = "\n\n".join(matched[:max_entries]) return f"--- Lorebook (relevant world info) ---\n{block}\n---"