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"
}
PackageMục đích
pi-aiTrừu tượng LLM cốt lõi: Model, streamSimple, kiểu message, API provider
pi-agent-coreVòng lặp agent, thực thi công cụ, kiểu AgentMessage
pi-coding-agentSDK cấp cao: createAgentSession, SessionManager, AuthStorage, ModelRegistry, công cụ tích hợp
pi-tuiComponent 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:

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: 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:

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. Đăng ký sự kiện

subscribeEmbeddedPiSession() đăng ký các sự kiện AgentSession của pi:

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,
});

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_end
  • turn_start / turn_end
  • agent_start / agent_end
  • auto_compaction_start / auto_compaction_end

4. Prompting

Sau khi thiết lập, phiên được nhắc nhở:

typescript
await 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ụ

  1. Công cụ cơ bản: codingTools của pi (read, bash, edit, write)
  2. Thay thế tùy chỉnh: Mayros thay bash bằng exec/process, tùy chỉnh read/edit/write cho sandbox
  3. Công cụ Mayros: nhắn tin, browser, canvas, phiên, cron, gateway, v.v.
  4. Công cụ kênh: Công cụ hành động riêng Discord/Telegram/Slack/WhatsApp
  5. Lọc chính sách: Công cụ được lọc theo profile, provider, agent, nhóm, chính sách sandbox
  6. Chuẩn hóa schema: Schema được làm sạch cho quirk Gemini/OpenAI
  7. 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:

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) => {
      // 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:

typescript
export 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():

typescript
const 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ữ:

typescript
const 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:

typescript
await 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:

typescript
const 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:

typescript
const 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:

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

Giải quyết model

typescript
import { 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:

typescript
if (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:

typescript
if (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:

typescript
if (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:

typescript
const 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>:

typescript
const 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:

typescript
const { 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:

typescript
isContextOverflowError(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ề:

typescript
const 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ế:

typescript
const 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_patch cho 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ạnhPi CLIMayros Embedded
GọiLệnh pi / RPCSDK qua createAgentSession()
Công cụCông cụ coding mặc địnhBộ công cụ Mayros tùy chỉnh
System promptAGENTS.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ựcCredential đơnĐa profile với xoay
ExtensionTải từ diskLập trình + đường dẫn disk
Xử lý sự kiệnRender TUIDự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:

  1. 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
  2. Bao bọc session manager: guardSessionManager thêm an toàn nhưng tăng độ phức tạp
  3. Tải extension: Có thể sử dụng ResourceLoader của pi trực tiếp hơn
  4. Độ phức tạp handler streaming: subscribeEmbeddedPiSession đã phát triển lớn
  5. 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.ts
  • src/agents/pi-embedded-helpers.buildbootstrapcontextfiles.test.ts
  • src/agents/pi-embedded-helpers.classifyfailoverreason.test.ts
  • src/agents/pi-embedded-helpers.downgradeopenai-reasoning.test.ts
  • src/agents/pi-embedded-helpers.formatassistanterrortext.test.ts
  • src/agents/pi-embedded-helpers.formatrawassistanterrorforui.test.ts
  • src/agents/pi-embedded-helpers.image-dimension-error.test.ts
  • src/agents/pi-embedded-helpers.image-size-error.test.ts
  • src/agents/pi-embedded-helpers.isautherrormessage.test.ts
  • src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts
  • src/agents/pi-embedded-helpers.iscloudcodeassistformaterror.test.ts
  • src/agents/pi-embedded-helpers.iscompactionfailureerror.test.ts
  • src/agents/pi-embedded-helpers.iscontextoverflowerror.test.ts
  • src/agents/pi-embedded-helpers.isfailovererrormessage.test.ts
  • src/agents/pi-embedded-helpers.islikelycontextoverflowerror.test.ts
  • src/agents/pi-embedded-helpers.ismessagingtoolduplicate.test.ts
  • src/agents/pi-embedded-helpers.messaging-duplicate.test.ts
  • src/agents/pi-embedded-helpers.normalizetextforcomparison.test.ts
  • src/agents/pi-embedded-helpers.resolvebootstrapmaxchars.test.ts
  • (và nhiều test khác...)