GemmaPoddocs
Guides

CopilotKit-style hosts

Drop GemmaPod into a CopilotKit-shaped React shell using the AG-UI event mapping.

If your existing app already speaks AG-UI — CopilotKit, AI SDK consumers, anything that expects PascalCase event types — GemmaPod plugs in with one mapping call.

The translation

GemmaPod's gemmapod.ui.event topic carries DARTC events using SCREAMING_SNAKE type strings. AG-UI uses PascalCase. The payload field names match either way. The shim ships a pure function that rewrites only the discriminator:

const aguiEvent = GemmaPod.mapDartcUiEventToAgUi(event);
DARTCAG-UI
RUN_STARTEDRunStarted
RUN_FINISHEDRunFinished
RUN_ERRORRunError
TEXT_MESSAGE_STARTTextMessageStart
TEXT_MESSAGE_CONTENTTextMessageContent
TEXT_MESSAGE_ENDTextMessageEnd
TOOL_CALL_STARTToolCallStart
TOOL_CALL_ARGSToolCallArgs
TOOL_CALL_ENDToolCallEnd
TOOL_CALL_RESULTToolCallResult
STATE_SNAPSHOTStateSnapshot
STATE_DELTAStateDelta
MESSAGES_SNAPSHOTMessagesSnapshot
ACTIVITY_SNAPSHOTActivitySnapshot
ACTIVITY_DELTAActivityDelta
CUSTOMCustom
RAW / unknownRaw

The whole integration in one snippet

const { runtime } = await GemmaPod.mountPod(null, config, {
  ui: "none",
  fallbackUi: "default",
});

runtime.events.on("ui.event", ({ event }) => {
  const aguiEvent = GemmaPod.mapDartcUiEventToAgUi(event);
  // Dispatch into your existing AG-UI host:
  yourHost.dispatch(aguiEvent);
});

See it side-by-side

The copilotkit-style example renders every event in two columns — raw DARTC on the left, AG-UI on the right — so you can verify the mapping before wiring it into a real host.

pnpm --filter @gemmapod/example-copilotkit-style dev
# open http://localhost:5175

Why two vocabularies

DARTC predates AG-UI in the GemmaPod project. The discriminators differ because we wanted DARTC type strings that are visually distinct from other JSON fields when reading raw frames (logs, network panel, debugger). AG-UI uses PascalCase to match TypeScript convention. Field names converged — that was the harder thing to get right, so we built to match it.

The mapper is pure — call it where it's convenient. No runtime state. No async. No allocation beyond the new object.

See also