diff --git a/agent/characters/hendrik/persona.yaml b/agent/characters/hendrik/personality.yaml similarity index 100% rename from agent/characters/hendrik/persona.yaml rename to agent/characters/hendrik/personality.yaml diff --git a/config.py b/config.py index a6cf119..e7a2fb0 100644 --- a/config.py +++ b/config.py @@ -80,15 +80,15 @@ AGENT_MAX_ITERATIONS = int(os.getenv("AGENT_MAX_ITERATIONS", default=_yaml_get AGENT_MAX_TOOL_OUTPUT = int(os.getenv("AGENT_MAX_TOOL_OUTPUT", default=_yaml_get("agent", "max_tool_output", default="40000"))) AGENT_SKILL = os.getenv("AGENT_SKILL", default="programmer").strip().lower() -PERSONA_NAME = os.getenv("PERSONA_NAME", default=_yaml_get("persona", "name", default="Hendrik")).strip() or "Hendrik" -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() +PERSONALITY_NAME = os.getenv("PERSONALITY_NAME", default=_yaml_get("personality", "name", default="Hendrik")).strip() or "Hendrik" +PERSONALITY_AGE = os.getenv("PERSONALITY_AGE", default=_yaml_get("personality", "age", default="")).strip() +PERSONALITY_GENDER = os.getenv("PERSONALITY_GENDER", default=_yaml_get("personality", "gender", default="")).strip() +PERSONALITY_TONE = os.getenv("PERSONALITY_TONE", default=_yaml_get("personality", "tone", default="casual")).strip().lower() or "casual" +PERSONALITY_VERBOSITY = os.getenv("PERSONALITY_VERBOSITY", default=_yaml_get("personality", "verbosity", default="balanced")).strip().lower() or "balanced" +PERSONALITY_HUMOR = os.getenv("PERSONALITY_HUMOR", default=_yaml_get("personality", "humor", default="light")).strip().lower() or "light" +PERSONALITY_LANGUAGE = os.getenv("PERSONALITY_LANGUAGE", default=_yaml_get("personality", "language", default="id")).strip().lower() or "id" +PERSONALITY_MOOD = os.getenv("PERSONALITY_MOOD", default=_yaml_get("personality", "mood", default="cheerful")).strip().lower() or "cheerful" +PERSONALITY_CATCHPHRASES = os.getenv("PERSONALITY_CATCHPHRASES", default=_yaml_get("personality", "catchphrases", default="")).strip() # ─── Character & Skills (YAML, bisa di-override dari .env) ───────────────────── @@ -135,22 +135,22 @@ TYPING_MAX = float(os.getenv("TYPING_MAX", default=_yaml_get("delay", "t # ─── Character Preset Override ────────────────────────────────────────────────── # Jika AGENT_CHARACTER di-set, baca character.md dari agent/characters// -# dan override nilai persona yang relevan. +# dan override nilai personality 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 -# Coba persona.yaml dulu (prioritas utama), kalau tidak ada fallback ke character.md -_persona_yaml_path = ENV_CHARACTERS_DIR / AGENT_CHARACTER / "persona.yaml" if AGENT_CHARACTER else None +# Coba personality.yaml dulu (prioritas utama), kalau tidak ada fallback ke character.md +_personality_yaml_path = ENV_CHARACTERS_DIR / AGENT_CHARACTER / "personality.yaml" if AGENT_CHARACTER else None -if _persona_yaml_path and _persona_yaml_path.is_file(): - # Prioritas utama: baca persona.yaml dari character directory +if _personality_yaml_path and _personality_yaml_path.is_file(): + # Prioritas utama: baca personality.yaml dari character directory try: - _character_env = yaml.safe_load(_persona_yaml_path.read_text(encoding="utf-8")) or {} + _character_env = yaml.safe_load(_personality_yaml_path.read_text(encoding="utf-8")) or {} if not isinstance(_character_env, dict): _character_env = {} except Exception as _e: - print(f"[config] Warning: gagal load persona.yaml untuk '{AGENT_CHARACTER}': {_e}", flush=True) + print(f"[config] Warning: gagal load personality.yaml untuk '{AGENT_CHARACTER}': {_e}", flush=True) _character_env = {} elif ENV_CHARACTER_CONFIG_PATH and ENV_CHARACTER_CONFIG_PATH.is_file(): # Fallback: baca character.md (format lama) @@ -169,36 +169,36 @@ if _character_env: _character_overrides = { "AGENT_SKILL": AGENT_SKILL, - "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, + "PERSONALITY_NAME": PERSONALITY_NAME, + "PERSONALITY_AGE": PERSONALITY_AGE, + "PERSONALITY_GENDER": PERSONALITY_GENDER, + "PERSONALITY_TONE": PERSONALITY_TONE, + "PERSONALITY_VERBOSITY": PERSONALITY_VERBOSITY, + "PERSONALITY_HUMOR": PERSONALITY_HUMOR, + "PERSONALITY_LANGUAGE": PERSONALITY_LANGUAGE, + "PERSONALITY_MOOD": PERSONALITY_MOOD, + "PERSONALITY_CATCHPHRASES": PERSONALITY_CATCHPHRASES, } - # Mapping dari key persona.yaml ke key config + # Mapping dari key personality.yaml ke key config _yaml_to_config_key = { "AGENT_SKILL": "skill", - "PERSONA_NAME": "name", - "PERSONA_AGE": "age", - "PERSONA_GENDER": "gender", - "PERSONA_TONE": "tone", - "PERSONA_VERBOSITY": "verbosity", - "PERSONA_HUMOR": "humor", - "PERSONA_LANGUAGE": "language", - "PERSONA_MOOD": "mood", - "PERSONA_CATCHPHRASES": "catchphrases", + "PERSONALITY_NAME": "name", + "PERSONALITY_AGE": "age", + "PERSONALITY_GENDER": "gender", + "PERSONALITY_TONE": "tone", + "PERSONALITY_VERBOSITY": "verbosity", + "PERSONALITY_HUMOR": "humor", + "PERSONALITY_LANGUAGE": "language", + "PERSONALITY_MOOD": "mood", + "PERSONALITY_CATCHPHRASES": "catchphrases", } for key, fallback in _character_overrides.items(): yaml_key = _yaml_to_config_key.get(key, key.lower()) raw = _character_env.get(yaml_key, _character_env.get(key, fallback)) value = str(raw).strip() if raw is not None else "" - if key in {"AGENT_SKILL", "PERSONA_TONE", "PERSONA_VERBOSITY", "PERSONA_HUMOR", "PERSONA_LANGUAGE", "PERSONA_MOOD"}: + if key in {"AGENT_SKILL", "PERSONALITY_TONE", "PERSONALITY_VERBOSITY", "PERSONALITY_HUMOR", "PERSONALITY_LANGUAGE", "PERSONALITY_MOOD"}: value = value.lower() or fallback - if key == "PERSONA_NAME" and not value: + if key == "PERSONALITY_NAME" and not value: value = fallback _character_overrides[key] = value diff --git a/hendrik.py b/hendrik.py index 6a384f0..4d004bd 100644 --- a/hendrik.py +++ b/hendrik.py @@ -8,7 +8,7 @@ from services.xmpp_client import XMPPClient from scripts.llm_client import LLMClient from tools import coder, rag, carrack from scripts import gadget -from scripts.persona import build_system_prompt +from scripts.personality import build_system_prompt tools_definition = [ diff --git a/scripts/gadget.py b/scripts/gadget.py index ddeebae..81d3766 100644 --- a/scripts/gadget.py +++ b/scripts/gadget.py @@ -1,4 +1,4 @@ -from .persona import build_system_prompt +from .personality import build_system_prompt def tools_mapping(schema, handler, name=None): tool_name = name or schema["function"]["name"] diff --git a/scripts/persona.py b/scripts/personality.py similarity index 81% rename from scripts/persona.py rename to scripts/personality.py index 9559b47..fc091de 100644 --- a/scripts/persona.py +++ b/scripts/personality.py @@ -50,18 +50,18 @@ class PersonalityConfig: def _load_personality_from_env() -> PersonalityConfig: """Baca personality config dari environment variables.""" - raw_catchphrases = os.getenv("PERSONA_CATCHPHRASES", default="").strip() + raw_catchphrases = os.getenv("PERSONALITY_CATCHPHRASES", default="").strip() catchphrases = [c.strip() for c in raw_catchphrases.split(",") if c.strip()] if raw_catchphrases else [] return PersonalityConfig( - name=os.getenv("PERSONA_NAME", default="OWL").strip() or "OWL", - age=os.getenv("PERSONA_AGE", default="").strip(), - gender=os.getenv("PERSONA_GENDER", default="").strip(), - tone=os.getenv("PERSONA_TONE", default="casual").strip().lower() or "casual", - verbosity=os.getenv("PERSONA_VERBOSITY", default="balanced").strip().lower() or "balanced", - humor_level=os.getenv("PERSONA_HUMOR", default="light").strip().lower() or "light", - language=os.getenv("PERSONA_LANGUAGE", default="id").strip().lower() or "id", - mood=os.getenv("PERSONA_MOOD", default="cheerful").strip().lower() or "cheerful", + name=os.getenv("PERSONALITY_NAME", default="OWL").strip() or "OWL", + age=os.getenv("PERSONALITY_AGE", default="").strip(), + gender=os.getenv("PERSONALITY_GENDER", default="").strip(), + tone=os.getenv("PERSONALITY_TONE", default="casual").strip().lower() or "casual", + verbosity=os.getenv("PERSONALITY_VERBOSITY", default="balanced").strip().lower() or "balanced", + humor_level=os.getenv("PERSONALITY_HUMOR", default="light").strip().lower() or "light", + language=os.getenv("PERSONALITY_LANGUAGE", default="id").strip().lower() or "id", + mood=os.getenv("PERSONALITY_MOOD", default="cheerful").strip().lower() or "cheerful", catchphrases=catchphrases, ) @@ -119,10 +119,10 @@ def _build_personality_block(cfg: PersonalityConfig) -> str: parts = [f"You are {cfg.name}."] if cfg.age: - parts.append(f"Your persona age is {cfg.age} years old.") + parts.append(f"Your personality age is {cfg.age} years old.") if cfg.gender: - parts.append(f"Your persona gender is {cfg.gender}.") + parts.append(f"Your personality gender is {cfg.gender}.") tone_map = { "casual": "You speak in a casual, relaxed manner — like chatting with a friend.", @@ -261,46 +261,46 @@ def build_system_prompt( # Resolve character name character_name = (character or os.getenv("AGENT_CHARACTER", default="")).strip().lower() - # ── Load persona.yaml dari character directory ───────────────────────────────── + # ── Load personality.yaml dari character directory ───────────────────────────────── if character_name: char_dir = ENV_CHARACTERS_DIR / character_name - persona_yaml_path = char_dir / "persona.yaml" - if persona_yaml_path.is_file(): + personality_yaml_path = char_dir / "personality.yaml" + if personality_yaml_path.is_file(): try: - with open(persona_yaml_path, "r", encoding="utf-8") as f: - _persona_data = yaml.safe_load(f) or {} - if isinstance(_persona_data, dict): - if _persona_data.get("name"): - cfg.name = _persona_data["name"] - if _persona_data.get("age"): - cfg.age = str(_persona_data["age"]) - if _persona_data.get("gender"): - cfg.gender = _persona_data["gender"] - if _persona_data.get("tone"): - cfg.tone = _persona_data["tone"] - if _persona_data.get("verbosity"): - cfg.verbosity = _persona_data["verbosity"] - if _persona_data.get("humor"): - cfg.humor_level = _persona_data["humor"] - if _persona_data.get("language"): - cfg.language = _persona_data["language"] - if _persona_data.get("mood"): - cfg.mood = _persona_data["mood"] - # Skill wajib dari persona.yaml - _skill_from_yaml = _persona_data.get("skill") or _persona_data.get("mode") + with open(personality_yaml_path, "r", encoding="utf-8") as f: + _personality_data = yaml.safe_load(f) or {} + if isinstance(_personality_data, dict): + if _personality_data.get("name"): + cfg.name = _personality_data["name"] + if _personality_data.get("age"): + cfg.age = str(_personality_data["age"]) + if _personality_data.get("gender"): + cfg.gender = _personality_data["gender"] + if _personality_data.get("tone"): + cfg.tone = _personality_data["tone"] + if _personality_data.get("verbosity"): + cfg.verbosity = _personality_data["verbosity"] + if _personality_data.get("humor"): + cfg.humor_level = _personality_data["humor"] + if _personality_data.get("language"): + cfg.language = _personality_data["language"] + if _personality_data.get("mood"): + cfg.mood = _personality_data["mood"] + # Skill wajib dari personality.yaml + _skill_from_yaml = _personality_data.get("skill") or _personality_data.get("mode") if _skill_from_yaml: selected_skill = _skill_from_yaml.strip().lower() else: selected_skill = "" except Exception as e: - print(f"[persona] Warning: gagal load persona.yaml untuk '{character_name}': {e}", flush=True) + print(f"[personality] Warning: gagal load personality.yaml untuk '{character_name}': {e}", flush=True) # Resolve skills list - # Priority: explicit skills param > persona.yaml skill > AGENT_SKILL env > AGENT_SKILLS env > selected_skill + # Priority: explicit skills param > personality.yaml skill > AGENT_SKILL env > AGENT_SKILLS env > selected_skill if skills is not None: skills_list = skills elif selected_skill != SKILL: - # persona.yaml meng-override skill → pakai skill dari persona.yaml + # personality.yaml meng-override skill → pakai skill dari personality.yaml skills_list = [selected_skill] if selected_skill in ("programmer", "roleplayer", "analyst") else [] else: skills_env = os.getenv("AGENT_SKILLS", default="").strip() diff --git a/services/telegram_client.py b/services/telegram_client.py index a2cca00..40beaef 100644 --- a/services/telegram_client.py +++ b/services/telegram_client.py @@ -8,7 +8,7 @@ from datetime import datetime import config from services.session_manager import SessionManager from services.agent_loop import run_agent_loop -from scripts.persona import PERSONALITY +from scripts.personality import PERSONALITY from tools.roleplayer import _name_mentioned diff --git a/services/xmpp_client.py b/services/xmpp_client.py index 6313a2d..0505f44 100644 --- a/services/xmpp_client.py +++ b/services/xmpp_client.py @@ -10,7 +10,7 @@ from services.agent_loop import run_agent_loop import config from tools.roleplayer import should_respond -from scripts.persona import PERSONALITY +from scripts.personality import PERSONALITY # Anti-ban: delay constants for MUC rejoin behavior MUC_REJOIN_INITIAL_DELAY = 5.0 # detik, delay awal sebelum rejoin