Langsung ke konten utama

Arsitektur Integrasi Pi

Dokumen ini menjelaskan bagaimana OpenClaw terintegrasi dengan pi-coding-agent dan paket saudaranya (pi-ai, pi-agent-core, pi-tui) untuk mendukung kemampuan agen AI-nya.

Ikhtisar

OpenClaw menggunakan Pi SDK untuk menyematkan agen coding AI ke dalam arsitektur gateway perpesanannya. Alih-alih menjalankan pi sebagai subprocess atau menggunakan mode RPC, OpenClaw langsung mengimpor dan membuat instance AgentSession milik pi melalui createAgentSession(). Pendekatan tersemat ini memberikan:
  • Kontrol penuh atas siklus hidup sesi dan penanganan event
  • Injeksi tool kustom (perpesanan, sandbox, aksi khusus channel)
  • Kustomisasi system prompt per channel/konteks
  • Persistensi sesi dengan dukungan branching/compaction
  • Rotasi profil auth multi-akun dengan failover
  • Peralihan model yang agnostik terhadap provider

Dependensi Paket

{
  "@mariozechner/pi-agent-core": "0.64.0",
  "@mariozechner/pi-ai": "0.64.0",
  "@mariozechner/pi-coding-agent": "0.64.0",
  "@mariozechner/pi-tui": "0.64.0"
}
PackageTujuan
pi-aiAbstraksi LLM inti: Model, streamSimple, tipe pesan, API provider
pi-agent-coreLoop agen, eksekusi tool, tipe AgentMessage
pi-coding-agentSDK tingkat tinggi: createAgentSession, SessionManager, AuthStorage, ModelRegistry, tool bawaan
pi-tuiKomponen UI terminal (digunakan dalam mode TUI lokal OpenClaw)

Struktur File

src/agents/
├── pi-embedded-runner.ts          # Re-export dari pi-embedded-runner/
├── pi-embedded-runner/
│   ├── run.ts                     # Entrypoint utama: runEmbeddedPiAgent()
│   ├── run/
│   │   ├── attempt.ts             # Logika percobaan tunggal dengan penyiapan sesi
│   │   ├── params.ts              # Tipe RunEmbeddedPiAgentParams
│   │   ├── payloads.ts            # Membangun payload respons dari hasil run
│   │   ├── images.ts              # Injeksi gambar model vision
│   │   └── types.ts               # EmbeddedRunAttemptResult
│   ├── abort.ts                   # Deteksi error abort
│   ├── cache-ttl.ts               # Pelacakan TTL cache untuk pruning konteks
│   ├── compact.ts                 # Logika compaction manual/otomatis
│   ├── extensions.ts              # Memuat extension pi untuk run tersemat
│   ├── extra-params.ts            # Parameter stream khusus provider
│   ├── google.ts                  # Perbaikan pengurutan giliran Google/Gemini
│   ├── history.ts                 # Pembatasan riwayat (DM vs grup)
│   ├── lanes.ts                   # Lane perintah sesi/global
│   ├── logger.ts                  # Logger subsistem
│   ├── model.ts                   # Resolusi model melalui ModelRegistry
│   ├── runs.ts                    # Pelacakan run aktif, abort, antrean
│   ├── sandbox-info.ts            # Info sandbox untuk system prompt
│   ├── session-manager-cache.ts   # Caching instance SessionManager
│   ├── session-manager-init.ts    # Inisialisasi file sesi
│   ├── system-prompt.ts           # Builder system prompt
│   ├── tool-split.ts              # Memisahkan tool menjadi builtIn vs custom
│   ├── types.ts                   # EmbeddedPiAgentMeta, EmbeddedPiRunResult
│   └── utils.ts                   # Pemetaan ThinkLevel, deskripsi error
├── pi-embedded-subscribe.ts       # Langganan/distribusi event sesi
├── pi-embedded-subscribe.types.ts # SubscribeEmbeddedPiSessionParams
├── pi-embedded-subscribe.handlers.ts # Factory handler event
├── pi-embedded-subscribe.handlers.lifecycle.ts
├── pi-embedded-subscribe.handlers.types.ts
├── pi-embedded-block-chunker.ts   # Chunking balasan blok streaming
├── pi-embedded-messaging.ts       # Pelacakan pengiriman tool perpesanan
├── pi-embedded-helpers.ts         # Klasifikasi error, validasi giliran
├── pi-embedded-helpers/           # Modul helper
├── pi-embedded-utils.ts           # Utilitas pemformatan
├── pi-tools.ts                    # createOpenClawCodingTools()
├── pi-tools.abort.ts              # Pembungkus AbortSignal untuk tool
├── pi-tools.policy.ts             # Kebijakan allowlist/denylist tool
├── pi-tools.read.ts               # Kustomisasi tool baca
├── pi-tools.schema.ts             # Normalisasi skema tool
├── pi-tools.types.ts              # Alias tipe AnyAgentTool
├── pi-tool-definition-adapter.ts  # Adapter AgentTool -> ToolDefinition
├── pi-settings.ts                 # Override pengaturan
├── pi-hooks/                      # Hook pi kustom
│   ├── compaction-safeguard.ts    # Extension safeguard
│   ├── compaction-safeguard-runtime.ts
│   ├── context-pruning.ts         # Extension pruning konteks berbasis cache-TTL
│   └── context-pruning/
├── model-auth.ts                  # Resolusi profil auth
├── auth-profiles.ts               # Penyimpanan profil, cooldown, failover
├── model-selection.ts             # Resolusi model default
├── models-config.ts               # Pembuatan models.json
├── model-catalog.ts               # Cache katalog model
├── context-window-guard.ts        # Validasi context window
├── failover-error.ts              # Kelas FailoverError
├── defaults.ts                    # DEFAULT_PROVIDER, DEFAULT_MODEL
├── system-prompt.ts               # buildAgentSystemPrompt()
├── system-prompt-params.ts        # Resolusi parameter system prompt
├── system-prompt-report.ts        # Pembuatan laporan debug
├── tool-summaries.ts              # Ringkasan deskripsi tool
├── tool-policy.ts                 # Resolusi kebijakan tool
├── transcript-policy.ts           # Kebijakan validasi transkrip
├── skills.ts                      # Snapshot/pembuatan prompt Skills
├── skills/                        # Subsistem skill
├── sandbox.ts                     # Resolusi konteks sandbox
├── sandbox/                       # Subsistem sandbox
├── channel-tools.ts               # Injeksi tool khusus channel
├── openclaw-tools.ts              # Tool khusus OpenClaw
├── bash-tools.ts                  # Tool exec/process
├── apply-patch.ts                 # Tool apply_patch (OpenAI)
├── tools/                         # Implementasi masing-masing tool
│   ├── 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
│   └── ...
└── ...
Runtime aksi pesan khusus channel sekarang berada di direktori extension milik plugin alih-alih di bawah src/agents/tools, contohnya:
  • file runtime aksi plugin Discord
  • file runtime aksi plugin Slack
  • file runtime aksi plugin Telegram
  • file runtime aksi plugin WhatsApp

Alur Integrasi Inti

1. Menjalankan Agen Tersemat

Entrypoint utama adalah runEmbeddedPiAgent() di pi-embedded-runner/run.ts:
import { runEmbeddedPiAgent } from "./agents/pi-embedded-runner.js";

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. Pembuatan Sesi

Di dalam runEmbeddedAttempt() (dipanggil oleh runEmbeddedPiAgent()), Pi SDK digunakan:
import {
  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. Langganan Event

subscribeEmbeddedPiSession() berlangganan ke event AgentSession milik 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,
});
Event yang ditangani mencakup:
  • message_start / message_end / message_update (streaming teks/thinking)
  • tool_execution_start / tool_execution_update / tool_execution_end
  • turn_start / turn_end
  • agent_start / agent_end
  • auto_compaction_start / auto_compaction_end

4. Prompting

Setelah penyiapan, prompt dikirimkan ke sesi:
await session.prompt(effectivePrompt, { images: imageResult.images });
SDK menangani loop agen penuh: mengirim ke LLM, menjalankan pemanggilan tool, men-stream respons. Injeksi gambar bersifat lokal pada prompt: OpenClaw memuat referensi gambar dari prompt saat ini dan meneruskannya melalui images hanya untuk giliran tersebut. Sistem ini tidak memindai ulang giliran riwayat yang lebih lama untuk menyuntikkan ulang payload gambar.

Arsitektur Tool

Pipeline Tool

  1. Tool Dasar: codingTools milik pi (read, bash, edit, write)
  2. Pengganti Kustom: OpenClaw mengganti bash dengan exec/process, menyesuaikan read/edit/write untuk sandbox
  3. Tool OpenClaw: perpesanan, browser, canvas, sessions, cron, gateway, dll.
  4. Tool Channel: tool aksi khusus Discord/Telegram/Slack/WhatsApp
  5. Pemfilteran Kebijakan: Tool difilter berdasarkan profil, provider, agen, grup, kebijakan sandbox
  6. Normalisasi Skema: Skema dibersihkan untuk quirk Gemini/OpenAI
  7. Pembungkusan AbortSignal: Tool dibungkus agar mematuhi abort signal

Adapter Definisi Tool

AgentTool milik pi-agent-core memiliki signature execute yang berbeda dari ToolDefinition milik pi-coding-agent. Adapter di pi-tool-definition-adapter.ts menjembatani perbedaan ini:
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) => {
      // signature pi-coding-agent berbeda dari pi-agent-core
      return await tool.execute(toolCallId, params, signal, onUpdate);
    },
  }));
}

Strategi Pemisahan Tool

splitSdkTools() meneruskan semua tool melalui customTools:
export function splitSdkTools(options: { tools: AnyAgentTool[]; sandboxEnabled: boolean }) {
  return {
    builtInTools: [], // Kosong. Kami mengganti semuanya
    customTools: toToolDefinitions(options.tools),
  };
}
Ini memastikan pemfilteran kebijakan OpenClaw, integrasi sandbox, dan toolset yang diperluas tetap konsisten di semua provider.

Konstruksi System Prompt

System prompt dibangun di buildAgentSystemPrompt() (system-prompt.ts). Komponen ini menyusun prompt lengkap dengan bagian-bagian termasuk Tooling, Tool Call Style, guardrail Safety, referensi CLI OpenClaw, Skills, Dokumen, Workspace, Sandbox, Messaging, Reply Tags, Voice, Silent Replies, Heartbeats, metadata Runtime, serta Memory dan Reactions saat diaktifkan, dan file konteks opsional serta konten system prompt tambahan. Bagian-bagian dipangkas untuk mode prompt minimal yang digunakan oleh subagent. Prompt diterapkan setelah pembuatan sesi melalui applySystemPromptOverrideToSession():
const systemPromptOverride = createSystemPromptOverride(appendPrompt);
applySystemPromptOverrideToSession(session, systemPromptOverride);

Manajemen Sesi

File Sesi

Sesi adalah file JSONL dengan struktur tree (tautan id/parentId). SessionManager milik Pi menangani persistensi:
const sessionManager = SessionManager.open(params.sessionFile);
OpenClaw membungkus ini dengan guardSessionManager() untuk keamanan hasil tool.

Caching Sesi

session-manager-cache.ts melakukan cache pada instance SessionManager untuk menghindari parsing file berulang:
await prewarmSessionFile(params.sessionFile);
sessionManager = SessionManager.open(params.sessionFile);
trackSessionManagerAccess(params.sessionFile);

Pembatasan Riwayat

limitHistoryTurns() memangkas riwayat percakapan berdasarkan jenis channel (DM vs grup).

Compaction

Compaction otomatis dipicu saat konteks meluap. Tanda tangan overflow yang umum mencakup 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, dan ollama error: context length exceeded. compactEmbeddedPiSessionDirect() menangani compaction manual:
const compactResult = await compactEmbeddedPiSessionDirect({
  sessionId, sessionFile, provider, model, ...
});

Auth dan Resolusi Model

Profil Auth

OpenClaw memelihara penyimpanan profil auth dengan beberapa API key per provider:
const authStore = ensureAuthProfileStore(agentDir, { allowKeychainPrompt: false });
const profileOrder = resolveAuthProfileOrder({ cfg, store: authStore, provider, preferredProfile });
Profil dirotasi saat terjadi kegagalan dengan pelacakan cooldown:
await markAuthProfileFailure({ store, profileId, reason, cfg, agentDir });
const rotated = await advanceAuthProfile();

Resolusi Model

import { resolveModel } from "./pi-embedded-runner/model.js";

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

// Menggunakan ModelRegistry dan AuthStorage milik pi
authStorage.setRuntimeApiKey(model.provider, apiKeyInfo.apiKey);

Failover

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

Pi Extensions

OpenClaw memuat extension pi kustom untuk perilaku khusus:

Compaction Safeguard

src/agents/pi-hooks/compaction-safeguard.ts menambahkan guardrail ke compaction, termasuk penganggaran token adaptif plus ringkasan kegagalan tool dan operasi file:
if (resolveCompactionMode(params.cfg) === "safeguard") {
  setCompactionSafeguardRuntime(params.sessionManager, { maxHistoryShare });
  paths.push(resolvePiExtensionPath("compaction-safeguard"));
}

Context Pruning

src/agents/pi-hooks/context-pruning.ts mengimplementasikan pruning konteks berbasis cache-TTL:
if (cfg?.agents?.defaults?.contextPruning?.mode === "cache-ttl") {
  setContextPruningRuntime(params.sessionManager, {
    settings,
    contextWindowTokens,
    isToolPrunable,
    lastCacheTouchAt,
  });
  paths.push(resolvePiExtensionPath("context-pruning"));
}

Streaming dan Balasan Blok

Chunking Blok

EmbeddedBlockChunker mengelola streaming teks menjadi blok balasan diskret:
const blockChunker = blockChunking ? new EmbeddedBlockChunker(blockChunking) : null;

Penghapusan Tag Thinking/Final

Output streaming diproses untuk menghapus blok <think>/<thinking> dan mengekstrak konten <final>:
const stripBlockTags = (text: string, state: { thinking: boolean; final: boolean }) => {
  // Hapus konten <think>...</think>
  // Jika enforceFinalTag, hanya kembalikan konten <final>...</final>
};

Directive Balasan

Directive balasan seperti [[media:url]], [[voice]], [[reply:id]] diparse dan diekstrak:
const { text: cleanedText, mediaUrls, audioAsVoice, replyToId } = consumeReplyDirectives(chunk);

Penanganan Error

Klasifikasi Error

pi-embedded-helpers.ts mengklasifikasikan error untuk penanganan yang sesuai:
isContextOverflowError(errorText)     // Konteks terlalu besar
isCompactionFailureError(errorText)   // Compaction gagal
isAuthAssistantError(lastAssistant)   // Kegagalan auth
isRateLimitAssistantError(...)        // Terkena rate limit
isFailoverAssistantError(...)         // Harus failover
classifyFailoverReason(errorText)     // "auth" | "rate_limit" | "quota" | "timeout" | ...

Fallback Tingkat Thinking

Jika suatu tingkat thinking tidak didukung, sistem akan melakukan fallback:
const fallbackThinking = pickFallbackThinkingLevel({
  message: errorText,
  attempted: attemptedThinking,
});
if (fallbackThinking) {
  thinkLevel = fallbackThinking;
  continue;
}

Integrasi Sandbox

Saat mode sandbox diaktifkan, tool dan path dibatasi:
const sandbox = await resolveSandboxContext({
  config: params.config,
  sessionKey: sandboxSessionKey,
  workspaceDir: resolvedWorkspace,
});

if (sandboxRoot) {
  // Gunakan tool read/edit/write dalam sandbox
  // Exec berjalan di container
  // Browser menggunakan URL bridge
}

Penanganan Khusus Provider

Anthropic

  • Pembersihan magic string penolakan
  • Validasi giliran untuk role yang berurutan
  • Validasi parameter tool Pi upstream yang ketat

Google/Gemini

  • Sanitasi skema tool milik plugin

OpenAI

  • Tool apply_patch untuk model Codex
  • Penanganan downgrade tingkat thinking

Integrasi TUI

OpenClaw juga memiliki mode TUI lokal yang menggunakan komponen pi-tui secara langsung:
// src/tui/tui.ts
import { ... } from "@mariozechner/pi-tui";
Ini menyediakan pengalaman terminal interaktif yang mirip dengan mode native pi.

Perbedaan Utama dari Pi CLI

AspekPi CLIOpenClaw Embedded
InvocationPerintah pi / RPCSDK melalui createAgentSession()
ToolsTool coding defaultRangkaian tool OpenClaw kustom
System promptAGENTS.md + promptDinamis per channel/konteks
Penyimpanan sesi~/.pi/agent/sessions/~/.openclaw/agents/<agentId>/sessions/ (atau $OPENCLAW_STATE_DIR/agents/<agentId>/sessions/)
AuthKredensial tunggalMulti-profil dengan rotasi
ExtensionsDimuat dari diskJalur programatik + disk
Penanganan eventRendering TUIBerbasis callback (onBlockReply, dll.)

Pertimbangan Masa Depan

Area yang berpotensi untuk dikerjakan ulang:
  1. Penyelarasan signature tool: Saat ini masih mengadaptasi antara signature pi-agent-core dan pi-coding-agent
  2. Pembungkusan session manager: guardSessionManager menambahkan keamanan tetapi meningkatkan kompleksitas
  3. Pemuatan extension: Dapat menggunakan ResourceLoader milik pi secara lebih langsung
  4. Kompleksitas handler streaming: subscribeEmbeddedPiSession semakin besar
  5. Quirk provider: Banyak codepath khusus provider yang berpotensi dapat ditangani oleh pi

Pengujian

Cakupan integrasi Pi mencakup suite berikut:
  • 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
Live/opt-in:
  • src/agents/pi-embedded-runner-extraparams.live.test.ts (aktifkan OPENCLAW_LIVE_TEST=1)
Untuk perintah run saat ini, lihat Pi Development Workflow.