Files
pocketpaw/docs/concepts/agent-loop.mdx
Rohit Kushwaha d8bdc9ffb3 docs: add documentation for PII masking, streaming redaction, AGENTS.md, Discord conversation mode, identity drift prevention, and kill command
- New pages: PII detection/masking, streaming redaction, AGENTS.md support
- Updated: Discord (conversation mode, admin commands, kill command), agent loop (identity drift, kill, AGENTS.md), backends (full tool access, OpenRouter)
- Updated security overview and sidebar navigation
2026-03-10 21:58:07 +05:30

150 lines
6.0 KiB
Plaintext

---
title: "Agent Loop: Message Processing Pipeline"
description: "The Agent Loop is PocketPaw's central orchestrator: it consumes messages from the bus, builds context from memory, delegates to the agent backend, and streams responses back."
section: Core Concepts
ogType: article
keywords: ["agent loop", "orchestrator", "message processing", "context building", "streaming"]
tags: ["architecture", "agent"]
---
# Agent Loop: Message Processing Pipeline
The `AgentLoop` is the central orchestrator in PocketPaw. It consumes messages from the bus, builds context, delegates to the agent backend, and streams responses back.
## Responsibilities
The AgentLoop handles:
1. **Message consumption** — Subscribes to `InboundMessage` events from the bus
2. **Security checks** — Runs Guardian AI and injection scanner on incoming messages
3. **Context building** — Assembles system prompt with identity, memory, and state
4. **Backend delegation** — Routes to the configured agent backend via `AgentRouter`
5. **Response streaming** — Publishes `OutboundMessage` chunks back to the bus
6. **Memory updates** — Saves conversation history and triggers Mem0 auto-learn
7. **System events** — Emits tool activity events for the web dashboard
8. **Inbox updates** — Publishes cross-channel inbox events
## Processing Flow
```python
# Simplified AgentLoop flow
async def handle_message(self, message: InboundMessage):
# 1. Security check
threat = await self.guardian.check(message.content)
if threat.level >= ThreatLevel.HIGH:
await self.bus.publish(OutboundMessage(
content="Message blocked by safety check",
...
))
return
# 2. Injection scan
if await self.scanner.scan(message.content):
return # Block injected messages
# 3. Build context
context = await self.context_builder.build(
session_id=message.session_id,
user_query=message.content,
)
# 4. Delegate to backend
async for event in self.router.process(context, message.content):
if event.type == "message":
await self.bus.publish(OutboundMessage(
content=event.content,
is_stream_chunk=True,
...
))
elif event.type == "tool_use":
await self.bus.publish(SystemEvent(
event_type="tool_start",
data=event.metadata,
))
# 5. Save to memory
await self.memory.save(message.session_id, message.content, response)
# 6. Trigger Mem0 auto-learn (background task)
if settings.mem0_auto_learn:
asyncio.create_task(self.mem0.learn(message.content, response))
```
## Agent Router
The `AgentRouter` uses a **backend registry** to select and delegate to one of six backends:
| Backend | Setting Value | Best For |
|---------|--------------|----------|
| Claude Agent SDK | `claude_agent_sdk` | Coding, complex reasoning, built-in tools |
| OpenAI Agents SDK | `openai_agents` | GPT models, Ollama local inference |
| Google ADK | `google_adk` | Gemini models, native MCP |
| Codex CLI | `codex_cli` | Code-focused tasks |
| OpenCode | `opencode` | External server architecture |
| Copilot SDK | `copilot_sdk` | Multi-provider (Copilot, OpenAI, Azure, Anthropic) |
The router lazily imports the selected backend via `registry.get_backend_class()` to avoid loading unused dependencies. Legacy backend names (e.g., `pocketpaw_native`, `open_interpreter`) are automatically mapped to their replacements.
## Response Standardization
All backends yield standardized `AgentEvent` objects:
```python
AgentEvent(
type="message", # message, tool_use, tool_result, error, done
content="...", # Text content
metadata={ # Backend-specific metadata
"tool_name": "...",
"tool_input": {...},
}
)
```
The `AgentEvent` dataclass is defined in `agents/backend.py` alongside the `AgentBackend` protocol and `Capability` flags. This ensures consistent behavior regardless of which backend is active.
## Identity Drift Prevention
Long conversations can cause models to gradually drift from their configured identity, tone, and communication style. PocketPaw prevents this through two mechanisms:
### Structural Placement
The system prompt is structured so identity stays close to the conversation:
1. **Tool instructions go first** as background reference material
2. **Identity block goes last**, wrapped in `<identity>` XML tags, positioned closest to the live conversation turns where the model pays the most attention
```
# Instructions
[Tool documentation, knowledge base...]
<identity>
# Identity: PocketPaw
[Personality, soul, communication style, user profile...]
</identity>
```
### Periodic Reinforcement
When a conversation reaches **20+ turns** (user and assistant messages combined), a compact identity reminder is automatically appended to the system prompt:
```
# Identity Reminder
Regardless of conversation length, you remain the agent described in the
<identity> block above. Maintain your defined personality, tone, and
communication style consistently throughout this conversation.
```
This nudges the model back on character without re-injecting the full identity (which would waste context window). The reminder is applied once at the threshold and persists for the rest of the session.
## Kill Command
Send `/kill` or `!kill` from any channel to cancel the active agent task for the current session. The kill command is intercepted before the session lock, so it works even when the agent is mid-processing. Cancellations are logged to the audit log.
## AGENTS.md Constraints
When a message includes file context (e.g., from the desktop client), PocketPaw searches for an `AGENTS.md` file in the project directory tree and injects its constraints into the system prompt. See [AGENTS.md Support](/advanced/agents-md) for details.
## Concurrency
The AgentLoop processes one message per session at a time. If a new message arrives while processing, it's queued. Different sessions can be processed concurrently.