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
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
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
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
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
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.