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

# Python SDK

> API reference for the iii SDK for Python.

## Installation

```bash theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
pip install iii-sdk
```

## Initialization

### register\_worker

Register the worker with a iii instance, returns a connected worker client.

Blocks up to 30 seconds for the WebSocket connection to be established.
If the engine is not reachable in time, a warning is logged and the
client is returned anyway; it keeps retrying in the background and
flushes registrations once connected. Use
`add_connection_state_listener` to observe the actual transition.

**Signature**

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
register_worker(address: str | None = None, options: InitOptions | None = None) -> III
```

> [tab] Parameters
>
> **address** `str | None`
>
> WebSocket URL of the III engine (e.g. `ws://localhost:49134`). When omitted, resolves from `III_URL` and then `DEFAULT_ENGINE_URL`.
>
> **options** `InitOptions | None`
>
> Optional configuration for worker name, timeouts, reconnection, and OTel.
>
> **`InitOptions` fields**
>
> **enable\_metrics\_reporting** `bool`
>
> Enable worker metrics via OpenTelemetry. Default `True`.
>
> **headers** `dict[str, str] | None`
>
> Custom HTTP headers sent during the WebSocket handshake, on the main connection and on streaming channels. `Authorization: Bearer $III_TOKEN` is added unless you set `Authorization` here.
>
> **invocation\_timeout\_ms** `int`
>
> Default timeout for `worker.trigger()` invocations in milliseconds. Default `30000`.
>
> **namespace** `str | None`
>
> Namespace this worker belongs to. Falls back to the `III_NAMESPACE` env var; when neither is set the engine applies `default`. It scopes more than the registration: the worker and its functions register here, and everything the worker does afterwards follows it: `trigger` resolves its target here and `register_trigger` binds here, unless the call names another namespace.
>
> **otel** `OtelConfig | dict[str, Any] | None`
>
> OpenTelemetry configuration. Enabled by default. Set `{'enabled': False}` or env `OTEL_ENABLED=false` to disable.
>
> **reconnection\_config** `ReconnectionConfig | None`
>
> WebSocket reconnection behavior.
>
> **telemetry** `TelemetryOptions | None`
>
> Internal worker metadata reported to the engine.
>
> **worker\_description** `str | None`
>
> One-line, human/LLM-readable summary of what this worker does. Surfaces in `engine::workers::list` / `engine::workers::info`.
>
> **worker\_name** `str | None`
>
> Display name for this worker. A non-empty `III_WORKER_NAME` overrides it. Defaults to `hostname:pid`.

> [tab] Example
>
> ```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> from iii import register_worker, InitOptions
> worker = register_worker()  # address from III_URL
> other = register_worker('ws://localhost:49134', InitOptions(worker_name='my-worker'))
> ```

## Methods

### register\_trigger

> [!WARNING]
>
> **Deprecated since 0.25.0.** Use `iii.observe(source, target)` instead: `iii.observe({"function_id": ..., "args": ..., "filters": ...}, target, {"metadata": ...})`. Emits a `DeprecationWarning` and logs a warning once per process. The http, cron, queue, state, stream, pubsub and database workers still publish trigger types: keep using `register_trigger` for them until they ship source functions. Migration guide: [https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md)

Bind a trigger configuration to a registered function.

**Signature**

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
register_trigger(trigger: RegisterTriggerInput | dict[str, Any]) -> Trigger
```

> [tab] Parameters
>
> **trigger** `RegisterTriggerInput | dict[str, Any]` *required*
>
> A `RegisterTriggerInput` or dict with `type`, `function_id`, and optional `config`.
>
> **`RegisterTriggerInput` fields**
>
> **config** `Any`
>
> Trigger-type-specific configuration, matching the shape the trigger type expects.
>
> **function\_id** `str` *required*
>
> ID of the function this trigger invokes when it fires.
>
> **metadata** `Any | None`
>
> Arbitrary user-specifiable metadata supplied to the triggered handler function on every invocation.
>
> **namespace** `str | None`
>
> Namespace the target function resolves in.
>
> **trigger\_namespace** `str | None`
>
> Namespace the trigger type's provider is found in.
>
> **type** `str` *required*
>
> Identifier of the registered trigger type this trigger uses (e.g. `storage::object-created`, `http`).

> [tab] Example
>
> ```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> trigger = worker.register_trigger({
>   'type': 'http',
>   'function_id': 'greet',
>   'config': {'api_path': '/greet', 'http_method': 'GET'}
> })
> trigger = worker.register_trigger(RegisterTriggerInput(
>     type="http", function_id="greet",
>     config={'api_path': '/greet', 'http_method': 'GET'}
> ))
> trigger.unregister()
> ```

***

### register\_function

Register a function with the engine.

Pass a handler for local execution, or an `HttpInvocationConfig`
for HTTP-invoked functions (Lambda, Cloudflare Workers, etc.).

Handlers can be synchronous or asynchronous.  Sync handlers are
automatically wrapped with `run_in_executor` so they do not
block the event loop.  Each handler receives a `data` argument
containing the trigger payload, and may optionally accept a second
`metadata` argument carrying per-invocation metadata (e.g.
`def handler(data, metadata=None)` or `def handler(data, *,
metadata=None)`).  Metadata is only forwarded to handlers that
declare a parameter literally named `metadata`, so existing
handlers, including ones with unrelated extra parameters,
`*args`, or `**kwargs`, keep working unchanged.

`request_format` and `response_format` are auto-extracted
from the handler's type hints when omitted or passed as `None`
(the default).  To opt out of auto-extraction, pass an explicit
schema (`RegisterFunctionFormat` or `dict`).  This behavior
is Python-specific; the Node SDK relies on explicit schemas because
TypeScript types are erased at runtime.

**Signature**

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
register_function(function_id: str, handler_or_invocation: RemoteFunctionHandler | HttpInvocationConfig, *, description: str | None = None, metadata: dict[str, Any] | None = None, request_format: RegisterFunctionFormat | dict[str, Any] | None = None, response_format: RegisterFunctionFormat | dict[str, Any] | None = None, observe: ObserveHooks | dict[str, Any] | None = None, local_dispatch: bool = True) -> FunctionRef
```

> [tab] Parameters
>
> **function\_id** `str` *required*
>
> Unique string identifier for the function.
>
> **handler\_or\_invocation** `RemoteFunctionHandler | HttpInvocationConfig` *required*
>
> A callable handler or `HttpInvocationConfig`.  Callable handlers receive `data` (the trigger payload) as the first argument and may optionally accept `metadata` (per-invocation metadata) as a second argument; they may return a value.
>
> **description** `str | None`
>
> Human-readable description of what the function does.
>
> **metadata** `dict[str, Any] | None`
>
> Arbitrary metadata attached to the function.
>
> **request\_format** `RegisterFunctionFormat | dict[str, Any] | None`
>
> Schema describing expected input.  When `None` (default), auto-extracted from the handler's first-parameter type hint.  Pass an explicit schema to override; there is no way to register with no schema when the handler is typed.
>
> **`RegisterFunctionFormat` fields**
>
> **body** `list[RegisterFunctionFormat] | None`
>
> Nested fields for object types.
>
> **description** `str | None`
>
> Human-readable description of the parameter.
>
> **items** `RegisterFunctionFormat | None`
>
> Item schema for array types.
>
> **name** `str` *required*
>
> Parameter name.
>
> **required** `bool`
>
> Whether the parameter is required.
>
> **type** `str` *required*
>
> Type string (`string`, `number`, `boolean`, `object`, `array`, `null`, `map`).
>
> **response\_format** `RegisterFunctionFormat | dict[str, Any] | None`
>
> Schema describing expected output.  Same auto-extraction semantics as `request_format`.
>
> **observe** `ObserveHooks | dict[str, Any] | None`
>
> Makes the function observable on its own terms: owner delivery (`delivery="owner"`, `args_format`), and callbacks when an observer is added or removed (an :class:`ObserveHooks`, a subclass of it, or a dict of its fields). Without it the function is still observable (auto delivery, no args).
>
> **`ObserveHooks` fields**
>
> **allow** `bool | None`
>
> Default `True`; `False` refuses every observer (`NOT_OBSERVABLE`).
>
> **args\_format** `Any`
>
> Owner only: JSON Schema (or a Pydantic model) of the observers' `args`; the engine answers `INVALID_ARGS`.
>
> **delivery** `Delivery | None`
>
> `"auto"` (default): every invocation is offered to every observer. `"owner"`: the handler hands each event to the observers it belongs to, with `obs.emit` / `obs.call`.
>
> **from\_value** `(value: ObserveHooks | dict[str, Any] | None) -\> ObserveHooks | None` *required*
>
> An `ObserveHooks` from what `register_function(observe=...)` was given.
>
> **legacy\_trigger\_type** `str | None`
>
> Accept old `register_trigger({"type": ...})` calls for this trigger type (the engine's legacy shim).
>
> **on\_observer\_added** `ObserveHook | None`
>
> Runs once per added observer, before the SDK acks it. Raise to reject it (an :class:`~iii.ObserveRejection` sets the code, anything else is `OBSERVE_REJECTED`); after 30 s it is rejected with `OWNER_TIMEOUT`.
>
> **on\_observer\_removed** `ObserveHook | None`
>
> Runs once per removed observer. Cannot fail: errors are logged.
>
> **local\_dispatch** `bool`
>
> Calls this worker makes to its own function run in-process once the engine confirmed it (default `True`). Like a remote invocation, each local call to a sync handler runs on a thread of its own (one per call, not pooled), so the caller can stop waiting at its timeout. A sync handler that blocks for long should be async, or set `False` so its calls go through the engine (also for a handler that relies on engine-side effects).

> [tab] Example
>
> ```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> def greet(data):
>     return {'message': f"Hello, {data['name']}!"}
> fn = worker.register_function("greet", greet, description="Greets a user")
> fn.unregister()
> from pydantic import BaseModel
> class GreetInput(BaseModel):
>     name: str
> class GreetOutput(BaseModel):
>     message: str
> async def greet(data: GreetInput) -> GreetOutput:
>     return GreetOutput(message=f"Hello, {data.name}!")
> fn = worker.register_function("greet", greet, description="Greets a user")
> ```

***

### trigger

Invoke a remote function.

The routing behavior and return type depend on the `action` field:

* No action: synchronous, waits for the function to return.
* `TriggerAction.Enqueue(...)`: async via named queue, returns a dict
  with `messageReceiptId`.
* `TriggerAction.Void()`: fire-and-forget, returns `None`.

A function this worker registered with a handler, once the engine
confirmed it, runs in-process (local dispatch, sdk.md §3): a sync
handler on a thread of its own (the caller waits up to the timeout),
an async one on the SDK loop. Its observers are still evaluated, and
only matched calls reach the engine. `dispatch="remote"` (or
`action=Enqueue`) always goes through the engine. Whatever a local
handler raises, `BaseException`s such as `KeyboardInterrupt` and
`SystemExit` included, reaches the caller as
`InvocationError("invocation_failed")` with the original as its
`__cause__` (for a `Void` call nothing reaches the caller: the
error is logged).

**Signature**

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
trigger(request: dict[str, Any] | TriggerRequest) -> Any
```

> [tab] Parameters
>
> **request** `dict[str, Any] | TriggerRequest` *required*
>
> A `TriggerRequest` or dict with `function_id`, `payload`, and optional `action` / `timeout_ms` / `metadata` / `namespace` / `dispatch` (`"auto"`, the default, or `"remote"`).
>
> **`TriggerRequest` fields**
>
> **action** `TriggerActionEnqueue | TriggerActionVoid | None`
>
> Sets how the trigger is routed. Omit for a synchronous request/response. Specify for a specific routing scheme (e.g. `TriggerAction.Enqueue(...)`, `TriggerAction.Void()`).
>
> **dispatch** `Literal['auto', 'remote'] | None`
>
> `auto` (default) runs a function this worker hosts in-process once the engine confirmed it; `remote` always goes through the engine.
>
> **function\_id** `str` *required*
>
> ID of the function to invoke.
>
> **metadata** `Any | None`
>
> Arbitrary user-specifiable metadata supplied to the triggered handler function on every invocation.
>
> **namespace** `str | None`
>
> Target namespace for routing. Omit to inherit this worker's; say `default` to reach the engine's from a namespaced worker.
>
> **payload** `Any`
>
> Input data passed to the function.
>
> **timeout\_ms** `int | None`
>
> Override the default invocation timeout, in milliseconds.

> [tab] Example
>
> ```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> result = worker.trigger({'function_id': 'greet', 'payload': {'name': 'World'}})
> worker.trigger({'function_id': 'notify', 'payload': {}, 'action': TriggerAction.Void()})
> ```

***

### register\_trigger\_type

> [!WARNING]
>
> **Deprecated since 0.25.0.** Register a function with an observe descriptor instead: `register_function(id, handler, observe=ObserveHooks(delivery="owner", on_observer_added=..., on_observer_removed=...))`. Emits a `DeprecationWarning` and logs a warning once per process. Migration guide: [https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md)

Register a custom trigger type with the engine.

Returns a :class:`TriggerTypeRef` handle with `register_trigger`
and `register_function` methods.

**Signature**

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
register_trigger_type(trigger_type: RegisterTriggerTypeInput | dict[str, Any], handler: TriggerHandler[Any]) -> TriggerTypeRef[Any, Any]
```

> [tab] Parameters
>
> **trigger\_type** `RegisterTriggerTypeInput | dict[str, Any]` *required*
>
> A `RegisterTriggerTypeInput` or dict with `id`, `description`, and optional `trigger_request_format` / `call_request_format` (Pydantic class or dict).
>
> **`RegisterTriggerTypeInput` fields**
>
> **call\_request\_format** `Any | None`
>
> JSON Schema describing the payload sent to functions.
>
> **description** `str` *required*
>
> Human-readable description of what this trigger type does.
>
> **id** `str` *required*
>
> Unique identifier for the trigger type (e.g. `state`, `durable:subscriber`).
>
> **trigger\_request\_format** `Any | None`
>
> JSON Schema describing the expected trigger config.
>
> **handler** `TriggerHandler[Any]` *required*
>
> A `TriggerHandler` instance.
>
> **`TriggerHandler` fields**
>
> **register\_trigger** `async (config: TriggerConfig[TConfig]) -\> None` *required*
>
> Register a trigger with the given configuration.
>
> **unregister\_trigger** `async (config: TriggerConfig[TConfig]) -\> None` *required*
>
> Unregister a trigger with the given configuration.

> [tab] Example
>
> ```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> webhook = worker.register_trigger_type(
>     RegisterTriggerTypeInput(
>         id="webhook",
>         description="Webhook trigger",
>         trigger_request_format=WebhookConfig,
>         call_request_format=WebhookCallRequest,
>     ),
>     WebhookHandler(),
> )
> webhook.register_function("handler", handle_webhook)
> webhook.register_trigger("handler", WebhookConfig(url="/hook"))
> ```

***

### unregister\_trigger\_type

> [!WARNING]
>
> **Deprecated since 0.25.0.** Trigger types are replaced by functions with an observe descriptor; unregister the function instead. Migration guide: [https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md)

Unregister a previously registered trigger type.

**Signature**

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
unregister_trigger_type(trigger_type: RegisterTriggerTypeInput | dict[str, Any]) -> None
```

> [tab] Parameters
>
> **trigger\_type** `RegisterTriggerTypeInput | dict[str, Any]` *required*
>
> A `RegisterTriggerTypeInput` or dict with `id`, an optional `description`, and (dict only) the `namespace` it was registered in.
>
> **`RegisterTriggerTypeInput` fields**
>
> **call\_request\_format** `Any | None`
>
> JSON Schema describing the payload sent to functions.
>
> **description** `str` *required*
>
> Human-readable description of what this trigger type does.
>
> **id** `str` *required*
>
> Unique identifier for the trigger type (e.g. `state`, `durable:subscriber`).
>
> **trigger\_request\_format** `Any | None`
>
> JSON Schema describing the expected trigger config.

> [tab] Example
>
> ```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> worker.unregister_trigger_type({"id": "webhook", "description": "Webhook trigger"})
> worker.unregister_trigger_type(RegisterTriggerTypeInput(id="webhook", description="Webhook trigger"))
> ```

***

### add\_connection\_state\_listener

Subscribe to connection-state transitions.

The handler is fired immediately with the current state (on the
caller's thread), then once per transition. Transitions fire on the
SDK's background event-loop thread: keep handlers fast and do not
call sync SDK methods from them (they would raise `RuntimeError`).
Treat calls as state notifications, not edges. A state may rarely
be observed twice around subscription. Registering the same handler
twice fires it twice. Returns an idempotent unsubscribe function
that removes only its own registration.

**Signature**

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
add_connection_state_listener(handler: ConnectionStateCallback) -> Callable[[], None]
```

> [tab] Parameters
>
> **handler** `ConnectionStateCallback` *required*

> [tab] Example
>
> ```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> unsubscribe = worker.add_connection_state_listener(
>     lambda state: print(f"engine link: {state}")
> )
> ```

***

### connect\_async

Connect to the III Engine via WebSocket.

Initializes OpenTelemetry (if configured), attaches the event loop,
and establishes the WebSocket connection. This is called automatically
during construction; use it only if you need to reconnect manually
from an async context.

**Signature**

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
async () -> None
```

***

### current\_invocation

The invocation the calling code runs in (in every handler, remote or
local), or `None` outside any handler.

**Signature**

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
current_invocation() -> InvocationContext | None
```

#### Example

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
def create_order(order):
    inv = iii.current_invocation()  # function_id, invocation_id, caller, observe_depth
    return {"id": inv.invocation_id if inv else None}
```

***

### get\_address

Return the engine address this worker resolved to.

The explicit `register_worker` argument, else `III_URL`, else
:data:`DEFAULT_ENGINE_URL`. Mirrors the Rust SDK's `address()` and the
Node SDK's `getAddress()`.

**Signature**

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
get_address() -> str
```

***

### get\_connection\_state

Return the current WebSocket connection state.

**Signature**

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
get_connection_state() -> IIIConnectionState
```

#### Example

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
worker = register_worker("ws://localhost:49134")
if worker.get_connection_state() != "connected":
    print("engine not reachable yet")
```

***

### observe

Observes a function: every event of `source` (an invocation of an
auto function, or what its owner hands over) that passes
`source["filters"]` invokes `target`, a registered function.

Returns synchronously, also before the connection is up; the observer
is replayed with the same id on every reconnect. Errors
(`INVALID_ARGS`, `INVALID_FILTER`, `FORBIDDEN`, an owner's
rejection, `UNSUPPORTED` against an engine without observe) show up
as state `error` and make `ready()` raise :class:`ObserveRejection`.

**Signature**

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
observe(source: ObserveSource | dict[str, Any], target: Target, options: ObserverOptions | dict[str, Any] | None = None) -> ObserverHandle
```

> [tab] Parameters
>
> **source** `ObserveSource | dict[str, Any]` *required*
>
> What is observed: `function_id`, `namespace`, `args` (owner-delivered functions only), `filters`, and `on` / `capture` / `deliver`.
>
> **`ObserveSource` fields**
>
> **args** `dict[str, Any]` *required*
>
> Owner-delivered functions only: for the owner; validated against its `args_format`.
>
> **capture** `list[Capture]` *required*
>
> Auto and `obs.emit`; default `["input", "output", "caller"]`.
>
> **deliver** `Literal['envelope', 'input', 'output']` *required*
>
> Auto and `obs.emit`; default `"envelope"`.
>
> **filters** `Filter` *required*
>
> Which events reach the target; `{}` (or absent) = every event.
>
> **namespace** `str` *required*
>
> Defaults to this worker's (`engine::*` resolves to `default`).
>
> **on** `Literal['success', 'error', 'complete']` *required*
>
> Auto only; default `"success"`.
>
> **target** `Target` *required*
>
> The function to invoke: its id, or `{"function_id": ..., "namespace": ...}`. Register it first; until then the observer stays `pending`.
>
> **options** `ObserverOptions | dict[str, Any] | None`
>
> `id`, `max_fires`, `expires_in_ms`, `max_in_flight`, `metadata` (the activation's metadata sidecar).
>
> **`ObserverOptions` fields**
>
> **expires\_in\_ms** `int` *required*
>
> Disposed after this long.
>
> **id** `str` *required*
>
> Default: a random UUID, stable across replays.
>
> **max\_fires** `int` *required*
>
> Disposed after this many activations.
>
> **max\_in\_flight** `int` *required*
>
> Activations running at once (the engine queues the rest).
>
> **metadata** `dict[str, Any]` *required*
>
> Delivered as the metadata sidecar of every activation.

> [tab] Example
>
> ```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> iii.register_function("alerts::payment-failed", notify)
> failures = iii.observe(
>     {"function_id": "payments::charge", "on": "error",
>      "filters": {"input.amount": {"$gte": 500}}},
>     "alerts::payment-failed",
>     {"max_in_flight": 4},
> )
> failures.ready()            # or: await failures.ready_async()
> failures.dispose()
> ```

***

### shutdown

Gracefully shut down the client, releasing all resources.

Cancels any pending reconnection attempts, rejects all in-flight
invocations with an error, closes the WebSocket connection, and
stops the background event-loop thread.  After this call the
instance must not be reused.

**Signature**

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
shutdown() -> None
```

#### Example

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
worker = register_worker('ws://localhost:49134')
# ... do work ...
worker.shutdown()
```

***

### shutdown\_async

Gracefully shut down the client, releasing all resources.

Cancels any pending reconnection attempts, rejects all in-flight
invocations with an error, closes the WebSocket connection, and
stops the background event-loop thread.  After this call the
instance must not be reused.

**Signature**

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
async () -> None
```

#### Example

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
worker = register_worker('ws://localhost:49134')
# ... do work ...
await worker.shutdown_async()
```

***

### trigger\_async

Invoke a remote function.

The routing behavior and return type depend on the `action` field:

* No action: synchronous, waits for the function to return.
* `TriggerAction.Enqueue(...)`: async via named queue, returns a dict
  with `messageReceiptId`.
* `TriggerAction.Void()`: fire-and-forget, returns `None`.

Works from any event loop. A function this worker registered with a
handler, once the engine confirmed it, runs in-process on the
calling loop (a sync handler on a thread of its own);
`dispatch="remote"` (or `action=Enqueue`) always goes through
the engine.

**Signature**

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
async (request: dict[str, Any] | TriggerRequest) -> Any
```

> [tab] Parameters
>
> **request** `dict[str, Any] | TriggerRequest` *required*
>
> A `TriggerRequest` or dict with `function_id`, `payload`, and optional `action` / `timeout_ms` / `metadata` / `namespace` / `dispatch` (`"auto"` or `"remote"`).
>
> **`TriggerRequest` fields**
>
> **action** `TriggerActionEnqueue | TriggerActionVoid | None`
>
> Sets how the trigger is routed. Omit for a synchronous request/response. Specify for a specific routing scheme (e.g. `TriggerAction.Enqueue(...)`, `TriggerAction.Void()`).
>
> **dispatch** `Literal['auto', 'remote'] | None`
>
> `auto` (default) runs a function this worker hosts in-process once the engine confirmed it; `remote` always goes through the engine.
>
> **function\_id** `str` *required*
>
> ID of the function to invoke.
>
> **metadata** `Any | None`
>
> Arbitrary user-specifiable metadata supplied to the triggered handler function on every invocation.
>
> **namespace** `str | None`
>
> Target namespace for routing. Omit to inherit this worker's; say `default` to reach the engine's from a namespaced worker.
>
> **payload** `Any`
>
> Input data passed to the function.
>
> **timeout\_ms** `int | None`
>
> Override the default invocation timeout, in milliseconds.

> [tab] Example
>
> ```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> result = await worker.trigger_async({'function_id': 'greet', 'payload': {'name': 'World'}})
> await worker.trigger_async({'function_id': 'notify', 'payload': {}, 'action': TriggerAction.Void()})
> ```

## Types

### iii

[`Caller`](#caller) · [`EnqueueResult`](#enqueueresult) · [`InitOptions`](#initoptions) · [`InvocationContext`](#invocationcontext) · [`MiddlewareFunctionInput`](#middlewarefunctioninput) · [`Observed`](#observed) · [`ObserveHooks`](#observehooks) · [`Observer`](#observer) · [`ObserverHandle`](#observerhandle) · [`ObserverOptions`](#observeroptions) · [`ObserveSource`](#observesource) · [`StreamRequest`](#streamrequest) · [`StreamResponse`](#streamresponse) · [`TelemetryOptions`](#telemetryoptions) · [`TriggerAction`](#triggeraction) · [`TriggerActionEnqueue`](#triggeractionenqueue)

#### Caller

Who started an invocation: the worker (`worker_id` / `worker_name`,
stamped by the engine), and the function and invocation the call was made
from (absent for top-level calls). `parent` is that handler's own caller,
one level only.

| Name | Type | Required | Description |
| - | - | - | - |
| `parent` | `CallerParent` | Yes | - |

***

#### EnqueueResult

Result returned when a function is invoked with `TriggerAction.Enqueue`.

| Name | Type | Required | Description |
| - | - | - | - |
| `messageReceiptId` | `str` | Yes | Unique receipt ID for the enqueued message. |

***

#### InitOptions

Configuration options passed to `register_worker`.

| Name | Type | Required | Description |
| - | - | - | - |
| `enable_metrics_reporting` | `bool` | No | Enable worker metrics via OpenTelemetry. Default `True`. |
| `headers` | `dict[str, str] \| None` | No | Custom HTTP headers sent during the WebSocket handshake, on the main connection and on streaming channels. `Authorization: Bearer $III_TOKEN` is added unless you set `Authorization` here. |
| `invocation_timeout_ms` | `int` | No | Default timeout for `worker.trigger()` invocations in milliseconds. Default `30000`. |
| `namespace` | `str \| None` | No | Namespace this worker belongs to. Falls back to the `III_NAMESPACE` env var; when neither is set the engine applies `default`. It scopes more than the registration: the worker and its functions register here, and everything the worker does afterwards follows it: `trigger` resolves its target here and `register_trigger` binds here, unless the call names another namespace. |
| `otel` | `OtelConfig \| dict[str, Any] \| None` | No | OpenTelemetry configuration. Enabled by default. Set `\{'enabled': False\}` or env `OTEL_ENABLED=false` to disable. |
| `reconnection_config` | `ReconnectionConfig \| None` | No | WebSocket reconnection behavior. |
| `telemetry` | [`TelemetryOptions`](#telemetryoptions) \| None | No | Internal worker metadata reported to the engine. |
| `worker_description` | `str \| None` | No | One-line, human/LLM-readable summary of what this worker does. Surfaces in `engine::workers::list` / `engine::workers::info`. |
| `worker_name` | `str \| None` | No | Display name for this worker. A non-empty `III_WORKER_NAME` overrides it. Defaults to `hostname:pid`. |

***

#### InvocationContext

The invocation the current code runs in, in every handler, remote or local.

Returned by `iii.current_invocation()`.

| Name | Type | Required | Description |
| - | - | - | - |
| `activation` | `dict[str, Any] \| None` | No | `\{observer_id, activation_id?\}` when this invocation is the activation of an observer's target. |
| `caller` | `dict[str, Any] \| None` | No | Who started it: `\{worker_id, worker_name, function_id?, invocation_id?, parent?\}`; `None` when unknown. |
| `function_id` | `str` | Yes | The function whose handler is running. |
| `invocation_id` | `str` | Yes | This invocation's id. |
| `observe_depth` | `int` | No | Depth of the causal chain in observe hops (0 outside any activation). |

***

#### MiddlewareFunctionInput

Input passed to the RBAC middleware function on every function invocation
through the RBAC port.

| Name | Type | Required | Description |
| - | - | - | - |
| `action` | [`TriggerActionEnqueue`](#triggeractionenqueue) \| [`TriggerActionVoid`](#triggeractionvoid) \| None | No | Routing action, if any. |
| `context` | `dict[str, Any]` | Yes | Auth context returned by the auth function for this session. |
| `function_id` | `str` | Yes | ID of the function being invoked. |
| `namespace` | `str \| None` | No | Target namespace the invoke addressed; forward the call here to stay in the caller's namespace. Absent -> the engine's default namespace. |
| `payload` | `dict[str, Any]` | Yes | Payload sent by the caller. |

***

#### Observed

What the target of an auto observer (or of `obs.emit`) receives with
`deliver: "envelope"` (the default). Fields not in the observer's
`capture` are absent.

| Name | Type | Required | Description |
| - | - | - | - |
| `activation_id` | `str` | Yes | - |
| `caller` | [`Caller`](#caller) | Yes | - |
| `duration_ms` | `float` | Yes | - |
| `error` | `dict[str, Any]` | Yes | - |
| `function_id` | `str` | Yes | - |
| `input` | `Any` | Yes | - |
| `invocation_id` | `str` | Yes | - |
| `metadata` | `dict[str, Any]` | Yes | - |
| `namespace` | `str` | Yes | - |
| `observer_id` | `str` | Yes | - |
| `output` | `Any` | Yes | - |
| `started_at_ms` | `int` | Yes | - |
| `status` | `Literal['success', 'error']` | Yes | - |

***

#### ObserveHooks

The `observe` option of `register_function`: how the function's
observers are delivered, and the callbacks that run when one is added or
removed.

Pass an instance, built with keyword arguments or from a subclass that
sets the attributes and defines the callbacks as (sync or async) methods.
Only `delivery`, `args_format`, `legacy_trigger_type` and `allow`
travel to the engine; the callbacks stay in this process.

| Name | Type | Required | Description |
| - | - | - | - |
| `allow` | `bool \| None` | No | Default `True`; `False` refuses every observer (`NOT_OBSERVABLE`). |
| `args_format` | `Any` | No | Owner only: JSON Schema (or a Pydantic model) of the observers' `args`; the engine answers `INVALID_ARGS`. |
| `delivery` | `Delivery \| None` | No | `"auto"` (default): every invocation is offered to every observer. `"owner"`: the handler hands each event to the observers it belongs to, with `obs.emit` / `obs.call`. |
| `from_value` | (value: [`ObserveHooks`](#observehooks) \| dict\[str, Any] \| None) -> [`ObserveHooks`](#observehooks) \| None | Yes | An `ObserveHooks` from what `register_function(observe=...)` was given. |
| `legacy_trigger_type` | `str \| None` | No | Accept old `register_trigger(\{"type": ...\})` calls for this trigger type (the engine's legacy shim). |
| `on_observer_added` | `ObserveHook \| None` | No | Runs once per added observer, before the SDK acks it. Raise to reject it (an :class:`~iii.ObserveRejection` sets the code, anything else is `OBSERVE_REJECTED`); after 30 s it is rejected with `OWNER_TIMEOUT`. |
| `on_observer_removed` | `ObserveHook \| None` | No | Runs once per removed observer. Cannot fail: errors are logged. |

***

#### Observer

An observer as the function's owner sees it (`on_observer_added`,
`FunctionRef.observers()`): its args, filters, target, capture and
`on`. Never its metadata, policy or the observing worker.

The object stays the same for the observer's whole lifetime, so owners
keep it in their own index (expression → observers, route table, ...).

| Name | Type | Required | Description |
| - | - | - | - |
| `args` | `dict[str, Any]` | No | The observer's args, validated against `args_format` by the engine. |
| `call` | `(payload: Any, *, timeout_ms: int \| None = None) -> Any` | Yes | Owner delivery, request/response: invokes the target with |
| `call_async` | `async (payload: Any, *, timeout_ms: int \| None = None) -> Any` | Yes | The async form of :meth:`call`. |
| `capture` | `list[str]` | No | What travels to the target (auto and `emit`). |
| `emit` | `(event: Any) -> bool` | Yes | Owner delivery, fire-and-forget: hands `event` to this observer. |
| `filters` | `dict[str, Any]` | No | The observer's filters, normalized; the SDK applies them in `emit` / `call`. |
| `function_id` | `str` | No | The observed function (the one this worker hosts). |
| `id` | `str` | No | The observer's id. |
| `legacy` | `dict[str, Any] \| None` | No | `\{trigger_type, config\}` when the engine's legacy shim created the observer from an old `register_trigger`. |
| `matches` | `(doc: Mapping[str, Any]) -> bool` | Yes | Evaluates the observer's filters on a document |
| `on` | `str` | No | `success`, `error` or `complete` (auto only). |
| `reject` | `(code: str, message: str) -> None` | Yes | Late rejection of an active observer (e.g. after a config reload). |
| `target` | `str` | No | The target function id. |
| `to_dict` | `() -> dict[str, Any]` | Yes | - |

***

#### ObserverHandle

What `iii.observe` returns, synchronously.

The observer is replayed with the same id on every reconnect until it is
disposed. State listeners are called in order, on a callback thread of the
SDK (never on the event loop that reads the engine's frames), so they may
call the sync API.

| Name | Type | Required | Description |
| - | - | - | - |
| `dispose` | `() -> None` | Yes | Removes the observer (`unobserve`). It is not replayed on reconnect. |
| `dispose_async` | `async () -> None` | Yes | The async form of :meth:`dispose` (it does not wait for the engine). |
| `id` | `Any` | No | The observer's id (stable across replays). |
| `on_state_change` | `(listener: StateListener) -> Callable[[], None]` | Yes | Calls `listener(state, reason)` on every state change, in order, |
| `ready` | `(timeout: float \| None = None) -> None` | Yes | Blocks until the observer is `active`. Use :meth:`ready_async` in async code. |
| `ready_async` | `async () -> None` | Yes | Waits until the observer is `active` (on any event loop). |
| `reason` | `ObserveReason \| None` | Yes | Why the observer is in its state (`error`, `suspended`, `disposed`). |
| `state` | `ObserverState` | Yes | `pending`, `active`, `suspended`, `error` or `disposed`. |

***

#### ObserverOptions

The observer itself: its id, policy and metadata (the third argument of `iii.observe`).

| Name | Type | Required | Description |
| - | - | - | - |
| `expires_in_ms` | `int` | Yes | Disposed after this long. |
| `id` | `str` | Yes | Default: a random UUID, stable across replays. |
| `max_fires` | `int` | Yes | Disposed after this many activations. |
| `max_in_flight` | `int` | Yes | Activations running at once (the engine queues the rest). |
| `metadata` | `dict[str, Any]` | Yes | Delivered as the metadata sidecar of every activation. |

***

#### ObserveSource

The left side of `iii.observe`: what is observed.

| Name | Type | Required | Description |
| - | - | - | - |
| `args` | `dict[str, Any]` | Yes | Owner-delivered functions only: for the owner; validated against its `args_format`. |
| `capture` | `list[Capture]` | Yes | Auto and `obs.emit`; default `["input", "output", "caller"]`. |
| `deliver` | `Literal['envelope', 'input', 'output']` | Yes | Auto and `obs.emit`; default `"envelope"`. |
| `filters` | `Filter` | Yes | Which events reach the target; `\{\}` (or absent) = every event. |
| `namespace` | `str` | Yes | Defaults to this worker's (`engine::*` resolves to `default`). |
| `on` | `Literal['success', 'error', 'complete']` | Yes | Auto only; default `"success"`. |

***

#### StreamRequest

Incoming streaming request received by a function registered with a stream trigger.

| Name | Type | Required | Description |
| - | - | - | - |
| `body` | `Any` | Yes | - |
| `headers` | `dict[str, str \| list[str]]` | Yes | - |
| `method` | `str` | Yes | - |
| `path_params` | `dict[str, str]` | Yes | - |
| `query_params` | `dict[str, str \| list[str]]` | Yes | - |
| `request_body` | [`ChannelReader`](#channelreader) | Yes | - |

***

#### StreamResponse

Streaming response built on top of a ChannelWriter.

| Name | Type | Required | Description |
| - | - | - | - |
| `close` | `() -> None` | Yes | - |
| `headers` | `async (headers: dict[str, str]) -> None` | Yes | - |
| `status` | `async (status_code: int) -> None` | Yes | - |
| `stream` | `WritableStream` | Yes | - |
| `writer` | [`ChannelWriter`](#channelwriter) | Yes | - |

***

#### TelemetryOptions

Worker metadata reported to the engine (language, framework, project).

| Name | Type | Required | Description |
| - | - | - | - |
| `framework` | `str \| None` | No | Framework name, if applicable. |
| `language` | `str \| None` | No | Programming language of the worker. |
| `project_name` | `str \| None` | No | Name of the project this worker belongs to. |

***

#### TriggerAction

Factory for creating trigger actions used with `trigger()`.

| Name | Type | Required | Description |
| - | - | - | - |
| `Enqueue` | (\*, queue: str) -> [`TriggerActionEnqueue`](#triggeractionenqueue) | Yes | Route the invocation through a named queue for async processing. |
| `Void` | () -> [`TriggerActionVoid`](#triggeractionvoid) | Yes | Fire-and-forget routing. No response is returned. |

***

#### TriggerActionEnqueue

Routes the invocation through a named queue for async processing.

Requires the `queue` worker in `worker-compose.yaml` and a matching
entry under that worker's `queue_configs`.
Without it the trigger rejects with `enqueue_error` (no queue provider).

| Name | Type | Required | Description |
| - | - | - | - |
| `queue` | `str` | Yes | Name of the target queue. |
| `type` | `Literal['enqueue']` | No | Always `'enqueue'`. |

### iii.channel

[`Channel`](#channel) · [`ChannelReader`](#channelreader) · [`ChannelWriter`](#channelwriter) · [`StreamChannelRef`](#streamchannelref)

#### Channel

A streaming channel pair for worker-to-worker data transfer.

| Name | Type | Required | Description |
| - | - | - | - |
| `reader` | [`ChannelReader`](#channelreader) | Yes | - |
| `reader_ref` | [`StreamChannelRef`](#streamchannelref) | Yes | - |
| `writer` | [`ChannelWriter`](#channelwriter) | Yes | - |
| `writer_ref` | [`StreamChannelRef`](#streamchannelref) | Yes | - |

***

#### ChannelReader

WebSocket-backed reader for streaming binary data and text messages.

| Name | Type | Required | Description |
| - | - | - | - |
| `close_async` | `async () -> None` | Yes | - |
| `on_message` | `(callback: Callable[[str], Any]) -> None` | Yes | - |
| `read_all` | `async () -> bytes` | Yes | Read the entire stream into a single bytes object. |
| `stream` | `Any` | No | - |

***

#### ChannelWriter

WebSocket-backed writer for streaming binary data and text messages.

| Name | Type | Required | Description |
| - | - | - | - |
| `close` | `() -> None` | Yes | Fire-and-forget close. |
| `close_async` | `async () -> None` | Yes | - |
| `send_message` | `(msg: str) -> None` | Yes | Fire-and-forget text message. Queues a coroutine on the running loop. |
| `send_message_async` | `async (msg: str) -> None` | Yes | - |
| `stream` | `Any` | No | - |
| `write` | `async (data: bytes) -> None` | Yes | - |

***

#### StreamChannelRef

Reference to a streaming channel for worker-to-worker data transfer.

| Name | Type | Required | Description |
| - | - | - | - |
| `access_key` | `str` | Yes | Secret key for authenticating channel access. |
| `channel_id` | `str` | Yes | Unique channel identifier. |
| `direction` | `Literal['read', 'write']` | Yes | Channel direction (`read` or `write`). |

### iii.engine

[`EngineFunctions`](#enginefunctions) · [`EngineTriggers`](#enginetriggers)

#### EngineFunctions

Engine function ids for internal operations (parity with the Node SDK).

| Name | Type | Required | Description |
| - | - | - | - |
| `INFO_FUNCTIONS` | `Final[str]` | No | - |
| `INFO_REGISTERED_TRIGGERS` | `Final[str]` | No | - |
| `INFO_TRIGGERS` | `Final[str]` | No | - |
| `INFO_WORKERS` | `Final[str]` | No | - |
| `LIST_FUNCTIONS` | `Final[str]` | No | - |
| `LIST_REGISTERED_TRIGGERS` | `Final[str]` | No | - |
| `LIST_TRIGGERS` | `Final[str]` | No | - |
| `LIST_WORKERS` | `Final[str]` | No | - |
| `REGISTER_WORKER` | `Final[str]` | No | - |

***

#### EngineTriggers

Engine trigger ids (parity with the Node SDK).

| Name | Type | Required | Description |
| - | - | - | - |
| `FUNCTIONS_AVAILABLE` | `Final[str]` | No | - |
| `LOG` | `Final[str]` | No | - |

### iii.errors

[`InvocationError`](#invocationerror) · [`ObserveRejection`](#observerejection) · [`RegistrationRejectedError`](#registrationrejectederror)

#### InvocationError

Raised when an invocation dispatched by the SDK fails.

Inspect `err.code` to react to a specific category (e.g.
`'FORBIDDEN'` for RBAC denials, `'TIMEOUT'` for timeouts). Catch
this class to handle every rejection. `except Exception` continues to
work because `InvocationError` inherits from `Exception`.

Attributes are read-only after construction. `stacktrace` is the
engine-side trace when the remote handler raised; it may include
internal file paths and should not be surfaced to end users. `str(err)`
intentionally never includes the stacktrace.

| Name | Type | Required | Description |
| - | - | - | - |
| `code` | `Any` | No | - |
| `function_id` | `Any` | No | - |
| `invocation_id` | `Any` | No | - |
| `message` | `Any` | No | - |
| `stacktrace` | `Any` | No | - |

***

#### ObserveRejection

Rejects an observer with a code of its own.

Raise it from an `on_observer_added` hook (`HTTP_ROUTE_CONFLICT`,
`INVALID_CRON_EXPRESSION`, ...); any other exception rejects the
observer with `OBSERVE_REJECTED`. Also what `ObserverHandle.ready()`
raises when the observer turns `error` or `disposed`, with the
engine's code (`INVALID_ARGS`, `FORBIDDEN`, `UNSUPPORTED`, ...).

| Name | Type | Required | Description |
| - | - | - | - |
| `code` | `Any` | No | - |
| `message` | `Any` | No | - |

***

#### RegistrationRejectedError

Raised when the engine rejects this worker's registration.

The engine pushes a `registrationrejected` message and closes the
connection on a registration collision (e.g. another live worker already
owns `(namespace, worker_name)`). This is fatal: the SDK does not
reconnect. Inspect the attributes to identify the conflict.

| Name | Type | Required | Description |
| - | - | - | - |
| `code` | `Any` | No | - |
| `namespace` | `Any` | No | - |
| `owner_worker_id` | `Any` | No | - |
| `worker_name` | `Any` | No | - |

### iii.protocol

[`MessageType`](#messagetype) · [`RegisterFunctionFormat`](#registerfunctionformat) · [`RegisterFunctionInput`](#registerfunctioninput) · [`RegisterFunctionMessage`](#registerfunctionmessage) · [`RegisterTriggerInput`](#registertriggerinput) · [`RegisterTriggerMessage`](#registertriggermessage) · [`RegisterTriggerTypeInput`](#registertriggertypeinput) · [`RegisterTriggerTypeMessage`](#registertriggertypemessage) · [`SDK_FEATURES`](#sdk_features) · [`TriggerRequest`](#triggerrequest)

#### MessageType

Message types for iii communication.

| Name | Type | Required | Description |
| - | - | - | - |
| `FUNCTION_REGISTERED` | `Any` | No | - |
| `INVOCATIONS_OBSERVED` | `Any` | No | - |
| `INVOCATION_RESULT` | `Any` | No | - |
| `INVOKE_FUNCTION` | `Any` | No | - |
| `LOCAL_INVOCATION_STATS` | `Any` | No | - |
| `OBSERVE` | `Any` | No | - |
| `OBSERVER_ACK` | `Any` | No | - |
| `OBSERVER_ADDED` | `Any` | No | - |
| `OBSERVER_REMOVED` | `Any` | No | - |
| `OBSERVER_STATE_CHANGED` | `Any` | No | - |
| `OBSERVE_RESULT` | `Any` | No | - |
| `REATTACH` | `Any` | No | - |
| `REGISTER_FUNCTION` | `Any` | No | - |
| `REGISTER_SERVICE` | `Any` | No | - |
| `REGISTER_TRIGGER` | `Any` | No | - |
| `REGISTER_TRIGGER_TYPE` | `Any` | No | - |
| `REGISTRATION_REJECTED` | `Any` | No | - |
| `TRIGGER_REGISTRATION_RESULT` | `Any` | No | - |
| `UNOBSERVE` | `Any` | No | - |
| `UNREGISTER_FUNCTION` | `Any` | No | - |
| `UNREGISTER_TRIGGER` | `Any` | No | - |
| `UNREGISTER_TRIGGER_TYPE` | `Any` | No | - |
| `WORKER_REGISTERED` | `Any` | No | - |

***

#### RegisterFunctionFormat

Format definition for function parameters.

| Name | Type | Required | Description |
| - | - | - | - |
| `body` | list\[[`RegisterFunctionFormat`](#registerfunctionformat)] \| None | No | Nested fields for object types. |
| `description` | `str \| None` | No | Human-readable description of the parameter. |
| `items` | [`RegisterFunctionFormat`](#registerfunctionformat) \| None | No | Item schema for array types. |
| `name` | `str` | Yes | Parameter name. |
| `required` | `bool` | No | Whether the parameter is required. |
| `type` | `str` | Yes | Type string (`string`, `number`, `boolean`, `object`, `array`, `null`, `map`). |

***

#### RegisterFunctionInput

Input for registering a function, matches Node.js RegisterFunctionInput.

| Name | Type | Required | Description |
| - | - | - | - |
| `description` | `str \| None` | No | Human-readable description. |
| `id` | `str` | Yes | Unique function identifier. |
| `invocation` | `HttpInvocationConfig \| None` | No | HTTP invocation config for externally hosted functions. |
| `metadata` | `Any \| None` | No | Arbitrary metadata attached to the function. |
| `request_format` | [`RegisterFunctionFormat`](#registerfunctionformat) \| dict\[str, Any] \| None | No | Schema describing expected input. |
| `response_format` | [`RegisterFunctionFormat`](#registerfunctionformat) \| dict\[str, Any] \| None | No | Schema describing expected output. |

***

#### RegisterFunctionMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `description` | `str \| None` | No | - |
| `id` | `str` | Yes | - |
| `invocation` | `HttpInvocationConfig \| None` | No | - |
| `message_type` | [`MessageType`](#messagetype) | No | - |
| `metadata` | `Any \| None` | No | - |
| `observe` | `ObserveDescriptor \| None` | No | - |
| `request_format` | [`RegisterFunctionFormat`](#registerfunctionformat) \| dict\[str, Any] \| None | No | - |
| `response_format` | [`RegisterFunctionFormat`](#registerfunctionformat) \| dict\[str, Any] \| None | No | - |

***

#### RegisterTriggerInput

Input for registering a trigger (matches Node SDK's RegisterTriggerInput).

| Name | Type | Required | Description |
| - | - | - | - |
| `config` | `Any` | No | Trigger-type-specific configuration, matching the shape the trigger type expects. |
| `function_id` | `str` | Yes | ID of the function this trigger invokes when it fires. |
| `metadata` | `Any \| None` | No | Arbitrary user-specifiable metadata supplied to the triggered handler function on every invocation. |
| `namespace` | `str \| None` | No | Namespace the target function resolves in. |
| `trigger_namespace` | `str \| None` | No | Namespace the trigger type's provider is found in. |
| `type` | `str` | Yes | Identifier of the registered trigger type this trigger uses (e.g. `storage::object-created`, `http`). |

***

#### RegisterTriggerMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `config` | `Any` | Yes | - |
| `function_id` | `str` | Yes | - |
| `id` | `str` | Yes | - |
| `message_type` | [`MessageType`](#messagetype) | No | - |
| `metadata` | `Any \| None` | No | - |
| `namespace` | `str \| None` | No | - |
| `trigger_namespace` | `str \| None` | No | - |
| `trigger_type` | `str` | Yes | - |

***

#### RegisterTriggerTypeInput

Input for registering a trigger type.

| Name | Type | Required | Description |
| - | - | - | - |
| `call_request_format` | `Any \| None` | No | JSON Schema describing the payload sent to functions. |
| `description` | `str` | Yes | Human-readable description of what this trigger type does. |
| `id` | `str` | Yes | Unique identifier for the trigger type (e.g. `state`, `durable:subscriber`). |
| `trigger_request_format` | `Any \| None` | No | JSON Schema describing the expected trigger config. |

***

#### RegisterTriggerTypeMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `call_request_format` | `Any \| None` | No | - |
| `description` | `str` | Yes | - |
| `id` | `str` | Yes | - |
| `message_type` | [`MessageType`](#messagetype) | No | - |
| `namespace` | `str \| None` | No | - |
| `trigger_request_format` | `Any \| None` | No | - |

***

#### SDK\_FEATURES

```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
SDK_FEATURES = tuple[str, ...]
```

***

#### TriggerRequest

Request object for `trigger()`.

| Name | Type | Required | Description |
| - | - | - | - |
| `action` | [`TriggerActionEnqueue`](#triggeractionenqueue) \| [`TriggerActionVoid`](#triggeractionvoid) \| None | No | Sets how the trigger is routed. Omit for a synchronous request/response. Specify for a specific routing scheme (e.g. `TriggerAction.Enqueue(...)`, `TriggerAction.Void()`). |
| `dispatch` | `Literal['auto', 'remote'] \| None` | No | `auto` (default) runs a function this worker hosts in-process once the engine confirmed it; `remote` always goes through the engine. |
| `function_id` | `str` | Yes | ID of the function to invoke. |
| `metadata` | `Any \| None` | No | Arbitrary user-specifiable metadata supplied to the triggered handler function on every invocation. |
| `namespace` | `str \| None` | No | Target namespace for routing. Omit to inherit this worker's; say `default` to reach the engine's from a namespaced worker. |
| `payload` | `Any` | No | Input data passed to the function. |
| `timeout_ms` | `int \| None` | No | Override the default invocation timeout, in milliseconds. |

### iii.runtime

[`FunctionRef`](#functionref) · [`TriggerTypeRef`](#triggertyperef)

#### FunctionRef

Reference to a registered function, allowing programmatic unregistration.

| Name | Type | Required | Description |
| - | - | - | - |
| `id` | `str` | Yes | The unique function identifier. |
| `is_observed` | `() -> bool` | Yes | Whether any observer is active on this function (one load, for the |
| `observers` | `() -> list[Any]` | Yes | The active observers (`iii.Observer`), as this owner sees them. |
| `unregister` | `Callable[[], None]` | Yes | Removes this function from the engine. |

***

#### TriggerTypeRef

Typed handle returned by :meth:`iii.III.register_trigger_type`.

.. deprecated:: 0.25.0
Trigger types are replaced by functions with an observe descriptor,
and these helpers by `iii.observe`. Migration guide:
[https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md)

Type parameters:

* `C`: configuration type for :meth:`register_trigger`
* `R`: call-request type for :meth:`register_function`

| Name | Type | Required | Description |
| - | - | - | - |
| `register_function` | `(function_id: str, handler: Callable[[R], Any] \| Callable[[R], Awaitable[Any]], *, description: str \| None = None) -> Any` | Yes | Register a function whose input matches the call-request format. |
| `register_trigger` | (function\_id: str, config: C, metadata: dict\[str, Any] \| None = None) -> [`Trigger`](#trigger) | Yes | Register a trigger with validated config. |

### iii.state

[`IState`](#istate) · [`StateDeleteInput`](#statedeleteinput) · [`StateDeleteResult`](#statedeleteresult) · [`StateEventData`](#stateeventdata) · [`StateEventType`](#stateeventtype) · [`StateGetInput`](#stategetinput) · [`StateListInput`](#statelistinput) · [`StateSetInput`](#statesetinput) · [`StateSetResult`](#statesetresult) · [`StateUpdateInput`](#stateupdateinput) · [`StateUpdateResult`](#stateupdateresult)

#### IState

Abstract interface for state management operations.

| Name | Type | Required | Description |
| - | - | - | - |
| `delete` | async (input: [`StateDeleteInput`](#statedeleteinput)) -> [`StateDeleteResult`](#statedeleteresult) | Yes | Delete a state value. |
| `get` | async (input: [`StateGetInput`](#stategetinput)) -> TData \| None | Yes | Retrieve a value by scope and key. |
| `list` | async (input: [`StateListInput`](#statelistinput)) -> list\[TData] | Yes | List all values in a scope. |
| `set` | async (input: [`StateSetInput`](#statesetinput)) -> [`StateSetResult`](#statesetresult)\[TData] \| None | Yes | Set (create or overwrite) a state value. |
| `update` | async (input: [`StateUpdateInput`](#stateupdateinput)) -> [`StateUpdateResult`](#stateupdateresult)\[TData] \| None | Yes | Apply atomic update operations to a state value. |

***

#### StateDeleteInput

Input for deleting a state value.

| Name | Type | Required | Description |
| - | - | - | - |
| `key` | `str` | Yes | Key within the scope. |
| `scope` | `str` | Yes | State scope (namespace). |

***

#### StateDeleteResult

Result of a state delete operation.

| Name | Type | Required | Description |
| - | - | - | - |
| `old_value` | `Any \| None` | No | Previous value (if it existed). |

***

#### StateEventData

Payload for state change events.

| Name | Type | Required | Description |
| - | - | - | - |
| `event_type` | [`StateEventType`](#stateeventtype) | Yes | Type of state change. |
| `key` | `str` | Yes | Key within the scope. |
| `new_value` | `TData \| None` | No | New value (for create/update events). |
| `old_value` | `TData \| None` | No | Previous value (for update/delete events). |
| `scope` | `str` | Yes | State scope (namespace). |
| `type` | `str` | No | Event category (always `state`). |

***

#### StateEventType

Types of state change events.

| Name | Type | Required | Description |
| - | - | - | - |
| `CREATED` | `Any` | No | - |
| `DELETED` | `Any` | No | - |
| `UPDATED` | `Any` | No | - |

***

#### StateGetInput

Input for retrieving a state value.

| Name | Type | Required | Description |
| - | - | - | - |
| `key` | `str` | Yes | Key within the scope. |
| `scope` | `str` | Yes | State scope (namespace). |

***

#### StateListInput

Input for listing all values in a state scope.

| Name | Type | Required | Description |
| - | - | - | - |
| `scope` | `str` | Yes | State scope (namespace). |

***

#### StateSetInput

Input for setting a state value.

| Name | Type | Required | Description |
| - | - | - | - |
| `key` | `str` | Yes | Key within the scope. |
| `scope` | `str` | Yes | State scope (namespace). |
| `value` | `Any` | Yes | Value to store. |

***

#### StateSetResult

Result of a state set operation.

| Name | Type | Required | Description |
| - | - | - | - |
| `new_value` | `TData` | Yes | New value that was stored. |
| `old_value` | `TData \| None` | No | Previous value (if it existed). |

***

#### StateUpdateInput

Input for atomically updating a state value.

| Name | Type | Required | Description |
| - | - | - | - |
| `key` | `str` | Yes | Key within the scope. |
| `ops` | `list[UpdateOp]` | Yes | Ordered list of update operations to apply atomically. |
| `scope` | `str` | Yes | State scope (namespace). |

***

#### StateUpdateResult

Result of a state update operation.

| Name | Type | Required | Description |
| - | - | - | - |
| `new_value` | `TData` | Yes | New value after the update. |
| `old_value` | `TData \| None` | No | Previous value (if it existed). |

### iii.stream

[`IStream`](#istream) · [`StreamDeleteInput`](#streamdeleteinput) · [`StreamDeleteResult`](#streamdeleteresult) · [`StreamGetInput`](#streamgetinput) · [`StreamListGroupsInput`](#streamlistgroupsinput) · [`StreamListInput`](#streamlistinput) · [`StreamSetInput`](#streamsetinput) · [`StreamSetResult`](#streamsetresult) · [`StreamUpdateInput`](#streamupdateinput) · [`StreamUpdateResult`](#streamupdateresult)

#### IStream

Abstract interface for stream operations.

| Name | Type | Required | Description |
| - | - | - | - |
| `delete` | async (input: [`StreamDeleteInput`](#streamdeleteinput)) -> [`StreamDeleteResult`](#streamdeleteresult) | Yes | Delete an item from the stream. |
| `get` | async (input: [`StreamGetInput`](#streamgetinput)) -> TData \| None | Yes | Get an item from the stream. |
| `list` | async (input: [`StreamListInput`](#streamlistinput)) -> list\[TData] | Yes | Get all items in a group. |
| `list_groups` | async (input: [`StreamListGroupsInput`](#streamlistgroupsinput)) -> List\[str] | Yes | List all groups in the stream. |
| `set` | async (input: [`StreamSetInput`](#streamsetinput)) -> [`StreamSetResult`](#streamsetresult)\[TData] \| None | Yes | Set an item in the stream. |
| `update` | async (input: [`StreamUpdateInput`](#streamupdateinput)) -> [`StreamUpdateResult`](#streamupdateresult)\[TData] \| None | Yes | Apply atomic update operations to a stream item. |

***

#### StreamDeleteInput

Input for stream delete operation.

| Name | Type | Required | Description |
| - | - | - | - |
| `group_id` | `str` | Yes | Group identifier. |
| `item_id` | `str` | Yes | Item identifier. |
| `stream_name` | `str` | Yes | Name of the stream. |

***

#### StreamDeleteResult

Result of stream delete operation.

| Name | Type | Required | Description |
| - | - | - | - |
| `old_value` | `Any \| None` | No | Previous value (if it existed). |

***

#### StreamGetInput

Input for stream get operation.

| Name | Type | Required | Description |
| - | - | - | - |
| `group_id` | `str` | Yes | Group identifier. |
| `item_id` | `str` | Yes | Item identifier. |
| `stream_name` | `str` | Yes | Name of the stream. |

***

#### StreamListGroupsInput

Input for stream list groups operation.

| Name | Type | Required | Description |
| - | - | - | - |
| `stream_name` | `str` | Yes | Name of the stream. |

***

#### StreamListInput

Input for stream list operation.

| Name | Type | Required | Description |
| - | - | - | - |
| `group_id` | `str` | Yes | Group identifier. |
| `stream_name` | `str` | Yes | Name of the stream. |

***

#### StreamSetInput

Input for stream set operation.

| Name | Type | Required | Description |
| - | - | - | - |
| `data` | `Any` | Yes | Data to store. |
| `group_id` | `str` | Yes | Group identifier. |
| `item_id` | `str` | Yes | Item identifier. |
| `stream_name` | `str` | Yes | Name of the stream. |

***

#### StreamSetResult

Result of stream set operation.

| Name | Type | Required | Description |
| - | - | - | - |
| `new_value` | `TData` | Yes | New value that was stored. |
| `old_value` | `TData \| None` | No | Previous value (if it existed). |

***

#### StreamUpdateInput

Input for stream update operation.

| Name | Type | Required | Description |
| - | - | - | - |
| `group_id` | `str` | Yes | Group identifier. |
| `item_id` | `str` | Yes | Item identifier. |
| `ops` | `list['UpdateOp']` | Yes | Ordered list of update operations to apply atomically. |
| `stream_name` | `str` | Yes | Name of the stream. |

***

#### StreamUpdateResult

Result of stream update operation.

| Name | Type | Required | Description |
| - | - | - | - |
| `errors` | `list[UpdateOpError]` | No | Per-op errors. Emitted by `merge` and `append` for validation rejections (path depth/size, value depth, or a `__proto__` / `constructor` / `prototype` segment or top-level key) and by `append` for the `append.type_mismatch` and `append.target_not_object` surfaces. Successfully applied ops are still reflected in `new_value`. The field is omitted from the JSON wire when empty. |
| `new_value` | `TData` | Yes | New value after the update. |
| `old_value` | `TData \| None` | No | Previous value (if it existed). |

### iii.trigger

[`Trigger`](#trigger) · [`TriggerActionVoid`](#triggeractionvoid) · [`TriggerConfig`](#triggerconfig) · [`TriggerHandler`](#triggerhandler)

#### Trigger

Represents a registered trigger.

.. deprecated:: 0.25.0
`register_trigger` is replaced by `iii.observe`, which returns an
:class:`~iii.ObserverHandle`.

| Name | Type | Required | Description |
| - | - | - | - |
| `unregister` | `() -> None` | Yes | Unregister this trigger. |

***

#### TriggerActionVoid

Fire-and-forget routing. No response is returned.

| Name | Type | Required | Description |
| - | - | - | - |
| `type` | `Literal['void']` | No | Always `'void'`. |

***

#### TriggerConfig

Configuration passed to a trigger handler when a trigger instance is
registered or unregistered.

.. deprecated:: 0.25.0
Replaced by the :class:`~iii.Observer` an `on_observer_added` hook
receives (`id`, `args`, `filters`, `target`).

| Name | Type | Required | Description |
| - | - | - | - |
| `config` | `Any` | Yes | Trigger-specific configuration. |
| `function_id` | `str` | Yes | Function to invoke when the trigger fires. |
| `id` | `str` | Yes | Trigger instance ID. |
| `metadata` | `dict[str, Any] \| None` | No | Arbitrary user-specifiable metadata supplied to the triggered handler function on every invocation. |
| `namespace` | `str \| None` | No | Resolved namespace the target function uses. Current SDKs fill an omitted registration value from the registering worker's namespace; `None` is the legacy/default case. |

***

#### TriggerHandler

Abstract base class for trigger handlers.

.. deprecated:: 0.25.0
Replaced by :class:`~iii.ObserveHooks` (`on_observer_added` /
`on_observer_removed`) on `register_function`. Migration guide:
[https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md)

| Name | Type | Required | Description |
| - | - | - | - |
| `register_trigger` | async (config: [`TriggerConfig`](#triggerconfig)\[TConfig]) -> None | Yes | Register a trigger with the given configuration. |
| `unregister_trigger` | async (config: [`TriggerConfig`](#triggerconfig)\[TConfig]) -> None | Yes | Unregister a trigger with the given configuration. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.