WalkXR-AI / Paul-Game-Jam-Phase-2.5 / src / schemas / state.py
state.py
Raw
from __future__ import annotations

from typing import Any, TypedDict

from langchain_core.messages import BaseMessage


class EmotionSnapshot(TypedDict, total=False):
    """Single-turn emotion measurement."""

    turn: int
    valence: float  # -1 (negative) to +1 (positive)
    arousal: float  # 0 (calm) to 1 (intense)
    label: str  # e.g. "anxious", "hopeful", "neutral"


class UserMemory(TypedDict, total=False):
    """User state memory accumulated per turn."""

    # Trust & rapport
    confidence_level: float  # 0~1, how much James trusts the user
    rapport_score: float  # 0~1, overall relationship quality

    # Emotion tracking
    emotion_trajectory: list[EmotionSnapshot]
    dominant_emotion: str  # most frequent emotion label

    # Conversation flow
    current_conversation_stage: str  # opening / developing / deepening / closing
    stage_history: list[str]  # track stage transitions

    # Behavioral analysis
    key_observations: list[str]
    empathy_hits: int  # count of empathetic responses
    empathy_misses: int  # count of insensitive/cliché responses
    empathy_ratio: float  # hits / (hits + misses)

    # Engagement
    avg_response_length: float  # average user message length
    silence_count: int  # short/empty responses (disengagement signal)

    # NPC internal state
    npc_openness: float  # 0~1, how open James is being
    npc_mood: str  # guarded / cautious / warming / open / withdrawn


class AgentOutput(TypedDict, total=False):
    """LLM call result."""

    response: str  # NPC dialogue
    should_end_turn: bool  # Whether to end the conversation
    next_step: str  # reflection / continue
    emotion_assessment: dict[str, Any]  # User emotion assessment
    observation: str  # Observation for this turn
    empathy_quality: str  # "hit" / "miss" / "neutral"
    trust_shift: float  # -0.3 to +0.3, how much trust changed this turn
    npc_internal_mood: str  # James's internal emotional state


class WalkState(TypedDict, total=False):
    """LangGraph full state."""

    # Conversation
    messages: list[BaseMessage]
    user_input: str

    # Scenario
    scenario: dict[str, Any]

    # Turn management
    turn_index: int

    # Memory
    memory: UserMemory

    # LLM output
    agent_output: AgentOutput

    # Reflection
    reflection_result: str

    # Error
    error: str | None