← Volver al listado de tecnologías

Capítulo 8: Manejo de Sesiones

Por: Artiko
claudeagent-sdksesionescontexto

Capítulo 8: Manejo de Sesiones

¿Qué son las Sesiones?

Las sesiones permiten mantener el contexto entre múltiples consultas. El agente recuerda:

flowchart TD
    subgraph Sesion["SESIÓN"]
        Q1["Query 1: Lee el archivo main.py"]
        Q1 --> C1["Contexto: main.py"]
        Q2["Query 2: ¿Qué funciones tiene?"]
        C1 --> Q2
        Q2 --> C2["Contexto + análisis<br/>Recuerda main.py"]
        Q3["Query 3: Agrega una función nueva"]
        C2 --> Q3
        Q3 --> C3["Contexto completo<br/>Conoce la estructura"]
    end

Capturar Session ID

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions

async def main():
    session_id = None

    # Primera consulta
    async for msg in query(
        prompt="Lee el archivo config.py",
        options=ClaudeAgentOptions(allowed_tools=["Read"])
    ):
        # Captura el session_id del mensaje init
        if hasattr(msg, 'subtype') and msg.subtype == 'init':
            session_id = msg.session_id
        print(msg)

    print(f"Session ID: {session_id}")
    return session_id

session_id = asyncio.run(main())

Reanudar una Sesión

async def continuar_sesion(session_id: str):
    # Reanuda con el contexto anterior
    async for msg in query(
        prompt="¿Qué variables de configuración encontraste?",
        options=ClaudeAgentOptions(resume=session_id)
    ):
        print(msg)

TypeScript

import { query } from "@anthropic-ai/claude-agent-sdk";

let sessionId: string | undefined;

// Primera consulta
for await (const message of query({
  prompt: "Lee config.py",
  options: { allowedTools: ["Read"] }
})) {
  if (message.type === "system" && message.subtype === "init") {
    sessionId = message.session_id;
  }
}

// Segunda consulta (misma sesión)
for await (const message of query({
  prompt: "¿Qué encontraste?",
  options: { resume: sessionId }
})) {
  console.log(message);
}

Ejemplo: Asistente de Desarrollo

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions

class AsistenteDesarrollo:
    def __init__(self, proyecto: str):
        self.proyecto = proyecto
        self.session_id = None
        self.options = ClaudeAgentOptions(
            allowed_tools=["Read", "Write", "Edit", "Glob", "Grep"],
            permission_mode="acceptEdits",
            cwd=proyecto
        )

    async def iniciar(self):
        async for msg in query(
            prompt="Analiza la estructura de este proyecto",
            options=self.options
        ):
            if hasattr(msg, 'subtype') and msg.subtype == 'init':
                self.session_id = msg.session_id
            if hasattr(msg, 'result'):
                print(msg.result)

    async def preguntar(self, pregunta: str):
        if not self.session_id:
            raise ValueError("Primero inicia la sesión")

        options = ClaudeAgentOptions(
            resume=self.session_id,
            allowed_tools=["Read", "Write", "Edit", "Glob", "Grep"],
            permission_mode="acceptEdits"
        )

        async for msg in query(prompt=pregunta, options=options):
            if hasattr(msg, 'result'):
                return msg.result

async def main():
    asistente = AsistenteDesarrollo("/mi/proyecto")
    await asistente.iniciar()

    respuesta = await asistente.preguntar("¿Cuáles son los archivos principales?")
    print(respuesta)

    respuesta = await asistente.preguntar("Agrega logging al archivo principal")
    print(respuesta)

asyncio.run(main())

Fork de Sesiones

Crea una rama del contexto para explorar diferentes alternativas:

flowchart TD
    Base["Sesión Original<br/>Contexto Base"]
    Base --> ForkA["Fork A<br/>Opción 1"]
    Base --> ForkB["Fork B<br/>Opción 2"]
# Después de tener session_id base
async def explorar_alternativas(session_id_base: str):
    # Fork A: Una aproximación
    async for msg in query(
        prompt="Implementa usando funciones",
        options=ClaudeAgentOptions(
            resume=session_id_base,
            allowed_tools=["Read", "Write"]
        )
    ):
        print("[Fork A]", msg)

    # Fork B: Otra aproximación (desde el mismo punto)
    async for msg in query(
        prompt="Implementa usando clases",
        options=ClaudeAgentOptions(
            resume=session_id_base,
            allowed_tools=["Read", "Write"]
        )
    ):
        print("[Fork B]", msg)

Persistir Sesiones

Guarda el session_id para reanudar después:

import json

def guardar_sesion(session_id: str, metadata: dict):
    with open("sesion.json", "w") as f:
        json.dump({
            "session_id": session_id,
            "metadata": metadata
        }, f)

def cargar_sesion() -> str:
    with open("sesion.json", "r") as f:
        data = json.load(f)
        return data["session_id"]

Ejemplo: Chatbot con Memoria

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions

class Chatbot:
    def __init__(self):
        self.session_id = None

    async def chat(self, mensaje: str) -> str:
        options = ClaudeAgentOptions(
            allowed_tools=["Read", "WebSearch"],
            system_prompt="Eres un asistente amigable"
        )

        if self.session_id:
            options = ClaudeAgentOptions(
                resume=self.session_id,
                allowed_tools=["Read", "WebSearch"]
            )

        resultado = None
        async for msg in query(prompt=mensaje, options=options):
            if hasattr(msg, 'subtype') and msg.subtype == 'init':
                self.session_id = msg.session_id
            if hasattr(msg, 'result'):
                resultado = msg.result

        return resultado

async def main():
    bot = Chatbot()

    print("Chatbot iniciado. Escribe 'salir' para terminar.")

    while True:
        mensaje = input("Tú: ")
        if mensaje.lower() == 'salir':
            break

        respuesta = await bot.chat(mensaje)
        print(f"Bot: {respuesta}")

asyncio.run(main())

Compactación Automática

El SDK compacta automáticamente cuando el contexto crece demasiado:

flowchart TD
    Original["Contexto Original (muy largo)<br/>[Mensaje 1] [Mensaje 2] ... [Mensaje 100]"]
    Original -->|Compactación| Compacto["[Resumen 1-90] [Mensaje 91-100]"]

Resumen