Extension API Reference

This page is the reference companion to Writing extensions and Events. It documents the objects an extension’s register(mb) function receives and the types it works with.

register(mb) is called once at startup with an ExtensionContext built from the module’s [extensions.config.<module>] section. Import and registration failures are fatal — a module that cannot load stops startup rather than leaving the agent silently unable to use its tools.

ExtensionContext

class minibot.app.extensions.ExtensionContext(name, config, settings, event_bus, logger, entrypoint='daemon', tools=<factory>, subscriptions=<factory>, services=<factory>)[source]

Handed to an extension’s register(mb) function.

Deliberately narrow: the container is a class-level singleton, and passing it whole would make every one of its fields public API.

entrypoint is "daemon", "console", or "worker". Channel extensions must contribute nothing outside the daemon: those entrypoints do not drive channel services.

Parameters:
name: str
config: dict[str, Any]
settings: Settings
event_bus: EventBus
logger: Logger
entrypoint: ExtensionEntrypoint = 'daemon'
tools: list[ToolBinding]
subscriptions: list[tuple[type[BaseEvent], Callable[[Any], Awaitable[None]]]]
services: list[ExtensionService]
on(event_type, handler=None)[source]

Subscribe to event_type. Usable directly or as a decorator.

Parameters:
Return type:

Any

tool(func)[source]

Register func as a tool: name from __name__, description from its docstring, parameters from its first argument’s pydantic model.

For anything this does not cover — a name that is not a Python identifier, a hand-written schema, a description loaded from a file — build the ToolBinding yourself and pass it to add_tool.

Parameters:

func (Callable[[Any, ToolContext], Awaitable[Any]])

Return type:

Callable[[Any, ToolContext], Awaitable[Any]]

add_tool(bindings)[source]
Parameters:

bindings (ToolBinding | Sequence[ToolBinding])

Return type:

None

add_service(service)[source]
Parameters:

service (ExtensionService)

Return type:

None

ExtensionService

Objects passed to mb.add_service implement this protocol. They are started when the entrypoint starts and stopped on shutdown.

class minibot.app.extensions.ExtensionService(*args, **kwargs)[source]
async start()[source]
Return type:

None

async stop()[source]
Return type:

None

Tools

class minibot.llm.tools.base.ToolBinding(tool: 'Tool', handler: 'ToolHandler')[source]
Parameters:
tool: Tool
handler: Callable[[dict[str, Any], ToolContext], Awaitable[ToolResult | Any]]
class minibot.llm.tools.base.ToolContext(owner_id: 'str | None' = None, channel: 'str | None' = None, chat_id: 'int | None' = None, user_id: 'int | None' = None, turn_id: 'str | None' = None, task_handoff_callback: 'Callable[[str], Awaitable[None]] | None' = None)[source]
Parameters:
owner_id: str | None = None
channel: str | None = None
chat_id: int | None = None
user_id: int | None = None
turn_id: str | None = None
task_handoff_callback: Callable[[str], Awaitable[None]] | None = None

Events

Subscribe to any of these with @mb.on(EventType) or mb.on(EventType, handler). See Events for when each one fires and what its payload carries. Handlers are async and lossy: a slow handler drops events rather than blocking the pipeline.

class minibot.core.events.MessageEvent(*, event_id=<factory>, event_type='message', message)[source]
Parameters:
  • event_id (str)

  • event_type (str)

  • message (ChannelMessage)

event_type: str
message: ChannelMessage
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class minibot.core.events.OutboundEvent(*, event_id=<factory>, event_type='outbound', response)[source]
Parameters:
  • event_id (str)

  • event_type (str)

  • response (ChannelResponse)

event_type: str
response: ChannelResponse
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class minibot.core.events.OutboundFileEvent(*, event_id=<factory>, event_type='outbound_file', response)[source]
Parameters:
  • event_id (str)

  • event_type (str)

  • response (ChannelFileResponse)

event_type: str
response: ChannelFileResponse
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class minibot.core.events.OutboundFormatRepairEvent(*, event_id=<factory>, event_type='outbound_format_repair', response, parse_error, attempt=1, chat_id, channel, user_id=None)[source]
Parameters:
  • event_id (str)

  • event_type (str)

  • response (ChannelResponse)

  • parse_error (str)

  • attempt (int)

  • chat_id (int)

  • channel (str)

  • user_id (int | None)

event_type: str
response: ChannelResponse
parse_error: str
attempt: int
chat_id: int
channel: str
user_id: int | None
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class minibot.core.events.SystemEvent(*, event_id=<factory>, event_type='system', payload=None)[source]
Parameters:
  • event_id (str)

  • event_type (str)

  • payload (dict | None)

event_type: str
payload: dict | None
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class minibot.core.events.TurnStartedEvent(*, event_id=<factory>, event_type='turn_started', turn_id, channel, chat_id=None, user_id=None)[source]

Emitted when the dispatcher begins processing an inbound message.

Parameters:
  • event_id (str)

  • event_type (str)

  • turn_id (str)

  • channel (str)

  • chat_id (int | None)

  • user_id (int | None)

event_type: str
turn_id: str
channel: str
chat_id: int | None
user_id: int | None
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class minibot.core.events.TurnCompletedEvent(*, event_id=<factory>, event_type='turn_completed', turn_id, channel, chat_id=None, should_reply=True, llm_provider=None, llm_model=None, token_trace=<factory>, compaction_performed=None)[source]

Emitted once a turn is fully done.

Fires after the response has been dispatched to the channel, or deliberately suppressed when should_reply is false — never before.

Parameters:
  • event_id (str)

  • event_type (str)

  • turn_id (str)

  • channel (str)

  • chat_id (int | None)

  • should_reply (bool)

  • llm_provider (str | None)

  • llm_model (str | None)

  • token_trace (dict[str, Any])

  • compaction_performed (bool | None)

event_type: str
turn_id: str
channel: str
chat_id: int | None
should_reply: bool
llm_provider: str | None
llm_model: str | None
token_trace: dict[str, Any]
compaction_performed: bool | None
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class minibot.core.events.TurnFailedEvent(*, event_id=<factory>, event_type='turn_failed', turn_id, channel, chat_id=None, error)[source]

Emitted when a turn raised before producing a response.

Parameters:
  • event_id (str)

  • event_type (str)

  • turn_id (str)

  • channel (str)

  • chat_id (int | None)

  • error (str)

event_type: str
turn_id: str
channel: str
chat_id: int | None
error: str
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class minibot.core.events.ReasoningEvent(*, event_id=<factory>, event_type='reasoning', text, step, turn_id=None, owner_id=None, channel=None, chat_id=None)[source]

Emitted as soon as one provider step returns reasoning, before the turn finishes.

Reasoning is also attached to the final response metadata; this event exists so a channel can show thinking while the turn is still running instead of only after it completes.

Parameters:
  • event_id (str)

  • event_type (str)

  • text (str)

  • step (int)

  • turn_id (str | None)

  • owner_id (str | None)

  • channel (str | None)

  • chat_id (int | None)

event_type: str
text: str
step: int
turn_id: str | None
owner_id: str | None
channel: str | None
chat_id: int | None
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class minibot.core.events.ToolCallEvent(*, event_id=<factory>, event_type='tool_call', phase, tool_name, turn_id=None, owner_id=None, channel=None, chat_id=None, detail='', error=None)[source]

Emitted around every tool handler invocation.

detail is already redacted and clipped by minibot/shared/tool_call_display.py before this event is published — the raw argument payload (which can hold credentials, e.g. http_request headers, bash env, python_execute code) never leaves the tool-execution layer. Safe to log, persist, or forward to any subscriber, including extensions.

Parameters:
  • event_id (str)

  • event_type (str)

  • phase (Literal['started', 'completed', 'failed'])

  • tool_name (str)

  • turn_id (str | None)

  • owner_id (str | None)

  • channel (str | None)

  • chat_id (int | None)

  • detail (str)

  • error (str | None)

event_type: str
phase: Literal['started', 'completed', 'failed']
tool_name: str
turn_id: str | None
owner_id: str | None
channel: str | None
chat_id: int | None
detail: str
error: str | None
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].