Files
openclaw/docs/zh-CN/pi.md
2026-03-29 09:10:39 +01:00

572 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
read_when:
- 理解 OpenClaw 中 Pi SDK 集成设计时
- 修改 Pi 的智能体会话生命周期、工具或提供商接线时
summary: OpenClaw 内嵌 Pi 智能体集成与会话生命周期的架构
title: Pi 集成架构
x-i18n:
generated_at: "2026-03-29T04:10:02Z"
model: gpt-5.4
provider: openai
source_hash: 43a5d646ed66fab1492b6f18fb1623d895922ecf539e52e069d99e7e83c0be11
source_path: pi.md
workflow: 15
---
# Pi 集成架构
本文档介绍 OpenClaw 如何与 [pi-coding-agent](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent) 及其同级软件包(`pi-ai``pi-agent-core``pi-tui`)集成,以提供其 AI 智能体能力。
## 概览
OpenClaw 使用 pi SDK 将 AI 编码智能体嵌入到其消息 Gateway 网关架构中。OpenClaw 不会将 pi 作为子进程启动,也不会使用 RPC 模式,而是通过 `createAgentSession()` 直接导入并实例化 pi 的 `AgentSession`。这种内嵌方式提供了:
- 对会话生命周期和事件处理的完全控制
- 自定义工具注入(消息、沙箱、渠道特定操作)
- 按渠道 / 上下文定制系统提示词
- 支持分支 / 压缩的会话持久化
- 带故障转移的多账户凭证配置轮换
- 与提供商无关的模型切换
## 软件包依赖
```json
{
"@mariozechner/pi-agent-core": "0.61.1",
"@mariozechner/pi-ai": "0.61.1",
"@mariozechner/pi-coding-agent": "0.61.1",
"@mariozechner/pi-tui": "0.61.1"
}
```
| 软件包 | 用途 |
| ----------------- | ------------------------------------------------------------------------------------------ |
| `pi-ai` | 核心 LLM 抽象:`Model``streamSimple`、消息类型、提供商 API |
| `pi-agent-core` | 智能体循环、工具执行、`AgentMessage` 类型 |
| `pi-coding-agent` | 高层 SDK`createAgentSession``SessionManager``AuthStorage``ModelRegistry`、内置工具 |
| `pi-tui` | 终端 UI 组件(用于 OpenClaw 的本地 TUI 模式) |
## 文件结构
```
src/agents/
├── pi-embedded-runner.ts # Re-exports from pi-embedded-runner/
├── pi-embedded-runner/
│ ├── run.ts # Main entry: runEmbeddedPiAgent()
│ ├── run/
│ │ ├── attempt.ts # Single attempt logic with session setup
│ │ ├── params.ts # RunEmbeddedPiAgentParams type
│ │ ├── payloads.ts # Build response payloads from run results
│ │ ├── images.ts # Vision model image injection
│ │ └── types.ts # EmbeddedRunAttemptResult
│ ├── abort.ts # Abort error detection
│ ├── cache-ttl.ts # Cache TTL tracking for context pruning
│ ├── compact.ts # Manual/auto compaction logic
│ ├── extensions.ts # Load pi extensions for embedded runs
│ ├── extra-params.ts # Provider-specific stream params
│ ├── google.ts # Google/Gemini turn ordering fixes
│ ├── history.ts # History limiting (DM vs group)
│ ├── lanes.ts # Session/global command lanes
│ ├── logger.ts # Subsystem logger
│ ├── model.ts # Model resolution via ModelRegistry
│ ├── runs.ts # Active run tracking, abort, queue
│ ├── sandbox-info.ts # Sandbox info for system prompt
│ ├── session-manager-cache.ts # SessionManager instance caching
│ ├── session-manager-init.ts # Session file initialization
│ ├── system-prompt.ts # System prompt builder
│ ├── tool-split.ts # Split tools into builtIn vs custom
│ ├── types.ts # EmbeddedPiAgentMeta, EmbeddedPiRunResult
│ └── utils.ts # ThinkLevel mapping, error description
├── pi-embedded-subscribe.ts # Session event subscription/dispatch
├── pi-embedded-subscribe.types.ts # SubscribeEmbeddedPiSessionParams
├── pi-embedded-subscribe.handlers.ts # Event handler factory
├── pi-embedded-subscribe.handlers.lifecycle.ts
├── pi-embedded-subscribe.handlers.types.ts
├── pi-embedded-block-chunker.ts # Streaming block reply chunking
├── pi-embedded-messaging.ts # Messaging tool sent tracking
├── pi-embedded-helpers.ts # Error classification, turn validation
├── pi-embedded-helpers/ # Helper modules
├── pi-embedded-utils.ts # Formatting utilities
├── pi-tools.ts # createOpenClawCodingTools()
├── pi-tools.abort.ts # AbortSignal wrapping for tools
├── pi-tools.policy.ts # Tool allowlist/denylist policy
├── pi-tools.read.ts # Read tool customizations
├── pi-tools.schema.ts # Tool schema normalization
├── pi-tools.types.ts # AnyAgentTool type alias
├── pi-tool-definition-adapter.ts # AgentTool -> ToolDefinition adapter
├── pi-settings.ts # Settings overrides
├── pi-hooks/ # Custom pi hooks
│ ├── compaction-safeguard.ts # Safeguard extension
│ ├── compaction-safeguard-runtime.ts
│ ├── context-pruning.ts # Cache-TTL context pruning extension
│ └── context-pruning/
├── model-auth.ts # Auth profile resolution
├── auth-profiles.ts # Profile store, cooldown, failover
├── model-selection.ts # Default model resolution
├── models-config.ts # models.json generation
├── model-catalog.ts # Model catalog cache
├── context-window-guard.ts # Context window validation
├── failover-error.ts # FailoverError class
├── defaults.ts # DEFAULT_PROVIDER, DEFAULT_MODEL
├── system-prompt.ts # buildAgentSystemPrompt()
├── system-prompt-params.ts # System prompt parameter resolution
├── system-prompt-report.ts # Debug report generation
├── tool-summaries.ts # Tool description summaries
├── tool-policy.ts # Tool policy resolution
├── transcript-policy.ts # Transcript validation policy
├── skills.ts # Skill snapshot/prompt building
├── skills/ # Skill subsystem
├── sandbox.ts # Sandbox context resolution
├── sandbox/ # Sandbox subsystem
├── channel-tools.ts # Channel-specific tool injection
├── openclaw-tools.ts # OpenClaw-specific tools
├── bash-tools.ts # exec/process tools
├── apply-patch.ts # apply_patch tool (OpenAI)
├── tools/ # Individual tool implementations
│ ├── 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
│ └── ...
└── ...
```
渠道特定的消息操作运行时现在位于插件自有的扩展目录中,而不是放在 `src/agents/tools` 下,例如:
- `extensions/discord/src/actions/runtime*.ts`
- `extensions/slack/src/action-runtime.ts`
- `extensions/telegram/src/action-runtime.ts`
- `extensions/whatsapp/src/action-runtime.ts`
## 核心集成流程
### 1. 运行内嵌智能体
主入口是 `pi-embedded-runner/run.ts` 中的 `runEmbeddedPiAgent()`
```typescript
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-20250514",
timeoutMs: 120_000,
runId: "run-abc",
onBlockReply: async (payload) => {
await sendToChannel(payload.text, payload.mediaUrls);
},
});
```
### 2. 创建会话
`runEmbeddedAttempt()`(由 `runEmbeddedPiAgent()` 调用)内部,会使用 pi SDK
```typescript
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. 事件订阅
`subscribeEmbeddedPiSession()` 会订阅 pi 的 `AgentSession` 事件:
```typescript
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,
});
```
处理的事件包括:
- `message_start` / `message_end` / `message_update`(流式文本 / 思考)
- `tool_execution_start` / `tool_execution_update` / `tool_execution_end`
- `turn_start` / `turn_end`
- `agent_start` / `agent_end`
- `auto_compaction_start` / `auto_compaction_end`
### 4. 发送提示
完成设置后,会向会话发送提示:
```typescript
await session.prompt(effectivePrompt, { images: imageResult.images });
```
SDK 会处理完整的智能体循环:发送给 LLM、执行工具调用、流式返回响应。
图像注入仅限当前提示OpenClaw 会从当前提示中加载图像引用,并仅通过 `images` 将其传入该轮。它不会重新扫描较早的历史轮次来重新注入图像负载。
## 工具架构
### 工具流水线
1. **基础工具**pi 的 `codingTools`read、bash、edit、write
2. **自定义替换**OpenClaw 用 `exec` / `process` 替换 bash并为沙箱定制 read / edit / write
3. **OpenClaw 工具**消息、浏览器、画布、会话、cron、Gateway 网关 等
4. **渠道工具**Discord / Telegram / Slack / WhatsApp 特定操作工具
5. **策略过滤**:按配置、提供商、智能体、群组、沙箱策略过滤工具
6. **模式归一化**:清理模式以适配 Gemini / OpenAI 的特殊行为
7. **AbortSignal 包装**:包装工具以遵循中止信号
### 工具定义适配器
pi-agent-core 的 `AgentTool` 与 pi-coding-agent 的 `ToolDefinition``execute` 签名上不同。`pi-tool-definition-adapter.ts` 中的适配器用于桥接这一差异:
```typescript
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);
},
}));
}
```
### 工具拆分策略
`splitSdkTools()` 会通过 `customTools` 传入所有工具:
```typescript
export function splitSdkTools(options: { tools: AnyAgentTool[]; sandboxEnabled: boolean }) {
return {
builtInTools: [], // Empty. We override everything
customTools: toToolDefinitions(options.tools),
};
}
```
这样可以确保 OpenClaw 的策略过滤、沙箱集成和扩展工具集在不同提供商之间保持一致。
## 系统提示词构建
系统提示词在 `buildAgentSystemPrompt()``system-prompt.ts`中构建。它会组装完整提示词包含工具、工具调用风格、安全护栏、OpenClaw CLI 参考、Skills、文档、工作区、沙箱、消息、回复标签、语音、静默回复、心跳、运行时元数据等部分并在启用时包含 Memory 和 Reactions以及可选的上下文文件和额外系统提示词内容。为子智能体使用的最小提示词模式会对各部分进行裁剪。
系统提示词会在会话创建后通过 `applySystemPromptOverrideToSession()` 应用:
```typescript
const systemPromptOverride = createSystemPromptOverride(appendPrompt);
applySystemPromptOverrideToSession(session, systemPromptOverride);
```
## 会话管理
### 会话文件
会话是具有树状结构(通过 id / parentId 关联)的 JSONL 文件。Pi 的 `SessionManager` 负责持久化:
```typescript
const sessionManager = SessionManager.open(params.sessionFile);
```
OpenClaw 通过 `guardSessionManager()` 对其进行包装,以保证工具结果安全。
### 会话缓存
`session-manager-cache.ts` 会缓存 `SessionManager` 实例,以避免重复解析文件:
```typescript
await prewarmSessionFile(params.sessionFile);
sessionManager = SessionManager.open(params.sessionFile);
trackSessionManagerAccess(params.sessionFile);
```
### 历史限制
`limitHistoryTurns()` 会根据渠道类型(私信 与群组)裁剪对话历史。
### 压缩
上下文溢出时会触发自动压缩。`compactEmbeddedPiSessionDirect()` 负责手动压缩:
```typescript
const compactResult = await compactEmbeddedPiSessionDirect({
sessionId, sessionFile, provider, model, ...
});
```
## 身份验证与模型解析
### 凭证配置
OpenClaw 维护一个凭证配置存储,为每个提供商保存多个 API 密钥:
```typescript
const authStore = ensureAuthProfileStore(agentDir, { allowKeychainPrompt: false });
const profileOrder = resolveAuthProfileOrder({ cfg, store: authStore, provider, preferredProfile });
```
配置会在失败时轮换,并跟踪冷却状态:
```typescript
await markAuthProfileFailure({ store, profileId, reason, cfg, agentDir });
const rotated = await advanceAuthProfile();
```
### 模型解析
```typescript
import { resolveModel } from "./pi-embedded-runner/model.js";
const { model, error, authStorage, modelRegistry } = resolveModel(
provider,
modelId,
agentDir,
config,
);
// Uses pi's ModelRegistry and AuthStorage
authStorage.setRuntimeApiKey(model.provider, apiKeyInfo.apiKey);
```
### 故障转移
配置了回退时,`FailoverError` 会触发模型故障转移:
```typescript
if (fallbackConfigured && isFailoverErrorMessage(errorText)) {
throw new FailoverError(errorText, {
reason: promptFailoverReason ?? "unknown",
provider,
model: modelId,
profileId,
status: resolveFailoverStatus(promptFailoverReason),
});
}
```
## Pi 扩展
OpenClaw 会加载自定义的 pi 扩展,以实现专门行为:
### 压缩保护
`src/agents/pi-hooks/compaction-safeguard.ts` 会为压缩添加护栏,包括自适应 token 预算,以及工具失败和文件操作摘要:
```typescript
if (resolveCompactionMode(params.cfg) === "safeguard") {
setCompactionSafeguardRuntime(params.sessionManager, { maxHistoryShare });
paths.push(resolvePiExtensionPath("compaction-safeguard"));
}
```
### 上下文裁剪
`src/agents/pi-hooks/context-pruning.ts` 实现了基于 cache-TTL 的上下文裁剪:
```typescript
if (cfg?.agents?.defaults?.contextPruning?.mode === "cache-ttl") {
setContextPruningRuntime(params.sessionManager, {
settings,
contextWindowTokens,
isToolPrunable,
lastCacheTouchAt,
});
paths.push(resolvePiExtensionPath("context-pruning"));
}
```
## 流式传输与分块回复
### 分块处理
`EmbeddedBlockChunker` 负责将流式文本管理为离散的回复块:
```typescript
const blockChunker = blockChunking ? new EmbeddedBlockChunker(blockChunking) : null;
```
### 思考 / 最终标签剥离
流式输出会经过处理,以去除 `<think>` / `<thinking>` 块并提取 `<final>` 内容:
```typescript
const stripBlockTags = (text: string, state: { thinking: boolean; final: boolean }) => {
// Strip <think>...</think> content
// If enforceFinalTag, only return <final>...</final> content
};
```
### 回复指令
会解析并提取诸如 `[[media:url]]``[[voice]]``[[reply:id]]` 之类的回复指令:
```typescript
const { text: cleanedText, mediaUrls, audioAsVoice, replyToId } = consumeReplyDirectives(chunk);
```
## 错误处理
### 错误分类
`pi-embedded-helpers.ts` 会对错误进行分类,以便进行适当处理:
```typescript
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" | ...
```
### 思考级别回退
如果某个思考级别不受支持,它会回退:
```typescript
const fallbackThinking = pickFallbackThinkingLevel({
message: errorText,
attempted: attemptedThinking,
});
if (fallbackThinking) {
thinkLevel = fallbackThinking;
continue;
}
```
## 沙箱集成
启用沙箱模式时,工具和路径都会受到约束:
```typescript
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
}
```
## 提供商特定处理
### Anthropic
- 清理拒绝魔法字符串
- 针对连续角色的轮次验证
- Claude Code 参数兼容性
### Google / Gemini
- 轮次顺序修复(`applyGoogleTurnOrderingFix`
- 工具模式净化(`sanitizeToolsForGoogle`
- 会话历史净化(`sanitizeSessionHistory`
### OpenAI
- 面向 Codex 模型的 `apply_patch` 工具
- 思考级别降级处理
## TUI 集成
OpenClaw 还提供本地 TUI 模式,可直接使用 pi-tui 组件:
```typescript
// src/tui/tui.ts
import { ... } from "@mariozechner/pi-tui";
```
这提供了与 pi 原生模式类似的交互式终端体验。
## 与 Pi CLI 的关键差异
| 方面 | Pi CLI | OpenClaw 内嵌版 |
| ---------- | ----------------------- | ----------------------------------------------------------------------------------------------- |
| 调用方式 | `pi` 命令 / RPC | 通过 `createAgentSession()` 使用 SDK |
| 工具 | 默认编码工具 | 自定义 OpenClaw 工具套件 |
| 系统提示词 | AGENTS.md + prompts | 按渠道 / 上下文动态生成 |
| 会话存储 | `~/.pi/agent/sessions/` | `~/.openclaw/agents/<agentId>/sessions/`(或 `$OPENCLAW_STATE_DIR/agents/<agentId>/sessions/` |
| 身份验证 | 单一凭证 | 支持轮换的多配置 |
| 扩展 | 从磁盘加载 | 通过编程方式 + 磁盘路径 |
| 事件处理 | TUI 渲染 | 基于回调(`onBlockReply` 等) |
## 未来考虑
潜在的重构方向包括:
1. **工具签名对齐**:当前需要在 pi-agent-core 与 pi-coding-agent 的签名之间进行适配
2. **会话管理器包装**`guardSessionManager` 增加了安全性,但也提高了复杂度
3. **扩展加载**:可以更直接地使用 pi 的 `ResourceLoader`
4. **流式处理器复杂度**`subscribeEmbeddedPiSession` 已经变得较大
5. **提供商特殊行为**:存在许多提供商特定代码路径,未来 pi 或许可以统一处理
## 测试
Pi 集成的覆盖范围包括以下测试套件:
- `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`
实时 / 按需启用:
- `src/agents/pi-embedded-runner-extraparams.live.test.ts`(启用 `OPENCLAW_LIVE_TEST=1`
有关当前运行命令,请参见 [Pi 开发工作流](/pi-dev)。