Pi-Integrationsarchitektur
Dieses Dokument beschreibt, wie Mayros mit pi-coding-agent und seinen Schwester-Paketen (pi-ai, pi-agent-core, pi-tui) integriert, um seine AI-Agent-Funktionen zu ermöglichen.
Übersicht
Mayros verwendet das Pi SDK, um einen AI-Coding-Agenten in seine Messaging-Gateway-Architektur einzubetten. Anstatt Pi als Subprozess zu spawnen oder den RPC-Modus zu verwenden, importiert und instanziiert Mayros direkt Pi's AgentSession via createAgentSession(). Dieser eingebettete Ansatz bietet:
- Volle Kontrolle über Session-Lebenszyklus und Event-Handling
- Benutzerdefinierte Tool-Injektion (Messaging, Sandbox, Channel-spezifische Aktionen)
- System-Prompt-Anpassung pro Channel/Kontext
- Session-Persistenz mit Branching-/Compaction-Unterstützung
- Multi-Account-Auth-Profil-Rotation mit Failover
- Provider-agnostisches Modell-Switching
Package-Abhängigkeiten
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 | Zweck |
|---|---|
pi-ai | Kern-LLM-Abstraktionen: Model, streamSimple, Message-Typen, Provider-APIs |
pi-agent-core | Agent-Loop, Tool-Ausführung, AgentMessage-Typen |
pi-coding-agent | High-Level-SDK: createAgentSession, SessionManager, AuthStorage, ModelRegistry, eingebaute Tools |
pi-tui | Terminal-UI-Komponenten (verwendet im lokalen TUI-Modus von Mayros) |
Dateistruktur
src/agents/
├── pi-embedded-runner.ts # Re-Exports aus pi-embedded-runner/
├── pi-embedded-runner/
│ ├── run.ts # Haupt-Einstieg: runEmbeddedPiAgent()
│ ├── run/
│ │ ├── attempt.ts # Einzelversuchs-Logik mit Session-Setup
│ │ ├── params.ts # RunEmbeddedPiAgentParams-Typ
│ │ ├── payloads.ts # Response-Payloads aus Run-Ergebnissen bauen
│ │ ├── images.ts # Vision-Model-Image-Injektion
│ │ └── types.ts # EmbeddedRunAttemptResult
│ ├── abort.ts # Abort-Fehler-Erkennung
│ ├── cache-ttl.ts # Cache-TTL-Tracking für Context-Pruning
│ ├── compact.ts # Manuelle/Auto-Compaction-Logik
│ ├── extensions.ts # Pi-Extensions für eingebettete Runs laden
│ ├── extra-params.ts # Provider-spezifische Stream-Params
│ ├── google.ts # Google/Gemini-Turn-Ordering-Fixes
│ ├── history.ts # History-Limiting (DM vs Gruppe)
│ ├── lanes.ts # Session/globale Command-Lanes
│ ├── logger.ts # Subsystem-Logger
│ ├── model.ts # Modell-Auflösung via ModelRegistry
│ ├── runs.ts # Aktive Run-Tracking, Abort, Queue
│ ├── sandbox-info.ts # Sandbox-Info für System-Prompt
│ ├── session-manager-cache.ts # SessionManager-Instanz-Caching
│ ├── session-manager-init.ts # Session-Datei-Initialisierung
│ ├── system-prompt.ts # System-Prompt-Builder
│ ├── tool-split.ts # Tools in builtIn vs custom aufteilen
│ ├── types.ts # EmbeddedPiAgentMeta, EmbeddedPiRunResult
│ └── utils.ts # ThinkLevel-Mapping, Fehlerbeschreibung
├── 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 # Fehlerklassifikation, Turn-Validierung
├── pi-embedded-helpers/ # Helper-Module
├── pi-embedded-utils.ts # Formatierungs-Utilities
├── pi-tools.ts # createMayrosCodingTools()
├── pi-tools.abort.ts # AbortSignal-Wrapping für Tools
├── pi-tools.policy.ts # Tool-Allowlist/Denylist-Policy
├── pi-tools.read.ts # Read-Tool-Anpassungen
├── pi-tools.schema.ts # Tool-Schema-Normalisierung
├── pi-tools.types.ts # AnyAgentTool-Typ-Alias
├── pi-tool-definition-adapter.ts # AgentTool -> ToolDefinition-Adapter
├── pi-settings.ts # Settings-Overrides
├── pi-extensions/ # Benutzerdefinierte Pi-Extensions
│ ├── compaction-safeguard.ts # Safeguard-Extension
│ ├── compaction-safeguard-runtime.ts
│ ├── context-pruning.ts # Cache-TTL-Context-Pruning-Extension
│ └── context-pruning/
├── model-auth.ts # Auth-Profil-Auflösung
├── auth-profiles.ts # Profil-Store, Cooldown, Failover
├── model-selection.ts # Standard-Modell-Auflösung
├── models-config.ts # models.json-Generierung
├── model-catalog.ts # Modell-Katalog-Cache
├── context-window-guard.ts # Context-Window-Validierung
├── failover-error.ts # FailoverError-Klasse
├── defaults.ts # DEFAULT_PROVIDER, DEFAULT_MODEL
├── system-prompt.ts # buildAgentSystemPrompt()
├── system-prompt-params.ts # System-Prompt-Parameter-Auflösung
├── system-prompt-report.ts # Debug-Report-Generierung
├── tool-summaries.ts # Tool-Beschreibungs-Zusammenfassungen
├── tool-policy.ts # Tool-Policy-Auflösung
├── transcript-policy.ts # Transcript-Validierungs-Policy
├── skills.ts # Skill-Snapshot/Prompt-Building
├── skills/ # Skill-Subsystem
├── sandbox.ts # Sandbox-Kontext-Auflösung
├── sandbox/ # Sandbox-Subsystem
├── channel-tools.ts # Channel-spezifische Tool-Injektion
├── mayros-tools.ts # Mayros-spezifische Tools
├── bash-tools.ts # exec/process-Tools
├── apply-patch.ts # apply_patch-Tool (OpenAI)
├── tools/ # Einzelne Tool-Implementierungen
│ ├── 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
└── ...
Kern-Integrations-Flow
1. Embedded Agent ausführen
Der Haupteinstiegspunkt ist runEmbeddedPiAgent() in 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. Session-Erstellung
Innerhalb von runEmbeddedAttempt() (aufgerufen von runEmbeddedPiAgent()), wird das Pi SDK verwendet:
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. Event-Subscription
subscribeEmbeddedPiSession() abonniert Pi's AgentSession-Events:
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, });
Behandelte Events umfassen:
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
Nach dem Setup wird die Session geprompted:
typescriptawait session.prompt(effectivePrompt, { images: imageResult.images });
Das SDK handhabt den vollständigen Agent-Loop: Senden an LLM, Ausführen von Tool-Calls, Streaming von Responses.
Tool-Architektur
Tool-Pipeline
- Base-Tools: Pi's
codingTools(read, bash, edit, write) - Custom-Replacements: Mayros ersetzt bash mit
exec/process, passt read/edit/write für Sandbox an - Mayros-Tools: Messaging, Browser, Canvas, Sessions, Cron, Gateway, etc.
- Channel-Tools: Discord/Telegram/Slack/WhatsApp-spezifische Aktions-Tools
- Policy-Filtering: Tools gefiltert nach Profil, Provider, Agent, Gruppe, Sandbox-Policies
- Schema-Normalisierung: Schemas bereinigt für Gemini/OpenAI-Eigenheiten
- AbortSignal-Wrapping: Tools gewickelt, um Abort-Signale zu respektieren
Tool-Definition-Adapter
Pi-agent-core's AgentTool hat eine andere execute-Signatur als pi-coding-agent's ToolDefinition. Der Adapter in pi-tool-definition-adapter.ts überbrückt dies:
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-Signatur unterscheidet sich von pi-agent-core return await tool.execute(toolCallId, params, signal, onUpdate); }, })); }
Tool-Split-Strategie
splitSdkTools() übergibt alle Tools via customTools:
typescriptexport function splitSdkTools(options: { tools: AnyAgentTool[]; sandboxEnabled: boolean }) { return { builtInTools: [], // Leer. Wir überschreiben alles customTools: toToolDefinitions(options.tools), }; }
Dies stellt sicher, dass Mayros's Policy-Filtering, Sandbox-Integration und erweitertes Toolset über Provider hinweg konsistent bleiben.
System-Prompt-Konstruktion
Der System-Prompt wird in buildAgentSystemPrompt() (system-prompt.ts) gebaut. Er assembliert einen vollständigen Prompt mit Abschnitten einschließlich Tooling, Tool Call Style, Safety-Guardrails, Mayros CLI-Referenz, Skills, Docs, Workspace, Sandbox, Messaging, Reply Tags, Voice, Silent Replies, Heartbeats, Runtime-Metadaten, plus Memory und Reactions wenn aktiviert, und optionale Context-Dateien und Extra-System-Prompt-Content. Abschnitte werden für minimalen Prompt-Modus getrimmt, der von Subagenten verwendet wird.
Der Prompt wird nach Session-Erstellung via applySystemPromptOverrideToSession() angewendet:
typescriptconst systemPromptOverride = createSystemPromptOverride(appendPrompt); applySystemPromptOverrideToSession(session, systemPromptOverride);
Session-Management
Session-Dateien
Sessions sind JSONL-Dateien mit Baumstruktur (id/parentId-Verknüpfung). Pi's SessionManager behandelt Persistenz:
typescriptconst sessionManager = SessionManager.open(params.sessionFile);
Mayros umhüllt dies mit guardSessionManager() für Tool-Result-Sicherheit.
Session-Caching
session-manager-cache.ts cached SessionManager-Instanzen, um wiederholtes Datei-Parsing zu vermeiden:
typescriptawait prewarmSessionFile(params.sessionFile); sessionManager = SessionManager.open(params.sessionFile); trackSessionManagerAccess(params.sessionFile);
History-Limiting
limitHistoryTurns() trimmt Conversation-Historie basierend auf Channel-Typ (DM vs Gruppe).
Compaction
Auto-Compaction triggert bei Context-Overflow. compactEmbeddedPiSessionDirect() behandelt manuelle Compaction:
typescriptconst compactResult = await compactEmbeddedPiSessionDirect({ sessionId, sessionFile, provider, model, ... });
Authentifizierung & Modell-Auflösung
Auth-Profile
Mayros pflegt einen Auth-Profil-Store mit mehreren API-Keys pro Provider:
typescriptconst authStore = ensureAuthProfileStore(agentDir, { allowKeychainPrompt: false }); const profileOrder = resolveAuthProfileOrder({ cfg, store: authStore, provider, preferredProfile });
Profile rotieren bei Fehlern mit Cooldown-Tracking:
typescriptawait markAuthProfileFailure({ store, profileId, reason, cfg, agentDir }); const rotated = await advanceAuthProfile();
Modell-Auflösung
typescriptimport { resolveModel } from "./pi-embedded-runner/model.js"; const { model, error, authStorage, modelRegistry } = resolveModel( provider, modelId, agentDir, config, ); // Verwendet Pi's ModelRegistry und AuthStorage authStorage.setRuntimeApiKey(model.provider, apiKeyInfo.apiKey);
Failover
FailoverError triggert Modell-Fallback wenn konfiguriert:
typescriptif (fallbackConfigured && isFailoverErrorMessage(errorText)) { throw new FailoverError(errorText, { reason: promptFailoverReason ?? "unknown", provider, model: modelId, profileId, status: resolveFailoverStatus(promptFailoverReason), }); }
Pi-Extensions
Mayros lädt benutzerdefinierte Pi-Extensions für spezialisiertes Verhalten:
Compaction-Safeguard
pi-extensions/compaction-safeguard.ts fügt Guardrails zu Compaction hinzu, einschließlich adaptivem Token-Budgeting plus Tool-Failure- und File-Operation-Zusammenfassungen:
typescriptif (resolveCompactionMode(params.cfg) === "safeguard") { setCompactionSafeguardRuntime(params.sessionManager, { maxHistoryShare }); paths.push(resolvePiExtensionPath("compaction-safeguard")); }
Context-Pruning
pi-extensions/context-pruning.ts implementiert Cache-TTL-basiertes Context-Pruning:
typescriptif (cfg?.agents?.defaults?.contextPruning?.mode === "cache-ttl") { setContextPruningRuntime(params.sessionManager, { settings, contextWindowTokens, isToolPrunable, lastCacheTouchAt, }); paths.push(resolvePiExtensionPath("context-pruning")); }
Streaming & Block-Replies
Block-Chunking
EmbeddedBlockChunker verwaltet Streaming-Text in diskrete Reply-Blöcke:
typescriptconst blockChunker = blockChunking ? new EmbeddedBlockChunker(blockChunking) : null;
Thinking/Final-Tag-Stripping
Streaming-Output wird verarbeitet, um <think>/<thinking>-Blöcke zu entfernen und <final>-Content zu extrahieren:
typescriptconst stripBlockTags = (text: string, state: { thinking: boolean; final: boolean }) => { // Entfernt <think>...</think>-Content // Wenn enforceFinalTag, gibt nur <final>...</final>-Content zurück };
Reply-Directives
Reply-Directives wie [[media:url]], [[voice]], [[reply:id]] werden geparst und extrahiert:
typescriptconst { text: cleanedText, mediaUrls, audioAsVoice, replyToId } = consumeReplyDirectives(chunk);
Fehlerbehandlung
Fehlerklassifikation
pi-embedded-helpers.ts klassifiziert Fehler für angemessene Behandlung:
typescriptisContextOverflowError(errorText) // Context zu groß isCompactionFailureError(errorText) // Compaction fehlgeschlagen isAuthAssistantError(lastAssistant) // Auth-Fehler isRateLimitAssistantError(...) // Rate Limited isFailoverAssistantError(...) // Sollte Failover durchführen classifyFailoverReason(errorText) // "auth" | "rate_limit" | "quota" | "timeout" | ...
Thinking-Level-Fallback
Wenn ein Thinking-Level nicht unterstützt wird, fällt es zurück:
typescriptconst fallbackThinking = pickFallbackThinkingLevel({ message: errorText, attempted: attemptedThinking, }); if (fallbackThinking) { thinkLevel = fallbackThinking; continue; }
Sandbox-Integration
Wenn Sandbox-Modus aktiviert ist, werden Tools und Pfade eingeschränkt:
typescriptconst sandbox = await resolveSandboxContext({ config: params.config, sessionKey: sandboxSessionKey, workspaceDir: resolvedWorkspace, }); if (sandboxRoot) { // Verwendet sandboxed read/edit/write-Tools // Exec läuft im Container // Browser verwendet Bridge-URL }
Provider-spezifische Behandlung
Anthropic
- Refusal-Magic-String-Scrubbing
- Turn-Validierung für aufeinanderfolgende Rollen
- Claude Code-Parameter-Kompatibilität
Google/Gemini
- Turn-Ordering-Fixes (
applyGoogleTurnOrderingFix) - Tool-Schema-Sanitisierung (
sanitizeToolsForGoogle) - Session-History-Sanitisierung (
sanitizeSessionHistory)
OpenAI
apply_patch-Tool für Codex-Modelle- Thinking-Level-Downgrade-Handling
TUI-Integration
Mayros hat auch einen lokalen TUI-Modus, der Pi-TUI-Komponenten direkt verwendet:
typescript// src/tui/tui.ts import { ... } from "@mariozechner/pi-tui";
Dies bietet die interaktive Terminal-Erfahrung ähnlich zum nativen Pi-Modus.
Hauptunterschiede zu Pi CLI
| Aspekt | Pi CLI | Mayros Embedded |
|---|---|---|
| Invocation | pi-Befehl / RPC | SDK via createAgentSession() |
| Tools | Standard-Coding-Tools | Benutzerdefiniertes Mayros-Tool-Suite |
| System-Prompt | AGENTS.md + Prompts | Dynamisch pro Channel/Kontext |
| Session-Storage | ~/.pi/agent/sessions/ | ~/.mayros/agents/<agentId>/sessions/ (oder $MAYROS_STATE_DIR/agents/<agentId>/sessions/) |
| Auth | Single Credential | Multi-Profil mit Rotation |
| Extensions | Von Disk geladen | Programmatisch + Disk-Pfade |
| Event-Handling | TUI-Rendering | Callback-basiert (onBlockReply, etc.) |
Zukünftige Überlegungen
Bereiche für potenzielle Überarbeitung:
- Tool-Signatur-Alignment: Derzeit Anpassung zwischen pi-agent-core- und pi-coding-agent-Signaturen
- Session-Manager-Wrapping:
guardSessionManagerfügt Sicherheit hinzu, erhöht aber Komplexität - Extension-Loading: Könnte Pi's
ResourceLoaderdirekter verwenden - Streaming-Handler-Komplexität:
subscribeEmbeddedPiSessionist groß geworden - Provider-Eigenheiten: Viele Provider-spezifische Codepfade, die Pi potenziell behandeln könnte
Tests
Alle existierenden Tests, die die Pi-Integration und ihre Extensions abdecken:
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(live)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