src — personas
src — personas
The src/personas module is the core of Grok's personality management system. It allows the agent to adopt different behaviors, expertise, and communication styles, making it adaptable to various development tasks and user preferences. This module provides a robust framework for defining, managing, and dynamically switching between agent personas.
Purpose and Features
The primary goal of the personas module is to enable flexible and context-aware customization of Grok's interactions. Key features include:
- Predefined Personas: A set of built-in personas (e.g.,
Senior Developer,Code Reviewer,Debugging Expert) that offer specialized capabilities. - Custom Persona Creation: Users can define their own personas, tailoring Grok's
systemPrompt,traits,expertise, andstyle. - Context-Aware Selection: Personas can be configured with
triggersthat automatically activate them based on user input, file types, or commands. - Dynamic Switching: The active persona can be changed manually or automatically during a conversation.
- Persistence: Custom personas are saved to disk, ensuring they persist across sessions.
- Hot-Reloading: Changes to custom persona files on disk are automatically detected and reloaded without restarting the application.
- System Prompt Generation: Dynamically constructs a comprehensive system prompt for the underlying LLM, incorporating the active persona's characteristics.
Core Concepts
The Persona Interface
At the heart of the module is the Persona interface, which defines the structure of an agent's personality:
export interface Persona {
id: string;
name: string;
description: string;
systemPrompt: string; class="hl-cmt">// The core instruction for the LLM
traits: PersonaTrait[]; class="hl-cmt">// e.g., helpfulness, precision
expertise: string[]; class="hl-cmt">// e.g., 39;software architecture39;, 39;debugging39;
style: PersonaStyle; class="hl-cmt">// e.g., verbosity, tone, codeStyle
examples?: ConversationExample[]; class="hl-cmt">// Few-shot examples
triggers?: PersonaTrigger[]; class="hl-cmt">// For auto-selection
isBuiltin: boolean;
isDefault: boolean;
createdAt: Date;
updatedAt: Date;
}
Supporting interfaces further define persona characteristics:
PersonaTrait: Quantifiable attributes (0-100) likehelpfulnessorprecision.PersonaStyle: Defines communication preferences such asverbosity,formality,tone,codeStyle, andexplanationDepth.ConversationExample: Pairs of user input and assistant responses for few-shot prompting.PersonaTrigger: Rules forautoSelectPersona, specifyingtype(keyword, fileType, command, context),pattern, andpriority.
Built-in vs. Custom Personas
The module distinguishes between:
- Built-in Personas: Defined within the
BUILTIN_PERSONASconstant inpersona-manager.ts. These are read-only and cannot be modified or deleted by users. They provide a set of curated, high-quality starting points. - Custom Personas: Created by users and stored as JSON files in a dedicated directory (default:
~/.codebuddy/personas). These are fully editable and deletable.
PersonaManager Class
The PersonaManager class is the central orchestrator for all persona-related operations. It extends EventEmitter to broadcast changes in persona state.
Initialization and Lifecycle
The PersonaManager is initialized upon instantiation:
- Constructor: Takes an optional
PersonaConfigto set the initial active persona, auto-switch preference, and custom personas directory. It then callsinitialize(). initialize():
- Ensures the
customPersonasDirexists on disk usingfs.ensureDir. - Loads all
BUILTIN_PERSONASinto its internalMap. - Calls
loadCustomPersonas()to read existing custom persona JSON files from disk. - Sets the
activePersonabased on the configuration (defaulting to 'default' if none specified or found). - Starts
startWatcher()to monitor the custom personas directory for changes.
loadCustomPersonas(): Reads all.jsonfiles from thecustomPersonasDir, parses them, and adds them to the internalpersonasmap. Invalid files are skipped.startWatcher(): Usesfs.watchto detect file system events (creation, modification, deletion) in thecustomPersonasDir. It debounces rapid events to prevent excessive reloads. Upon detecting a change to a.jsonfile:
- If a file is added/modified, it's reloaded, and a
persona:reloadedevent is emitted. - If a file is deleted, the persona is removed from memory, and if it was the active persona, the system switches to 'default'. A
persona:removedevent is emitted.
dispose(): Cleans up resources by closing the file system watcher and removing all event listeners. This is crucial for proper shutdown or resetting the singleton.
Key Functionality
Persona Management
createPersona(options): Creates a new custom persona, generates a unique ID, saves it as a JSON file tocustomPersonasDir, adds it to the internal map, and emitspersona:created.updatePersona(id, updates): Modifies an existing custom persona, updates its JSON file on disk, and emitspersona:updated. Built-in personas cannot be updated.deletePersona(id): Removes a custom persona's JSON file from disk and deletes it from the internal map. If the deleted persona was active, it switches to 'default'. Emitspersona:deleted. Built-in personas cannot be deleted.clonePersona(id, newName): Creates a new custom persona by copying an existing one, usingcreatePersonainternally.exportPersona(id): Returns the JSON string representation of a persona.importPersona(json): Parses a JSON string, validates it, generates a new unique ID, and creates a new custom persona usingcreatePersona.
Persona Selection and Retrieval
setActivePersona(id): Explicitly sets the active persona. If successful, it emits apersona:changedevent with the previous and current persona.getActivePersona(): Returns the currently activePersonaobject.getPersona(id): Retrieves a specific persona by its ID.getAllPersonas(): Returns an array of all loaded personas (built-in and custom).getBuiltinPersonas(): Returns an array of only built-in personas.getCustomPersonas(): Returns an array of only custom personas.autoSelectPersona(context): This method implements context-aware persona switching.- If
config.autoSwitchisfalse, it returns the current active persona. - It iterates through all available personas and their
triggers. - Triggers are matched against the provided
context(e.g.,messagekeywords,fileType,command). - The persona with the highest
prioritymatching trigger is selected. - If a new persona is selected,
setActivePersona()is called, triggering apersona:changedevent.
System Prompt Generation
buildSystemPrompt(additionalContext?): Constructs the complete system prompt that will be sent to the LLM. It starts with theactivePersona.systemPromptand dynamically appends instructions based on:PersonaStyleproperties (verbosity, tone, codeStyle).expertiseareas.ConversationExampleinteractions (few-shot prompting).- Any
additionalContextprovided by the caller.
Status and Configuration
formatStatus(): Generates a formatted string displaying the active persona and a list of all available personas, useful for CLI output.getConfig(): Returns the currentPersonaConfig.
Events
PersonaManager emits the following events:
persona:changed: When the active persona is switched (manual or auto-select).persona:created: When a new custom persona is successfully created.persona:updated: When an existing custom persona is modified.persona:deleted: When a custom persona is removed.persona:reloaded: When a custom persona file is changed on disk and reloaded.persona:removed: When a custom persona file is deleted from disk.
Singleton Access
The module provides a singleton pattern for PersonaManager to ensure a single, consistent state across the application:
getPersonaManager(config?): Returns the singleton instance ofPersonaManager. If an instance doesn't exist, it creates one.resetPersonaManager(): Disposes of the current singleton instance and sets it tonull, allowing a fresh instance to be created on the nextgetPersonaManagercall. This is primarily used for testing or application shutdown.
Integration with the System
The PersonaManager is a critical component that influences Grok's behavior across various interactions.
graph TD
subgraph PersonaManager
A[initialize()]
B[loadCustomPersonas()]
C[startWatcher()]
D[setActivePersona()]
E[autoSelectPersona()]
F[buildSystemPrompt()]
G[createPersona()]
H[updatePersona()]
I[deletePersona()]
end
J[App Startup] --> A
A --> B
A --> C
A --> D
K[User Input / Context] --> E
E --> D
L[Agent Executor] --> F
M[CLI / UI] --> G
M --> H
M --> I
C -- File Changes --> B
Key Integration Points:
- Agent Execution (
agent/execution/agent-executor.ts): - The
agent-executorretrieves thePersonaManagerinstance viagetPersonaManager(). - For each user message, it calls
autoSelectPersona()to potentially switch to a more relevant persona based on the conversation context. - Before sending a prompt to the LLM, it calls
buildSystemPrompt()to generate the complete, persona-infused system prompt. - Command Handlers (
commands/handlers/persona-handler.ts): - The
/personacommand handler directly interacts withPersonaManagermethods likesetActivePersona(),createPersona(),deletePersona(),getPersona(),getAllPersonas(), etc., to allow users to manage personas via the CLI. - Status Commands (
commands/handlers/missing-handlers.ts): - The status command handler uses
getPersonaManager()andgetActivePersona()(andformatStatus()) to display information about the current persona state. - Testing (
tests/persona-manager.test.ts): - The test suite thoroughly exercises all public and some private methods of
PersonaManager, including lifecycle, CRUD operations, auto-selection, and event emission.
Extending and Contributing
Adding New Built-in Personas
To add a new built-in persona:
- Define a new object conforming to
Omitin theBUILTIN_PERSONASarray withinsrc/personas/persona-manager.ts. - Ensure the
idis unique and descriptive. - Craft a detailed
systemPromptthat clearly defines the persona's role and instructions. - Populate
traits,expertise,style,examples, andtriggersto give the persona depth and enable effective auto-selection. - Set
isBuiltin: trueandisDefault: false(unless it's intended to replace the current default).
Creating Custom Personas
Users can create custom personas directly through the CLI (if implemented) or by manually creating JSON files in the ~/.codebuddy/personas directory. The PersonaManager will automatically detect and load these files.
Modifying the Persona Structure
Any changes to the Persona interface or its supporting interfaces (e.g., adding new fields to PersonaStyle or PersonaTrigger) will require:
- Updating the interface definitions in
src/personas/persona-manager.ts. - Adjusting
BUILTIN_PERSONASto include default values for new fields. - Modifying
createPersona()andupdatePersona()to handle new fields, including default values if necessary. - Updating
buildSystemPrompt()if new fields should influence the LLM prompt. - Reviewing
autoSelectPersona()if new trigger types are introduced. - Updating any UI or CLI components that interact with persona data.
- Updating relevant tests in
tests/persona-manager.test.ts.