@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.cjs
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunk6IQN5RQD_cjs = require('../chunk-6IQN5RQD.cjs');
|
|
4
|
+
var pino = require('pino');
|
|
4
5
|
var fs = require('fs');
|
|
5
6
|
var path = require('path');
|
|
6
7
|
|
|
8
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
|
|
7
10
|
function _interopNamespace(e) {
|
|
8
11
|
if (e && e.__esModule) return e;
|
|
9
12
|
var n = Object.create(null);
|
|
@@ -22,6 +25,7 @@ function _interopNamespace(e) {
|
|
|
22
25
|
return Object.freeze(n);
|
|
23
26
|
}
|
|
24
27
|
|
|
28
|
+
var pino__default = /*#__PURE__*/_interopDefault(pino);
|
|
25
29
|
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
26
30
|
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
27
31
|
|
|
@@ -345,6 +349,14 @@ function resamplePcm16(pcm, fromRate, toRate) {
|
|
|
345
349
|
}
|
|
346
350
|
return out;
|
|
347
351
|
}
|
|
352
|
+
var DEFAULT_LOGGER = pino__default.default({ name: "clawops.agent" });
|
|
353
|
+
var NOOP_LOGGER = pino__default.default({ level: "silent" });
|
|
354
|
+
function createAgentLogger(userLogger) {
|
|
355
|
+
return userLogger ?? DEFAULT_LOGGER;
|
|
356
|
+
}
|
|
357
|
+
function createPipelineLogger(parent) {
|
|
358
|
+
return parent.child({ module: "pipeline" });
|
|
359
|
+
}
|
|
348
360
|
|
|
349
361
|
// src/agent/control-ws.ts
|
|
350
362
|
var INITIAL_RECONNECT_DELAY = 1e3;
|
|
@@ -373,6 +385,10 @@ var ControlWebSocket = class {
|
|
|
373
385
|
_closed = false;
|
|
374
386
|
_connectedResolve = null;
|
|
375
387
|
_connectedPromise;
|
|
388
|
+
_log = NOOP_LOGGER;
|
|
389
|
+
setLogger(logger) {
|
|
390
|
+
this._log = logger;
|
|
391
|
+
}
|
|
376
392
|
/** Register an event handler for a specific event type. */
|
|
377
393
|
on(event, handler) {
|
|
378
394
|
let list = this._handlers.get(event);
|
|
@@ -420,13 +436,14 @@ var ControlWebSocket = class {
|
|
|
420
436
|
this._connectedResolve();
|
|
421
437
|
this._connectedResolve = null;
|
|
422
438
|
}
|
|
439
|
+
this._log.info("Control WS connected: %s", this._url);
|
|
423
440
|
});
|
|
424
441
|
ws.on("message", (data) => {
|
|
425
442
|
try {
|
|
426
443
|
const msg = JSON.parse(data.toString());
|
|
427
444
|
this._dispatchEvent(msg);
|
|
428
445
|
} catch {
|
|
429
|
-
|
|
446
|
+
this._log.warn("Control WS parse error");
|
|
430
447
|
}
|
|
431
448
|
});
|
|
432
449
|
ws.on("close", () => {
|
|
@@ -435,7 +452,7 @@ var ControlWebSocket = class {
|
|
|
435
452
|
}
|
|
436
453
|
});
|
|
437
454
|
ws.on("error", (err) => {
|
|
438
|
-
|
|
455
|
+
this._log.warn("Control WS error: %s", err.message);
|
|
439
456
|
});
|
|
440
457
|
}
|
|
441
458
|
_dispatchEvent(event) {
|
|
@@ -446,11 +463,11 @@ var ControlWebSocket = class {
|
|
|
446
463
|
const result = handler(event);
|
|
447
464
|
if (result && typeof result.catch === "function") {
|
|
448
465
|
result.catch((err) => {
|
|
449
|
-
|
|
466
|
+
this._log.error({ err }, "Control WS handler error: %s", event.event);
|
|
450
467
|
});
|
|
451
468
|
}
|
|
452
469
|
} catch (err) {
|
|
453
|
-
|
|
470
|
+
this._log.error({ err }, "Control WS handler error: %s", event.event);
|
|
454
471
|
}
|
|
455
472
|
}
|
|
456
473
|
}
|
|
@@ -458,10 +475,11 @@ var ControlWebSocket = class {
|
|
|
458
475
|
_scheduleReconnect() {
|
|
459
476
|
const delay = this._reconnectDelay;
|
|
460
477
|
this._reconnectDelay = Math.min(this._reconnectDelay * 2, MAX_RECONNECT_DELAY);
|
|
478
|
+
this._log.info("Control WS reconnecting in %ds...", delay / 1e3);
|
|
461
479
|
setTimeout(() => {
|
|
462
480
|
if (!this._closed) {
|
|
463
481
|
this._doConnect().catch((err) => {
|
|
464
|
-
|
|
482
|
+
this._log.warn({ err }, "Control WS reconnect failed");
|
|
465
483
|
this._scheduleReconnect();
|
|
466
484
|
});
|
|
467
485
|
}
|
|
@@ -473,6 +491,10 @@ var ControlWebSocket = class {
|
|
|
473
491
|
var MCPClient = class {
|
|
474
492
|
_servers = /* @__PURE__ */ new Map();
|
|
475
493
|
_clients = /* @__PURE__ */ new Map();
|
|
494
|
+
_log = NOOP_LOGGER;
|
|
495
|
+
setLogger(logger) {
|
|
496
|
+
this._log = logger;
|
|
497
|
+
}
|
|
476
498
|
/** Add an MCP server configuration. */
|
|
477
499
|
addServer(name, config) {
|
|
478
500
|
this._servers.set(name, config);
|
|
@@ -485,7 +507,7 @@ var MCPClient = class {
|
|
|
485
507
|
const tools = await this._connectServer(name, config);
|
|
486
508
|
allTools.push(...tools);
|
|
487
509
|
} catch (err) {
|
|
488
|
-
|
|
510
|
+
this._log.error({ err }, "MCP connection failed: %s", name);
|
|
489
511
|
}
|
|
490
512
|
}
|
|
491
513
|
return allTools;
|
|
@@ -494,12 +516,13 @@ var MCPClient = class {
|
|
|
494
516
|
async disconnect() {
|
|
495
517
|
for (const [name, client] of this._clients) {
|
|
496
518
|
try {
|
|
519
|
+
this._log.debug("MCP closing: %s", name);
|
|
497
520
|
const c = client;
|
|
498
521
|
if (c.close) {
|
|
499
522
|
await c.close();
|
|
500
523
|
}
|
|
501
524
|
} catch (err) {
|
|
502
|
-
|
|
525
|
+
this._log.error({ err }, "MCP disconnect error: %s", name);
|
|
503
526
|
}
|
|
504
527
|
}
|
|
505
528
|
this._clients.clear();
|
|
@@ -508,6 +531,11 @@ var MCPClient = class {
|
|
|
508
531
|
const sdk = await import('@modelcontextprotocol/sdk/client/index.js');
|
|
509
532
|
const { Client } = sdk;
|
|
510
533
|
const client = new Client({ name: `clawops-${name}`, version: "1.0.0" });
|
|
534
|
+
if (config.type === "stdio") {
|
|
535
|
+
this._log.debug("MCP connecting (stdio): %s", config["command"]);
|
|
536
|
+
} else if (config.type === "http") {
|
|
537
|
+
this._log.debug("MCP connecting (http): %s", config["url"]);
|
|
538
|
+
}
|
|
511
539
|
let transport;
|
|
512
540
|
if (config.type === "stdio") {
|
|
513
541
|
const { StdioClientTransport } = await import('@modelcontextprotocol/sdk/client/stdio.js');
|
|
@@ -536,6 +564,7 @@ var MCPClient = class {
|
|
|
536
564
|
parameters: inputSchema.properties ?? {},
|
|
537
565
|
required: inputSchema.required ?? [],
|
|
538
566
|
handler: async (args) => {
|
|
567
|
+
this._log.debug("MCP call_tool: %s", toolDef.name);
|
|
539
568
|
const result = await client.callTool({
|
|
540
569
|
name: toolDef.name,
|
|
541
570
|
arguments: args
|
|
@@ -548,6 +577,8 @@ var MCPClient = class {
|
|
|
548
577
|
}
|
|
549
578
|
});
|
|
550
579
|
}
|
|
580
|
+
this._log.info("MCP server connected: %d tools found", tools.length);
|
|
581
|
+
this._log.debug("MCP tools: %s", tools.map((t) => t.name));
|
|
551
582
|
return tools;
|
|
552
583
|
}
|
|
553
584
|
};
|
|
@@ -602,6 +633,10 @@ var MediaWebSocket = class {
|
|
|
602
633
|
_onClose = null;
|
|
603
634
|
_onDtmf = null;
|
|
604
635
|
_markWaiters = /* @__PURE__ */ new Map();
|
|
636
|
+
_log = NOOP_LOGGER;
|
|
637
|
+
setLogger(logger) {
|
|
638
|
+
this._log = logger;
|
|
639
|
+
}
|
|
605
640
|
/** Set the handler for inbound audio data. */
|
|
606
641
|
onAudio(handler) {
|
|
607
642
|
this._onAudio = handler;
|
|
@@ -643,6 +678,7 @@ var MediaWebSocket = class {
|
|
|
643
678
|
ws.on("open", () => {
|
|
644
679
|
this._startSendLoop();
|
|
645
680
|
resolve();
|
|
681
|
+
this._log.info("Media WS connected: %s", url);
|
|
646
682
|
});
|
|
647
683
|
ws.on("message", (data) => {
|
|
648
684
|
try {
|
|
@@ -661,7 +697,7 @@ var MediaWebSocket = class {
|
|
|
661
697
|
if (!this._ws) {
|
|
662
698
|
reject(err);
|
|
663
699
|
}
|
|
664
|
-
|
|
700
|
+
this._log.error({ err }, "Media WS error");
|
|
665
701
|
});
|
|
666
702
|
});
|
|
667
703
|
}
|
|
@@ -822,6 +858,10 @@ var AudioRecorder = class {
|
|
|
822
858
|
_mixWritten = 0;
|
|
823
859
|
_startTime = 0;
|
|
824
860
|
_started = false;
|
|
861
|
+
_log = NOOP_LOGGER;
|
|
862
|
+
setLogger(logger) {
|
|
863
|
+
this._log = logger;
|
|
864
|
+
}
|
|
825
865
|
constructor(recordingPath, callId) {
|
|
826
866
|
this._dir = path__namespace.join(recordingPath, callId);
|
|
827
867
|
}
|
|
@@ -836,6 +876,7 @@ var AudioRecorder = class {
|
|
|
836
876
|
fs__namespace.writeSync(this._fdMix, header);
|
|
837
877
|
this._startTime = performance.now();
|
|
838
878
|
this._started = true;
|
|
879
|
+
this._log.info("Recording started: %s", this._dir);
|
|
839
880
|
}
|
|
840
881
|
_expectedBytes() {
|
|
841
882
|
const elapsed = (performance.now() - this._startTime) / 1e3;
|
|
@@ -888,7 +929,7 @@ var AudioRecorder = class {
|
|
|
888
929
|
this._inWritten += pcm16_8k.length;
|
|
889
930
|
this._writeToMix(pcm16_8k, posBefore);
|
|
890
931
|
} catch (err) {
|
|
891
|
-
|
|
932
|
+
this._log.error({ err }, "Recording write error (inbound)");
|
|
892
933
|
}
|
|
893
934
|
}
|
|
894
935
|
writeOutbound(pcm16_8k) {
|
|
@@ -901,7 +942,7 @@ var AudioRecorder = class {
|
|
|
901
942
|
this._outWritten += pcm16_8k.length;
|
|
902
943
|
this._writeToMix(pcm16_8k, posBefore);
|
|
903
944
|
} catch (err) {
|
|
904
|
-
|
|
945
|
+
this._log.error({ err }, "Recording write error (outbound)");
|
|
905
946
|
}
|
|
906
947
|
}
|
|
907
948
|
stop() {
|
|
@@ -922,8 +963,10 @@ var AudioRecorder = class {
|
|
|
922
963
|
fs__namespace.writeSync(fd, makeWavHeader(maxWritten), 0, 44, 0);
|
|
923
964
|
fs__namespace.closeSync(fd);
|
|
924
965
|
}
|
|
966
|
+
const maxSec = maxWritten / 16e3;
|
|
967
|
+
this._log.info("Recording stopped: %s (%ds)", this._dir, maxSec);
|
|
925
968
|
} catch (err) {
|
|
926
|
-
|
|
969
|
+
this._log.error({ err }, "Recording stop error");
|
|
927
970
|
} finally {
|
|
928
971
|
this._fdIn = null;
|
|
929
972
|
this._fdOut = null;
|
|
@@ -953,6 +996,7 @@ var CallSession = class {
|
|
|
953
996
|
_dtmfCollectorActive = false;
|
|
954
997
|
_dtmfResolvers = [];
|
|
955
998
|
_dtmfBuffer = [];
|
|
999
|
+
_log = NOOP_LOGGER;
|
|
956
1000
|
_handlers = /* @__PURE__ */ new Map();
|
|
957
1001
|
_endedPromise;
|
|
958
1002
|
_resolveEnded;
|
|
@@ -969,6 +1013,9 @@ var CallSession = class {
|
|
|
969
1013
|
this._resolveEnded = resolve;
|
|
970
1014
|
});
|
|
971
1015
|
}
|
|
1016
|
+
setLogger(logger) {
|
|
1017
|
+
this._log = logger;
|
|
1018
|
+
}
|
|
972
1019
|
get status() {
|
|
973
1020
|
return this._status;
|
|
974
1021
|
}
|
|
@@ -1044,7 +1091,9 @@ var CallSession = class {
|
|
|
1044
1091
|
this._dtmfResolvers = [];
|
|
1045
1092
|
this._dtmfBuffer = [];
|
|
1046
1093
|
}
|
|
1047
|
-
|
|
1094
|
+
const result = collected.join("");
|
|
1095
|
+
this._log.info("DTMF collected: %s", result);
|
|
1096
|
+
return result;
|
|
1048
1097
|
}
|
|
1049
1098
|
/** Send a sequence of DTMF digits. */
|
|
1050
1099
|
async sendDtmfSequence(digits) {
|
|
@@ -1096,11 +1145,11 @@ var CallSession = class {
|
|
|
1096
1145
|
const result = handler(this, ...args);
|
|
1097
1146
|
if (result && typeof result.catch === "function") {
|
|
1098
1147
|
result.catch((err) => {
|
|
1099
|
-
|
|
1148
|
+
this._log.error({ err }, "CallSession handler error: %s", event);
|
|
1100
1149
|
});
|
|
1101
1150
|
}
|
|
1102
1151
|
} catch (err) {
|
|
1103
|
-
|
|
1152
|
+
this._log.error({ err }, "CallSession handler error: %s", event);
|
|
1104
1153
|
}
|
|
1105
1154
|
}
|
|
1106
1155
|
}
|
|
@@ -1348,6 +1397,9 @@ var ClawOpsAgent = class {
|
|
|
1348
1397
|
_passiveDtmfTimer = null;
|
|
1349
1398
|
_passiveDtmfCallId = null;
|
|
1350
1399
|
_callSessions = /* @__PURE__ */ new Map();
|
|
1400
|
+
_log;
|
|
1401
|
+
_pipelineLog;
|
|
1402
|
+
_isPipelineSession = false;
|
|
1351
1403
|
constructor(options) {
|
|
1352
1404
|
this._apiKey = options.apiKey ?? process.env["CLAWOPS_API_KEY"] ?? "";
|
|
1353
1405
|
this._accountId = options.accountId ?? process.env["CLAWOPS_ACCOUNT_ID"] ?? "";
|
|
@@ -1362,6 +1414,9 @@ var ClawOpsAgent = class {
|
|
|
1362
1414
|
if (options.tracing) {
|
|
1363
1415
|
setTracingConfig(options.tracing);
|
|
1364
1416
|
}
|
|
1417
|
+
this._log = createAgentLogger(options.logger);
|
|
1418
|
+
this._pipelineLog = createPipelineLogger(this._log);
|
|
1419
|
+
this._isPipelineSession = "_stt" in this._session && "_llm" in this._session;
|
|
1365
1420
|
}
|
|
1366
1421
|
/**
|
|
1367
1422
|
* Register a function tool.
|
|
@@ -1421,6 +1476,7 @@ var ClawOpsAgent = class {
|
|
|
1421
1476
|
accountId: this._accountId,
|
|
1422
1477
|
number: this._fromNumber
|
|
1423
1478
|
});
|
|
1479
|
+
this._controlWs.setLogger(this._log);
|
|
1424
1480
|
this._controlWs.on("call.incoming", (event) => this._handleIncoming(event));
|
|
1425
1481
|
this._controlWs.on("call.ended", (event) => this._handleEnded(event));
|
|
1426
1482
|
this._controlWs.on("call.outbound_ready", (event) => this._handleOutboundReady(event));
|
|
@@ -1434,7 +1490,7 @@ var ClawOpsAgent = class {
|
|
|
1434
1490
|
`Failed to connect to ClawOps: ${err instanceof Error ? err.message : String(err)}`
|
|
1435
1491
|
);
|
|
1436
1492
|
}
|
|
1437
|
-
|
|
1493
|
+
this._log.info("ClawOpsAgent connected on %s", this._fromNumber);
|
|
1438
1494
|
}
|
|
1439
1495
|
/**
|
|
1440
1496
|
* Connect and block until disconnected.
|
|
@@ -1461,7 +1517,7 @@ var ClawOpsAgent = class {
|
|
|
1461
1517
|
}
|
|
1462
1518
|
this._activeSessions.clear();
|
|
1463
1519
|
this._callSessions.clear();
|
|
1464
|
-
|
|
1520
|
+
this._log.info("ClawOpsAgent disconnected");
|
|
1465
1521
|
}
|
|
1466
1522
|
/**
|
|
1467
1523
|
* Initiate an outbound call.
|
|
@@ -1496,10 +1552,9 @@ var ClawOpsAgent = class {
|
|
|
1496
1552
|
callSession.on(evt, handler);
|
|
1497
1553
|
}
|
|
1498
1554
|
}
|
|
1555
|
+
callSession.setLogger(this._log);
|
|
1499
1556
|
this._activeSessions.set(callSession.callId, callSession);
|
|
1500
|
-
|
|
1501
|
-
`[ClawOpsAgent] Outbound call initiated: ${this._fromNumber} -> ${to} (${callSession.callId})`
|
|
1502
|
-
);
|
|
1557
|
+
this._log.info("Outbound call initiated: %s -> %s (%s)", this._fromNumber, to, callSession.callId);
|
|
1503
1558
|
return callSession;
|
|
1504
1559
|
}
|
|
1505
1560
|
_handleIncoming(event) {
|
|
@@ -1518,13 +1573,15 @@ var ClawOpsAgent = class {
|
|
|
1518
1573
|
session.on(evt, handler);
|
|
1519
1574
|
}
|
|
1520
1575
|
}
|
|
1576
|
+
session.setLogger(this._log);
|
|
1521
1577
|
this._activeSessions.set(callId, session);
|
|
1578
|
+
this._log.info("Incoming call: %s -> %s (%s)", fromNumber, this._fromNumber, callId);
|
|
1522
1579
|
if (this._controlWs) {
|
|
1523
1580
|
this._controlWs.send({ event: "call.accept", callId });
|
|
1524
1581
|
}
|
|
1525
1582
|
if (mediaUrl) {
|
|
1526
1583
|
this._startCallSession(session, mediaUrl).catch((err) => {
|
|
1527
|
-
|
|
1584
|
+
this._log.error({ err }, "Call session error: %s", callId);
|
|
1528
1585
|
});
|
|
1529
1586
|
}
|
|
1530
1587
|
}
|
|
@@ -1532,6 +1589,7 @@ var ClawOpsAgent = class {
|
|
|
1532
1589
|
const callId = event["callId"];
|
|
1533
1590
|
const session = this._activeSessions.get(callId);
|
|
1534
1591
|
if (session) {
|
|
1592
|
+
this._log.info("Call ended (server): %s", callId);
|
|
1535
1593
|
session._markEnded();
|
|
1536
1594
|
this._activeSessions.delete(callId);
|
|
1537
1595
|
}
|
|
@@ -1548,6 +1606,7 @@ var ClawOpsAgent = class {
|
|
|
1548
1606
|
accountId: this._accountId,
|
|
1549
1607
|
direction: "outbound"
|
|
1550
1608
|
});
|
|
1609
|
+
session.setLogger(this._log);
|
|
1551
1610
|
for (const [evt, handlers] of this._handlers) {
|
|
1552
1611
|
for (const handler of handlers) {
|
|
1553
1612
|
session.on(evt, handler);
|
|
@@ -1556,8 +1615,9 @@ var ClawOpsAgent = class {
|
|
|
1556
1615
|
this._activeSessions.set(callId, session);
|
|
1557
1616
|
}
|
|
1558
1617
|
if (mediaUrl) {
|
|
1618
|
+
this._log.info("Outbound call answered: %s -> %s (%s)", this._fromNumber, session.toNumber, callId);
|
|
1559
1619
|
this._startCallSession(session, mediaUrl).catch((err) => {
|
|
1560
|
-
|
|
1620
|
+
this._log.error({ err }, "Call session error: %s", callId);
|
|
1561
1621
|
});
|
|
1562
1622
|
}
|
|
1563
1623
|
}
|
|
@@ -1565,13 +1625,14 @@ var ClawOpsAgent = class {
|
|
|
1565
1625
|
const callId = event["callId"];
|
|
1566
1626
|
const session = this._activeSessions.get(callId);
|
|
1567
1627
|
if (session) {
|
|
1568
|
-
|
|
1628
|
+
this._log.info("Outbound call ringing: %s", callId);
|
|
1569
1629
|
}
|
|
1570
1630
|
}
|
|
1571
1631
|
_handleFailed(event) {
|
|
1572
1632
|
const callId = event["callId"];
|
|
1573
1633
|
const session = this._activeSessions.get(callId);
|
|
1574
1634
|
if (session) {
|
|
1635
|
+
this._log.info("Outbound call failed: %s (%s)", callId, event["reason"] ?? "failed");
|
|
1575
1636
|
session._emit("call_failed", event["reason"] ?? "failed");
|
|
1576
1637
|
session._markEnded();
|
|
1577
1638
|
this._activeSessions.delete(callId);
|
|
@@ -1596,7 +1657,7 @@ var ClawOpsAgent = class {
|
|
|
1596
1657
|
this._passiveDtmfCallId = null;
|
|
1597
1658
|
if (digits && sessionHandler && sessionHandler.feedDtmf) {
|
|
1598
1659
|
sessionHandler.feedDtmf(digits).catch((err) => {
|
|
1599
|
-
|
|
1660
|
+
this._log.error({ err }, "DTMF feed error");
|
|
1600
1661
|
});
|
|
1601
1662
|
}
|
|
1602
1663
|
}, this._passiveDtmfDebounceMs);
|
|
@@ -1615,22 +1676,25 @@ var ClawOpsAgent = class {
|
|
|
1615
1676
|
if (this._mcpServers.length > 0) {
|
|
1616
1677
|
for (const serverConfig of this._mcpServers) {
|
|
1617
1678
|
const client = new MCPClient();
|
|
1679
|
+
client.setLogger(this._log);
|
|
1618
1680
|
client.addServer("mcp", serverConfig);
|
|
1619
1681
|
try {
|
|
1620
1682
|
const tools = await client.connect();
|
|
1621
1683
|
sessionTools.registerMcpTools(tools);
|
|
1622
1684
|
mcpClients.push(client);
|
|
1623
1685
|
} catch (err) {
|
|
1624
|
-
|
|
1686
|
+
this._log.error({ err }, "MCP connection error");
|
|
1625
1687
|
}
|
|
1626
1688
|
}
|
|
1627
1689
|
}
|
|
1628
1690
|
let recorder = null;
|
|
1629
1691
|
if (this._recording) {
|
|
1630
1692
|
recorder = new AudioRecorder(this._recordingPath, session.callId);
|
|
1693
|
+
recorder.setLogger(this._log);
|
|
1631
1694
|
recorder.start();
|
|
1632
1695
|
}
|
|
1633
1696
|
const mediaWs = new MediaWebSocket();
|
|
1697
|
+
mediaWs.setLogger(this._log);
|
|
1634
1698
|
session._bindTransport(
|
|
1635
1699
|
(audio) => {
|
|
1636
1700
|
mediaWs.sendAudio(audio.toString("base64"));
|
|
@@ -1660,6 +1724,9 @@ var ClawOpsAgent = class {
|
|
|
1660
1724
|
if ("setBuiltinTools" in sessionHandler && typeof sessionHandler.setBuiltinTools === "function") {
|
|
1661
1725
|
sessionHandler.setBuiltinTools(this._builtinTools);
|
|
1662
1726
|
}
|
|
1727
|
+
if ("setLogger" in sessionHandler && typeof sessionHandler.setLogger === "function") {
|
|
1728
|
+
sessionHandler.setLogger(this._isPipelineSession ? this._pipelineLog : this._log);
|
|
1729
|
+
}
|
|
1663
1730
|
this._callSessions.set(session.callId, sessionHandler);
|
|
1664
1731
|
mediaWs.onAudio((ulawAudio, _timestamp) => {
|
|
1665
1732
|
if (sessionHandler) {
|
|
@@ -1673,6 +1740,7 @@ var ClawOpsAgent = class {
|
|
|
1673
1740
|
this._onDtmfEvent(session, digit);
|
|
1674
1741
|
});
|
|
1675
1742
|
mediaWs.onClose(() => {
|
|
1743
|
+
this._log.info("Media stream stopped: %s", session.callId);
|
|
1676
1744
|
if (recorder) {
|
|
1677
1745
|
recorder.stop();
|
|
1678
1746
|
}
|
|
@@ -1681,11 +1749,12 @@ var ClawOpsAgent = class {
|
|
|
1681
1749
|
session._emit("call_start");
|
|
1682
1750
|
try {
|
|
1683
1751
|
await mediaWs.connect(mediaWsUrl, this._apiKey);
|
|
1752
|
+
this._log.info("Media stream started: %s", session.callId);
|
|
1684
1753
|
await sessionHandler.start(session, sessionTools);
|
|
1685
1754
|
await session.wait();
|
|
1686
1755
|
await sessionHandler.stop();
|
|
1687
1756
|
} catch (err) {
|
|
1688
|
-
|
|
1757
|
+
this._log.error({ err }, "Call session error: %s", session.callId);
|
|
1689
1758
|
} finally {
|
|
1690
1759
|
if (mcpClients.length > 0) {
|
|
1691
1760
|
sessionTools.clearMcpTools();
|
|
@@ -1713,7 +1782,11 @@ var HANG_UP_TOOL = {
|
|
|
1713
1782
|
type: "function",
|
|
1714
1783
|
name: "hang_up",
|
|
1715
1784
|
description: "End the phone call. Use when the conversation is finished or the caller says goodbye.",
|
|
1716
|
-
parameters: {
|
|
1785
|
+
parameters: {
|
|
1786
|
+
type: "object",
|
|
1787
|
+
properties: {},
|
|
1788
|
+
required: []
|
|
1789
|
+
}
|
|
1717
1790
|
};
|
|
1718
1791
|
var COLLECT_DTMF_TOOL = {
|
|
1719
1792
|
type: "function",
|
|
@@ -1736,7 +1809,10 @@ var SEND_DTMF_TOOL = {
|
|
|
1736
1809
|
parameters: {
|
|
1737
1810
|
type: "object",
|
|
1738
1811
|
properties: {
|
|
1739
|
-
digits: {
|
|
1812
|
+
digits: {
|
|
1813
|
+
type: "string",
|
|
1814
|
+
description: "\uC804\uC1A1\uD560 \uBC88\uD638 (0-9, *, #). 'w'\uB294 500ms \uB300\uAE30, 'W'\uB294 1000ms \uB300\uAE30."
|
|
1815
|
+
}
|
|
1740
1816
|
},
|
|
1741
1817
|
required: ["digits"]
|
|
1742
1818
|
}
|
|
@@ -1749,7 +1825,11 @@ var OpenAIRealtime = class {
|
|
|
1749
1825
|
_language;
|
|
1750
1826
|
_eagerness;
|
|
1751
1827
|
_greeting;
|
|
1828
|
+
_log = NOOP_LOGGER;
|
|
1752
1829
|
_builtinTools = null;
|
|
1830
|
+
setLogger(logger) {
|
|
1831
|
+
this._log = logger;
|
|
1832
|
+
}
|
|
1753
1833
|
setBuiltinTools(tools) {
|
|
1754
1834
|
this._builtinTools = tools;
|
|
1755
1835
|
}
|
|
@@ -1806,6 +1886,7 @@ var OpenAIRealtime = class {
|
|
|
1806
1886
|
const ws = this._ws;
|
|
1807
1887
|
ws.on("open", () => {
|
|
1808
1888
|
this._sendSessionUpdate();
|
|
1889
|
+
this._log.info("OpenAI Realtime connected");
|
|
1809
1890
|
if (this._greeting) {
|
|
1810
1891
|
this._send({ type: "response.create" });
|
|
1811
1892
|
}
|
|
@@ -1825,7 +1906,7 @@ var OpenAIRealtime = class {
|
|
|
1825
1906
|
if (!this._ws) {
|
|
1826
1907
|
reject(err);
|
|
1827
1908
|
}
|
|
1828
|
-
|
|
1909
|
+
this._log.error({ err }, "OpenAI Realtime WS error");
|
|
1829
1910
|
});
|
|
1830
1911
|
});
|
|
1831
1912
|
}
|
|
@@ -1859,9 +1940,12 @@ var OpenAIRealtime = class {
|
|
|
1859
1940
|
_sendSessionUpdate() {
|
|
1860
1941
|
if (!this._ws || this._ws.readyState !== 1) return;
|
|
1861
1942
|
const toolSchemas = this._tools ? this._tools.toOpenAITools().map((t) => ({ type: "function", ...t.function })) : [];
|
|
1862
|
-
if (!this._builtinTools || this._builtinTools.has("hang_up" /* HANG_UP */))
|
|
1863
|
-
|
|
1864
|
-
if (!this._builtinTools || this._builtinTools.has("
|
|
1943
|
+
if (!this._builtinTools || this._builtinTools.has("hang_up" /* HANG_UP */))
|
|
1944
|
+
toolSchemas.push(HANG_UP_TOOL);
|
|
1945
|
+
if (!this._builtinTools || this._builtinTools.has("collect_dtmf" /* COLLECT_DTMF */))
|
|
1946
|
+
toolSchemas.push(COLLECT_DTMF_TOOL);
|
|
1947
|
+
if (!this._builtinTools || this._builtinTools.has("send_dtmf" /* SEND_DTMF */))
|
|
1948
|
+
toolSchemas.push(SEND_DTMF_TOOL);
|
|
1865
1949
|
this._send({
|
|
1866
1950
|
type: "session.update",
|
|
1867
1951
|
session: {
|
|
@@ -1871,7 +1955,7 @@ var OpenAIRealtime = class {
|
|
|
1871
1955
|
input_audio_format: "g711_ulaw",
|
|
1872
1956
|
output_audio_format: "g711_ulaw",
|
|
1873
1957
|
input_audio_transcription: {
|
|
1874
|
-
model: "
|
|
1958
|
+
model: "whisper-1",
|
|
1875
1959
|
language: this._language
|
|
1876
1960
|
},
|
|
1877
1961
|
input_audio_noise_reduction: { type: "far_field" },
|
|
@@ -1942,7 +2026,7 @@ var OpenAIRealtime = class {
|
|
|
1942
2026
|
break;
|
|
1943
2027
|
}
|
|
1944
2028
|
case "error": {
|
|
1945
|
-
|
|
2029
|
+
this._log.error({ apiError: msg["error"] }, "OpenAI error");
|
|
1946
2030
|
break;
|
|
1947
2031
|
}
|
|
1948
2032
|
}
|
|
@@ -1992,6 +2076,7 @@ var OpenAIRealtime = class {
|
|
|
1992
2076
|
async _handleToolCall(item) {
|
|
1993
2077
|
const funcName = item["name"];
|
|
1994
2078
|
const callId = item["call_id"];
|
|
2079
|
+
this._log.info("Tool call: %s", funcName);
|
|
1995
2080
|
if (funcName === "hang_up") {
|
|
1996
2081
|
if (this._call) {
|
|
1997
2082
|
await this._call.hangup();
|
|
@@ -2048,7 +2133,7 @@ var OpenAIRealtime = class {
|
|
|
2048
2133
|
return;
|
|
2049
2134
|
}
|
|
2050
2135
|
if (!this._tools || !this._tools.has(funcName)) {
|
|
2051
|
-
|
|
2136
|
+
this._log.error("Unknown tool: %s", funcName);
|
|
2052
2137
|
return;
|
|
2053
2138
|
}
|
|
2054
2139
|
let result;
|
|
@@ -2056,7 +2141,7 @@ var OpenAIRealtime = class {
|
|
|
2056
2141
|
const args = JSON.parse(item["arguments"] ?? "{}");
|
|
2057
2142
|
result = await this._tools.call(funcName, args);
|
|
2058
2143
|
} catch (err) {
|
|
2059
|
-
|
|
2144
|
+
this._log.error({ err }, "Tool call failed: %s", funcName);
|
|
2060
2145
|
result = `Error: ${err}`;
|
|
2061
2146
|
}
|
|
2062
2147
|
await this._waitForResponseDone();
|
|
@@ -2205,6 +2290,7 @@ var GeminiRealtime = class {
|
|
|
2205
2290
|
_audioRemainder = Buffer.alloc(0);
|
|
2206
2291
|
_builtinTools = null;
|
|
2207
2292
|
_toolCallInProgress = false;
|
|
2293
|
+
_log = NOOP_LOGGER;
|
|
2208
2294
|
constructor(options = {}) {
|
|
2209
2295
|
this._apiKey = options.apiKey ?? process.env["GOOGLE_API_KEY"] ?? "";
|
|
2210
2296
|
this._systemPrompt = options.systemPrompt ?? "";
|
|
@@ -2224,6 +2310,9 @@ var GeminiRealtime = class {
|
|
|
2224
2310
|
setBuiltinTools(tools) {
|
|
2225
2311
|
this._builtinTools = tools;
|
|
2226
2312
|
}
|
|
2313
|
+
setLogger(logger) {
|
|
2314
|
+
this._log = logger;
|
|
2315
|
+
}
|
|
2227
2316
|
async start(callSession, tools) {
|
|
2228
2317
|
this._call = callSession;
|
|
2229
2318
|
if (tools) this._tools = tools;
|
|
@@ -2260,12 +2349,10 @@ var GeminiRealtime = class {
|
|
|
2260
2349
|
callbacks: {
|
|
2261
2350
|
onmessage: (msg) => this._handleMessage(msg),
|
|
2262
2351
|
onerror: (err) => {
|
|
2263
|
-
|
|
2352
|
+
this._log.error({ err }, "Gemini SDK error");
|
|
2264
2353
|
},
|
|
2265
2354
|
onclose: (ev) => {
|
|
2266
|
-
|
|
2267
|
-
`[GeminiRealtime] Connection closed: code=${ev?.code ?? "unknown"}`
|
|
2268
|
-
);
|
|
2355
|
+
this._log.info({ code: ev?.code ?? "unknown" }, "Gemini connection closed");
|
|
2269
2356
|
this._closed = true;
|
|
2270
2357
|
}
|
|
2271
2358
|
}
|
|
@@ -2345,11 +2432,11 @@ var GeminiRealtime = class {
|
|
|
2345
2432
|
}
|
|
2346
2433
|
}
|
|
2347
2434
|
if (serverContent.turnComplete) {
|
|
2348
|
-
|
|
2435
|
+
this._log.debug("Turn complete");
|
|
2349
2436
|
this._flushAudioRemainder();
|
|
2350
2437
|
}
|
|
2351
2438
|
if (serverContent.interrupted) {
|
|
2352
|
-
|
|
2439
|
+
this._log.info("Barge-in detected");
|
|
2353
2440
|
if (this._call) {
|
|
2354
2441
|
this._call.clearAudio();
|
|
2355
2442
|
}
|
|
@@ -2358,12 +2445,12 @@ var GeminiRealtime = class {
|
|
|
2358
2445
|
}
|
|
2359
2446
|
const inputText = serverContent.inputTranscription?.text;
|
|
2360
2447
|
if (inputText && this._call) {
|
|
2361
|
-
|
|
2448
|
+
this._log.info("User: %s", inputText);
|
|
2362
2449
|
this._call._emit("transcript", "user", inputText);
|
|
2363
2450
|
}
|
|
2364
2451
|
const outputText = serverContent.outputTranscription?.text;
|
|
2365
2452
|
if (outputText && this._call) {
|
|
2366
|
-
|
|
2453
|
+
this._log.info("Assistant: %s", outputText);
|
|
2367
2454
|
this._call._emit("transcript", "assistant", outputText);
|
|
2368
2455
|
}
|
|
2369
2456
|
}
|
|
@@ -2372,9 +2459,7 @@ var GeminiRealtime = class {
|
|
|
2372
2459
|
}
|
|
2373
2460
|
const toolCancellation = msg["toolCallCancellation"];
|
|
2374
2461
|
if (toolCancellation) {
|
|
2375
|
-
|
|
2376
|
-
`[GeminiRealtime] Tool call cancelled: ${(toolCancellation.ids ?? []).join(", ")}`
|
|
2377
|
-
);
|
|
2462
|
+
this._log.info({ ids: toolCancellation.ids }, "Tool call cancelled");
|
|
2378
2463
|
}
|
|
2379
2464
|
}
|
|
2380
2465
|
_handleAudioData(b64Data) {
|
|
@@ -2409,17 +2494,14 @@ var GeminiRealtime = class {
|
|
|
2409
2494
|
const functionCalls = toolCall.functionCalls;
|
|
2410
2495
|
if (!functionCalls) return;
|
|
2411
2496
|
this._toolCallInProgress = true;
|
|
2412
|
-
console.log(
|
|
2413
|
-
`[GeminiRealtime] toolCall: ${functionCalls.map((fc) => fc.name).join(", ")}`
|
|
2414
|
-
);
|
|
2415
2497
|
const responses = [];
|
|
2416
2498
|
for (const fc of functionCalls) {
|
|
2417
2499
|
const name = fc.name ?? "";
|
|
2418
2500
|
const fcId = fc.id ?? "";
|
|
2419
2501
|
const args = fc.args ?? {};
|
|
2420
|
-
|
|
2502
|
+
this._log.info({ tool: name, args }, "Tool call: %s", name);
|
|
2421
2503
|
if (name === "hang_up") {
|
|
2422
|
-
|
|
2504
|
+
this._log.info("hang_up: ending call");
|
|
2423
2505
|
if (this._call) {
|
|
2424
2506
|
await this._call.hangup();
|
|
2425
2507
|
}
|
|
@@ -2429,17 +2511,15 @@ var GeminiRealtime = class {
|
|
|
2429
2511
|
if (this._call) {
|
|
2430
2512
|
let result;
|
|
2431
2513
|
try {
|
|
2432
|
-
|
|
2433
|
-
`[GeminiRealtime] collect_dtmf: waiting for digits (maxDigits=${args["max_digits"] ?? 4}, timeout=${args["timeout"] ?? 5})`
|
|
2434
|
-
);
|
|
2514
|
+
this._log.info({ maxDigits: args["max_digits"] ?? 4, timeout: args["timeout"] ?? 5 }, "collect_dtmf: waiting for digits");
|
|
2435
2515
|
result = await this._call.collectDtmf({
|
|
2436
2516
|
maxDigits: args["max_digits"] ?? 4,
|
|
2437
2517
|
finishOnKey: args["finish_on_key"] ?? "#",
|
|
2438
2518
|
timeout: args["timeout"] ?? 5
|
|
2439
2519
|
});
|
|
2440
|
-
|
|
2520
|
+
this._log.info("DTMF collected: %s", result || "(empty)");
|
|
2441
2521
|
} catch (err) {
|
|
2442
|
-
|
|
2522
|
+
this._log.error({ err }, "collect_dtmf error");
|
|
2443
2523
|
result = `Error: ${err}`;
|
|
2444
2524
|
}
|
|
2445
2525
|
responses.push({
|
|
@@ -2454,12 +2534,12 @@ var GeminiRealtime = class {
|
|
|
2454
2534
|
if (this._call) {
|
|
2455
2535
|
let result;
|
|
2456
2536
|
try {
|
|
2457
|
-
|
|
2537
|
+
this._log.info('send_dtmf: digits="%s"', args["digits"] ?? "");
|
|
2458
2538
|
await this._call.sendDtmfSequence(args["digits"] ?? "");
|
|
2459
2539
|
result = "sent";
|
|
2460
|
-
|
|
2540
|
+
this._log.info("send_dtmf: sent");
|
|
2461
2541
|
} catch (err) {
|
|
2462
|
-
|
|
2542
|
+
this._log.error({ err }, "send_dtmf error");
|
|
2463
2543
|
result = `Error: ${err}`;
|
|
2464
2544
|
}
|
|
2465
2545
|
responses.push({ id: fcId, name, response: { result } });
|
|
@@ -2467,21 +2547,21 @@ var GeminiRealtime = class {
|
|
|
2467
2547
|
continue;
|
|
2468
2548
|
}
|
|
2469
2549
|
if (!this._tools || !this._tools.has(name)) {
|
|
2470
|
-
|
|
2550
|
+
this._log.error("Unknown tool: %s", name);
|
|
2471
2551
|
responses.push({ id: fcId, name, response: { error: `Unknown tool: ${name}` } });
|
|
2472
2552
|
continue;
|
|
2473
2553
|
}
|
|
2474
2554
|
try {
|
|
2475
2555
|
const result = await this._tools.call(name, args);
|
|
2476
2556
|
const resultStr = typeof result === "string" ? result : JSON.stringify(result);
|
|
2477
|
-
|
|
2557
|
+
this._log.info("Tool result: %s -> %s", name, resultStr.substring(0, 200));
|
|
2478
2558
|
responses.push({
|
|
2479
2559
|
id: fcId,
|
|
2480
2560
|
name,
|
|
2481
2561
|
response: { result: resultStr }
|
|
2482
2562
|
});
|
|
2483
2563
|
} catch (err) {
|
|
2484
|
-
|
|
2564
|
+
this._log.error({ err }, "Tool call failed: %s", name);
|
|
2485
2565
|
responses.push({
|
|
2486
2566
|
id: fcId,
|
|
2487
2567
|
name,
|
|
@@ -2490,7 +2570,7 @@ var GeminiRealtime = class {
|
|
|
2490
2570
|
}
|
|
2491
2571
|
}
|
|
2492
2572
|
if (responses.length > 0 && this._session) {
|
|
2493
|
-
|
|
2573
|
+
this._log.debug("Sending %d tool response(s)", responses.length);
|
|
2494
2574
|
this._session.sendToolResponse({
|
|
2495
2575
|
functionResponses: responses
|
|
2496
2576
|
});
|
|
@@ -2543,6 +2623,7 @@ var PipelineSession = class {
|
|
|
2543
2623
|
_running = false;
|
|
2544
2624
|
_speaking = false;
|
|
2545
2625
|
_builtinTools = null;
|
|
2626
|
+
_log = NOOP_LOGGER;
|
|
2546
2627
|
constructor(options) {
|
|
2547
2628
|
this._stt = options.stt;
|
|
2548
2629
|
this._llm = options.llm;
|
|
@@ -2566,10 +2647,20 @@ var PipelineSession = class {
|
|
|
2566
2647
|
setBuiltinTools(tools) {
|
|
2567
2648
|
this._builtinTools = tools;
|
|
2568
2649
|
}
|
|
2650
|
+
setLogger(logger) {
|
|
2651
|
+
this._log = logger;
|
|
2652
|
+
if ("setLogger" in this._stt && typeof this._stt.setLogger === "function") {
|
|
2653
|
+
this._stt.setLogger(logger);
|
|
2654
|
+
}
|
|
2655
|
+
if ("setLogger" in this._tts && typeof this._tts.setLogger === "function") {
|
|
2656
|
+
this._tts.setLogger(logger);
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2569
2659
|
async start(callSession, tools) {
|
|
2570
2660
|
this._callSession = callSession;
|
|
2571
2661
|
this._tools = tools ?? null;
|
|
2572
2662
|
this._running = true;
|
|
2663
|
+
this._log.info("PipelineSession started");
|
|
2573
2664
|
this._conversation = [];
|
|
2574
2665
|
if (this._systemPrompt) {
|
|
2575
2666
|
this._conversation.push({
|
|
@@ -2579,11 +2670,11 @@ var PipelineSession = class {
|
|
|
2579
2670
|
}
|
|
2580
2671
|
if (this._greeting) {
|
|
2581
2672
|
this._generateGreeting().catch((err) => {
|
|
2582
|
-
|
|
2673
|
+
this._log.error({ err }, "Greeting error");
|
|
2583
2674
|
});
|
|
2584
2675
|
}
|
|
2585
2676
|
this._runSttLoop().catch((err) => {
|
|
2586
|
-
|
|
2677
|
+
this._log.error({ err }, "STT loop error");
|
|
2587
2678
|
});
|
|
2588
2679
|
}
|
|
2589
2680
|
feedAudio(audio) {
|
|
@@ -2600,6 +2691,7 @@ var PipelineSession = class {
|
|
|
2600
2691
|
}
|
|
2601
2692
|
async stop() {
|
|
2602
2693
|
this._running = false;
|
|
2694
|
+
this._log.info("PipelineSession stopped");
|
|
2603
2695
|
this._audioBuffer = [];
|
|
2604
2696
|
}
|
|
2605
2697
|
async _runSttLoop() {
|
|
@@ -2613,8 +2705,10 @@ var PipelineSession = class {
|
|
|
2613
2705
|
if (this._callSession) {
|
|
2614
2706
|
this._callSession.clearAudio();
|
|
2615
2707
|
}
|
|
2708
|
+
this._log.info('Barge-in: "%s"', event.transcript.substring(0, 30));
|
|
2616
2709
|
}
|
|
2617
2710
|
if (event.type === "final" && event.transcript.trim()) {
|
|
2711
|
+
this._log.info("STT: %s", event.transcript);
|
|
2618
2712
|
await this._handleUserSpeech(event.transcript);
|
|
2619
2713
|
}
|
|
2620
2714
|
}
|
|
@@ -2683,6 +2777,7 @@ var PipelineSession = class {
|
|
|
2683
2777
|
}
|
|
2684
2778
|
}
|
|
2685
2779
|
if (fullResponse.trim()) {
|
|
2780
|
+
this._log.info("Assistant: %s", fullResponse.substring(0, 100));
|
|
2686
2781
|
this._conversation.push({ role: "assistant", content: fullResponse });
|
|
2687
2782
|
await this._synthesizeAndSend(fullResponse);
|
|
2688
2783
|
}
|
|
@@ -2750,7 +2845,7 @@ var PipelineSession = class {
|
|
|
2750
2845
|
await this._synthesizeAndSend(followUpText);
|
|
2751
2846
|
}
|
|
2752
2847
|
} catch (err) {
|
|
2753
|
-
|
|
2848
|
+
this._log.error({ err }, "Tool call failed: %s", name);
|
|
2754
2849
|
}
|
|
2755
2850
|
}
|
|
2756
2851
|
async _synthesizeAndSend(text) {
|
|
@@ -2776,7 +2871,7 @@ var PipelineSession = class {
|
|
|
2776
2871
|
}
|
|
2777
2872
|
}
|
|
2778
2873
|
} catch (err) {
|
|
2779
|
-
|
|
2874
|
+
this._log.error({ err }, "TTS error");
|
|
2780
2875
|
} finally {
|
|
2781
2876
|
this._speaking = false;
|
|
2782
2877
|
}
|
|
@@ -2786,6 +2881,10 @@ var PipelineSession = class {
|
|
|
2786
2881
|
// src/agent/pipeline/deepgram-stt.ts
|
|
2787
2882
|
var DeepgramSTT = class {
|
|
2788
2883
|
_options;
|
|
2884
|
+
_log = NOOP_LOGGER;
|
|
2885
|
+
setLogger(logger) {
|
|
2886
|
+
this._log = logger;
|
|
2887
|
+
}
|
|
2789
2888
|
constructor(options = {}) {
|
|
2790
2889
|
this._options = {
|
|
2791
2890
|
model: "nova-3",
|
|
@@ -2855,7 +2954,7 @@ var DeepgramSTT = class {
|
|
|
2855
2954
|
}
|
|
2856
2955
|
});
|
|
2857
2956
|
ws.on("error", (err) => {
|
|
2858
|
-
|
|
2957
|
+
this._log.error({ err }, "Deepgram STT error");
|
|
2859
2958
|
done = true;
|
|
2860
2959
|
if (resolveWait) {
|
|
2861
2960
|
resolveWait();
|
|
@@ -2866,6 +2965,7 @@ var DeepgramSTT = class {
|
|
|
2866
2965
|
ws.on("open", resolve);
|
|
2867
2966
|
ws.on("error", reject);
|
|
2868
2967
|
});
|
|
2968
|
+
this._log.info("Deepgram STT connected");
|
|
2869
2969
|
const feedPromise = (async () => {
|
|
2870
2970
|
try {
|
|
2871
2971
|
for await (const chunk of audioStream) {
|
|
@@ -2902,6 +3002,10 @@ var DeepgramSTT = class {
|
|
|
2902
3002
|
// src/agent/pipeline/elevenlabs-tts.ts
|
|
2903
3003
|
var ElevenLabsTTS = class {
|
|
2904
3004
|
_options;
|
|
3005
|
+
_log = NOOP_LOGGER;
|
|
3006
|
+
setLogger(logger) {
|
|
3007
|
+
this._log = logger;
|
|
3008
|
+
}
|
|
2905
3009
|
constructor(options = {}) {
|
|
2906
3010
|
this._options = {
|
|
2907
3011
|
voiceId: "EXAVITQu4vr4xnSDxMaL",
|
|
@@ -3001,7 +3105,7 @@ var ElevenLabsTTS = class {
|
|
|
3001
3105
|
}
|
|
3002
3106
|
});
|
|
3003
3107
|
ws.on("error", (err) => {
|
|
3004
|
-
|
|
3108
|
+
this._log.error({ err }, "ElevenLabs TTS error");
|
|
3005
3109
|
done = true;
|
|
3006
3110
|
if (resolveWait) {
|
|
3007
3111
|
resolveWait();
|
|
@@ -3012,16 +3116,19 @@ var ElevenLabsTTS = class {
|
|
|
3012
3116
|
ws.on("open", resolve);
|
|
3013
3117
|
ws.on("error", reject);
|
|
3014
3118
|
});
|
|
3119
|
+
this._log.info("ElevenLabs TTS connected");
|
|
3015
3120
|
const feedPromise = (async () => {
|
|
3016
3121
|
try {
|
|
3017
3122
|
for await (const chunk of textStream) {
|
|
3018
3123
|
if (done) break;
|
|
3019
3124
|
if (ws.readyState === 1) {
|
|
3125
|
+
this._log.debug("ElevenLabs sending text: %s", chunk.substring(0, 60));
|
|
3020
3126
|
ws.send(JSON.stringify({ text: chunk }));
|
|
3021
3127
|
}
|
|
3022
3128
|
}
|
|
3023
3129
|
} finally {
|
|
3024
3130
|
if (ws.readyState === 1) {
|
|
3131
|
+
this._log.debug("ElevenLabs sending EOS");
|
|
3025
3132
|
ws.send(JSON.stringify({ text: "" }));
|
|
3026
3133
|
}
|
|
3027
3134
|
}
|
|
@@ -3583,6 +3690,8 @@ exports.PipelineSession = PipelineSession;
|
|
|
3583
3690
|
exports.TogetherLLM = TogetherLLM;
|
|
3584
3691
|
exports.ToolRegistry = ToolRegistry;
|
|
3585
3692
|
exports.XaiLLM = XaiLLM;
|
|
3693
|
+
exports.createAgentLogger = createAgentLogger;
|
|
3694
|
+
exports.createPipelineLogger = createPipelineLogger;
|
|
3586
3695
|
exports.functionTool = functionTool;
|
|
3587
3696
|
exports.getTracingConfig = getTracingConfig;
|
|
3588
3697
|
exports.mcpServerHTTP = mcpServerHTTP;
|