بنية تكامل Pi
يصف هذا المستند كيف يتكامل Mayros مع pi-coding-agent وحزمه الشقيقة (pi-ai، pi-agent-core، pi-tui) لتشغيل قدرات وكيل الذكاء الاصطناعي الخاصة به.
نظرة عامة
يستخدم Mayros SDK الخاص بـ pi لتضمين وكيل ترميز الذكاء الاصطناعي في بنية بوابة المراسلة الخاصة به. بدلاً من تفريخ pi كعملية فرعية أو استخدام وضع RPC، يستورد Mayros مباشرة وينشئ AgentSession الخاص بـ pi عبر createAgentSession(). يوفر هذا النهج المضمن:
- التحكم الكامل في دورة حياة الجلسة ومعالجة الأحداث
- حقن أداة مخصصة (المراسلة، sandbox، إجراءات خاصة بالقناة)
- تخصيص المطالبة النظامية لكل قناة/سياق
- استمرارية الجلسة مع دعم التفرع/الضغط
- تدوير ملف تعريف المصادقة متعدد الحسابات مع الاحتياطي
- تبديل النموذج بشكل مستقل عن الموفر
تبعيات الحزم
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" }
| الحزمة | الغرض |
|---|---|
pi-ai | تجريدات LLM الأساسية: Model، streamSimple، أنواع الرسائل، واجهات برمجة تطبيقات الموفر |
pi-agent-core | حلقة الوكيل، تنفيذ الأداة، أنواع AgentMessage |
pi-coding-agent | SDK عالي المستوى: createAgentSession، SessionManager، AuthStorage، ModelRegistry، أدوات مدمجة |
pi-tui | مكونات واجهة المستخدم الطرفية (تُستخدم في وضع TUI المحلي لـ Mayros) |
بنية الملف
src/agents/
├── pi-embedded-runner.ts # إعادة التصدير من pi-embedded-runner/
├── pi-embedded-runner/
│ ├── run.ts # نقطة الدخول الرئيسية: runEmbeddedPiAgent()
│ ├── run/
│ │ ├── attempt.ts # منطق محاولة واحدة مع إعداد الجلسة
│ │ ├── params.ts # نوع RunEmbeddedPiAgentParams
│ │ ├── payloads.ts # بناء حمولات الاستجابة من نتائج التشغيل
│ │ ├── images.ts # حقن صورة نموذج الرؤية
│ │ └── types.ts # EmbeddedRunAttemptResult
│ ├── abort.ts # كشف خطأ الإلغاء
│ ├── cache-ttl.ts # تتبع TTL للتخزين المؤقت لتقليم السياق
│ ├── compact.ts # منطق الضغط اليدوي/التلقائي
│ ├── extensions.ts # تحميل امتدادات pi للتشغيلات المضمنة
│ ├── extra-params.ts # معلمات البث الخاصة بالموفر
│ ├── google.ts # إصلاحات ترتيب دورة Google/Gemini
│ ├── history.ts # تحديد السجل (DM مقابل المجموعة)
│ ├── lanes.ts # مسارات أوامر الجلسة/العامة
│ ├── logger.ts # مسجل النظام الفرعي
│ ├── model.ts # حل النموذج عبر ModelRegistry
│ ├── runs.ts # تتبع التشغيل النشط، الإلغاء، قائمة الانتظار
│ ├── sandbox-info.ts # معلومات Sandbox للمطالبة النظامية
│ ├── session-manager-cache.ts # التخزين المؤقت لمثيل SessionManager
│ ├── session-manager-init.ts # تهيئة ملف الجلسة
│ ├── system-prompt.ts # منشئ المطالبة النظامية
│ ├── tool-split.ts # تقسيم الأدوات إلى builtIn مقابل مخصص
│ ├── types.ts # EmbeddedPiAgentMeta، EmbeddedPiRunResult
│ └── utils.ts # تعيين ThinkLevel، وصف الخطأ
├── pi-embedded-subscribe.ts # اشتراك/إرسال حدث الجلسة
├── pi-embedded-subscribe.types.ts # SubscribeEmbeddedPiSessionParams
├── pi-embedded-subscribe.handlers.ts # مصنع معالج الأحداث
├── pi-embedded-subscribe.handlers.lifecycle.ts
├── pi-embedded-subscribe.handlers.types.ts
├── pi-embedded-block-chunker.ts # تقسيم الرد على الكتلة بالبث
├── pi-embedded-messaging.ts # تتبع أداة المراسلة المرسلة
├── pi-embedded-helpers.ts # تصنيف الخطأ، التحقق من الدورة
├── pi-embedded-helpers/ # وحدات المساعد
├── pi-embedded-utils.ts # أدوات التنسيق
├── pi-tools.ts # createMayrosCodingTools()
├── pi-tools.abort.ts # تغليف AbortSignal للأدوات
├── pi-tools.policy.ts # سياسة قائمة السماح/الحظر للأداة
├── pi-tools.read.ts # تخصيصات أداة القراءة
├── pi-tools.schema.ts # تطبيع مخطط الأداة
├── pi-tools.types.ts # اسم مستعار لنوع AnyAgentTool
├── pi-tool-definition-adapter.ts # محول AgentTool -> ToolDefinition
├── pi-settings.ts # تجاوزات الإعدادات
├── pi-extensions/ # امتدادات pi مخصصة
│ ├── compaction-safeguard.ts # امتداد الحماية
│ ├── compaction-safeguard-runtime.ts
│ ├── context-pruning.ts # امتداد تقليم السياق Cache-TTL
│ └── context-pruning/
├── model-auth.ts # حل ملف تعريف المصادقة
├── auth-profiles.ts # مخزن الملف الشخصي، فترة التهدئة، الاحتياطي
├── model-selection.ts # حل النموذج الافتراضي
├── models-config.ts # توليد models.json
├── model-catalog.ts # ذاكرة التخزين المؤقت لكتالوج النموذج
├── context-window-guard.ts # التحقق من نافذة السياق
├── failover-error.ts # فئة FailoverError
├── defaults.ts # DEFAULT_PROVIDER، DEFAULT_MODEL
├── system-prompt.ts # buildAgentSystemPrompt()
├── system-prompt-params.ts # حل معلمة المطالبة النظامية
├── system-prompt-report.ts # توليد تقرير التصحيح
├── tool-summaries.ts # ملخصات وصف الأداة
├── tool-policy.ts # حل سياسة الأداة
├── transcript-policy.ts # سياسة التحقق من النص
├── skills.ts # لقطة المهارة/بناء المطالبة
├── skills/ # نظام فرعي للمهارات
├── sandbox.ts # حل سياق Sandbox
├── sandbox/ # نظام فرعي Sandbox
├── channel-tools.ts # حقن أداة خاصة بالقناة
├── mayros-tools.ts # أدوات خاصة بـ Mayros
├── bash-tools.ts # أدوات exec/process
├── apply-patch.ts # أداة apply_patch (OpenAI)
├── tools/ # تطبيقات الأدوات الفردية
│ ├── 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
└── ...
تدفق التكامل الأساسي
1. تشغيل وكيل مضمن
نقطة الدخول الرئيسية هي runEmbeddedPiAgent() في 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: "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())، يتم استخدام SDK الخاص بـ pi:
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. اشتراك الحدث
يشترك subscribeEmbeddedPiSession() في أحداث AgentSession الخاصة بـ 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, });
الأحداث المعالجة تشمل:
message_start/message_end/message_update(بث النص/التفكير)tool_execution_start/tool_execution_update/tool_execution_endturn_start/turn_endagent_start/agent_endauto_compaction_start/auto_compaction_end
4. المطالبة
بعد الإعداد، يتم مطالبة الجلسة:
typescriptawait session.prompt(effectivePrompt, { images: imageResult.images });
يتعامل SDK مع حلقة الوكيل الكاملة: الإرسال إلى LLM، تنفيذ استدعاءات الأداة، بث الردود.
بنية الأداة
خط أنابيب الأداة
- الأدوات الأساسية: أدوات
codingToolsالخاصة بـ pi (read، bash، edit، write) - الاستبدالات المخصصة: يستبدل Mayros bash بـ
exec/process، يخصص read/edit/write لـ sandbox - أدوات Mayros: المراسلة، المتصفح، canvas، الجلسات، cron، البوابة، إلخ.
- أدوات القناة: أدوات إجراءات خاصة بـ Discord/Telegram/Slack/WhatsApp
- تصفية السياسة: الأدوات مُصفاة حسب الملف الشخصي، الموفر، الوكيل، المجموعة، سياسات sandbox
- تطبيع المخطط: المخططات منظفة لخصوصيات Gemini/OpenAI
- تغليف AbortSignal: الأدوات مُغلفة لاحترام إشارات الإلغاء
محول تعريف الأداة
إن AgentTool الخاص بـ pi-agent-core له توقيع execute مختلف عن ToolDefinition الخاص بـ pi-coding-agent. المحول في pi-tool-definition-adapter.ts يجسر هذا:
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) => { // توقيع pi-coding-agent يختلف عن pi-agent-core return await tool.execute(toolCallId, params, signal, onUpdate); }, })); }
استراتيجية تقسيم الأداة
يمرر splitSdkTools() جميع الأدوات عبر customTools:
typescriptexport function splitSdkTools(options: { tools: AnyAgentTool[]; sandboxEnabled: boolean }) { return { builtInTools: [], // فارغ. نحن نتجاوز كل شيء customTools: toToolDefinitions(options.tools), }; }
هذا يضمن أن تصفية السياسة الخاصة بـ Mayros، تكامل sandbox، ومجموعة الأدوات الموسعة تبقى متسقة عبر الموفرين.
بناء المطالبة النظامية
يتم بناء المطالبة النظامية في buildAgentSystemPrompt() (system-prompt.ts). تجمع مطالبة كاملة مع أقسام بما في ذلك الأدوات، أسلوب استدعاء الأداة، حواجز الأمان، مرجع Mayros CLI، المهارات، الوثائق، مساحة العمل، Sandbox، المراسلة، علامات الرد، الصوت، الردود الصامتة، نبضات القلب، بيانات تعريفية وقت التشغيل، بالإضافة إلى الذاكرة والتفاعلات عند التمكين، وملفات السياق الاختيارية ومحتوى المطالبة النظامية الإضافي. يتم قص الأقسام لوضع المطالبة الأدنى المستخدم بواسطة الوكلاء الفرعيين.
يتم تطبيق المطالبة بعد إنشاء الجلسة عبر applySystemPromptOverrideToSession():
typescriptconst systemPromptOverride = createSystemPromptOverride(appendPrompt); applySystemPromptOverrideToSession(session, systemPromptOverride);
إدارة الجلسة
ملفات الجلسة
الجلسات هي ملفات JSONL مع بنية شجرية (ربط id/parentId). يتعامل SessionManager الخاص بـ Pi مع الاستمرارية:
typescriptconst sessionManager = SessionManager.open(params.sessionFile);
يغلف Mayros هذا بـ guardSessionManager() لسلامة نتيجة الأداة.
التخزين المؤقت للجلسة
يخزن session-manager-cache.ts مثيلات SessionManager مؤقتًا لتجنب تحليل الملفات المتكرر:
typescriptawait prewarmSessionFile(params.sessionFile); sessionManager = SessionManager.open(params.sessionFile); trackSessionManagerAccess(params.sessionFile);
تحديد السجل
يقص limitHistoryTurns() سجل المحادثة بناءً على نوع القناة (DM مقابل المجموعة).
الضغط
يُشغل الضغط التلقائي عند تجاوز السياق. يتعامل compactEmbeddedPiSessionDirect() مع الضغط اليدوي:
typescriptconst compactResult = await compactEmbeddedPiSessionDirect({ sessionId, sessionFile, provider, model, ... });
المصادقة وحل النموذج
ملفات تعريف المصادقة
يحتفظ Mayros بمخزن ملف تعريف المصادقة مع مفاتيح API متعددة لكل موفر:
typescriptconst authStore = ensureAuthProfileStore(agentDir, { allowKeychainPrompt: false }); const profileOrder = resolveAuthProfileOrder({ cfg, store: authStore, provider, preferredProfile });
تتناوب الملفات الشخصية على حالات الفشل مع تتبع فترة التهدئة:
typescriptawait markAuthProfileFailure({ store, profileId, reason, cfg, agentDir }); const rotated = await advanceAuthProfile();
حل النموذج
typescriptimport { resolveModel } from "./pi-embedded-runner/model.js"; const { model, error, authStorage, modelRegistry } = resolveModel( provider, modelId, agentDir, config, ); // يستخدم ModelRegistry و AuthStorage الخاصين بـ pi authStorage.setRuntimeApiKey(model.provider, apiKeyInfo.apiKey);
الاحتياطي
يُشغل FailoverError احتياطي النموذج عند التكوين:
typescriptif (fallbackConfigured && isFailoverErrorMessage(errorText)) { throw new FailoverError(errorText, { reason: promptFailoverReason ?? "unknown", provider, model: modelId, profileId, status: resolveFailoverStatus(promptFailoverReason), }); }
امتدادات Pi
يحمل Mayros امتدادات pi مخصصة لسلوك متخصص:
حماية الضغط
يضيف pi-extensions/compaction-safeguard.ts حواجز حماية للضغط، بما في ذلك ميزانية رمز تكيفية بالإضافة إلى فشل الأداة وملخصات عمليات الملف:
typescriptif (resolveCompactionMode(params.cfg) === "safeguard") { setCompactionSafeguardRuntime(params.sessionManager, { maxHistoryShare }); paths.push(resolvePiExtensionPath("compaction-safeguard")); }
تقليم السياق
ينفذ pi-extensions/context-pruning.ts تقليم السياق المستند إلى cache-TTL:
typescriptif (cfg?.agents?.defaults?.contextPruning?.mode === "cache-ttl") { setContextPruningRuntime(params.sessionManager, { settings, contextWindowTokens, isToolPrunable, lastCacheTouchAt, }); paths.push(resolvePiExtensionPath("context-pruning")); }
البث وردود الكتلة
تقسيم الكتلة
يدير EmbeddedBlockChunker بث النص إلى كتل رد منفصلة:
typescriptconst blockChunker = blockChunking ? new EmbeddedBlockChunker(blockChunking) : null;
إزالة علامة التفكير/النهائي
تتم معالجة مخرجات البث لإزالة كتل <think>/<thinking> واستخراج محتوى <final>:
typescriptconst stripBlockTags = (text: string, state: { thinking: boolean; final: boolean }) => { // إزالة محتوى <think>...</think> // إذا enforceFinalTag، قم فقط بإرجاع محتوى <final>...</final> };
توجيهات الرد
يتم تحليل واستخراج توجيهات الرد مثل [[media:url]]، [[voice]]، [[reply:id]]:
typescriptconst { text: cleanedText, mediaUrls, audioAsVoice, replyToId } = consumeReplyDirectives(chunk);
معالجة الأخطاء
تصنيف الخطأ
يصنف pi-embedded-helpers.ts الأخطاء للمعالجة المناسبة:
typescriptisContextOverflowError(errorText) // السياق كبير جدًا isCompactionFailureError(errorText) // فشل الضغط isAuthAssistantError(lastAssistant) // فشل المصادقة isRateLimitAssistantError(...) // محدود بالمعدل isFailoverAssistantError(...) // يجب الاحتياط classifyFailoverReason(errorText) // "auth" | "rate_limit" | "quota" | "timeout" | ...
احتياطي مستوى التفكير
إذا كان مستوى التفكير غير مدعوم، فإنه يعود:
typescriptconst fallbackThinking = pickFallbackThinkingLevel({ message: errorText, attempted: attemptedThinking, }); if (fallbackThinking) { thinkLevel = fallbackThinking; continue; }
تكامل Sandbox
عند تمكين وضع sandbox، يتم تقييد الأدوات والمسارات:
typescriptconst sandbox = await resolveSandboxContext({ config: params.config, sessionKey: sandboxSessionKey, workspaceDir: resolvedWorkspace, }); if (sandboxRoot) { // استخدم أدوات read/edit/write المُحمية بـ sandbox // يعمل Exec في الحاوية // يستخدم المتصفح عنوان URL للجسر }
معالجة خاصة بالموفر
Anthropic
- إزالة سلسلة رفض سحرية
- التحقق من الدورة للأدوار المتتالية
- توافق معلمة Claude Code
Google/Gemini
- إصلاحات ترتيب الدورة (
applyGoogleTurnOrderingFix) - تعقيم مخطط الأداة (
sanitizeToolsForGoogle) - تعقيم سجل الجلسة (
sanitizeSessionHistory)
OpenAI
- أداة
apply_patchلنماذج Codex - معالجة تخفيض مستوى التفكير
تكامل TUI
لدى Mayros أيضًا وضع TUI محلي يستخدم مكونات pi-tui مباشرة:
typescript// src/tui/tui.ts import { ... } from "@mariozechner/pi-tui";
هذا يوفر تجربة طرفية تفاعلية مشابهة لوضع pi الأصلي.
الاختلافات الرئيسية عن Pi CLI
| الجانب | Pi CLI | Mayros المضمن |
|---|---|---|
| الاستدعاء | أمر pi / RPC | SDK عبر createAgentSession() |
| الأدوات | أدوات الترميز الافتراضية | مجموعة أدوات Mayros المخصصة |
| المطالبة النظامية | AGENTS.md + المطالبات | ديناميكي لكل قناة/سياق |
| تخزين الجلسة | ~/.pi/agent/sessions/ | ~/.mayros/agents/<agentId>/sessions/ (أو $MAYROS_STATE_DIR/agents/<agentId>/sessions/) |
| المصادقة | بيانات اعتماد واحدة | متعدد الملفات الشخصية مع التدوير |
| الامتدادات | محملة من القرص | برمجية + مسارات القرص |
| معالجة الأحداث | عرض TUI | قائم على رد الاتصال (onBlockReply، إلخ.) |
اعتبارات مستقبلية
مجالات لإعادة العمل المحتملة:
- محاذاة توقيع الأداة: التكيف حاليًا بين توقيعات pi-agent-core و pi-coding-agent
- تغليف مدير الجلسة:
guardSessionManagerيضيف الأمان لكن يزيد التعقيد - تحميل الامتداد: يمكن استخدام
ResourceLoaderالخاص بـ pi بشكل أكثر مباشرة - تعقيد معالج البث:
subscribeEmbeddedPiSessionنما كبيرًا - خصوصيات الموفر: العديد من مسارات الكود الخاصة بالموفر التي يمكن لـ pi التعامل معها محتملاً
الاختبارات
جميع الاختبارات الموجودة التي تغطي تكامل pi وامتداداته:
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.tssrc/agents/pi-embedded-helpers.sanitize-session-messages-images.keeps-tool-call-tool-result-ids-unchanged.test.tssrc/agents/pi-embedded-helpers.sanitize-session-messages-images.removes-empty-assistant-text-blocks-but-preserves.test.tssrc/agents/pi-embedded-helpers.sanitizegoogleturnordering.test.tssrc/agents/pi-embedded-helpers.sanitizesessionmessagesimages-thought-signature-stripping.test.tssrc/agents/pi-embedded-helpers.sanitizetoolcallid.test.tssrc/agents/pi-embedded-helpers.sanitizeuserfacingtext.test.tssrc/agents/pi-embedded-helpers.stripthoughtsignatures.test.tssrc/agents/pi-embedded-helpers.validate-turns.test.tssrc/agents/pi-embedded-runner-extraparams.live.test.ts(مباشر)src/agents/pi-embedded-runner-extraparams.test.tssrc/agents/pi-embedded-runner.applygoogleturnorderingfix.test.tssrc/agents/pi-embedded-runner.buildembeddedsandboxinfo.test.tssrc/agents/pi-embedded-runner.createsystempromptoverride.test.tssrc/agents/pi-embedded-runner.get-dm-history-limit-from-session-key.falls-back-provider-default-per-dm-not.test.tssrc/agents/pi-embedded-runner.get-dm-history-limit-from-session-key.returns-undefined-sessionkey-is-undefined.test.tssrc/agents/pi-embedded-runner.google-sanitize-thinking.test.tssrc/agents/pi-embedded-runner.guard.test.tssrc/agents/pi-embedded-runner.limithistoryturns.test.tssrc/agents/pi-embedded-runner.resolvesessionagentids.test.tssrc/agents/pi-embedded-runner.run-embedded-pi-agent.auth-profile-rotation.test.tssrc/agents/pi-embedded-runner.sanitize-session-history.test.tssrc/agents/pi-embedded-runner.splitsdktools.test.tssrc/agents/pi-embedded-runner.test.tssrc/agents/pi-embedded-subscribe.code-span-awareness.test.tssrc/agents/pi-embedded-subscribe.reply-tags.test.tssrc/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.calls-onblockreplyflush-before-tool-execution-start-preserve.test.tssrc/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.does-not-append-text-end-content-is.test.tssrc/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.does-not-call-onblockreplyflush-callback-is-not.test.tssrc/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.does-not-duplicate-text-end-repeats-full.test.tssrc/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.does-not-emit-duplicate-block-replies-text.test.tssrc/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.emits-block-replies-text-end-does-not.test.tssrc/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.emits-reasoning-as-separate-message-enabled.test.tssrc/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.filters-final-suppresses-output-without-start-tag.test.tssrc/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.includes-canvas-action-metadata-tool-summaries.test.tssrc/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.keeps-assistanttexts-final-answer-block-replies-are.test.tssrc/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.keeps-indented-fenced-blocks-intact.test.tssrc/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.reopens-fenced-blocks-splitting-inside-them.test.tssrc/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.splits-long-single-line-fenced-blocks-reopen.test.tssrc/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.streams-soft-chunks-paragraph-preference.test.tssrc/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.subscribeembeddedpisession.test.tssrc/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.suppresses-message-end-block-replies-message-tool.test.tssrc/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.waits-multiple-compaction-retries-before-resolving.test.tssrc/agents/pi-embedded-subscribe.tools.test.tssrc/agents/pi-embedded-utils.test.tssrc/agents/pi-extensions/compaction-safeguard.test.tssrc/agents/pi-extensions/context-pruning.test.tssrc/agents/pi-settings.test.tssrc/agents/pi-tool-definition-adapter.test.tssrc/agents/pi-tools-agent-config.test.tssrc/agents/pi-tools.create-mayros-coding-tools.adds-claude-style-aliases-schemas-without-dropping-b.test.tssrc/agents/pi-tools.create-mayros-coding-tools.adds-claude-style-aliases-schemas-without-dropping-d.test.tssrc/agents/pi-tools.create-mayros-coding-tools.adds-claude-style-aliases-schemas-without-dropping-f.test.tssrc/agents/pi-tools.create-mayros-coding-tools.adds-claude-style-aliases-schemas-without-dropping.test.tssrc/agents/pi-tools.policy.test.tssrc/agents/pi-tools.safe-bins.test.tssrc/agents/pi-tools.workspace-paths.test.ts