@teamlearners/clawops 0.5.3 → 0.5.4
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/agent/index.cjs +178 -69
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +46 -1
- package/dist/agent/index.d.ts +46 -1
- package/dist/agent/index.js +174 -70
- package/dist/agent/index.js.map +1 -1
- package/package.json +12 -11
package/dist/agent/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_BASE_URL, AgentError, AgentConnectionError } from '../chunk-7S2OEBS6.js';
|
|
2
|
+
import pino from 'pino';
|
|
2
3
|
import * as fs from 'fs';
|
|
3
4
|
import * as path from 'path';
|
|
4
5
|
|
|
@@ -322,6 +323,14 @@ function resamplePcm16(pcm, fromRate, toRate) {
|
|
|
322
323
|
}
|
|
323
324
|
return out;
|
|
324
325
|
}
|
|
326
|
+
var DEFAULT_LOGGER = pino({ name: "clawops.agent" });
|
|
327
|
+
var NOOP_LOGGER = pino({ level: "silent" });
|
|
328
|
+
function createAgentLogger(userLogger) {
|
|
329
|
+
return userLogger ?? DEFAULT_LOGGER;
|
|
330
|
+
}
|
|
331
|
+
function createPipelineLogger(parent) {
|
|
332
|
+
return parent.child({ module: "pipeline" });
|
|
333
|
+
}
|
|
325
334
|
|
|
326
335
|
// src/agent/control-ws.ts
|
|
327
336
|
var INITIAL_RECONNECT_DELAY = 1e3;
|
|
@@ -350,6 +359,10 @@ var ControlWebSocket = class {
|
|
|
350
359
|
_closed = false;
|
|
351
360
|
_connectedResolve = null;
|
|
352
361
|
_connectedPromise;
|
|
362
|
+
_log = NOOP_LOGGER;
|
|
363
|
+
setLogger(logger) {
|
|
364
|
+
this._log = logger;
|
|
365
|
+
}
|
|
353
366
|
/** Register an event handler for a specific event type. */
|
|
354
367
|
on(event, handler) {
|
|
355
368
|
let list = this._handlers.get(event);
|
|
@@ -397,13 +410,14 @@ var ControlWebSocket = class {
|
|
|
397
410
|
this._connectedResolve();
|
|
398
411
|
this._connectedResolve = null;
|
|
399
412
|
}
|
|
413
|
+
this._log.info("Control WS connected: %s", this._url);
|
|
400
414
|
});
|
|
401
415
|
ws.on("message", (data) => {
|
|
402
416
|
try {
|
|
403
417
|
const msg = JSON.parse(data.toString());
|
|
404
418
|
this._dispatchEvent(msg);
|
|
405
419
|
} catch {
|
|
406
|
-
|
|
420
|
+
this._log.warn("Control WS parse error");
|
|
407
421
|
}
|
|
408
422
|
});
|
|
409
423
|
ws.on("close", () => {
|
|
@@ -412,7 +426,7 @@ var ControlWebSocket = class {
|
|
|
412
426
|
}
|
|
413
427
|
});
|
|
414
428
|
ws.on("error", (err) => {
|
|
415
|
-
|
|
429
|
+
this._log.warn("Control WS error: %s", err.message);
|
|
416
430
|
});
|
|
417
431
|
}
|
|
418
432
|
_dispatchEvent(event) {
|
|
@@ -423,11 +437,11 @@ var ControlWebSocket = class {
|
|
|
423
437
|
const result = handler(event);
|
|
424
438
|
if (result && typeof result.catch === "function") {
|
|
425
439
|
result.catch((err) => {
|
|
426
|
-
|
|
440
|
+
this._log.error({ err }, "Control WS handler error: %s", event.event);
|
|
427
441
|
});
|
|
428
442
|
}
|
|
429
443
|
} catch (err) {
|
|
430
|
-
|
|
444
|
+
this._log.error({ err }, "Control WS handler error: %s", event.event);
|
|
431
445
|
}
|
|
432
446
|
}
|
|
433
447
|
}
|
|
@@ -435,10 +449,11 @@ var ControlWebSocket = class {
|
|
|
435
449
|
_scheduleReconnect() {
|
|
436
450
|
const delay = this._reconnectDelay;
|
|
437
451
|
this._reconnectDelay = Math.min(this._reconnectDelay * 2, MAX_RECONNECT_DELAY);
|
|
452
|
+
this._log.info("Control WS reconnecting in %ds...", delay / 1e3);
|
|
438
453
|
setTimeout(() => {
|
|
439
454
|
if (!this._closed) {
|
|
440
455
|
this._doConnect().catch((err) => {
|
|
441
|
-
|
|
456
|
+
this._log.warn({ err }, "Control WS reconnect failed");
|
|
442
457
|
this._scheduleReconnect();
|
|
443
458
|
});
|
|
444
459
|
}
|
|
@@ -450,6 +465,10 @@ var ControlWebSocket = class {
|
|
|
450
465
|
var MCPClient = class {
|
|
451
466
|
_servers = /* @__PURE__ */ new Map();
|
|
452
467
|
_clients = /* @__PURE__ */ new Map();
|
|
468
|
+
_log = NOOP_LOGGER;
|
|
469
|
+
setLogger(logger) {
|
|
470
|
+
this._log = logger;
|
|
471
|
+
}
|
|
453
472
|
/** Add an MCP server configuration. */
|
|
454
473
|
addServer(name, config) {
|
|
455
474
|
this._servers.set(name, config);
|
|
@@ -462,7 +481,7 @@ var MCPClient = class {
|
|
|
462
481
|
const tools = await this._connectServer(name, config);
|
|
463
482
|
allTools.push(...tools);
|
|
464
483
|
} catch (err) {
|
|
465
|
-
|
|
484
|
+
this._log.error({ err }, "MCP connection failed: %s", name);
|
|
466
485
|
}
|
|
467
486
|
}
|
|
468
487
|
return allTools;
|
|
@@ -471,12 +490,13 @@ var MCPClient = class {
|
|
|
471
490
|
async disconnect() {
|
|
472
491
|
for (const [name, client] of this._clients) {
|
|
473
492
|
try {
|
|
493
|
+
this._log.debug("MCP closing: %s", name);
|
|
474
494
|
const c = client;
|
|
475
495
|
if (c.close) {
|
|
476
496
|
await c.close();
|
|
477
497
|
}
|
|
478
498
|
} catch (err) {
|
|
479
|
-
|
|
499
|
+
this._log.error({ err }, "MCP disconnect error: %s", name);
|
|
480
500
|
}
|
|
481
501
|
}
|
|
482
502
|
this._clients.clear();
|
|
@@ -485,6 +505,11 @@ var MCPClient = class {
|
|
|
485
505
|
const sdk = await import('@modelcontextprotocol/sdk/client/index.js');
|
|
486
506
|
const { Client } = sdk;
|
|
487
507
|
const client = new Client({ name: `clawops-${name}`, version: "1.0.0" });
|
|
508
|
+
if (config.type === "stdio") {
|
|
509
|
+
this._log.debug("MCP connecting (stdio): %s", config["command"]);
|
|
510
|
+
} else if (config.type === "http") {
|
|
511
|
+
this._log.debug("MCP connecting (http): %s", config["url"]);
|
|
512
|
+
}
|
|
488
513
|
let transport;
|
|
489
514
|
if (config.type === "stdio") {
|
|
490
515
|
const { StdioClientTransport } = await import('@modelcontextprotocol/sdk/client/stdio.js');
|
|
@@ -513,6 +538,7 @@ var MCPClient = class {
|
|
|
513
538
|
parameters: inputSchema.properties ?? {},
|
|
514
539
|
required: inputSchema.required ?? [],
|
|
515
540
|
handler: async (args) => {
|
|
541
|
+
this._log.debug("MCP call_tool: %s", toolDef.name);
|
|
516
542
|
const result = await client.callTool({
|
|
517
543
|
name: toolDef.name,
|
|
518
544
|
arguments: args
|
|
@@ -525,6 +551,8 @@ var MCPClient = class {
|
|
|
525
551
|
}
|
|
526
552
|
});
|
|
527
553
|
}
|
|
554
|
+
this._log.info("MCP server connected: %d tools found", tools.length);
|
|
555
|
+
this._log.debug("MCP tools: %s", tools.map((t) => t.name));
|
|
528
556
|
return tools;
|
|
529
557
|
}
|
|
530
558
|
};
|
|
@@ -579,6 +607,10 @@ var MediaWebSocket = class {
|
|
|
579
607
|
_onClose = null;
|
|
580
608
|
_onDtmf = null;
|
|
581
609
|
_markWaiters = /* @__PURE__ */ new Map();
|
|
610
|
+
_log = NOOP_LOGGER;
|
|
611
|
+
setLogger(logger) {
|
|
612
|
+
this._log = logger;
|
|
613
|
+
}
|
|
582
614
|
/** Set the handler for inbound audio data. */
|
|
583
615
|
onAudio(handler) {
|
|
584
616
|
this._onAudio = handler;
|
|
@@ -620,6 +652,7 @@ var MediaWebSocket = class {
|
|
|
620
652
|
ws.on("open", () => {
|
|
621
653
|
this._startSendLoop();
|
|
622
654
|
resolve();
|
|
655
|
+
this._log.info("Media WS connected: %s", url);
|
|
623
656
|
});
|
|
624
657
|
ws.on("message", (data) => {
|
|
625
658
|
try {
|
|
@@ -638,7 +671,7 @@ var MediaWebSocket = class {
|
|
|
638
671
|
if (!this._ws) {
|
|
639
672
|
reject(err);
|
|
640
673
|
}
|
|
641
|
-
|
|
674
|
+
this._log.error({ err }, "Media WS error");
|
|
642
675
|
});
|
|
643
676
|
});
|
|
644
677
|
}
|
|
@@ -799,6 +832,10 @@ var AudioRecorder = class {
|
|
|
799
832
|
_mixWritten = 0;
|
|
800
833
|
_startTime = 0;
|
|
801
834
|
_started = false;
|
|
835
|
+
_log = NOOP_LOGGER;
|
|
836
|
+
setLogger(logger) {
|
|
837
|
+
this._log = logger;
|
|
838
|
+
}
|
|
802
839
|
constructor(recordingPath, callId) {
|
|
803
840
|
this._dir = path.join(recordingPath, callId);
|
|
804
841
|
}
|
|
@@ -813,6 +850,7 @@ var AudioRecorder = class {
|
|
|
813
850
|
fs.writeSync(this._fdMix, header);
|
|
814
851
|
this._startTime = performance.now();
|
|
815
852
|
this._started = true;
|
|
853
|
+
this._log.info("Recording started: %s", this._dir);
|
|
816
854
|
}
|
|
817
855
|
_expectedBytes() {
|
|
818
856
|
const elapsed = (performance.now() - this._startTime) / 1e3;
|
|
@@ -865,7 +903,7 @@ var AudioRecorder = class {
|
|
|
865
903
|
this._inWritten += pcm16_8k.length;
|
|
866
904
|
this._writeToMix(pcm16_8k, posBefore);
|
|
867
905
|
} catch (err) {
|
|
868
|
-
|
|
906
|
+
this._log.error({ err }, "Recording write error (inbound)");
|
|
869
907
|
}
|
|
870
908
|
}
|
|
871
909
|
writeOutbound(pcm16_8k) {
|
|
@@ -878,7 +916,7 @@ var AudioRecorder = class {
|
|
|
878
916
|
this._outWritten += pcm16_8k.length;
|
|
879
917
|
this._writeToMix(pcm16_8k, posBefore);
|
|
880
918
|
} catch (err) {
|
|
881
|
-
|
|
919
|
+
this._log.error({ err }, "Recording write error (outbound)");
|
|
882
920
|
}
|
|
883
921
|
}
|
|
884
922
|
stop() {
|
|
@@ -899,8 +937,10 @@ var AudioRecorder = class {
|
|
|
899
937
|
fs.writeSync(fd, makeWavHeader(maxWritten), 0, 44, 0);
|
|
900
938
|
fs.closeSync(fd);
|
|
901
939
|
}
|
|
940
|
+
const maxSec = maxWritten / 16e3;
|
|
941
|
+
this._log.info("Recording stopped: %s (%ds)", this._dir, maxSec);
|
|
902
942
|
} catch (err) {
|
|
903
|
-
|
|
943
|
+
this._log.error({ err }, "Recording stop error");
|
|
904
944
|
} finally {
|
|
905
945
|
this._fdIn = null;
|
|
906
946
|
this._fdOut = null;
|
|
@@ -930,6 +970,7 @@ var CallSession = class {
|
|
|
930
970
|
_dtmfCollectorActive = false;
|
|
931
971
|
_dtmfResolvers = [];
|
|
932
972
|
_dtmfBuffer = [];
|
|
973
|
+
_log = NOOP_LOGGER;
|
|
933
974
|
_handlers = /* @__PURE__ */ new Map();
|
|
934
975
|
_endedPromise;
|
|
935
976
|
_resolveEnded;
|
|
@@ -946,6 +987,9 @@ var CallSession = class {
|
|
|
946
987
|
this._resolveEnded = resolve;
|
|
947
988
|
});
|
|
948
989
|
}
|
|
990
|
+
setLogger(logger) {
|
|
991
|
+
this._log = logger;
|
|
992
|
+
}
|
|
949
993
|
get status() {
|
|
950
994
|
return this._status;
|
|
951
995
|
}
|
|
@@ -1021,7 +1065,9 @@ var CallSession = class {
|
|
|
1021
1065
|
this._dtmfResolvers = [];
|
|
1022
1066
|
this._dtmfBuffer = [];
|
|
1023
1067
|
}
|
|
1024
|
-
|
|
1068
|
+
const result = collected.join("");
|
|
1069
|
+
this._log.info("DTMF collected: %s", result);
|
|
1070
|
+
return result;
|
|
1025
1071
|
}
|
|
1026
1072
|
/** Send a sequence of DTMF digits. */
|
|
1027
1073
|
async sendDtmfSequence(digits) {
|
|
@@ -1073,11 +1119,11 @@ var CallSession = class {
|
|
|
1073
1119
|
const result = handler(this, ...args);
|
|
1074
1120
|
if (result && typeof result.catch === "function") {
|
|
1075
1121
|
result.catch((err) => {
|
|
1076
|
-
|
|
1122
|
+
this._log.error({ err }, "CallSession handler error: %s", event);
|
|
1077
1123
|
});
|
|
1078
1124
|
}
|
|
1079
1125
|
} catch (err) {
|
|
1080
|
-
|
|
1126
|
+
this._log.error({ err }, "CallSession handler error: %s", event);
|
|
1081
1127
|
}
|
|
1082
1128
|
}
|
|
1083
1129
|
}
|
|
@@ -1325,6 +1371,9 @@ var ClawOpsAgent = class {
|
|
|
1325
1371
|
_passiveDtmfTimer = null;
|
|
1326
1372
|
_passiveDtmfCallId = null;
|
|
1327
1373
|
_callSessions = /* @__PURE__ */ new Map();
|
|
1374
|
+
_log;
|
|
1375
|
+
_pipelineLog;
|
|
1376
|
+
_isPipelineSession = false;
|
|
1328
1377
|
constructor(options) {
|
|
1329
1378
|
this._apiKey = options.apiKey ?? process.env["CLAWOPS_API_KEY"] ?? "";
|
|
1330
1379
|
this._accountId = options.accountId ?? process.env["CLAWOPS_ACCOUNT_ID"] ?? "";
|
|
@@ -1339,6 +1388,9 @@ var ClawOpsAgent = class {
|
|
|
1339
1388
|
if (options.tracing) {
|
|
1340
1389
|
setTracingConfig(options.tracing);
|
|
1341
1390
|
}
|
|
1391
|
+
this._log = createAgentLogger(options.logger);
|
|
1392
|
+
this._pipelineLog = createPipelineLogger(this._log);
|
|
1393
|
+
this._isPipelineSession = "_stt" in this._session && "_llm" in this._session;
|
|
1342
1394
|
}
|
|
1343
1395
|
/**
|
|
1344
1396
|
* Register a function tool.
|
|
@@ -1398,6 +1450,7 @@ var ClawOpsAgent = class {
|
|
|
1398
1450
|
accountId: this._accountId,
|
|
1399
1451
|
number: this._fromNumber
|
|
1400
1452
|
});
|
|
1453
|
+
this._controlWs.setLogger(this._log);
|
|
1401
1454
|
this._controlWs.on("call.incoming", (event) => this._handleIncoming(event));
|
|
1402
1455
|
this._controlWs.on("call.ended", (event) => this._handleEnded(event));
|
|
1403
1456
|
this._controlWs.on("call.outbound_ready", (event) => this._handleOutboundReady(event));
|
|
@@ -1411,7 +1464,7 @@ var ClawOpsAgent = class {
|
|
|
1411
1464
|
`Failed to connect to ClawOps: ${err instanceof Error ? err.message : String(err)}`
|
|
1412
1465
|
);
|
|
1413
1466
|
}
|
|
1414
|
-
|
|
1467
|
+
this._log.info("ClawOpsAgent connected on %s", this._fromNumber);
|
|
1415
1468
|
}
|
|
1416
1469
|
/**
|
|
1417
1470
|
* Connect and block until disconnected.
|
|
@@ -1438,7 +1491,7 @@ var ClawOpsAgent = class {
|
|
|
1438
1491
|
}
|
|
1439
1492
|
this._activeSessions.clear();
|
|
1440
1493
|
this._callSessions.clear();
|
|
1441
|
-
|
|
1494
|
+
this._log.info("ClawOpsAgent disconnected");
|
|
1442
1495
|
}
|
|
1443
1496
|
/**
|
|
1444
1497
|
* Initiate an outbound call.
|
|
@@ -1473,10 +1526,9 @@ var ClawOpsAgent = class {
|
|
|
1473
1526
|
callSession.on(evt, handler);
|
|
1474
1527
|
}
|
|
1475
1528
|
}
|
|
1529
|
+
callSession.setLogger(this._log);
|
|
1476
1530
|
this._activeSessions.set(callSession.callId, callSession);
|
|
1477
|
-
|
|
1478
|
-
`[ClawOpsAgent] Outbound call initiated: ${this._fromNumber} -> ${to} (${callSession.callId})`
|
|
1479
|
-
);
|
|
1531
|
+
this._log.info("Outbound call initiated: %s -> %s (%s)", this._fromNumber, to, callSession.callId);
|
|
1480
1532
|
return callSession;
|
|
1481
1533
|
}
|
|
1482
1534
|
_handleIncoming(event) {
|
|
@@ -1495,13 +1547,15 @@ var ClawOpsAgent = class {
|
|
|
1495
1547
|
session.on(evt, handler);
|
|
1496
1548
|
}
|
|
1497
1549
|
}
|
|
1550
|
+
session.setLogger(this._log);
|
|
1498
1551
|
this._activeSessions.set(callId, session);
|
|
1552
|
+
this._log.info("Incoming call: %s -> %s (%s)", fromNumber, this._fromNumber, callId);
|
|
1499
1553
|
if (this._controlWs) {
|
|
1500
1554
|
this._controlWs.send({ event: "call.accept", callId });
|
|
1501
1555
|
}
|
|
1502
1556
|
if (mediaUrl) {
|
|
1503
1557
|
this._startCallSession(session, mediaUrl).catch((err) => {
|
|
1504
|
-
|
|
1558
|
+
this._log.error({ err }, "Call session error: %s", callId);
|
|
1505
1559
|
});
|
|
1506
1560
|
}
|
|
1507
1561
|
}
|
|
@@ -1509,6 +1563,7 @@ var ClawOpsAgent = class {
|
|
|
1509
1563
|
const callId = event["callId"];
|
|
1510
1564
|
const session = this._activeSessions.get(callId);
|
|
1511
1565
|
if (session) {
|
|
1566
|
+
this._log.info("Call ended (server): %s", callId);
|
|
1512
1567
|
session._markEnded();
|
|
1513
1568
|
this._activeSessions.delete(callId);
|
|
1514
1569
|
}
|
|
@@ -1525,6 +1580,7 @@ var ClawOpsAgent = class {
|
|
|
1525
1580
|
accountId: this._accountId,
|
|
1526
1581
|
direction: "outbound"
|
|
1527
1582
|
});
|
|
1583
|
+
session.setLogger(this._log);
|
|
1528
1584
|
for (const [evt, handlers] of this._handlers) {
|
|
1529
1585
|
for (const handler of handlers) {
|
|
1530
1586
|
session.on(evt, handler);
|
|
@@ -1533,8 +1589,9 @@ var ClawOpsAgent = class {
|
|
|
1533
1589
|
this._activeSessions.set(callId, session);
|
|
1534
1590
|
}
|
|
1535
1591
|
if (mediaUrl) {
|
|
1592
|
+
this._log.info("Outbound call answered: %s -> %s (%s)", this._fromNumber, session.toNumber, callId);
|
|
1536
1593
|
this._startCallSession(session, mediaUrl).catch((err) => {
|
|
1537
|
-
|
|
1594
|
+
this._log.error({ err }, "Call session error: %s", callId);
|
|
1538
1595
|
});
|
|
1539
1596
|
}
|
|
1540
1597
|
}
|
|
@@ -1542,13 +1599,14 @@ var ClawOpsAgent = class {
|
|
|
1542
1599
|
const callId = event["callId"];
|
|
1543
1600
|
const session = this._activeSessions.get(callId);
|
|
1544
1601
|
if (session) {
|
|
1545
|
-
|
|
1602
|
+
this._log.info("Outbound call ringing: %s", callId);
|
|
1546
1603
|
}
|
|
1547
1604
|
}
|
|
1548
1605
|
_handleFailed(event) {
|
|
1549
1606
|
const callId = event["callId"];
|
|
1550
1607
|
const session = this._activeSessions.get(callId);
|
|
1551
1608
|
if (session) {
|
|
1609
|
+
this._log.info("Outbound call failed: %s (%s)", callId, event["reason"] ?? "failed");
|
|
1552
1610
|
session._emit("call_failed", event["reason"] ?? "failed");
|
|
1553
1611
|
session._markEnded();
|
|
1554
1612
|
this._activeSessions.delete(callId);
|
|
@@ -1573,7 +1631,7 @@ var ClawOpsAgent = class {
|
|
|
1573
1631
|
this._passiveDtmfCallId = null;
|
|
1574
1632
|
if (digits && sessionHandler && sessionHandler.feedDtmf) {
|
|
1575
1633
|
sessionHandler.feedDtmf(digits).catch((err) => {
|
|
1576
|
-
|
|
1634
|
+
this._log.error({ err }, "DTMF feed error");
|
|
1577
1635
|
});
|
|
1578
1636
|
}
|
|
1579
1637
|
}, this._passiveDtmfDebounceMs);
|
|
@@ -1592,22 +1650,25 @@ var ClawOpsAgent = class {
|
|
|
1592
1650
|
if (this._mcpServers.length > 0) {
|
|
1593
1651
|
for (const serverConfig of this._mcpServers) {
|
|
1594
1652
|
const client = new MCPClient();
|
|
1653
|
+
client.setLogger(this._log);
|
|
1595
1654
|
client.addServer("mcp", serverConfig);
|
|
1596
1655
|
try {
|
|
1597
1656
|
const tools = await client.connect();
|
|
1598
1657
|
sessionTools.registerMcpTools(tools);
|
|
1599
1658
|
mcpClients.push(client);
|
|
1600
1659
|
} catch (err) {
|
|
1601
|
-
|
|
1660
|
+
this._log.error({ err }, "MCP connection error");
|
|
1602
1661
|
}
|
|
1603
1662
|
}
|
|
1604
1663
|
}
|
|
1605
1664
|
let recorder = null;
|
|
1606
1665
|
if (this._recording) {
|
|
1607
1666
|
recorder = new AudioRecorder(this._recordingPath, session.callId);
|
|
1667
|
+
recorder.setLogger(this._log);
|
|
1608
1668
|
recorder.start();
|
|
1609
1669
|
}
|
|
1610
1670
|
const mediaWs = new MediaWebSocket();
|
|
1671
|
+
mediaWs.setLogger(this._log);
|
|
1611
1672
|
session._bindTransport(
|
|
1612
1673
|
(audio) => {
|
|
1613
1674
|
mediaWs.sendAudio(audio.toString("base64"));
|
|
@@ -1637,6 +1698,9 @@ var ClawOpsAgent = class {
|
|
|
1637
1698
|
if ("setBuiltinTools" in sessionHandler && typeof sessionHandler.setBuiltinTools === "function") {
|
|
1638
1699
|
sessionHandler.setBuiltinTools(this._builtinTools);
|
|
1639
1700
|
}
|
|
1701
|
+
if ("setLogger" in sessionHandler && typeof sessionHandler.setLogger === "function") {
|
|
1702
|
+
sessionHandler.setLogger(this._isPipelineSession ? this._pipelineLog : this._log);
|
|
1703
|
+
}
|
|
1640
1704
|
this._callSessions.set(session.callId, sessionHandler);
|
|
1641
1705
|
mediaWs.onAudio((ulawAudio, _timestamp) => {
|
|
1642
1706
|
if (sessionHandler) {
|
|
@@ -1650,6 +1714,7 @@ var ClawOpsAgent = class {
|
|
|
1650
1714
|
this._onDtmfEvent(session, digit);
|
|
1651
1715
|
});
|
|
1652
1716
|
mediaWs.onClose(() => {
|
|
1717
|
+
this._log.info("Media stream stopped: %s", session.callId);
|
|
1653
1718
|
if (recorder) {
|
|
1654
1719
|
recorder.stop();
|
|
1655
1720
|
}
|
|
@@ -1658,11 +1723,12 @@ var ClawOpsAgent = class {
|
|
|
1658
1723
|
session._emit("call_start");
|
|
1659
1724
|
try {
|
|
1660
1725
|
await mediaWs.connect(mediaWsUrl, this._apiKey);
|
|
1726
|
+
this._log.info("Media stream started: %s", session.callId);
|
|
1661
1727
|
await sessionHandler.start(session, sessionTools);
|
|
1662
1728
|
await session.wait();
|
|
1663
1729
|
await sessionHandler.stop();
|
|
1664
1730
|
} catch (err) {
|
|
1665
|
-
|
|
1731
|
+
this._log.error({ err }, "Call session error: %s", session.callId);
|
|
1666
1732
|
} finally {
|
|
1667
1733
|
if (mcpClients.length > 0) {
|
|
1668
1734
|
sessionTools.clearMcpTools();
|
|
@@ -1690,7 +1756,11 @@ var HANG_UP_TOOL = {
|
|
|
1690
1756
|
type: "function",
|
|
1691
1757
|
name: "hang_up",
|
|
1692
1758
|
description: "End the phone call. Use when the conversation is finished or the caller says goodbye.",
|
|
1693
|
-
parameters: {
|
|
1759
|
+
parameters: {
|
|
1760
|
+
type: "object",
|
|
1761
|
+
properties: {},
|
|
1762
|
+
required: []
|
|
1763
|
+
}
|
|
1694
1764
|
};
|
|
1695
1765
|
var COLLECT_DTMF_TOOL = {
|
|
1696
1766
|
type: "function",
|
|
@@ -1713,7 +1783,10 @@ var SEND_DTMF_TOOL = {
|
|
|
1713
1783
|
parameters: {
|
|
1714
1784
|
type: "object",
|
|
1715
1785
|
properties: {
|
|
1716
|
-
digits: {
|
|
1786
|
+
digits: {
|
|
1787
|
+
type: "string",
|
|
1788
|
+
description: "\uC804\uC1A1\uD560 \uBC88\uD638 (0-9, *, #). 'w'\uB294 500ms \uB300\uAE30, 'W'\uB294 1000ms \uB300\uAE30."
|
|
1789
|
+
}
|
|
1717
1790
|
},
|
|
1718
1791
|
required: ["digits"]
|
|
1719
1792
|
}
|
|
@@ -1726,7 +1799,11 @@ var OpenAIRealtime = class {
|
|
|
1726
1799
|
_language;
|
|
1727
1800
|
_eagerness;
|
|
1728
1801
|
_greeting;
|
|
1802
|
+
_log = NOOP_LOGGER;
|
|
1729
1803
|
_builtinTools = null;
|
|
1804
|
+
setLogger(logger) {
|
|
1805
|
+
this._log = logger;
|
|
1806
|
+
}
|
|
1730
1807
|
setBuiltinTools(tools) {
|
|
1731
1808
|
this._builtinTools = tools;
|
|
1732
1809
|
}
|
|
@@ -1783,6 +1860,7 @@ var OpenAIRealtime = class {
|
|
|
1783
1860
|
const ws = this._ws;
|
|
1784
1861
|
ws.on("open", () => {
|
|
1785
1862
|
this._sendSessionUpdate();
|
|
1863
|
+
this._log.info("OpenAI Realtime connected");
|
|
1786
1864
|
if (this._greeting) {
|
|
1787
1865
|
this._send({ type: "response.create" });
|
|
1788
1866
|
}
|
|
@@ -1802,7 +1880,7 @@ var OpenAIRealtime = class {
|
|
|
1802
1880
|
if (!this._ws) {
|
|
1803
1881
|
reject(err);
|
|
1804
1882
|
}
|
|
1805
|
-
|
|
1883
|
+
this._log.error({ err }, "OpenAI Realtime WS error");
|
|
1806
1884
|
});
|
|
1807
1885
|
});
|
|
1808
1886
|
}
|
|
@@ -1836,9 +1914,12 @@ var OpenAIRealtime = class {
|
|
|
1836
1914
|
_sendSessionUpdate() {
|
|
1837
1915
|
if (!this._ws || this._ws.readyState !== 1) return;
|
|
1838
1916
|
const toolSchemas = this._tools ? this._tools.toOpenAITools().map((t) => ({ type: "function", ...t.function })) : [];
|
|
1839
|
-
if (!this._builtinTools || this._builtinTools.has("hang_up" /* HANG_UP */))
|
|
1840
|
-
|
|
1841
|
-
if (!this._builtinTools || this._builtinTools.has("
|
|
1917
|
+
if (!this._builtinTools || this._builtinTools.has("hang_up" /* HANG_UP */))
|
|
1918
|
+
toolSchemas.push(HANG_UP_TOOL);
|
|
1919
|
+
if (!this._builtinTools || this._builtinTools.has("collect_dtmf" /* COLLECT_DTMF */))
|
|
1920
|
+
toolSchemas.push(COLLECT_DTMF_TOOL);
|
|
1921
|
+
if (!this._builtinTools || this._builtinTools.has("send_dtmf" /* SEND_DTMF */))
|
|
1922
|
+
toolSchemas.push(SEND_DTMF_TOOL);
|
|
1842
1923
|
this._send({
|
|
1843
1924
|
type: "session.update",
|
|
1844
1925
|
session: {
|
|
@@ -1848,7 +1929,7 @@ var OpenAIRealtime = class {
|
|
|
1848
1929
|
input_audio_format: "g711_ulaw",
|
|
1849
1930
|
output_audio_format: "g711_ulaw",
|
|
1850
1931
|
input_audio_transcription: {
|
|
1851
|
-
model: "
|
|
1932
|
+
model: "whisper-1",
|
|
1852
1933
|
language: this._language
|
|
1853
1934
|
},
|
|
1854
1935
|
input_audio_noise_reduction: { type: "far_field" },
|
|
@@ -1919,7 +2000,7 @@ var OpenAIRealtime = class {
|
|
|
1919
2000
|
break;
|
|
1920
2001
|
}
|
|
1921
2002
|
case "error": {
|
|
1922
|
-
|
|
2003
|
+
this._log.error({ apiError: msg["error"] }, "OpenAI error");
|
|
1923
2004
|
break;
|
|
1924
2005
|
}
|
|
1925
2006
|
}
|
|
@@ -1969,6 +2050,7 @@ var OpenAIRealtime = class {
|
|
|
1969
2050
|
async _handleToolCall(item) {
|
|
1970
2051
|
const funcName = item["name"];
|
|
1971
2052
|
const callId = item["call_id"];
|
|
2053
|
+
this._log.info("Tool call: %s", funcName);
|
|
1972
2054
|
if (funcName === "hang_up") {
|
|
1973
2055
|
if (this._call) {
|
|
1974
2056
|
await this._call.hangup();
|
|
@@ -2025,7 +2107,7 @@ var OpenAIRealtime = class {
|
|
|
2025
2107
|
return;
|
|
2026
2108
|
}
|
|
2027
2109
|
if (!this._tools || !this._tools.has(funcName)) {
|
|
2028
|
-
|
|
2110
|
+
this._log.error("Unknown tool: %s", funcName);
|
|
2029
2111
|
return;
|
|
2030
2112
|
}
|
|
2031
2113
|
let result;
|
|
@@ -2033,7 +2115,7 @@ var OpenAIRealtime = class {
|
|
|
2033
2115
|
const args = JSON.parse(item["arguments"] ?? "{}");
|
|
2034
2116
|
result = await this._tools.call(funcName, args);
|
|
2035
2117
|
} catch (err) {
|
|
2036
|
-
|
|
2118
|
+
this._log.error({ err }, "Tool call failed: %s", funcName);
|
|
2037
2119
|
result = `Error: ${err}`;
|
|
2038
2120
|
}
|
|
2039
2121
|
await this._waitForResponseDone();
|
|
@@ -2182,6 +2264,7 @@ var GeminiRealtime = class {
|
|
|
2182
2264
|
_audioRemainder = Buffer.alloc(0);
|
|
2183
2265
|
_builtinTools = null;
|
|
2184
2266
|
_toolCallInProgress = false;
|
|
2267
|
+
_log = NOOP_LOGGER;
|
|
2185
2268
|
constructor(options = {}) {
|
|
2186
2269
|
this._apiKey = options.apiKey ?? process.env["GOOGLE_API_KEY"] ?? "";
|
|
2187
2270
|
this._systemPrompt = options.systemPrompt ?? "";
|
|
@@ -2201,6 +2284,9 @@ var GeminiRealtime = class {
|
|
|
2201
2284
|
setBuiltinTools(tools) {
|
|
2202
2285
|
this._builtinTools = tools;
|
|
2203
2286
|
}
|
|
2287
|
+
setLogger(logger) {
|
|
2288
|
+
this._log = logger;
|
|
2289
|
+
}
|
|
2204
2290
|
async start(callSession, tools) {
|
|
2205
2291
|
this._call = callSession;
|
|
2206
2292
|
if (tools) this._tools = tools;
|
|
@@ -2237,12 +2323,10 @@ var GeminiRealtime = class {
|
|
|
2237
2323
|
callbacks: {
|
|
2238
2324
|
onmessage: (msg) => this._handleMessage(msg),
|
|
2239
2325
|
onerror: (err) => {
|
|
2240
|
-
|
|
2326
|
+
this._log.error({ err }, "Gemini SDK error");
|
|
2241
2327
|
},
|
|
2242
2328
|
onclose: (ev) => {
|
|
2243
|
-
|
|
2244
|
-
`[GeminiRealtime] Connection closed: code=${ev?.code ?? "unknown"}`
|
|
2245
|
-
);
|
|
2329
|
+
this._log.info({ code: ev?.code ?? "unknown" }, "Gemini connection closed");
|
|
2246
2330
|
this._closed = true;
|
|
2247
2331
|
}
|
|
2248
2332
|
}
|
|
@@ -2322,11 +2406,11 @@ var GeminiRealtime = class {
|
|
|
2322
2406
|
}
|
|
2323
2407
|
}
|
|
2324
2408
|
if (serverContent.turnComplete) {
|
|
2325
|
-
|
|
2409
|
+
this._log.debug("Turn complete");
|
|
2326
2410
|
this._flushAudioRemainder();
|
|
2327
2411
|
}
|
|
2328
2412
|
if (serverContent.interrupted) {
|
|
2329
|
-
|
|
2413
|
+
this._log.info("Barge-in detected");
|
|
2330
2414
|
if (this._call) {
|
|
2331
2415
|
this._call.clearAudio();
|
|
2332
2416
|
}
|
|
@@ -2335,12 +2419,12 @@ var GeminiRealtime = class {
|
|
|
2335
2419
|
}
|
|
2336
2420
|
const inputText = serverContent.inputTranscription?.text;
|
|
2337
2421
|
if (inputText && this._call) {
|
|
2338
|
-
|
|
2422
|
+
this._log.info("User: %s", inputText);
|
|
2339
2423
|
this._call._emit("transcript", "user", inputText);
|
|
2340
2424
|
}
|
|
2341
2425
|
const outputText = serverContent.outputTranscription?.text;
|
|
2342
2426
|
if (outputText && this._call) {
|
|
2343
|
-
|
|
2427
|
+
this._log.info("Assistant: %s", outputText);
|
|
2344
2428
|
this._call._emit("transcript", "assistant", outputText);
|
|
2345
2429
|
}
|
|
2346
2430
|
}
|
|
@@ -2349,9 +2433,7 @@ var GeminiRealtime = class {
|
|
|
2349
2433
|
}
|
|
2350
2434
|
const toolCancellation = msg["toolCallCancellation"];
|
|
2351
2435
|
if (toolCancellation) {
|
|
2352
|
-
|
|
2353
|
-
`[GeminiRealtime] Tool call cancelled: ${(toolCancellation.ids ?? []).join(", ")}`
|
|
2354
|
-
);
|
|
2436
|
+
this._log.info({ ids: toolCancellation.ids }, "Tool call cancelled");
|
|
2355
2437
|
}
|
|
2356
2438
|
}
|
|
2357
2439
|
_handleAudioData(b64Data) {
|
|
@@ -2386,17 +2468,14 @@ var GeminiRealtime = class {
|
|
|
2386
2468
|
const functionCalls = toolCall.functionCalls;
|
|
2387
2469
|
if (!functionCalls) return;
|
|
2388
2470
|
this._toolCallInProgress = true;
|
|
2389
|
-
console.log(
|
|
2390
|
-
`[GeminiRealtime] toolCall: ${functionCalls.map((fc) => fc.name).join(", ")}`
|
|
2391
|
-
);
|
|
2392
2471
|
const responses = [];
|
|
2393
2472
|
for (const fc of functionCalls) {
|
|
2394
2473
|
const name = fc.name ?? "";
|
|
2395
2474
|
const fcId = fc.id ?? "";
|
|
2396
2475
|
const args = fc.args ?? {};
|
|
2397
|
-
|
|
2476
|
+
this._log.info({ tool: name, args }, "Tool call: %s", name);
|
|
2398
2477
|
if (name === "hang_up") {
|
|
2399
|
-
|
|
2478
|
+
this._log.info("hang_up: ending call");
|
|
2400
2479
|
if (this._call) {
|
|
2401
2480
|
await this._call.hangup();
|
|
2402
2481
|
}
|
|
@@ -2406,17 +2485,15 @@ var GeminiRealtime = class {
|
|
|
2406
2485
|
if (this._call) {
|
|
2407
2486
|
let result;
|
|
2408
2487
|
try {
|
|
2409
|
-
|
|
2410
|
-
`[GeminiRealtime] collect_dtmf: waiting for digits (maxDigits=${args["max_digits"] ?? 4}, timeout=${args["timeout"] ?? 5})`
|
|
2411
|
-
);
|
|
2488
|
+
this._log.info({ maxDigits: args["max_digits"] ?? 4, timeout: args["timeout"] ?? 5 }, "collect_dtmf: waiting for digits");
|
|
2412
2489
|
result = await this._call.collectDtmf({
|
|
2413
2490
|
maxDigits: args["max_digits"] ?? 4,
|
|
2414
2491
|
finishOnKey: args["finish_on_key"] ?? "#",
|
|
2415
2492
|
timeout: args["timeout"] ?? 5
|
|
2416
2493
|
});
|
|
2417
|
-
|
|
2494
|
+
this._log.info("DTMF collected: %s", result || "(empty)");
|
|
2418
2495
|
} catch (err) {
|
|
2419
|
-
|
|
2496
|
+
this._log.error({ err }, "collect_dtmf error");
|
|
2420
2497
|
result = `Error: ${err}`;
|
|
2421
2498
|
}
|
|
2422
2499
|
responses.push({
|
|
@@ -2431,12 +2508,12 @@ var GeminiRealtime = class {
|
|
|
2431
2508
|
if (this._call) {
|
|
2432
2509
|
let result;
|
|
2433
2510
|
try {
|
|
2434
|
-
|
|
2511
|
+
this._log.info('send_dtmf: digits="%s"', args["digits"] ?? "");
|
|
2435
2512
|
await this._call.sendDtmfSequence(args["digits"] ?? "");
|
|
2436
2513
|
result = "sent";
|
|
2437
|
-
|
|
2514
|
+
this._log.info("send_dtmf: sent");
|
|
2438
2515
|
} catch (err) {
|
|
2439
|
-
|
|
2516
|
+
this._log.error({ err }, "send_dtmf error");
|
|
2440
2517
|
result = `Error: ${err}`;
|
|
2441
2518
|
}
|
|
2442
2519
|
responses.push({ id: fcId, name, response: { result } });
|
|
@@ -2444,21 +2521,21 @@ var GeminiRealtime = class {
|
|
|
2444
2521
|
continue;
|
|
2445
2522
|
}
|
|
2446
2523
|
if (!this._tools || !this._tools.has(name)) {
|
|
2447
|
-
|
|
2524
|
+
this._log.error("Unknown tool: %s", name);
|
|
2448
2525
|
responses.push({ id: fcId, name, response: { error: `Unknown tool: ${name}` } });
|
|
2449
2526
|
continue;
|
|
2450
2527
|
}
|
|
2451
2528
|
try {
|
|
2452
2529
|
const result = await this._tools.call(name, args);
|
|
2453
2530
|
const resultStr = typeof result === "string" ? result : JSON.stringify(result);
|
|
2454
|
-
|
|
2531
|
+
this._log.info("Tool result: %s -> %s", name, resultStr.substring(0, 200));
|
|
2455
2532
|
responses.push({
|
|
2456
2533
|
id: fcId,
|
|
2457
2534
|
name,
|
|
2458
2535
|
response: { result: resultStr }
|
|
2459
2536
|
});
|
|
2460
2537
|
} catch (err) {
|
|
2461
|
-
|
|
2538
|
+
this._log.error({ err }, "Tool call failed: %s", name);
|
|
2462
2539
|
responses.push({
|
|
2463
2540
|
id: fcId,
|
|
2464
2541
|
name,
|
|
@@ -2467,7 +2544,7 @@ var GeminiRealtime = class {
|
|
|
2467
2544
|
}
|
|
2468
2545
|
}
|
|
2469
2546
|
if (responses.length > 0 && this._session) {
|
|
2470
|
-
|
|
2547
|
+
this._log.debug("Sending %d tool response(s)", responses.length);
|
|
2471
2548
|
this._session.sendToolResponse({
|
|
2472
2549
|
functionResponses: responses
|
|
2473
2550
|
});
|
|
@@ -2520,6 +2597,7 @@ var PipelineSession = class {
|
|
|
2520
2597
|
_running = false;
|
|
2521
2598
|
_speaking = false;
|
|
2522
2599
|
_builtinTools = null;
|
|
2600
|
+
_log = NOOP_LOGGER;
|
|
2523
2601
|
constructor(options) {
|
|
2524
2602
|
this._stt = options.stt;
|
|
2525
2603
|
this._llm = options.llm;
|
|
@@ -2543,10 +2621,20 @@ var PipelineSession = class {
|
|
|
2543
2621
|
setBuiltinTools(tools) {
|
|
2544
2622
|
this._builtinTools = tools;
|
|
2545
2623
|
}
|
|
2624
|
+
setLogger(logger) {
|
|
2625
|
+
this._log = logger;
|
|
2626
|
+
if ("setLogger" in this._stt && typeof this._stt.setLogger === "function") {
|
|
2627
|
+
this._stt.setLogger(logger);
|
|
2628
|
+
}
|
|
2629
|
+
if ("setLogger" in this._tts && typeof this._tts.setLogger === "function") {
|
|
2630
|
+
this._tts.setLogger(logger);
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2546
2633
|
async start(callSession, tools) {
|
|
2547
2634
|
this._callSession = callSession;
|
|
2548
2635
|
this._tools = tools ?? null;
|
|
2549
2636
|
this._running = true;
|
|
2637
|
+
this._log.info("PipelineSession started");
|
|
2550
2638
|
this._conversation = [];
|
|
2551
2639
|
if (this._systemPrompt) {
|
|
2552
2640
|
this._conversation.push({
|
|
@@ -2556,11 +2644,11 @@ var PipelineSession = class {
|
|
|
2556
2644
|
}
|
|
2557
2645
|
if (this._greeting) {
|
|
2558
2646
|
this._generateGreeting().catch((err) => {
|
|
2559
|
-
|
|
2647
|
+
this._log.error({ err }, "Greeting error");
|
|
2560
2648
|
});
|
|
2561
2649
|
}
|
|
2562
2650
|
this._runSttLoop().catch((err) => {
|
|
2563
|
-
|
|
2651
|
+
this._log.error({ err }, "STT loop error");
|
|
2564
2652
|
});
|
|
2565
2653
|
}
|
|
2566
2654
|
feedAudio(audio) {
|
|
@@ -2577,6 +2665,7 @@ var PipelineSession = class {
|
|
|
2577
2665
|
}
|
|
2578
2666
|
async stop() {
|
|
2579
2667
|
this._running = false;
|
|
2668
|
+
this._log.info("PipelineSession stopped");
|
|
2580
2669
|
this._audioBuffer = [];
|
|
2581
2670
|
}
|
|
2582
2671
|
async _runSttLoop() {
|
|
@@ -2590,8 +2679,10 @@ var PipelineSession = class {
|
|
|
2590
2679
|
if (this._callSession) {
|
|
2591
2680
|
this._callSession.clearAudio();
|
|
2592
2681
|
}
|
|
2682
|
+
this._log.info('Barge-in: "%s"', event.transcript.substring(0, 30));
|
|
2593
2683
|
}
|
|
2594
2684
|
if (event.type === "final" && event.transcript.trim()) {
|
|
2685
|
+
this._log.info("STT: %s", event.transcript);
|
|
2595
2686
|
await this._handleUserSpeech(event.transcript);
|
|
2596
2687
|
}
|
|
2597
2688
|
}
|
|
@@ -2660,6 +2751,7 @@ var PipelineSession = class {
|
|
|
2660
2751
|
}
|
|
2661
2752
|
}
|
|
2662
2753
|
if (fullResponse.trim()) {
|
|
2754
|
+
this._log.info("Assistant: %s", fullResponse.substring(0, 100));
|
|
2663
2755
|
this._conversation.push({ role: "assistant", content: fullResponse });
|
|
2664
2756
|
await this._synthesizeAndSend(fullResponse);
|
|
2665
2757
|
}
|
|
@@ -2727,7 +2819,7 @@ var PipelineSession = class {
|
|
|
2727
2819
|
await this._synthesizeAndSend(followUpText);
|
|
2728
2820
|
}
|
|
2729
2821
|
} catch (err) {
|
|
2730
|
-
|
|
2822
|
+
this._log.error({ err }, "Tool call failed: %s", name);
|
|
2731
2823
|
}
|
|
2732
2824
|
}
|
|
2733
2825
|
async _synthesizeAndSend(text) {
|
|
@@ -2753,7 +2845,7 @@ var PipelineSession = class {
|
|
|
2753
2845
|
}
|
|
2754
2846
|
}
|
|
2755
2847
|
} catch (err) {
|
|
2756
|
-
|
|
2848
|
+
this._log.error({ err }, "TTS error");
|
|
2757
2849
|
} finally {
|
|
2758
2850
|
this._speaking = false;
|
|
2759
2851
|
}
|
|
@@ -2763,6 +2855,10 @@ var PipelineSession = class {
|
|
|
2763
2855
|
// src/agent/pipeline/deepgram-stt.ts
|
|
2764
2856
|
var DeepgramSTT = class {
|
|
2765
2857
|
_options;
|
|
2858
|
+
_log = NOOP_LOGGER;
|
|
2859
|
+
setLogger(logger) {
|
|
2860
|
+
this._log = logger;
|
|
2861
|
+
}
|
|
2766
2862
|
constructor(options = {}) {
|
|
2767
2863
|
this._options = {
|
|
2768
2864
|
model: "nova-3",
|
|
@@ -2832,7 +2928,7 @@ var DeepgramSTT = class {
|
|
|
2832
2928
|
}
|
|
2833
2929
|
});
|
|
2834
2930
|
ws.on("error", (err) => {
|
|
2835
|
-
|
|
2931
|
+
this._log.error({ err }, "Deepgram STT error");
|
|
2836
2932
|
done = true;
|
|
2837
2933
|
if (resolveWait) {
|
|
2838
2934
|
resolveWait();
|
|
@@ -2843,6 +2939,7 @@ var DeepgramSTT = class {
|
|
|
2843
2939
|
ws.on("open", resolve);
|
|
2844
2940
|
ws.on("error", reject);
|
|
2845
2941
|
});
|
|
2942
|
+
this._log.info("Deepgram STT connected");
|
|
2846
2943
|
const feedPromise = (async () => {
|
|
2847
2944
|
try {
|
|
2848
2945
|
for await (const chunk of audioStream) {
|
|
@@ -2879,6 +2976,10 @@ var DeepgramSTT = class {
|
|
|
2879
2976
|
// src/agent/pipeline/elevenlabs-tts.ts
|
|
2880
2977
|
var ElevenLabsTTS = class {
|
|
2881
2978
|
_options;
|
|
2979
|
+
_log = NOOP_LOGGER;
|
|
2980
|
+
setLogger(logger) {
|
|
2981
|
+
this._log = logger;
|
|
2982
|
+
}
|
|
2882
2983
|
constructor(options = {}) {
|
|
2883
2984
|
this._options = {
|
|
2884
2985
|
voiceId: "EXAVITQu4vr4xnSDxMaL",
|
|
@@ -2978,7 +3079,7 @@ var ElevenLabsTTS = class {
|
|
|
2978
3079
|
}
|
|
2979
3080
|
});
|
|
2980
3081
|
ws.on("error", (err) => {
|
|
2981
|
-
|
|
3082
|
+
this._log.error({ err }, "ElevenLabs TTS error");
|
|
2982
3083
|
done = true;
|
|
2983
3084
|
if (resolveWait) {
|
|
2984
3085
|
resolveWait();
|
|
@@ -2989,16 +3090,19 @@ var ElevenLabsTTS = class {
|
|
|
2989
3090
|
ws.on("open", resolve);
|
|
2990
3091
|
ws.on("error", reject);
|
|
2991
3092
|
});
|
|
3093
|
+
this._log.info("ElevenLabs TTS connected");
|
|
2992
3094
|
const feedPromise = (async () => {
|
|
2993
3095
|
try {
|
|
2994
3096
|
for await (const chunk of textStream) {
|
|
2995
3097
|
if (done) break;
|
|
2996
3098
|
if (ws.readyState === 1) {
|
|
3099
|
+
this._log.debug("ElevenLabs sending text: %s", chunk.substring(0, 60));
|
|
2997
3100
|
ws.send(JSON.stringify({ text: chunk }));
|
|
2998
3101
|
}
|
|
2999
3102
|
}
|
|
3000
3103
|
} finally {
|
|
3001
3104
|
if (ws.readyState === 1) {
|
|
3105
|
+
this._log.debug("ElevenLabs sending EOS");
|
|
3002
3106
|
ws.send(JSON.stringify({ text: "" }));
|
|
3003
3107
|
}
|
|
3004
3108
|
}
|
|
@@ -3536,6 +3640,6 @@ function mcpServerHTTP(options) {
|
|
|
3536
3640
|
};
|
|
3537
3641
|
}
|
|
3538
3642
|
|
|
3539
|
-
export { AnthropicLLM, AudioRecorder, BuiltinTool, CallSession, ClawOpsAgent, DECODE_TABLE, DeepSeekLLM, DeepgramSTT, ElevenLabsTTS, FireworksLLM, GeminiLLM, GeminiRealtime, GroqLLM, MCPClient, MistralLLM, OllamaLLM, OpenAICompatLLM, OpenAILLM, OpenAIRealtime, PerplexityLLM, PipelineSession, TogetherLLM, ToolRegistry, XaiLLM, functionTool, getTracingConfig, mcpServerHTTP, mcpServerStdio, pcm16ToUlaw, resamplePcm16, resetTracingConfig, setTracingConfig, ulawToPcm16, zodToToolParams };
|
|
3643
|
+
export { AnthropicLLM, AudioRecorder, BuiltinTool, CallSession, ClawOpsAgent, DECODE_TABLE, DeepSeekLLM, DeepgramSTT, ElevenLabsTTS, FireworksLLM, GeminiLLM, GeminiRealtime, GroqLLM, MCPClient, MistralLLM, OllamaLLM, OpenAICompatLLM, OpenAILLM, OpenAIRealtime, PerplexityLLM, PipelineSession, TogetherLLM, ToolRegistry, XaiLLM, createAgentLogger, createPipelineLogger, functionTool, getTracingConfig, mcpServerHTTP, mcpServerStdio, pcm16ToUlaw, resamplePcm16, resetTracingConfig, setTracingConfig, ulawToPcm16, zodToToolParams };
|
|
3540
3644
|
//# sourceMappingURL=index.js.map
|
|
3541
3645
|
//# sourceMappingURL=index.js.map
|