Events
Create and route custom events in Python
Defining Custom Events
Subclass Event to define typed, self-documenting events. The event_type is
automatically set to the class name, and fields are type-annotated for clarity
but stored as JSON internally.
from blazen import Event
class AnalyzeEvent(Event):
text: str
score: float
ev = AnalyzeEvent(text="hello", score=0.9)
print(ev.event_type) # "AnalyzeEvent"
print(ev.text) # "hello"
print(ev.to_dict()) # {"text": "hello", "score": 0.9}
Built-in Events
StartEvent and StopEvent are provided by the framework. Every workflow
begins with a StartEvent and terminates when a StopEvent is returned.
from blazen import StartEvent, StopEvent
start = StartEvent(message="hello") # event_type: "blazen::StartEvent"
stop = StopEvent(result={"answer": 42}) # event_type: "blazen::StopEvent"
Event Routing via Type Hints
The type hint on the ev parameter controls which events a step accepts.
No explicit accepts list is needed.
ev: Event(or no type hint) — the step handlesStartEventby default.ev: SomeCustomEvent— the step automatically accepts onlySomeCustomEvent.
from blazen import Event, StartEvent, StopEvent, Context, step
class AnalyzeEvent(Event):
text: str
@step
async def first(ctx: Context, ev: Event):
# ev: Event -> accepts StartEvent
return AnalyzeEvent(text=ev.message)
@step
async def second(ctx: Context, ev: AnalyzeEvent):
# ev: AnalyzeEvent -> automatically accepts=["AnalyzeEvent"]
return StopEvent(result={"text": ev.text})
Fan-out (Multiple Events)
Return a list to dispatch multiple events simultaneously. Each event routes to its matching step independently.
from blazen import Event, Context, step
class BranchA(Event):
value: str
class BranchB(Event):
value: str
@step
async def fan_out(ctx: Context, ev: Event):
return [BranchA(value="a"), BranchB(value="b")]
Side-Effect Steps
Return None and use ctx.send_event() when a step needs to perform a
side effect without directly producing a next event in the return value.
from blazen import Event, Context, step
class ContinueEvent(Event):
pass
@step
async def side_effect(ctx: Context, ev: Event):
ctx.set("processed", True)
ctx.send_event(ContinueEvent())
return None
Alternative: Inline Events
For quick prototyping you can still create events inline without a subclass:
ev = Event("AnalyzeEvent", text="hello", score=0.9)
This is equivalent to defining a one-off event class. Prefer subclasses for production code since they give you type safety and self-documenting fields.