@dtelecom/agents-js 0.1.17 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -403,9 +403,198 @@ var OpenRouterLLM = class {
403
403
  }
404
404
  };
405
405
 
406
+ // src/providers/openai-llm.ts
407
+ var log3 = createLogger("OpenAILLM");
408
+ var OPENAI_URL = "https://api.openai.com/v1/chat/completions";
409
+ var OpenAILLM = class {
410
+ apiKey;
411
+ model;
412
+ maxTokens;
413
+ temperature;
414
+ responseFormat;
415
+ constructor(options) {
416
+ if (!options.apiKey) {
417
+ throw new Error("OpenAILLM requires an apiKey");
418
+ }
419
+ this.apiKey = options.apiKey;
420
+ this.model = options.model;
421
+ this.maxTokens = options.maxTokens ?? 512;
422
+ this.temperature = options.temperature ?? 0.7;
423
+ this.responseFormat = options.responseFormat;
424
+ }
425
+ /**
426
+ * Warm up the LLM by sending the system prompt and a short message.
427
+ * Primes the HTTP/TLS connection and model loading on the provider side.
428
+ */
429
+ async warmup(systemPrompt) {
430
+ log3.info("Warming up LLM connection...");
431
+ const start = performance.now();
432
+ const messages = [
433
+ { role: "system", content: systemPrompt },
434
+ { role: "user", content: "Hello" }
435
+ ];
436
+ try {
437
+ const gen = this.chat(messages);
438
+ for await (const chunk of gen) {
439
+ if (chunk.type === "done") break;
440
+ }
441
+ log3.info(`LLM warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
442
+ } catch (err) {
443
+ log3.warn("LLM warmup failed (non-fatal):", err);
444
+ }
445
+ }
446
+ async *chat(messages, signal, options) {
447
+ const body = {
448
+ model: this.model,
449
+ messages,
450
+ max_tokens: this.maxTokens,
451
+ temperature: this.temperature,
452
+ stream: true,
453
+ stream_options: { include_usage: true }
454
+ };
455
+ if (this.responseFormat && !options?.plainText) {
456
+ body.response_format = this.responseFormat;
457
+ }
458
+ log3.debug(`LLM request: model=${this.model}, messages=${messages.length}`);
459
+ const response = await fetch(OPENAI_URL, {
460
+ method: "POST",
461
+ headers: {
462
+ "Content-Type": "application/json",
463
+ "Authorization": `Bearer ${this.apiKey}`
464
+ },
465
+ body: JSON.stringify(body),
466
+ signal
467
+ });
468
+ if (!response.ok) {
469
+ const errorText = await response.text();
470
+ throw new Error(`OpenAI API error ${response.status}: ${errorText}`);
471
+ }
472
+ if (!response.body) {
473
+ throw new Error("OpenAI response has no body");
474
+ }
475
+ const reader = response.body.getReader();
476
+ const decoder = new TextDecoder();
477
+ let buffer = "";
478
+ const structured = !!this.responseFormat && !options?.plainText;
479
+ let jsonBuffer = "";
480
+ let segmentsYielded = false;
481
+ let lastUsage;
482
+ let inSegmentsArray = false;
483
+ let objectStart = -1;
484
+ let braceDepth = 0;
485
+ let scanIndex = 0;
486
+ let inString = false;
487
+ let escaped = false;
488
+ function extractSegments(buf) {
489
+ const results = [];
490
+ for (let i = scanIndex; i < buf.length; i++) {
491
+ const ch = buf[i];
492
+ if (escaped) {
493
+ escaped = false;
494
+ continue;
495
+ }
496
+ if (ch === "\\" && inString) {
497
+ escaped = true;
498
+ continue;
499
+ }
500
+ if (ch === '"') {
501
+ inString = !inString;
502
+ continue;
503
+ }
504
+ if (inString) continue;
505
+ if (!inSegmentsArray) {
506
+ if (ch === "[") {
507
+ const before = buf.slice(0, i).trimEnd();
508
+ if (before.endsWith(":") && buf.slice(0, i).includes('"segments"')) {
509
+ inSegmentsArray = true;
510
+ }
511
+ }
512
+ continue;
513
+ }
514
+ if (ch === "{") {
515
+ if (braceDepth === 0) objectStart = i;
516
+ braceDepth++;
517
+ } else if (ch === "}") {
518
+ braceDepth--;
519
+ if (braceDepth === 0 && objectStart >= 0) {
520
+ const objStr = buf.slice(objectStart, i + 1);
521
+ try {
522
+ const seg = JSON.parse(objStr);
523
+ if (seg.lang && seg.text) {
524
+ results.push({ lang: seg.lang, text: seg.text });
525
+ }
526
+ } catch {
527
+ }
528
+ objectStart = -1;
529
+ }
530
+ } else if (ch === "]" && braceDepth === 0) {
531
+ inSegmentsArray = false;
532
+ }
533
+ }
534
+ scanIndex = buf.length;
535
+ return results;
536
+ }
537
+ try {
538
+ while (true) {
539
+ if (signal?.aborted) break;
540
+ const { done, value } = await reader.read();
541
+ if (done) break;
542
+ buffer += decoder.decode(value, { stream: true });
543
+ const lines = buffer.split("\n");
544
+ buffer = lines.pop() ?? "";
545
+ for (const line of lines) {
546
+ const trimmed = line.trim();
547
+ if (!trimmed || !trimmed.startsWith("data: ")) continue;
548
+ const data = trimmed.slice(6);
549
+ if (data === "[DONE]") break;
550
+ try {
551
+ const parsed = JSON.parse(data);
552
+ const choice = parsed.choices?.[0];
553
+ if (!choice) {
554
+ if (parsed.usage) {
555
+ lastUsage = {
556
+ promptTokens: parsed.usage.prompt_tokens,
557
+ completionTokens: parsed.usage.completion_tokens
558
+ };
559
+ }
560
+ continue;
561
+ }
562
+ const delta = choice.delta;
563
+ if (delta?.content) {
564
+ if (structured) {
565
+ jsonBuffer += delta.content;
566
+ const segments = extractSegments(jsonBuffer);
567
+ for (const seg of segments) {
568
+ yield { type: "segment", segment: seg };
569
+ segmentsYielded = true;
570
+ }
571
+ } else {
572
+ yield { type: "token", token: delta.content };
573
+ }
574
+ }
575
+ if (parsed.usage) {
576
+ lastUsage = {
577
+ promptTokens: parsed.usage.prompt_tokens,
578
+ completionTokens: parsed.usage.completion_tokens
579
+ };
580
+ }
581
+ } catch {
582
+ }
583
+ }
584
+ }
585
+ } finally {
586
+ reader.releaseLock();
587
+ }
588
+ if (structured && !segmentsYielded && jsonBuffer.length > 0) {
589
+ log3.warn(`LLM returned no segments. Raw JSON: "${jsonBuffer.slice(0, 300)}"`);
590
+ }
591
+ yield { type: "done", ...lastUsage ? { usage: lastUsage } : {} };
592
+ }
593
+ };
594
+
406
595
  // src/providers/cartesia-tts.ts
407
596
  import WebSocket2 from "ws";
408
- var log3 = createLogger("CartesiaTTS");
597
+ var log4 = createLogger("CartesiaTTS");
409
598
  var CARTESIA_WS_BASE = "wss://api.cartesia.ai/tts/websocket";
410
599
  var DEFAULT_API_VERSION = "2024-06-10";
411
600
  var DEFAULT_MODEL = "sonic-3";
@@ -444,7 +633,7 @@ var CartesiaTTS = class {
444
633
  /** Close the WebSocket connection to allow clean process exit. */
445
634
  close() {
446
635
  if (this.ws) {
447
- log3.debug("Closing Cartesia WebSocket");
636
+ log4.debug("Closing Cartesia WebSocket");
448
637
  this.ws.close();
449
638
  this.ws = null;
450
639
  }
@@ -453,17 +642,17 @@ var CartesiaTTS = class {
453
642
  }
454
643
  /** Pre-connect the WebSocket so first synthesize() doesn't pay connection cost. */
455
644
  async warmup() {
456
- log3.info("Warming up TTS connection...");
645
+ log4.info("Warming up TTS connection...");
457
646
  const start = performance.now();
458
647
  try {
459
648
  await this.ensureConnection();
460
- log3.info(`TTS warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
649
+ log4.info(`TTS warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
461
650
  } catch (err) {
462
- log3.warn("TTS warmup failed (non-fatal):", err);
651
+ log4.warn("TTS warmup failed (non-fatal):", err);
463
652
  }
464
653
  }
465
654
  async *synthesize(text, signal) {
466
- log3.debug(`Synthesizing: "${text.slice(0, 60)}"`);
655
+ log4.debug(`Synthesizing: "${text.slice(0, 60)}"`);
467
656
  await this.ensureConnection();
468
657
  if (!this.ws || this.ws.readyState !== WebSocket2.OPEN) {
469
658
  throw new Error("Cartesia WebSocket not connected");
@@ -534,12 +723,12 @@ var CartesiaTTS = class {
534
723
  if (this.connectPromise) return this.connectPromise;
535
724
  this.connectPromise = new Promise((resolve, reject) => {
536
725
  const url = `${CARTESIA_WS_BASE}?api_key=${this.apiKey}&cartesia_version=${this.apiVersion}`;
537
- log3.debug("Connecting to Cartesia...");
726
+ log4.debug("Connecting to Cartesia...");
538
727
  this.ws = new WebSocket2(url);
539
728
  this.ws.on("open", () => {
540
729
  this._connected = true;
541
730
  this.connectPromise = null;
542
- log3.info("Cartesia WebSocket connected");
731
+ log4.info("Cartesia WebSocket connected");
543
732
  resolve();
544
733
  });
545
734
  this.ws.on("message", (data) => {
@@ -547,12 +736,12 @@ var CartesiaTTS = class {
547
736
  const msg = JSON.parse(data.toString());
548
737
  this.handleMessage(msg);
549
738
  } catch (err) {
550
- log3.error("Failed to parse Cartesia message:", err);
739
+ log4.error("Failed to parse Cartesia message:", err);
551
740
  }
552
741
  });
553
742
  this.ws.on("error", (err) => {
554
743
  const error = err instanceof Error ? err : new Error(String(err));
555
- log3.error("Cartesia WebSocket error:", error);
744
+ log4.error("Cartesia WebSocket error:", error);
556
745
  for (const ctx of this.contexts.values()) {
557
746
  ctx.error = error;
558
747
  ctx.wake?.();
@@ -562,7 +751,7 @@ var CartesiaTTS = class {
562
751
  reject(error);
563
752
  });
564
753
  this.ws.on("close", (code, reason) => {
565
- log3.debug(`Cartesia WebSocket closed: ${code} ${reason.toString()}`);
754
+ log4.debug(`Cartesia WebSocket closed: ${code} ${reason.toString()}`);
566
755
  this._connected = false;
567
756
  this.connectPromise = null;
568
757
  for (const ctx of this.contexts.values()) {
@@ -587,12 +776,12 @@ var CartesiaTTS = class {
587
776
  ctx.wake?.();
588
777
  }
589
778
  } else if (type === "done") {
590
- log3.debug(`Cartesia synthesis done for ${contextId} (${ctx.chunks.length} chunks pending)`);
779
+ log4.debug(`Cartesia synthesis done for ${contextId} (${ctx.chunks.length} chunks pending)`);
591
780
  ctx.done = true;
592
781
  ctx.wake?.();
593
782
  } else if (type === "error") {
594
783
  const errorMsg = msg.error ?? "Unknown Cartesia error";
595
- log3.error(`Cartesia error for ${contextId}: ${errorMsg}`);
784
+ log4.error(`Cartesia error for ${contextId}: ${errorMsg}`);
596
785
  ctx.error = new Error(`Cartesia TTS error: ${errorMsg}`);
597
786
  ctx.wake?.();
598
787
  }
@@ -601,7 +790,7 @@ var CartesiaTTS = class {
601
790
 
602
791
  // src/providers/deepgram-tts.ts
603
792
  import WebSocket3 from "ws";
604
- var log4 = createLogger("DeepgramTTS");
793
+ var log5 = createLogger("DeepgramTTS");
605
794
  var DEEPGRAM_WS_BASE = "wss://api.deepgram.com/v1/speak";
606
795
  var DEFAULT_SAMPLE_RATE2 = 48e3;
607
796
  function parseLangSegments(text, defaultLang) {
@@ -698,7 +887,7 @@ var DeepgramTTS = class {
698
887
  /** Close all WebSocket connections to allow clean process exit. */
699
888
  close() {
700
889
  for (const [lang, ws] of this.connections) {
701
- log4.debug(`Closing WebSocket for [${lang}]`);
890
+ log5.debug(`Closing WebSocket for [${lang}]`);
702
891
  ws.close();
703
892
  }
704
893
  this.connections.clear();
@@ -707,13 +896,13 @@ var DeepgramTTS = class {
707
896
  }
708
897
  /** Pre-connect all language WebSocket connections. */
709
898
  async warmup() {
710
- log4.info("Warming up TTS connections...");
899
+ log5.info("Warming up TTS connections...");
711
900
  const start = performance.now();
712
901
  try {
713
902
  await Promise.all(Object.keys(this.models).map((lang) => this.ensureConnection(lang)));
714
- log4.info(`TTS warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
903
+ log5.info(`TTS warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
715
904
  } catch (err) {
716
- log4.warn("TTS warmup failed (non-fatal):", err);
905
+ log5.warn("TTS warmup failed (non-fatal):", err);
717
906
  }
718
907
  }
719
908
  /** Strip SSML lang tags from text for display/events. */
@@ -746,7 +935,7 @@ var DeepgramTTS = class {
746
935
  }
747
936
  }
748
937
  async *synthesizeSegment(lang, text, signal) {
749
- log4.debug(`Synthesizing [${lang}]: "${text.slice(0, 60)}"`);
938
+ log5.debug(`Synthesizing [${lang}]: "${text.slice(0, 60)}"`);
750
939
  await this.ensureConnection(lang);
751
940
  const ws = this.connections.get(lang);
752
941
  if (!ws || ws.readyState !== WebSocket3.OPEN) {
@@ -804,7 +993,7 @@ var DeepgramTTS = class {
804
993
  }
805
994
  const promise = new Promise((resolve, reject) => {
806
995
  const url = `${DEEPGRAM_WS_BASE}?model=${encodeURIComponent(model)}&encoding=linear16&sample_rate=${this.sampleRate}`;
807
- log4.debug(`Connecting to Deepgram for [${lang}]: ${model}`);
996
+ log5.debug(`Connecting to Deepgram for [${lang}]: ${model}`);
808
997
  const ws = new WebSocket3(url, {
809
998
  headers: {
810
999
  Authorization: `Token ${this.apiKey}`
@@ -813,7 +1002,7 @@ var DeepgramTTS = class {
813
1002
  ws.on("open", () => {
814
1003
  this.connections.set(lang, ws);
815
1004
  this.connectPromises.delete(lang);
816
- log4.info(`Deepgram WebSocket connected for [${lang}] (${model})`);
1005
+ log5.info(`Deepgram WebSocket connected for [${lang}] (${model})`);
817
1006
  resolve();
818
1007
  });
819
1008
  ws.on("message", (data, isBinary) => {
@@ -830,16 +1019,16 @@ var DeepgramTTS = class {
830
1019
  state.flushed = true;
831
1020
  state.wake?.();
832
1021
  } else if (msg.type === "Warning" || msg.type === "Error") {
833
- log4.warn(`Deepgram [${lang}] ${msg.type}: ${msg.description || msg.message || JSON.stringify(msg)}`);
1022
+ log5.warn(`Deepgram [${lang}] ${msg.type}: ${msg.description || msg.message || JSON.stringify(msg)}`);
834
1023
  }
835
1024
  } catch {
836
- log4.warn(`Failed to parse Deepgram message for [${lang}]`);
1025
+ log5.warn(`Failed to parse Deepgram message for [${lang}]`);
837
1026
  }
838
1027
  }
839
1028
  });
840
1029
  ws.on("error", (err) => {
841
1030
  const error = err instanceof Error ? err : new Error(String(err));
842
- log4.error(`Deepgram WebSocket error [${lang}]:`, error);
1031
+ log5.error(`Deepgram WebSocket error [${lang}]:`, error);
843
1032
  const state = this.flushStates.get(lang);
844
1033
  if (state) {
845
1034
  state.error = error;
@@ -850,7 +1039,7 @@ var DeepgramTTS = class {
850
1039
  reject(error);
851
1040
  });
852
1041
  ws.on("close", (code, reason) => {
853
- log4.debug(`Deepgram WebSocket closed [${lang}]: ${code} ${reason.toString()}`);
1042
+ log5.debug(`Deepgram WebSocket closed [${lang}]: ${code} ${reason.toString()}`);
854
1043
  this.connections.delete(lang);
855
1044
  this.connectPromises.delete(lang);
856
1045
  const state = this.flushStates.get(lang);
@@ -867,7 +1056,7 @@ var DeepgramTTS = class {
867
1056
 
868
1057
  // src/providers/dtelecom-stt.ts
869
1058
  import WebSocket4 from "ws";
870
- var log5 = createLogger("DtelecomSTT");
1059
+ var log6 = createLogger("DtelecomSTT");
871
1060
  var KEEPALIVE_INTERVAL_MS2 = 5e3;
872
1061
  var DtelecomSTT = class {
873
1062
  options;
@@ -875,6 +1064,9 @@ var DtelecomSTT = class {
875
1064
  if (!options.serverUrl) {
876
1065
  throw new Error("DtelecomSTT requires a serverUrl");
877
1066
  }
1067
+ if (!options.sessionKey) {
1068
+ throw new Error("DtelecomSTT requires a sessionKey");
1069
+ }
878
1070
  this.options = options;
879
1071
  }
880
1072
  createStream(options) {
@@ -885,6 +1077,7 @@ var DtelecomSTT = class {
885
1077
  var DtelecomSTTStream = class extends BaseSTTStream {
886
1078
  ws = null;
887
1079
  serverUrl;
1080
+ sessionKey;
888
1081
  forceWhisper;
889
1082
  _ready = false;
890
1083
  _closed = false;
@@ -894,6 +1087,7 @@ var DtelecomSTTStream = class extends BaseSTTStream {
894
1087
  constructor(options, language) {
895
1088
  super();
896
1089
  this.serverUrl = options.serverUrl;
1090
+ this.sessionKey = options.sessionKey;
897
1091
  this.language = language;
898
1092
  this.forceWhisper = options.forceWhisper ?? false;
899
1093
  this.connect();
@@ -921,7 +1115,7 @@ var DtelecomSTTStream = class extends BaseSTTStream {
921
1115
  }
922
1116
  if (this.ws?.readyState === WebSocket4.OPEN) {
923
1117
  this.ws.send(JSON.stringify(config));
924
- log5.info(`Reconfiguring STT: language=${language}${options?.forceWhisper ? ", model=whisper" : ""}`);
1118
+ log6.info(`Reconfiguring STT: language=${language}${options?.forceWhisper ? ", model=whisper" : ""}`);
925
1119
  }
926
1120
  }
927
1121
  async close() {
@@ -934,14 +1128,20 @@ var DtelecomSTTStream = class extends BaseSTTStream {
934
1128
  this.ws.close();
935
1129
  this.ws = null;
936
1130
  }
937
- log5.debug("DtelecomSTT stream closed");
1131
+ log6.debug("DtelecomSTT stream closed");
938
1132
  }
939
1133
  connect() {
940
- log5.debug(`Connecting to dTelecom STT: ${this.serverUrl}`);
941
- this.ws = new WebSocket4(this.serverUrl);
1134
+ const url = this.serverUrl.replace(/\/$/, "") + "/v1/stream";
1135
+ const wsUrl = url.replace("https://", "wss://").replace("http://", "ws://");
1136
+ log6.debug(`Connecting to dTelecom STT: ${wsUrl}`);
1137
+ this.ws = new WebSocket4(wsUrl);
942
1138
  this.ws.on("open", () => {
943
- log5.info("dTelecom STT WebSocket connected");
944
- const config = { type: "config", language: this.language };
1139
+ log6.info("dTelecom STT WebSocket connected");
1140
+ const config = {
1141
+ type: "config",
1142
+ language: this.language,
1143
+ session_key: this.sessionKey
1144
+ };
945
1145
  if (this.forceWhisper) {
946
1146
  config.model = "whisper";
947
1147
  }
@@ -953,19 +1153,19 @@ var DtelecomSTTStream = class extends BaseSTTStream {
953
1153
  const msg = JSON.parse(data.toString());
954
1154
  this.handleMessage(msg);
955
1155
  } catch (err) {
956
- log5.error("Failed to parse dTelecom STT message:", err);
1156
+ log6.error("Failed to parse dTelecom STT message:", err);
957
1157
  }
958
1158
  });
959
1159
  this.ws.on("error", (err) => {
960
- log5.error("dTelecom STT WebSocket error:", err);
1160
+ log6.error("dTelecom STT WebSocket error:", err);
961
1161
  this.emit("error", err instanceof Error ? err : new Error(String(err)));
962
1162
  });
963
1163
  this.ws.on("close", (code, reason) => {
964
- log5.debug(`dTelecom STT WebSocket closed: ${code} ${reason.toString()}`);
1164
+ log6.debug(`dTelecom STT WebSocket closed: ${code} ${reason.toString()}`);
965
1165
  this._ready = false;
966
1166
  this.stopKeepAlive();
967
1167
  if (!this._closed) {
968
- log5.info("dTelecom STT connection lost, reconnecting in 1s...");
1168
+ log6.info("dTelecom STT connection lost, reconnecting in 1s...");
969
1169
  setTimeout(() => {
970
1170
  if (!this._closed) this.connect();
971
1171
  }, 1e3);
@@ -984,14 +1184,14 @@ var DtelecomSTTStream = class extends BaseSTTStream {
984
1184
  } else if (type === "error") {
985
1185
  const errData = msg.error;
986
1186
  const errorMsg = msg.message || (typeof errData === "string" ? errData : JSON.stringify(errData)) || "Unknown STT error";
987
- log5.error(`dTelecom STT error: ${errorMsg}`);
1187
+ log6.error(`dTelecom STT error: ${errorMsg}`);
988
1188
  this.emit("error", new Error(errorMsg));
989
1189
  }
990
1190
  }
991
1191
  handleReady(msg) {
992
1192
  const clientId = msg.client_id;
993
1193
  const lang = msg.language;
994
- log5.info(`dTelecom STT ready: client_id=${clientId}, language=${lang}`);
1194
+ log6.info(`dTelecom STT ready: client_id=${clientId}, language=${lang}`);
995
1195
  this._ready = true;
996
1196
  for (const buf of this.pendingAudio) {
997
1197
  if (this.ws?.readyState === WebSocket4.OPEN) {
@@ -1008,7 +1208,7 @@ var DtelecomSTTStream = class extends BaseSTTStream {
1008
1208
  const latencyMs = msg.latency_ms;
1009
1209
  if (!text) return;
1010
1210
  if (isFinal && latencyMs !== void 0) {
1011
- log5.info(`stt_final: ${latencyMs.toFixed(0)}ms "${text.slice(0, 50)}"`);
1211
+ log6.info(`stt_final: ${latencyMs.toFixed(0)}ms "${text.slice(0, 50)}"`);
1012
1212
  }
1013
1213
  this.emit("transcription", {
1014
1214
  text,
@@ -1019,7 +1219,7 @@ var DtelecomSTTStream = class extends BaseSTTStream {
1019
1219
  }
1020
1220
  handleVadEvent(msg) {
1021
1221
  const event = msg.event;
1022
- log5.debug(`VAD event: ${event}`);
1222
+ log6.debug(`VAD event: ${event}`);
1023
1223
  if (event === "speech_start") {
1024
1224
  this.emit("transcription", {
1025
1225
  text: "",
@@ -1045,9 +1245,10 @@ var DtelecomSTTStream = class extends BaseSTTStream {
1045
1245
 
1046
1246
  // src/providers/dtelecom-tts.ts
1047
1247
  import WebSocket5 from "ws";
1048
- var log6 = createLogger("DtelecomTTS");
1248
+ var log7 = createLogger("DtelecomTTS");
1049
1249
  var DtelecomTTS = class {
1050
1250
  serverUrl;
1251
+ sessionKey;
1051
1252
  voices;
1052
1253
  defaultLang;
1053
1254
  speed;
@@ -1062,29 +1263,33 @@ var DtelecomTTS = class {
1062
1263
  if (!options.serverUrl) {
1063
1264
  throw new Error("DtelecomTTS requires a serverUrl");
1064
1265
  }
1266
+ if (!options.sessionKey) {
1267
+ throw new Error("DtelecomTTS requires a sessionKey");
1268
+ }
1065
1269
  if (!options.voices || Object.keys(options.voices).length === 0) {
1066
1270
  throw new Error("DtelecomTTS requires at least one voice config");
1067
1271
  }
1068
1272
  this.serverUrl = options.serverUrl;
1273
+ this.sessionKey = options.sessionKey;
1069
1274
  this.voices = { ...options.voices };
1070
1275
  this.defaultLang = options.defaultLanguage ?? Object.keys(this.voices)[0];
1071
1276
  this.speed = options.speed ?? 1;
1072
1277
  }
1073
1278
  /** Pre-connect WebSocket to TTS server. */
1074
1279
  async warmup() {
1075
- log6.info("Warming up TTS connection...");
1280
+ log7.info("Warming up TTS connection...");
1076
1281
  const start = performance.now();
1077
1282
  try {
1078
1283
  await this.ensureConnection();
1079
- log6.info(`TTS warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
1284
+ log7.info(`TTS warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
1080
1285
  } catch (err) {
1081
- log6.warn("TTS warmup failed (non-fatal):", err);
1286
+ log7.warn("TTS warmup failed (non-fatal):", err);
1082
1287
  }
1083
1288
  }
1084
1289
  /** Close WebSocket connection. */
1085
1290
  close() {
1086
1291
  if (this.ws) {
1087
- log6.debug("Closing TTS WebSocket");
1292
+ log7.debug("Closing TTS WebSocket");
1088
1293
  this.ws.close();
1089
1294
  this.ws = null;
1090
1295
  }
@@ -1146,7 +1351,7 @@ var DtelecomTTS = class {
1146
1351
  msg.lang_code = voiceConfig.langCode;
1147
1352
  msg.speed = this.speed;
1148
1353
  }
1149
- log6.info(`TTS send [${lang}]: voice=${voiceConfig?.voice ?? "default"} lang_code=${voiceConfig?.langCode ?? "default"} "${text.slice(0, 60)}"`);
1354
+ log7.info(`TTS send [${lang}]: voice=${voiceConfig?.voice ?? "default"} lang_code=${voiceConfig?.langCode ?? "default"} "${text.slice(0, 60)}"`);
1150
1355
  ws.send(JSON.stringify(msg));
1151
1356
  try {
1152
1357
  while (true) {
@@ -1177,22 +1382,26 @@ var DtelecomTTS = class {
1177
1382
  }
1178
1383
  if (this.connectPromise) return this.connectPromise;
1179
1384
  this.connectPromise = new Promise((resolve, reject) => {
1180
- log6.debug(`Connecting to dTelecom TTS: ${this.serverUrl}`);
1181
- const ws = new WebSocket5(this.serverUrl);
1385
+ const url = this.serverUrl.replace(/\/$/, "") + "/v1/stream";
1386
+ const wsUrl = url.replace("https://", "wss://").replace("http://", "ws://");
1387
+ log7.debug(`Connecting to dTelecom TTS: ${wsUrl}`);
1388
+ const ws = new WebSocket5(wsUrl);
1182
1389
  ws.on("open", () => {
1183
1390
  this.ws = ws;
1184
1391
  this.connectPromise = null;
1185
1392
  const defaultVoice = this.voices[this.defaultLang];
1393
+ const msg = {
1394
+ session_key: this.sessionKey
1395
+ };
1186
1396
  if (defaultVoice) {
1187
- ws.send(JSON.stringify({
1188
- config: {
1189
- voice: defaultVoice.voice,
1190
- lang_code: defaultVoice.langCode,
1191
- speed: this.speed
1192
- }
1193
- }));
1397
+ msg.config = {
1398
+ voice: defaultVoice.voice,
1399
+ lang_code: defaultVoice.langCode,
1400
+ speed: this.speed
1401
+ };
1194
1402
  }
1195
- log6.info("dTelecom TTS WebSocket connected");
1403
+ ws.send(JSON.stringify(msg));
1404
+ log7.info("dTelecom TTS WebSocket connected");
1196
1405
  resolve();
1197
1406
  });
1198
1407
  ws.on("message", (data, isBinary) => {
@@ -1213,21 +1422,21 @@ var DtelecomTTS = class {
1213
1422
  state.done = true;
1214
1423
  state.wake?.();
1215
1424
  } else if (msg.type === "generating") {
1216
- log6.debug(`TTS generating: "${msg.text?.slice(0, 40)}"`);
1425
+ log7.debug(`TTS generating: "${msg.text?.slice(0, 40)}"`);
1217
1426
  } else if (msg.type === "error") {
1218
1427
  const errorMsg = msg.message || "Unknown TTS error";
1219
- log6.error(`dTelecom TTS error: ${errorMsg}`);
1428
+ log7.error(`dTelecom TTS error: ${errorMsg}`);
1220
1429
  state.error = new Error(errorMsg);
1221
1430
  state.wake?.();
1222
1431
  }
1223
1432
  } catch {
1224
- log6.warn("Failed to parse dTelecom TTS message");
1433
+ log7.warn("Failed to parse dTelecom TTS message");
1225
1434
  }
1226
1435
  }
1227
1436
  });
1228
1437
  ws.on("error", (err) => {
1229
1438
  const error = err instanceof Error ? err : new Error(String(err));
1230
- log6.error("dTelecom TTS WebSocket error:", error);
1439
+ log7.error("dTelecom TTS WebSocket error:", error);
1231
1440
  const state = this.flushState;
1232
1441
  if (state) {
1233
1442
  state.error = error;
@@ -1238,7 +1447,7 @@ var DtelecomTTS = class {
1238
1447
  reject(error);
1239
1448
  });
1240
1449
  ws.on("close", (code, reason) => {
1241
- log6.debug(`dTelecom TTS WebSocket closed: ${code} ${reason.toString()}`);
1450
+ log7.debug(`dTelecom TTS WebSocket closed: ${code} ${reason.toString()}`);
1242
1451
  this.ws = null;
1243
1452
  this.connectPromise = null;
1244
1453
  const state = this.flushState;
@@ -1257,6 +1466,7 @@ export {
1257
1466
  DeepgramTTS,
1258
1467
  DtelecomSTT,
1259
1468
  DtelecomTTS,
1469
+ OpenAILLM,
1260
1470
  OpenRouterLLM
1261
1471
  };
1262
1472
  //# sourceMappingURL=index.mjs.map