@teamlearners/clawops 0.5.3 → 0.5.5
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 +201 -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 +197 -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,10 +323,19 @@ 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;
|
|
328
337
|
var MAX_RECONNECT_DELAY = 3e4;
|
|
338
|
+
var PING_TIMEOUT = 6e4;
|
|
329
339
|
function buildControlWsUrl(options) {
|
|
330
340
|
const scheme = options.baseUrl.startsWith("https") ? "wss" : "ws";
|
|
331
341
|
const host = options.baseUrl.replace(/^https?:\/\//, "").replace(/\/$/, "");
|
|
@@ -350,6 +360,11 @@ var ControlWebSocket = class {
|
|
|
350
360
|
_closed = false;
|
|
351
361
|
_connectedResolve = null;
|
|
352
362
|
_connectedPromise;
|
|
363
|
+
_log = NOOP_LOGGER;
|
|
364
|
+
_pingTimer = null;
|
|
365
|
+
setLogger(logger) {
|
|
366
|
+
this._log = logger;
|
|
367
|
+
}
|
|
353
368
|
/** Register an event handler for a specific event type. */
|
|
354
369
|
on(event, handler) {
|
|
355
370
|
let list = this._handlers.get(event);
|
|
@@ -377,6 +392,7 @@ var ControlWebSocket = class {
|
|
|
377
392
|
/** Close the WebSocket and stop reconnecting. */
|
|
378
393
|
close() {
|
|
379
394
|
this._closed = true;
|
|
395
|
+
this._clearPingTimer();
|
|
380
396
|
if (this._ws) {
|
|
381
397
|
this._ws.close();
|
|
382
398
|
this._ws = null;
|
|
@@ -393,26 +409,32 @@ var ControlWebSocket = class {
|
|
|
393
409
|
this._ws = ws;
|
|
394
410
|
ws.on("open", () => {
|
|
395
411
|
this._reconnectDelay = INITIAL_RECONNECT_DELAY;
|
|
412
|
+
this._resetPingTimer();
|
|
396
413
|
if (this._connectedResolve) {
|
|
397
414
|
this._connectedResolve();
|
|
398
415
|
this._connectedResolve = null;
|
|
399
416
|
}
|
|
417
|
+
this._log.info("Control WS connected: %s", this._url);
|
|
418
|
+
});
|
|
419
|
+
ws.on("ping", () => {
|
|
420
|
+
this._resetPingTimer();
|
|
400
421
|
});
|
|
401
422
|
ws.on("message", (data) => {
|
|
402
423
|
try {
|
|
403
424
|
const msg = JSON.parse(data.toString());
|
|
404
425
|
this._dispatchEvent(msg);
|
|
405
426
|
} catch {
|
|
406
|
-
|
|
427
|
+
this._log.warn("Control WS parse error");
|
|
407
428
|
}
|
|
408
429
|
});
|
|
409
430
|
ws.on("close", () => {
|
|
431
|
+
this._clearPingTimer();
|
|
410
432
|
if (!this._closed) {
|
|
411
433
|
this._scheduleReconnect();
|
|
412
434
|
}
|
|
413
435
|
});
|
|
414
436
|
ws.on("error", (err) => {
|
|
415
|
-
|
|
437
|
+
this._log.warn("Control WS error: %s", err.message);
|
|
416
438
|
});
|
|
417
439
|
}
|
|
418
440
|
_dispatchEvent(event) {
|
|
@@ -423,22 +445,38 @@ var ControlWebSocket = class {
|
|
|
423
445
|
const result = handler(event);
|
|
424
446
|
if (result && typeof result.catch === "function") {
|
|
425
447
|
result.catch((err) => {
|
|
426
|
-
|
|
448
|
+
this._log.error({ err }, "Control WS handler error: %s", event.event);
|
|
427
449
|
});
|
|
428
450
|
}
|
|
429
451
|
} catch (err) {
|
|
430
|
-
|
|
452
|
+
this._log.error({ err }, "Control WS handler error: %s", event.event);
|
|
431
453
|
}
|
|
432
454
|
}
|
|
433
455
|
}
|
|
434
456
|
}
|
|
457
|
+
_resetPingTimer() {
|
|
458
|
+
this._clearPingTimer();
|
|
459
|
+
this._pingTimer = setTimeout(() => {
|
|
460
|
+
this._log.warn("Control WS ping timeout, closing connection");
|
|
461
|
+
if (this._ws) {
|
|
462
|
+
this._ws.terminate();
|
|
463
|
+
}
|
|
464
|
+
}, PING_TIMEOUT);
|
|
465
|
+
}
|
|
466
|
+
_clearPingTimer() {
|
|
467
|
+
if (this._pingTimer) {
|
|
468
|
+
clearTimeout(this._pingTimer);
|
|
469
|
+
this._pingTimer = null;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
435
472
|
_scheduleReconnect() {
|
|
436
473
|
const delay = this._reconnectDelay;
|
|
437
474
|
this._reconnectDelay = Math.min(this._reconnectDelay * 2, MAX_RECONNECT_DELAY);
|
|
475
|
+
this._log.info("Control WS reconnecting in %ds...", delay / 1e3);
|
|
438
476
|
setTimeout(() => {
|
|
439
477
|
if (!this._closed) {
|
|
440
478
|
this._doConnect().catch((err) => {
|
|
441
|
-
|
|
479
|
+
this._log.warn({ err }, "Control WS reconnect failed");
|
|
442
480
|
this._scheduleReconnect();
|
|
443
481
|
});
|
|
444
482
|
}
|
|
@@ -450,6 +488,10 @@ var ControlWebSocket = class {
|
|
|
450
488
|
var MCPClient = class {
|
|
451
489
|
_servers = /* @__PURE__ */ new Map();
|
|
452
490
|
_clients = /* @__PURE__ */ new Map();
|
|
491
|
+
_log = NOOP_LOGGER;
|
|
492
|
+
setLogger(logger) {
|
|
493
|
+
this._log = logger;
|
|
494
|
+
}
|
|
453
495
|
/** Add an MCP server configuration. */
|
|
454
496
|
addServer(name, config) {
|
|
455
497
|
this._servers.set(name, config);
|
|
@@ -462,7 +504,7 @@ var MCPClient = class {
|
|
|
462
504
|
const tools = await this._connectServer(name, config);
|
|
463
505
|
allTools.push(...tools);
|
|
464
506
|
} catch (err) {
|
|
465
|
-
|
|
507
|
+
this._log.error({ err }, "MCP connection failed: %s", name);
|
|
466
508
|
}
|
|
467
509
|
}
|
|
468
510
|
return allTools;
|
|
@@ -471,12 +513,13 @@ var MCPClient = class {
|
|
|
471
513
|
async disconnect() {
|
|
472
514
|
for (const [name, client] of this._clients) {
|
|
473
515
|
try {
|
|
516
|
+
this._log.debug("MCP closing: %s", name);
|
|
474
517
|
const c = client;
|
|
475
518
|
if (c.close) {
|
|
476
519
|
await c.close();
|
|
477
520
|
}
|
|
478
521
|
} catch (err) {
|
|
479
|
-
|
|
522
|
+
this._log.error({ err }, "MCP disconnect error: %s", name);
|
|
480
523
|
}
|
|
481
524
|
}
|
|
482
525
|
this._clients.clear();
|
|
@@ -485,6 +528,11 @@ var MCPClient = class {
|
|
|
485
528
|
const sdk = await import('@modelcontextprotocol/sdk/client/index.js');
|
|
486
529
|
const { Client } = sdk;
|
|
487
530
|
const client = new Client({ name: `clawops-${name}`, version: "1.0.0" });
|
|
531
|
+
if (config.type === "stdio") {
|
|
532
|
+
this._log.debug("MCP connecting (stdio): %s", config["command"]);
|
|
533
|
+
} else if (config.type === "http") {
|
|
534
|
+
this._log.debug("MCP connecting (http): %s", config["url"]);
|
|
535
|
+
}
|
|
488
536
|
let transport;
|
|
489
537
|
if (config.type === "stdio") {
|
|
490
538
|
const { StdioClientTransport } = await import('@modelcontextprotocol/sdk/client/stdio.js');
|
|
@@ -513,6 +561,7 @@ var MCPClient = class {
|
|
|
513
561
|
parameters: inputSchema.properties ?? {},
|
|
514
562
|
required: inputSchema.required ?? [],
|
|
515
563
|
handler: async (args) => {
|
|
564
|
+
this._log.debug("MCP call_tool: %s", toolDef.name);
|
|
516
565
|
const result = await client.callTool({
|
|
517
566
|
name: toolDef.name,
|
|
518
567
|
arguments: args
|
|
@@ -525,6 +574,8 @@ var MCPClient = class {
|
|
|
525
574
|
}
|
|
526
575
|
});
|
|
527
576
|
}
|
|
577
|
+
this._log.info("MCP server connected: %d tools found", tools.length);
|
|
578
|
+
this._log.debug("MCP tools: %s", tools.map((t) => t.name));
|
|
528
579
|
return tools;
|
|
529
580
|
}
|
|
530
581
|
};
|
|
@@ -579,6 +630,10 @@ var MediaWebSocket = class {
|
|
|
579
630
|
_onClose = null;
|
|
580
631
|
_onDtmf = null;
|
|
581
632
|
_markWaiters = /* @__PURE__ */ new Map();
|
|
633
|
+
_log = NOOP_LOGGER;
|
|
634
|
+
setLogger(logger) {
|
|
635
|
+
this._log = logger;
|
|
636
|
+
}
|
|
582
637
|
/** Set the handler for inbound audio data. */
|
|
583
638
|
onAudio(handler) {
|
|
584
639
|
this._onAudio = handler;
|
|
@@ -620,6 +675,7 @@ var MediaWebSocket = class {
|
|
|
620
675
|
ws.on("open", () => {
|
|
621
676
|
this._startSendLoop();
|
|
622
677
|
resolve();
|
|
678
|
+
this._log.info("Media WS connected: %s", url);
|
|
623
679
|
});
|
|
624
680
|
ws.on("message", (data) => {
|
|
625
681
|
try {
|
|
@@ -638,7 +694,7 @@ var MediaWebSocket = class {
|
|
|
638
694
|
if (!this._ws) {
|
|
639
695
|
reject(err);
|
|
640
696
|
}
|
|
641
|
-
|
|
697
|
+
this._log.error({ err }, "Media WS error");
|
|
642
698
|
});
|
|
643
699
|
});
|
|
644
700
|
}
|
|
@@ -799,6 +855,10 @@ var AudioRecorder = class {
|
|
|
799
855
|
_mixWritten = 0;
|
|
800
856
|
_startTime = 0;
|
|
801
857
|
_started = false;
|
|
858
|
+
_log = NOOP_LOGGER;
|
|
859
|
+
setLogger(logger) {
|
|
860
|
+
this._log = logger;
|
|
861
|
+
}
|
|
802
862
|
constructor(recordingPath, callId) {
|
|
803
863
|
this._dir = path.join(recordingPath, callId);
|
|
804
864
|
}
|
|
@@ -813,6 +873,7 @@ var AudioRecorder = class {
|
|
|
813
873
|
fs.writeSync(this._fdMix, header);
|
|
814
874
|
this._startTime = performance.now();
|
|
815
875
|
this._started = true;
|
|
876
|
+
this._log.info("Recording started: %s", this._dir);
|
|
816
877
|
}
|
|
817
878
|
_expectedBytes() {
|
|
818
879
|
const elapsed = (performance.now() - this._startTime) / 1e3;
|
|
@@ -865,7 +926,7 @@ var AudioRecorder = class {
|
|
|
865
926
|
this._inWritten += pcm16_8k.length;
|
|
866
927
|
this._writeToMix(pcm16_8k, posBefore);
|
|
867
928
|
} catch (err) {
|
|
868
|
-
|
|
929
|
+
this._log.error({ err }, "Recording write error (inbound)");
|
|
869
930
|
}
|
|
870
931
|
}
|
|
871
932
|
writeOutbound(pcm16_8k) {
|
|
@@ -878,7 +939,7 @@ var AudioRecorder = class {
|
|
|
878
939
|
this._outWritten += pcm16_8k.length;
|
|
879
940
|
this._writeToMix(pcm16_8k, posBefore);
|
|
880
941
|
} catch (err) {
|
|
881
|
-
|
|
942
|
+
this._log.error({ err }, "Recording write error (outbound)");
|
|
882
943
|
}
|
|
883
944
|
}
|
|
884
945
|
stop() {
|
|
@@ -899,8 +960,10 @@ var AudioRecorder = class {
|
|
|
899
960
|
fs.writeSync(fd, makeWavHeader(maxWritten), 0, 44, 0);
|
|
900
961
|
fs.closeSync(fd);
|
|
901
962
|
}
|
|
963
|
+
const maxSec = maxWritten / 16e3;
|
|
964
|
+
this._log.info("Recording stopped: %s (%ds)", this._dir, maxSec);
|
|
902
965
|
} catch (err) {
|
|
903
|
-
|
|
966
|
+
this._log.error({ err }, "Recording stop error");
|
|
904
967
|
} finally {
|
|
905
968
|
this._fdIn = null;
|
|
906
969
|
this._fdOut = null;
|
|
@@ -930,6 +993,7 @@ var CallSession = class {
|
|
|
930
993
|
_dtmfCollectorActive = false;
|
|
931
994
|
_dtmfResolvers = [];
|
|
932
995
|
_dtmfBuffer = [];
|
|
996
|
+
_log = NOOP_LOGGER;
|
|
933
997
|
_handlers = /* @__PURE__ */ new Map();
|
|
934
998
|
_endedPromise;
|
|
935
999
|
_resolveEnded;
|
|
@@ -946,6 +1010,9 @@ var CallSession = class {
|
|
|
946
1010
|
this._resolveEnded = resolve;
|
|
947
1011
|
});
|
|
948
1012
|
}
|
|
1013
|
+
setLogger(logger) {
|
|
1014
|
+
this._log = logger;
|
|
1015
|
+
}
|
|
949
1016
|
get status() {
|
|
950
1017
|
return this._status;
|
|
951
1018
|
}
|
|
@@ -1021,7 +1088,9 @@ var CallSession = class {
|
|
|
1021
1088
|
this._dtmfResolvers = [];
|
|
1022
1089
|
this._dtmfBuffer = [];
|
|
1023
1090
|
}
|
|
1024
|
-
|
|
1091
|
+
const result = collected.join("");
|
|
1092
|
+
this._log.info("DTMF collected: %s", result);
|
|
1093
|
+
return result;
|
|
1025
1094
|
}
|
|
1026
1095
|
/** Send a sequence of DTMF digits. */
|
|
1027
1096
|
async sendDtmfSequence(digits) {
|
|
@@ -1073,11 +1142,11 @@ var CallSession = class {
|
|
|
1073
1142
|
const result = handler(this, ...args);
|
|
1074
1143
|
if (result && typeof result.catch === "function") {
|
|
1075
1144
|
result.catch((err) => {
|
|
1076
|
-
|
|
1145
|
+
this._log.error({ err }, "CallSession handler error: %s", event);
|
|
1077
1146
|
});
|
|
1078
1147
|
}
|
|
1079
1148
|
} catch (err) {
|
|
1080
|
-
|
|
1149
|
+
this._log.error({ err }, "CallSession handler error: %s", event);
|
|
1081
1150
|
}
|
|
1082
1151
|
}
|
|
1083
1152
|
}
|
|
@@ -1325,6 +1394,9 @@ var ClawOpsAgent = class {
|
|
|
1325
1394
|
_passiveDtmfTimer = null;
|
|
1326
1395
|
_passiveDtmfCallId = null;
|
|
1327
1396
|
_callSessions = /* @__PURE__ */ new Map();
|
|
1397
|
+
_log;
|
|
1398
|
+
_pipelineLog;
|
|
1399
|
+
_isPipelineSession = false;
|
|
1328
1400
|
constructor(options) {
|
|
1329
1401
|
this._apiKey = options.apiKey ?? process.env["CLAWOPS_API_KEY"] ?? "";
|
|
1330
1402
|
this._accountId = options.accountId ?? process.env["CLAWOPS_ACCOUNT_ID"] ?? "";
|
|
@@ -1339,6 +1411,9 @@ var ClawOpsAgent = class {
|
|
|
1339
1411
|
if (options.tracing) {
|
|
1340
1412
|
setTracingConfig(options.tracing);
|
|
1341
1413
|
}
|
|
1414
|
+
this._log = createAgentLogger(options.logger);
|
|
1415
|
+
this._pipelineLog = createPipelineLogger(this._log);
|
|
1416
|
+
this._isPipelineSession = "_stt" in this._session && "_llm" in this._session;
|
|
1342
1417
|
}
|
|
1343
1418
|
/**
|
|
1344
1419
|
* Register a function tool.
|
|
@@ -1398,6 +1473,7 @@ var ClawOpsAgent = class {
|
|
|
1398
1473
|
accountId: this._accountId,
|
|
1399
1474
|
number: this._fromNumber
|
|
1400
1475
|
});
|
|
1476
|
+
this._controlWs.setLogger(this._log);
|
|
1401
1477
|
this._controlWs.on("call.incoming", (event) => this._handleIncoming(event));
|
|
1402
1478
|
this._controlWs.on("call.ended", (event) => this._handleEnded(event));
|
|
1403
1479
|
this._controlWs.on("call.outbound_ready", (event) => this._handleOutboundReady(event));
|
|
@@ -1411,7 +1487,7 @@ var ClawOpsAgent = class {
|
|
|
1411
1487
|
`Failed to connect to ClawOps: ${err instanceof Error ? err.message : String(err)}`
|
|
1412
1488
|
);
|
|
1413
1489
|
}
|
|
1414
|
-
|
|
1490
|
+
this._log.info("ClawOpsAgent connected on %s", this._fromNumber);
|
|
1415
1491
|
}
|
|
1416
1492
|
/**
|
|
1417
1493
|
* Connect and block until disconnected.
|
|
@@ -1438,7 +1514,7 @@ var ClawOpsAgent = class {
|
|
|
1438
1514
|
}
|
|
1439
1515
|
this._activeSessions.clear();
|
|
1440
1516
|
this._callSessions.clear();
|
|
1441
|
-
|
|
1517
|
+
this._log.info("ClawOpsAgent disconnected");
|
|
1442
1518
|
}
|
|
1443
1519
|
/**
|
|
1444
1520
|
* Initiate an outbound call.
|
|
@@ -1473,10 +1549,9 @@ var ClawOpsAgent = class {
|
|
|
1473
1549
|
callSession.on(evt, handler);
|
|
1474
1550
|
}
|
|
1475
1551
|
}
|
|
1552
|
+
callSession.setLogger(this._log);
|
|
1476
1553
|
this._activeSessions.set(callSession.callId, callSession);
|
|
1477
|
-
|
|
1478
|
-
`[ClawOpsAgent] Outbound call initiated: ${this._fromNumber} -> ${to} (${callSession.callId})`
|
|
1479
|
-
);
|
|
1554
|
+
this._log.info("Outbound call initiated: %s -> %s (%s)", this._fromNumber, to, callSession.callId);
|
|
1480
1555
|
return callSession;
|
|
1481
1556
|
}
|
|
1482
1557
|
_handleIncoming(event) {
|
|
@@ -1495,13 +1570,15 @@ var ClawOpsAgent = class {
|
|
|
1495
1570
|
session.on(evt, handler);
|
|
1496
1571
|
}
|
|
1497
1572
|
}
|
|
1573
|
+
session.setLogger(this._log);
|
|
1498
1574
|
this._activeSessions.set(callId, session);
|
|
1575
|
+
this._log.info("Incoming call: %s -> %s (%s)", fromNumber, this._fromNumber, callId);
|
|
1499
1576
|
if (this._controlWs) {
|
|
1500
1577
|
this._controlWs.send({ event: "call.accept", callId });
|
|
1501
1578
|
}
|
|
1502
1579
|
if (mediaUrl) {
|
|
1503
1580
|
this._startCallSession(session, mediaUrl).catch((err) => {
|
|
1504
|
-
|
|
1581
|
+
this._log.error({ err }, "Call session error: %s", callId);
|
|
1505
1582
|
});
|
|
1506
1583
|
}
|
|
1507
1584
|
}
|
|
@@ -1509,6 +1586,7 @@ var ClawOpsAgent = class {
|
|
|
1509
1586
|
const callId = event["callId"];
|
|
1510
1587
|
const session = this._activeSessions.get(callId);
|
|
1511
1588
|
if (session) {
|
|
1589
|
+
this._log.info("Call ended (server): %s", callId);
|
|
1512
1590
|
session._markEnded();
|
|
1513
1591
|
this._activeSessions.delete(callId);
|
|
1514
1592
|
}
|
|
@@ -1525,6 +1603,7 @@ var ClawOpsAgent = class {
|
|
|
1525
1603
|
accountId: this._accountId,
|
|
1526
1604
|
direction: "outbound"
|
|
1527
1605
|
});
|
|
1606
|
+
session.setLogger(this._log);
|
|
1528
1607
|
for (const [evt, handlers] of this._handlers) {
|
|
1529
1608
|
for (const handler of handlers) {
|
|
1530
1609
|
session.on(evt, handler);
|
|
@@ -1533,8 +1612,9 @@ var ClawOpsAgent = class {
|
|
|
1533
1612
|
this._activeSessions.set(callId, session);
|
|
1534
1613
|
}
|
|
1535
1614
|
if (mediaUrl) {
|
|
1615
|
+
this._log.info("Outbound call answered: %s -> %s (%s)", this._fromNumber, session.toNumber, callId);
|
|
1536
1616
|
this._startCallSession(session, mediaUrl).catch((err) => {
|
|
1537
|
-
|
|
1617
|
+
this._log.error({ err }, "Call session error: %s", callId);
|
|
1538
1618
|
});
|
|
1539
1619
|
}
|
|
1540
1620
|
}
|
|
@@ -1542,13 +1622,14 @@ var ClawOpsAgent = class {
|
|
|
1542
1622
|
const callId = event["callId"];
|
|
1543
1623
|
const session = this._activeSessions.get(callId);
|
|
1544
1624
|
if (session) {
|
|
1545
|
-
|
|
1625
|
+
this._log.info("Outbound call ringing: %s", callId);
|
|
1546
1626
|
}
|
|
1547
1627
|
}
|
|
1548
1628
|
_handleFailed(event) {
|
|
1549
1629
|
const callId = event["callId"];
|
|
1550
1630
|
const session = this._activeSessions.get(callId);
|
|
1551
1631
|
if (session) {
|
|
1632
|
+
this._log.info("Outbound call failed: %s (%s)", callId, event["reason"] ?? "failed");
|
|
1552
1633
|
session._emit("call_failed", event["reason"] ?? "failed");
|
|
1553
1634
|
session._markEnded();
|
|
1554
1635
|
this._activeSessions.delete(callId);
|
|
@@ -1573,7 +1654,7 @@ var ClawOpsAgent = class {
|
|
|
1573
1654
|
this._passiveDtmfCallId = null;
|
|
1574
1655
|
if (digits && sessionHandler && sessionHandler.feedDtmf) {
|
|
1575
1656
|
sessionHandler.feedDtmf(digits).catch((err) => {
|
|
1576
|
-
|
|
1657
|
+
this._log.error({ err }, "DTMF feed error");
|
|
1577
1658
|
});
|
|
1578
1659
|
}
|
|
1579
1660
|
}, this._passiveDtmfDebounceMs);
|
|
@@ -1592,22 +1673,25 @@ var ClawOpsAgent = class {
|
|
|
1592
1673
|
if (this._mcpServers.length > 0) {
|
|
1593
1674
|
for (const serverConfig of this._mcpServers) {
|
|
1594
1675
|
const client = new MCPClient();
|
|
1676
|
+
client.setLogger(this._log);
|
|
1595
1677
|
client.addServer("mcp", serverConfig);
|
|
1596
1678
|
try {
|
|
1597
1679
|
const tools = await client.connect();
|
|
1598
1680
|
sessionTools.registerMcpTools(tools);
|
|
1599
1681
|
mcpClients.push(client);
|
|
1600
1682
|
} catch (err) {
|
|
1601
|
-
|
|
1683
|
+
this._log.error({ err }, "MCP connection error");
|
|
1602
1684
|
}
|
|
1603
1685
|
}
|
|
1604
1686
|
}
|
|
1605
1687
|
let recorder = null;
|
|
1606
1688
|
if (this._recording) {
|
|
1607
1689
|
recorder = new AudioRecorder(this._recordingPath, session.callId);
|
|
1690
|
+
recorder.setLogger(this._log);
|
|
1608
1691
|
recorder.start();
|
|
1609
1692
|
}
|
|
1610
1693
|
const mediaWs = new MediaWebSocket();
|
|
1694
|
+
mediaWs.setLogger(this._log);
|
|
1611
1695
|
session._bindTransport(
|
|
1612
1696
|
(audio) => {
|
|
1613
1697
|
mediaWs.sendAudio(audio.toString("base64"));
|
|
@@ -1637,6 +1721,9 @@ var ClawOpsAgent = class {
|
|
|
1637
1721
|
if ("setBuiltinTools" in sessionHandler && typeof sessionHandler.setBuiltinTools === "function") {
|
|
1638
1722
|
sessionHandler.setBuiltinTools(this._builtinTools);
|
|
1639
1723
|
}
|
|
1724
|
+
if ("setLogger" in sessionHandler && typeof sessionHandler.setLogger === "function") {
|
|
1725
|
+
sessionHandler.setLogger(this._isPipelineSession ? this._pipelineLog : this._log);
|
|
1726
|
+
}
|
|
1640
1727
|
this._callSessions.set(session.callId, sessionHandler);
|
|
1641
1728
|
mediaWs.onAudio((ulawAudio, _timestamp) => {
|
|
1642
1729
|
if (sessionHandler) {
|
|
@@ -1650,6 +1737,7 @@ var ClawOpsAgent = class {
|
|
|
1650
1737
|
this._onDtmfEvent(session, digit);
|
|
1651
1738
|
});
|
|
1652
1739
|
mediaWs.onClose(() => {
|
|
1740
|
+
this._log.info("Media stream stopped: %s", session.callId);
|
|
1653
1741
|
if (recorder) {
|
|
1654
1742
|
recorder.stop();
|
|
1655
1743
|
}
|
|
@@ -1658,11 +1746,12 @@ var ClawOpsAgent = class {
|
|
|
1658
1746
|
session._emit("call_start");
|
|
1659
1747
|
try {
|
|
1660
1748
|
await mediaWs.connect(mediaWsUrl, this._apiKey);
|
|
1749
|
+
this._log.info("Media stream started: %s", session.callId);
|
|
1661
1750
|
await sessionHandler.start(session, sessionTools);
|
|
1662
1751
|
await session.wait();
|
|
1663
1752
|
await sessionHandler.stop();
|
|
1664
1753
|
} catch (err) {
|
|
1665
|
-
|
|
1754
|
+
this._log.error({ err }, "Call session error: %s", session.callId);
|
|
1666
1755
|
} finally {
|
|
1667
1756
|
if (mcpClients.length > 0) {
|
|
1668
1757
|
sessionTools.clearMcpTools();
|
|
@@ -1690,7 +1779,11 @@ var HANG_UP_TOOL = {
|
|
|
1690
1779
|
type: "function",
|
|
1691
1780
|
name: "hang_up",
|
|
1692
1781
|
description: "End the phone call. Use when the conversation is finished or the caller says goodbye.",
|
|
1693
|
-
parameters: {
|
|
1782
|
+
parameters: {
|
|
1783
|
+
type: "object",
|
|
1784
|
+
properties: {},
|
|
1785
|
+
required: []
|
|
1786
|
+
}
|
|
1694
1787
|
};
|
|
1695
1788
|
var COLLECT_DTMF_TOOL = {
|
|
1696
1789
|
type: "function",
|
|
@@ -1713,7 +1806,10 @@ var SEND_DTMF_TOOL = {
|
|
|
1713
1806
|
parameters: {
|
|
1714
1807
|
type: "object",
|
|
1715
1808
|
properties: {
|
|
1716
|
-
digits: {
|
|
1809
|
+
digits: {
|
|
1810
|
+
type: "string",
|
|
1811
|
+
description: "\uC804\uC1A1\uD560 \uBC88\uD638 (0-9, *, #). 'w'\uB294 500ms \uB300\uAE30, 'W'\uB294 1000ms \uB300\uAE30."
|
|
1812
|
+
}
|
|
1717
1813
|
},
|
|
1718
1814
|
required: ["digits"]
|
|
1719
1815
|
}
|
|
@@ -1726,7 +1822,11 @@ var OpenAIRealtime = class {
|
|
|
1726
1822
|
_language;
|
|
1727
1823
|
_eagerness;
|
|
1728
1824
|
_greeting;
|
|
1825
|
+
_log = NOOP_LOGGER;
|
|
1729
1826
|
_builtinTools = null;
|
|
1827
|
+
setLogger(logger) {
|
|
1828
|
+
this._log = logger;
|
|
1829
|
+
}
|
|
1730
1830
|
setBuiltinTools(tools) {
|
|
1731
1831
|
this._builtinTools = tools;
|
|
1732
1832
|
}
|
|
@@ -1783,6 +1883,7 @@ var OpenAIRealtime = class {
|
|
|
1783
1883
|
const ws = this._ws;
|
|
1784
1884
|
ws.on("open", () => {
|
|
1785
1885
|
this._sendSessionUpdate();
|
|
1886
|
+
this._log.info("OpenAI Realtime connected");
|
|
1786
1887
|
if (this._greeting) {
|
|
1787
1888
|
this._send({ type: "response.create" });
|
|
1788
1889
|
}
|
|
@@ -1802,7 +1903,7 @@ var OpenAIRealtime = class {
|
|
|
1802
1903
|
if (!this._ws) {
|
|
1803
1904
|
reject(err);
|
|
1804
1905
|
}
|
|
1805
|
-
|
|
1906
|
+
this._log.error({ err }, "OpenAI Realtime WS error");
|
|
1806
1907
|
});
|
|
1807
1908
|
});
|
|
1808
1909
|
}
|
|
@@ -1836,9 +1937,12 @@ var OpenAIRealtime = class {
|
|
|
1836
1937
|
_sendSessionUpdate() {
|
|
1837
1938
|
if (!this._ws || this._ws.readyState !== 1) return;
|
|
1838
1939
|
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("
|
|
1940
|
+
if (!this._builtinTools || this._builtinTools.has("hang_up" /* HANG_UP */))
|
|
1941
|
+
toolSchemas.push(HANG_UP_TOOL);
|
|
1942
|
+
if (!this._builtinTools || this._builtinTools.has("collect_dtmf" /* COLLECT_DTMF */))
|
|
1943
|
+
toolSchemas.push(COLLECT_DTMF_TOOL);
|
|
1944
|
+
if (!this._builtinTools || this._builtinTools.has("send_dtmf" /* SEND_DTMF */))
|
|
1945
|
+
toolSchemas.push(SEND_DTMF_TOOL);
|
|
1842
1946
|
this._send({
|
|
1843
1947
|
type: "session.update",
|
|
1844
1948
|
session: {
|
|
@@ -1848,7 +1952,7 @@ var OpenAIRealtime = class {
|
|
|
1848
1952
|
input_audio_format: "g711_ulaw",
|
|
1849
1953
|
output_audio_format: "g711_ulaw",
|
|
1850
1954
|
input_audio_transcription: {
|
|
1851
|
-
model: "
|
|
1955
|
+
model: "whisper-1",
|
|
1852
1956
|
language: this._language
|
|
1853
1957
|
},
|
|
1854
1958
|
input_audio_noise_reduction: { type: "far_field" },
|
|
@@ -1919,7 +2023,7 @@ var OpenAIRealtime = class {
|
|
|
1919
2023
|
break;
|
|
1920
2024
|
}
|
|
1921
2025
|
case "error": {
|
|
1922
|
-
|
|
2026
|
+
this._log.error({ apiError: msg["error"] }, "OpenAI error");
|
|
1923
2027
|
break;
|
|
1924
2028
|
}
|
|
1925
2029
|
}
|
|
@@ -1969,6 +2073,7 @@ var OpenAIRealtime = class {
|
|
|
1969
2073
|
async _handleToolCall(item) {
|
|
1970
2074
|
const funcName = item["name"];
|
|
1971
2075
|
const callId = item["call_id"];
|
|
2076
|
+
this._log.info("Tool call: %s", funcName);
|
|
1972
2077
|
if (funcName === "hang_up") {
|
|
1973
2078
|
if (this._call) {
|
|
1974
2079
|
await this._call.hangup();
|
|
@@ -2025,7 +2130,7 @@ var OpenAIRealtime = class {
|
|
|
2025
2130
|
return;
|
|
2026
2131
|
}
|
|
2027
2132
|
if (!this._tools || !this._tools.has(funcName)) {
|
|
2028
|
-
|
|
2133
|
+
this._log.error("Unknown tool: %s", funcName);
|
|
2029
2134
|
return;
|
|
2030
2135
|
}
|
|
2031
2136
|
let result;
|
|
@@ -2033,7 +2138,7 @@ var OpenAIRealtime = class {
|
|
|
2033
2138
|
const args = JSON.parse(item["arguments"] ?? "{}");
|
|
2034
2139
|
result = await this._tools.call(funcName, args);
|
|
2035
2140
|
} catch (err) {
|
|
2036
|
-
|
|
2141
|
+
this._log.error({ err }, "Tool call failed: %s", funcName);
|
|
2037
2142
|
result = `Error: ${err}`;
|
|
2038
2143
|
}
|
|
2039
2144
|
await this._waitForResponseDone();
|
|
@@ -2182,6 +2287,7 @@ var GeminiRealtime = class {
|
|
|
2182
2287
|
_audioRemainder = Buffer.alloc(0);
|
|
2183
2288
|
_builtinTools = null;
|
|
2184
2289
|
_toolCallInProgress = false;
|
|
2290
|
+
_log = NOOP_LOGGER;
|
|
2185
2291
|
constructor(options = {}) {
|
|
2186
2292
|
this._apiKey = options.apiKey ?? process.env["GOOGLE_API_KEY"] ?? "";
|
|
2187
2293
|
this._systemPrompt = options.systemPrompt ?? "";
|
|
@@ -2201,6 +2307,9 @@ var GeminiRealtime = class {
|
|
|
2201
2307
|
setBuiltinTools(tools) {
|
|
2202
2308
|
this._builtinTools = tools;
|
|
2203
2309
|
}
|
|
2310
|
+
setLogger(logger) {
|
|
2311
|
+
this._log = logger;
|
|
2312
|
+
}
|
|
2204
2313
|
async start(callSession, tools) {
|
|
2205
2314
|
this._call = callSession;
|
|
2206
2315
|
if (tools) this._tools = tools;
|
|
@@ -2237,12 +2346,10 @@ var GeminiRealtime = class {
|
|
|
2237
2346
|
callbacks: {
|
|
2238
2347
|
onmessage: (msg) => this._handleMessage(msg),
|
|
2239
2348
|
onerror: (err) => {
|
|
2240
|
-
|
|
2349
|
+
this._log.error({ err }, "Gemini SDK error");
|
|
2241
2350
|
},
|
|
2242
2351
|
onclose: (ev) => {
|
|
2243
|
-
|
|
2244
|
-
`[GeminiRealtime] Connection closed: code=${ev?.code ?? "unknown"}`
|
|
2245
|
-
);
|
|
2352
|
+
this._log.info({ code: ev?.code ?? "unknown" }, "Gemini connection closed");
|
|
2246
2353
|
this._closed = true;
|
|
2247
2354
|
}
|
|
2248
2355
|
}
|
|
@@ -2322,11 +2429,11 @@ var GeminiRealtime = class {
|
|
|
2322
2429
|
}
|
|
2323
2430
|
}
|
|
2324
2431
|
if (serverContent.turnComplete) {
|
|
2325
|
-
|
|
2432
|
+
this._log.debug("Turn complete");
|
|
2326
2433
|
this._flushAudioRemainder();
|
|
2327
2434
|
}
|
|
2328
2435
|
if (serverContent.interrupted) {
|
|
2329
|
-
|
|
2436
|
+
this._log.info("Barge-in detected");
|
|
2330
2437
|
if (this._call) {
|
|
2331
2438
|
this._call.clearAudio();
|
|
2332
2439
|
}
|
|
@@ -2335,12 +2442,12 @@ var GeminiRealtime = class {
|
|
|
2335
2442
|
}
|
|
2336
2443
|
const inputText = serverContent.inputTranscription?.text;
|
|
2337
2444
|
if (inputText && this._call) {
|
|
2338
|
-
|
|
2445
|
+
this._log.info("User: %s", inputText);
|
|
2339
2446
|
this._call._emit("transcript", "user", inputText);
|
|
2340
2447
|
}
|
|
2341
2448
|
const outputText = serverContent.outputTranscription?.text;
|
|
2342
2449
|
if (outputText && this._call) {
|
|
2343
|
-
|
|
2450
|
+
this._log.info("Assistant: %s", outputText);
|
|
2344
2451
|
this._call._emit("transcript", "assistant", outputText);
|
|
2345
2452
|
}
|
|
2346
2453
|
}
|
|
@@ -2349,9 +2456,7 @@ var GeminiRealtime = class {
|
|
|
2349
2456
|
}
|
|
2350
2457
|
const toolCancellation = msg["toolCallCancellation"];
|
|
2351
2458
|
if (toolCancellation) {
|
|
2352
|
-
|
|
2353
|
-
`[GeminiRealtime] Tool call cancelled: ${(toolCancellation.ids ?? []).join(", ")}`
|
|
2354
|
-
);
|
|
2459
|
+
this._log.info({ ids: toolCancellation.ids }, "Tool call cancelled");
|
|
2355
2460
|
}
|
|
2356
2461
|
}
|
|
2357
2462
|
_handleAudioData(b64Data) {
|
|
@@ -2386,17 +2491,14 @@ var GeminiRealtime = class {
|
|
|
2386
2491
|
const functionCalls = toolCall.functionCalls;
|
|
2387
2492
|
if (!functionCalls) return;
|
|
2388
2493
|
this._toolCallInProgress = true;
|
|
2389
|
-
console.log(
|
|
2390
|
-
`[GeminiRealtime] toolCall: ${functionCalls.map((fc) => fc.name).join(", ")}`
|
|
2391
|
-
);
|
|
2392
2494
|
const responses = [];
|
|
2393
2495
|
for (const fc of functionCalls) {
|
|
2394
2496
|
const name = fc.name ?? "";
|
|
2395
2497
|
const fcId = fc.id ?? "";
|
|
2396
2498
|
const args = fc.args ?? {};
|
|
2397
|
-
|
|
2499
|
+
this._log.info({ tool: name, args }, "Tool call: %s", name);
|
|
2398
2500
|
if (name === "hang_up") {
|
|
2399
|
-
|
|
2501
|
+
this._log.info("hang_up: ending call");
|
|
2400
2502
|
if (this._call) {
|
|
2401
2503
|
await this._call.hangup();
|
|
2402
2504
|
}
|
|
@@ -2406,17 +2508,15 @@ var GeminiRealtime = class {
|
|
|
2406
2508
|
if (this._call) {
|
|
2407
2509
|
let result;
|
|
2408
2510
|
try {
|
|
2409
|
-
|
|
2410
|
-
`[GeminiRealtime] collect_dtmf: waiting for digits (maxDigits=${args["max_digits"] ?? 4}, timeout=${args["timeout"] ?? 5})`
|
|
2411
|
-
);
|
|
2511
|
+
this._log.info({ maxDigits: args["max_digits"] ?? 4, timeout: args["timeout"] ?? 5 }, "collect_dtmf: waiting for digits");
|
|
2412
2512
|
result = await this._call.collectDtmf({
|
|
2413
2513
|
maxDigits: args["max_digits"] ?? 4,
|
|
2414
2514
|
finishOnKey: args["finish_on_key"] ?? "#",
|
|
2415
2515
|
timeout: args["timeout"] ?? 5
|
|
2416
2516
|
});
|
|
2417
|
-
|
|
2517
|
+
this._log.info("DTMF collected: %s", result || "(empty)");
|
|
2418
2518
|
} catch (err) {
|
|
2419
|
-
|
|
2519
|
+
this._log.error({ err }, "collect_dtmf error");
|
|
2420
2520
|
result = `Error: ${err}`;
|
|
2421
2521
|
}
|
|
2422
2522
|
responses.push({
|
|
@@ -2431,12 +2531,12 @@ var GeminiRealtime = class {
|
|
|
2431
2531
|
if (this._call) {
|
|
2432
2532
|
let result;
|
|
2433
2533
|
try {
|
|
2434
|
-
|
|
2534
|
+
this._log.info('send_dtmf: digits="%s"', args["digits"] ?? "");
|
|
2435
2535
|
await this._call.sendDtmfSequence(args["digits"] ?? "");
|
|
2436
2536
|
result = "sent";
|
|
2437
|
-
|
|
2537
|
+
this._log.info("send_dtmf: sent");
|
|
2438
2538
|
} catch (err) {
|
|
2439
|
-
|
|
2539
|
+
this._log.error({ err }, "send_dtmf error");
|
|
2440
2540
|
result = `Error: ${err}`;
|
|
2441
2541
|
}
|
|
2442
2542
|
responses.push({ id: fcId, name, response: { result } });
|
|
@@ -2444,21 +2544,21 @@ var GeminiRealtime = class {
|
|
|
2444
2544
|
continue;
|
|
2445
2545
|
}
|
|
2446
2546
|
if (!this._tools || !this._tools.has(name)) {
|
|
2447
|
-
|
|
2547
|
+
this._log.error("Unknown tool: %s", name);
|
|
2448
2548
|
responses.push({ id: fcId, name, response: { error: `Unknown tool: ${name}` } });
|
|
2449
2549
|
continue;
|
|
2450
2550
|
}
|
|
2451
2551
|
try {
|
|
2452
2552
|
const result = await this._tools.call(name, args);
|
|
2453
2553
|
const resultStr = typeof result === "string" ? result : JSON.stringify(result);
|
|
2454
|
-
|
|
2554
|
+
this._log.info("Tool result: %s -> %s", name, resultStr.substring(0, 200));
|
|
2455
2555
|
responses.push({
|
|
2456
2556
|
id: fcId,
|
|
2457
2557
|
name,
|
|
2458
2558
|
response: { result: resultStr }
|
|
2459
2559
|
});
|
|
2460
2560
|
} catch (err) {
|
|
2461
|
-
|
|
2561
|
+
this._log.error({ err }, "Tool call failed: %s", name);
|
|
2462
2562
|
responses.push({
|
|
2463
2563
|
id: fcId,
|
|
2464
2564
|
name,
|
|
@@ -2467,7 +2567,7 @@ var GeminiRealtime = class {
|
|
|
2467
2567
|
}
|
|
2468
2568
|
}
|
|
2469
2569
|
if (responses.length > 0 && this._session) {
|
|
2470
|
-
|
|
2570
|
+
this._log.debug("Sending %d tool response(s)", responses.length);
|
|
2471
2571
|
this._session.sendToolResponse({
|
|
2472
2572
|
functionResponses: responses
|
|
2473
2573
|
});
|
|
@@ -2520,6 +2620,7 @@ var PipelineSession = class {
|
|
|
2520
2620
|
_running = false;
|
|
2521
2621
|
_speaking = false;
|
|
2522
2622
|
_builtinTools = null;
|
|
2623
|
+
_log = NOOP_LOGGER;
|
|
2523
2624
|
constructor(options) {
|
|
2524
2625
|
this._stt = options.stt;
|
|
2525
2626
|
this._llm = options.llm;
|
|
@@ -2543,10 +2644,20 @@ var PipelineSession = class {
|
|
|
2543
2644
|
setBuiltinTools(tools) {
|
|
2544
2645
|
this._builtinTools = tools;
|
|
2545
2646
|
}
|
|
2647
|
+
setLogger(logger) {
|
|
2648
|
+
this._log = logger;
|
|
2649
|
+
if ("setLogger" in this._stt && typeof this._stt.setLogger === "function") {
|
|
2650
|
+
this._stt.setLogger(logger);
|
|
2651
|
+
}
|
|
2652
|
+
if ("setLogger" in this._tts && typeof this._tts.setLogger === "function") {
|
|
2653
|
+
this._tts.setLogger(logger);
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2546
2656
|
async start(callSession, tools) {
|
|
2547
2657
|
this._callSession = callSession;
|
|
2548
2658
|
this._tools = tools ?? null;
|
|
2549
2659
|
this._running = true;
|
|
2660
|
+
this._log.info("PipelineSession started");
|
|
2550
2661
|
this._conversation = [];
|
|
2551
2662
|
if (this._systemPrompt) {
|
|
2552
2663
|
this._conversation.push({
|
|
@@ -2556,11 +2667,11 @@ var PipelineSession = class {
|
|
|
2556
2667
|
}
|
|
2557
2668
|
if (this._greeting) {
|
|
2558
2669
|
this._generateGreeting().catch((err) => {
|
|
2559
|
-
|
|
2670
|
+
this._log.error({ err }, "Greeting error");
|
|
2560
2671
|
});
|
|
2561
2672
|
}
|
|
2562
2673
|
this._runSttLoop().catch((err) => {
|
|
2563
|
-
|
|
2674
|
+
this._log.error({ err }, "STT loop error");
|
|
2564
2675
|
});
|
|
2565
2676
|
}
|
|
2566
2677
|
feedAudio(audio) {
|
|
@@ -2577,6 +2688,7 @@ var PipelineSession = class {
|
|
|
2577
2688
|
}
|
|
2578
2689
|
async stop() {
|
|
2579
2690
|
this._running = false;
|
|
2691
|
+
this._log.info("PipelineSession stopped");
|
|
2580
2692
|
this._audioBuffer = [];
|
|
2581
2693
|
}
|
|
2582
2694
|
async _runSttLoop() {
|
|
@@ -2590,8 +2702,10 @@ var PipelineSession = class {
|
|
|
2590
2702
|
if (this._callSession) {
|
|
2591
2703
|
this._callSession.clearAudio();
|
|
2592
2704
|
}
|
|
2705
|
+
this._log.info('Barge-in: "%s"', event.transcript.substring(0, 30));
|
|
2593
2706
|
}
|
|
2594
2707
|
if (event.type === "final" && event.transcript.trim()) {
|
|
2708
|
+
this._log.info("STT: %s", event.transcript);
|
|
2595
2709
|
await this._handleUserSpeech(event.transcript);
|
|
2596
2710
|
}
|
|
2597
2711
|
}
|
|
@@ -2660,6 +2774,7 @@ var PipelineSession = class {
|
|
|
2660
2774
|
}
|
|
2661
2775
|
}
|
|
2662
2776
|
if (fullResponse.trim()) {
|
|
2777
|
+
this._log.info("Assistant: %s", fullResponse.substring(0, 100));
|
|
2663
2778
|
this._conversation.push({ role: "assistant", content: fullResponse });
|
|
2664
2779
|
await this._synthesizeAndSend(fullResponse);
|
|
2665
2780
|
}
|
|
@@ -2727,7 +2842,7 @@ var PipelineSession = class {
|
|
|
2727
2842
|
await this._synthesizeAndSend(followUpText);
|
|
2728
2843
|
}
|
|
2729
2844
|
} catch (err) {
|
|
2730
|
-
|
|
2845
|
+
this._log.error({ err }, "Tool call failed: %s", name);
|
|
2731
2846
|
}
|
|
2732
2847
|
}
|
|
2733
2848
|
async _synthesizeAndSend(text) {
|
|
@@ -2753,7 +2868,7 @@ var PipelineSession = class {
|
|
|
2753
2868
|
}
|
|
2754
2869
|
}
|
|
2755
2870
|
} catch (err) {
|
|
2756
|
-
|
|
2871
|
+
this._log.error({ err }, "TTS error");
|
|
2757
2872
|
} finally {
|
|
2758
2873
|
this._speaking = false;
|
|
2759
2874
|
}
|
|
@@ -2763,6 +2878,10 @@ var PipelineSession = class {
|
|
|
2763
2878
|
// src/agent/pipeline/deepgram-stt.ts
|
|
2764
2879
|
var DeepgramSTT = class {
|
|
2765
2880
|
_options;
|
|
2881
|
+
_log = NOOP_LOGGER;
|
|
2882
|
+
setLogger(logger) {
|
|
2883
|
+
this._log = logger;
|
|
2884
|
+
}
|
|
2766
2885
|
constructor(options = {}) {
|
|
2767
2886
|
this._options = {
|
|
2768
2887
|
model: "nova-3",
|
|
@@ -2832,7 +2951,7 @@ var DeepgramSTT = class {
|
|
|
2832
2951
|
}
|
|
2833
2952
|
});
|
|
2834
2953
|
ws.on("error", (err) => {
|
|
2835
|
-
|
|
2954
|
+
this._log.error({ err }, "Deepgram STT error");
|
|
2836
2955
|
done = true;
|
|
2837
2956
|
if (resolveWait) {
|
|
2838
2957
|
resolveWait();
|
|
@@ -2843,6 +2962,7 @@ var DeepgramSTT = class {
|
|
|
2843
2962
|
ws.on("open", resolve);
|
|
2844
2963
|
ws.on("error", reject);
|
|
2845
2964
|
});
|
|
2965
|
+
this._log.info("Deepgram STT connected");
|
|
2846
2966
|
const feedPromise = (async () => {
|
|
2847
2967
|
try {
|
|
2848
2968
|
for await (const chunk of audioStream) {
|
|
@@ -2879,6 +2999,10 @@ var DeepgramSTT = class {
|
|
|
2879
2999
|
// src/agent/pipeline/elevenlabs-tts.ts
|
|
2880
3000
|
var ElevenLabsTTS = class {
|
|
2881
3001
|
_options;
|
|
3002
|
+
_log = NOOP_LOGGER;
|
|
3003
|
+
setLogger(logger) {
|
|
3004
|
+
this._log = logger;
|
|
3005
|
+
}
|
|
2882
3006
|
constructor(options = {}) {
|
|
2883
3007
|
this._options = {
|
|
2884
3008
|
voiceId: "EXAVITQu4vr4xnSDxMaL",
|
|
@@ -2978,7 +3102,7 @@ var ElevenLabsTTS = class {
|
|
|
2978
3102
|
}
|
|
2979
3103
|
});
|
|
2980
3104
|
ws.on("error", (err) => {
|
|
2981
|
-
|
|
3105
|
+
this._log.error({ err }, "ElevenLabs TTS error");
|
|
2982
3106
|
done = true;
|
|
2983
3107
|
if (resolveWait) {
|
|
2984
3108
|
resolveWait();
|
|
@@ -2989,16 +3113,19 @@ var ElevenLabsTTS = class {
|
|
|
2989
3113
|
ws.on("open", resolve);
|
|
2990
3114
|
ws.on("error", reject);
|
|
2991
3115
|
});
|
|
3116
|
+
this._log.info("ElevenLabs TTS connected");
|
|
2992
3117
|
const feedPromise = (async () => {
|
|
2993
3118
|
try {
|
|
2994
3119
|
for await (const chunk of textStream) {
|
|
2995
3120
|
if (done) break;
|
|
2996
3121
|
if (ws.readyState === 1) {
|
|
3122
|
+
this._log.debug("ElevenLabs sending text: %s", chunk.substring(0, 60));
|
|
2997
3123
|
ws.send(JSON.stringify({ text: chunk }));
|
|
2998
3124
|
}
|
|
2999
3125
|
}
|
|
3000
3126
|
} finally {
|
|
3001
3127
|
if (ws.readyState === 1) {
|
|
3128
|
+
this._log.debug("ElevenLabs sending EOS");
|
|
3002
3129
|
ws.send(JSON.stringify({ text: "" }));
|
|
3003
3130
|
}
|
|
3004
3131
|
}
|
|
@@ -3536,6 +3663,6 @@ function mcpServerHTTP(options) {
|
|
|
3536
3663
|
};
|
|
3537
3664
|
}
|
|
3538
3665
|
|
|
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 };
|
|
3666
|
+
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
3667
|
//# sourceMappingURL=index.js.map
|
|
3541
3668
|
//# sourceMappingURL=index.js.map
|