@dtelecom/agents-js 0.2.0 → 0.2.2
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.
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +90 -36
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +90 -36
- package/dist/index.mjs.map +1 -1
- package/dist/providers/index.d.mts +41 -1
- package/dist/providers/index.d.ts +41 -1
- package/dist/providers/index.js +242 -51
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/index.mjs +241 -51
- package/dist/providers/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -121,9 +121,9 @@ declare class Pipeline extends EventEmitter {
|
|
|
121
121
|
/** Queued turn while current one is still processing */
|
|
122
122
|
private pendingTurn;
|
|
123
123
|
constructor(options: PipelineOptions);
|
|
124
|
-
|
|
125
|
-
private
|
|
126
|
-
private
|
|
124
|
+
private readonly _warmupPromise;
|
|
125
|
+
private readonly _ttsWarmupPromise;
|
|
126
|
+
private readonly _llmWarmupPromise;
|
|
127
127
|
get processing(): boolean;
|
|
128
128
|
get running(): boolean;
|
|
129
129
|
get agentState(): AgentState;
|
package/dist/index.d.ts
CHANGED
|
@@ -121,9 +121,9 @@ declare class Pipeline extends EventEmitter {
|
|
|
121
121
|
/** Queued turn while current one is still processing */
|
|
122
122
|
private pendingTurn;
|
|
123
123
|
constructor(options: PipelineOptions);
|
|
124
|
-
|
|
125
|
-
private
|
|
126
|
-
private
|
|
124
|
+
private readonly _warmupPromise;
|
|
125
|
+
private readonly _ttsWarmupPromise;
|
|
126
|
+
private readonly _llmWarmupPromise;
|
|
127
127
|
get processing(): boolean;
|
|
128
128
|
get running(): boolean;
|
|
129
129
|
get agentState(): AgentState;
|
package/dist/index.js
CHANGED
|
@@ -1151,6 +1151,49 @@ var AUDIO_DRAIN_MS = 800;
|
|
|
1151
1151
|
function sleep2(ms) {
|
|
1152
1152
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1153
1153
|
}
|
|
1154
|
+
function prefetchTTS(tts, text, signal) {
|
|
1155
|
+
const buffer = [];
|
|
1156
|
+
let done = false;
|
|
1157
|
+
let error = null;
|
|
1158
|
+
let wake = null;
|
|
1159
|
+
const notify = () => {
|
|
1160
|
+
if (wake) {
|
|
1161
|
+
const w = wake;
|
|
1162
|
+
wake = null;
|
|
1163
|
+
w();
|
|
1164
|
+
}
|
|
1165
|
+
};
|
|
1166
|
+
void (async () => {
|
|
1167
|
+
try {
|
|
1168
|
+
const stream = tts.synthesize(text, signal);
|
|
1169
|
+
for await (const chunk of stream) {
|
|
1170
|
+
if (signal?.aborted) break;
|
|
1171
|
+
buffer.push(chunk);
|
|
1172
|
+
notify();
|
|
1173
|
+
}
|
|
1174
|
+
} catch (e) {
|
|
1175
|
+
if (!(e instanceof Error && e.name === "AbortError")) error = e;
|
|
1176
|
+
} finally {
|
|
1177
|
+
done = true;
|
|
1178
|
+
notify();
|
|
1179
|
+
}
|
|
1180
|
+
})();
|
|
1181
|
+
return async function* () {
|
|
1182
|
+
let index = 0;
|
|
1183
|
+
while (true) {
|
|
1184
|
+
if (signal?.aborted) return;
|
|
1185
|
+
if (error) throw error;
|
|
1186
|
+
if (index < buffer.length) {
|
|
1187
|
+
yield buffer[index++];
|
|
1188
|
+
continue;
|
|
1189
|
+
}
|
|
1190
|
+
if (done) return;
|
|
1191
|
+
await new Promise((r) => {
|
|
1192
|
+
wake = r;
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
};
|
|
1196
|
+
}
|
|
1154
1197
|
var Pipeline = class extends import_events.EventEmitter {
|
|
1155
1198
|
stt;
|
|
1156
1199
|
llm;
|
|
@@ -1203,28 +1246,18 @@ var Pipeline = class extends import_events.EventEmitter {
|
|
|
1203
1246
|
this.splitter.reset();
|
|
1204
1247
|
this.setAgentState("idle");
|
|
1205
1248
|
};
|
|
1206
|
-
this.
|
|
1249
|
+
this._ttsWarmupPromise = this.tts?.warmup ? this.tts.warmup().catch((err) => {
|
|
1250
|
+
log7.warn("TTS warmup failed (non-fatal):", err);
|
|
1251
|
+
}) : Promise.resolve();
|
|
1252
|
+
this._llmWarmupPromise = this.llm.warmup ? this.llm.warmup(options.instructions).catch((err) => {
|
|
1253
|
+
log7.warn("LLM warmup failed (non-fatal):", err);
|
|
1254
|
+
}) : Promise.resolve();
|
|
1255
|
+
this._warmupPromise = Promise.all([this._ttsWarmupPromise, this._llmWarmupPromise]).then(() => {
|
|
1256
|
+
});
|
|
1207
1257
|
}
|
|
1208
|
-
/** One-shot warmup — safe to call from constructor, resolves when both LLM and TTS are ready. */
|
|
1209
1258
|
_warmupPromise;
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
if (this.llm.warmup) {
|
|
1213
|
-
tasks.push(
|
|
1214
|
-
this.llm.warmup(instructions).catch((err) => {
|
|
1215
|
-
log7.warn("LLM warmup failed:", err);
|
|
1216
|
-
})
|
|
1217
|
-
);
|
|
1218
|
-
}
|
|
1219
|
-
if (this.tts?.warmup) {
|
|
1220
|
-
tasks.push(
|
|
1221
|
-
this.tts.warmup().catch((err) => {
|
|
1222
|
-
log7.warn("TTS warmup failed:", err);
|
|
1223
|
-
})
|
|
1224
|
-
);
|
|
1225
|
-
}
|
|
1226
|
-
await Promise.all(tasks);
|
|
1227
|
-
}
|
|
1259
|
+
_ttsWarmupPromise;
|
|
1260
|
+
_llmWarmupPromise;
|
|
1228
1261
|
get processing() {
|
|
1229
1262
|
return this._processing;
|
|
1230
1263
|
}
|
|
@@ -1451,29 +1484,50 @@ var Pipeline = class extends import_events.EventEmitter {
|
|
|
1451
1484
|
};
|
|
1452
1485
|
const consumer = async () => {
|
|
1453
1486
|
this.audioOutput.beginResponse();
|
|
1487
|
+
const state = { prefetched: null };
|
|
1454
1488
|
try {
|
|
1455
1489
|
while (true) {
|
|
1456
1490
|
if (signal.aborted) break;
|
|
1457
|
-
|
|
1458
|
-
|
|
1491
|
+
let sentence;
|
|
1492
|
+
let existingStream;
|
|
1493
|
+
if (state.prefetched) {
|
|
1494
|
+
sentence = state.prefetched.sentence;
|
|
1495
|
+
existingStream = state.prefetched.streamFn();
|
|
1496
|
+
state.prefetched = null;
|
|
1497
|
+
} else if (sentenceQueue.length > 0) {
|
|
1498
|
+
sentence = sentenceQueue.shift();
|
|
1459
1499
|
if (!/\w/.test(sentence)) {
|
|
1460
1500
|
log7.debug(`Skipping non-word sentence: "${sentence}"`);
|
|
1461
1501
|
continue;
|
|
1462
1502
|
}
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1503
|
+
existingStream = void 0;
|
|
1504
|
+
} else if (producerDone) {
|
|
1505
|
+
break;
|
|
1506
|
+
} else {
|
|
1507
|
+
await new Promise((resolve) => {
|
|
1508
|
+
wakeConsumer = resolve;
|
|
1469
1509
|
});
|
|
1510
|
+
wakeConsumer = null;
|
|
1470
1511
|
continue;
|
|
1471
1512
|
}
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1513
|
+
const tryPrefetch = () => {
|
|
1514
|
+
if (state.prefetched || !this.tts) return;
|
|
1515
|
+
if (sentenceQueue.length > 0) {
|
|
1516
|
+
const next = sentenceQueue.shift();
|
|
1517
|
+
if (/\w/.test(next)) {
|
|
1518
|
+
state.prefetched = { sentence: next, streamFn: prefetchTTS(this.tts, next, signal) };
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
};
|
|
1522
|
+
tryPrefetch();
|
|
1523
|
+
await this.synthesizeAndPlay(sentence, signal, (t) => {
|
|
1524
|
+
if (!tFirstAudioPlayed) {
|
|
1525
|
+
tFirstAudioPlayed = t;
|
|
1526
|
+
this.setAgentState("speaking");
|
|
1527
|
+
}
|
|
1528
|
+
this.emit("sentence", this.cleanText(sentence), sentence);
|
|
1529
|
+
tryPrefetch();
|
|
1530
|
+
}, existingStream);
|
|
1477
1531
|
}
|
|
1478
1532
|
} finally {
|
|
1479
1533
|
if (!signal.aborted) {
|
|
@@ -1526,7 +1580,7 @@ var Pipeline = class extends import_events.EventEmitter {
|
|
|
1526
1580
|
return;
|
|
1527
1581
|
}
|
|
1528
1582
|
this._processing = true;
|
|
1529
|
-
await this.
|
|
1583
|
+
await this._ttsWarmupPromise;
|
|
1530
1584
|
log7.info(`say(): "${text.slice(0, 60)}"`);
|
|
1531
1585
|
try {
|
|
1532
1586
|
const signal = this.bargeIn.startCycle();
|
|
@@ -1563,7 +1617,7 @@ var Pipeline = class extends import_events.EventEmitter {
|
|
|
1563
1617
|
}
|
|
1564
1618
|
}
|
|
1565
1619
|
}
|
|
1566
|
-
async synthesizeAndPlay(text, signal, onFirstAudio) {
|
|
1620
|
+
async synthesizeAndPlay(text, signal, onFirstAudio, existingStream) {
|
|
1567
1621
|
if (!this.tts || signal.aborted) {
|
|
1568
1622
|
log7.info(`[Agent says]: ${text}`);
|
|
1569
1623
|
return;
|
|
@@ -1572,7 +1626,7 @@ var Pipeline = class extends import_events.EventEmitter {
|
|
|
1572
1626
|
const ttsStart = performance.now();
|
|
1573
1627
|
let firstChunk = true;
|
|
1574
1628
|
let ttsChunkCount = 0;
|
|
1575
|
-
const ttsStream = this.tts.synthesize(text, signal);
|
|
1629
|
+
const ttsStream = existingStream ?? this.tts.synthesize(text, signal);
|
|
1576
1630
|
const measuredStream = async function* () {
|
|
1577
1631
|
for await (const chunk of ttsStream) {
|
|
1578
1632
|
ttsChunkCount++;
|