Skip to main content

A Python SDK for creating and simulating AI personas with emotional states, personality traits, and memory

Project description

Personaut PDK

Python 3.10+ License Hatch

A Python SDK for creating and simulating AI personas with emotional states, personality traits, memories, and relationships.

Overview

Personaut PDK enables you to create rich, psychologically-grounded AI personas that can participate in:

  • Conversations: Multi-party dialogues with realistic emotional dynamics
  • Surveys: Persona-driven questionnaire responses
  • Outcome Analysis: Simulation-based prediction of behavioral outcomes
  • Live Interactions: Real-time chat with modality-specific interfaces

Features

  • 🎭 36 Emotional States - Fine-grained emotional modeling across 6 categories
  • 🧠 17 Personality Traits - Based on the 16PF psychological model
  • 📍 Situational Facts - Structured context with 8 categories and LLM extraction
  • 💾 Vector Memory - Semantic memory retrieval with trust-gated access
  • 🔗 Relationships - Trust-based relationship dynamics
  • 🎯 Triggers & Masks - Context-aware behavioral modifications
  • 🚀 Live Server - FastAPI backend + Flask UI for interactive sessions

Installation

pip install personaut

Optional Dependencies

# For Gemini model provider
pip install personaut[gemini]

# For AWS Bedrock provider
pip install personaut[bedrock]

# For live interaction server
pip install personaut[server]

# For development
pip install personaut[dev]

# Install everything
pip install personaut[all]

Quick Start

Creating an Individual

import personaut

# Create an individual with personality traits and emotional state
sarah = personaut.create_individual(
    name="Sarah",
    traits={"warmth": 0.8, "dominance": 0.4, "sensitivity": 0.7},
    emotional_state={"cheerful": 0.6, "curious": 0.5},
)

# Update emotional state
sarah.change_emotion("anxious", 0.3)

# Access traits
print(sarah.get_high_traits())  # [('warmth', 0.8), ...]

# Get dominant emotion (respects active mask)
print(sarah.get_dominant_emotion())  # ('cheerful', 0.6)

Using Masks for Contextual Behavior

from personaut.masks import PROFESSIONAL_MASK

# Add a professional mask
sarah.add_mask(PROFESSIONAL_MASK)
sarah.activate_mask("professional")

# Emotional state is now filtered through the mask
modified_state = sarah.get_emotional_state()  # Suppresses strong emotions

# Get raw state without mask
raw_state = sarah.get_raw_emotional_state()

Running a Conversation Simulation

import personaut

# Create individuals
sarah = personaut.create_individual(name="Sarah")
mike = personaut.create_individual(name="Mike")

# Create situation
situation = personaut.situation.create_situation(
    type=personaut.types.modality.TEXT_MESSAGE,
    description='Catching up after a long time'
)

# Create and run simulation
simulation = personaut.simulation.create_simulation(
    situation=situation,
    individuals=[sarah, mike],
    type=personaut.simulations.types.CONVERSATION,
    style=personaut.simulations.styles.SCRIPT
)

simulation.run(num=5, dir='./output/')

Situational Facts

from personaut.facts import FactExtractor, LLMFactExtractor

# Regex-based extraction (fast, deterministic)
extractor = FactExtractor()
ctx = extractor.extract(
    "A busy coffee shop in downtown Miami around 3pm. "
    "80% capacity with a line of 5 people."
)
print(ctx.get_value("venue_type"))       # "coffee shop"
print(ctx.get_value("capacity_percent")) # 80

# LLM-based extraction (richer, more nuanced)
llm_extractor = LLMFactExtractor(llm_client=your_client)
ctx = await llm_extractor.extract(
    "We grabbed coffee at the corner spot. Super packed, great vibe."
)

# Generate embedding text
print(ctx.to_embedding_text())

Live Interactive Chat

import personaut
from personaut.server import LiveInteractionServer

# Create server and add individual
server = LiveInteractionServer()
server.add_individual(sarah)

# Start server
server.start(api_port=8000, ui_port=5000)

# Access:
# - UI: http://localhost:5000
# - API: http://localhost:8000/docs

Emotional System

The emotion system models 36 discrete emotions organized into 6 categories:

Category Emotions
Anger/Mad hostile, hurt, angry, selfish, hateful, critical
Sad/Sadness guilty, ashamed, depressed, lonely, bored, apathetic
Fear/Scared rejected, confused, submissive, insecure, anxious, helpless
Joy/Happiness excited, sensual, energetic, cheerful, creative, hopeful
Powerful/Confident proud, respected, appreciated, important, faithful, satisfied
Peaceful/Calm content, thoughtful, intimate, loving, trusting, nurturing
from personaut.emotions import EmotionalState, ANXIOUS, HOPEFUL

state = EmotionalState()
state.change_emotion(ANXIOUS, 0.6)
state.change_emotion(HOPEFUL, 0.8)

# Query dominant emotion
dominant, value = state.get_dominant()  # ('hopeful', 0.8)

Personality Traits

Based on the 16PF model with 17 traits that influence emotional transitions:

from personaut.traits import create_trait, WARMTH, EMOTIONAL_STABILITY

# High warmth = more approachable, friendly
warmth = create_trait(trait=WARMTH, value=0.8)

# High emotional stability = less reactive to stress
stability = create_trait(trait=EMOTIONAL_STABILITY, value=0.7)

Memory System

Store and retrieve memories with emotional context and trust-gated access:

from personaut.memory import (
    create_individual_memory,
    create_shared_memory,
    create_private_memory,
    InMemoryVectorStore,
    search_memories,
)

# Individual memory with situational context
memory = create_individual_memory(
    owner_id="sarah_123",
    description="Met Alex at the coffee shop",
    context=ctx,  # SituationalContext from facts extraction
    salience=0.8,
)

# Shared memory between multiple people
shared = create_shared_memory(
    description="Team dinner at the Italian restaurant",
    participant_ids=["sarah_123", "mike_456"],
    perspectives={
        "sarah_123": "Great food, but Mike was late",
        "mike_456": "Traffic was terrible",
    },
)

# Private memory with trust threshold
private = create_private_memory(
    owner_id="sarah_123",
    description="My anxiety about the presentation",
    trust_threshold=0.8,  # Only shared with high-trust individuals
)

# Store and search memories
store = InMemoryVectorStore()
store.store(memory, embedding=[...])  # Vector from embedding model

results = search_memories(
    store=store,
    query="coffee meetings",
    embed_func=my_embed_function,
    trust_level=0.5,  # Filters private memories
)

Masks and Triggers

Masks modify emotional expression based on context. Triggers activate responses when conditions are met:

from personaut.masks import (
    create_mask,
    PROFESSIONAL_MASK,
    STOIC_MASK,
)
from personaut.triggers import (
    create_emotional_trigger,
    create_situational_trigger,
)

# Apply professional mask in office settings
if PROFESSIONAL_MASK.should_trigger("Going to an office meeting"):
    modified_state = PROFESSIONAL_MASK.apply(emotional_state)
    # Suppresses anger, boosts composure

# Create custom mask
interview_mask = create_mask(
    name="interview",
    emotional_modifications={"anxious": -0.3, "content": 0.2},
    trigger_situations=["interview", "formal"],
)

# Emotional trigger: activate stoic mask when anxiety is high
anxiety_trigger = create_emotional_trigger(
    description="High anxiety response",
    rules=[{"emotion": "anxious", "threshold": 0.8, "operator": ">"}],
    response=STOIC_MASK,
)

if anxiety_trigger.check(emotional_state):
    calmed_state = anxiety_trigger.fire(emotional_state)

# Situational trigger: increase anxiety in dark spaces
dark_trigger = create_situational_trigger(
    description="Dark space phobia",
    keywords=["dark", "basement", "cave"],
    response={"anxious": 0.3, "helpless": 0.2},
)

Relationships

Model trust dynamics between individuals and query relationship networks:

from personaut.relationships import (
    create_relationship,
    RelationshipNetwork,
    get_trust_level,
    TrustLevel,
)

# Create relationship with asymmetric trust
rel = create_relationship(
    individual_ids=["sarah", "mike"],
    trust={"sarah": 0.8, "mike": 0.5},  # Sarah trusts Mike more
    history="Roommates in college for 2 years",
    relationship_type="friends",
)

# Query trust
trust = rel.get_trust("sarah", "mike")  # 0.8
mutual = rel.get_mutual_trust("sarah", "mike")  # 0.65

# Update trust after an event
rel.update_trust("mike", "sarah", 0.2, "helped during crisis")

# Check trust level
level = rel.get_trust_level("sarah", "mike")
if level == TrustLevel.HIGH:
    # Sarah will share private memories with Mike

# Build a relationship network
network = RelationshipNetwork()
network.add_relationship(rel)
network.add_relationship(create_relationship(["mike", "carol"], trust={"mike": 0.7, "carol": 0.6}))

# Find connection path
path = network.find_path("sarah", "carol")  # ['sarah', 'mike', 'carol']
path_trust = network.calculate_path_trust(path)  # Trust decays along path

Situations

Define the context for simulations with modality, location, and structured context:

from datetime import datetime
from personaut.situations import (
    create_situation,
    SituationContext,
    create_environment_context,
)
from personaut.types.modality import Modality

# Create a situation
situation = create_situation(
    modality=Modality.IN_PERSON,
    description="Meeting at a coffee shop to discuss a project",
    time=datetime.now(),
    location="Miami, FL",
    context={"atmosphere": "relaxed"},
)

# Query modality characteristics
if situation.is_synchronous():
    # Real-time communication expected
    traits = situation.get_modality_traits()
    print(f"Visual cues: {traits['visual_cues']}")

# Build structured context with validation
ctx = create_environment_context(
    lighting="dim",
    noise_level="quiet",
    indoor=True,
    private=True,
)
result = ctx.validate()
if result.valid:
    # Context data meets schema requirements
    pass

Documentation

Document Description
PERSONAS.md Main agent guidelines
docs/EMOTIONS.md Emotion system reference
docs/TRAITS.md Trait system reference
docs/FACTS.md Situational context and fact extraction
docs/MEMORY.md Memory system and vector storage
docs/PROMPTS.md Prompt generation
docs/SIMULATIONS.md Simulation types
docs/LIVE_INTERACTIONS.md Server architecture
docs/STYLE_GUIDE.md Code conventions

Development

# Clone repository
git clone https://github.com/personaut/python-pdk.git
cd python-pdk

# Install with dev dependencies
pip install hatch
hatch shell

# Run tests
hatch test

# Run linters
hatch fmt

# Type check
hatch run type

See CONTRIBUTING.md for full development guidelines.

Requirements

License

Apache License 2.0 - see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

personaut-0.2.0.tar.gz (468.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

personaut-0.2.0-py3-none-any.whl (389.6 kB view details)

Uploaded Python 3

File details

Details for the file personaut-0.2.0.tar.gz.

File metadata

  • Download URL: personaut-0.2.0.tar.gz
  • Upload date:
  • Size: 468.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for personaut-0.2.0.tar.gz
Algorithm Hash digest
SHA256 95bec046614e8cdc4b00f63825942098cc23f3a76e3ad4d599e1d3887cba80a9
MD5 5b8b7a1996fb7378e0bc0f43824ee79f
BLAKE2b-256 3625f75279dd8ce5f29028b1beb0eaff19bcc31b2a5facbb0fcab752dde6f285

See more details on using hashes here.

Provenance

The following attestation bundles were made for personaut-0.2.0.tar.gz:

Publisher: publish.yml on Personaut/python-pdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file personaut-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: personaut-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 389.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for personaut-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fcbdf4732d599120678db22bc05bf06baed5ed2a937a3227ce77b8b4151975b7
MD5 29927173abf37febc0e5d9815c395a85
BLAKE2b-256 6d2677a1f85dd86b8ab4318953c9c4883f700651928061dd37f4374047bbfea2

See more details on using hashes here.

Provenance

The following attestation bundles were made for personaut-0.2.0-py3-none-any.whl:

Publisher: publish.yml on Personaut/python-pdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page