22 KiB
| read_when | summary | title | x-i18n | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Arsitektur integrasi agen Pi tertanam OpenClaw dan siklus hidup sesi | Arsitektur Integrasi Pi |
|
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 SDK pi untuk menanamkan agen coding AI ke dalam arsitektur gateway pesan. Alih-alih menjalankan pi sebagai subprocess atau menggunakan mode RPC, OpenClaw secara langsung mengimpor dan membuat instance AgentSession pi melalui createAgentSession(). Pendekatan tertanam ini memberikan:
- Kontrol penuh atas siklus hidup sesi dan penanganan event
- Injeksi tool kustom (messaging, 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 provider
Dependensi Paket
{
"@mariozechner/pi-agent-core": "0.68.1",
"@mariozechner/pi-ai": "0.68.1",
"@mariozechner/pi-coding-agent": "0.68.1",
"@mariozechner/pi-tui": "0.68.1"
}
| Package | Purpose |
|---|---|
pi-ai |
Abstraksi LLM inti: Model, streamSimple, tipe pesan, API provider |
pi-agent-core |
Loop agen, eksekusi tool, tipe AgentMessage |
pi-coding-agent |
SDK tingkat tinggi: createAgentSession, SessionManager, AuthStorage, ModelRegistry, tool bawaan |
pi-tui |
Komponen UI terminal (digunakan dalam mode TUI lokal OpenClaw) |
Struktur File
src/agents/
├── pi-embedded-runner.ts # Ekspor ulang dari pi-embedded-runner/
├── pi-embedded-runner/
│ ├── run.ts # Entri utama: runEmbeddedPiAgent()
│ ├── run/
│ │ ├── attempt.ts # Logika satu percobaan 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 ekstensi pi untuk run tertanam
│ ├── extra-params.ts # Parameter stream khusus provider
│ ├── google.ts # Perbaikan urutan giliran Google/Gemini
│ ├── history.ts # Pembatasan riwayat (DM vs grup)
│ ├── lanes.ts # Lajur 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/pengiriman 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 untuk streaming
├── pi-embedded-messaging.ts # Pelacakan pengiriman tool messaging
├── 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 # Pembungkusan 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 # Ekstensi safeguard
│ ├── compaction-safeguard-runtime.ts
│ ├── context-pruning.ts # Ekstensi pruning konteks 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 # Generasi models.json
├── model-catalog.ts # Cache katalog model
├── context-window-guard.ts # Validasi jendela konteks
├── 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 # Generasi laporan debug
├── tool-summaries.ts # Ringkasan deskripsi tool
├── tool-policy.ts # Resolusi kebijakan tool
├── transcript-policy.ts # Kebijakan validasi transkrip
├── skills.ts # Pembangunan snapshot/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 tool individual
│ ├── 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 ekstensi
milik Plugin alih-alih di bawah src/agents/tools, misalnya:
- 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 Tertanam
Titik masuk 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()), SDK pi 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 event AgentSession 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_endturn_start/turn_endagent_start/agent_endcompaction_start/compaction_end
4. Prompting
Setelah penyiapan, sesi diberi prompt:
await session.prompt(effectivePrompt, { images: imageResult.images });
SDK menangani loop agen penuh: mengirim ke LLM, menjalankan pemanggilan tool, dan melakukan streaming respons.
Injeksi gambar bersifat lokal terhadap prompt: OpenClaw memuat ref gambar dari prompt saat ini dan
meneruskannya melalui images hanya untuk giliran tersebut. OpenClaw tidak memindai ulang giliran riwayat lama
untuk menginjeksi ulang payload gambar.
Arsitektur Tool
Pipeline Tool
- Tool Dasar:
codingToolsmilik pi (read, bash, edit, write) - Pengganti Kustom: OpenClaw mengganti bash dengan
exec/process, menyesuaikan read/edit/write untuk sandbox - Tool OpenClaw: messaging, browser, canvas, sessions, Cron, gateway, dll.
- Tool Channel: tool aksi khusus Discord/Telegram/Slack/WhatsApp
- Pemfilteran Kebijakan: tool difilter berdasarkan profil, provider, agen, grup, dan kebijakan sandbox
- Normalisasi Skema: skema dibersihkan untuk quirk Gemini/OpenAI
- Pembungkusan AbortSignal: tool dibungkus agar mematuhi abort signal
Adapter Definisi Tool
AgentTool milik pi-agent-core memiliki signature execute yang berbeda dibanding ToolDefinition milik pi-coding-agent. Adapter di pi-tool-definition-adapter.ts menjembatani 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 menimpa semuanya
customTools: toToolDefinitions(options.tools),
};
}
Ini memastikan pemfilteran kebijakan, integrasi sandbox, dan kumpulan tool yang diperluas milik OpenClaw tetap konsisten di seluruh provider.
Konstruksi System Prompt
System prompt dibangun di buildAgentSystemPrompt() (system-prompt.ts). Fungsi ini merakit prompt penuh dengan bagian-bagian termasuk Tooling, Gaya Pemanggilan Tool, guardrail keamanan, referensi CLI OpenClaw, Skills, Docs, Workspace, Sandbox, Messaging, Tag Balasan, Voice, Balasan Senyap, Heartbeat, 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 subagen.
Prompt diterapkan setelah pembuatan sesi melalui applySystemPromptOverrideToSession():
const systemPromptOverride = createSystemPromptOverride(appendPrompt);
applySystemPromptOverrideToSession(session, systemPromptOverride);
Manajemen Sesi
File Sesi
Sesi adalah file JSONL dengan struktur pohon (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 meng-cache 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 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, ...
});
Autentikasi & Resolusi Model
Profil Auth
OpenClaw mempertahankan 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),
});
}
Ekstensi Pi
OpenClaw memuat ekstensi Pi kustom untuk perilaku khusus:
Safeguard Compaction
src/agents/pi-hooks/compaction-safeguard.ts menambahkan guardrail ke Compaction, termasuk penganggaran token adaptif serta ringkasan kegagalan tool dan operasi file:
if (resolveCompactionMode(params.cfg) === "safeguard") {
setCompactionSafeguardRuntime(params.sessionManager, { maxHistoryShare });
paths.push(resolvePiExtensionPath("compaction-safeguard"));
}
Pruning Konteks
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 & 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]] di-parse 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 tingkat thinking tidak didukung, sistem menggunakan 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 yang di-sandbox
// Exec berjalan di container
// Browser menggunakan URL bridge
}
Penanganan Khusus Provider
Anthropic
- Scrubbing magic string penolakan
- Validasi giliran untuk peran berurutan
- Validasi parameter tool Pi upstream yang ketat
Google/Gemini
- Sanitasi skema tool milik Plugin
OpenAI
- Tool
apply_patchuntuk model Codex - Penanganan penurunan 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
| Aspect | Pi CLI | OpenClaw Embedded |
|---|---|---|
| Invocation | perintah pi / RPC |
SDK melalui createAgentSession() |
| Tools | Tool coding default | Kumpulan tool OpenClaw kustom |
| System prompt | AGENTS.md + prompt | Dinamis per channel/konteks |
| Session storage | ~/.pi/agent/sessions/ |
~/.openclaw/agents/<agentId>/sessions/ (atau $OPENCLAW_STATE_DIR/agents/<agentId>/sessions/) |
| Auth | Kredensial tunggal | Multi-profil dengan rotasi |
| Extensions | Dimuat dari disk | Path terprogram + disk |
| Event handling | Rendering TUI | Berbasis callback (onBlockReply, dll.) |
Pertimbangan Mendatang
Area yang berpotensi dikerjakan ulang:
- Penyelarasan signature tool: Saat ini mengadaptasi antara signature pi-agent-core dan pi-coding-agent
- Pembungkusan session manager:
guardSessionManagermenambah keamanan tetapi meningkatkan kompleksitas - Pemuatan ekstensi: Bisa menggunakan
ResourceLoadermilik Pi secara lebih langsung - Kompleksitas handler streaming:
subscribeEmbeddedPiSessiontelah berkembang besar - Keunikan provider: Banyak codepath khusus provider yang berpotensi dapat ditangani oleh Pi
Pengujian
Cakupan integrasi Pi mencakup suite berikut:
src/agents/pi-*.test.tssrc/agents/pi-auth-json.test.tssrc/agents/pi-embedded-*.test.tssrc/agents/pi-embedded-helpers*.test.tssrc/agents/pi-embedded-runner*.test.tssrc/agents/pi-embedded-runner/**/*.test.tssrc/agents/pi-embedded-subscribe*.test.tssrc/agents/pi-tools*.test.tssrc/agents/pi-tool-definition-adapter*.test.tssrc/agents/pi-settings.test.tssrc/agents/pi-hooks/**/*.test.ts
Live/opsional:
src/agents/pi-embedded-runner-extraparams.live.test.ts(aktifkanOPENCLAW_LIVE_TEST=1)
Untuk perintah run saat ini, lihat Pi Development Workflow.