/** * March Agent SDK - Structural Streaming Base * Port of Python march_agent/structural/base.py * * Base class for structural streaming objects. */ import type { Streamer } from '../streamer.js' /** * Abstract base class for structural streaming objects. * * Structural streamers generate events but don't hold streaming state. * The Streamer binds to them via streamBy() to enable streaming. */ export abstract class StructuralStreamer { readonly id: string protected _streamer?: Streamer constructor(id?: string) { this.id = id ?? this._generateId() } /** * Generate a unique ID for this streamer type. */ protected abstract _generateId(): string /** * Get the event type prefix (e.g., 'artifact', 'text_block'). */ abstract getEventTypePrefix(): string /** * Bind this structural streamer to a Streamer instance. * Called by Streamer.streamBy(). Returns self for chaining. */ _bindStreamer(streamer: Streamer): this { this._streamer = streamer return this } /** * Send an event through the bound streamer. * * Creates event payload and sends via streamer._send(). * Returns self for method chaining. */ protected _sendEvent(action: string, data: Record = {}): this { if (!this._streamer) { throw new Error( `${this.constructor.name} not bound to a Streamer. ` + `Call streamer.streamBy() first.` ) } // Build event body const body = { id: this.id, ...data } // Build event type const eventType = `${this.getEventTypePrefix()}:${action}` // Send through streamer using existing _send() method // content = stringified JSON body // eventType = structural event type // persist = false (structural events not persisted as content) this._streamer._send( JSON.stringify(body), false, // done false, // persist eventType ) return this } } /** * Generate a short random hex string for IDs. */ export function generateShortId(): string { return Math.random().toString(16).slice(2, 10) }