Core Concepts

Understanding the building blocks of a Melony agent.

Events: The Universal Currency

In Melony, everything is an Event. Whether it's a piece of text, a tool result, or custom data, it's represented as a standard event object.

interface Event {
  type: string;
  data: any;
  meta?: EventMeta; // id, runId, timestamp, role, state, etc.
}

The Runtime (created via the melony() builder) manages the flow of these events from the server to the client.

Event Handlers: Reactive Logic

Event handlers are the "brain" of your agent. They listen for specific event types and can yield new events. This event-driven approach allows for highly decoupled and reactive logic.

Example: Routing with Event Handlers

const agent = melony()
  .on("user:text", async function* (event, { runtime }) {
    // Route text messages based on content
    if (event.data.content.includes("weather")) {
      yield { type: "assistant:text", data: { content: "Weather in NYC is 72°F" } };
    }
  });

Handler Context

Handlers receive a context object which provides:

  • state: The current run state.
  • runtime: Access to the runtime instance (to trigger other events).
  • runId: Unique ID for the current execution.
  • suspend: A function to immediately halt execution (useful for Human-in-the-Loop).

Plugin System: Modular Agent Logic

Melony features a lightweight plugin system that allows you to modularize and reuse handlers across different agents. A plugin is simply a function that receives the MelonyBuilder.

import { melony, MelonyPlugin } from "melony";

const loggingPlugin: MelonyPlugin = (builder) => {
  builder.on("*", async function* (event) {
    console.log(`[Plugin] Event: ${event.type}`);
  });
};

const agent = melony()
  .use(loggingPlugin)
  .on("user:text", async function* () {
    yield { type: "assistant:text", data: { content: "Hello!" } };
  });

Chaining & Recursion

When a handler yields an event, that event is automatically passed back through the runtime's handlers. This allows for powerful, recursive behaviors.

const agent = melony()
  .on("greet", async function* () {
    yield { type: "assistant:text", data: { content: "Hello!" } };
  })
  .on("user:text", async function* (event) {
    if (event.data.content === "hi") {
      yield { type: "greet", data: {} }; // This will trigger the 'greet' handler
    }
  });
Core Concepts | Melony