@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.
@@ -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
- console.error("[ControlWebSocket] Failed to parse message");
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
- console.error("[ControlWebSocket] Error:", err.message);
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
- console.error(`[ControlWebSocket] Error in handler for ${event.event}:`, err);
440
+ this._log.error({ err }, "Control WS handler error: %s", event.event);
427
441
  });
428
442
  }
429
443
  } catch (err) {
430
- console.error(`[ControlWebSocket] Error in handler for ${event.event}:`, err);
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
- console.error("[ControlWebSocket] Reconnect failed:", err);
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
- console.error(`[MCPClient] Failed to connect to server '${name}':`, err);
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
- console.error(`[MCPClient] Error disconnecting from '${name}':`, err);
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
- console.error("[MediaWebSocket] Error:", err.message);
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
- console.error("Error writing inbound audio:", err);
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
- console.error("Error writing outbound audio:", err);
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
- console.error("Error stopping recorder:", err);
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
- return collected.join("");
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
- console.error(`[CallSession] Error in ${event} handler:`, err);
1122
+ this._log.error({ err }, "CallSession handler error: %s", event);
1077
1123
  });
1078
1124
  }
1079
1125
  } catch (err) {
1080
- console.error(`[CallSession] Error in ${event} handler:`, err);
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
- console.log(`[ClawOpsAgent] Connected on ${this._fromNumber}`);
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
- console.log("[ClawOpsAgent] Disconnected");
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
- console.log(
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
- console.error(`[ClawOpsAgent] Error in call session ${callId}:`, err);
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
- console.error(`[ClawOpsAgent] Error in call session ${callId}:`, err);
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
- console.log(`[ClawOpsAgent] Outbound call ringing: ${callId}`);
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
- console.error("[ClawOpsAgent] feedDtmf error:", err);
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
- console.error("[ClawOpsAgent] MCP connection error:", err);
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
- console.error(`[ClawOpsAgent] Call session error:`, err);
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: { type: "object", properties: {}, required: [] }
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: { type: "string", description: "\uC804\uC1A1\uD560 \uBC88\uD638 (0-9, *, #). 'w'\uB294 500ms \uB300\uAE30, 'W'\uB294 1000ms \uB300\uAE30." }
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
- console.error("[OpenAIRealtime] WebSocket error:", err.message);
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 */)) toolSchemas.push(HANG_UP_TOOL);
1840
- if (!this._builtinTools || this._builtinTools.has("collect_dtmf" /* COLLECT_DTMF */)) toolSchemas.push(COLLECT_DTMF_TOOL);
1841
- if (!this._builtinTools || this._builtinTools.has("send_dtmf" /* SEND_DTMF */)) toolSchemas.push(SEND_DTMF_TOOL);
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: "gpt-4o-mini-transcribe",
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
- console.error("[OpenAIRealtime] API error:", msg["error"]);
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
- console.error(`[OpenAIRealtime] Unknown tool: ${funcName}`);
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
- console.error(`[OpenAIRealtime] Tool call failed: ${funcName}:`, err);
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
- console.error("[GeminiRealtime] SDK error:", err);
2326
+ this._log.error({ err }, "Gemini SDK error");
2241
2327
  },
2242
2328
  onclose: (ev) => {
2243
- console.log(
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
- console.log("[GeminiRealtime] Turn complete");
2409
+ this._log.debug("Turn complete");
2326
2410
  this._flushAudioRemainder();
2327
2411
  }
2328
2412
  if (serverContent.interrupted) {
2329
- console.log("[GeminiRealtime] Barge-in detected");
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
- console.log(`[GeminiRealtime] [TRANSCRIPT-USER] ${inputText}`);
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
- console.log(`[GeminiRealtime] [TRANSCRIPT-ASSISTANT] ${outputText}`);
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
- console.log(
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
- console.log(`[GeminiRealtime] Tool call: ${name}(${JSON.stringify(args)})`);
2476
+ this._log.info({ tool: name, args }, "Tool call: %s", name);
2398
2477
  if (name === "hang_up") {
2399
- console.log("[GeminiRealtime] hang_up: ending call");
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
- console.log(
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
- console.log(`[GeminiRealtime] DTMF collected: ${result || "(empty)"}`);
2494
+ this._log.info("DTMF collected: %s", result || "(empty)");
2418
2495
  } catch (err) {
2419
- console.error(`[GeminiRealtime] collect_dtmf error:`, err);
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
- console.log(`[GeminiRealtime] send_dtmf: digits="${args["digits"] ?? ""}"`);
2511
+ this._log.info('send_dtmf: digits="%s"', args["digits"] ?? "");
2435
2512
  await this._call.sendDtmfSequence(args["digits"] ?? "");
2436
2513
  result = "sent";
2437
- console.log(`[GeminiRealtime] send_dtmf: sent`);
2514
+ this._log.info("send_dtmf: sent");
2438
2515
  } catch (err) {
2439
- console.error(`[GeminiRealtime] send_dtmf error:`, err);
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
- console.error(`[GeminiRealtime] Unknown tool: ${name}`);
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
- console.log(`[GeminiRealtime] Tool result: ${name} -> ${resultStr.substring(0, 200)}`);
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
- console.error(`[GeminiRealtime] Tool call failed: ${name}:`, err);
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
- console.log(`[GeminiRealtime] Sending ${responses.length} tool response(s)`);
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
- console.error("[PipelineSession] Greeting error:", err);
2647
+ this._log.error({ err }, "Greeting error");
2560
2648
  });
2561
2649
  }
2562
2650
  this._runSttLoop().catch((err) => {
2563
- console.error("[PipelineSession] STT loop error:", err);
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
- console.error(`[PipelineSession] Tool call error for ${name}:`, err);
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
- console.error("[PipelineSession] TTS error:", err);
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
- console.error("[DeepgramSTT] WebSocket error:", err.message);
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
- console.error("[ElevenLabsTTS] WebSocket error:", err.message);
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