Skip to content

Event System

AmritaCore's pipeline is event-driven. Workflow nodes and strategies dispatch events; registered matchers intercept them, may mutate them, and control flow through exceptions.

Matcher — the Hook Primitive

In AmritaSense terms: events are BaseEvents, dispatched through MatcherFactory.trigger_event(event, exception_ignored=...). Matchers match by event type string:

python
from amrita_sense.hook.matcher import Matcher

matcher = Matcher("agent.step_intro", priority=1)


@matcher.handle()
async def on_step_intro(event): ...

Use the literal string, not SomeEvent.event_type — the latter is a property object, not a string.

Event base classes

AmritaSense ships two event bases:

Base classAbstract contractUse when
BaseEventget_event_type() onlyThe event never needs a constructor()
ConstructableEventBaseEvent plus abstract constructor() — every subclass must implement itThe event is built via constructor()

constructor() is an inheritance-tree constraint (an abstract method), not a duck-typed protocol: a subclass of ConstructableEvent that omits it fails type-checking. All built-in step events inherit ConstructableEvent and implement constructor() — usually built manually via StepIntroEvent.constructor(rs) and dispatched with trigger_event(instance), but also usable by a workflow TRIGGER_EVENT node, which builds the instance from the class.

Event Categories

Pipeline events

EventType stringWhen
PreCompletionEventBefore the LLM call (mutate context here)
CompletionEventAfter the response (rewrite model_response)

Convenience decorators: @on_precompletion, @on_completion, @on_event("<type>").

Step lifecycle events (built-in ReAct)

Type stringMutable fieldsRaised on
agent.step_introoverride_phaseStep starts
agent.step_leaveoverride_verb, override_objectStep ends
agent.step_iterationend_stepAfter each tool round
agent.tool_callarguments, cancelBefore a regular tool executes
agent.tool_returnresult, skip_appendAfter a regular tool returns

All step events are constructed from AgentRunState via their constructor() classmethod.

Mutation and Control Flow

Two powerful properties:

  1. Events are mutable — the hook reads fields back after dispatch:

    python
    @on_event("agent.step_leave")
    async def fix_summary(event):
        event.override_verb = "Reviewed"  # replaces the auto summary
  2. exception_ignored — exceptions listed there propagate out of trigger_event to the hook. StepAbortError (a BaseException) is the framework's control-flow signal:

    python
    from amrita_core.builtins.agent.events import StepAbortError
    
    
    @on_event("agent.tool_call")
    async def block_tool(event):
        raise StepAbortError("blocked")  # tool never executes

How Events Reach Nodes

Workflow nodes and lifecycle hooks call _trigger_step_event(...); matchers registered in the same process see every dispatch. This is the extension point for guardrails, telemetry, and human-in-the-loop.

Next

Tool System — how tools are defined and executed.

Apache 2.0 License