/** * Copyright 2023 Kapeta Inc. * SPDX-License-Identifier: BUSL-1.1 */ import { EventEmitter } from 'node:events'; import { StormEvent } from './events'; import { AIFileTypes, GeneratedFile } from '@kapeta/codegen'; import { BlockDefinition } from '@kapeta/schemas'; import { BlockDefinitionInfo } from './event-parser'; export class StormStream extends EventEmitter { private conversationId: string = ''; private lines: string[] = []; private aborted: boolean = false; private done: boolean = false; constructor(prompt: string = '', conversationId?: string | null) { super(); this.conversationId = conversationId || ''; } getConversationId() { return this.conversationId; } isAborted() { return this.aborted; } addJSONLine(line: string) { try { this.lines.push(line); const event = JSON.parse(line); if (!event.created) { event.created = Date.now(); } this.emit('data', event); } catch (e: any) { this.emit('error', e); console.warn('Failed to parse JSON line', e, line); } } end() { this.done = true; this.emit('end'); } on(event: 'end', listener: () => void): this; on(event: 'aborted', listener: () => void): this; on(event: 'error', listener: (e: Error) => void): this; on(event: 'data', listener: (data: StormEvent) => void): this; on(event: string, listener: (...args: any[]) => void): this { return super.on(event, listener); } emit(event: 'end'): boolean; emit(event: 'aborted'): void; emit(event: 'error', e: Error): boolean; emit(event: 'data', data: StormEvent): boolean; emit(eventName: string | symbol, ...args: any[]): boolean { return super.emit(eventName, ...args); } waitForDone() { if (this.done) { return Promise.resolve(); } return new Promise((resolve, reject) => { const errorHandler = (err: any) => { this.removeListener('error', errorHandler); this.removeListener('end', endHandler); reject(err); }; const endHandler = () => { this.removeListener('error', errorHandler); this.removeListener('end', endHandler); resolve(); }; this.on('error', errorHandler); this.on('end', endHandler); }); } abort() { if (this.aborted) { return; } this.aborted = true; this.done = true; this.emit('aborted'); } } export interface ConversationItem { role: 'user' | 'model'; content: string; } export interface StormContextRequest { conversationId?: string; systemId?: string; history?: ConversationItem[]; prompt: T; } export interface StormCreateBlockRequest { definition: BlockDefinition; tmpPath: string; newPath: string; } export interface StormCodegenRequest { block: BlockDefinitionInfo; prompt: string; events: StormEvent[]; outDir: string; } export interface StormFileInfo extends GeneratedFile { type: AIFileTypes; } export interface StormFileImplementationPrompt { context: StormFileInfo[]; template: StormFileInfo; prompt: string; } export interface StormUIImplementationPrompt { events: StormEvent[]; template: StormFileInfo; filename: string; context: StormFileInfo[]; blockName: string; prompt: string; } export interface StormUIListPrompt { events: StormEvent[]; templates: StormFileInfo[]; context: StormFileInfo[]; blockName: string; prompt: string; } export enum HTMLPageEncoding { TEXT = 'TEXT', BINARY = 'BINARY', } export interface ImplementAPIClients { pages: HTMLPage[]; systemId: string; } export interface HTMLPage { fileName: string; content: string; encoding: HTMLPageEncoding; } export interface CreateSimpleBackendRequest { pages: HTMLPage[]; }