Kiến trúc tích hợp Pi
Tài liệu này mô tả cách Mayros tích hợp với pi-coding-agent và các package anh em của nó (pi-ai, pi-agent-core, pi-tui) để cung cấp khả năng AI agent.
Tổng quan
Mayros sử dụng SDK pi để nhúng AI coding agent vào kiến trúc gateway nhắn tin của nó. Thay vì spawn pi như một subprocess hoặc sử dụng chế độ RPC, Mayros trực tiếp import và khởi tạo AgentSession của pi qua createAgentSession(). Cách tiếp cận nhúng này cung cấp:
- Kiểm soát đầy đủ vòng đời phiên và xử lý sự kiện
- Chèn công cụ tùy chỉnh (nhắn tin, sandbox, hành động riêng kênh)
- Tùy chỉnh system prompt theo kênh/ngữ cảnh
- Lưu trữ phiên với hỗ trợ phân nhánh/nén
- Xoay profile xác thực đa tài khoản với failover
- Chuyển model độc lập provider
Phụ thuộc package
json{ "@mariozechner/pi-agent-core": "0.49.3", "@mariozechner/pi-ai": "0.49.3", "@mariozechner/pi-coding-agent": "0.49.3", "@mariozechner/pi-tui": "0.49.3" }
| Package | Mục đích |
|---|---|
pi-ai | Trừu tượng LLM cốt lõi: Model, streamSimple, kiểu message, API provider |
pi-agent-core | Vòng lặp agent, thực thi công cụ, kiểu AgentMessage |
pi-coding-agent | SDK cấp cao: createAgentSession, SessionManager, AuthStorage, ModelRegistry, công cụ tích hợp |
pi-tui | Component UI terminal (được sử dụng trong chế độ TUI local của Mayros) |
Cấu trúc file
src/agents/
├── pi-embedded-runner.ts # Re-export từ pi-embedded-runner/
├── pi-embedded-runner/
│ ├── run.ts # Entry chính: runEmbeddedPiAgent()
│ ├── run/
│ │ ├── attempt.ts # Logic attempt đơn với thiết lập phiên
│ │ ├── params.ts # Kiểu RunEmbeddedPiAgentParams
│ │ ├── payloads.ts # Build payload phản hồi từ kết quả run
│ │ ├── images.ts # Chèn hình ảnh model vision
│ │ └── types.ts # EmbeddedRunAttemptResult
│ ├── abort.ts # Phát hiện lỗi abort
│ ├── cache-ttl.ts # Theo dõi TTL cache cho cắt tỉa ngữ cảnh
│ ├── compact.ts # Logic nén thủ công/tự động
│ ├── extensions.ts # Load extension pi cho run nhúng
│ ├── extra-params.ts # Tham số stream riêng provider
│ ├── google.ts # Sửa thứ tự turn Google/Gemini
│ ├── history.ts # Giới hạn lịch sử (DM vs nhóm)
│ ├── lanes.ts # Lane lệnh phiên/global
│ ├── logger.ts # Logger hệ thống con
│ ├── model.ts # Giải quyết model qua ModelRegistry
│ ├── runs.ts # Theo dõi run đang hoạt động, abort, queue
│ ├── sandbox-info.ts # Thông tin sandbox cho system prompt
│ ├── session-manager-cache.ts # Caching instance SessionManager
│ ├── session-manager-init.ts # Khởi tạo file phiên
│ ├── system-prompt.ts # Builder system prompt
│ ├── tool-split.ts # Chia công cụ thành builtIn vs custom
│ ├── types.ts # EmbeddedPiAgentMeta, EmbeddedPiRunResult
│ └── utils.ts # Ánh xạ ThinkLevel, mô tả lỗi
├── pi-embedded-subscribe.ts # Đăng ký/dispatch sự kiện phiên
├── pi-embedded-subscribe.types.ts # SubscribeEmbeddedPiSessionParams
├── pi-embedded-subscribe.handlers.ts # Factory handler sự kiện
├── pi-embedded-subscribe.handlers.lifecycle.ts
├── pi-embedded-subscribe.handlers.types.ts
├── pi-embedded-block-chunker.ts # Chunking phản hồi block streaming
├── pi-embedded-messaging.ts # Theo dõi công cụ nhắn tin đã gửi
├── pi-embedded-helpers.ts # Phân loại lỗi, xác thực turn
├── pi-embedded-helpers/ # Module helper
├── pi-embedded-utils.ts # Tiện ích định dạng
├── pi-tools.ts # createMayrosCodingTools()
├── pi-tools.abort.ts # Bao bọc AbortSignal cho công cụ
├── pi-tools.policy.ts # Chính sách allowlist/denylist công cụ
├── pi-tools.read.ts # Tùy chỉnh công cụ read
├── pi-tools.schema.ts # Chuẩn hóa schema công cụ
├── pi-tools.types.ts # Alias kiểu AnyAgentTool
├── pi-tool-definition-adapter.ts # Adapter AgentTool -> ToolDefinition
├── pi-settings.ts # Ghi đè cài đặt
├── pi-extensions/ # Extension pi tùy chỉnh
│ ├── compaction-safeguard.ts # Extension safeguard
│ ├── compaction-safeguard-runtime.ts
│ ├── context-pruning.ts # Extension cắt tỉa ngữ cảnh Cache-TTL
│ └── context-pruning/
├── model-auth.ts # Giải quyết profile xác thực
├── auth-profiles.ts # Kho profile, cooldown, failover
├── model-selection.ts # Giải quyết model mặc định
├── models-config.ts # Tạo models.json
├── model-catalog.ts # Cache catalog model
├── context-window-guard.ts # Xác thực cửa sổ ngữ cảnh
├── failover-error.ts # Class FailoverError
├── defaults.ts # DEFAULT_PROVIDER, DEFAULT_MODEL
├── system-prompt.ts # buildAgentSystemPrompt()
├── system-prompt-params.ts # Giải quyết tham số system prompt
├── system-prompt-report.ts # Tạo báo cáo debug
├── tool-summaries.ts # Tóm tắt mô tả công cụ
├── tool-policy.ts # Giải quyết chính sách công cụ
├── transcript-policy.ts # Chính sách xác thực transcript
├── skills.ts # Snapshot/build prompt skill
├── skills/ # Hệ thống con skill
├── sandbox.ts # Giải quyết ngữ cảnh sandbox
├── sandbox/ # Hệ thống con sandbox
├── channel-tools.ts # Chèn công cụ riêng kênh
├── mayros-tools.ts # Công cụ riêng Mayros
├── bash-tools.ts # Công cụ exec/process
├── apply-patch.ts # Công cụ apply_patch (OpenAI)
├── tools/ # Triển khai công cụ riêng lẻ
│ ├── browser-tool.ts
│ ├── canvas-tool.ts
│ ├── cron-tool.ts
│ ├── discord-actions*.ts
│ ├── gateway-tool.ts
│ ├── image-tool.ts
│ ├── message-tool.ts
│ ├── nodes-tool.ts
│ ├── session*.ts
│ ├── slack-actions.ts
│ ├── telegram-actions.ts
│ ├── web-*.ts
│ └── whatsapp-actions.ts
└── ...
Quy trình tích hợp cốt lõi
1. Chạy Embedded Agent
Điểm vào chính là runEmbeddedPiAgent() trong pi-embedded-runner/run.ts:
typescriptimport { 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: mayrosConfig, prompt: "Xin chào, bạn khỏe không?", provider: "anthropic", model: "claude-sonnet-4-20250514", timeoutMs: 120_000, runId: "run-abc", onBlockReply: async (payload) => { await sendToChannel(payload.text, payload.mediaUrls); }, });
2. Tạo phiên
Bên trong runEmbeddedAttempt() (được gọi bởi runEmbeddedPiAgent()), SDK pi được sử dụng:
typescriptimport { 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. Đăng ký sự kiện
subscribeEmbeddedPiSession() đăng ký các sự kiện AgentSession của pi:
typescriptconst 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, });
Các sự kiện được xử lý bao gồm:
message_start/message_end/message_update(streaming text/thinking)tool_execution_start/tool_execution_update/tool_execution_endturn_start/turn_endagent_start/agent_endauto_compaction_start/auto_compaction_end
4. Prompting
Sau khi thiết lập, phiên được nhắc nhở:
typescriptawait session.prompt(effectivePrompt, { images: imageResult.images });
SDK xử lý vòng lặp agent đầy đủ: gửi đến LLM, thực thi lệnh gọi công cụ, streaming phản hồi.
Kiến trúc công cụ
Pipeline công cụ
- Công cụ cơ bản:
codingToolscủa pi (read, bash, edit, write) - Thay thế tùy chỉnh: Mayros thay bash bằng
exec/process, tùy chỉnh read/edit/write cho sandbox - Công cụ Mayros: nhắn tin, browser, canvas, phiên, cron, gateway, v.v.
- Công cụ kênh: Công cụ hành động riêng Discord/Telegram/Slack/WhatsApp
- Lọc chính sách: Công cụ được lọc theo profile, provider, agent, nhóm, chính sách sandbox
- Chuẩn hóa schema: Schema được làm sạch cho quirk Gemini/OpenAI
- Bao bọc AbortSignal: Công cụ được bao bọc để tuân thủ signal abort
Adapter định nghĩa công cụ
AgentTool của pi-agent-core có chữ ký execute khác với ToolDefinition của pi-coding-agent. Adapter trong pi-tool-definition-adapter.ts kết nối điều này:
typescriptexport 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) => { // chữ ký pi-coding-agent khác với pi-agent-core return await tool.execute(toolCallId, params, signal, onUpdate); }, })); }
Chiến lược chia công cụ
splitSdkTools() truyền tất cả công cụ qua customTools:
typescriptexport function splitSdkTools(options: { tools: AnyAgentTool[]; sandboxEnabled: boolean }) { return { builtInTools: [], // Trống. Chúng ta ghi đè mọi thứ customTools: toToolDefinitions(options.tools), }; }
Điều này đảm bảo lọc chính sách, tích hợp sandbox và toolset mở rộng của Mayros vẫn nhất quán qua các provider.
Xây dựng System Prompt
System prompt được xây dựng trong buildAgentSystemPrompt() (system-prompt.ts). Nó tập hợp một prompt đầy đủ với các phần bao gồm Tooling, Tool Call Style, hàng rào bảo vệ an toàn, tham chiếu Mayros CLI, Skills, Docs, Workspace, Sandbox, Messaging, Reply Tags, Voice, Silent Replies, Heartbeats, metadata Runtime, cộng Memory và Reactions khi được bật, và file ngữ cảnh tùy chọn và nội dung system prompt bổ sung. Các phần được cắt ngắn cho chế độ prompt tối thiểu được sử dụng bởi subagent.
Prompt được áp dụng sau khi tạo phiên qua applySystemPromptOverrideToSession():
typescriptconst systemPromptOverride = createSystemPromptOverride(appendPrompt); applySystemPromptOverrideToSession(session, systemPromptOverride);
Quản lý phiên
File phiên
Phiên là file JSONL với cấu trúc cây (liên kết id/parentId). SessionManager của Pi xử lý lưu trữ:
typescriptconst sessionManager = SessionManager.open(params.sessionFile);
Mayros bao bọc điều này với guardSessionManager() để đảm bảo an toàn kết quả công cụ.
Caching phiên
session-manager-cache.ts cache các instance SessionManager để tránh phân tích file lặp lại:
typescriptawait prewarmSessionFile(params.sessionFile); sessionManager = SessionManager.open(params.sessionFile); trackSessionManagerAccess(params.sessionFile);
Giới hạn lịch sử
limitHistoryTurns() cắt tỉa lịch sử cuộc trò chuyện dựa trên loại kênh (DM vs nhóm).
Nén
Auto-compaction kích hoạt khi tràn ngữ cảnh. compactEmbeddedPiSessionDirect() xử lý nén thủ công:
typescriptconst compactResult = await compactEmbeddedPiSessionDirect({ sessionId, sessionFile, provider, model, ... });
Xác thực & Giải quyết model
Profile xác thực
Mayros duy trì kho profile xác thực với nhiều API key cho mỗi provider:
typescriptconst authStore = ensureAuthProfileStore(agentDir, { allowKeychainPrompt: false }); const profileOrder = resolveAuthProfileOrder({ cfg, store: authStore, provider, preferredProfile });
Profile xoay khi thất bại với theo dõi cooldown:
typescriptawait markAuthProfileFailure({ store, profileId, reason, cfg, agentDir }); const rotated = await advanceAuthProfile();
Giải quyết model
typescriptimport { resolveModel } from "./pi-embedded-runner/model.js"; const { model, error, authStorage, modelRegistry } = resolveModel( provider, modelId, agentDir, config, ); // Sử dụng ModelRegistry và AuthStorage của pi authStorage.setRuntimeApiKey(model.provider, apiKeyInfo.apiKey);
Failover
FailoverError kích hoạt dự phòng model khi được cấu hình:
typescriptif (fallbackConfigured && isFailoverErrorMessage(errorText)) { throw new FailoverError(errorText, { reason: promptFailoverReason ?? "unknown", provider, model: modelId, profileId, status: resolveFailoverStatus(promptFailoverReason), }); }
Extension Pi
Mayros tải extension pi tùy chỉnh cho hành vi chuyên biệt:
Safeguard nén
pi-extensions/compaction-safeguard.ts thêm hàng rào bảo vệ vào nén, bao gồm ngân sách token thích ứng cộng tóm tắt thất bại công cụ và hoạt động file:
typescriptif (resolveCompactionMode(params.cfg) === "safeguard") { setCompactionSafeguardRuntime(params.sessionManager, { maxHistoryShare }); paths.push(resolvePiExtensionPath("compaction-safeguard")); }
Cắt tỉa ngữ cảnh
pi-extensions/context-pruning.ts triển khai cắt tỉa ngữ cảnh dựa trên cache-TTL:
typescriptif (cfg?.agents?.defaults?.contextPruning?.mode === "cache-ttl") { setContextPruningRuntime(params.sessionManager, { settings, contextWindowTokens, isToolPrunable, lastCacheTouchAt, }); paths.push(resolvePiExtensionPath("context-pruning")); }
Streaming & Phản hồi block
Block chunking
EmbeddedBlockChunker quản lý streaming text thành các block phản hồi riêng biệt:
typescriptconst blockChunker = blockChunking ? new EmbeddedBlockChunker(blockChunking) : null;
Loại bỏ thẻ Thinking/Final
Output streaming được xử lý để loại bỏ block <think>/<thinking> và trích xuất nội dung <final>:
typescriptconst stripBlockTags = (text: string, state: { thinking: boolean; final: boolean }) => { // Loại bỏ nội dung <think>...</think> // Nếu enforceFinalTag, chỉ trả về nội dung <final>...</final> };
Chỉ thị phản hồi
Chỉ thị phản hồi như [[media:url]], [[voice]], [[reply:id]] được phân tích và trích xuất:
typescriptconst { text: cleanedText, mediaUrls, audioAsVoice, replyToId } = consumeReplyDirectives(chunk);
Xử lý lỗi
Phân loại lỗi
pi-embedded-helpers.ts phân loại lỗi cho xử lý phù hợp:
typescriptisContextOverflowError(errorText) // Ngữ cảnh quá lớn isCompactionFailureError(errorText) // Nén thất bại isAuthAssistantError(lastAssistant) // Thất bại xác thực isRateLimitAssistantError(...) // Rate limited isFailoverAssistantError(...) // Nên failover classifyFailoverReason(errorText) // "auth" | "rate_limit" | "quota" | "timeout" | ...
Dự phòng mức thinking
Nếu mức thinking không được hỗ trợ, nó quay về:
typescriptconst fallbackThinking = pickFallbackThinkingLevel({ message: errorText, attempted: attemptedThinking, }); if (fallbackThinking) { thinkLevel = fallbackThinking; continue; }
Tích hợp Sandbox
Khi chế độ sandbox được bật, công cụ và đường dẫn bị hạn chế:
typescriptconst sandbox = await resolveSandboxContext({ config: params.config, sessionKey: sandboxSessionKey, workspaceDir: resolvedWorkspace, }); if (sandboxRoot) { // Sử dụng công cụ read/edit/write đã sandbox // Exec chạy trong container // Browser sử dụng URL bridge }
Xử lý riêng provider
Anthropic
- Scrubbing chuỗi magic từ chối
- Xác thực turn cho vai trò liên tiếp
- Tương thích tham số Claude Code
Google/Gemini
- Sửa thứ tự turn (
applyGoogleTurnOrderingFix) - Khử trùng schema công cụ (
sanitizeToolsForGoogle) - Khử trùng lịch sử phiên (
sanitizeSessionHistory)
OpenAI
- Công cụ
apply_patchcho model Codex - Xử lý hạ cấp mức thinking
Tích hợp TUI
Mayros cũng có chế độ TUI local sử dụng trực tiếp component pi-tui:
typescript// src/tui/tui.ts import { ... } from "@mariozechner/pi-tui";
Điều này cung cấp trải nghiệm terminal tương tác tương tự chế độ native của pi.
Sự khác biệt chính so với Pi CLI
| Khía cạnh | Pi CLI | Mayros Embedded |
|---|---|---|
| Gọi | Lệnh pi / RPC | SDK qua createAgentSession() |
| Công cụ | Công cụ coding mặc định | Bộ công cụ Mayros tùy chỉnh |
| System prompt | AGENTS.md + prompt | Động theo kênh/ngữ cảnh |
| Lưu trữ phiên | ~/.pi/agent/sessions/ | ~/.mayros/agents/<agentId>/sessions/ (hoặc $MAYROS_STATE_DIR/agents/<agentId>/sessions/) |
| Xác thực | Credential đơn | Đa profile với xoay |
| Extension | Tải từ disk | Lập trình + đường dẫn disk |
| Xử lý sự kiện | Render TUI | Dựa trên callback (onBlockReply, v.v.) |
Cân nhắc tương lai
Khu vực cho việc làm lại tiềm năng:
- Căn chỉnh chữ ký công cụ: Hiện đang điều chỉnh giữa chữ ký pi-agent-core và pi-coding-agent
- Bao bọc session manager:
guardSessionManagerthêm an toàn nhưng tăng độ phức tạp - Tải extension: Có thể sử dụng
ResourceLoadercủa pi trực tiếp hơn - Độ phức tạp handler streaming:
subscribeEmbeddedPiSessionđã phát triển lớn - Quirk provider: Nhiều codepath riêng provider mà pi có thể xử lý
Test
Tất cả test hiện có bao phủ tích hợp pi và extension của nó:
src/agents/pi-embedded-block-chunker.test.tssrc/agents/pi-embedded-helpers.buildbootstrapcontextfiles.test.tssrc/agents/pi-embedded-helpers.classifyfailoverreason.test.tssrc/agents/pi-embedded-helpers.downgradeopenai-reasoning.test.tssrc/agents/pi-embedded-helpers.formatassistanterrortext.test.tssrc/agents/pi-embedded-helpers.formatrawassistanterrorforui.test.tssrc/agents/pi-embedded-helpers.image-dimension-error.test.tssrc/agents/pi-embedded-helpers.image-size-error.test.tssrc/agents/pi-embedded-helpers.isautherrormessage.test.tssrc/agents/pi-embedded-helpers.isbillingerrormessage.test.tssrc/agents/pi-embedded-helpers.iscloudcodeassistformaterror.test.tssrc/agents/pi-embedded-helpers.iscompactionfailureerror.test.tssrc/agents/pi-embedded-helpers.iscontextoverflowerror.test.tssrc/agents/pi-embedded-helpers.isfailovererrormessage.test.tssrc/agents/pi-embedded-helpers.islikelycontextoverflowerror.test.tssrc/agents/pi-embedded-helpers.ismessagingtoolduplicate.test.tssrc/agents/pi-embedded-helpers.messaging-duplicate.test.tssrc/agents/pi-embedded-helpers.normalizetextforcomparison.test.tssrc/agents/pi-embedded-helpers.resolvebootstrapmaxchars.test.ts- (và nhiều test khác...)