Mozaik

Semantic events

Everything interesting on the runtime is a SemanticEvent with type, producerId, occurredAt, and payload.

The runtime is an event bus. Everything interesting is a SemanticEvent:

FieldMeaning
typeString name of the event ("message.sent", "inference.completed", …).
producerIdId of the participant that caused it.
occurredAtWhen it was created.
payloadTyped data for that event.

publish delivers every event to every joined participant. There is no built-in “internal vs external” split — a situation specification filters on event.type and on event.producerId versus participant.getId().

Participants never poll. Custom events go through sendEvent(event, senderId) with any type string.

import { SemanticEvent } from '@mozaik-ai/core';

sendEvent(SemanticEvent.create('goal.set', human.getId(), { goal: 'ship docs' }), human.getId());

sendEvent still requires senderId to be a joined participant. The event you pass is published as-is (including its own type and producerId).

Lifecycle and messaging

EventPublished whenPayload
participant.joinedjoin(participant)Participant manifest (id, name, role, capabilities)
participant.leftleave(participant)Participant manifest
message.sentsendMessage(message, senderId){ message: string }
customsendEvent(event, senderId)Whatever you put on the event

Agent loop

Producer is the agent whose loop is running:

EventPublished whenPayload
context_update.startedThe loop begins appending the user messageReceived message plus loopId
context_update.completedContext is ready for inferenceInferenceInput plus loopId
inference.startedThe model call beginsInferenceInput
inference.streamEach streaming chunk (only when streaming: true)The inner provider event
inference.completedThe model call finishedInferenceOutput (items, tokenUsage, rowResponse)
function_call.startedA tool is about to run{ call, inferenceInput }
function_call.completedThe tool returnedFunctionCallOutputItem
model.answerThe assistant message is committed{ answer: ModelMessageItem }
interception.startedAn InterceptionHandler matched a transitionThe pending LoopTransition
interception.finishedThe handler returned (possibly rewritten)The transition that will execute

context_update.started payload is { content, input, loopId } — the received user text, the InferenceInput you passed to runLoop, and that loop's id.

Streaming

Pass streaming: true on the InferenceInput you give runLoop. The loop takes the inference_streaming path and publishes each provider chunk as inference.stream (the inner event is the payload). Requesting streaming for a model whose specification has supportsStreaming: false fails validation before the API is called. See Streaming.

On this page