How PersonalityProvider Manages Agent Personality and System Prompts in Heurist Agent Framework

The PersonalityProvider class assembles dynamic system prompts by combining a base configuration with randomly sampled personality traits from a YAML file, ensuring each LLM interaction receives consistent instructions with varied character flavor.

The PersonalityProvider in the heurist-network/heurist-agent-framework serves as the central component for defining how AI agents behave and respond. By managing both static system instructions and dynamic personality attributes, this class enables developers to create agents with consistent core behaviors while maintaining variety in individual interactions.

Understanding the PersonalityProvider Architecture

Configuration Loading via PromptConfig Singleton

The PersonalityProvider initializes by creating a PromptConfig singleton instance defined in core/config.py. This singleton reads the default prompts.yaml file located at agents/config/ and parses sections including system.base, character.basic_settings, character.interaction_styles, and character.name.

When instantiated with an optional config_path parameter, the provider attempts to load a custom YAML file and merge its contents into the singleton's dictionary. This merge capability allows projects to override default personalities without modifying core framework files, as implemented in lines 25-33 of core/components/personality_provider.py.

Core Methods for Personality Retrieval

The class exposes several getter methods that interface directly with the PromptConfig singleton:

  • get_system_prompt() forwards to PromptConfig.get_system_prompt(), returning the system.base value from the configuration
  • get_name() retrieves the character identifier from character.name
  • get_basic_settings() and get_interaction_styles() return the raw lists defined under their respective configuration keys

These methods provide direct access to personality components while maintaining abstraction from the underlying YAML structure.

How PersonalityProvider Builds System Prompts

Sampling Random Personality Traits

The get_formatted_personality() method (lines 53-65 in core/components/personality_provider.py) implements the core personality randomization logic. This method:

  1. Retrieves the base system prompt as the foundation
  2. Randomly samples up to two items from the basic_settings list
  3. Randomly samples up to two items from the interaction_styles list
  4. Concatenates these sampled traits into a "settings" clause

This sampling approach ensures that each conversation initialization receives a unique combination of personality attributes while maintaining the core behavioral constraints defined in the base prompt.

Formatting the Final Prompt String

The method appends the sampled traits to the base system prompt using a structured format. The final output combines:

  • The stable system.base instructions (defining task constraints and capabilities)
  • The dynamic personality clause (providing behavioral flavor and interaction style)

This concatenated string serves as the complete system prompt transmitted to the LLM during chat.completions.create or equivalent API calls.

Practical Implementation Examples

Creating a standard provider instance uses the default configuration:

from core.components.personality_provider import PersonalityProvider

# Initialize with default prompts.yaml

provider = PersonalityProvider()

# Retrieve base system prompt

system_prompt = provider.get_system_prompt()
print("System prompt:", system_prompt)

# Get agent name

agent_name = provider.get_name()
print("Agent name:", agent_name)

To generate a dynamic personality prompt for LLM integration:


# Get formatted personality with random traits

formatted_prompt = provider.get_formatted_personality()
print("\nFull prompt sent to LLM:\n", formatted_prompt)

For custom personality configurations:

custom_path = "/my/project/custom_prompts.yaml"
provider = PersonalityProvider(config_path=custom_path)

# Custom YAML merges with defaults

print(provider.get_formatted_personality())

Integration with an LLM client:

from openai import AsyncOpenAI

client = AsyncOpenAI()

async def chat(message: str):
    prompt = provider.get_formatted_personality()
    response = await client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": prompt},
            {"role": "user", "content": message}
        ]
    )
    return response.choices[0].message.content

Summary

  • The PersonalityProvider class in core/components/personality_provider.py centralizes agent personality management and system prompt generation.
  • It utilizes a PromptConfig singleton to load YAML configurations from agents/config/prompts.yaml, supporting custom config paths for project-specific overrides.
  • The get_formatted_personality() method constructs dynamic prompts by combining a stable base system prompt with randomly sampled traits from basic_settings and interaction_styles.
  • This architecture ensures consistent core behavior while providing variety in agent personality across different conversations.

Frequently Asked Questions

What file format does PersonalityProvider use for configuration?

The PersonalityProvider uses YAML files for configuration, specifically expecting a prompts.yaml structure. By default, it loads from agents/config/prompts.yaml, which contains nested sections like system.base, character.name, character.basic_settings, and character.interaction_styles. The provider can also accept custom YAML paths via the config_path parameter during initialization.

How does PersonalityProvider ensure variety in agent responses?

Variety is achieved through the get_formatted_personality() method, which randomly samples up to two items from the basic_settings list and up to two items from the interaction_styles list each time it is called. These sampled traits are appended to the base system prompt, creating a unique personality flavor for every conversation initialization while maintaining the core behavioral constraints defined in the stable system.base configuration.

Can I override the default personality configuration?

Yes, the PersonalityProvider supports configuration overrides through the optional config_path parameter in its constructor. When provided, the provider attempts to load the specified YAML file and merge its contents into the PromptConfig singleton's dictionary. This merge capability allows projects to customize personality traits, interaction styles, or system prompts without modifying the core framework files in agents/config/.

Where is the system prompt base text defined?

The base system prompt text is defined in the system.base section of the prompts.yaml configuration file. The PersonalityProvider retrieves this value through the get_system_prompt() method, which internally calls PromptConfig.get_system_prompt() as implemented in core/config.py (lines 50-52). This base text provides the stable foundation upon which dynamic personality traits are layered.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →