Skip to content

defineEvent ​

Function, in src/define-event.ts of @jr2/agent-protocol, a dependency of @jr2/orchestrator. It is an export of @jr2/orchestrator, on the Authoring surface page, in Machine and events.

ts
function defineEvent<const Name extends string, Input extends z.ZodObject>(def: {
  name: Name;
  description?: string;
  input: Input;
  semantics?: EventSemantics;
  audience?: EventAudience;
}): EventDef<Name, Input>

Define one workflow event: an event that an Agent or the caller of a Gate may send into your Machine. Give the result to jr2Setup({ events }), and write its name as an on key on the states that take it. An Agent sees each event it may send as one tool on its Menu.

It gives back a frozen EventDef and registers nothing. Each Machine whose jr2Setup lists the event takes it. A Machine that does not list it does not take it.

Give an event only the params that the Machine reads. When a pick enters a state that invokes an Effect, createMachine refuses each param of the pick that nothing reads: the input of the Effect, an assign, or the fill of fromPick. The compiler does not find this error. jr2 check and jr2 up find it when they load the module. Thus when you copy a finish event with a summary and nothing uses the summary, drop summary from the input, or store it with assign.

It refuses:

  • a name with a character other than a letter, a digit, _ or -: defineEvent: invalid name "<name>" — must match /^[a-zA-Z0-9_-]+$/ (it becomes an MCP tool name and an xstate event type)
  • an input with a sender field: defineEvent: "<name>" declares `sender` in its input — the Orchestrator writes that field on every delivered event (who sent it); name the payload field something else
  • an output field: defineEvent: "<name>" declares an `output`, which is retired — every pick is answered when the work it started is done, and the answer is the Machine's, not the def's. With semantics: "deferred", the text says declares `deferred` in place of declares an `output` .

Parameters

  • def: The event: its name, its input schema, and optionally its description, semantics and audience.

    • name: Name

      The event's name: the on key that takes it, and the name of its tool on the Agent's Menu. Letters, digits, _ and - only.

    • description (optional): string

      What the event means, and when to send it. An Agent's model reads it as the tool's description. Make it true at every state that takes the event.

    • input: Input

      The schema of the payload: a flat z.object. Use z.object({}) for an event with no payload. Do not name a field sender: jr2 writes that field.

    • semantics (optional): EventSemantics

      How the sender gets its answer. Default: "ack", the only value createMachine accepts.

    • audience (optional): EventAudience

      Who may send the event: "agent", "external" or "any". Default: unset, and the state of each on key decides (see EventAudience).

Returns: The event, as plain data to list in jr2Setup({ events }).

Example

ts
import { z } from "zod";
import { agent, defineEvent, fail, jr2Setup } from "@jr2/orchestrator";

const done = defineEvent({
  name: "done",
  description: "Call this when the summary is written.",
  input: z.object({ summary: z.string() }),
});

export const machine = jr2Setup({
  events: [done],
  actors: {
    writer: agent({
      model: "anthropic/claude-haiku-5-5",
      instructions: "You write short summaries.",
      workspace: "none",
    }),
    fail: fail(),
  },
}).createMachine({
  id: "summary",
  on: { "agent.fault": ".failed" },
  initial: "writing",
  states: {
    writing: {
      invoke: { src: "writer", input: { prompt: "Summarize the release notes in one line." } },
      on: { done: "finished" },
    },
    finished: { type: "final" },
    failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
  },
});

See also

The docs of Kit version 0.5.1. Each page is also at its .md URL.