Refactor for override character
This commit is contained in:
parent
61c727662c
commit
b9a76d080a
109
config.py
109
config.py
@ -79,21 +79,21 @@ XMPP_PASSWORD = os.getenv("XMPP_PASSWORD", default="")
|
|||||||
AGENT_MAX_ITERATIONS = int(os.getenv("AGENT_MAX_ITERATIONS", default=_yaml_get("agent", "max_iterations", default="30")))
|
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")))
|
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()
|
AGENT_SKILL = "programmer"
|
||||||
PERSONALITY_NAME = os.getenv("PERSONALITY_NAME", default=_yaml_get("personality", "name", default="Hendrik")).strip() or "Hendrik"
|
PERSONALITY_NAME = "Hendrik"
|
||||||
PERSONALITY_AGE = os.getenv("PERSONALITY_AGE", default=_yaml_get("personality", "age", default="")).strip()
|
PERSONALITY_AGE = ""
|
||||||
PERSONALITY_GENDER = os.getenv("PERSONALITY_GENDER", default=_yaml_get("personality", "gender", default="")).strip()
|
PERSONALITY_GENDER = ""
|
||||||
PERSONALITY_TONE = os.getenv("PERSONALITY_TONE", default=_yaml_get("personality", "tone", default="casual")).strip().lower() or "casual"
|
PERSONALITY_TONE = "casual"
|
||||||
PERSONALITY_VERBOSITY = os.getenv("PERSONALITY_VERBOSITY", default=_yaml_get("personality", "verbosity", default="balanced")).strip().lower() or "balanced"
|
PERSONALITY_VERBOSITY = "balanced"
|
||||||
PERSONALITY_HUMOR = os.getenv("PERSONALITY_HUMOR", default=_yaml_get("personality", "humor", default="light")).strip().lower() or "light"
|
PERSONALITY_HUMOR = "light"
|
||||||
PERSONALITY_LANGUAGE = os.getenv("PERSONALITY_LANGUAGE", default=_yaml_get("personality", "language", default="id")).strip().lower() or "id"
|
PERSONALITY_LANGUAGE = "id"
|
||||||
PERSONALITY_MOOD = os.getenv("PERSONALITY_MOOD", default=_yaml_get("personality", "mood", default="cheerful")).strip().lower() or "cheerful"
|
PERSONALITY_MOOD = "cheerful"
|
||||||
PERSONALITY_CATCHPHRASES = os.getenv("PERSONALITY_CATCHPHRASES", default=_yaml_get("personality", "catchphrases", default="")).strip()
|
PERSONALITY_CATCHPHRASES = ""
|
||||||
|
|
||||||
|
|
||||||
# ─── Character & Skills (YAML, bisa di-override dari .env) ─────────────────────
|
# ─── Character & Skills ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
AGENT_CHARACTER = os.getenv("AGENT_CHARACTER", default=_yaml_get("agent", "character", default="")).strip().lower()
|
AGENT_CHARACTER = _yaml_get("agent", "character", default="").strip().lower()
|
||||||
AGENT_SKILLS = os.getenv("AGENT_SKILLS", default="").strip().lower()
|
AGENT_SKILLS = os.getenv("AGENT_SKILLS", default="").strip().lower()
|
||||||
|
|
||||||
|
|
||||||
@ -127,41 +127,65 @@ TYPING_SPEED = float( _yaml_get("delay", "typing_speed", default="15.0" ) )
|
|||||||
TYPING_MAX = float( _yaml_get("delay", "typing_max", default="10.0" ) )
|
TYPING_MAX = float( _yaml_get("delay", "typing_max", default="10.0" ) )
|
||||||
|
|
||||||
|
|
||||||
# ─── Character Preset Override ──────────────────────────────────────────────────
|
# ─── Character Loader ──────────────────────────────────────────────────────────
|
||||||
# Jika AGENT_CHARACTER di-set, baca character.md dari agent/characters/<preset>/
|
|
||||||
# dan override nilai personality yang relevan.
|
|
||||||
|
|
||||||
ENV_CHARACTERS_DIR = Path(__file__).resolve().parent / "agent" / "characters"
|
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 personality.yaml dulu (prioritas utama), kalau tidak ada fallback ke character.md
|
_yaml_to_config_key = {
|
||||||
_personality_yaml_path = ENV_CHARACTERS_DIR / AGENT_CHARACTER / "personality.yaml" if AGENT_CHARACTER else None
|
"AGENT_SKILL": "skill",
|
||||||
|
"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",
|
||||||
|
}
|
||||||
|
|
||||||
if _personality_yaml_path and _personality_yaml_path.is_file():
|
_lowercase_keys = {"AGENT_SKILL", "PERSONALITY_TONE", "PERSONALITY_VERBOSITY", "PERSONALITY_HUMOR", "PERSONALITY_LANGUAGE", "PERSONALITY_MOOD"}
|
||||||
# Prioritas utama: baca personality.yaml dari character directory
|
|
||||||
|
|
||||||
|
def load_character(char_override=None):
|
||||||
|
"""Load personality dari character directory. Bisa di-call ulang untuk override."""
|
||||||
|
global AGENT_CHARACTER, AGENT_SKILL, PERSONALITY_NAME, PERSONALITY_AGE, PERSONALITY_GENDER
|
||||||
|
global PERSONALITY_TONE, PERSONALITY_VERBOSITY, PERSONALITY_HUMOR, PERSONALITY_LANGUAGE
|
||||||
|
global PERSONALITY_MOOD, PERSONALITY_CATCHPHRASES
|
||||||
|
|
||||||
|
if char_override:
|
||||||
|
AGENT_CHARACTER = char_override.strip().lower()
|
||||||
|
|
||||||
|
if not AGENT_CHARACTER:
|
||||||
|
return
|
||||||
|
|
||||||
|
personality_yaml_path = CHARACTERS_DIR / AGENT_CHARACTER / "personality.yaml"
|
||||||
|
character_config_path = CHARACTERS_DIR / AGENT_CHARACTER / "character.md"
|
||||||
|
|
||||||
|
if personality_yaml_path.is_file():
|
||||||
try:
|
try:
|
||||||
_character_env = yaml.safe_load(_personality_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):
|
if not isinstance(_character_env, dict):
|
||||||
_character_env = {}
|
_character_env = {}
|
||||||
except Exception as _e:
|
except Exception as _e:
|
||||||
print(f"[config] Warning: gagal load personality.yaml untuk '{AGENT_CHARACTER}': {_e}", flush=True)
|
print(f"[config] Warning: gagal load personality.yaml untuk '{AGENT_CHARACTER}': {_e}", flush=True)
|
||||||
_character_env = {}
|
_character_env = {}
|
||||||
elif ENV_CHARACTER_CONFIG_PATH and ENV_CHARACTER_CONFIG_PATH.is_file():
|
elif character_config_path.is_file():
|
||||||
# Fallback: baca character.md (format lama)
|
|
||||||
_character_env = {}
|
_character_env = {}
|
||||||
for line in ENV_CHARACTER_CONFIG_PATH.read_text(encoding="utf-8").splitlines():
|
for line in character_config_path.read_text(encoding="utf-8").splitlines():
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if not line or line.startswith("#"):
|
if not line or line.startswith("#"):
|
||||||
continue
|
continue
|
||||||
if "=" in line:
|
if "=" in line:
|
||||||
key, value = line.split("=", 1)
|
key, value = line.split("=", 1)
|
||||||
_character_env[key.strip()] = value.strip()
|
_character_env[key.strip()] = value.strip()
|
||||||
else:
|
else:
|
||||||
_character_env = None
|
return
|
||||||
|
|
||||||
if _character_env:
|
if not _character_env:
|
||||||
|
return
|
||||||
|
|
||||||
_character_overrides = {
|
_defaults = {
|
||||||
"AGENT_SKILL": AGENT_SKILL,
|
"AGENT_SKILL": AGENT_SKILL,
|
||||||
"PERSONALITY_NAME": PERSONALITY_NAME,
|
"PERSONALITY_NAME": PERSONALITY_NAME,
|
||||||
"PERSONALITY_AGE": PERSONALITY_AGE,
|
"PERSONALITY_AGE": PERSONALITY_AGE,
|
||||||
@ -173,29 +197,20 @@ if _character_env:
|
|||||||
"PERSONALITY_MOOD": PERSONALITY_MOOD,
|
"PERSONALITY_MOOD": PERSONALITY_MOOD,
|
||||||
"PERSONALITY_CATCHPHRASES": PERSONALITY_CATCHPHRASES,
|
"PERSONALITY_CATCHPHRASES": PERSONALITY_CATCHPHRASES,
|
||||||
}
|
}
|
||||||
# Mapping dari key personality.yaml ke key config
|
|
||||||
_yaml_to_config_key = {
|
for key, fallback in _defaults.items():
|
||||||
"AGENT_SKILL": "skill",
|
|
||||||
"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())
|
yaml_key = _yaml_to_config_key.get(key, key.lower())
|
||||||
raw = _character_env.get(yaml_key, _character_env.get(key, fallback))
|
raw = _character_env.get(yaml_key, _character_env.get(key, fallback))
|
||||||
value = str(raw).strip() if raw is not None else ""
|
value = str(raw).strip() if raw is not None else ""
|
||||||
if key in {"AGENT_SKILL", "PERSONALITY_TONE", "PERSONALITY_VERBOSITY", "PERSONALITY_HUMOR", "PERSONALITY_LANGUAGE", "PERSONALITY_MOOD"}:
|
if key in _lowercase_keys:
|
||||||
value = value.lower() or fallback
|
value = value.lower() or fallback
|
||||||
if key == "PERSONALITY_NAME" and not value:
|
if key == "PERSONALITY_NAME" and not value:
|
||||||
value = fallback
|
value = fallback
|
||||||
_character_overrides[key] = value
|
_defaults[key] = value
|
||||||
|
|
||||||
for key, value in _character_overrides.items():
|
for key, value in _defaults.items():
|
||||||
globals()[key] = value
|
globals()[key] = value
|
||||||
os.environ[key] = value
|
|
||||||
|
|
||||||
|
# Load character dari config.yaml saat import time
|
||||||
|
load_character()
|
||||||
|
|||||||
10
hendrik.py
10
hendrik.py
@ -1,13 +1,6 @@
|
|||||||
import os, sys
|
import os, sys
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
# Pre-parse --char BEFORE config import (config reads os.environ at import time)
|
|
||||||
_pre = argparse.ArgumentParser(add_help=False)
|
|
||||||
_pre.add_argument('--char', type=str, default=None)
|
|
||||||
_pre_args, _ = _pre.parse_known_args()
|
|
||||||
if _pre_args.char:
|
|
||||||
os.environ['AGENT_CHARACTER'] = _pre_args.char
|
|
||||||
|
|
||||||
import threading, time, signal
|
import threading, time, signal
|
||||||
|
|
||||||
import config
|
import config
|
||||||
@ -73,6 +66,9 @@ def main():
|
|||||||
parser.add_argument('-w', '--workspace', type=str, default=None, help='Working directory')
|
parser.add_argument('-w', '--workspace', type=str, default=None, help='Working directory')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.char:
|
||||||
|
config.load_character(char_override=args.char)
|
||||||
|
|
||||||
if args.workspace:
|
if args.workspace:
|
||||||
resolved = os.path.abspath(args.workspace)
|
resolved = os.path.abspath(args.workspace)
|
||||||
if not os.path.isdir(resolved):
|
if not os.path.isdir(resolved):
|
||||||
|
|||||||
@ -273,7 +273,7 @@ def build_system_prompt(
|
|||||||
cfg = personality or PERSONALITY
|
cfg = personality or PERSONALITY
|
||||||
|
|
||||||
# Resolve character name
|
# Resolve character name
|
||||||
character_name = (character or os.getenv("AGENT_CHARACTER", default="")).strip().lower()
|
character_name = (character or "").strip().lower()
|
||||||
|
|
||||||
# ── Load personality.yaml dari character directory ─────────────────────────────────
|
# ── Load personality.yaml dari character directory ─────────────────────────────────
|
||||||
if character_name:
|
if character_name:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user