/** * March Agent SDK - Stepper Structural Streamer * Port of Python march_agent/structural/stepper.py * * Stepper structural streamer for multi-step progress indicators. */ import { StructuralStreamer, generateShortId } from './base.js' /** * Manages multi-step progress indicator. * * Stepper events are NOT persisted to database. * IDs are auto-generated - no need to provide them manually. * * @example * ```typescript * const stepper = new Stepper({ steps: ["Fetch", "Process", "Report"] }) // ID auto-generated * s.streamBy(stepper).startStep(0) * s.streamBy(stepper).completeStep(0) * s.streamBy(stepper).startStep(1) * s.streamBy(stepper).addStep("Verify") // Dynamic step * s.streamBy(stepper).completeStep(1) * s.streamBy(stepper).done() * ``` */ export class Stepper extends StructuralStreamer { readonly steps: string[] private _initialized: boolean = false constructor(options?: { id?: string; steps?: string[] }) { super(options?.id) this.steps = options?.steps ?? [] } protected _generateId(): string { return `stepper-${generateShortId()}` } getEventTypePrefix(): string { return 'stepper' } /** * Send initialization event with steps if not already sent. * This is automatically called before any other stepper event. */ private _ensureInitialized(): this { if (!this._initialized && this.steps.length > 0) { this._sendEvent('init', { steps: this.steps }) this._initialized = true } return this } /** * Mark step as in progress. * * @param index - Step index to start * @returns this for method chaining */ startStep(index: number): this { this._ensureInitialized() return this._sendEvent('start_step', { index }) } /** * Mark step as complete. * * @param index - Step index to complete * @returns this for method chaining */ completeStep(index: number): this { this._ensureInitialized() return this._sendEvent('complete_step', { index }) } /** * Mark step as failed. * * @param index - Step index that failed * @param error - Optional error message * @returns this for method chaining */ failStep(index: number, error?: string): this { this._ensureInitialized() const data: Record = { index } if (error) { data.error = error } return this._sendEvent('fail_step', data) } /** * Add a new step dynamically. * * @param label - Step label * @param index - Optional position to insert at * @returns this for method chaining */ addStep(label: string, index?: number): this { this._ensureInitialized() const data: Record = { label } if (index !== undefined) { data.index = index } return this._sendEvent('add_step', data) } /** * Update step label. * * @param index - Step index to update * @param label - New label * @returns this for method chaining */ updateStepLabel(index: number, label: string): this { this._ensureInitialized() return this._sendEvent('update_step_label', { index, label }) } /** * Mark stepper as complete (all steps finished). * * @returns this for method chaining */ done(): this { this._ensureInitialized() return this._sendEvent('done') } }