import os from pathlib import Path import yaml from dotenv import load_dotenv load_dotenv() # ─── YAML Config Loader ──────────────────────────────────────────────────────── _CONFIG_PATH = Path(__file__).resolve().parent / "config.yaml" _yaml: dict = {} if _CONFIG_PATH.is_file(): with open(_CONFIG_PATH, "r", encoding="utf-8") as f: _yaml = yaml.safe_load(f) or {} def _yaml_get(*keys, default=None): """Navigate nested yaml dict, return default if any key missing.""" d = _yaml for k in keys: if isinstance(d, dict) and k in d: d = d[k] else: return default return d if d is not None else default # ─── Credential / Secret (hanya dari .env) ───────────────────────────────────── llm_baseurl = os.getenv("LLM_BASE_URL", default="http://localhost:11434/v1") llm_model = os.getenv("LLM_MODEL", default="granite4.1:8b") llm_api_key = os.getenv("LLM_API_KEY", default="ollama") llm_timeout = int(os.getenv("LLM_TIMEOUT", default="600")) XMPP_USERNAME = os.getenv("XMPP_USERNAME", default="") XMPP_PASSWORD = os.getenv("XMPP_PASSWORD", default="") # ─── Agent Config (YAML, bisa di-override dari .env) ──────────────────────────── AGENT_MAX_ITERATIONS = int(os.getenv("AGENT_MAX_ITERATIONS", default=_yaml_get("agent", "max_iterations", default="30"))) AGENT_MAX_TOOL_OUTPUT = int(os.getenv("AGENT_MAX_TOOL_OUTPUT", default=_yaml_get("agent", "max_tool_output", default="40000"))) # ─── Persona / Mode (YAML, bisa di-override dari .env) ────────────────────────── PERSONA_MODE = os.getenv("PERSONA_MODE", default=_yaml_get("persona", "mode", default="programmer")).strip().lower() PERSONA_NAME = os.getenv("PERSONA_NAME", default=_yaml_get("persona", "name", default="OWL")).strip() or "OWL" PERSONA_AGE = os.getenv("PERSONA_AGE", default=_yaml_get("persona", "age", default="")).strip() PERSONA_GENDER = os.getenv("PERSONA_GENDER", default=_yaml_get("persona", "gender", default="")).strip() PERSONA_TONE = os.getenv("PERSONA_TONE", default=_yaml_get("persona", "tone", default="casual")).strip().lower() or "casual" PERSONA_VERBOSITY = os.getenv("PERSONA_VERBOSITY", default=_yaml_get("persona", "verbosity", default="balanced")).strip().lower() or "balanced" PERSONA_HUMOR = os.getenv("PERSONA_HUMOR", default=_yaml_get("persona", "humor", default="light")).strip().lower() or "light" PERSONA_LANGUAGE = os.getenv("PERSONA_LANGUAGE", default=_yaml_get("persona", "language", default="id")).strip().lower() or "id" PERSONA_MOOD = os.getenv("PERSONA_MOOD", default=_yaml_get("persona", "mood", default="cheerful")).strip().lower() or "cheerful" PERSONA_CATCHPHRASES = os.getenv("PERSONA_CATCHPHRASES", default=_yaml_get("persona", "catchphrases", default="")).strip() # ─── Character & Skills (YAML, bisa di-override dari .env) ───────────────────── AGENT_CHARACTER = os.getenv("AGENT_CHARACTER", default=_yaml_get("character", "preset", default="")).strip().lower() AGENT_SKILLS = os.getenv("AGENT_SKILLS", default=_yaml_get("character", "skills", default="")).strip().lower() # ─── XMPP (non-credential dari YAML, credential dari .env) ───────────────────── XMPP_ENABLED = os.getenv("XMPP_ENABLED", default=str(_yaml_get("xmpp", "enabled", default="false"))).strip().lower() in ("true", "1", "yes") XMPP_MUC_ROOMS = os.getenv("XMPP_MUC_ROOMS", default=_yaml_get("xmpp", "muc_rooms", default="")).strip() XMPP_NICKNAME = os.getenv("XMPP_NICKNAME", default=_yaml_get("xmpp", "nickname", default="")).strip() XMPP_SELECTIVE_RESPONSE = os.getenv("XMPP_SELECTIVE_RESPONSE", default=str(_yaml_get("xmpp", "selective_response", default="true"))).strip().lower() in ("true", "1", "yes") # ─── RAG (YAML) ───────────────────────────────────────────────────────────────── RAG_PERSIST_DIR = os.getenv("RAG_PERSIST_DIR", default=_yaml_get("rag", "persist_dir", default="chroma_db")) # ─── Humanize Delay (YAML) ───────────────────────────────────────────────────── READ_DELAY_MIN = float(os.getenv("READ_DELAY_MIN", default=_yaml_get("delay", "read_min", default="1.0"))) READ_DELAY_MAX = float(os.getenv("READ_DELAY_MAX", default=_yaml_get("delay", "read_max", default="2.0"))) TYPING_SPEED = float(os.getenv("TYPING_SPEED", default=_yaml_get("delay", "typing_speed", default="15.0"))) TYPING_MAX = float(os.getenv("TYPING_MAX", default=_yaml_get("delay", "typing_max", default="10.0"))) # ─── Character Preset Override ────────────────────────────────────────────────── # Jika AGENT_CHARACTER di-set, baca character.md dari agent/characters// # dan override nilai persona yang relevan. ENV_CHARACTERS_DIR = Path(__file__).resolve().parent / "agent" / "characters" ENV_CHARACTER_CONFIG_PATH = ENV_CHARACTERS_DIR / AGENT_CHARACTER / "character.md" if AGENT_CHARACTER else None if ENV_CHARACTER_CONFIG_PATH and ENV_CHARACTER_CONFIG_PATH.is_file(): _character_env: dict[str, str] = {} for line in ENV_CHARACTER_CONFIG_PATH.read_text(encoding="utf-8").splitlines(): line = line.strip() if not line or line.startswith("#"): continue if "=" in line: key, value = line.split("=", 1) _character_env[key.strip()] = value.strip() _character_overrides = { "PERSONA_MODE": PERSONA_MODE, "PERSONA_NAME": PERSONA_NAME, "PERSONA_AGE": PERSONA_AGE, "PERSONA_GENDER": PERSONA_GENDER, "PERSONA_TONE": PERSONA_TONE, "PERSONA_VERBOSITY": PERSONA_VERBOSITY, "PERSONA_HUMOR": PERSONA_HUMOR, "PERSONA_LANGUAGE": PERSONA_LANGUAGE, "PERSONA_MOOD": PERSONA_MOOD, "PERSONA_CATCHPHRASES": PERSONA_CATCHPHRASES, } for key, fallback in _character_overrides.items(): value = _character_env.get(key, fallback).strip() if key in {"PERSONA_MODE", "PERSONA_TONE", "PERSONA_VERBOSITY", "PERSONA_HUMOR", "PERSONA_LANGUAGE", "PERSONA_MOOD"}: value = value.lower() or fallback if key == "PERSONA_NAME" and not value: value = fallback _character_overrides[key] = value for key, value in _character_overrides.items(): globals()[key] = value os.environ[key] = value