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.3.0.tar.gz (469.1 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.3.0-py3-none-any.whl (392.3 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for personaut-0.3.0.tar.gz
Algorithm Hash digest
SHA256 acf3ad98d37971460e1395e46a8c9056bfd2ef6a93e7cd9bc75ccd1c076676b8
MD5 df1254206da73ecd74a8d871adbb76a2
BLAKE2b-256 dc7eeab5cb200a6801de97469a2a5c0dc3c652965ba988d8d6f640e0d0625f92

See more details on using hashes here.

Provenance

The following attestation bundles were made for personaut-0.3.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.3.0-py3-none-any.whl.

File metadata

  • Download URL: personaut-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 392.3 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.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b1cfe8f5e0413bc269f10d4f059c4cb8dab403c1e4942c4457dfea795abfd7c7
MD5 a0ce548d268ffe9defa8bfa645ae3385
BLAKE2b-256 9926877e645f5a68d66d8d2a5a2d1dc01497d8fc67a0438d65858bd19a84a866

See more details on using hashes here.

Provenance

The following attestation bundles were made for personaut-0.3.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