# Events & Triggers

Events allow agents to respond to external changes and automate actions based on various triggers. LLMling-agent supports different types of triggers that can activate agents automatically.

## Basic Concepts

Events flow through the system in this order:
1. Event Source detects change
2. Event Manager processes event
3. Agent receives and handles event
4. Optional: Agent forwards event results through connections

## Event Types

### File Watch Events
Monitor file system changes and trigger agent actions:ä

```yaml
agents:
  code_monitor:
    triggers:
      - type: "file"
        name: "python_watcher"        # Unique identifier
        enabled: true                 # Can be disabled without removal
        paths: ["src/**/*.py"]        # Glob patterns to watch
        extensions: [".py"]           # Optional file type filter
        ignore_paths:                 # Optional ignore patterns
          - "**/__pycache__"
          - "**/.git"
        recursive: true               # Watch subdirectories
        debounce: 1600               # Minimum ms between triggers
```

### Webhook Events
Listen for HTTP requests:

```yaml
agents:
  api_handler:
    triggers:
      - type: "webhook"
        name: "github_webhook"
        enabled: true
        port: 8000
        path: "/github"
        secret: "${WEBHOOK_SECRET}"   # Optional validation secret
```

## Event Configuration

### Common Properties
All event types share these base properties:

```yaml
triggers:
  - name: "my_trigger"               # Unique identifier
    enabled: true                    # Whether trigger is active
    knowledge:                       # Optional knowledge to load
      paths: ["context/*.md"]        # Files to load as context
      resources:                     # LLMling resources
        - type: "cli"
          command: "git status"
      prompts:                       # Context prompts
        - "Consider this background information..."
```

### Multiple Triggers
Agents can have multiple triggers of different types:

```yaml
agents:
  project_assistant:
    triggers:
      # Watch for code changes
      - type: "file"
        name: "code_watcher"
        paths: ["src/**/*.py"]
        extensions: [".py"]

      # Listen for GitHub webhooks
      - type: "webhook"
        name: "github_events"
        port: 8000
        path: "/github"

      # Manual review trigger
      - type: "manual"
        name: "review_code"
        prompt: "Review latest changes"
```

## Event Handling

### In Configuration
Configure how agents handle events through system prompts:

```yaml
agents:
  file_monitor:
    system_prompts:
      - |
        You monitor file changes and analyze their impact.
        When receiving file change events:
        1. Check file type and content
        2. Assess impact of changes
        3. Recommend actions if needed
    triggers:
      - type: "file"
        name: "config_watch"
        paths: ["config/*.yml"]
```

### In Code

Events can be handled in two ways:

1. **Automatic Handling**: Events are automatically converted to agent runs using their `to_prompt()` method
2. **Custom Callbacks**: Custom event handlers for more control

#### Default Handler
By default, events are automatically converted to prompts and passed to the agent:

```python
# Auto-handling is enabled by default
event_manager = EventManager(agent)

# Can be disabled
event_manager.auto_handle = False

# Re-enable
event_manager.auto_handle = True
```

#### Custom Event Handlers

Register custom callbacks to handle events:

```python
async def handle_events(event: EventData) -> None:
    match event:
        case FileEvent(type="modified", path=p) if p.endswith('.py'):
            await agent.run(f"Python file modified: {p}")
        case WebhookEvent(path="/github"):
            await agent.run(f"GitHub webhook received: {event.data}")

# Register callback
await agent.events.add_callback(handle_events)

# Remove callback
await agent.events.remove_callback(handle_events)
```

Callbacks can be both sync or async:

```python
# Sync callback
def sync_handler(event: EventData) -> None:
    print(f"Event received: {event}")

# Async callback
async def async_handler(event: EventData) -> None:
    await process_event(event)

# Both work
await agent.events.add_callback(sync_handler)
await agent.events.add_callback(async_handler)
```

## CLI Usage

Run agents in event-watching mode to handle events:

```bash
# Start watching with default configuration
llmling-agent watch agents.yml

# With specific log level
llmling-agent watch agents.yml --log-level DEBUG
```

The agents will:
1. Start monitoring configured event sources
2. Handle events based on their configuration
3. Run until interrupted (Ctrl+C)

## Event Data

Each event type provides specific data:

### FileEvent
```python
@dataclass(frozen=True)
class FileEvent(EventData):
    path: str           # Path to affected file
    type: ChangeType    # "added" | "modified" | "deleted"
    timestamp: datetime # When event occurred
    source: str        # Trigger name
```

### WebhookEvent
```python
@dataclass(frozen=True)
class WebhookEvent(EventData):
    path: str          # Request path
    method: str        # HTTP method
    data: dict        # Request data
    timestamp: datetime
    source: str
```

## Best Practices

1. **Choose Handling Strategy**
   - Use auto-handling for simple cases
   - Use custom callbacks for complex logic
   - Can combine both approaches

2. **Error Handling**
   - Events are handled independently
   - Errors in one callback don't affect others
   - Default handler errors are logged but don't stop processing

3. **Performance**
   - Keep handlers light and fast
   - Use async operations for I/O
   - Consider debouncing for high-frequency events

## Common Patterns

### Code Review Automation
```yaml
agents:
  code_reviewer:
    triggers:
      - type: "file"
        name: "pr_watch"
        paths: ["src/**/*.py"]
    system_prompts:
      - "You review Python code changes and provide feedback."
```

### Configuration Monitor
```yaml
agents:
  config_monitor:
    triggers:
      - type: "file"
        name: "config_watch"
        paths: ["config/*.yml"]
        debounce: 5000  # 5 second delay
```

### Mixed Handling
```python
# Custom handling for specific cases
async def special_handler(event: EventData) -> None:
    if isinstance(event, FileEvent) and event.path.endswith('.secret'):
        await handle_secret_file(event.path)

# Register custom handler but keep auto-handling
await agent.events.add_callback(special_handler)
# Auto-handling will still process other events
```
