GemmaPoddocs
ReferenceDARTC

UI events

The AG-UI-shaped event catalogue carried on `gemmapod.ui.event`.

gemmapod.ui.event is the typed event stream pods use to drive a host UI without minting new DARTC topics per affordance. Every envelope on this topic wraps a DartcUiEvent in a versioned payload:

interface DartcUiEventPayload {
  schema: "dartc.ui.event/0.1";
  event: DartcUiEvent;
}

The runtime auto-verifies envelopes, unwraps the event, and re-emits it on the typed bus:

runtime.events.on("ui.event", ({ event }) => {
  // event is a fully-typed DartcUiEvent
});

Catalogue

Lifecycle

TypePayload fields beyond type
RUN_STARTEDthreadId, runId, parentRunId?, input?, timestamp?
RUN_FINISHEDthreadId, runId, timestamp?
RUN_ERRORthreadId, runId, message, code?, timestamp?

Text messages

Start/content/end triplet for streaming assistant (or other-role) text.

TypePayload fields beyond type
TEXT_MESSAGE_STARTthreadId, runId, messageId, role: "assistant" | "user" | "system" | "tool" | "reasoning", timestamp?
TEXT_MESSAGE_CONTENTthreadId, runId, messageId, delta, timestamp?
TEXT_MESSAGE_ENDthreadId, runId, messageId, timestamp?

Tool calls

TypePayload fields beyond type
TOOL_CALL_STARTthreadId, runId, toolCallId, toolCallName, parentMessageId?, timestamp?
TOOL_CALL_ARGSthreadId, runId, toolCallId, delta, timestamp?
TOOL_CALL_ENDthreadId, runId, toolCallId, timestamp?
TOOL_CALL_RESULTthreadId, runId, messageId, toolCallId, content, role?: "tool", timestamp?

State

Auto-applied into RuntimeStateStore.

TypePayload fields beyond type
STATE_SNAPSHOTthreadId, runId?, snapshot, timestamp?
STATE_DELTAthreadId, runId?, delta: JsonPatchOperation[], timestamp? (RFC 6902)

Chat history

TypePayload fields beyond type
MESSAGES_SNAPSHOTthreadId, messages: Array<{ id?: string; role: string; content?: string; …}>, timestamp?

Auto-applied into RuntimeChatApi.setHistory.

Activity (per-message side panels)

Not auto-applied — the host decides how to render.

TypePayload fields beyond type
ACTIVITY_SNAPSHOTthreadId, runId?, messageId, activityType, content, replace?, timestamp?
ACTIVITY_DELTAthreadId, runId?, messageId, activityType, patch: JsonPatchOperation[], timestamp?

Escape hatches

TypePayload fields beyond typeWhen to use
CUSTOMthreadId, runId?, name, value?, timestamp?Anything app-specific that doesn't fit the typed catalogue.
RAWthreadId?, runId?, event: unknown, timestamp?Vendor-specific telemetry. MUST NOT carry chat content.

AG-UI mapping

Use mapDartcUiEventToAgUi(event) to rewrite the type discriminator from SCREAMING_SNAKE to PascalCase for AG-UI consumers. Field names are unchanged. Unknown DARTC types map to Raw.

See AG-UI bridge guide.

Helper

@gemmapod/dartc#createUiEventEnvelope wraps a DartcUiEvent in a signed DARTC envelope with the right topic + schema:

import { createUiEventEnvelope, signEnvelope } from "@gemmapod/dartc";

const envelope = await signEnvelope(
  createUiEventEnvelope({
    from: "pod:hello-pod:origin",
    to: "visitor:session-pubkey",
    event: {
      type: "STATE_DELTA",
      threadId: "conv_xyz",
      runId: "run_abc",
      delta: [{ op: "replace", path: "/cart/subtotalCents", value: 1400 }],
      timestamp: Date.now(),
    },
  }),
  sign,
);

See also