Overview
Handles slash commands (/command) sent through the WebSocket connection. Provides administrative and configuration functions for managing worlds, characters, sessions, models, and rules.
Main Handler
handle_command(cmd_str: str, websocket: WebSocket)
async def handle_command(cmd_str: str, websocket: WebSocket)
Parses and executes slash commands received from the client.
Command string starting with / (e.g., /world select fantasy)
FastAPI WebSocket connection for sending responses
Command Parsing
parts = cmd_str.split(" ", 2)
cmd = parts[0] # e.g., "/model"
Commands are split into at most 3 parts:
parts[0]: Command name (e.g., /model)
parts[1]: Subcommand or first argument (e.g., select)
parts[2]: Remaining arguments (e.g., my long lore text)
Commands
Model Management
/model <model_id>
Switches the active AI model (hot-swaps without restarting).
if cmd == "/model" and len(parts) >= 2:
new_model = parts[1]
if any(m["id"] == new_model for m in state.AVAILABLE_MODELS):
state.CURRENT_MODEL = new_model
state.MODEL_CONFIRMED = True
state.save_state()
await websocket.send_text(
build_ws_payload(
"system_update",
f"Hot-swapped model to {state.CURRENT_MODEL}",
{"model": state.CURRENT_MODEL, "model_confirmed": True},
)
)
Example
Always true when model switch succeeds
Error Response
else:
await websocket.send_text(
build_ws_payload(
"system_update", f"Error: {new_model} is not recognized."
)
)
World Commands
/world attach_lore <text>
Dynamically adds lore text to the current world’s RAG vector store.
elif cmd == "/world" and len(parts) >= 3:
sub = parts[1]
if sub == "attach_lore":
lore_text = parts[2]
rag_manager.add_lore(state.ACTIVE_WORLD_ID, str(uuid.uuid4()), lore_text)
await websocket.send_text(
build_ws_payload("system_update", "Lore attached successfully.")
)
Example
/world attach_lore The ancient ruins hold a dark secret that only the elders remember.
Lore text to add to the world’s knowledge base (automatically embedded)
/world select <world_id>
Sets the active world for the current session.
elif sub == "select":
state.ACTIVE_WORLD_ID = parts[2].strip()
state.save_state()
await websocket.send_text(
build_ws_payload(
"system_update",
f"Active world set to {state.ACTIVE_WORLD_ID}",
{"world_id": state.ACTIVE_WORLD_ID},
)
)
await broadcast_sync_state(websocket)
Example
ID of the newly selected world
Character Commands
/character select <character_id>
Sets the active character (persona) for conversations.
elif cmd == "/character" and len(parts) >= 3 and parts[1] == "select":
state.ACTIVE_CHARACTER_ID = parts[2].strip()
state.save_state()
await websocket.send_text(
build_ws_payload(
"system_update",
f"Active character set to {state.ACTIVE_CHARACTER_ID}",
{"character_id": state.ACTIVE_CHARACTER_ID},
)
)
await broadcast_sync_state(websocket)
Example
ID of the newly selected character
Rules Management
/rules add <rule_id>
Activates a rule file from assets/rules/.
elif cmd == "/rules":
if len(parts) >= 3 and parts[1] == "add":
rule_id = parts[2].strip()
if os.path.exists(f"assets/rules/{rule_id}.yaml"):
if rule_id not in state.ACTIVE_RULES:
state.ACTIVE_RULES.append(rule_id)
state.save_state()
await websocket.send_text(
build_ws_payload(
"system_update",
f"✓ Rule '{rule_id}' activated",
{"active_rules": state.ACTIVE_RULES},
)
)
await broadcast_sync_state(websocket)
Example
List of all currently active rule IDs
/rules clear
Removes all active rules.
elif len(parts) >= 2 and parts[1] == "clear":
state.ACTIVE_RULES.clear()
state.save_state()
await websocket.send_text(
build_ws_payload(
"system_update",
"✓ All active rules cleared",
{"active_rules": state.ACTIVE_RULES},
)
)
await broadcast_sync_state(websocket)
Example
NSFW Mode
/nsfw
Toggles NSFW (Not Safe For Work) mode by adding or removing the nsfw rule.
elif cmd == "/nsfw":
if "nsfw" not in state.ACTIVE_RULES:
if os.path.exists("assets/rules/nsfw.yaml"):
state.ACTIVE_RULES.append("nsfw")
state.save_state()
await websocket.send_text(
build_ws_payload(
"system_update",
"✓ NSFW mode ENABLED - Unrestricted adult content",
{"active_rules": state.ACTIVE_RULES},
)
)
await broadcast_sync_state(websocket)
Example
Updated rules list (includes or excludes "nsfw")
Disabling NSFW
else:
state.ACTIVE_RULES.remove("nsfw")
state.save_state()
await websocket.send_text(
build_ws_payload(
"system_update",
"✓ NSFW mode DISABLED - Back to standard content",
{"active_rules": state.ACTIVE_RULES},
)
)
await broadcast_sync_state(websocket)
Session Commands
/session new
Creates a new conversation session.
elif cmd == "/session":
if len(parts) >= 2 and parts[1] == "new":
if not state.ACTIVE_WORLD_ID or not state.ACTIVE_CHARACTER_ID:
await websocket.send_text(
build_ws_payload("system_update", "✗ Select world/char first.")
)
else:
state.ACTIVE_SESSION_ID = uuid.uuid4().hex[:12]
session_manager.create_session(
state.ACTIVE_SESSION_ID,
state.ACTIVE_CHARACTER_ID,
state.ACTIVE_WORLD_ID,
state.CURRENT_MODEL,
)
state.save_state()
Example
Generated 12-character session ID
Start Message Handling
If the world has a start_message, it’s automatically added to the session:
world = world_manager.get_world(state.ACTIVE_WORLD_ID)
start_history = []
if world:
if world.start_message:
msg_manager.add_message(
Message(
role="assistant",
content=world.start_message,
character_id=state.ACTIVE_CHARACTER_ID,
session_id=state.ACTIVE_SESSION_ID,
)
)
start_history.append(
{"role": "assistant", "content": world.start_message}
)
The start message is sent back to the client via a chat_history event:
await websocket.send_text(
json.dumps(
{
"event": "chat_history",
"payload": {
"content": "",
"metadata": {"history": start_history},
},
}
)
)
/session continue <session_id>
Resumes an existing session by loading its history.
elif len(parts) >= 3 and parts[1] == "continue":
sess_id = parts[2].strip()
sess = session_manager.get_session(sess_id)
if sess:
state.ACTIVE_SESSION_ID = sess.id
state.ACTIVE_WORLD_ID = sess.world_id
state.ACTIVE_CHARACTER_ID = sess.character_id
if sess.model:
state.CURRENT_MODEL = sess.model
session_manager.touch(sess_id)
state.save_state()
await send_chat_history(
websocket, state.ACTIVE_CHARACTER_ID, state.ACTIVE_SESSION_ID
)
await broadcast_sync_state(websocket)
Example
/session continue a1b2c3d4e5f6
12-character session ID to resume
/session delete <session_id>
Permanently deletes a session and all associated data.
elif len(parts) >= 3 and parts[1] == "delete":
sess_id = parts[2].strip()
session_manager.delete_session(sess_id)
msg_manager.delete_session_messages(sess_id)
rag_manager.delete_session_memory(sess_id)
if state.ACTIVE_SESSION_ID == sess_id:
state.ACTIVE_SESSION_ID = ""
await websocket.send_text(
build_ws_payload("system_update", f"✓ Deleted session {sess_id}")
)
await broadcast_sync_state(websocket)
Example
/session delete a1b2c3d4e5f6
Deletes:
- Session metadata from database
- All messages in the session
- All RAG vector embeddings for the session
State Synchronization
Many commands call broadcast_sync_state(websocket) to send updated state to the client:
await broadcast_sync_state(websocket)
This sends a sync_state event with:
- Available worlds
- Available characters
- Recent sessions
- Active selections
- Available models
- Active rules
Error Handling
Invalid Model
if any(m["id"] == new_model for m in state.AVAILABLE_MODELS):
# success
else:
await websocket.send_text(
build_ws_payload(
"system_update", f"Error: {new_model} is not recognized."
)
)
Missing Prerequisites
if not state.ACTIVE_WORLD_ID or not state.ACTIVE_CHARACTER_ID:
await websocket.send_text(
build_ws_payload("system_update", "✗ Select world/char first.")
)
Missing Rule File
if os.path.exists("assets/rules/nsfw.yaml"):
# success
else:
await websocket.send_text(
build_ws_payload("system_update", "✗ NSFW rule file not found.")
)
Complete Command Reference
| Command | Description | Example |
|---|
/model <model_id> | Switch AI model | /model deepseek-chat |
/world select <world_id> | Select world | /world select fantasy |
/world attach_lore <text> | Add dynamic lore | /world attach_lore Ancient ruins... |
/character select <char_id> | Select character | /character select elara |
/rules add <rule_id> | Activate rule | /rules add nsfw |
/rules clear | Clear all rules | /rules clear |
/nsfw | Toggle NSFW mode | /nsfw |
/session new | Create session | /session new |
/session continue <id> | Resume session | /session continue a1b2c3d4e5f6 |
/session delete <id> | Delete session | /session delete a1b2c3d4e5f6 |
Usage Example
import asyncio
import websockets
import json
async def setup_engine():
uri = "ws://localhost:8000/ws/rpc"
async with websockets.connect(uri) as ws:
# Wait for ready message
await ws.recv()
# Setup commands
commands = [
"/model deepseek-chat",
"/world select cyberpunk",
"/character select nova",
"/rules add nsfw",
"/session new"
]
for cmd in commands:
await ws.send(json.dumps({"prompt": cmd}))
response = await ws.recv()
print(json.loads(response))
asyncio.run(setup_engine())