@dexwox-labs/a2a-server
Version:
TypeScript server implementation for Google's Agent-to-Agent (A2A) protocol - includes Express/WebSocket handlers, request validation and queue management
235 lines • 7.97 kB
JavaScript
;
/**
* @module EventQueue
* @description Event queue system for task events in the A2A protocol
*
* This module provides an event queue implementation for managing and distributing
* task-related events in the A2A protocol server. It supports event publishing,
* subscription, history tracking, and hierarchical event propagation.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EventQueue = void 0;
const node_events_1 = require("node:events");
/**
* Event queue for task-related events
*
* The EventQueue provides a publish-subscribe system for task-related events
* in the A2A protocol server. It maintains a history of recent events, supports
* hierarchical event propagation through child queues, and provides methods for
* publishing and subscribing to events.
*
* @example
* ```typescript
* // Create an event queue
* const eventQueue = new EventQueue();
*
* // Subscribe to events
* const unsubscribe = eventQueue.subscribe(event => {
* console.log(`Event: ${event.type} for task ${event.task.id}`);
*
* if (event.type === 'taskCompleted') {
* console.log('Task completed successfully!');
* }
* });
*
* // Publish an event
* eventQueue.publish({
* type: 'taskCreated',
* task: someTask,
* timestamp: Date.now()
* });
*
* // Later, unsubscribe
* unsubscribe();
*
* // Create a child queue that receives all events from the parent
* const childQueue = eventQueue.tap();
* ```
*/
class EventQueue {
constructor() {
/** Event emitter for handling event subscriptions */
this.emitter = new node_events_1.EventEmitter();
/** History of recent events */
this.history = [];
/** Maximum number of events to keep in history */
this.maxHistory = 1000;
/** Child queues that receive events from this queue */
this.children = [];
/** Whether this queue has been shut down */
this.isShutdown = false;
}
/**
* Publishes an event to the queue
*
* This method adds an event to the queue's history, emits it to all subscribers,
* and propagates it to any child queues. If the queue has been shut down,
* an error is thrown.
*
* @param event - The event to publish
* @throws Error if the queue has been shut down
*
* @example
* ```typescript
* eventQueue.publish({
* type: 'taskUpdated',
* task: updatedTask,
* timestamp: Date.now(),
* previousState: 'submitted'
* });
* ```
*/
publish(event) {
if (this.isShutdown) {
throw new Error('EventQueue has been shutdown');
}
// Add to history and enforce size limit
this.history.push(event);
if (this.history.length > this.maxHistory) {
this.history.shift();
}
this.emitter.emit('event', event);
// Propagate to child queues
this.children.forEach(child => child.publish(event));
}
/**
* Subscribes to events from the queue
*
* This method registers a callback to be called for each event in the queue.
* It immediately calls the callback with all historical events, then registers
* it for future events. It returns a function that can be called to unsubscribe.
*
* @param callback - Function to call for each event
* @returns Function to call to unsubscribe
*
* @example
* ```typescript
* const unsubscribe = eventQueue.subscribe(event => {
* if (event.type === 'taskCompleted') {
* console.log(`Task ${event.task.id} completed`);
* }
* });
*
* // Later, when no longer interested in events
* unsubscribe();
* ```
*/
subscribe(callback) {
// Send historical events first
this.history.forEach(event => callback(event));
// Subscribe to new events
this.emitter.on('event', callback);
return () => this.emitter.off('event', callback);
}
/**
* Creates a child queue that receives all events from this queue
*
* This method creates a new EventQueue and registers it as a child of this queue.
* All events published to this queue will also be published to the child queue.
* This is useful for creating specialized event handlers or for filtering events.
*
* @returns A new EventQueue that receives all events from this queue
*
* @example
* ```typescript
* // Create a main event queue
* const mainQueue = new EventQueue();
*
* // Create a specialized queue for completed tasks
* const completedTasksQueue = mainQueue.tap();
* completedTasksQueue.subscribe(event => {
* if (event.type === 'taskCompleted') {
* // Handle completed tasks
* }
* });
* ```
*/
tap() {
const child = new EventQueue();
this.children.push(child);
return child;
}
/**
* Shuts down the event queue
*
* This method marks the queue as shut down, closes all child queues,
* and removes all event listeners. After calling this method, no more
* events can be published to the queue.
*
* @example
* ```typescript
* // When done with the event queue
* eventQueue.close();
* ```
*/
close() {
this.isShutdown = true;
this.children.forEach(child => child.close());
this.emitter.removeAllListeners();
}
/**
* Gets a copy of the event history
*
* This method returns a copy of the queue's event history. The returned array
* is a new instance, so modifications to it will not affect the queue's history.
*
* @returns A copy of the event history
*
* @example
* ```typescript
* const history = eventQueue.getHistory();
* console.log(`Queue has ${history.length} events in history`);
* ```
*/
getHistory() {
return [...this.history];
}
/**
* Waits for and returns the next event from the queue
*
* This method returns a promise that resolves with the next event published
* to the queue. If the queue is shut down, it resolves with undefined.
* This is useful for implementing event-driven workflows.
*
* @returns Promise that resolves with the next event, or undefined if the queue is shut down
*
* @example
* ```typescript
* // Process events one at a time
* async function processEvents() {
* while (true) {
* const event = await eventQueue.dequeue();
* if (!event) {
* console.log('Queue has been shut down');
* break;
* }
* console.log(`Processing event: ${event.type}`);
* }
* }
* ```
*/
dequeue() {
return __awaiter(this, void 0, void 0, function* () {
if (this.isShutdown) {
return undefined;
}
return new Promise(resolve => {
const unsubscribe = this.subscribe(event => {
unsubscribe();
resolve(event);
});
});
});
}
}
exports.EventQueue = EventQueue;
//# sourceMappingURL=event-queue.js.map