Architecture
Environment, participants, capabilities, and generators — how the four pieces fit together.
Mozaik has four moving parts. They are deliberately decoupled so you can change one without touching the others.
flowchart LR
Human[BaseHumanParticipant] -->|streamInput| Env(("AgenticEnvironment"))
Agent[BaseAgentParticipant] -->|"runInference / executeFunctionCall"| Env
Observer[Custom Participant] -->|join| Env
Env -->|onContextItem| Human
Env -->|onContextItem| Agent
Env -->|onContextItem| Observer
The four pieces
| Piece | Responsibility |
|---|---|
AgenticEnvironment | A broadcast bus. Receives items via deliverContextItem and fans them out to every joined participant's onContextItem callback. No central scheduler. |
Participant | The single abstraction for humans, agents, observers, and tools. Joins an environment and reacts to items via onContextItem(source, item). |
| Capabilities | What a participant can produce. InputCapable streams input items; InferenceCapable streams model output; FunctionCallCapable streams tool outputs. Capability methods are non-blocking — they return Promise<void> and emit items in the background. |
| Generators | The pluggable I/O behind the capabilities: InputItemSource, InferenceRunner, FunctionCallRunner. Swap any of them without changing the participant or the environment. |
How items flow
At runtime, every layer trades the same currency: typed ContextItems.
- A capability method (
streamInput,runInference,executeFunctionCall) is invoked on a participant. - The participant's generator yields items as they are produced.
- Each item is delivered to the environment via
deliverContextItem(initiator, item). - The environment dispatches
onContextItem(source, item)on every other participant — synchronously and without awaiting them, so a slow listener never blocks producers or other listeners. - Listening participants choose to observe, react (by triggering their own capabilities), or ignore.
Because each capability invocation is a fresh promise wrapping an async iterable, multiple participants can produce items into the same environment concurrently without any of them blocking on another.
How to choose a starting point
- Single agent reacting to user input — start with
BaseHumanParticipant+BaseAgentParticipantand the Quickstart. - Add observability without changing agent logic — add a passive observer that just logs in
onContextItem. - Multi-agent collaboration —
join()moreParticipants. They all see the same items in real time and can react independently. - Custom input, model, or tool execution — build a generator and pass it into
BaseAgentParticipant. - Direct, single-shot inference — call
OpenAIResponsesyourself with aModelContext.