Technical reference

Arquitectura de integración de Pi

OpenClaw se integra con pi-coding-agent y sus paquetes hermanos (pi-ai, pi-agent-core, pi-tui) para impulsar sus capacidades de agente de IA.

Descripción general

OpenClaw usa el SDK de pi para integrar un agente de codificación de IA en su arquitectura de Gateway de mensajería. En lugar de iniciar pi como un subproceso o usar el modo RPC, OpenClaw importa e instancia directamente el AgentSession de pi mediante createAgentSession(). Este enfoque integrado proporciona:

  • Control completo del ciclo de vida de la sesión y del manejo de eventos
  • Inyección de herramientas personalizadas (mensajería, sandbox, acciones específicas del canal)
  • Personalización del prompt del sistema por canal/contexto
  • Persistencia de sesiones con compatibilidad para ramas/Compaction
  • Rotación de perfiles de autenticación multicuentas con conmutación por error
  • Cambio de modelo independiente del proveedor

Dependencias de paquetes

{
  "@mariozechner/pi-agent-core": "0.73.0",
  "@mariozechner/pi-ai": "0.73.0",
  "@mariozechner/pi-coding-agent": "0.73.0",
  "@mariozechner/pi-tui": "0.73.0"
}
Paquete Propósito
pi-ai Abstracciones LLM principales: Model, streamSimple, tipos de mensaje, API de proveedores
pi-agent-core Bucle del agente, ejecución de herramientas, tipos AgentMessage
pi-coding-agent SDK de alto nivel: createAgentSession, SessionManager, AuthStorage, ModelRegistry, herramientas integradas
pi-tui Componentes de interfaz de terminal (usados en el modo TUI local de OpenClaw)

Estructura de archivos

src/agents/
├── pi-embedded-runner.ts          # Reexporta desde pi-embedded-runner/
├── pi-embedded-runner/
│   ├── run.ts                     # Entrada principal: runEmbeddedPiAgent()
│   ├── run/
│   │   ├── attempt.ts             # Lógica de un solo intento con configuración de sesión
│   │   ├── params.ts              # Tipo RunEmbeddedPiAgentParams
│   │   ├── payloads.ts            # Construye cargas de respuesta a partir de resultados de ejecución
│   │   ├── images.ts              # Inyección de imágenes en modelos de visión
│   │   └── types.ts               # EmbeddedRunAttemptResult
│   ├── abort.ts                   # Detección de errores de cancelación
│   ├── cache-ttl.ts               # Seguimiento de TTL de caché para poda de contexto
│   ├── compact.ts                 # Lógica de Compaction manual/automática
│   ├── extensions.ts              # Carga extensiones de pi para ejecuciones integradas
│   ├── extra-params.ts            # Parámetros de stream específicos del proveedor
│   ├── google.ts                  # Correcciones de orden de turnos para Google/Gemini
│   ├── history.ts                 # Limitación del historial (DM frente a grupo)
│   ├── lanes.ts                   # Carriles de comandos de sesión/globales
│   ├── logger.ts                  # Registrador de subsistema
│   ├── model.ts                   # Resolución de modelos mediante ModelRegistry
│   ├── runs.ts                    # Seguimiento de ejecuciones activas, cancelación, cola
│   ├── sandbox-info.ts            # Información de sandbox para el prompt del sistema
│   ├── session-manager-cache.ts   # Caché de instancias de SessionManager
│   ├── session-manager-init.ts    # Inicialización del archivo de sesión
│   ├── system-prompt.ts           # Constructor del prompt del sistema
│   ├── tool-split.ts              # Divide herramientas en builtIn frente a custom
│   ├── types.ts                   # EmbeddedPiAgentMeta, EmbeddedPiRunResult
│   └── utils.ts                   # Mapeo ThinkLevel, descripción de errores
├── pi-embedded-subscribe.ts       # Suscripción/despacho de eventos de sesión
├── pi-embedded-subscribe.types.ts # SubscribeEmbeddedPiSessionParams
├── pi-embedded-subscribe.handlers.ts # Fábrica de manejadores de eventos
├── pi-embedded-subscribe.handlers.lifecycle.ts
├── pi-embedded-subscribe.handlers.types.ts
├── pi-embedded-block-chunker.ts   # Fragmentación de respuestas por bloques en streaming
├── pi-embedded-messaging.ts       # Seguimiento de herramientas de mensajería enviadas
├── pi-embedded-helpers.ts         # Clasificación de errores, validación de turnos
├── pi-embedded-helpers/           # Módulos auxiliares
├── pi-embedded-utils.ts           # Utilidades de formato
├── pi-tools.ts                    # createOpenClawCodingTools()
├── pi-tools.abort.ts              # Envoltorio AbortSignal para herramientas
├── pi-tools.policy.ts             # Política de lista de permitidos/denegados de herramientas
├── pi-tools.read.ts               # Personalizaciones de herramientas de lectura
├── pi-tools.schema.ts             # Normalización de esquemas de herramientas
├── pi-tools.types.ts              # Alias de tipo AnyAgentTool
├── pi-tool-definition-adapter.ts  # Adaptador AgentTool -> ToolDefinition
├── pi-settings.ts                 # Sobrescrituras de configuración
├── pi-hooks/                      # Hooks personalizados de pi
│   ├── compaction-safeguard.ts    # Extensión de salvaguarda
│   ├── compaction-safeguard-runtime.ts
│   ├── context-pruning.ts         # Extensión de poda de contexto Cache-TTL
│   └── context-pruning/
├── model-auth.ts                  # Resolución de perfiles de autenticación
├── auth-profiles.ts               # Almacén de perfiles, enfriamiento, conmutación por error
├── model-selection.ts             # Resolución del modelo predeterminado
├── models-config.ts               # Generación de models.json
├── model-catalog.ts               # Caché del catálogo de modelos
├── context-window-guard.ts        # Validación de ventana de contexto
├── failover-error.ts              # Clase FailoverError
├── defaults.ts                    # DEFAULT_PROVIDER, DEFAULT_MODEL
├── system-prompt.ts               # buildAgentSystemPrompt()
├── system-prompt-params.ts        # Resolución de parámetros del prompt del sistema
├── system-prompt-report.ts        # Generación de informe de depuración
├── tool-summaries.ts              # Resúmenes de descripciones de herramientas
├── tool-policy.ts                 # Resolución de políticas de herramientas
├── transcript-policy.ts           # Política de validación de transcripciones
├── skills.ts                      # Construcción de instantánea/prompt de Skills
├── skills/                        # Subsistema Skills
├── sandbox.ts                     # Resolución de contexto de sandbox
├── sandbox/                       # Subsistema de sandbox
├── channel-tools.ts               # Inyección de herramientas específicas del canal
├── openclaw-tools.ts              # Herramientas específicas de OpenClaw
├── bash-tools.ts                  # Herramientas exec/process
├── apply-patch.ts                 # Herramienta apply_patch (OpenAI)
├── tools/                         # Implementaciones individuales de herramientas
│   ├── browser-tool.ts
│   ├── canvas-tool.ts
│   ├── cron-tool.ts
│   ├── gateway-tool.ts
│   ├── image-tool.ts
│   ├── message-tool.ts
│   ├── nodes-tool.ts
│   ├── session*.ts
│   ├── web-*.ts
│   └── ...
└── ...

Los runtimes de acciones de mensajes específicas de canal ahora viven en los directorios de extensión propiedad del Plugin en lugar de bajo src/agents/tools, por ejemplo:

  • los archivos de runtime de acciones del Plugin de Discord
  • el archivo de runtime de acciones del Plugin de Slack
  • el archivo de runtime de acciones del Plugin de Telegram
  • el archivo de runtime de acciones del Plugin de WhatsApp

Flujo de integración principal

1. Ejecutar un agente integrado

El punto de entrada principal es runEmbeddedPiAgent() en pi-embedded-runner/run.ts:


const result = await runEmbeddedPiAgent({
  sessionId: "user-123",
  sessionKey: "main:whatsapp:+1234567890",
  sessionFile: "/path/to/session.jsonl",
  workspaceDir: "/path/to/workspace",
  config: openclawConfig,
  prompt: "Hello, how are you?",
  provider: "anthropic",
  model: "claude-sonnet-4-6",
  timeoutMs: 120_000,
  runId: "run-abc",
  onBlockReply: async (payload) => {
    await sendToChannel(payload.text, payload.mediaUrls);
  },
});

2. Creación de sesión

Dentro de runEmbeddedAttempt() (llamado por runEmbeddedPiAgent()), se usa el SDK de pi:


  createAgentSession,
  DefaultResourceLoader,
  SessionManager,
  SettingsManager,
} from "@mariozechner/pi-coding-agent";

const resourceLoader = new DefaultResourceLoader({
  cwd: resolvedWorkspace,
  agentDir,
  settingsManager,
  additionalExtensionPaths,
});
await resourceLoader.reload();

const { session } = await createAgentSession({
  cwd: resolvedWorkspace,
  agentDir,
  authStorage: params.authStorage,
  modelRegistry: params.modelRegistry,
  model: params.model,
  thinkingLevel: mapThinkingLevel(params.thinkLevel),
  tools: builtInTools,
  customTools: allCustomTools,
  sessionManager,
  settingsManager,
  resourceLoader,
});

applySystemPromptOverrideToSession(session, systemPromptOverride);

3. Suscripción a eventos

subscribeEmbeddedPiSession() se suscribe a los eventos AgentSession de pi:

const subscription = subscribeEmbeddedPiSession({
  session: activeSession,
  runId: params.runId,
  verboseLevel: params.verboseLevel,
  reasoningMode: params.reasoningLevel,
  toolResultFormat: params.toolResultFormat,
  onToolResult: params.onToolResult,
  onReasoningStream: params.onReasoningStream,
  onBlockReply: params.onBlockReply,
  onPartialReply: params.onPartialReply,
  onAgentEvent: params.onAgentEvent,
});

Los eventos manejados incluyen:

  • message_start / message_end / message_update (texto/pensamiento en streaming)
  • tool_execution_start / tool_execution_update / tool_execution_end
  • turn_start / turn_end
  • agent_start / agent_end
  • compaction_start / compaction_end

4. Prompting

Después de la configuración, se envía el prompt a la sesión:

await session.prompt(effectivePrompt, { images: imageResult.images });

El SDK maneja el bucle completo del agente: envío al LLM, ejecución de llamadas a herramientas, streaming de respuestas.

La inyección de imágenes es local al prompt: OpenClaw carga refs de imagen desde el prompt actual y las pasa mediante images solo para ese turno. No vuelve a escanear turnos de historial anteriores para volver a inyectar cargas de imágenes.

Arquitectura de herramientas

Canalización de herramientas

  1. Herramientas base: codingTools de pi (read, bash, edit, write)
  2. Reemplazos personalizados: OpenClaw reemplaza bash por exec/process, personaliza read/edit/write para sandbox
  3. Herramientas de OpenClaw: mensajería, navegador, canvas, sesiones, cron, gateway, etc.
  4. Herramientas de canal: herramientas de acción específicas de Discord/Telegram/Slack/WhatsApp
  5. Filtrado por políticas: herramientas filtradas por políticas de perfil, proveedor, agente, grupo y sandbox
  6. Normalización de esquemas: esquemas limpiados para particularidades de Gemini/OpenAI
  7. Envoltorio AbortSignal: herramientas envueltas para respetar señales de cancelación

Adaptador de definición de herramientas

El AgentTool de pi-agent-core tiene una firma de execute distinta de la ToolDefinition de pi-coding-agent. El adaptador en pi-tool-definition-adapter.ts las conecta:

export function toToolDefinitions(tools: AnyAgentTool[]): ToolDefinition[] {
  return tools.map((tool) => ({
    name: tool.name,
    label: tool.label ?? name,
    description: tool.description ?? "",
    parameters: tool.parameters,
    execute: async (toolCallId, params, onUpdate, _ctx, signal) => {
      // pi-coding-agent signature differs from pi-agent-core
      return await tool.execute(toolCallId, params, signal, onUpdate);
    },
  }));
}

Estrategia de división de herramientas

splitSdkTools() pasa todas las herramientas mediante customTools:

export function splitSdkTools(options: { tools: AnyAgentTool[]; sandboxEnabled: boolean }) {
  return {
    builtInTools: [], // Empty. We override everything
    customTools: toToolDefinitions(options.tools),
  };
}

Esto garantiza que el filtrado de políticas, la integración con sandbox y el conjunto de herramientas ampliado de OpenClaw sigan siendo coherentes entre proveedores.

Construcción del prompt del sistema

El prompt del sistema se crea en buildAgentSystemPrompt() (system-prompt.ts). Ensambla un prompt completo con secciones que incluyen Herramientas, Estilo de llamada a herramientas, protecciones de seguridad, referencia de CLI de OpenClaw, Skills, Documentación, Espacio de trabajo, Sandbox, Mensajería, Etiquetas de respuesta, Voz, Respuestas silenciosas, Heartbeats, metadatos de Runtime, además de Memory y Reactions cuando están habilitados, y archivos de contexto opcionales y contenido adicional del prompt del sistema. Las secciones se recortan para el modo de prompt mínimo usado por subagentes.

El prompt se aplica después de crear la sesión mediante applySystemPromptOverrideToSession():

const systemPromptOverride = createSystemPromptOverride(appendPrompt);
applySystemPromptOverrideToSession(session, systemPromptOverride);

Gestión de sesiones

Archivos de sesión

Las sesiones son archivos JSONL con estructura de árbol (enlace id/parentId). El SessionManager de Pi gestiona la persistencia:

const sessionManager = SessionManager.open(params.sessionFile);

OpenClaw envuelve esto con guardSessionManager() para la seguridad de los resultados de herramientas.

Caché de sesiones

session-manager-cache.ts almacena en caché instancias de SessionManager para evitar el análisis repetido de archivos:

await prewarmSessionFile(params.sessionFile);
sessionManager = SessionManager.open(params.sessionFile);
trackSessionManagerAccess(params.sessionFile);

Limitación del historial

limitHistoryTurns() recorta el historial de conversación según el tipo de canal (DM frente a grupo).

Compaction

La compactación automática se activa ante un desbordamiento de contexto. Las firmas comunes de desbordamiento incluyen request_too_large, context length exceeded, input exceeds the maximum number of tokens, input token count exceeds the maximum number of input tokens, input is too long for the model y ollama error: context length exceeded. compactEmbeddedPiSessionDirect() gestiona la compactación manual:

const compactResult = await compactEmbeddedPiSessionDirect({
  sessionId, sessionFile, provider, model, ...
});

Autenticación y resolución de modelos

Perfiles de autenticación

OpenClaw mantiene un almacén de perfiles de autenticación con varias claves de API por proveedor:

const authStore = ensureAuthProfileStore(agentDir, { allowKeychainPrompt: false });
const profileOrder = resolveAuthProfileOrder({ cfg, store: authStore, provider, preferredProfile });

Los perfiles rotan ante fallos con seguimiento de tiempo de enfriamiento:

await markAuthProfileFailure({ store, profileId, reason, cfg, agentDir });
const rotated = await advanceAuthProfile();

Resolución de modelos


const { model, error, authStorage, modelRegistry } = resolveModel(
  provider,
  modelId,
  agentDir,
  config,
);

// Uses pi's ModelRegistry and AuthStorage
authStorage.setRuntimeApiKey(model.provider, apiKeyInfo.apiKey);

Conmutación por error

FailoverError activa el modelo alternativo cuando está configurado:

if (fallbackConfigured && isFailoverErrorMessage(errorText)) {
  throw new FailoverError(errorText, {
    reason: promptFailoverReason ?? "unknown",
    provider,
    model: modelId,
    profileId,
    status: resolveFailoverStatus(promptFailoverReason),
  });
}

Extensiones de Pi

OpenClaw carga extensiones personalizadas de pi para comportamiento especializado:

Protección de Compaction

src/agents/pi-hooks/compaction-safeguard.ts añade protecciones a la compactación, incluido el presupuesto adaptativo de tokens, además de resúmenes de fallos de herramientas y operaciones de archivos:

if (resolveCompactionMode(params.cfg) === "safeguard") {
  setCompactionSafeguardRuntime(params.sessionManager, { maxHistoryShare });
  paths.push(resolvePiExtensionPath("compaction-safeguard"));
}

Poda de contexto

src/agents/pi-hooks/context-pruning.ts implementa la poda de contexto basada en TTL de caché:

if (cfg?.agents?.defaults?.contextPruning?.mode === "cache-ttl") {
  setContextPruningRuntime(params.sessionManager, {
    settings,
    contextWindowTokens,
    isToolPrunable,
    lastCacheTouchAt,
  });
  paths.push(resolvePiExtensionPath("context-pruning"));
}

Streaming y respuestas en bloque

Fragmentación de bloques

EmbeddedBlockChunker gestiona el streaming de texto en bloques de respuesta discretos:

const blockChunker = blockChunking ? new EmbeddedBlockChunker(blockChunking) : null;

Eliminación de etiquetas Thinking/Final

La salida de streaming se procesa para eliminar bloques <think>/<thinking> y extraer contenido de <final>:

const stripBlockTags = (text: string, state: { thinking: boolean; final: boolean }) => {
  // Strip <think>...</think> content
  // If enforceFinalTag, only return <final>...</final> content
};

Directivas de respuesta

Las directivas de respuesta como [[media:url]], [[voice]], [[reply:id]] se analizan y extraen:

const { text: cleanedText, mediaUrls, audioAsVoice, replyToId } = consumeReplyDirectives(chunk);

Manejo de errores

Clasificación de errores

pi-embedded-helpers.ts clasifica errores para el manejo adecuado:

isContextOverflowError(errorText)     // Context too large
isCompactionFailureError(errorText)   // Compaction failed
isAuthAssistantError(lastAssistant)   // Auth failure
isRateLimitAssistantError(...)        // Rate limited
isFailoverAssistantError(...)         // Should failover
classifyFailoverReason(errorText)     // "auth" | "rate_limit" | "quota" | "timeout" | ...

Alternativa de nivel de razonamiento

Si un nivel de razonamiento no es compatible, recurre a una alternativa:

const fallbackThinking = pickFallbackThinkingLevel({
  message: errorText,
  attempted: attemptedThinking,
});
if (fallbackThinking) {
  thinkLevel = fallbackThinking;
  continue;
}

Integración con sandbox

Cuando el modo sandbox está habilitado, las herramientas y rutas quedan restringidas:

const sandbox = await resolveSandboxContext({
  config: params.config,
  sessionKey: sandboxSessionKey,
  workspaceDir: resolvedWorkspace,
});

if (sandboxRoot) {
  // Use sandboxed read/edit/write tools
  // Exec runs in container
  // Browser uses bridge URL
}

Tratamiento específico por proveedor

Anthropic

  • Limpieza de cadena mágica de rechazo
  • Validación de turnos para roles consecutivos
  • Validación estricta de parámetros de herramientas de Pi aguas arriba

Google/Gemini

  • Sanitización de esquemas de herramientas propiedad del Plugin

OpenAI

  • Herramienta apply_patch para modelos Codex
  • Manejo de degradación de nivel de razonamiento

Integración con TUI

OpenClaw también tiene un modo TUI local que usa componentes de pi-tui directamente:

// src/tui/tui.ts

Esto proporciona la experiencia de terminal interactiva similar al modo nativo de pi.

Diferencias clave respecto a la CLI de Pi

Aspecto CLI de Pi OpenClaw integrado
Invocación Comando pi / RPC SDK mediante createAgentSession()
Herramientas Herramientas de codificación predeterminadas Conjunto personalizado de herramientas de OpenClaw
Prompt del sistema AGENTS.md + prompts Dinámico por canal/contexto
Almacenamiento de sesión ~/.pi/agent/sessions/ ~/.openclaw/agents/<agentId>/sessions/ (o $OPENCLAW_STATE_DIR/agents/<agentId>/sessions/)
Autenticación Credencial única Varios perfiles con rotación
Extensiones Cargadas desde disco Programáticas + rutas de disco
Manejo de eventos Renderizado de TUI Basado en callbacks (onBlockReply, etc.)

Consideraciones futuras

Áreas para posible revisión:

  1. Alineación de firmas de herramientas: Actualmente se adapta entre las firmas de pi-agent-core y pi-coding-agent
  2. Envoltorio del gestor de sesiones: guardSessionManager añade seguridad, pero aumenta la complejidad
  3. Carga de extensiones: Podría usar el ResourceLoader de pi de forma más directa
  4. Complejidad del manejador de streaming: subscribeEmbeddedPiSession ha crecido mucho
  5. Peculiaridades de proveedores: Muchas rutas de código específicas de proveedor que pi podría gestionar potencialmente

Pruebas

La cobertura de integración de Pi abarca estas suites:

  • src/agents/pi-*.test.ts
  • src/agents/pi-auth-json.test.ts
  • src/agents/pi-embedded-*.test.ts
  • src/agents/pi-embedded-helpers*.test.ts
  • src/agents/pi-embedded-runner*.test.ts
  • src/agents/pi-embedded-runner/**/*.test.ts
  • src/agents/pi-embedded-subscribe*.test.ts
  • src/agents/pi-tools*.test.ts
  • src/agents/pi-tool-definition-adapter*.test.ts
  • src/agents/pi-settings.test.ts
  • src/agents/pi-hooks/**/*.test.ts

En vivo/por suscripción explícita:

  • src/agents/pi-embedded-runner-extraparams.live.test.ts (habilitar OPENCLAW_LIVE_TEST=1)

Para los comandos de ejecución actuales, consulta Flujo de desarrollo de Pi.

Relacionado