@@ -3,6 +3,8 @@ import type {
33 StreamingInputs ,
44 StreamingOutputs
55} from "@nodetool-ai/node-sdk" ;
6+ import type { ImageRef , AudioRef } from "@nodetool-ai/node-sdk" ;
7+ import type { Chunk } from "@nodetool-ai/protocol" ;
68import type { ProcessingContext } from "@nodetool-ai/runtime" ;
79import { fetchExternalMedia } from "@nodetool-ai/runtime" ;
810import { tagAsServer } from "@nodetool-ai/nodes-utils" ;
@@ -57,9 +59,9 @@ export class EmbeddingNode extends BaseNode {
5759
5860 async process ( ) : Promise < Record < string , unknown > > {
5961 const apiKey = getApiKey ( this . _secrets ) ;
60- const text = String ( this . input ?? "" ) ;
61- const model = String ( this . model ?? "text-embedding-3-small" ) ;
62- const chunkSize = Number ( this . chunk_size ?? 4096 ) ;
62+ const text = this . input ;
63+ const model = this . model ;
64+ const chunkSize = this . chunk_size ;
6365
6466 const chunks : string [ ] = [ ] ;
6567 for ( let i = 0 ; i < text . length ; i += chunkSize ) {
@@ -123,7 +125,7 @@ export class WebSearchNode extends BaseNode {
123125
124126 async process ( ) : Promise < WebSearchNodeOutputs > {
125127 const apiKey = getApiKey ( this . _secrets ) ;
126- const query = String ( this . query ?? "" ) ;
128+ const query = this . query ;
127129 if ( ! query ) throw new Error ( "Search query cannot be empty" ) ;
128130
129131 const res = await fetch ( `${ OPENAI_API_BASE } /chat/completions` , {
@@ -195,8 +197,8 @@ export class ModerationNode extends BaseNode {
195197
196198 async process ( ) : Promise < Record < string , unknown > > {
197199 const apiKey = getApiKey ( this . _secrets ) ;
198- const text = String ( this . input ?? "" ) ;
199- const model = String ( this . model ?? "omni-moderation-latest" ) ;
200+ const text = this . input ;
201+ const model = this . model ;
200202 if ( ! text ) throw new Error ( "Input text cannot be empty" ) ;
201203
202204 const res = await fetch ( `${ OPENAI_API_BASE } /moderations` , {
@@ -292,13 +294,13 @@ export class CreateImageNode extends BaseNode {
292294
293295 async process ( ) : Promise < CreateImageNodeOutputs > {
294296 const apiKey = getApiKey ( this . _secrets ) ;
295- const prompt = String ( this . prompt ?? "" ) ;
297+ const prompt = this . prompt ;
296298 if ( ! prompt ) throw new Error ( "Prompt cannot be empty" ) ;
297299
298- const model = String ( this . model ?? "gpt-image-1" ) ;
299- const size = String ( this . size ?? "1024x1024" ) ;
300- const quality = String ( this . quality ?? "high" ) ;
301- const background = String ( this . background ?? "auto" ) ;
300+ const model = this . model ;
301+ const size = this . size ;
302+ const quality = this . quality ;
303+ const background = this . background ;
302304
303305 const res = await fetch ( `${ OPENAI_API_BASE } /images/generations` , {
304306 method : "POST" ,
@@ -419,17 +421,17 @@ export class EditImageNode extends BaseNode {
419421
420422 async process ( ) : Promise < EditImageNodeOutputs > {
421423 const apiKey = getApiKey ( this . _secrets ) ;
422- const prompt = String ( this . prompt ?? "" ) ;
424+ const prompt = this . prompt ;
423425 if ( ! prompt ) throw new Error ( "Edit prompt cannot be empty" ) ;
424426
425- const image = this . image as Record < string , unknown > | undefined ;
427+ const image = this . image ;
426428 if ( ! image || ( ! image . data && ! image . uri ) ) {
427429 throw new Error ( "Input image is required" ) ;
428430 }
429431
430- const model = String ( this . model ?? "gpt-image-1" ) ;
431- const size = String ( this . size ?? "1024x1024" ) ;
432- const quality = String ( this . quality ?? "high" ) ;
432+ const model = this . model ;
433+ const size = this . size ;
434+ const quality = this . quality ;
433435
434436 // gpt-image-1 always returns base64 and rejects `response_format`, so it
435437 // must not be sent (unlike the legacy dall-e-2 edits endpoint).
@@ -444,7 +446,7 @@ export class EditImageNode extends BaseNode {
444446 formData . append ( "image" , imageBlob , "image.png" ) ;
445447
446448 // Optional mask
447- const mask = this . mask as Record < string , unknown > | undefined ;
449+ const mask = this . mask ;
448450 if ( mask && ( mask . data || mask . uri ) ) {
449451 const maskBlob = await refToBlob ( mask ) ;
450452 formData . append ( "mask" , maskBlob , "mask.png" ) ;
@@ -521,11 +523,11 @@ export class ImageVariationNode extends BaseNode {
521523
522524 async process ( ) : Promise < ImageVariationNodeOutputs > {
523525 const apiKey = getApiKey ( this . _secrets ) ;
524- const image = this . image as Record < string , unknown > | undefined ;
526+ const image = this . image ;
525527 if ( ! image || ( ! image . data && ! image . uri ) ) {
526528 throw new Error ( "Input image is required" ) ;
527529 }
528- const size = String ( this . size ?? "1024x1024" ) ;
530+ const size = this . size ;
529531
530532 // The variations endpoint only supports dall-e-2, which requires the
531533 // `response_format` to request base64 output.
@@ -577,7 +579,9 @@ function audioRefFromB64(b64: string, contentType: string) {
577579}
578580
579581/** Convert an image/audio ref object to a Blob for multipart upload. */
580- async function refToBlob ( ref : Record < string , unknown > ) : Promise < Blob > {
582+ type MediaRefLike = { uri ?: string ; data ?: unknown } ;
583+
584+ async function refToBlob ( ref : MediaRefLike ) : Promise < Blob > {
581585 if ( ref . data && isString ( ref . data ) ) {
582586 const dataStr = ref . data ;
583587 // Handle data: URI
@@ -666,12 +670,12 @@ export class TextToSpeechNode extends BaseNode {
666670
667671 async process ( ) : Promise < TextToSpeechNodeOutputs > {
668672 const apiKey = getApiKey ( this . _secrets ) ;
669- const text = String ( this . input ?? "" ) ;
673+ const text = this . input ;
670674 if ( ! text ) throw new Error ( "Input text cannot be empty" ) ;
671- const model = String ( this . model ?? "tts-1" ) ;
672- const voice = String ( this . voice ?? "alloy" ) ;
673- const speed = Number ( this . speed ?? 1.0 ) ;
674- const instructions = String ( this . instructions ?? "" ) ;
675+ const model = this . model ;
676+ const voice = this . voice ;
677+ const speed = this . speed ;
678+ const instructions = this . instructions ;
675679
676680 const isMiniTts = model === "gpt-4o-mini-tts" ;
677681 const body : Record < string , unknown > = {
@@ -750,11 +754,11 @@ export class TranslateNode extends BaseNode {
750754
751755 async process ( ) : Promise < TranslateNodeOutputs > {
752756 const apiKey = getApiKey ( this . _secrets ) ;
753- const audio = this . audio as Record < string , unknown > | undefined ;
757+ const audio = this . audio ;
754758 if ( ! audio || ( ! audio . data && ! audio . uri ) ) {
755759 throw new Error ( "Audio input is required" ) ;
756760 }
757- const temperature = Number ( this . temperature ?? 0.0 ) ;
761+ const temperature = this . temperature ;
758762
759763 const audioBlob = await refToBlob ( audio ) ;
760764 const formData = new FormData ( ) ;
@@ -926,16 +930,16 @@ export class TranscribeNode extends BaseNode {
926930
927931 async process ( ) : Promise < TranscribeNodeOutputs > {
928932 const apiKey = getApiKey ( this . _secrets ) ;
929- const audio = this . audio as Record < string , unknown > | undefined ;
933+ const audio = this . audio ;
930934 if ( ! audio || ( ! audio . data && ! audio . uri ) ) {
931935 throw new Error ( "Audio input is required" ) ;
932936 }
933937
934- const model = String ( this . model ?? "whisper-1" ) ;
935- const language = String ( this . language ?? "auto_detect" ) ;
936- const timestamps = Boolean ( this . timestamps ?? false ) ;
937- const promptText = String ( this . prompt ?? "" ) ;
938- const temperature = Number ( this . temperature ?? 0 ) ;
938+ const model = this . model ;
939+ const language = this . language ;
940+ const timestamps = this . timestamps ;
941+ const promptText = this . prompt ;
942+ const temperature = this . temperature ;
939943
940944 const isNewModel =
941945 model === "gpt-4o-transcribe" || model === "gpt-4o-mini-transcribe" ;
@@ -1124,11 +1128,11 @@ export class RealtimeAgentNode extends BaseNode {
11241128 if ( ! apiKey ) apiKey = process . env . OPENAI_API_KEY ?? "" ;
11251129 if ( ! apiKey ) throw new Error ( "OPENAI_API_KEY is not configured" ) ;
11261130
1127- const model = String ( this . model ?? "gpt-4o-mini-realtime-preview" ) ;
1128- const voice = String ( this . voice ?? "alloy" ) ;
1129- const system = String ( this . system ?? "" ) ;
1130- const temperature = Number ( this . temperature ?? 0.8 ) ;
1131- const speed = Number ( this . speed ?? 1 ) ;
1131+ const model = this . model ;
1132+ const voice = this . voice ;
1133+ const system = this . system ;
1134+ const temperature = this . temperature ;
1135+ const speed = this . speed ;
11321136 const wantAudio = voice !== "none" ;
11331137
11341138 const { WebSocket } = await import ( "ws" ) ;
@@ -1406,8 +1410,8 @@ export class RealtimeTranscriptionNode extends BaseNode {
14061410 if ( ! apiKey ) apiKey = process . env . OPENAI_API_KEY ?? "" ;
14071411 if ( ! apiKey ) throw new Error ( "OPENAI_API_KEY is not configured" ) ;
14081412
1409- const model = String ( this . model ?? "gpt-4o-mini-realtime-preview" ) ;
1410- const temperature = Number ( this . temperature ?? 0.8 ) ;
1413+ const model = this . model ;
1414+ const temperature = this . temperature ;
14111415
14121416 const { WebSocket } = await import ( "ws" ) ;
14131417 const wsUrl = `wss://api.openai.com/v1/realtime?model=${ encodeURIComponent ( model ) } ` ;
@@ -1429,7 +1433,7 @@ export class RealtimeTranscriptionNode extends BaseNode {
14291433 type : "session.update" ,
14301434 session : {
14311435 modalities : [ "text" ] ,
1432- instructions : this . system ? String ( this . system ) : undefined ,
1436+ instructions : this . system || undefined ,
14331437 input_audio_format : "pcm16" ,
14341438 input_audio_transcription : { model : "gpt-4o-mini-transcribe" } ,
14351439 turn_detection : {
0 commit comments