Spaces:
Sleeping
Sleeping
| title: "Pi Integration Architecture" | |
| # Pi Integration Architecture | |
| This document describes how OpenClaw integrates with [pi-coding-agent](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent) and its sibling packages (`pi-ai`, `pi-agent-core`, `pi-tui`) to power its AI agent capabilities. | |
| ## Overview | |
| OpenClaw uses the pi SDK to embed an AI coding agent into its messaging gateway architecture. Instead of spawning pi as a subprocess or using RPC mode, OpenClaw directly imports and instantiates pi's `AgentSession` via `createAgentSession()`. This embedded approach provides: | |
| - Full control over session lifecycle and event handling | |
| - Custom tool injection (messaging, sandbox, channel-specific actions) | |
| - System prompt customization per channel/context | |
| - Session persistence with branching/compaction support | |
| - Multi-account auth profile rotation with failover | |
| - Provider-agnostic model switching | |
| ## Package Dependencies | |
| ```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 | Purpose | | |
| | ----------------- | ------------------------------------------------------------------------------------------------------ | | |
| | `pi-ai` | Core LLM abstractions: `Model`, `streamSimple`, message types, provider APIs | | |
| | `pi-agent-core` | Agent loop, tool execution, `AgentMessage` types | | |
| | `pi-coding-agent` | High-level SDK: `createAgentSession`, `SessionManager`, `AuthStorage`, `ModelRegistry`, built-in tools | | |
| | `pi-tui` | Terminal UI components (used in OpenClaw's local TUI mode) | | |
| ## File Structure | |
| ``` | |
| src/agents/ | |
| βββ pi-embedded-runner.ts # Re-exports from pi-embedded-runner/ | |
| βββ pi-embedded-runner/ | |
| β βββ run.ts # Main entry: runEmbeddedPiAgent() | |
| β βββ run/ | |
| β β βββ attempt.ts # Single attempt logic with session setup | |
| β β βββ params.ts # RunEmbeddedPiAgentParams type | |
| β β βββ payloads.ts # Build response payloads from run results | |
| β β βββ images.ts # Vision model image injection | |
| β β βββ types.ts # EmbeddedRunAttemptResult | |
| β βββ abort.ts # Abort error detection | |
| β βββ cache-ttl.ts # Cache TTL tracking for context pruning | |
| β βββ compact.ts # Manual/auto compaction logic | |
| β βββ extensions.ts # Load pi extensions for embedded runs | |
| β βββ extra-params.ts # Provider-specific stream params | |
| β βββ google.ts # Google/Gemini turn ordering fixes | |
| β βββ history.ts # History limiting (DM vs group) | |
| β βββ lanes.ts # Session/global command lanes | |
| β βββ logger.ts # Subsystem logger | |
| β βββ model.ts # Model resolution via ModelRegistry | |
| β βββ runs.ts # Active run tracking, abort, queue | |
| β βββ sandbox-info.ts # Sandbox info for system prompt | |
| β βββ session-manager-cache.ts # SessionManager instance caching | |
| β βββ session-manager-init.ts # Session file initialization | |
| β βββ system-prompt.ts # System prompt builder | |
| β βββ tool-split.ts # Split tools into builtIn vs custom | |
| β βββ types.ts # EmbeddedPiAgentMeta, EmbeddedPiRunResult | |
| β βββ utils.ts # ThinkLevel mapping, error description | |
| βββ 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 # Error classification, turn validation | |
| βββ pi-embedded-helpers/ # Helper modules | |
| βββ pi-embedded-utils.ts # Formatting utilities | |
| βββ pi-tools.ts # createOpenClawCodingTools() | |
| βββ pi-tools.abort.ts # AbortSignal wrapping for tools | |
| βββ pi-tools.policy.ts # Tool allowlist/denylist policy | |
| βββ pi-tools.read.ts # Read tool customizations | |
| βββ pi-tools.schema.ts # Tool schema normalization | |
| βββ pi-tools.types.ts # AnyAgentTool type alias | |
| βββ pi-tool-definition-adapter.ts # AgentTool -> ToolDefinition adapter | |
| βββ pi-settings.ts # Settings overrides | |
| βββ pi-extensions/ # Custom 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 profile resolution | |
| βββ auth-profiles.ts # Profile store, cooldown, failover | |
| βββ model-selection.ts # Default model resolution | |
| βββ models-config.ts # models.json generation | |
| βββ model-catalog.ts # Model catalog cache | |
| βββ context-window-guard.ts # Context window validation | |
| βββ failover-error.ts # FailoverError class | |
| βββ defaults.ts # DEFAULT_PROVIDER, DEFAULT_MODEL | |
| βββ system-prompt.ts # buildAgentSystemPrompt() | |
| βββ system-prompt-params.ts # System prompt parameter resolution | |
| βββ system-prompt-report.ts # Debug report generation | |
| βββ tool-summaries.ts # Tool description summaries | |
| βββ tool-policy.ts # Tool policy resolution | |
| βββ transcript-policy.ts # Transcript validation policy | |
| βββ skills.ts # Skill snapshot/prompt building | |
| βββ skills/ # Skill subsystem | |
| βββ sandbox.ts # Sandbox context resolution | |
| βββ sandbox/ # Sandbox subsystem | |
| βββ channel-tools.ts # Channel-specific tool injection | |
| βββ openclaw-tools.ts # OpenClaw-specific tools | |
| βββ bash-tools.ts # exec/process tools | |
| βββ apply-patch.ts # apply_patch tool (OpenAI) | |
| βββ tools/ # Individual tool implementations | |
| β βββ 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 | |
| βββ ... | |
| ``` | |
| ## Core Integration Flow | |
| ### 1. Running an Embedded Agent | |
| The main entry point is `runEmbeddedPiAgent()` in `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: openclawConfig, | |
| 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 Creation | |
| Inside `runEmbeddedAttempt()` (called by `runEmbeddedPiAgent()`), the pi SDK is used: | |
| ```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. Event Subscription | |
| `subscribeEmbeddedPiSession()` subscribes to pi's `AgentSession` events: | |
| ```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, | |
| }); | |
| ``` | |
| Events handled include: | |
| - `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 | |
| After setup, the session is prompted: | |
| ```typescript | |
| await session.prompt(effectivePrompt, { images: imageResult.images }); | |
| ``` | |
| The SDK handles the full agent loop: sending to LLM, executing tool calls, streaming responses. | |
| ## Tool Architecture | |
| ### Tool Pipeline | |
| 1. **Base Tools**: pi's `codingTools` (read, bash, edit, write) | |
| 2. **Custom Replacements**: OpenClaw replaces bash with `exec`/`process`, customizes read/edit/write for sandbox | |
| 3. **OpenClaw Tools**: messaging, browser, canvas, sessions, cron, gateway, etc. | |
| 4. **Channel Tools**: Discord/Telegram/Slack/WhatsApp-specific action tools | |
| 5. **Policy Filtering**: Tools filtered by profile, provider, agent, group, sandbox policies | |
| 6. **Schema Normalization**: Schemas cleaned for Gemini/OpenAI quirks | |
| 7. **AbortSignal Wrapping**: Tools wrapped to respect abort signals | |
| ### Tool Definition Adapter | |
| pi-agent-core's `AgentTool` has a different `execute` signature than pi-coding-agent's `ToolDefinition`. The adapter in `pi-tool-definition-adapter.ts` bridges this: | |
| ```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) => { | |
| // pi-coding-agent signature differs from pi-agent-core | |
| return await tool.execute(toolCallId, params, signal, onUpdate); | |
| }, | |
| })); | |
| } | |
| ``` | |
| ### Tool Split Strategy | |
| `splitSdkTools()` passes all tools via `customTools`: | |
| ```typescript | |
| export function splitSdkTools(options: { tools: AnyAgentTool[]; sandboxEnabled: boolean }) { | |
| return { | |
| builtInTools: [], // Empty. We override everything | |
| customTools: toToolDefinitions(options.tools), | |
| }; | |
| } | |
| ``` | |
| This ensures OpenClaw's policy filtering, sandbox integration, and extended toolset remain consistent across providers. | |
| ## System Prompt Construction | |
| The system prompt is built in `buildAgentSystemPrompt()` (`system-prompt.ts`). It assembles a full prompt with sections including Tooling, Tool Call Style, Safety guardrails, OpenClaw CLI reference, Skills, Docs, Workspace, Sandbox, Messaging, Reply Tags, Voice, Silent Replies, Heartbeats, Runtime metadata, plus Memory and Reactions when enabled, and optional context files and extra system prompt content. Sections are trimmed for minimal prompt mode used by subagents. | |
| The prompt is applied after session creation via `applySystemPromptOverrideToSession()`: | |
| ```typescript | |
| const systemPromptOverride = createSystemPromptOverride(appendPrompt); | |
| applySystemPromptOverrideToSession(session, systemPromptOverride); | |
| ``` | |
| ## Session Management | |
| ### Session Files | |
| Sessions are JSONL files with tree structure (id/parentId linking). Pi's `SessionManager` handles persistence: | |
| ```typescript | |
| const sessionManager = SessionManager.open(params.sessionFile); | |
| ``` | |
| OpenClaw wraps this with `guardSessionManager()` for tool result safety. | |
| ### Session Caching | |
| `session-manager-cache.ts` caches SessionManager instances to avoid repeated file parsing: | |
| ```typescript | |
| await prewarmSessionFile(params.sessionFile); | |
| sessionManager = SessionManager.open(params.sessionFile); | |
| trackSessionManagerAccess(params.sessionFile); | |
| ``` | |
| ### History Limiting | |
| `limitHistoryTurns()` trims conversation history based on channel type (DM vs group). | |
| ### Compaction | |
| Auto-compaction triggers on context overflow. `compactEmbeddedPiSessionDirect()` handles manual compaction: | |
| ```typescript | |
| const compactResult = await compactEmbeddedPiSessionDirect({ | |
| sessionId, sessionFile, provider, model, ... | |
| }); | |
| ``` | |
| ## Authentication & Model Resolution | |
| ### Auth Profiles | |
| OpenClaw maintains an auth profile store with multiple API keys per provider: | |
| ```typescript | |
| const authStore = ensureAuthProfileStore(agentDir, { allowKeychainPrompt: false }); | |
| const profileOrder = resolveAuthProfileOrder({ cfg, store: authStore, provider, preferredProfile }); | |
| ``` | |
| Profiles rotate on failures with cooldown tracking: | |
| ```typescript | |
| await markAuthProfileFailure({ store, profileId, reason, cfg, agentDir }); | |
| const rotated = await advanceAuthProfile(); | |
| ``` | |
| ### Model Resolution | |
| ```typescript | |
| import { 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` triggers model fallback when configured: | |
| ```typescript | |
| if (fallbackConfigured && isFailoverErrorMessage(errorText)) { | |
| throw new FailoverError(errorText, { | |
| reason: promptFailoverReason ?? "unknown", | |
| provider, | |
| model: modelId, | |
| profileId, | |
| status: resolveFailoverStatus(promptFailoverReason), | |
| }); | |
| } | |
| ``` | |
| ## Pi Extensions | |
| OpenClaw loads custom pi extensions for specialized behavior: | |
| ### Compaction Safeguard | |
| `pi-extensions/compaction-safeguard.ts` adds guardrails to compaction, including adaptive token budgeting plus tool failure and file operation summaries: | |
| ```typescript | |
| if (resolveCompactionMode(params.cfg) === "safeguard") { | |
| setCompactionSafeguardRuntime(params.sessionManager, { maxHistoryShare }); | |
| paths.push(resolvePiExtensionPath("compaction-safeguard")); | |
| } | |
| ``` | |
| ### Context Pruning | |
| `pi-extensions/context-pruning.ts` implements cache-TTL based context pruning: | |
| ```typescript | |
| if (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` manages streaming text into discrete reply blocks: | |
| ```typescript | |
| const blockChunker = blockChunking ? new EmbeddedBlockChunker(blockChunking) : null; | |
| ``` | |
| ### Thinking/Final Tag Stripping | |
| Streaming output is processed to strip `<think>`/`<thinking>` blocks and extract `<final>` content: | |
| ```typescript | |
| const stripBlockTags = (text: string, state: { thinking: boolean; final: boolean }) => { | |
| // Strip <think>...</think> content | |
| // If enforceFinalTag, only return <final>...</final> content | |
| }; | |
| ``` | |
| ### Reply Directives | |
| Reply directives like `[[media:url]]`, `[[voice]]`, `[[reply:id]]` are parsed and extracted: | |
| ```typescript | |
| const { text: cleanedText, mediaUrls, audioAsVoice, replyToId } = consumeReplyDirectives(chunk); | |
| ``` | |
| ## Error Handling | |
| ### Error Classification | |
| `pi-embedded-helpers.ts` classifies errors for appropriate handling: | |
| ```typescript | |
| isContextOverflowError(errorText) // Context too large | |
| isCompactionFailureError(errorText) // Compaction failed | |
| isAuthAssistantError(lastAssistant) // Auth failure | |
| isRateLimitAssistantError(...) // Rate limited | |
| isFailoverAssistantError(...) // Should failover | |
| classifyFailoverReason(errorText) // "auth" | "rate_limit" | "quota" | "timeout" | ... | |
| ``` | |
| ### Thinking Level Fallback | |
| If a thinking level is unsupported, it falls back: | |
| ```typescript | |
| const fallbackThinking = pickFallbackThinkingLevel({ | |
| message: errorText, | |
| attempted: attemptedThinking, | |
| }); | |
| if (fallbackThinking) { | |
| thinkLevel = fallbackThinking; | |
| continue; | |
| } | |
| ``` | |
| ## Sandbox Integration | |
| When sandbox mode is enabled, tools and paths are constrained: | |
| ```typescript | |
| const 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 | |
| } | |
| ``` | |
| ## Provider-Specific Handling | |
| ### Anthropic | |
| - Refusal magic string scrubbing | |
| - Turn validation for consecutive roles | |
| - Claude Code parameter compatibility | |
| ### Google/Gemini | |
| - Turn ordering fixes (`applyGoogleTurnOrderingFix`) | |
| - Tool schema sanitization (`sanitizeToolsForGoogle`) | |
| - Session history sanitization (`sanitizeSessionHistory`) | |
| ### OpenAI | |
| - `apply_patch` tool for Codex models | |
| - Thinking level downgrade handling | |
| ## TUI Integration | |
| OpenClaw also has a local TUI mode that uses pi-tui components directly: | |
| ```typescript | |
| // src/tui/tui.ts | |
| import { ... } from "@mariozechner/pi-tui"; | |
| ``` | |
| This provides the interactive terminal experience similar to pi's native mode. | |
| ## Key Differences from Pi CLI | |
| | Aspect | Pi CLI | OpenClaw Embedded | | |
| | --------------- | ----------------------- | ---------------------------------------------------------------------------------------------- | | |
| | Invocation | `pi` command / RPC | SDK via `createAgentSession()` | | |
| | Tools | Default coding tools | Custom OpenClaw tool suite | | |
| | System prompt | AGENTS.md + prompts | Dynamic per-channel/context | | |
| | Session storage | `~/.pi/agent/sessions/` | `~/.openclaw/agents/<agentId>/sessions/` (or `$OPENCLAW_STATE_DIR/agents/<agentId>/sessions/`) | | |
| | Auth | Single credential | Multi-profile with rotation | | |
| | Extensions | Loaded from disk | Programmatic + disk paths | | |
| | Event handling | TUI rendering | Callback-based (onBlockReply, etc.) | | |
| ## Future Considerations | |
| Areas for potential rework: | |
| 1. **Tool signature alignment**: Currently adapting between pi-agent-core and pi-coding-agent signatures | |
| 2. **Session manager wrapping**: `guardSessionManager` adds safety but increases complexity | |
| 3. **Extension loading**: Could use pi's `ResourceLoader` more directly | |
| 4. **Streaming handler complexity**: `subscribeEmbeddedPiSession` has grown large | |
| 5. **Provider quirks**: Many provider-specific codepaths that pi could potentially handle | |
| ## Tests | |
| All existing tests that cover the pi integration and its extensions: | |
| - `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` | |
| - `src/agents/pi-embedded-helpers.sanitize-session-messages-images.keeps-tool-call-tool-result-ids-unchanged.test.ts` | |
| - `src/agents/pi-embedded-helpers.sanitize-session-messages-images.removes-empty-assistant-text-blocks-but-preserves.test.ts` | |
| - `src/agents/pi-embedded-helpers.sanitizegoogleturnordering.test.ts` | |
| - `src/agents/pi-embedded-helpers.sanitizesessionmessagesimages-thought-signature-stripping.test.ts` | |
| - `src/agents/pi-embedded-helpers.sanitizetoolcallid.test.ts` | |
| - `src/agents/pi-embedded-helpers.sanitizeuserfacingtext.test.ts` | |
| - `src/agents/pi-embedded-helpers.stripthoughtsignatures.test.ts` | |
| - `src/agents/pi-embedded-helpers.validate-turns.test.ts` | |
| - `src/agents/pi-embedded-runner-extraparams.live.test.ts` (live) | |
| - `src/agents/pi-embedded-runner-extraparams.test.ts` | |
| - `src/agents/pi-embedded-runner.applygoogleturnorderingfix.test.ts` | |
| - `src/agents/pi-embedded-runner.buildembeddedsandboxinfo.test.ts` | |
| - `src/agents/pi-embedded-runner.createsystempromptoverride.test.ts` | |
| - `src/agents/pi-embedded-runner.get-dm-history-limit-from-session-key.falls-back-provider-default-per-dm-not.test.ts` | |
| - `src/agents/pi-embedded-runner.get-dm-history-limit-from-session-key.returns-undefined-sessionkey-is-undefined.test.ts` | |
| - `src/agents/pi-embedded-runner.google-sanitize-thinking.test.ts` | |
| - `src/agents/pi-embedded-runner.guard.test.ts` | |
| - `src/agents/pi-embedded-runner.limithistoryturns.test.ts` | |
| - `src/agents/pi-embedded-runner.resolvesessionagentids.test.ts` | |
| - `src/agents/pi-embedded-runner.run-embedded-pi-agent.auth-profile-rotation.test.ts` | |
| - `src/agents/pi-embedded-runner.sanitize-session-history.test.ts` | |
| - `src/agents/pi-embedded-runner.splitsdktools.test.ts` | |
| - `src/agents/pi-embedded-runner.test.ts` | |
| - `src/agents/pi-embedded-subscribe.code-span-awareness.test.ts` | |
| - `src/agents/pi-embedded-subscribe.reply-tags.test.ts` | |
| - `src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.calls-onblockreplyflush-before-tool-execution-start-preserve.test.ts` | |
| - `src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.does-not-append-text-end-content-is.test.ts` | |
| - `src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.does-not-call-onblockreplyflush-callback-is-not.test.ts` | |
| - `src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.does-not-duplicate-text-end-repeats-full.test.ts` | |
| - `src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.does-not-emit-duplicate-block-replies-text.test.ts` | |
| - `src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.emits-block-replies-text-end-does-not.test.ts` | |
| - `src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.emits-reasoning-as-separate-message-enabled.test.ts` | |
| - `src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.filters-final-suppresses-output-without-start-tag.test.ts` | |
| - `src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.includes-canvas-action-metadata-tool-summaries.test.ts` | |
| - `src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.keeps-assistanttexts-final-answer-block-replies-are.test.ts` | |
| - `src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.keeps-indented-fenced-blocks-intact.test.ts` | |
| - `src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.reopens-fenced-blocks-splitting-inside-them.test.ts` | |
| - `src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.splits-long-single-line-fenced-blocks-reopen.test.ts` | |
| - `src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.streams-soft-chunks-paragraph-preference.test.ts` | |
| - `src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.subscribeembeddedpisession.test.ts` | |
| - `src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.suppresses-message-end-block-replies-message-tool.test.ts` | |
| - `src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.waits-multiple-compaction-retries-before-resolving.test.ts` | |
| - `src/agents/pi-embedded-subscribe.tools.test.ts` | |
| - `src/agents/pi-embedded-utils.test.ts` | |
| - `src/agents/pi-extensions/compaction-safeguard.test.ts` | |
| - `src/agents/pi-extensions/context-pruning.test.ts` | |
| - `src/agents/pi-settings.test.ts` | |
| - `src/agents/pi-tool-definition-adapter.test.ts` | |
| - `src/agents/pi-tools-agent-config.test.ts` | |
| - `src/agents/pi-tools.create-openclaw-coding-tools.adds-claude-style-aliases-schemas-without-dropping-b.test.ts` | |
| - `src/agents/pi-tools.create-openclaw-coding-tools.adds-claude-style-aliases-schemas-without-dropping-d.test.ts` | |
| - `src/agents/pi-tools.create-openclaw-coding-tools.adds-claude-style-aliases-schemas-without-dropping-f.test.ts` | |
| - `src/agents/pi-tools.create-openclaw-coding-tools.adds-claude-style-aliases-schemas-without-dropping.test.ts` | |
| - `src/agents/pi-tools.policy.test.ts` | |
| - `src/agents/pi-tools.safe-bins.test.ts` | |
| - `src/agents/pi-tools.workspace-paths.test.ts` | |