Configuración, personalización, ajustes de plataforma y referencias de API para Pi.

Compactación y resumen de ramas

Los LLM tienen ventanas de contexto limitadas. Cuando las conversaciones se alargan demasiado, Pi utiliza la compactación para resumir el contenido anterior y al mismo tiempo preservar el trabajo reciente. Esta página cubre tanto la autocompactación como branch summarization.

Archivos fuente (pi-mono):

Para las definiciones de TypeScript en su proyecto, inspeccione node_modules/@earendil-works/pi-coding-agent/dist/.

Descripción general

Pi tiene dos mecanismos de resumen:

Mecanismo Desencadenar Objetivo
Compactación El contexto supera el umbral, o /compact Resumir mensajes antiguos para liberar contexto
Resumen de sucursales /tree navegación Preservar el contexto al cambiar de sucursal

Ambos utilizan el mismo formato de resumen estructurado y realizan un seguimiento de las operaciones de archivos de forma acumulativa. Las solicitudes de compactación y resumen de bifurcación utilizan ID de sesión de enrutamiento nuevos y, cuando el proveedor las admite, deshabilitan las escrituras de caché de avisos porque es poco probable que estos avisos únicos se reutilicen.

Compactación

Cuando se activa

La compactación automática se activa cuando:

contextTokens > contextWindow - reserveTokens

De forma predeterminada, reserveTokens son 16384 tokens (configurables en ~/.pi/agent/settings.json o <project-dir>/.pi/settings.json). Esto deja espacio para la respuesta del LLM.

También puedes activarlo manualmente con /compact [instructions], donde las instrucciones opcionales centran el resumen.

Cómo funciona

  1. Buscar punto de corte: retroceda desde el mensaje más reciente, acumulando estimaciones de tokens hasta alcanzar keepRecentTokens (20k predeterminado, configurable en ~/.pi/agent/settings.json o <project-dir>/.pi/settings.json).
  2. Extraer mensajes: recopile mensajes desde el límite mantenido anterior (o inicio de sesión) hasta el punto de corte.
  3. Generar resumen: Llame a LLM para resumir con formato estructurado, pasando el resumen anterior como contexto iterativo cuando esté presente.
  4. Agregar entrada: Guarde CompactionEntry con resumen y firstKeptEntryId
  5. Recarga: Se recarga la sesión, usando resumen + mensajes desde firstKeptEntryId en adelante
Before compaction:

  entry:  0     1     2     3      4     5     6      7      8     9
        ┌─────┬─────┬─────┬─────┬──────┬─────┬──── ─┬──────┬─────┬─────┐
        │ hdr │ usr │ ass │ tool │ usr │ ass │ tool │ tool │ ass │ tool│
        └─────┴─────┴─────┴──────┴─────┴─────┴──────┴──────┴─────┴─────┘
                └────────┬───────┘ └──────────────┬──────────────┘
               messagesToSummarize            kept messages
                                   ↑
                          firstKeptEntryId (entry 4)

After compaction (new entry appended):

  entry:  0     1     2     3      4     5     6      7      8     9     10
        ┌─────┬─────┬─────┬─────┬──────┬─────┬──── ─┬──────┬─────┬─────┬─────┐
        │ hdr │ usr │ ass │ tool │ usr │ ass │ tool │ tool │ ass │ tool│ cmp │
        └─────┴─────┴─────┴──────┴─────┴─────┴──────┴──────┴─────┴─────┴─────┘
               └──────────┬──────┘ └──────────────────────┬───────────────────┘
                 not sent to LLM                    sent to LLM
                                                         ↑
                                              starts from firstKeptEntryId

What the LLM sees:

  ┌────────┬─────────┬─────┬─────┬──────┬──────┬─────┬──────┐
  │ system │ summary │ usr │ ass │ tool │ tool │ ass │ tool │
  └────────┴─────────┴─────┴─────┴──────┴──────┴─────┴──────┘
       ↑         ↑      └─────────────────┬────────────────┘
    prompt   from cmp          messages from firstKeptEntryId

En compactaciones repetidas, el tramo resumido comienza en el límite mantenido de la compactación anterior (firstKeptEntryId), no en la entrada de compactación en sí, y vuelve a la entrada después de la compactación anterior si esa entrada mantenida no se puede encontrar en el camino. Esto preserva los mensajes que sobrevivieron a la compactación anterior al incluirlos también en la siguiente pasada de resumen. Pi también vuelve a calcular tokensBefore a partir del contexto de sesión reconstruido antes de escribir el nuevo CompactionEntry, por lo que el recuento de tokens refleja el contexto real previo a la compactación que se reemplaza.

Giros divididos

Un "turno" comienza con un mensaje de usuario e incluye todas las respuestas del asistente y llamadas de herramientas hasta el siguiente mensaje de usuario. Normalmente, la compactación corta en los límites de las curvas.

Cuando un solo giro excede keepRecentTokens, el punto de corte llega a mitad del giro en un mensaje del asistente. Este es un "turno dividido":

Split turn (one huge turn exceeds budget):

  entry:  0     1     2      3     4      5      6     7      8
        ┌─────┬─────┬─────┬──────┬─────┬──────┬──────┬─────┬──────┐
        │ hdr │ usr │ ass │ tool │ ass │ tool │ tool │ ass │ tool │
        └─────┴─────┴─────┴──────┴─────┴──────┴──────┴─────┴──────┘
                ↑                                     ↑
         turnStartIndex = 1                  firstKeptEntryId = 7
                │                                     │
                └──── turnPrefixMessages (1-6) ───────┘
                                                      └── kept (7-8)

  isSplitTurn = true
  messagesToSummarize = []  (no complete turns before)
  turnPrefixMessages = [usr, ass, tool, ass, tool, tool]

Para turnos divididos, Pi genera dos resúmenes y los fusiona:

  1. Resumen del historial: contexto anterior (si corresponde)
  2. Resumen del prefijo de turno: la primera parte del turno dividido

Reglas de punto de corte

Los puntos de corte válidos son:

  • Mensajes de usuario
  • Mensajes del asistente
  • Mensajes de ejecución de Bash
  • Mensajes personalizados (mensaje_personalizado, resumen_rama)

Nunca corte los resultados de la herramienta (deben permanecer con su llamada de herramienta).

Estructura de entrada de compactación

Definido en session-manager.ts:

interface CompactionEntry<T = unknown> {
  type: "compaction";
  id: string;
  parentId: string;
  timestamp: number;
  summary: string;
  firstKeptEntryId: string;
  tokensBefore: number;
  usage?: Usage;       // LLM usage that generated the summary
  fromHook?: boolean;  // true if provided by extension (legacy field name)
  details?: T;         // implementation-specific data
}

// Default compaction uses this for details (from compaction.ts):
interface CompactionDetails {
  readFiles: string[];
  modifiedFiles: string[];
}

Extensions puede almacenar cualquier dato serializable JSON en details. La compactación predeterminada rastrea las operaciones de archivos, pero las implementaciones de extensiones personalizadas pueden usar su propia estructura. Los resúmenes generados y proporcionados por la extensión almacenan su LLM usage cuando esté disponible, de modo que los totales de las sesiones incluyan el trabajo de resumen.

Consulte prepareCompaction() y compact() para conocer la implementación. Para un resumen programático directo, generateSummary() devuelve el texto de resumen y generateSummaryWithUsage() devuelve { text, usage }.

Resumen de sucursales

Cuando se activa

Cuando usas /tree para navegar a una rama diferente, Pi te ofrece resumir el trabajo que estás dejando. Esto inyecta contexto de la rama izquierda a la nueva rama.

Cómo funciona

  1. Buscar ancestro común: nodo más profundo compartido por posiciones antiguas y nuevas
  2. Recopila entradas: camina desde la hoja vieja hasta el ancestro común
  3. Prepárese con el presupuesto: incluya mensajes hasta el presupuesto simbólico (los más recientes primero)
  4. Generar resumen: Llame a LLM con formato estructurado
  5. Agregar entrada: Guardar BranchSummaryEntry en el punto de navegación
Tree before navigation:

         ┌─ B ─ C ─ D (old leaf, being abandoned)
    A ───┤
         └─ E ─ F (target)

Common ancestor: A
Entries to summarize: B, C, D

After navigation with summary:

         ┌─ B ─ C ─ D
    A ───┤
         └─ E ─ F ─ [summary of B,C,D] (new leaf)

Seguimiento de archivos acumulativos

Tanto la compactación como el branch summarization rastrean archivos de forma acumulativa. Al generar un resumen, pi extrae las operaciones de archivos de:

  • Llamadas a herramientas en los mensajes que se resumen
  • Compactación anterior o resumen de ramas details (si corresponde)

Esto significa que el seguimiento de archivos se acumula en múltiples compactaciones o resúmenes de ramas anidadas, preservando el historial completo de archivos leídos y modificados.

RamaResumenEstructura de entrada

Definido en session-manager.ts:

interface BranchSummaryEntry<T = unknown> {
  type: "branch_summary";
  id: string;
  parentId: string;
  timestamp: number;
  summary: string;
  fromId: string;      // Entry we navigated from
  usage?: Usage;       // LLM usage that generated the summary
  fromHook?: boolean;  // true if provided by extension (legacy field name)
  details?: T;         // implementation-specific data
}

// Default branch summarization uses this for details (from branch-summarization.ts):
interface BranchSummaryDetails {
  readFiles: string[];
  modifiedFiles: string[];
}

Al igual que la compactación, las extensiones pueden almacenar datos personalizados en details.

Consulte collectEntriesForBranchSummary(), prepareBranchEntries() y generateBranchSummary() para conocer la implementación.

Formato de resumen

Tanto la compactación como branch summarization usan el mismo formato estructurado:

## Goal
[What the user is trying to accomplish]

## Constraints & Preferences
- [Requirements mentioned by user]

## Progress
### Done
- [x] [Completed tasks]

### In Progress
- [ ] [Current work]

### Blocked
- [Issues, if any]

## Key Decisions
- **[Decision]**: [Rationale]

## Next Steps
1. [What should happen next]

## Critical Context
- [Data needed to continue]

<read-files>
path/to/file1.ts
path/to/file2.ts
</read-files>

<modified-files>
path/to/changed.ts
</modified-files>

Serialización de mensajes

Antes del resumen, los mensajes se serializan en texto mediante serializeConversation():

[User]: What they said
[Assistant thinking]: Internal reasoning
[Assistant]: Response text
[Assistant tool calls]: read(path="foo.ts"); edit(path="bar.ts", ...)
[Tool result]: Output from tool

Esto evita que el modelo lo trate como una conversación para continuar.

Los resultados de la herramienta se truncan a 2000 caracteres durante la serialización. El contenido que supera ese límite se reemplaza con un marcador que indica cuántos caracteres se truncaron. Esto mantiene las solicitudes de resumen dentro de presupuestos simbólicos razonables, ya que los resultados de las herramientas (especialmente de read y bash) suelen ser los que más contribuyen al tamaño del contexto.

Resumen personalizado a través de Extensions

Extensions puede interceptar y personalizar tanto la compactación como branch summarization. Consulte extensions/types.ts para conocer las definiciones de tipos de eventos.

sesión_antes_compact

Disparado antes de la autocompactación o /compact. Puede cancelar o proporcionar un resumen personalizado. Consulte SessionBeforeCompactEvent y CompactionPreparation en el archivo de tipos.

pi.on("session_before_compact", async (event, ctx) => {
  const { preparation, branchEntries, customInstructions, reason, willRetry, signal } = event;

  // preparation.messagesToSummarize - messages to summarize
  // preparation.turnPrefixMessages - split turn prefix (if isSplitTurn)
  // preparation.previousSummary - previous compaction summary
  // preparation.fileOps - extracted file operations
  // preparation.tokensBefore - context tokens before compaction
  // preparation.firstKeptEntryId - where kept messages start
  // preparation.settings - compaction settings

  // branchEntries - all entries on current branch (for custom state)
  // reason - "manual" (/compact), "threshold", or "overflow"
  // willRetry - whether the aborted turn is retried after compaction (overflow recovery)
  // signal - AbortSignal (pass to LLM calls)

  // Cancel:
  return { cancel: true };

  // Custom summary:
  return {
    compaction: {
      summary: "Your summary...",
      firstKeptEntryId: preparation.firstKeptEntryId,
      tokensBefore: preparation.tokensBefore,
      // usage: summaryResponse.usage, // Optional; included in session totals
      details: { /* custom data */ },
    }
  };
});

Convertir mensajes a texto

Para generar un resumen con tu propio modelo, convierte mensajes a texto usando serializeConversation:

import { convertToLlm, serializeConversation } from "@earendil-works/pi-coding-agent";

pi.on("session_before_compact", async (event, ctx) => {
  const { preparation } = event;
  
  // Convert AgentMessage[] to Message[], then serialize to text
  const conversationText = serializeConversation(
    convertToLlm(preparation.messagesToSummarize)
  );
  // Returns:
  // [User]: message text
  // [Assistant thinking]: thinking content
  // [Assistant]: response text
  // [Assistant tool calls]: read(path="..."); bash(command="...")
  // [Tool result]: output text

  // Now send to your model for summarization
  const { summary, usage } = await myModel.summarize(conversationText);
  
  return {
    compaction: {
      summary,
      firstKeptEntryId: preparation.firstKeptEntryId,
      tokensBefore: preparation.tokensBefore,
      usage,
    }
  };
});

Consulte custom-compaction.ts para ver un ejemplo completo utilizando un modelo diferente.

sesión_antes_árbol

Disparado antes de la navegación /tree. Siempre se activa independientemente de si el usuario elige resumir. Puede cancelar la navegación o proporcionar un resumen personalizado.

pi.on("session_before_tree", async (event, ctx) => {
  const { preparation, signal } = event;

  // preparation.targetId - where we're navigating to
  // preparation.oldLeafId - current position (being abandoned)
  // preparation.commonAncestorId - shared ancestor
  // preparation.entriesToSummarize - entries that would be summarized
  // preparation.userWantsSummary - whether user chose to summarize

  // Cancel navigation entirely:
  return { cancel: true };

  // Provide custom summary (only used if userWantsSummary is true):
  if (preparation.userWantsSummary) {
    return {
      summary: {
        summary: "Your summary...",
        // usage: summaryResponse.usage, // Optional; included in session totals
        details: { /* custom data */ },
      }
    };
  }
});

Consulte SessionBeforeTreeEvent y TreePreparation en el archivo de tipos.

Ajustes

Configure la compactación en ~/.pi/agent/settings.json o <project-dir>/.pi/settings.json:

{
  "compaction": {
    "enabled": true,
    "reserveTokens": 16384,
    "keepRecentTokens": 20000
  }
}
Configuración Por defecto Descripción
enabled true Habilitar la autocompactación
reserveTokens 16384 Tokens para reservar para la respuesta LLM
keepRecentTokens 20000 Tokens recientes para conservar (no resumidos)

Desactive la compactación automática con "enabled": false. Aún puedes compactar manualmente con /compact.