# Built-in Plugins

Pre-built plugins that extend agent behavior via event hooks.

## Quick Reference

| Plugin | Purpose | Import |
|--------|---------|--------|
| [skills](../concepts/skills.md) | Invoke workflows with scoped permissions | `from connectonion.useful_plugins import skills` |
| [subagents](subagents.md) | Run tasks in parallel sub-agents | `from connectonion.useful_plugins import subagents` |
| [tool_approval](tool_approval.md) | Web-based tool approval | `from connectonion.useful_plugins import tool_approval` |
| [re_act](re_act.md) | ReAct reasoning pattern | `from connectonion.useful_plugins import re_act` |
| [eval](eval.md) | Task evaluation/debugging | `from connectonion.useful_plugins import eval` |
| [system_reminder](system_reminder.md) | Inject contextual guidance | `from connectonion.useful_plugins import system_reminder` |
| [image_result_formatter](image_result_formatter.md) | Format images for vision | `from connectonion.useful_plugins import image_result_formatter` |
| [shell_approval](shell_approval.md) | Shell command approval | `from connectonion.useful_plugins import shell_approval` |
| [ui_stream](ui_stream.md) | Stream events to WebSocket clients | `from connectonion.useful_plugins import ui_stream` |
| [auto_compact](auto_compact.md) | Compact conversation when context fills up | `from connectonion.useful_plugins import auto_compact` |
| [prefer_write_tool](prefer_write_tool.md) | Guide agent to prefer write for new files | `from connectonion.useful_plugins import prefer_write_tool` |
| [ulw](ulw.md) | Ultra-light workflow: pause for user input | `from connectonion.useful_plugins import ulw` |
| [gmail_plugin](gmail_plugin.md) | Gmail OAuth flow | `from connectonion.useful_plugins import gmail_plugin` |
| [calendar_plugin](calendar_plugin.md) | Calendar OAuth flow | `from connectonion.useful_plugins import calendar_plugin` |

## Usage Pattern

```python
from connectonion import Agent
from connectonion.useful_plugins import skills, tool_approval, re_act

agent = Agent(
    "assistant",
    tools=[search, bash],
    plugins=[skills, tool_approval, re_act]  # List of plugins
)
```

## Customizing Plugins

Need to modify a built-in plugin? Copy it to your project:

```bash
# Copy plugin source to ./plugins/
co copy re_act

# Copy multiple plugins
co copy re_act shell_approval
```

Then import from your local copy:

```python
# Before (from package)
from connectonion.useful_plugins import re_act

# After (from your copy)
from plugins.re_act import re_act  # Customize freely!
```

See [co copy](../cli/copy.md) for full details.

## Categories

### Workflows
- **skills** - Pre-packaged workflows with scoped permissions (/commit, /deploy, etc.)
- **subagents** - Run tasks in parallel sub-agents

### Security
- **tool_approval** - Web-based approval for dangerous tools
- **shell_approval** - CLI-based approval for shell commands

### Reasoning
- **re_act** - Plan before acting, reflect after tools

### Debugging
- **eval** - Generate expected outcomes, evaluate completion

### Guidance
- **system_reminder** - Inject contextual reminders into tool results
- **prefer_write_tool** - Guide agent to prefer write over edit for new files

### Media
- **image_result_formatter** - Convert base64 images for vision models

### Context Management
- **auto_compact** - Compact conversation when context window fills up

### User Interaction
- **ulw** - Ultra-light workflow: pause loop and wait for user input

### Streaming
- **ui_stream** - Stream agent trace events to WebSocket clients

### OAuth
- **gmail_plugin** - Handle Gmail authentication flow
- **calendar_plugin** - Handle Google Calendar authentication flow

## Event Lifecycle

Understanding when events fire is key to writing plugins.

```
User Input
    │
    ▼
┌─────────────────────────────────────────────────────┐
│  after_user_input                                   │
│  (re_act: plan_task, eval: generate_expected)       │
└─────────────────────────────────────────────────────┘
    │
    ▼
┌─────────────────── ITERATION LOOP ──────────────────┐
│                                                     │
│  before_llm → LLM Call → after_llm                  │
│                   │                                 │
│                   ▼                                 │
│        ┌─────────────────────┐                      │
│        │ Tool Calls (if any) │                      │
│        └─────────────────────┘                      │
│                   │                                 │
│                   ▼                                 │
│  ┌─────────────────────────────────────────────┐    │
│  │ before_tools (fires ONCE before all tools)  │    │
│  └─────────────────────────────────────────────┘    │
│                   │                                 │
│                   ▼                                 │
│  ┌─────────────────────────────────────────────┐    │
│  │ For EACH tool in parallel:                  │    │
│  │   before_each_tool → Execute → after_each_tool  │
│  │   (shell_approval)         (logging only!)      │
│  └─────────────────────────────────────────────┘    │
│                   │                                 │
│                   ▼                                 │
│  ┌─────────────────────────────────────────────┐    │
│  │ after_tools (fires ONCE after ALL tools)    │    │
│  │ (re_act: reflect, image_result_formatter)   │    │
│  │ ⚠️  ONLY place safe to modify messages       │    │
│  └─────────────────────────────────────────────┘    │
│                   │                                 │
│           Continue or Exit Loop                     │
└─────────────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────────────┐
│  on_complete                                        │
│  (eval: evaluate_completion)                        │
└─────────────────────────────────────────────────────┘
```

### Key Distinction

- **`after_each_tool`**: Fires for EACH tool individually. Use for logging, monitoring, side effects. **DO NOT modify messages here.**
- **`after_tools`**: Fires ONCE after ALL tools complete. **ONLY place safe to modify messages.**

### Why This Matters

LLM APIs require tool results to match tool calls exactly. If you modify messages in `after_each_tool`, you'll break the tool_call_id sequence.

```
❌ WRONG - modifying messages in after_each_tool:
tool_1 result → modify messages → tool_2 result → API ERROR!

✅ CORRECT - modifying messages in after_tools:
tool_1 result → tool_2 result → tool_3 result → after_tools → modify messages → OK
```

**Rule:** If your plugin modifies `agent.current_session['messages']`, use `after_tools`.

### Error You'll See If You Get This Wrong

```
BadRequestError: 400 An assistant message with 'tool_calls' must be
followed by tool messages responding to each 'tool_call_id'.
The following tool_call_ids did not have response messages: call_xxx
```

If you see this error, check if any plugin is modifying messages in `after_each_tool` - move that logic to `after_tools`.

Example: If LLM calls 3 tools in one round:
- `before_tools` fires 1 time
- `before_each_tool` fires 3 times (logging only!)
- `after_each_tool` fires 3 times (logging only!)
- `after_tools` fires 1 time (safe to modify messages)
