1 Data Flow 09 Self Management Operations
blightbow edited this page 2025-12-08 03:55:12 +00:00

Data Flow 09: Self-Management Operations

Projects, Goals, and Session Memory Execution Flows


Overview

This document traces the execution flows for the assistant's self-management operations:

  • Project context swapping
  • Goal decomposition and rollup
  • Session memory with persona protection

1. Project Context Swap

Sequence: swap_project Execution

LLM calls swap_project(project_key="quest_design",
                       current_project_update="Walls 60% done",
                       reasoning="Player asked about quests")
    │
    ▼
SwapProjectTool.execute()
    │
    ├── 1. Validate target exists
    │       projects = character.db.projects
    │       if project_key not in projects["slots"]:
    │           return {error: "Project does not exist", available_projects: [...]}
    │
    ├── 2. Save current project state
    │       old_key = projects["active"]
    │       if old_key and current_project_update:
    │           projects["slots"][old_key]["context"] = current_project_update
    │           projects["slots"][old_key]["last_active"] = now()
    │           projects["slots"][old_key]["status"] = "paused"
    │
    ├── 3. Activate target project
    │       projects["active"] = project_key
    │       projects["slots"][project_key]["last_active"] = now()
    │       projects["slots"][project_key]["status"] = "active"
    │
    ├── 4. Persist changes
    │       character.db.projects = projects
    │
    └── 5. Return context for LLM
            return {
                old_project: "build_tavern",
                new_project: "quest_design",
                new_project_summary: "Design main quest line",
                new_project_context: "Current: Act 1 outline complete...",
            }

State Transition

┌─────────────────────────────────────────────────────────────────┐
│                     character.db.projects                       │
├─────────────────────────────────────────────────────────────────┤
│  BEFORE                          AFTER                          │
│  ──────                          ─────                          │
│  active: "build_tavern"          active: "quest_design"         │
│                                                                 │
│  slots:                          slots:                         │
│    build_tavern:                   build_tavern:                │
│      status: "active"                status: "paused"           │
│      context: "Walls 50%..."         context: "Walls 60%..."    │
│                                                                 │
│    quest_design:                   quest_design:                │
│      status: "paused"                status: "active"           │
│      context: "Act 1 complete"       context: "Act 1 complete"  │
└─────────────────────────────────────────────────────────────────┘

2. Goal Decomposition Flow

Sequence: add_goaldecompose_goal

LLM calls add_goal(description="Build a complete tavern", priority="high")
    │
    ▼
AddGoalTool.execute()
    │
    ├── Find script via search.search_script("ai_assistant")
    │
    ├── script.add_goal(description, priority)
    │       goal = {
    │           "id": f"goal_{tick_count}_{len(goals)}",
    │           "description": description,
    │           "priority": priority,
    │           "status": "active",
    │           "progress": 0,
    │           "parent_id": None,
    │           "subtask_ids": [],
    │       }
    │       script.db.current_goals.append(goal)
    │
    └── return {goal_id: "goal_42_0", ...}

Later, LLM calls decompose_goal(goal_id="goal_42_0")
    │
    ▼
DecomposeGoalTool.execute() [ASYNC_REQUIRED - uses @inlineCallbacks]
    │
    ├── Find parent goal
    │       parent = script.find_goal("goal_42_0")
    │
    ├── yield script.decompose_goal(goal_id)
    │       │
    │       ├── Build LLM prompt:
    │       │       "Break down this goal into 3-7 actionable subtasks:
    │       │        Goal: Build a complete tavern
    │       │        Return JSON array of subtask descriptions."
    │       │
    │       ├── yield llm_client.complete(prompt)
    │       │
    │       ├── Parse response → subtasks = ["Design layout", "Build walls", ...]
    │       │
    │       └── For each subtask:
    │               child = add_goal(subtask_desc, parent_id="goal_42_0")
    │               parent["subtask_ids"].append(child["id"])
    │
    └── return {
            goal_id: "goal_42_0",
            subtasks_created: 5,
            subtasks: [{id: "goal_42_1", description: "..."}, ...]
        }

Parent Progress Rollup

LLM calls update_goal(goal_id="goal_42_1", status="completed", progress=100)
    │
    ▼
UpdateGoalTool.execute()
    │
    ├── script.update_goal(goal_id, status, progress)
    │       │
    │       ├── Update subtask
    │       │       subtask = find_goal("goal_42_1")
    │       │       subtask["status"] = "completed"
    │       │       subtask["progress"] = 100
    │       │
    │       └── Trigger parent rollup
    │               update_parent_progress("goal_42_0")
    │                   │
    │                   ├── Collect subtask progress
    │                   │       subtasks = [find_goal(id) for id in parent["subtask_ids"]]
    │                   │       total = sum(s["progress"] for s in subtasks)
    │                   │       parent["progress"] = total / len(subtasks)
    │                   │
    │                   └── Check auto-completion
    │                           if all(s["status"] == "completed" for s in subtasks):
    │                               parent["status"] = "completed"
    │
    └── return {goal_id: "goal_42_1", message: "Goal updated"}

Goal State Example

After decomposition and partial completion:

script.db.current_goals = [
    {id: "goal_42_0", description: "Build tavern", progress: 40,
     subtask_ids: ["goal_42_1", "goal_42_2", "goal_42_3", "goal_42_4", "goal_42_5"]},

    {id: "goal_42_1", description: "Design layout",    progress: 100, status: "completed"},
    {id: "goal_42_2", description: "Build structure",  progress: 100, status: "completed"},
    {id: "goal_42_3", description: "Add furniture",    progress: 0,   status: "active"},
    {id: "goal_42_4", description: "Create bartender", progress: 0,   status: "active"},
    {id: "goal_42_5", description: "Write descriptions", progress: 0, status: "active"},
]

# Parent progress = (100 + 100 + 0 + 0 + 0) / 5 = 40%

3. Session Memory Lifecycle

Add with Persona Protection

LLM calls add_session_memory(memory_type="fact", content="I helped Alice")
    │
    ▼
AddSessionMemoryTool.execute()
    │
    ├── Check for self-referential patterns
    │       content_lower = content.lower()
    │       patterns = ["i helped", "i did", "i was", "i should", ...]
    │
    │       if any(pattern in content_lower for pattern in patterns):
    │           return {
    │               success: False,
    │               error: "Content appears to reference assistant actions",
    │               suggestion: "Rephrase in third-person...",
    │               rejected_content: "I helped Alice"
    │           }
    │
    └── [REJECTED - flow ends here]

LLM retries: add_session_memory(memory_type="fact",
                                 content="Player Alice completed the intro quest")
    │
    ▼
AddSessionMemoryTool.execute()
    │
    ├── Persona check passes (no self-reference detected)
    │
    ├── Get current session memory
    │       session_mem = character.db.session_memory
    │
    ├── Append to appropriate list
    │       if memory_type == "fact":
    │           session_mem["key_facts"].append(content)
    │       else:
    │           session_mem["learned_patterns"].append(content)
    │
    ├── Persist
    │       character.db.session_memory = session_mem
    │
    └── return {
            success: True,
            memory_type: "fact",
            added: "Player Alice completed the intro quest",
            total_facts: 5,
            total_patterns: 2
        }

Compaction Flow

LLM reviews memory and calls compact_session_memory(
    new_facts=["Alice is level 5 warrior", "Server has 10 active players"],
    new_patterns=["Players explore before asking for help"],
    summary="Consolidated 8 facts about players into 2 key facts"
)
    │
    ▼
CompactSessionMemoryTool.execute()
    │
    ├── Capture before state
    │       old_fact_count = len(session_mem["key_facts"])       # 8
    │       old_pattern_count = len(session_mem["learned_patterns"])  # 4
    │
    ├── Replace with compacted memory
    │       character.db.session_memory = {
    │           "key_facts": new_facts,                # 2 facts
    │           "learned_patterns": new_patterns,     # 1 pattern
    │           "completed_tasks": old["completed_tasks"],  # preserved
    │           "last_compacted": now(),
    │       }
    │
    └── return {
            before: {facts: 8, patterns: 4},
            after: {facts: 2, patterns: 1},
            summary: "Consolidated 8 facts..."
        }

4. Cross-System Coordination

Typical Multi-System Flow

Tick Event: Player asks "Can you help me build a tavern?"
    │
    ▼
1. Check current project
   list_projects() → No active project
    │
    ▼
2. Create project for context preservation
   create_project(
       project_key="player_tavern_build",
       summary="Help player build a tavern",
       initial_context="Player requested help. Location: north district..."
   )
    │
    ▼
3. Create goal for progress tracking
   add_goal(
       description="Complete player's tavern request",
       priority="high"
   )
    │
    ▼
4. Decompose into subtasks
   decompose_goal(goal_id="goal_X_0")
   → Subtasks: requirements, location, design, construction, furnishing
    │
    ▼
5. Work on first subtask, update progress
   update_goal(goal_id="goal_X_1", progress=50)
    │
    ▼
6. Record learned preferences
   add_session_memory(
       memory_type="fact",
       content="Player prefers rustic architectural style"
   )
    │
    ▼
7. Periodic context save
   update_project(
       context_update="Requirements gathered. Player wants 3 rooms..."
   )

Key Files

File Lines Purpose
tools/context.py 330-411 SwapProjectTool.execute()
tools/context.py 104-166 AddSessionMemoryTool.execute() with persona filter
tools/goals.py 90-114 UpdateGoalTool.execute()
tools/goals.py 134-158 DecomposeGoalTool.execute()
assistant_script.py 480-520 update_parent_progress()

See also: Architecture-Self-Management | Data-Flow-02-ReAct-Loop | Data-Flow-06-Tool-Execution