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

# Events

> API reference for all 14 event types, ReactOutput, and stream utilities

# Events API Reference

## ReactOutput

```python theme={null}
from SimpleLLMFunc.hooks import ReactOutput, ResponseYield, EventYield
```

```python theme={null}
ReactOutput = ResponseYield | EventYield
```

### ResponseYield

```python theme={null}
@dataclass
class ResponseYield:
    response: Any                    # str, Pydantic model, or raw dict
    messages: NormalizedMessageList   # Updated conversation history
```

### EventYield

```python theme={null}
@dataclass
class EventYield:
    event: ReActEvent       # One of 14+ event types
    origin: EventOrigin     # Source identification
```

### EventOrigin

```python theme={null}
@dataclass
class EventOrigin:
    session_id: str
    agent_call_id: str
    event_seq: int
    parent_agent_call_id: str | None = None
    fork_id: str | None = None
    fork_depth: int = 0
    fork_seq: int | None = None
    selfref_instance_id: str | None = None
    source_memory_key: str | None = None
    memory_key: str | None = None
    tool_name: str | None = None
    tool_call_id: str | None = None
```

***

## Type Guards

```python theme={null}
from SimpleLLMFunc.hooks import is_response_yield, is_event_yield

is_response_yield(output: ReactOutput) -> bool
is_event_yield(output: ReactOutput) -> bool
```

***

## Stream Filters

```python theme={null}
from SimpleLLMFunc.hooks import responses_only, events_only, filter_events

# Only ResponseYield items
async for resp in responses_only(agent_stream):
    print(resp.response)

# Only EventYield items
async for evt in events_only(agent_stream):
    handle(evt.event)

# Only specific event types
async for evt in filter_events(agent_stream, LLMChunkArriveEvent):
    print(evt.event.accumulated_content)
```

***

## Event Types

### Loop Lifecycle Events

#### ReactStartEvent

```python theme={null}
@dataclass
class ReactStartEvent:
    event_type: ReActEventType = ReActEventType.REACT_START
```

Emitted once when the ReAct loop begins.

#### ReactIterationStartEvent

```python theme={null}
@dataclass
class ReactIterationStartEvent:
    iteration: int
    event_type: ReActEventType = ReActEventType.REACT_ITERATION_START
```

#### ReactIterationEndEvent

```python theme={null}
@dataclass
class ReactIterationEndEvent:
    iteration: int
    event_type: ReActEventType = ReActEventType.REACT_ITERATION_END
```

#### ReactEndEvent

```python theme={null}
@dataclass
class ReactEndEvent:
    final_messages: NormalizedMessageList
    response: Any
    event_type: ReActEventType = ReActEventType.REACT_END
```

Terminal event. Contains the final conversation state and response.

***

### LLM Call Events

#### LLMCallStartEvent

```python theme={null}
@dataclass
class LLMCallStartEvent:
    messages: NormalizedMessageList   # What the LLM will see
    event_type: ReActEventType = ReActEventType.LLM_CALL_START
```

#### LLMChunkArriveEvent

```python theme={null}
@dataclass
class LLMChunkArriveEvent:
    chunk: LLMStreamChunk             # Provider chunk object
    accumulated_content: str          # Content accumulated so far
    chunk_index: int
    event_type: ReActEventType = ReActEventType.LLM_CHUNK_ARRIVE
```

Emitted for each streaming text chunk. Only fires when `stream=True`.

#### LLMCallEndEvent

```python theme={null}
@dataclass
class LLMCallEndEvent:
    response: Any
    messages: NormalizedMessageList
    tool_calls: list[Any]
    execution_time: float
    content: str = ""
    usage: Optional[Dict[str, int]] = None
    event_type: ReActEventType = ReActEventType.LLM_CALL_END
```

#### LLMCallErrorEvent

```python theme={null}
@dataclass
class LLMCallErrorEvent:
    error: Exception
    event_type: ReActEventType = ReActEventType.LLM_CALL_ERROR
```

***

### Tool Execution Events

#### ToolCallsBatchStartEvent

```python theme={null}
@dataclass
class ToolCallsBatchStartEvent:
    tool_calls: List[Dict[str, Any]]  # All calls in this batch
    event_type: ReActEventType = ReActEventType.TOOL_CALLS_BATCH_START
```

#### ToolCallStartEvent

```python theme={null}
@dataclass
class ToolCallStartEvent:
    tool_name: str
    tool_call_id: str
    arguments: Dict[str, Any]
    event_type: ReActEventType = ReActEventType.TOOL_CALL_START
```

#### ToolCallArgumentsDeltaEvent

```python theme={null}
@dataclass
class ToolCallArgumentsDeltaEvent:
    tool_name: str
    tool_call_id: str
    argname: str
    argcontent_delta: str             # Streaming argument fragment
    event_type: ReActEventType = ReActEventType.TOOL_CALL_ARGUMENTS_DELTA
```

#### ToolCallEndEvent

```python theme={null}
@dataclass
class ToolCallEndEvent:
    tool_name: str
    tool_call_id: str
    arguments: Dict[str, Any]
    result: Any
    execution_time: float
    success: bool
    event_type: ReActEventType = ReActEventType.TOOL_CALL_END
```

#### ToolCallErrorEvent

```python theme={null}
@dataclass
class ToolCallErrorEvent:
    tool_name: str
    tool_call_id: str
    error: str
    event_type: ReActEventType = ReActEventType.TOOL_CALL_ERROR
```

#### ToolCallsBatchEndEvent

```python theme={null}
@dataclass
class ToolCallsBatchEndEvent:
    event_type: ReActEventType = ReActEventType.TOOL_CALLS_BATCH_END
```

***

### Custom Events

#### CustomEvent

```python theme={null}
@dataclass
class CustomEvent:
    event_name: str              # e.g., "kernel_stdout", "selfref_fork_spawn"
    data: Dict[str, Any]         # Event payload
    tool_call_id: Optional[str]  # Which tool emitted this
    event_type: ReActEventType = ReActEventType.CUSTOM
```

Emitted by tools via `ToolEventEmitter`. Common names:

| Event Name              | Source  | Data                                  |
| ----------------------- | ------- | ------------------------------------- |
| `kernel_stdout`         | PyRepl  | `{"text": "..."}`                     |
| `kernel_stderr`         | PyRepl  | `{"text": "..."}`                     |
| `selfref_fork_spawn`    | SelfRef | `{"fork_id": "..."}`                  |
| `selfref_fork_complete` | SelfRef | `{"fork_id": "...", "status": "..."}` |

***

## Event Emitters

### ToolEventEmitter

```python theme={null}
from SimpleLLMFunc.hooks import ToolEventEmitter

emitter = ToolEventEmitter()

# Inside a tool implementation:
await emitter.emit(CustomEvent(
    event_name="progress",
    data={"percent": 50},
    tool_call_id=current_tool_call_id,
))
```

### NoOpEventEmitter

```python theme={null}
from SimpleLLMFunc.hooks import NoOpEventEmitter
```

Silent emitter for testing or when events aren't needed.

***

## Event Observer

```python theme={null}
from SimpleLLMFunc.hooks import with_event_observer

@with_event_observer(my_observer_fn)
@llm_chat(...)
async def agent(...):
    ...
```

The observer function signature:

```python theme={null}
def my_observer(event: ReActEvent, origin: EventOrigin) -> None:
    ...
```

***

## AbortSignal

```python theme={null}
from SimpleLLMFunc.hooks import AbortSignal, ABORT_SIGNAL_PARAM

signal = AbortSignal()
signal.abort("reason")      # Trigger abort
signal.is_aborted           # bool
signal.reason               # str | None
```

`ABORT_SIGNAL_PARAM = "_abort_signal"` — the parameter name for passing abort signals.
