Arquitectura de Integración de Pi
Este documento describe cómo Mayros se integra con pi-coding-agent y sus paquetes hermanos (pi-ai, pi-agent-core, pi-tui) para potenciar sus capacidades de agente de IA.
Descripción General
Mayros usa el SDK de pi para incorporar un agente de codificación de IA en su arquitectura de gateway de mensajería. En lugar de generar pi como un subproceso o usar modo RPC, Mayros importa directamente e instancia el AgentSession de pi vía createAgentSession(). Este enfoque embebido proporciona:
- Control completo sobre el ciclo de vida de la sesión y manejo de eventos
- Inyección de herramientas personalizadas (mensajería, sandbox, acciones específicas de canal)
- Personalización del prompt del sistema por canal/contexto
- Persistencia de sesión con soporte para ramificación/compactación
- Rotación de perfiles de autenticación multicuenta con failover
- Cambio de modelo agnóstico al proveedor
Dependencias de Paquetes
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" }
| Paquete | Propósito |
|---|---|
pi-ai | Abstracciones LLM principales: Model, streamSimple, tipos de mensaje, APIs de proveedor |
pi-agent-core | Bucle de agente, ejecución de herramientas, tipos AgentMessage |
pi-coding-agent | SDK de alto nivel: createAgentSession, SessionManager, AuthStorage, ModelRegistry, herramientas incorporadas |
pi-tui | Componentes UI de terminal (usado en modo TUI local de Mayros) |
Estructura de Archivos
src/agents/
├── pi-embedded-runner.ts # Re-exports desde pi-embedded-runner/
├── pi-embedded-runner/
│ ├── run.ts # Punto de entrada principal: runEmbeddedPiAgent()
│ ├── run/
│ │ ├── attempt.ts # Lógica de intento único con configuración de sesión
│ │ ├── params.ts # Tipo RunEmbeddedPiAgentParams
│ │ ├── payloads.ts # Construir payloads de respuesta desde resultados de ejecución
│ │ ├── images.ts # Inyección de imágenes de modelo Vision
│ │ └── types.ts # EmbeddedRunAttemptResult
│ ├── abort.ts # Detección de errores de cancelación
│ ├── cache-ttl.ts # Seguimiento de Cache TTL para poda de contexto
│ ├── compact.ts # Lógica de compactación manual/automática
│ ├── extensions.ts # Cargar extensiones pi para ejecuciones embebidas
│ ├── extra-params.ts # Parámetros de stream específicos de proveedor
│ ├── google.ts # Correcciones de orden de turnos Google/Gemini
│ ├── history.ts # Limitación de historial (DM vs grupo)
│ ├── lanes.ts # Carriles de comandos sesión/global
│ ├── logger.ts # Logger de subsistema
│ ├── model.ts # Resolución de modelo vía ModelRegistry
│ ├── runs.ts # Seguimiento de ejecuciones activas, cancelación, cola
│ ├── sandbox-info.ts # Info de Sandbox para prompt del sistema
│ ├── session-manager-cache.ts # Caché de instancias SessionManager
│ ├── session-manager-init.ts # Inicialización de archivos de sesión
│ ├── system-prompt.ts # Constructor de prompt del sistema
│ ├── tool-split.ts # Dividir herramientas en builtIn vs custom
│ ├── types.ts # EmbeddedPiAgentMeta, EmbeddedPiRunResult
│ └── utils.ts # Mapeo de ThinkLevel, descripción de errores
├── pi-embedded-subscribe.ts # Suscripción/despacho de eventos de sesión
├── pi-embedded-subscribe.types.ts # SubscribeEmbeddedPiSessionParams
├── pi-embedded-subscribe.handlers.ts # Fábrica de manejadores de eventos
├── pi-embedded-subscribe.handlers.lifecycle.ts
├── pi-embedded-subscribe.handlers.types.ts
├── pi-embedded-block-chunker.ts # Fragmentación de respuestas en streaming
├── pi-embedded-messaging.ts # Seguimiento de envío de herramienta de mensajería
├── pi-embedded-helpers.ts # Clasificación de errores, validación de turnos
├── pi-embedded-helpers/ # Módulos de ayuda
├── pi-embedded-utils.ts # Utilidades de formato
├── pi-tools.ts # createMayrosCodingTools()
├── pi-tools.abort.ts # Envoltura AbortSignal para herramientas
├── pi-tools.policy.ts # Política allowlist/denylist de herramientas
├── pi-tools.read.ts # Personalizaciones de herramienta Read
├── pi-tools.schema.ts # Normalización de esquema de herramientas
├── pi-tools.types.ts # Alias de tipo AnyAgentTool
├── pi-tool-definition-adapter.ts # Adaptador AgentTool -> ToolDefinition
├── pi-settings.ts # Sobreescrituras de configuración
├── pi-extensions/ # Extensiones pi personalizadas
│ ├── compaction-safeguard.ts # Extensión Safeguard
│ ├── compaction-safeguard-runtime.ts
│ ├── context-pruning.ts # Extensión de poda de contexto Cache-TTL
│ └── context-pruning/
├── model-auth.ts # Resolución de perfiles Auth
├── auth-profiles.ts # Almacén de perfiles, cooldown, failover
├── model-selection.ts # Resolución de modelo por defecto
├── models-config.ts # Generación de models.json
├── model-catalog.ts # Caché de catálogo de modelos
├── context-window-guard.ts # Validación de ventana de contexto
├── failover-error.ts # Clase FailoverError
├── defaults.ts # DEFAULT_PROVIDER, DEFAULT_MODEL
├── system-prompt.ts # buildAgentSystemPrompt()
├── system-prompt-params.ts # Resolución de parámetros de prompt del sistema
├── system-prompt-report.ts # Generación de reporte de debug
├── tool-summaries.ts # Resúmenes de descripción de herramientas
├── tool-policy.ts # Resolución de política de herramientas
├── transcript-policy.ts # Política de validación de Transcript
├── skills.ts # Construcción de Skill snapshot/prompt
├── skills/ # Subsistema de Skills
├── sandbox.ts # Resolución de contexto Sandbox
├── sandbox/ # Subsistema Sandbox
├── channel-tools.ts # Inyección de herramientas específicas de canal
├── mayros-tools.ts # Herramientas específicas de Mayros
├── bash-tools.ts # Herramientas exec/process
├── apply-patch.ts # Herramienta apply_patch (OpenAI)
├── tools/ # Implementaciones de herramientas individuales
│ ├── 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
└── ...
Flujo de Integración Principal
1. Ejecutar un Agente Embebido
El punto de entrada principal es runEmbeddedPiAgent() en 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. Creación de Sesión
Dentro de runEmbeddedAttempt() (llamado por runEmbeddedPiAgent()), se usa el SDK de 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. Suscripción a Eventos
subscribeEmbeddedPiSession() se suscribe a eventos de AgentSession de 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, });
Eventos manejados incluyen:
message_start/message_end/message_update(streaming de texto/pensamiento)tool_execution_start/tool_execution_update/tool_execution_endturn_start/turn_endagent_start/agent_endauto_compaction_start/auto_compaction_end
4. Prompting
Después de la configuración, se solicita la sesión:
typescriptawait session.prompt(effectivePrompt, { images: imageResult.images });
El SDK maneja el bucle completo del agente: enviar al LLM, ejecutar llamadas de herramientas, transmitir respuestas.
Arquitectura de Herramientas
Pipeline de Herramientas
- Herramientas Base:
codingToolsde pi (read, bash, edit, write) - Reemplazos Personalizados: Mayros reemplaza bash con
exec/process, personaliza read/edit/write para sandbox - Herramientas de Mayros: mensajería, navegador, canvas, sesiones, cron, gateway, etc.
- Herramientas de Canal: herramientas de acción específicas de Discord/Telegram/Slack/WhatsApp
- Filtrado de Política: herramientas filtradas por perfil, proveedor, agente, grupo, políticas de sandbox
- Normalización de Esquema: esquemas limpiados para peculiaridades de Gemini/OpenAI
- Envolvimiento AbortSignal: herramientas envueltas para respetar señales de abortar
Adaptador de Definición de Herramienta
AgentTool de pi-agent-core tiene una firma execute diferente de ToolDefinition de pi-coding-agent. El adaptador en pi-tool-definition-adapter.ts une esto:
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 signature differs from pi-agent-core return await tool.execute(toolCallId, params, signal, onUpdate); }, })); }
Estrategia de División de Herramientas
splitSdkTools() pasa todas las herramientas vía customTools:
typescriptexport function splitSdkTools(options: { tools: AnyAgentTool[]; sandboxEnabled: boolean }) { return { builtInTools: [], // Empty. We override everything customTools: toToolDefinitions(options.tools), }; }
Esto asegura que el filtrado de políticas de Mayros, la integración de sandbox y el conjunto de herramientas extendido permanezcan consistentes entre proveedores.
Construcción del Prompt del Sistema
El prompt del sistema se construye en buildAgentSystemPrompt() (system-prompt.ts). Ensambla un prompt completo con secciones incluyendo Tooling, Tool Call Style, protecciones de Seguridad, referencia CLI de Mayros, Skills, Docs, Workspace, Sandbox, Messaging, Reply Tags, Voice, Silent Replies, Heartbeats, metadatos de Runtime, más Memory y Reactions cuando están habilitados, y archivos de contexto opcionales más contenido extra de prompt del sistema. Las secciones se recortan para el modo de prompt mínimo usado por subagentes.
El prompt se aplica después de la creación de sesión vía applySystemPromptOverrideToSession():
typescriptconst systemPromptOverride = createSystemPromptOverride(appendPrompt); applySystemPromptOverrideToSession(session, systemPromptOverride);
Gestión de Sesiones
Archivos de Sesión
Las sesiones son archivos JSONL con estructura de árbol (enlace id/parentId). El SessionManager de Pi maneja la persistencia:
typescriptconst sessionManager = SessionManager.open(params.sessionFile);
Mayros envuelve esto con guardSessionManager() para seguridad de resultados de herramientas.
Caché de Sesión
session-manager-cache.ts cachea instancias de SessionManager para evitar parseo repetido de archivos:
typescriptawait prewarmSessionFile(params.sessionFile); sessionManager = SessionManager.open(params.sessionFile); trackSessionManagerAccess(params.sessionFile);
Limitación de Historial
limitHistoryTurns() recorta el historial de conversación basado en el tipo de canal (DM vs grupo).
Compactación
La auto-compactación se activa en desbordamiento de contexto. compactEmbeddedPiSessionDirect() maneja la compactación manual:
typescriptconst compactResult = await compactEmbeddedPiSessionDirect({ sessionId, sessionFile, provider, model, ... });
Autenticación y Resolución de Modelo
Perfiles de Autenticación
Mayros mantiene un almacén de perfiles de autenticación con múltiples claves API por proveedor:
typescriptconst authStore = ensureAuthProfileStore(agentDir, { allowKeychainPrompt: false }); const profileOrder = resolveAuthProfileOrder({ cfg, store: authStore, provider, preferredProfile });
Los perfiles rotan en fallos con seguimiento de cooldown:
typescriptawait markAuthProfileFailure({ store, profileId, reason, cfg, agentDir }); const rotated = await advanceAuthProfile();
Resolución de Modelo
typescriptimport { 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);
Failover
FailoverError activa el fallback de modelo cuando está configurado:
typescriptif (fallbackConfigured && isFailoverErrorMessage(errorText)) { throw new FailoverError(errorText, { reason: promptFailoverReason ?? "unknown", provider, model: modelId, profileId, status: resolveFailoverStatus(promptFailoverReason), }); }
Extensiones de Pi
Mayros carga extensiones de pi personalizadas para comportamiento especializado:
Protección de Compactación
pi-extensions/compaction-safeguard.ts añade barandillas a la compactación, incluyendo presupuesto adaptativo de tokens más resúmenes de fallo de herramienta y operaciones de archivo:
typescriptif (resolveCompactionMode(params.cfg) === "safeguard") { setCompactionSafeguardRuntime(params.sessionManager, { maxHistoryShare }); paths.push(resolvePiExtensionPath("compaction-safeguard")); }
Poda de Contexto
pi-extensions/context-pruning.ts implementa poda de contexto basada en cache-TTL:
typescriptif (cfg?.agents?.defaults?.contextPruning?.mode === "cache-ttl") { setContextPruningRuntime(params.sessionManager, { settings, contextWindowTokens, isToolPrunable, lastCacheTouchAt, }); paths.push(resolvePiExtensionPath("context-pruning")); }
Streaming y Respuestas por Bloques
Fragmentación de Bloques
EmbeddedBlockChunker gestiona el streaming de texto en bloques de respuesta discretos:
typescriptconst blockChunker = blockChunking ? new EmbeddedBlockChunker(blockChunking) : null;
Eliminación de Etiquetas Thinking/Final
La salida en streaming se procesa para eliminar bloques <think>/<thinking> y extraer contenido <final>:
typescriptconst stripBlockTags = (text: string, state: { thinking: boolean; final: boolean }) => { // Strip <think>...</think> content // If enforceFinalTag, only return <final>...</final> content };
Directivas de Respuesta
Las directivas de respuesta como [[media:url]], [[voice]], [[reply:id]] se parsean y extraen:
typescriptconst { text: cleanedText, mediaUrls, audioAsVoice, replyToId } = consumeReplyDirectives(chunk);
Manejo de Errores
Clasificación de Errores
pi-embedded-helpers.ts clasifica errores para el manejo apropiado:
typescriptisContextOverflowError(errorText) // Contexto demasiado grande isCompactionFailureError(errorText) // Compactación fallida isAuthAssistantError(lastAssistant) // Fallo de autenticación isRateLimitAssistantError(...) // Rate limited isFailoverAssistantError(...) // Debería hacer failover classifyFailoverReason(errorText) // "auth" | "rate_limit" | "quota" | "timeout" | ...
Fallback de Nivel de Pensamiento
Si un nivel de pensamiento no está soportado, hace fallback:
typescriptconst fallbackThinking = pickFallbackThinkingLevel({ message: errorText, attempted: attemptedThinking, }); if (fallbackThinking) { thinkLevel = fallbackThinking; continue; }
Integración de Sandbox
Cuando el modo sandbox está habilitado, las herramientas y rutas se restringen:
typescriptconst 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 }
Manejo Específico de Proveedor
Anthropic
- Limpieza de cadena mágica de rechazo
- Validación de turnos para roles consecutivos
- Compatibilidad de parámetros de Claude Code
Google/Gemini
- Correcciones de orden de turnos (
applyGoogleTurnOrderingFix) - Sanitización de esquemas de herramientas (
sanitizeToolsForGoogle) - Sanitización de historial de sesión (
sanitizeSessionHistory)
OpenAI
- Herramienta
apply_patchpara modelos Codex - Manejo de downgrade de nivel de pensamiento
Integración TUI
Mayros también tiene un modo TUI local que usa componentes pi-tui directamente:
typescript// src/tui/tui.ts import { ... } from "@mariozechner/pi-tui";
Esto proporciona la experiencia de terminal interactiva similar al modo nativo de pi.
Diferencias Clave con Pi CLI
| Aspecto | Pi CLI | Mayros Embebido |
|---|---|---|
| Invocación | Comando pi / RPC | SDK vía createAgentSession() |
| Herramientas | Herramientas coding por defecto | Suite de herramientas Mayros personalizada |
| Prompt del sistema | AGENTS.md + prompts | Dinámico por canal/contexto |
| Almacenamiento sesión | ~/.pi/agent/sessions/ | ~/.mayros/agents/<agentId>/sessions/ (o $MAYROS_STATE_DIR/agents/<agentId>/sessions/) |
| Autenticación | Credencial única | Multi-perfil con rotación |
| Extensiones | Cargadas desde disco | Programáticas + rutas de disco |
| Manejo de eventos | Renderizado TUI | Basado en callbacks (onBlockReply, etc.) |
Consideraciones Futuras
Áreas para potencial refactorización:
- Alineación de firmas de herramientas: Actualmente adaptando entre firmas de pi-agent-core y pi-coding-agent
- Envolvimiento de session manager:
guardSessionManagerañade seguridad pero incrementa complejidad - Carga de extensiones: Podría usar el
ResourceLoaderde pi más directamente - Complejidad del handler de streaming:
subscribeEmbeddedPiSessionha crecido mucho - Peculiaridades de proveedor: Muchos codepaths específicos de proveedor que pi podría manejar potencialmente
Tests
Todos los tests existentes que cubren la integración pi y sus extensiones:
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