@dtelecom/agents-js 0.2.0 → 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.
@@ -94,6 +94,46 @@ declare class OpenRouterLLM implements LLMPlugin {
94
94
  chat(messages: Message[], signal?: AbortSignal, options?: LLMChatOptions): AsyncGenerator<LLMChunk>;
95
95
  }
96
96
 
97
+ /**
98
+ * OpenAILLM — streaming LLM via OpenAI API.
99
+ *
100
+ * Uses native fetch() with SSE parsing for streaming responses.
101
+ * No SDK dependency — just HTTP.
102
+ */
103
+
104
+ interface OpenAILLMOptions {
105
+ apiKey: string;
106
+ /** Model identifier (e.g. 'gpt-4o', 'gpt-4o-mini') */
107
+ model: string;
108
+ /** Max tokens in response (default: 512) */
109
+ maxTokens?: number;
110
+ /** Sampling temperature 0-2 (default: 0.7) */
111
+ temperature?: number;
112
+ /** Structured output via constrained decoding (e.g. for multi-language segment routing) */
113
+ responseFormat?: {
114
+ type: 'json_schema';
115
+ json_schema: {
116
+ name: string;
117
+ strict: boolean;
118
+ schema: Record<string, unknown>;
119
+ };
120
+ };
121
+ }
122
+ declare class OpenAILLM implements LLMPlugin {
123
+ private readonly apiKey;
124
+ private readonly model;
125
+ private readonly maxTokens;
126
+ private readonly temperature;
127
+ private readonly responseFormat?;
128
+ constructor(options: OpenAILLMOptions);
129
+ /**
130
+ * Warm up the LLM by sending the system prompt and a short message.
131
+ * Primes the HTTP/TLS connection and model loading on the provider side.
132
+ */
133
+ warmup(systemPrompt: string): Promise<void>;
134
+ chat(messages: Message[], signal?: AbortSignal, options?: LLMChatOptions): AsyncGenerator<LLMChunk>;
135
+ }
136
+
97
137
  /**
98
138
  * CartesiaTTS — real-time streaming TTS via Cartesia WebSocket API.
99
139
  *
@@ -288,4 +328,4 @@ declare class DtelecomTTS implements TTSPlugin {
288
328
  private ensureConnection;
289
329
  }
290
330
 
291
- export { CartesiaTTS, type CartesiaTTSOptions, DeepgramSTT, type DeepgramSTTOptions, DeepgramTTS, type DeepgramTTSOptions, DtelecomSTT, type DtelecomSTTOptions, DtelecomTTS, type DtelecomTTSOptions, type VoiceConfig as DtelecomVoiceConfig, OpenRouterLLM, type OpenRouterLLMOptions };
331
+ export { CartesiaTTS, type CartesiaTTSOptions, DeepgramSTT, type DeepgramSTTOptions, DeepgramTTS, type DeepgramTTSOptions, DtelecomSTT, type DtelecomSTTOptions, DtelecomTTS, type DtelecomTTSOptions, type VoiceConfig as DtelecomVoiceConfig, OpenAILLM, type OpenAILLMOptions, OpenRouterLLM, type OpenRouterLLMOptions };
@@ -94,6 +94,46 @@ declare class OpenRouterLLM implements LLMPlugin {
94
94
  chat(messages: Message[], signal?: AbortSignal, options?: LLMChatOptions): AsyncGenerator<LLMChunk>;
95
95
  }
96
96
 
97
+ /**
98
+ * OpenAILLM — streaming LLM via OpenAI API.
99
+ *
100
+ * Uses native fetch() with SSE parsing for streaming responses.
101
+ * No SDK dependency — just HTTP.
102
+ */
103
+
104
+ interface OpenAILLMOptions {
105
+ apiKey: string;
106
+ /** Model identifier (e.g. 'gpt-4o', 'gpt-4o-mini') */
107
+ model: string;
108
+ /** Max tokens in response (default: 512) */
109
+ maxTokens?: number;
110
+ /** Sampling temperature 0-2 (default: 0.7) */
111
+ temperature?: number;
112
+ /** Structured output via constrained decoding (e.g. for multi-language segment routing) */
113
+ responseFormat?: {
114
+ type: 'json_schema';
115
+ json_schema: {
116
+ name: string;
117
+ strict: boolean;
118
+ schema: Record<string, unknown>;
119
+ };
120
+ };
121
+ }
122
+ declare class OpenAILLM implements LLMPlugin {
123
+ private readonly apiKey;
124
+ private readonly model;
125
+ private readonly maxTokens;
126
+ private readonly temperature;
127
+ private readonly responseFormat?;
128
+ constructor(options: OpenAILLMOptions);
129
+ /**
130
+ * Warm up the LLM by sending the system prompt and a short message.
131
+ * Primes the HTTP/TLS connection and model loading on the provider side.
132
+ */
133
+ warmup(systemPrompt: string): Promise<void>;
134
+ chat(messages: Message[], signal?: AbortSignal, options?: LLMChatOptions): AsyncGenerator<LLMChunk>;
135
+ }
136
+
97
137
  /**
98
138
  * CartesiaTTS — real-time streaming TTS via Cartesia WebSocket API.
99
139
  *
@@ -288,4 +328,4 @@ declare class DtelecomTTS implements TTSPlugin {
288
328
  private ensureConnection;
289
329
  }
290
330
 
291
- export { CartesiaTTS, type CartesiaTTSOptions, DeepgramSTT, type DeepgramSTTOptions, DeepgramTTS, type DeepgramTTSOptions, DtelecomSTT, type DtelecomSTTOptions, DtelecomTTS, type DtelecomTTSOptions, type VoiceConfig as DtelecomVoiceConfig, OpenRouterLLM, type OpenRouterLLMOptions };
331
+ export { CartesiaTTS, type CartesiaTTSOptions, DeepgramSTT, type DeepgramSTTOptions, DeepgramTTS, type DeepgramTTSOptions, DtelecomSTT, type DtelecomSTTOptions, DtelecomTTS, type DtelecomTTSOptions, type VoiceConfig as DtelecomVoiceConfig, OpenAILLM, type OpenAILLMOptions, OpenRouterLLM, type OpenRouterLLMOptions };
@@ -35,6 +35,7 @@ __export(providers_exports, {
35
35
  DeepgramTTS: () => DeepgramTTS,
36
36
  DtelecomSTT: () => DtelecomSTT,
37
37
  DtelecomTTS: () => DtelecomTTS,
38
+ OpenAILLM: () => OpenAILLM,
38
39
  OpenRouterLLM: () => OpenRouterLLM
39
40
  });
40
41
  module.exports = __toCommonJS(providers_exports);
@@ -494,9 +495,198 @@ var OpenRouterLLM = class {
494
495
  }
495
496
  };
496
497
 
498
+ // src/providers/openai-llm.ts
499
+ var log3 = createLogger("OpenAILLM");
500
+ var OPENAI_URL = "https://api.openai.com/v1/chat/completions";
501
+ var OpenAILLM = class {
502
+ apiKey;
503
+ model;
504
+ maxTokens;
505
+ temperature;
506
+ responseFormat;
507
+ constructor(options) {
508
+ if (!options.apiKey) {
509
+ throw new Error("OpenAILLM requires an apiKey");
510
+ }
511
+ this.apiKey = options.apiKey;
512
+ this.model = options.model;
513
+ this.maxTokens = options.maxTokens ?? 512;
514
+ this.temperature = options.temperature ?? 0.7;
515
+ this.responseFormat = options.responseFormat;
516
+ }
517
+ /**
518
+ * Warm up the LLM by sending the system prompt and a short message.
519
+ * Primes the HTTP/TLS connection and model loading on the provider side.
520
+ */
521
+ async warmup(systemPrompt) {
522
+ log3.info("Warming up LLM connection...");
523
+ const start = performance.now();
524
+ const messages = [
525
+ { role: "system", content: systemPrompt },
526
+ { role: "user", content: "Hello" }
527
+ ];
528
+ try {
529
+ const gen = this.chat(messages);
530
+ for await (const chunk of gen) {
531
+ if (chunk.type === "done") break;
532
+ }
533
+ log3.info(`LLM warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
534
+ } catch (err) {
535
+ log3.warn("LLM warmup failed (non-fatal):", err);
536
+ }
537
+ }
538
+ async *chat(messages, signal, options) {
539
+ const body = {
540
+ model: this.model,
541
+ messages,
542
+ max_tokens: this.maxTokens,
543
+ temperature: this.temperature,
544
+ stream: true,
545
+ stream_options: { include_usage: true }
546
+ };
547
+ if (this.responseFormat && !options?.plainText) {
548
+ body.response_format = this.responseFormat;
549
+ }
550
+ log3.debug(`LLM request: model=${this.model}, messages=${messages.length}`);
551
+ const response = await fetch(OPENAI_URL, {
552
+ method: "POST",
553
+ headers: {
554
+ "Content-Type": "application/json",
555
+ "Authorization": `Bearer ${this.apiKey}`
556
+ },
557
+ body: JSON.stringify(body),
558
+ signal
559
+ });
560
+ if (!response.ok) {
561
+ const errorText = await response.text();
562
+ throw new Error(`OpenAI API error ${response.status}: ${errorText}`);
563
+ }
564
+ if (!response.body) {
565
+ throw new Error("OpenAI response has no body");
566
+ }
567
+ const reader = response.body.getReader();
568
+ const decoder = new TextDecoder();
569
+ let buffer = "";
570
+ const structured = !!this.responseFormat && !options?.plainText;
571
+ let jsonBuffer = "";
572
+ let segmentsYielded = false;
573
+ let lastUsage;
574
+ let inSegmentsArray = false;
575
+ let objectStart = -1;
576
+ let braceDepth = 0;
577
+ let scanIndex = 0;
578
+ let inString = false;
579
+ let escaped = false;
580
+ function extractSegments(buf) {
581
+ const results = [];
582
+ for (let i = scanIndex; i < buf.length; i++) {
583
+ const ch = buf[i];
584
+ if (escaped) {
585
+ escaped = false;
586
+ continue;
587
+ }
588
+ if (ch === "\\" && inString) {
589
+ escaped = true;
590
+ continue;
591
+ }
592
+ if (ch === '"') {
593
+ inString = !inString;
594
+ continue;
595
+ }
596
+ if (inString) continue;
597
+ if (!inSegmentsArray) {
598
+ if (ch === "[") {
599
+ const before = buf.slice(0, i).trimEnd();
600
+ if (before.endsWith(":") && buf.slice(0, i).includes('"segments"')) {
601
+ inSegmentsArray = true;
602
+ }
603
+ }
604
+ continue;
605
+ }
606
+ if (ch === "{") {
607
+ if (braceDepth === 0) objectStart = i;
608
+ braceDepth++;
609
+ } else if (ch === "}") {
610
+ braceDepth--;
611
+ if (braceDepth === 0 && objectStart >= 0) {
612
+ const objStr = buf.slice(objectStart, i + 1);
613
+ try {
614
+ const seg = JSON.parse(objStr);
615
+ if (seg.lang && seg.text) {
616
+ results.push({ lang: seg.lang, text: seg.text });
617
+ }
618
+ } catch {
619
+ }
620
+ objectStart = -1;
621
+ }
622
+ } else if (ch === "]" && braceDepth === 0) {
623
+ inSegmentsArray = false;
624
+ }
625
+ }
626
+ scanIndex = buf.length;
627
+ return results;
628
+ }
629
+ try {
630
+ while (true) {
631
+ if (signal?.aborted) break;
632
+ const { done, value } = await reader.read();
633
+ if (done) break;
634
+ buffer += decoder.decode(value, { stream: true });
635
+ const lines = buffer.split("\n");
636
+ buffer = lines.pop() ?? "";
637
+ for (const line of lines) {
638
+ const trimmed = line.trim();
639
+ if (!trimmed || !trimmed.startsWith("data: ")) continue;
640
+ const data = trimmed.slice(6);
641
+ if (data === "[DONE]") break;
642
+ try {
643
+ const parsed = JSON.parse(data);
644
+ const choice = parsed.choices?.[0];
645
+ if (!choice) {
646
+ if (parsed.usage) {
647
+ lastUsage = {
648
+ promptTokens: parsed.usage.prompt_tokens,
649
+ completionTokens: parsed.usage.completion_tokens
650
+ };
651
+ }
652
+ continue;
653
+ }
654
+ const delta = choice.delta;
655
+ if (delta?.content) {
656
+ if (structured) {
657
+ jsonBuffer += delta.content;
658
+ const segments = extractSegments(jsonBuffer);
659
+ for (const seg of segments) {
660
+ yield { type: "segment", segment: seg };
661
+ segmentsYielded = true;
662
+ }
663
+ } else {
664
+ yield { type: "token", token: delta.content };
665
+ }
666
+ }
667
+ if (parsed.usage) {
668
+ lastUsage = {
669
+ promptTokens: parsed.usage.prompt_tokens,
670
+ completionTokens: parsed.usage.completion_tokens
671
+ };
672
+ }
673
+ } catch {
674
+ }
675
+ }
676
+ }
677
+ } finally {
678
+ reader.releaseLock();
679
+ }
680
+ if (structured && !segmentsYielded && jsonBuffer.length > 0) {
681
+ log3.warn(`LLM returned no segments. Raw JSON: "${jsonBuffer.slice(0, 300)}"`);
682
+ }
683
+ yield { type: "done", ...lastUsage ? { usage: lastUsage } : {} };
684
+ }
685
+ };
686
+
497
687
  // src/providers/cartesia-tts.ts
498
688
  var import_ws2 = __toESM(require("ws"));
499
- var log3 = createLogger("CartesiaTTS");
689
+ var log4 = createLogger("CartesiaTTS");
500
690
  var CARTESIA_WS_BASE = "wss://api.cartesia.ai/tts/websocket";
501
691
  var DEFAULT_API_VERSION = "2024-06-10";
502
692
  var DEFAULT_MODEL = "sonic-3";
@@ -535,7 +725,7 @@ var CartesiaTTS = class {
535
725
  /** Close the WebSocket connection to allow clean process exit. */
536
726
  close() {
537
727
  if (this.ws) {
538
- log3.debug("Closing Cartesia WebSocket");
728
+ log4.debug("Closing Cartesia WebSocket");
539
729
  this.ws.close();
540
730
  this.ws = null;
541
731
  }
@@ -544,17 +734,17 @@ var CartesiaTTS = class {
544
734
  }
545
735
  /** Pre-connect the WebSocket so first synthesize() doesn't pay connection cost. */
546
736
  async warmup() {
547
- log3.info("Warming up TTS connection...");
737
+ log4.info("Warming up TTS connection...");
548
738
  const start = performance.now();
549
739
  try {
550
740
  await this.ensureConnection();
551
- log3.info(`TTS warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
741
+ log4.info(`TTS warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
552
742
  } catch (err) {
553
- log3.warn("TTS warmup failed (non-fatal):", err);
743
+ log4.warn("TTS warmup failed (non-fatal):", err);
554
744
  }
555
745
  }
556
746
  async *synthesize(text, signal) {
557
- log3.debug(`Synthesizing: "${text.slice(0, 60)}"`);
747
+ log4.debug(`Synthesizing: "${text.slice(0, 60)}"`);
558
748
  await this.ensureConnection();
559
749
  if (!this.ws || this.ws.readyState !== import_ws2.default.OPEN) {
560
750
  throw new Error("Cartesia WebSocket not connected");
@@ -625,12 +815,12 @@ var CartesiaTTS = class {
625
815
  if (this.connectPromise) return this.connectPromise;
626
816
  this.connectPromise = new Promise((resolve, reject) => {
627
817
  const url = `${CARTESIA_WS_BASE}?api_key=${this.apiKey}&cartesia_version=${this.apiVersion}`;
628
- log3.debug("Connecting to Cartesia...");
818
+ log4.debug("Connecting to Cartesia...");
629
819
  this.ws = new import_ws2.default(url);
630
820
  this.ws.on("open", () => {
631
821
  this._connected = true;
632
822
  this.connectPromise = null;
633
- log3.info("Cartesia WebSocket connected");
823
+ log4.info("Cartesia WebSocket connected");
634
824
  resolve();
635
825
  });
636
826
  this.ws.on("message", (data) => {
@@ -638,12 +828,12 @@ var CartesiaTTS = class {
638
828
  const msg = JSON.parse(data.toString());
639
829
  this.handleMessage(msg);
640
830
  } catch (err) {
641
- log3.error("Failed to parse Cartesia message:", err);
831
+ log4.error("Failed to parse Cartesia message:", err);
642
832
  }
643
833
  });
644
834
  this.ws.on("error", (err) => {
645
835
  const error = err instanceof Error ? err : new Error(String(err));
646
- log3.error("Cartesia WebSocket error:", error);
836
+ log4.error("Cartesia WebSocket error:", error);
647
837
  for (const ctx of this.contexts.values()) {
648
838
  ctx.error = error;
649
839
  ctx.wake?.();
@@ -653,7 +843,7 @@ var CartesiaTTS = class {
653
843
  reject(error);
654
844
  });
655
845
  this.ws.on("close", (code, reason) => {
656
- log3.debug(`Cartesia WebSocket closed: ${code} ${reason.toString()}`);
846
+ log4.debug(`Cartesia WebSocket closed: ${code} ${reason.toString()}`);
657
847
  this._connected = false;
658
848
  this.connectPromise = null;
659
849
  for (const ctx of this.contexts.values()) {
@@ -678,12 +868,12 @@ var CartesiaTTS = class {
678
868
  ctx.wake?.();
679
869
  }
680
870
  } else if (type === "done") {
681
- log3.debug(`Cartesia synthesis done for ${contextId} (${ctx.chunks.length} chunks pending)`);
871
+ log4.debug(`Cartesia synthesis done for ${contextId} (${ctx.chunks.length} chunks pending)`);
682
872
  ctx.done = true;
683
873
  ctx.wake?.();
684
874
  } else if (type === "error") {
685
875
  const errorMsg = msg.error ?? "Unknown Cartesia error";
686
- log3.error(`Cartesia error for ${contextId}: ${errorMsg}`);
876
+ log4.error(`Cartesia error for ${contextId}: ${errorMsg}`);
687
877
  ctx.error = new Error(`Cartesia TTS error: ${errorMsg}`);
688
878
  ctx.wake?.();
689
879
  }
@@ -692,7 +882,7 @@ var CartesiaTTS = class {
692
882
 
693
883
  // src/providers/deepgram-tts.ts
694
884
  var import_ws3 = __toESM(require("ws"));
695
- var log4 = createLogger("DeepgramTTS");
885
+ var log5 = createLogger("DeepgramTTS");
696
886
  var DEEPGRAM_WS_BASE = "wss://api.deepgram.com/v1/speak";
697
887
  var DEFAULT_SAMPLE_RATE2 = 48e3;
698
888
  function parseLangSegments(text, defaultLang) {
@@ -789,7 +979,7 @@ var DeepgramTTS = class {
789
979
  /** Close all WebSocket connections to allow clean process exit. */
790
980
  close() {
791
981
  for (const [lang, ws] of this.connections) {
792
- log4.debug(`Closing WebSocket for [${lang}]`);
982
+ log5.debug(`Closing WebSocket for [${lang}]`);
793
983
  ws.close();
794
984
  }
795
985
  this.connections.clear();
@@ -798,13 +988,13 @@ var DeepgramTTS = class {
798
988
  }
799
989
  /** Pre-connect all language WebSocket connections. */
800
990
  async warmup() {
801
- log4.info("Warming up TTS connections...");
991
+ log5.info("Warming up TTS connections...");
802
992
  const start = performance.now();
803
993
  try {
804
994
  await Promise.all(Object.keys(this.models).map((lang) => this.ensureConnection(lang)));
805
- log4.info(`TTS warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
995
+ log5.info(`TTS warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
806
996
  } catch (err) {
807
- log4.warn("TTS warmup failed (non-fatal):", err);
997
+ log5.warn("TTS warmup failed (non-fatal):", err);
808
998
  }
809
999
  }
810
1000
  /** Strip SSML lang tags from text for display/events. */
@@ -837,7 +1027,7 @@ var DeepgramTTS = class {
837
1027
  }
838
1028
  }
839
1029
  async *synthesizeSegment(lang, text, signal) {
840
- log4.debug(`Synthesizing [${lang}]: "${text.slice(0, 60)}"`);
1030
+ log5.debug(`Synthesizing [${lang}]: "${text.slice(0, 60)}"`);
841
1031
  await this.ensureConnection(lang);
842
1032
  const ws = this.connections.get(lang);
843
1033
  if (!ws || ws.readyState !== import_ws3.default.OPEN) {
@@ -895,7 +1085,7 @@ var DeepgramTTS = class {
895
1085
  }
896
1086
  const promise = new Promise((resolve, reject) => {
897
1087
  const url = `${DEEPGRAM_WS_BASE}?model=${encodeURIComponent(model)}&encoding=linear16&sample_rate=${this.sampleRate}`;
898
- log4.debug(`Connecting to Deepgram for [${lang}]: ${model}`);
1088
+ log5.debug(`Connecting to Deepgram for [${lang}]: ${model}`);
899
1089
  const ws = new import_ws3.default(url, {
900
1090
  headers: {
901
1091
  Authorization: `Token ${this.apiKey}`
@@ -904,7 +1094,7 @@ var DeepgramTTS = class {
904
1094
  ws.on("open", () => {
905
1095
  this.connections.set(lang, ws);
906
1096
  this.connectPromises.delete(lang);
907
- log4.info(`Deepgram WebSocket connected for [${lang}] (${model})`);
1097
+ log5.info(`Deepgram WebSocket connected for [${lang}] (${model})`);
908
1098
  resolve();
909
1099
  });
910
1100
  ws.on("message", (data, isBinary) => {
@@ -921,16 +1111,16 @@ var DeepgramTTS = class {
921
1111
  state.flushed = true;
922
1112
  state.wake?.();
923
1113
  } else if (msg.type === "Warning" || msg.type === "Error") {
924
- log4.warn(`Deepgram [${lang}] ${msg.type}: ${msg.description || msg.message || JSON.stringify(msg)}`);
1114
+ log5.warn(`Deepgram [${lang}] ${msg.type}: ${msg.description || msg.message || JSON.stringify(msg)}`);
925
1115
  }
926
1116
  } catch {
927
- log4.warn(`Failed to parse Deepgram message for [${lang}]`);
1117
+ log5.warn(`Failed to parse Deepgram message for [${lang}]`);
928
1118
  }
929
1119
  }
930
1120
  });
931
1121
  ws.on("error", (err) => {
932
1122
  const error = err instanceof Error ? err : new Error(String(err));
933
- log4.error(`Deepgram WebSocket error [${lang}]:`, error);
1123
+ log5.error(`Deepgram WebSocket error [${lang}]:`, error);
934
1124
  const state = this.flushStates.get(lang);
935
1125
  if (state) {
936
1126
  state.error = error;
@@ -941,7 +1131,7 @@ var DeepgramTTS = class {
941
1131
  reject(error);
942
1132
  });
943
1133
  ws.on("close", (code, reason) => {
944
- log4.debug(`Deepgram WebSocket closed [${lang}]: ${code} ${reason.toString()}`);
1134
+ log5.debug(`Deepgram WebSocket closed [${lang}]: ${code} ${reason.toString()}`);
945
1135
  this.connections.delete(lang);
946
1136
  this.connectPromises.delete(lang);
947
1137
  const state = this.flushStates.get(lang);
@@ -958,7 +1148,7 @@ var DeepgramTTS = class {
958
1148
 
959
1149
  // src/providers/dtelecom-stt.ts
960
1150
  var import_ws4 = __toESM(require("ws"));
961
- var log5 = createLogger("DtelecomSTT");
1151
+ var log6 = createLogger("DtelecomSTT");
962
1152
  var KEEPALIVE_INTERVAL_MS2 = 5e3;
963
1153
  var DtelecomSTT = class {
964
1154
  options;
@@ -1017,7 +1207,7 @@ var DtelecomSTTStream = class extends BaseSTTStream {
1017
1207
  }
1018
1208
  if (this.ws?.readyState === import_ws4.default.OPEN) {
1019
1209
  this.ws.send(JSON.stringify(config));
1020
- log5.info(`Reconfiguring STT: language=${language}${options?.forceWhisper ? ", model=whisper" : ""}`);
1210
+ log6.info(`Reconfiguring STT: language=${language}${options?.forceWhisper ? ", model=whisper" : ""}`);
1021
1211
  }
1022
1212
  }
1023
1213
  async close() {
@@ -1030,15 +1220,15 @@ var DtelecomSTTStream = class extends BaseSTTStream {
1030
1220
  this.ws.close();
1031
1221
  this.ws = null;
1032
1222
  }
1033
- log5.debug("DtelecomSTT stream closed");
1223
+ log6.debug("DtelecomSTT stream closed");
1034
1224
  }
1035
1225
  connect() {
1036
1226
  const url = this.serverUrl.replace(/\/$/, "") + "/v1/stream";
1037
1227
  const wsUrl = url.replace("https://", "wss://").replace("http://", "ws://");
1038
- log5.debug(`Connecting to dTelecom STT: ${wsUrl}`);
1228
+ log6.debug(`Connecting to dTelecom STT: ${wsUrl}`);
1039
1229
  this.ws = new import_ws4.default(wsUrl);
1040
1230
  this.ws.on("open", () => {
1041
- log5.info("dTelecom STT WebSocket connected");
1231
+ log6.info("dTelecom STT WebSocket connected");
1042
1232
  const config = {
1043
1233
  type: "config",
1044
1234
  language: this.language,
@@ -1055,19 +1245,19 @@ var DtelecomSTTStream = class extends BaseSTTStream {
1055
1245
  const msg = JSON.parse(data.toString());
1056
1246
  this.handleMessage(msg);
1057
1247
  } catch (err) {
1058
- log5.error("Failed to parse dTelecom STT message:", err);
1248
+ log6.error("Failed to parse dTelecom STT message:", err);
1059
1249
  }
1060
1250
  });
1061
1251
  this.ws.on("error", (err) => {
1062
- log5.error("dTelecom STT WebSocket error:", err);
1252
+ log6.error("dTelecom STT WebSocket error:", err);
1063
1253
  this.emit("error", err instanceof Error ? err : new Error(String(err)));
1064
1254
  });
1065
1255
  this.ws.on("close", (code, reason) => {
1066
- log5.debug(`dTelecom STT WebSocket closed: ${code} ${reason.toString()}`);
1256
+ log6.debug(`dTelecom STT WebSocket closed: ${code} ${reason.toString()}`);
1067
1257
  this._ready = false;
1068
1258
  this.stopKeepAlive();
1069
1259
  if (!this._closed) {
1070
- log5.info("dTelecom STT connection lost, reconnecting in 1s...");
1260
+ log6.info("dTelecom STT connection lost, reconnecting in 1s...");
1071
1261
  setTimeout(() => {
1072
1262
  if (!this._closed) this.connect();
1073
1263
  }, 1e3);
@@ -1086,14 +1276,14 @@ var DtelecomSTTStream = class extends BaseSTTStream {
1086
1276
  } else if (type === "error") {
1087
1277
  const errData = msg.error;
1088
1278
  const errorMsg = msg.message || (typeof errData === "string" ? errData : JSON.stringify(errData)) || "Unknown STT error";
1089
- log5.error(`dTelecom STT error: ${errorMsg}`);
1279
+ log6.error(`dTelecom STT error: ${errorMsg}`);
1090
1280
  this.emit("error", new Error(errorMsg));
1091
1281
  }
1092
1282
  }
1093
1283
  handleReady(msg) {
1094
1284
  const clientId = msg.client_id;
1095
1285
  const lang = msg.language;
1096
- log5.info(`dTelecom STT ready: client_id=${clientId}, language=${lang}`);
1286
+ log6.info(`dTelecom STT ready: client_id=${clientId}, language=${lang}`);
1097
1287
  this._ready = true;
1098
1288
  for (const buf of this.pendingAudio) {
1099
1289
  if (this.ws?.readyState === import_ws4.default.OPEN) {
@@ -1110,7 +1300,7 @@ var DtelecomSTTStream = class extends BaseSTTStream {
1110
1300
  const latencyMs = msg.latency_ms;
1111
1301
  if (!text) return;
1112
1302
  if (isFinal && latencyMs !== void 0) {
1113
- log5.info(`stt_final: ${latencyMs.toFixed(0)}ms "${text.slice(0, 50)}"`);
1303
+ log6.info(`stt_final: ${latencyMs.toFixed(0)}ms "${text.slice(0, 50)}"`);
1114
1304
  }
1115
1305
  this.emit("transcription", {
1116
1306
  text,
@@ -1121,7 +1311,7 @@ var DtelecomSTTStream = class extends BaseSTTStream {
1121
1311
  }
1122
1312
  handleVadEvent(msg) {
1123
1313
  const event = msg.event;
1124
- log5.debug(`VAD event: ${event}`);
1314
+ log6.debug(`VAD event: ${event}`);
1125
1315
  if (event === "speech_start") {
1126
1316
  this.emit("transcription", {
1127
1317
  text: "",
@@ -1147,7 +1337,7 @@ var DtelecomSTTStream = class extends BaseSTTStream {
1147
1337
 
1148
1338
  // src/providers/dtelecom-tts.ts
1149
1339
  var import_ws5 = __toESM(require("ws"));
1150
- var log6 = createLogger("DtelecomTTS");
1340
+ var log7 = createLogger("DtelecomTTS");
1151
1341
  var DtelecomTTS = class {
1152
1342
  serverUrl;
1153
1343
  sessionKey;
@@ -1179,19 +1369,19 @@ var DtelecomTTS = class {
1179
1369
  }
1180
1370
  /** Pre-connect WebSocket to TTS server. */
1181
1371
  async warmup() {
1182
- log6.info("Warming up TTS connection...");
1372
+ log7.info("Warming up TTS connection...");
1183
1373
  const start = performance.now();
1184
1374
  try {
1185
1375
  await this.ensureConnection();
1186
- log6.info(`TTS warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
1376
+ log7.info(`TTS warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
1187
1377
  } catch (err) {
1188
- log6.warn("TTS warmup failed (non-fatal):", err);
1378
+ log7.warn("TTS warmup failed (non-fatal):", err);
1189
1379
  }
1190
1380
  }
1191
1381
  /** Close WebSocket connection. */
1192
1382
  close() {
1193
1383
  if (this.ws) {
1194
- log6.debug("Closing TTS WebSocket");
1384
+ log7.debug("Closing TTS WebSocket");
1195
1385
  this.ws.close();
1196
1386
  this.ws = null;
1197
1387
  }
@@ -1253,7 +1443,7 @@ var DtelecomTTS = class {
1253
1443
  msg.lang_code = voiceConfig.langCode;
1254
1444
  msg.speed = this.speed;
1255
1445
  }
1256
- log6.info(`TTS send [${lang}]: voice=${voiceConfig?.voice ?? "default"} lang_code=${voiceConfig?.langCode ?? "default"} "${text.slice(0, 60)}"`);
1446
+ log7.info(`TTS send [${lang}]: voice=${voiceConfig?.voice ?? "default"} lang_code=${voiceConfig?.langCode ?? "default"} "${text.slice(0, 60)}"`);
1257
1447
  ws.send(JSON.stringify(msg));
1258
1448
  try {
1259
1449
  while (true) {
@@ -1286,7 +1476,7 @@ var DtelecomTTS = class {
1286
1476
  this.connectPromise = new Promise((resolve, reject) => {
1287
1477
  const url = this.serverUrl.replace(/\/$/, "") + "/v1/stream";
1288
1478
  const wsUrl = url.replace("https://", "wss://").replace("http://", "ws://");
1289
- log6.debug(`Connecting to dTelecom TTS: ${wsUrl}`);
1479
+ log7.debug(`Connecting to dTelecom TTS: ${wsUrl}`);
1290
1480
  const ws = new import_ws5.default(wsUrl);
1291
1481
  ws.on("open", () => {
1292
1482
  this.ws = ws;
@@ -1303,7 +1493,7 @@ var DtelecomTTS = class {
1303
1493
  };
1304
1494
  }
1305
1495
  ws.send(JSON.stringify(msg));
1306
- log6.info("dTelecom TTS WebSocket connected");
1496
+ log7.info("dTelecom TTS WebSocket connected");
1307
1497
  resolve();
1308
1498
  });
1309
1499
  ws.on("message", (data, isBinary) => {
@@ -1324,21 +1514,21 @@ var DtelecomTTS = class {
1324
1514
  state.done = true;
1325
1515
  state.wake?.();
1326
1516
  } else if (msg.type === "generating") {
1327
- log6.debug(`TTS generating: "${msg.text?.slice(0, 40)}"`);
1517
+ log7.debug(`TTS generating: "${msg.text?.slice(0, 40)}"`);
1328
1518
  } else if (msg.type === "error") {
1329
1519
  const errorMsg = msg.message || "Unknown TTS error";
1330
- log6.error(`dTelecom TTS error: ${errorMsg}`);
1520
+ log7.error(`dTelecom TTS error: ${errorMsg}`);
1331
1521
  state.error = new Error(errorMsg);
1332
1522
  state.wake?.();
1333
1523
  }
1334
1524
  } catch {
1335
- log6.warn("Failed to parse dTelecom TTS message");
1525
+ log7.warn("Failed to parse dTelecom TTS message");
1336
1526
  }
1337
1527
  }
1338
1528
  });
1339
1529
  ws.on("error", (err) => {
1340
1530
  const error = err instanceof Error ? err : new Error(String(err));
1341
- log6.error("dTelecom TTS WebSocket error:", error);
1531
+ log7.error("dTelecom TTS WebSocket error:", error);
1342
1532
  const state = this.flushState;
1343
1533
  if (state) {
1344
1534
  state.error = error;
@@ -1349,7 +1539,7 @@ var DtelecomTTS = class {
1349
1539
  reject(error);
1350
1540
  });
1351
1541
  ws.on("close", (code, reason) => {
1352
- log6.debug(`dTelecom TTS WebSocket closed: ${code} ${reason.toString()}`);
1542
+ log7.debug(`dTelecom TTS WebSocket closed: ${code} ${reason.toString()}`);
1353
1543
  this.ws = null;
1354
1544
  this.connectPromise = null;
1355
1545
  const state = this.flushState;
@@ -1369,6 +1559,7 @@ var DtelecomTTS = class {
1369
1559
  DeepgramTTS,
1370
1560
  DtelecomSTT,
1371
1561
  DtelecomTTS,
1562
+ OpenAILLM,
1372
1563
  OpenRouterLLM
1373
1564
  });
1374
1565
  //# sourceMappingURL=index.js.map