> For the complete documentation index, see [llms.txt](https://hive-4.gitbook.io/hive/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hive-4.gitbook.io/hive/modules/emitter-observability.md).

# Emitter (Observability)

> Location within the framework `Hive-agent-framework/emitter`.

An emitter is a core functionality of the framework that allows you to see what is happening under the hood.

## Standalone usage

The following examples demonstrate how `Emitter` concept works.

### Basic Usage

```ts
import { Emitter, EventMeta } from "Hive-agent-framework/emitter/emitter";

// Get the root emitter or create your own
const root = Emitter.root;

root.match("*.*", async (data: unknown, event: EventMeta) => {
  console.log(`Received event '${event.path}' with data ${JSON.stringify(data)}`);
});

await root.emit("start", { id: 123 });
await root.emit("end", { id: 123 });
```

*Source: examples/emitter/base.ts*

> \[!NOTE]
>
> You can create your own emitter by initiating the `Emitter` class, but typically it's better to use or fork the root one (as can be seen in the following examples).

### Advanced

```ts
import { Emitter, EventMeta, Callback } from "Hive-agent-framework/emitter/emitter";

// Define events in advanced
interface Events {
  start: Callback<{ id: number }>;
  update: Callback<{ id: number; data: string }>;
}

// Create emitter with a type support
const emitter = Emitter.root.child<Events>({
  namespace: ["Hive", "demo"],
  creator: {}, // typically a class
  context: {}, // custom data (propagates to the event's context property)
  groupId: undefined, // optional id for grouping common events (propagates to the event's groupId property)
  trace: undefined, // data related to identity what emitted what and which context (internally used by framework's components)
});

// Listen for "start" event
emitter.on("start", async (data, event: EventMeta) => {
  console.log(`Received ${event.name} event with id "${data.id}"`);
});

// Listen for "update" event
emitter.on("update", async (data, event: EventMeta) => {
  console.log(`Received ${event.name}' with id "${data.id}" and data ${data.data}`);
});

await emitter.emit("start", { id: 123 });
await emitter.emit("update", { id: 123, data: "Hello Hive!" });
```

*Source: examples/emitter/advanced.ts*

> \[!NOTE]
>
> Because we created the `Emitter` instance directly emitted events will not be propagated to the `root` which may or may not be desired. The `piping` concept is explained later on.

### Event Matching

```ts
import { Callback, Emitter } from "Hive-agent-framework/emitter/emitter";
import { BaseLLM } from "Hive-agent-framework/llms/base";

interface Events {
  update: Callback<{ data: string }>;
}

const emitter = new Emitter<Events>({
  namespace: ["app"],
});

// Match events by a concrete name (strictly typed)
emitter.on("update", async (data, event) => {});

// Match all events emitted directly on the instance (not nested)
emitter.match("*", async (data, event) => {});

// Match all events (included nested)
emitter.match("*.*", async (data, event) => {});

// Match events by providing a filter function
emitter.match(
  (event) => event.creator instanceof BaseLLM,
  async (data, event) => {},
);

// Match events by regex
emitter.match(/watsonx/, async (data, event) => {});
```

*Source: examples/emitter/matchers.ts*

### Event Piping

```ts
import { Emitter, EventMeta } from "Hive-agent-framework/emitter/emitter";

const first = new Emitter({
  namespace: ["app"],
});

first.match("*.*", (data: unknown, event: EventMeta) => {
  console.log(
    `'first' has retrieved the following event ${event.path}, isDirect: ${event.source === first}`,
  );
});

const second = new Emitter({
  namespace: ["app", "llm"],
});
second.match("*.*", (data: unknown, event: EventMeta) => {
  console.log(
    `'second' has retrieved the following event '${event.path}', isDirect: ${event.source === second}`,
  );
});

// Propagate all events from the 'second' emitter to the 'first' emitter
const unpipe = second.pipe(first);

await first.emit("a", {});
await second.emit("b", {});

console.log("Unpipe");
unpipe();

await first.emit("c", {});
await second.emit("d", {});
```

*Source: examples/emitter/piping.ts*

## Framework Usage

Typically, you consume out-of-the-box modules that use the `Emitter` concept on your behalf.

## Agent usage

```ts
import { HiveAgent } from "Hive-agent-framework/agents/Hive/agent";
import { UnconstrainedMemory } from "Hive-agent-framework/memory/unconstrainedMemory";
import { OllamaChatLLM } from "Hive-agent-framework/adapters/ollama/chat";

const agent = new HiveAgent({
  llm: new OllamaChatLLM(),
  memory: new UnconstrainedMemory(),
  tools: [],
});

// Matching events on the instance level
agent.emitter.match("*.*", (data, event) => {});

await agent
  .run({
    prompt: "Hello agent!",
  })
  .observe((emitter) => {
    // Matching events on the execution (run) level
    emitter.match("*.*", (data, event) => {
      console.info(`RUN LOG: received event '${event.path}'`);
    });
  });
```

*Source: examples/emitter/agentMatchers.ts*

> \[!IMPORTANT]
>
> The `observe` method is also supported on `Tools` and `LLMs`.

> \[!TIP]
>
> The more complex agentic example can be found here.

> \[!TIP]
>
> To verify if a given class instance has one, check for the presence of the `emitter` property.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hive-4.gitbook.io/hive/modules/emitter-observability.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
