27%

1.7 Session State and Resumption

Session State คืออะไร

Session State คือข้อมูลที่ agent สะสมระหว่างทำงาน — conversation history, intermediate results, decisions ที่ตัดสินไปแล้ว, files ที่แก้ไข — ทั้งหมดนี้รวมกันเป็น “state” ของ session ปัจจุบัน ปัญหาคือ: ถ้า session ถูก interrupt (network error, timeout, context window เต็ม, user หยุดกลางคัน) state เหล่านี้จะหายไป — ถ้าไม่มีกลไก persist

Resumption คือความสามารถในการกลับมาทำงานต่อจากจุดที่หยุดไป — โดยไม่ต้องเริ่มใหม่ทั้งหมด เหมือน save game ที่โหลดมาเล่นต่อได้

State Types

1. Conversation State

Messages ที่สะสมมาทั้ง session:

# Conversation state = list of messages
state = {
    "messages": [
        {"role": "user", "content": "สร้าง REST API สำหรับ todo app"},
        {"role": "assistant", "content": "...", "tool_use": [...]},
        {"role": "user", "content": [{"type": "tool_result", ...}]},
        # ... more turns
    ]
}

2. Task State

Progress ของ task ที่กำลังทำ:

state = {
    "task": "Build todo API",
    "plan": ["setup project", "create models", "create routes", "add tests"],
    "completed_steps": ["setup project", "create models"],
    "current_step": "create routes",
    "artifacts": {
        "models.py": "created",
        "routes.py": "in_progress"
    }
}

3. Decision State

การตัดสินใจที่ agent ทำไปแล้ว (ไม่ต้องถามซ้ำ):

state = {
    "decisions": {
        "framework": "FastAPI",
        "database": "PostgreSQL",
        "auth_method": "JWT",
        "deployment": "Docker + Cloud Run"
    }
}

Persistence Patterns

Pattern 1: File-Based Checkpointing

บันทึก state ลง file ทุก N steps:

import json

CHECKPOINT_FILE = ".agent-checkpoint.json"

def save_checkpoint(state):
    with open(CHECKPOINT_FILE, "w") as f:
        json.dump(state, f, indent=2)

def load_checkpoint():
    try:
        with open(CHECKPOINT_FILE) as f:
            return json.load(f)
    except FileNotFoundError:
        return None

# ในแต่ละ iteration ของ agentic loop
for step in plan:
    result = execute_step(step)
    state["completed_steps"].append(step)
    state["results"][step] = result
    save_checkpoint(state)  # persist ทุก step

Pattern 2: Context Summarization

เมื่อ context window ใกล้เต็ม สรุป history แล้วเริ่ม session ใหม่ด้วย summary:

def summarize_and_continue(messages, current_task):
    # สรุป conversation ที่ผ่านมา
    summary = client.messages.create(
        model="claude-sonnet-4-20250514",
        messages=[{
            "role": "user",
            "content": f"สรุป conversation นี้เป็น bullet points:\n{format_messages(messages)}"
        }]
    )

    # เริ่ม session ใหม่ด้วย summary เป็น context
    new_messages = [{
        "role": "user",
        "content": f"""
Continue the following task. Here's the context from our previous conversation:

## Summary of Previous Work
{summary}

## Current Task
{current_task}

## What's Been Done
{list_completed_steps()}

## What's Left
{list_remaining_steps()}
"""
    }]

    return new_messages

Pattern 3: Workflow Script Resumption

Claude Code Workflows มี built-in resume mechanism:

// Workflow script
export const meta = {
    name: 'build-feature',
    description: 'Build a feature end-to-end',
    phases: [{title: 'Plan'}, {title: 'Build'}, {title: 'Test'}]
}

phase('Plan')
const plan = await agent("Create implementation plan")

phase('Build')
// ถ้า resume จาก runId — phase Plan จะใช้ cached result
// เริ่ม execute ใหม่ตั้งแต่ Build
const code = await agent(`Implement: ${plan}`)

phase('Test')
const tests = await agent(`Write tests for: ${code}`)

Resume ด้วย resumeFromRunId:

  • Agent calls ที่ prompt เหมือนเดิม → return cached result ทันที
  • Agent call แรกที่ต่าง (หรือ new) → execute ใหม่ตั้งแต่จุดนั้น

Handling Interruptions

Graceful Shutdown

import signal

shutdown_requested = False

def handle_signal(signum, frame):
    global shutdown_requested
    shutdown_requested = True

signal.signal(signal.SIGINT, handle_signal)
signal.signal(signal.SIGTERM, handle_signal)

# ใน agentic loop
for step in remaining_steps:
    if shutdown_requested:
        save_checkpoint(current_state)
        print("Saved checkpoint. Resume later with --resume")
        break
    execute_step(step)

Idempotent Operations

ออกแบบ operations ให้ทำซ้ำได้อย่างปลอดภัย:

def create_file_if_not_exists(path, content):
    """Idempotent — safe to retry"""
    if os.path.exists(path):
        return "already exists"
    write_file(path, content)
    return "created"

Key Concepts

  • Checkpoint Granularity — save ถี่เกินไป = overhead มาก; save น้อยเกินไป = เสีย progress มากเมื่อ crash
  • State Minimality — persist เฉพาะข้อมูลที่ recover ไม่ได้จาก source อื่น (ไม่ต้อง save ทุกอย่าง)
  • Idempotency — operations ที่ทำซ้ำแล้วได้ผลเหมือนเดิม ทำให้ resume safe
  • Context Compression — summarize เพื่อ fit ใน context window ใหม่ แต่ต้องไม่เสียข้อมูลสำคัญ

Exam Tips

  • เข้าใจว่า resume mechanism ของ Workflow scripts ทำงานอย่างไร (cached results + same prompt = cache hit)
  • Context summarization เป็น trade-off: เสีย detail แต่ได้ continuation
  • Idempotent operations สำคัญมากสำหรับ resumable agents — ถ้า operation ไม่ idempotent ต้อง track ว่าทำไปแล้วหรือยัง
  • ข้อสอบอาจถามว่า state อะไรบ้างที่ต้อง persist — ตอบ: decisions, completed steps, intermediate results ที่ expensive ในการ recompute
  • stop_reason: "max_tokens" = context window เต็ม = ต้อง summarize and continue