All files / api/src/handlers realtime-handler-node.ts

0% Statements 0/106
0% Branches 0/1
0% Functions 0/1
0% Lines 0/106

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127                                                                                                                                                                                                                                                             
import { providerConfigs } from '@api/ai-providers';
import { RealtimeLlmEventParser } from '@api/services/realtime-llm-event-parser';
import type { AppContext } from '@api/types/hono';
import type { InternalProviderAPIConfig } from '@shared/types/ai-providers/config';
import type { RealtimeSessionOptions } from '@shared/types/realtime';
import type { WSContext, WSEvents } from 'hono/ws';
import { WebSocket } from 'ws';
 
export async function realTimeHandlerNode(
  c: AppContext,
): Promise<WSEvents<unknown>> {
  try {
    let incomingWebsocket: WSContext<unknown> | null = null;
 
    const saConfig = c.get('sa_config');
    const saRequestData = c.get('sa_request_data');
 
    const provider = saConfig?.targets[0]?.configuration.ai_provider;
    if (!provider) {
      throw new Error('Provider not found');
    }
 
    const providerConfig = providerConfigs[provider];
    if (!providerConfig) {
      throw new Error('Provider not found');
    }
 
    const apiConfig: InternalProviderAPIConfig = providerConfig.api;
    if (!apiConfig) {
      throw new Error('API config not found');
    }
    const saTarget = saConfig.targets[0];
    const baseUrl = apiConfig.getBaseURL({
      c,
      saTarget,
      saRequestData,
    });
    const endpoint = apiConfig.getEndpoint({
      c,
      saTarget,
      saRequestData,
    });
    let url = `${baseUrl}${endpoint}`;
    url = url.replace('https://', 'wss://');
 
    const requestHeaders = await apiConfig.headers({
      c,
      saTarget,
      saRequestData,
    });
 
    const sessionOptions: RealtimeSessionOptions = {
      id: crypto.randomUUID(),
      providerOptions: {
        ...saTarget,
        requestURL: url,
        rubeusURL: 'realtime',
      },
      requestHeaders,
      requestParams: {},
    };
 
    const outgoingWebSocket = new WebSocket(url, { headers: requestHeaders });
    const eventParser = new RealtimeLlmEventParser();
 
    outgoingWebSocket.addEventListener('message', (event) => {
      incomingWebsocket?.send(event.data as string);
      try {
        const parsedData = JSON.parse(event.data as string);
        eventParser.handleEvent(c, parsedData, sessionOptions);
      } catch (err: unknown) {
        if (err instanceof Error) {
          console.error(`eventParser.handleEvent error: ${err.message}`);
        } else {
          console.error(`eventParser.handleEvent error: ${err}`);
        }
      }
    });
 
    outgoingWebSocket.addEventListener('close', (event) => {
      incomingWebsocket?.close(event.code, event.reason);
    });
 
    outgoingWebSocket.addEventListener('error', (event) => {
      console.error(`outgoingWebSocket error: ${event.message}`);
      incomingWebsocket?.close();
    });
 
    return {
      onOpen(_event, ws): void {
        incomingWebsocket = ws;
      },
      onMessage(event): void {
        outgoingWebSocket?.send(event.data as string);
      },
      onError(event): void {
        console.error(`incomingWebsocket error: ${event.type}`);
        outgoingWebSocket?.close();
      },
      onClose(): void {
        outgoingWebSocket?.close();
      },
    };
  } catch (err: unknown) {
    if (err instanceof Error) {
      console.error(`realtimeHandlerNode error: ${err.message}`);
    } else {
      console.error(`realtimeHandlerNode error: ${err}`);
    }
    c.set('websocket_error', true);
    return {
      onOpen(): void {
        // pass
      },
      onMessage(): void {
        // pass
      },
      onError(): void {
        // pass
      },
      onClose(): void {
        // pass
      },
    };
  }
}