Page:
Architecture Prompt System
Pages
Architecture Commands and API
Architecture Context System
Architecture Core Engine
Architecture Event Sourcing
Architecture Generative Reflection
Architecture Helpers
Architecture Journal System
Architecture LLM Interaction
Architecture LLM Providers
Architecture Logging
Architecture Memory and Sleep
Architecture Overview
Architecture Persona Protection
Architecture Prompt System
Architecture RAG Implementation
Architecture Resilience System
Architecture Safety System
Architecture Self Management
Architecture Sub Agent Delegation
Architecture Task Assessment
Architecture Token Management
Architecture Tool System
Configuration Reference
Context and Memory Flow Analysis
Data Flow 01 Context Compaction
Data Flow 02 ReAct Loop
Data Flow 03 Memory Consolidation
Data Flow 04 Message Classification
Data Flow 05 Entity Profile System
Data Flow 06 Tool Execution
Data Flow 07 Sleep Mode Transitions
Data Flow 08 LLM Provider Interaction
Data Flow 09 Self Management Operations
Home
LLM Decision Patterns
Research Foundations
User Guide 00 Index
User Guide 01 Getting Started
User Guide 02 Configuration and Customization
User Guide 03 Advanced Capabilities
User Guide 04 Troubleshooting
No results
1
Architecture Prompt System
blightbow edited this page 2025-12-08 04:11:20 +00:00
Architecture: Prompt System
Layer 2 - Templates, Components, and Runtime Assembly
Overview
The prompt system manages the LLM context window through three interrelated concepts:
- PromptComponent - Ordered building blocks of the context window
- PromptTemplate - Reusable content with placeholders
- PromptRegistry - Persistent storage for user customizations
1. Component ID Scheme
Components use a 1000-point increment scheme for ordering:
Static Component IDs:
0 → System Prompt
1000 → Character Context
1500 → Entity Context (O-Mem Working Memory)
2000 → Semantic Memories
3000 → Context Buffer
4000 → Goals
5000 → Conversation History
6000 → Pending Event
7000 → Tool Result
Pluggable Component IDs:
1-999 → After System Prompt (0)
1001-1499 → After Character Context (1000)
1501-1999 → After Entity Context (1500)
2001-2999 → After Semantic Memories (2000)
...
The spacing provides 999 slots between each static component pair for user-defined content.
2. PromptComponent
Dataclass representing a context window segment (prompt_components.py).
@dataclass
class PromptComponent:
id: int # Ordered position (0, 1000, 2000... or 1, 2, 1001...)
key: str # Unique identifier ("system_prompt", "my_custom")
name: str # Human-readable display name
description: str # What this component provides
content: str # Template content with {placeholders}
is_static: bool # True for built-in, False for user-created
enabled: bool # Whether to include in assembly
role: str # Message role ("system", "user", "assistant", "tool")
Static Components
Built-in components with fixed IDs:
| ID | Key | Role | Purpose |
|---|---|---|---|
| 0 | system_prompt |
system | Core LLM instructions |
| 1000 | character_context |
system | Persona, active project, session memory |
| 1500 | entity_context |
system | O-Mem working memory for entities |
| 2000 | semantic_memories |
system | Retrieved facts from Mem0 |
| 3000 | context_buffer |
system | Ambient messages, environment |
| 4000 | goals |
system | Active goals with hierarchy |
| 5000 | conversation_history |
mixed | Recent user/assistant exchanges |
| 6000 | pending_event |
user | Current event being processed |
| 7000 | tool_result |
tool | Result from previous tool call |
Component Functions
from evennia.contrib.base_systems.ai.prompt_components import (
get_static_components, # All static components
get_static_component, # Single by key
get_ordered_component_ids, # [0, 1000, 1500, 2000, ...]
is_static_id, # Check if ID is static
allocate_pluggable_id, # Get next available ID
)
3. PromptTemplate
Reusable content with runtime placeholders (prompt_templates.py).
@dataclass
class PromptTemplate:
key: str # Unique identifier
name: str # Display name
description: str # What this template is for
content: str # Template text with {placeholders}
placeholders: list # List of placeholder names
is_builtin: bool # True for system templates
category: str # "system_prompt", "reflection", etc.
Built-in Templates
| Key | Category | Placeholders | Purpose |
|---|---|---|---|
default |
system_prompt | tick_rate |
Native tool calling mode |
default_fallback |
system_prompt | tick_rate, tool_schemas |
JSON format for non-native providers |
reflection |
reflection | 6 metrics | Self-reflection prompt |
Template Rendering
from evennia.contrib.base_systems.ai.prompt_templates import (
get_template, # Get by key
get_default_template, # Native mode template
get_fallback_template, # JSON fallback template
render_template, # Fill placeholders (raises on missing)
safe_render_template, # Fill placeholders (leaves missing unchanged)
)
# Example
template = get_default_template()
rendered = render_template(template, tick_rate=5)
4. PromptRegistry
Singleton script for persistent template and component storage (prompt_registry.py).
Getting the Registry
from evennia.contrib.base_systems.ai.prompt_registry import get_prompt_registry
registry = get_prompt_registry()
Template CRUD
# Create user template
registry.create_template(
key="my_template",
name="Custom Assistant",
content="You are a {personality} assistant...",
description="Custom personality template",
placeholders=["personality"],
category="system_prompt"
)
# Get template (checks user templates, then falls back to built-in)
template = registry.get_template("my_template")
# Update template
registry.update_template("my_template", content="New content...")
# Delete template
registry.delete_template("my_template")
# List all templates
all_templates = registry.list_templates(include_builtin=True)
# Clone built-in for customization
registry.clone_template("default", "my_custom", new_name="My Custom")
Component CRUD
# Create pluggable component (ID auto-allocated)
registry.create_component(
key="my_context",
name="Custom Context",
content="Additional context here...",
after_static=1000, # Insert after character_context
description="Custom context block",
role="system"
)
# → Returns component with allocated ID (e.g., 1001)
# Get component by ID or key
comp = registry.get_component(1001)
comp = registry.get_component_by_key("my_context")
# Update component
registry.update_component(1001, content="Updated content...")
# Delete component
registry.delete_component(1001)
# List components
all_comps = registry.list_components(include_static=True) # Sorted by ID
pluggable = registry.list_pluggable_components()
after_char = registry.list_components_after(1000) # Range 1001-1999
# Move component to different position
registry.move_component(1001, new_after_static=2000)
Template ↔ Component Bridge
# Apply template content to existing component
registry.apply_template_to_component("my_template", component_id=1001)
# Save component content as reusable template
registry.save_component_as_template(
component_id=1001,
template_key="saved_from_component",
name="Saved Component Template"
)
# Convert to PromptComponent dataclass for assembly
prompt_component = registry.component_to_prompt_component(1001)
Export/Import
# Export for sharing
json_data = registry.export_template_json("my_template")
json_data = registry.export_component_json(1001)
# Import from JSON
registry.import_template_json(data, overwrite=False)
registry.import_component_json(data, overwrite=False)
5. Runtime Assembly Flow
Tick Event
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ Collect Components (sorted by ID) │
├──────────────────────────────────────────────────────────────────┤
│ │
│ 0: System Prompt ← Rendered from template │
│ 1: (pluggable) ← User component if exists │
│ 2: (pluggable) ← User component if exists │
│ ... │
│ 1000: Character Context ← Persona, project, session memory │
│ 1001: (pluggable) ← User component if exists │
│ ... │
│ 1500: Entity Context ← O-Mem working memory │
│ ... │
│ 2000: Semantic Memories ← Mem0 retrieval results │
│ ... │
│ 7000: Tool Result ← Previous tool execution result │
│ │
└──────────────────────────────────────────────────────────────────┘
│
▼
Filter by enabled=True
│
▼
Render placeholders
│
▼
Convert to LLM message format by role
│
▼
Send to UnifiedLLMClient
6. ID Allocation Details
When creating a pluggable component:
def allocate_pluggable_id(existing_ids: list[int], after_static: int) -> int:
"""
Find next available ID in range (after_static + 1, after_static + 1000).
Example:
after_static=1000, existing=[1001, 1002]
→ Returns 1003
after_static=1000, existing=[]
→ Returns 1001
"""
Range limits:
- Each static component has 999 pluggable slots
- If a range fills up,
ValueErroris raised - Use
move_component()to relocate if needed
7. Data Storage
Registry Script Attributes
registry.db.templates = {
"template_key": {
"key": str,
"name": str,
"description": str,
"content": str,
"placeholders": list[str],
"category": str,
"is_builtin": False,
"created": datetime,
"updated": datetime,
},
...
}
registry.db.components = {
component_id: {
"id": int,
"key": str,
"name": str,
"description": str,
"content": str,
"role": str,
"after_static": int,
"is_static": False,
"created": datetime,
"updated": datetime,
},
...
}
Key Files
| File | Lines | Purpose |
|---|---|---|
prompt_components.py |
1-304 | PromptComponent dataclass, static definitions, ID utilities |
prompt_templates.py |
1-300 | PromptTemplate dataclass, built-in templates, rendering |
prompt_registry.py |
1-983 | PromptRegistry script, CRUD operations |
See also: Architecture-Context-System | Architecture-Core-Engine | Data-Flow-02-ReAct-Loop