> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orxhestra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Events

> Every agent yields typed Event objects via async generators. Learn EventType values, convenience properties, metadata, and EventActions.

Every agent yields a stream of unified `Event` objects. All events share the same `Event` class and are distinguished by their `type` field using the `EventType` enum.

## EventType values

| `EventType`     | When emitted                   | Description                                                              |
| --------------- | ------------------------------ | ------------------------------------------------------------------------ |
| `USER_MESSAGE`  | User input persisted by Runner | The user's message at the start of a turn                                |
| `AGENT_MESSAGE` | Agent response                 | Final answers, thoughts, tool call requests, or partial streaming chunks |
| `TOOL_RESPONSE` | Tool execution result          | The result returned by a tool after execution                            |
| `AGENT_START`   | Start of `astream()`           | Marks the beginning of an agent's execution                              |
| `AGENT_END`     | End of `astream()`             | Marks the end of an agent's execution                                    |

## Convenience properties

| Property               | Type                 | Description                                                                                          |
| ---------------------- | -------------------- | ---------------------------------------------------------------------------------------------------- |
| `event.text`           | `str`                | Concatenated text from all text parts in the event's content                                         |
| `event.thinking`       | `str`                | Concatenated thinking parts (extended thinking models like Claude with thinking enabled)             |
| `event.data`           | `dict \| None`       | First data part's dict, or `None`                                                                    |
| `event.tool_name`      | `str \| None`        | Name of the tool (for `TOOL_RESPONSE` events or first tool call)                                     |
| `event.tool_input`     | `dict \| None`       | Input arguments passed to the first tool call                                                        |
| `event.tool_calls`     | `list[ToolCallPart]` | List of `ToolCallPart` objects from the LLM response (access `.tool_name`, `.args`, `.tool_call_id`) |
| `event.has_tool_calls` | `bool`               | `True` if the event contains tool call requests                                                      |
| `event.error`          | `str \| None`        | Error message from tool response or metadata                                                         |

## Key methods

| Method                              | Description                                                                                                                  |
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `event.is_final_response()`         | Returns `True` if this is the agent's final answer (an `AGENT_MESSAGE` with no tool calls and not a partial streaming chunk) |
| `event.to_langchain_message()`      | Converts the event to the corresponding LangChain message type (`HumanMessage`, `AIMessage`, `ToolMessage`, etc.)            |
| `Event.from_langchain_message(msg)` | Class method that creates an `Event` from a LangChain message                                                                |
| `Event.new_id()`                    | Static method that generates a new unique event ID (UUID)                                                                    |

## Checking event types

Use the `EventType` enum and convenience methods instead of `isinstance` checks:

```python theme={null}
from orxhestra.events.event import Event, EventType

# Check for final response (replaces isinstance(event, FinalAnswerEvent))
if event.is_final_response():
    print(event.text)

# Check for tool calls (replaces isinstance(event, ToolCallEvent))
if event.has_tool_calls:
    for tc in event.tool_calls:
        print(f"Calling {tc.tool_name} with {tc.args}")

# Check for tool results (replaces isinstance(event, ToolResultEvent))
if event.type == EventType.TOOL_RESPONSE:
    print(f"{event.tool_name} returned: {event.text}")

# Check for agent lifecycle
if event.type == EventType.AGENT_START:
    print(f"Agent {event.agent_name} starting")
```

## Metadata conventions

Events use the `metadata` dict for additional context. Common keys:

| Key              | Description                                           |
| ---------------- | ----------------------------------------------------- |
| `react_step`     | The ReAct loop iteration number                       |
| `error`          | Error message string when something went wrong        |
| `exception_type` | The Python exception class name (e.g. `"ValueError"`) |
| `scratchpad`     | Internal reasoning or planning notes from the agent   |

## EventActions

Events carry `EventActions` for side-effects:

```python theme={null}
class EventActions(BaseModel):
    state_delta: dict[str, Any] = {}       # merged into session state
    artifact_delta: dict[str, int] = {}    # artifact filenames → version saved
    transfer_to_agent: str | None = None   # trigger agent handoff
    escalate: bool | None = None           # stop parent LoopAgent
    skip_summarization: bool | None = None
    end_of_agent: bool | None = None
    compaction: EventCompaction | None = None
```

## Event Filters

The `orxhestra.events.filters` module provides reusable functions for preparing session events before they are sent to the LLM. These are used internally by `LlmAgent` and available for custom agents.

### `should_include_event(event)`

Returns `True` if the event should be included in LLM context. Filters out:

* Partial (streaming) events
* Lifecycle events (`AGENT_START`, `AGENT_END`)
* Error-only metadata events
* Scratchpad notes
* Empty `AGENT_MESSAGE` events (no text, data, or tool calls)

```python theme={null}
from orxhestra.events.filters import should_include_event

visible = [e for e in session.events if should_include_event(e)]
```

### `apply_compaction(events)`

Replaces raw events with compaction summaries where applicable. When events carry an `EventActions.compaction` entry, all raw events within that timestamp range are replaced by a single synthetic event containing the summary.

```python theme={null}
from orxhestra.events.filters import apply_compaction

events = apply_compaction(session.events)
# Compacted ranges become single summary events
```

Both functions are also re-exported from `orxhestra.events`:

```python theme={null}
from orxhestra.events import should_include_event, apply_compaction
```

## LlmResponse

`AGENT_MESSAGE` events may carry an `llm_response: LlmResponse` field with token usage and model version:

```python theme={null}
event.llm_response.input_tokens
event.llm_response.output_tokens
event.llm_response.model_version
```

## Signed Events

Agents with a `signing_key` automatically sign every event they emit using Ed25519. This provides cryptographic proof of which agent produced each event.

| Property / Method          | Type          | Description                                                                                                            |
| -------------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `event.signature`          | `str \| None` | Base64url-encoded Ed25519 signature                                                                                    |
| `event.signer_did`         | `str`         | `did:key` identifier of the signing agent                                                                              |
| `event.is_signed`          | `bool`        | `True` if the event carries a signature                                                                                |
| `event.verify_signature()` | `bool`        | Verify the signature using the signer's DID public key                                                                 |
| `event.signable_payload()` | `dict`        | Canonical dict of fields included in the signature (`id`, `type`, `timestamp`, `agent_name`, `branch`, `content_text`) |

```python theme={null}
# Verify a signed event
if event.is_signed:
    valid = event.verify_signature()
    print(f"Signed by {event.signer_did}: {'valid' if valid else 'invalid'}")
```

Requires `orxhestra[auth]` (`pip install orxhestra[auth]`).
