mirror of
https://github.com/openclaw/openclaw.git
synced 2026-02-09 05:19:32 +08:00
613 lines
26 KiB
Markdown
613 lines
26 KiB
Markdown
---
|
|
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`
|