Merge PR #773: feat(cli,gateway): add /personality none and custom personality support

Authored by teyrebaz33. Closes #643.

- /personality none/default/neutral clears system prompt overlay
- Dict format personalities with description, tone, style fields
- Works in both CLI and gateway
- 18 tests
This commit is contained in:
teknium1
2026-03-11 02:54:27 -07:00
4 changed files with 275 additions and 8 deletions

View File

@@ -1733,14 +1733,39 @@ class GatewayRunner:
if not args:
lines = ["🎭 **Available Personalities**\n"]
lines.append("• `none` — (no personality overlay)")
for name, prompt in personalities.items():
preview = prompt[:50] + "..." if len(prompt) > 50 else prompt
if isinstance(prompt, dict):
preview = prompt.get("description") or prompt.get("system_prompt", "")[:50]
else:
preview = prompt[:50] + "..." if len(prompt) > 50 else prompt
lines.append(f"• `{name}` — {preview}")
lines.append(f"\nUsage: `/personality <name>`")
return "\n".join(lines)
if args in personalities:
new_prompt = personalities[args]
def _resolve_prompt(value):
if isinstance(value, dict):
parts = [value.get("system_prompt", "")]
if value.get("tone"):
parts.append(f'Tone: {value["tone"]}')
if value.get("style"):
parts.append(f'Style: {value["style"]}')
return "\n".join(p for p in parts if p)
return str(value)
if args in ("none", "default", "neutral"):
try:
if "agent" not in config or not isinstance(config.get("agent"), dict):
config["agent"] = {}
config["agent"]["system_prompt"] = ""
with open(config_path, "w") as f:
yaml.dump(config, f, default_flow_style=False, sort_keys=False)
except Exception as e:
return f"⚠️ Failed to save personality change: {e}"
self._ephemeral_system_prompt = ""
return "🎭 Personality cleared — using base agent behavior.\n_(takes effect on next message)_"
elif args in personalities:
new_prompt = _resolve_prompt(personalities[args])
# Write to config.yaml, same pattern as CLI save_config_value.
try:
@@ -1757,7 +1782,7 @@ class GatewayRunner:
return f"🎭 Personality set to **{args}**\n_(takes effect on next message)_"
available = ", ".join(f"`{n}`" for n in personalities.keys())
available = "`none`, " + ", ".join(f"`{n}`" for n in personalities.keys())
return f"Unknown personality: `{args}`\n\nAvailable: {available}"
async def _handle_retry_command(self, event: MessageEvent) -> str: