@teamlearners/clawops 0.41.0 → 0.42.0

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.
@@ -2,8 +2,8 @@
2
2
 
3
3
  var chunkLLPMUDNE_cjs = require('../chunk-LLPMUDNE.cjs');
4
4
  var chunkMXEZQRIL_cjs = require('../chunk-MXEZQRIL.cjs');
5
- var chunk7ZFSDBM6_cjs = require('../chunk-7ZFSDBM6.cjs');
6
- require('../chunk-WTG2QGQU.cjs');
5
+ var chunkMQXG2CWP_cjs = require('../chunk-MQXG2CWP.cjs');
6
+ require('../chunk-FQ5SY7WN.cjs');
7
7
  var fs = require('fs');
8
8
  var path = require('path');
9
9
 
@@ -32,6 +32,9 @@ var path__namespace = /*#__PURE__*/_interopNamespace(path);
32
32
  var INITIAL_RECONNECT_DELAY = 1e3;
33
33
  var MAX_RECONNECT_DELAY = 3e4;
34
34
  var PING_TIMEOUT = 6e4;
35
+ var CLOSE_REPLACED = 4409;
36
+ var CLOSE_OWNERSHIP_LOST = 4403;
37
+ var NON_RETRYABLE_CLOSE_CODES = /* @__PURE__ */ new Set([CLOSE_REPLACED, CLOSE_OWNERSHIP_LOST]);
35
38
  function buildControlWsUrl(options) {
36
39
  const scheme = options.baseUrl.startsWith("https") ? "wss" : "ws";
37
40
  const host = options.baseUrl.replace(/^https?:\/\//, "").replace(/\/$/, "");
@@ -57,7 +60,7 @@ var ControlWebSocket = class {
57
60
  _closed = false;
58
61
  _connectedResolve = null;
59
62
  _connectedPromise;
60
- _log = chunk7ZFSDBM6_cjs.NOOP_LOGGER;
63
+ _log = chunkMQXG2CWP_cjs.NOOP_LOGGER;
61
64
  _pingTimer = null;
62
65
  setLogger(logger) {
63
66
  this._log = logger;
@@ -153,11 +156,21 @@ var ControlWebSocket = class {
153
156
  this._log.warn("Control WS parse error");
154
157
  }
155
158
  });
156
- ws.on("close", () => {
159
+ ws.on("close", (code, reason) => {
157
160
  this._clearPingTimer();
158
- if (!this._closed) {
159
- this._scheduleReconnect();
161
+ if (this._closed) return;
162
+ if (NON_RETRYABLE_CLOSE_CODES.has(code)) {
163
+ const text = reason?.toString() || "";
164
+ this._closed = true;
165
+ this._log.info(
166
+ "Control WS closed by server (%d %s) \u2014 not reconnecting: this number is now served elsewhere",
167
+ code,
168
+ text
169
+ );
170
+ this._options.onTerminalClose?.({ code, reason: text });
171
+ return;
160
172
  }
173
+ this._scheduleReconnect();
161
174
  });
162
175
  ws.on("error", (err) => {
163
176
  this._log.warn("Control WS error: %s", err.message);
@@ -222,7 +235,7 @@ var ControlWebSocket = class {
222
235
  var MCPClient = class {
223
236
  _servers = /* @__PURE__ */ new Map();
224
237
  _clients = /* @__PURE__ */ new Map();
225
- _log = chunk7ZFSDBM6_cjs.NOOP_LOGGER;
238
+ _log = chunkMQXG2CWP_cjs.NOOP_LOGGER;
226
239
  setLogger(logger) {
227
240
  this._log = logger;
228
241
  }
@@ -364,7 +377,7 @@ var MediaWebSocket = class {
364
377
  _onClose = null;
365
378
  _onDtmf = null;
366
379
  _markWaiters = /* @__PURE__ */ new Map();
367
- _log = chunk7ZFSDBM6_cjs.NOOP_LOGGER;
380
+ _log = chunkMQXG2CWP_cjs.NOOP_LOGGER;
368
381
  setLogger(logger) {
369
382
  this._log = logger;
370
383
  }
@@ -590,7 +603,7 @@ var AudioRecorder = class {
590
603
  _started = false;
591
604
  _baseTs = null;
592
605
  _outCursor = 0;
593
- _log = chunk7ZFSDBM6_cjs.NOOP_LOGGER;
606
+ _log = chunkMQXG2CWP_cjs.NOOP_LOGGER;
594
607
  setLogger(logger) {
595
608
  this._log = logger;
596
609
  }
@@ -805,7 +818,7 @@ function generateComfortTone(volume = 0.12) {
805
818
  }
806
819
  }
807
820
  const pcm = int16ArrayToBuffer(concatInt16Arrays(...parts));
808
- const ulaw = chunk7ZFSDBM6_cjs.pcm16ToUlaw(pcm);
821
+ const ulaw = chunkMQXG2CWP_cjs.pcm16ToUlaw(pcm);
809
822
  const chunks = [];
810
823
  for (let i = 0; i < ulaw.length; i += CHUNK_SIZE) {
811
824
  chunks.push(ulaw.subarray(i, i + CHUNK_SIZE));
@@ -862,9 +875,9 @@ function loadHoldAudio(source) {
862
875
  pcmData = mono;
863
876
  }
864
877
  if (sampleRate !== SAMPLE_RATE2) {
865
- pcmData = chunk7ZFSDBM6_cjs.resamplePcm16(pcmData, sampleRate, SAMPLE_RATE2);
878
+ pcmData = chunkMQXG2CWP_cjs.resamplePcm16(pcmData, sampleRate, SAMPLE_RATE2);
866
879
  }
867
- const ulaw = chunk7ZFSDBM6_cjs.pcm16ToUlaw(pcmData);
880
+ const ulaw = chunkMQXG2CWP_cjs.pcm16ToUlaw(pcmData);
868
881
  const chunks = [];
869
882
  for (let i = 0; i < ulaw.length; i += CHUNK_SIZE) {
870
883
  chunks.push(ulaw.subarray(i, i + CHUNK_SIZE));
@@ -1099,6 +1112,8 @@ var ATTR_AGENT_ID = "clawops.agent.id";
1099
1112
 
1100
1113
  // src/agent/agent.ts
1101
1114
  var TERMINAL_FRAME_GRACE_MS = 2e3;
1115
+ var DEFAULT_DRAIN_TIMEOUT_MS = 12e4;
1116
+ var DRAIN_POLL_INTERVAL_MS = 200;
1102
1117
  var ClawOpsAgent = class _ClawOpsAgent {
1103
1118
  _apiKey;
1104
1119
  _accountId;
@@ -1112,6 +1127,17 @@ var ClawOpsAgent = class _ClawOpsAgent {
1112
1127
  _recording;
1113
1128
  _recordingPath;
1114
1129
  _activeSessions = /* @__PURE__ */ new Map();
1130
+ /** Set once the server hands this number to another process (rolling deploy takeover). */
1131
+ _takenOver = false;
1132
+ /**
1133
+ * Set once we deliberately give up the control connection (`drain()`/`disconnect()`).
1134
+ * Distinct from `_controlWs === null`, which also covers "never connected": only after a
1135
+ * hand-back is it certain that no server terminal frame can still arrive.
1136
+ */
1137
+ _controlGivenUp = false;
1138
+ /** serve()'s stop hook, so takeover can end the block the same way a signal does. */
1139
+ _stopServe = null;
1140
+ _onTakenOver;
1115
1141
  /** 미디어 정리를 마친 통화가 서버 종료 프레임을 기다리는 자리. callId → resolve. */
1116
1142
  _terminalWaiters = /* @__PURE__ */ new Map();
1117
1143
  _builtinTools;
@@ -1142,17 +1168,18 @@ var ClawOpsAgent = class _ClawOpsAgent {
1142
1168
  this._recording = options.recording ?? false;
1143
1169
  this._recordingPath = options.recordingPath ?? "./recordings";
1144
1170
  this._mcpServers = options.mcpServers ?? [];
1145
- this._builtinTools = chunk7ZFSDBM6_cjs.resolveBuiltinTools(options.builtinTools ?? "all" /* ALL */);
1171
+ this._builtinTools = chunkMQXG2CWP_cjs.resolveBuiltinTools(options.builtinTools ?? "all" /* ALL */);
1146
1172
  this._passiveDtmfDebounceMs = options.passiveDtmfDebounceMs ?? 500;
1147
1173
  this._rxGain = _ClawOpsAgent._validateGain("rxGain", options.rxGain ?? 1);
1148
1174
  this._txGain = _ClawOpsAgent._validateGain("txGain", options.txGain ?? 1);
1149
1175
  this._prewarmEnabled = options.prewarmEnabled ?? true;
1150
1176
  this._machineDetection = options.machineDetection;
1177
+ this._onTakenOver = options.onTakenOver;
1151
1178
  if (options.tracing) {
1152
1179
  setTracingConfig(options.tracing);
1153
1180
  }
1154
- this._log = chunk7ZFSDBM6_cjs.createAgentLogger(options.logger);
1155
- this._pipelineLog = chunk7ZFSDBM6_cjs.createPipelineLogger(this._log);
1181
+ this._log = chunkMQXG2CWP_cjs.createAgentLogger(options.logger);
1182
+ this._pipelineLog = chunkMQXG2CWP_cjs.createPipelineLogger(this._log);
1156
1183
  this._isPipelineSession = "_stt" in this._session && "_llm" in this._session;
1157
1184
  if (options.toolConfig?.holdAudio) {
1158
1185
  this._holdAudioChunks = loadHoldAudio(options.toolConfig.holdAudio);
@@ -1209,6 +1236,11 @@ var ClawOpsAgent = class _ClawOpsAgent {
1209
1236
  /** Connect to the ClawOps platform and start listening for calls. */
1210
1237
  async connect() {
1211
1238
  if (this._controlWs) return;
1239
+ if (this._takenOver) {
1240
+ throw new chunkMXEZQRIL_cjs.AgentError(
1241
+ `${this._fromNumber} is now served by another process \u2014 reconnecting would evict it. Start a new agent process instead of reconnecting this one.`
1242
+ );
1243
+ }
1212
1244
  if (!this._apiKey) {
1213
1245
  throw new chunkMXEZQRIL_cjs.AgentError("API key is required. Set CLAWOPS_API_KEY or pass apiKey option.");
1214
1246
  }
@@ -1217,11 +1249,13 @@ var ClawOpsAgent = class _ClawOpsAgent {
1217
1249
  "Account ID is required. Set CLAWOPS_ACCOUNT_ID or pass accountId option."
1218
1250
  );
1219
1251
  }
1252
+ this._controlGivenUp = false;
1220
1253
  this._controlWs = new ControlWebSocket({
1221
1254
  baseUrl: this._baseUrl,
1222
1255
  apiKey: this._apiKey,
1223
1256
  accountId: this._accountId,
1224
- number: this._fromNumber
1257
+ number: this._fromNumber,
1258
+ onTerminalClose: (info) => this._handleTakenOver(info)
1225
1259
  });
1226
1260
  this._controlWs.setLogger(this._log);
1227
1261
  this._controlWs.on("call.incoming", (event) => this._handleIncoming(event));
@@ -1233,7 +1267,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
1233
1267
  await this._controlWs.connect();
1234
1268
  await this._controlWs.waitConnected();
1235
1269
  try {
1236
- this._controlWs.send({ event: "agent.hello", sdk: chunk7ZFSDBM6_cjs.getSdkInfo() });
1270
+ this._controlWs.send({ event: "agent.hello", sdk: chunkMQXG2CWP_cjs.getSdkInfo() });
1237
1271
  } catch {
1238
1272
  }
1239
1273
  } catch (err) {
@@ -1244,21 +1278,140 @@ var ClawOpsAgent = class _ClawOpsAgent {
1244
1278
  this._log.info("ClawOpsAgent connected on %s", this._fromNumber);
1245
1279
  }
1246
1280
  /**
1247
- * Connect and block until disconnected.
1248
- * Convenience method for simple agent scripts.
1281
+ * Connect and block until it is time to stop.
1282
+ *
1283
+ * Returns on SIGINT/SIGTERM, or when another process takes over this number — in every case
1284
+ * after `drain()` has let in-flight calls finish. A second signal skips the wait and cuts them.
1285
+ *
1286
+ * Because it returns on takeover, a rolling deploy needs no shutdown wiring: bring the new
1287
+ * instance up, and the old one hands over the number, finishes the calls it still has, and
1288
+ * exits on its own. Give the platform a grace period longer than the drain timeout
1289
+ * (k8s `terminationGracePeriodSeconds`, ECS `stopTimeout`) so it does not SIGKILL mid-drain.
1290
+ *
1291
+ * @param options.drainTimeoutMs Passed through to `drain()`.
1249
1292
  */
1250
- async serve() {
1293
+ async serve(options) {
1251
1294
  await this.connect();
1252
1295
  return new Promise((resolve) => {
1253
- const shutdown = () => {
1254
- this.disconnect().then(resolve).catch(() => resolve());
1296
+ let stopping = false;
1297
+ let signals = 0;
1298
+ const finish = () => {
1299
+ process.off("SIGINT", onSigint);
1300
+ process.off("SIGTERM", onSigterm);
1301
+ this._stopServe = null;
1302
+ resolve();
1303
+ };
1304
+ const stop = (why) => {
1305
+ if (stopping) return;
1306
+ stopping = true;
1307
+ this._log.info("Stopping (%s) \u2014 draining in-flight calls", why);
1308
+ this.drain({ timeoutMs: options?.drainTimeoutMs }).then(finish).catch((err) => {
1309
+ this._log.error({ err }, "Drain failed");
1310
+ finish();
1311
+ });
1312
+ };
1313
+ const onSignal = (why) => {
1314
+ signals += 1;
1315
+ if (signals >= 2) {
1316
+ this._log.warn("Second stop signal (%s) \u2014 ending calls immediately", why);
1317
+ void this.disconnect().finally(finish);
1318
+ return;
1319
+ }
1320
+ if (stopping) {
1321
+ this._log.info(
1322
+ "%s arrived while draining \u2014 still waiting for in-flight calls (signal again to cut)",
1323
+ why
1324
+ );
1325
+ return;
1326
+ }
1327
+ stop(why);
1255
1328
  };
1256
- process.on("SIGINT", shutdown);
1257
- process.on("SIGTERM", shutdown);
1329
+ const onSigint = () => onSignal("SIGINT");
1330
+ const onSigterm = () => onSignal("SIGTERM");
1331
+ this._stopServe = stop;
1332
+ process.on("SIGINT", onSigint);
1333
+ process.on("SIGTERM", onSigterm);
1258
1334
  });
1259
1335
  }
1336
+ /**
1337
+ * The server handed this number's control connection to another process.
1338
+ *
1339
+ * Nothing here is an error: it is the normal middle of a rolling deploy, seen from the
1340
+ * instance being replaced. New calls already go to the new process, so all that is left is
1341
+ * to finish the calls we still hold and get out of the way. `serve()` does that by returning;
1342
+ * callers who wired `connect()` themselves get `onTakenOver` and should call `drain()`.
1343
+ */
1344
+ _handleTakenOver(info) {
1345
+ this._takenOver = true;
1346
+ this._log.info(
1347
+ "Another process now serves %s (close %d) \u2014 handing over",
1348
+ this._fromNumber,
1349
+ info.code
1350
+ );
1351
+ this._onTakenOver?.(info);
1352
+ this._stopServe?.("taken over");
1353
+ }
1354
+ /** Whether another process has taken over this number's control connection. */
1355
+ get takenOver() {
1356
+ return this._takenOver;
1357
+ }
1358
+ /**
1359
+ * Stop accepting new calls, let the ones already in progress finish, then disconnect.
1360
+ *
1361
+ * This is what a rolling deploy needs. `disconnect()` cuts live calls mid-sentence, which is
1362
+ * correct when you mean "stop now" and wrong when you mean "hand over". The two are separated
1363
+ * because only the caller knows which one a SIGTERM meant.
1364
+ *
1365
+ * It works because control and media are different connections. Closing the control WebSocket
1366
+ * only gives up this number's delivery slot — the server stops sending us `call.incoming` and
1367
+ * routes new calls to whichever process holds the slot next. Calls already up keep streaming
1368
+ * over their own per-call media connections, which nothing here touches, and each one tears
1369
+ * itself down normally when the caller hangs up.
1370
+ *
1371
+ * Deploy shape this is built for: start the new instance, let it take the slot (the server
1372
+ * hands it over and tells us not to reconnect), then drain the old one. New calls go to the
1373
+ * new instance from the moment it connects; in-flight calls end on the old one. No gap.
1374
+ *
1375
+ * One thing is given up: `endedDuration` on `call_end`. That figure rides the control
1376
+ * connection we just closed, so calls finishing during a drain report a null duration.
1377
+ *
1378
+ * @param options.timeoutMs How long to wait for in-flight calls. Default 120s. Calls still
1379
+ * running when it expires are ended the way `disconnect()` ends them. Keep the platform's
1380
+ * own grace period longer than this (k8s `terminationGracePeriodSeconds`, ECS
1381
+ * `stopTimeout`), or it will SIGKILL the process mid-drain and undo the point of draining.
1382
+ * @returns How many calls ended on their own, and how many had to be cut short.
1383
+ */
1384
+ async drain(options) {
1385
+ const timeoutMs = options?.timeoutMs ?? DEFAULT_DRAIN_TIMEOUT_MS;
1386
+ this._controlGivenUp = true;
1387
+ if (this._controlWs) {
1388
+ this._controlWs.close();
1389
+ this._controlWs = null;
1390
+ }
1391
+ for (const wake of [...this._terminalWaiters.values()]) wake();
1392
+ const inFlight = this._activeSessions.size;
1393
+ if (inFlight === 0) {
1394
+ this._log.info("Drain: no calls in progress");
1395
+ await this.disconnect();
1396
+ return { completed: 0, forced: 0 };
1397
+ }
1398
+ this._log.info("Drain: waiting for %d call(s) to finish (timeout %dms)", inFlight, timeoutMs);
1399
+ const deadline = Date.now() + timeoutMs;
1400
+ while (this._activeSessions.size > 0 && Date.now() < deadline) {
1401
+ await new Promise((resolve) => setTimeout(resolve, DRAIN_POLL_INTERVAL_MS));
1402
+ }
1403
+ const forced = this._activeSessions.size;
1404
+ if (forced > 0) {
1405
+ this._log.warn("Drain timed out \u2014 cutting %d call(s) still in progress", forced);
1406
+ } else {
1407
+ this._log.info("Drain complete: all %d call(s) finished", inFlight);
1408
+ }
1409
+ await this.disconnect();
1410
+ return { completed: inFlight - forced, forced };
1411
+ }
1260
1412
  /** Disconnect from the platform. */
1261
1413
  async disconnect() {
1414
+ this._controlGivenUp = true;
1262
1415
  if (this._controlWs) {
1263
1416
  this._controlWs.close();
1264
1417
  this._controlWs = null;
@@ -1305,7 +1458,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
1305
1458
  throw new chunkMXEZQRIL_cjs.AgentError(`\uBC1C\uC2E0 \uC2E4\uD328 (${resp.status}): ${error["error"] ?? ""}`);
1306
1459
  }
1307
1460
  const data = await resp.json();
1308
- const callSession = new chunk7ZFSDBM6_cjs.CallSession({
1461
+ const callSession = new chunkMQXG2CWP_cjs.CallSession({
1309
1462
  callId: data["callId"],
1310
1463
  fromNumber: this._fromNumber,
1311
1464
  toNumber: to,
@@ -1329,7 +1482,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
1329
1482
  const callId = event["callId"];
1330
1483
  const fromNumber = event["from"] ?? "";
1331
1484
  const mediaUrl = event["mediaUrl"] ?? "";
1332
- const session = new chunk7ZFSDBM6_cjs.CallSession({
1485
+ const session = new chunkMQXG2CWP_cjs.CallSession({
1333
1486
  callId,
1334
1487
  fromNumber,
1335
1488
  toNumber: this._fromNumber,
@@ -1363,6 +1516,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
1363
1516
  */
1364
1517
  async _awaitServerTerminal(session) {
1365
1518
  if (session.endedDuration !== null) return;
1519
+ if (this._controlGivenUp) return;
1366
1520
  await new Promise((resolve) => {
1367
1521
  const done = () => {
1368
1522
  clearTimeout(timer);
@@ -1430,7 +1584,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
1430
1584
  const mediaUrl = event["mediaUrl"] ?? "";
1431
1585
  let session = this._activeSessions.get(callId);
1432
1586
  if (!session) {
1433
- session = new chunk7ZFSDBM6_cjs.CallSession({
1587
+ session = new chunkMQXG2CWP_cjs.CallSession({
1434
1588
  callId,
1435
1589
  fromNumber: this._fromNumber,
1436
1590
  toNumber: event["to"] ?? "",
@@ -1632,9 +1786,9 @@ var ClawOpsAgent = class _ClawOpsAgent {
1632
1786
  let latestMediaTs = 0;
1633
1787
  session._bindTransport(
1634
1788
  (audio) => {
1635
- const gained = chunk7ZFSDBM6_cjs.applyUlawGain(audio, this._txGain);
1789
+ const gained = chunkMQXG2CWP_cjs.applyUlawGain(audio, this._txGain);
1636
1790
  if (recorder) {
1637
- recorder.writeOutbound(chunk7ZFSDBM6_cjs.ulawToPcm16(gained), latestMediaTs);
1791
+ recorder.writeOutbound(chunkMQXG2CWP_cjs.ulawToPcm16(gained), latestMediaTs);
1638
1792
  }
1639
1793
  mediaWs.sendAudio(gained.toString("base64"));
1640
1794
  session.recordFirstResponse();
@@ -1655,7 +1809,15 @@ var ClawOpsAgent = class _ClawOpsAgent {
1655
1809
  },
1656
1810
  () => mediaWs.isConnected
1657
1811
  );
1658
- session._transferFn = (params) => this._controlWs.requestTransfer(session.callId, params);
1812
+ session._transferFn = (params) => {
1813
+ const controlWs = this._controlWs;
1814
+ if (!controlWs) {
1815
+ throw new chunkMXEZQRIL_cjs.AgentError(
1816
+ "transfer unavailable: the control connection is closed (draining, or this number was taken over)"
1817
+ );
1818
+ }
1819
+ return controlWs.requestTransfer(session.callId, params);
1820
+ };
1659
1821
  session._sendMark = (name) => mediaWs.sendMark(name);
1660
1822
  session._waitForMark = (name, timeoutMs) => mediaWs.waitForMark(name, timeoutMs);
1661
1823
  session._flushTransport = () => mediaWs.flush();
@@ -1664,9 +1826,9 @@ var ClawOpsAgent = class _ClawOpsAgent {
1664
1826
  this._callSessions.set(session.callId, sessionHandler);
1665
1827
  mediaWs.onAudio((ulawAudio, timestamp) => {
1666
1828
  latestMediaTs = timestamp;
1667
- const gained = chunk7ZFSDBM6_cjs.applyUlawGain(ulawAudio, this._rxGain);
1829
+ const gained = chunkMQXG2CWP_cjs.applyUlawGain(ulawAudio, this._rxGain);
1668
1830
  if (recorder) {
1669
- recorder.writeInbound(chunk7ZFSDBM6_cjs.ulawToPcm16(gained), timestamp);
1831
+ recorder.writeInbound(chunkMQXG2CWP_cjs.ulawToPcm16(gained), timestamp);
1670
1832
  }
1671
1833
  if (sessionHandler) {
1672
1834
  sessionHandler.feedAudio(gained, timestamp);
@@ -1782,7 +1944,7 @@ var PipelineSession = class {
1782
1944
  _speaking = false;
1783
1945
  _builtinTools = null;
1784
1946
  _holdAudioChunks = null;
1785
- _log = chunk7ZFSDBM6_cjs.NOOP_LOGGER;
1947
+ _log = chunkMQXG2CWP_cjs.NOOP_LOGGER;
1786
1948
  constructor(options) {
1787
1949
  this._stt = options.stt;
1788
1950
  this._llm = options.llm;
@@ -1844,7 +2006,7 @@ var PipelineSession = class {
1844
2006
  */
1845
2007
  async prewarm(tools) {
1846
2008
  if (tools) this._tools = tools;
1847
- this._callSession = new chunk7ZFSDBM6_cjs.BufferingCall();
2009
+ this._callSession = new chunkMQXG2CWP_cjs.BufferingCall();
1848
2010
  this._running = true;
1849
2011
  this._conversation = [];
1850
2012
  this._log.info("PipelineSession prewarmed");
@@ -1867,7 +2029,7 @@ var PipelineSession = class {
1867
2029
  async attach(callSession) {
1868
2030
  const prev = this._callSession;
1869
2031
  this._callSession = callSession;
1870
- chunk7ZFSDBM6_cjs.attachBuffered(prev, callSession);
2032
+ chunkMQXG2CWP_cjs.attachBuffered(prev, callSession);
1871
2033
  }
1872
2034
  async start(callSession, tools) {
1873
2035
  this._tools = tools ?? null;
@@ -1914,8 +2076,8 @@ var PipelineSession = class {
1914
2076
  while (this._running) {
1915
2077
  if (this._audioBuffer.length > 0) {
1916
2078
  const ulaw = this._audioBuffer.shift();
1917
- const pcm8k = chunk7ZFSDBM6_cjs.ulawToPcm16(ulaw);
1918
- const pcm16k = chunk7ZFSDBM6_cjs.resamplePcm16(pcm8k, 8e3, 16e3);
2079
+ const pcm8k = chunkMQXG2CWP_cjs.ulawToPcm16(ulaw);
2080
+ const pcm16k = chunkMQXG2CWP_cjs.resamplePcm16(pcm8k, 8e3, 16e3);
1919
2081
  yield pcm16k;
1920
2082
  } else {
1921
2083
  await new Promise((resolve) => setTimeout(resolve, 20));
@@ -1931,7 +2093,7 @@ var PipelineSession = class {
1931
2093
  await this._respond();
1932
2094
  }
1933
2095
  _buildEffectiveTools() {
1934
- const builtinSchemas = chunk7ZFSDBM6_cjs.getBuiltinToolSchemas(this._builtinTools, "chat");
2096
+ const builtinSchemas = chunkMQXG2CWP_cjs.getBuiltinToolSchemas(this._builtinTools, "chat");
1935
2097
  const dtmfSchemas = builtinSchemas.filter((s) => {
1936
2098
  const name = s["function"]?.["name"];
1937
2099
  return name === "collect_dtmf" || name === "send_dtmf";
@@ -1980,8 +2142,8 @@ var PipelineSession = class {
1980
2142
  const { id, name, arguments: argsStr } = chunk.toolCall;
1981
2143
  try {
1982
2144
  const args = JSON.parse(argsStr);
1983
- if (chunk7ZFSDBM6_cjs.BUILTIN_TOOL_NAMES.has(name) && this._callSession && !(this._callSession instanceof chunk7ZFSDBM6_cjs.BufferingCall)) {
1984
- const result2 = await chunk7ZFSDBM6_cjs.executeBuiltinTool(name, args, this._callSession);
2145
+ if (chunkMQXG2CWP_cjs.BUILTIN_TOOL_NAMES.has(name) && this._callSession && !(this._callSession instanceof chunkMQXG2CWP_cjs.BufferingCall)) {
2146
+ const result2 = await chunkMQXG2CWP_cjs.executeBuiltinTool(name, args, this._callSession);
1985
2147
  if (result2 !== null) {
1986
2148
  if (name === "hang_up") return;
1987
2149
  this._conversation.push({ role: "tool", content: result2, tool_call_id: id, name });
@@ -1989,11 +2151,11 @@ var PipelineSession = class {
1989
2151
  return;
1990
2152
  }
1991
2153
  }
1992
- if (chunk7ZFSDBM6_cjs.BUILTIN_TOOL_NAMES.has(name) && this._callSession instanceof chunk7ZFSDBM6_cjs.BufferingCall) {
2154
+ if (chunkMQXG2CWP_cjs.BUILTIN_TOOL_NAMES.has(name) && this._callSession instanceof chunkMQXG2CWP_cjs.BufferingCall) {
1993
2155
  this._log.warn("Builtin tool %s called before answer \u2014 deferring", name);
1994
2156
  this._conversation.push({
1995
2157
  role: "tool",
1996
- content: chunk7ZFSDBM6_cjs.CALL_NOT_READY_RESULT,
2158
+ content: chunkMQXG2CWP_cjs.CALL_NOT_READY_RESULT,
1997
2159
  tool_call_id: id,
1998
2160
  name
1999
2161
  });
@@ -2002,7 +2164,7 @@ var PipelineSession = class {
2002
2164
  }
2003
2165
  if (!this._tools) return;
2004
2166
  this._callSession?.recordToolCall();
2005
- const player = this._holdAudioChunks && this._callSession && !(this._callSession instanceof chunk7ZFSDBM6_cjs.BufferingCall) ? new HoldAudioPlayer(this._callSession, this._holdAudioChunks) : null;
2167
+ const player = this._holdAudioChunks && this._callSession && !(this._callSession instanceof chunkMQXG2CWP_cjs.BufferingCall) ? new HoldAudioPlayer(this._callSession, this._holdAudioChunks) : null;
2006
2168
  player?.start();
2007
2169
  let result;
2008
2170
  try {
@@ -2053,8 +2215,8 @@ var PipelineSession = class {
2053
2215
  sampleRate: this._sampleRate
2054
2216
  })) {
2055
2217
  if (!this._running || !this._speaking) break;
2056
- const pcm8k = chunk7ZFSDBM6_cjs.resamplePcm16(audioChunk, this._sampleRate, 8e3);
2057
- const ulaw = chunk7ZFSDBM6_cjs.pcm16ToUlaw(pcm8k);
2218
+ const pcm8k = chunkMQXG2CWP_cjs.resamplePcm16(audioChunk, this._sampleRate, 8e3);
2219
+ const ulaw = chunkMQXG2CWP_cjs.pcm16ToUlaw(pcm8k);
2058
2220
  for (let off = 0; off < ulaw.length; off += 160) {
2059
2221
  let chunk = ulaw.subarray(off, off + 160);
2060
2222
  if (chunk.length < 160) {
@@ -2081,7 +2243,7 @@ var OpenAIRealtime = class {
2081
2243
  _language;
2082
2244
  _turnDetection;
2083
2245
  _greeting;
2084
- _log = chunk7ZFSDBM6_cjs.NOOP_LOGGER;
2246
+ _log = chunkMQXG2CWP_cjs.NOOP_LOGGER;
2085
2247
  _builtinTools = null;
2086
2248
  /**
2087
2249
  * 마지막 session.update 로 LLM 에 알린 tool 이름들. attach() 가 이 값과 현재
@@ -2158,7 +2320,7 @@ var OpenAIRealtime = class {
2158
2320
  /** Open WS + session.update + (optional) response.create without a CallSession. */
2159
2321
  async prewarm(tools) {
2160
2322
  if (tools) this._tools = tools;
2161
- this._call = new chunk7ZFSDBM6_cjs.BufferingCall();
2323
+ this._call = new chunkMQXG2CWP_cjs.BufferingCall();
2162
2324
  this._closed = false;
2163
2325
  this._playback = null;
2164
2326
  this._latestMediaTs = 0;
@@ -2200,7 +2362,7 @@ var OpenAIRealtime = class {
2200
2362
  this._resyncTools();
2201
2363
  const prev = this._call;
2202
2364
  this._call = callSession;
2203
- chunk7ZFSDBM6_cjs.attachBuffered(prev, callSession);
2365
+ chunkMQXG2CWP_cjs.attachBuffered(prev, callSession);
2204
2366
  }
2205
2367
  async start(callSession, tools) {
2206
2368
  if (tools) this._tools = tools;
@@ -2261,7 +2423,7 @@ var OpenAIRealtime = class {
2261
2423
  /** Current tool schemas: user tools + builtin tools (flat realtime format). */
2262
2424
  _currentToolSchemas() {
2263
2425
  const toolSchemas = this._tools ? this._tools.toOpenAITools().map((t) => ({ type: "function", ...t.function })) : [];
2264
- toolSchemas.push(...chunk7ZFSDBM6_cjs.getBuiltinToolSchemas(this._builtinTools, "realtime"));
2426
+ toolSchemas.push(...chunkMQXG2CWP_cjs.getBuiltinToolSchemas(this._builtinTools, "realtime"));
2265
2427
  return toolSchemas;
2266
2428
  }
2267
2429
  /**
@@ -2432,9 +2594,9 @@ var OpenAIRealtime = class {
2432
2594
  const controller = new AbortController();
2433
2595
  this._pendingToolCalls.set(callId, controller);
2434
2596
  try {
2435
- if (chunk7ZFSDBM6_cjs.BUILTIN_TOOL_NAMES.has(funcName) && this._call && !(this._call instanceof chunk7ZFSDBM6_cjs.BufferingCall)) {
2597
+ if (chunkMQXG2CWP_cjs.BUILTIN_TOOL_NAMES.has(funcName) && this._call && !(this._call instanceof chunkMQXG2CWP_cjs.BufferingCall)) {
2436
2598
  const args = JSON.parse(item["arguments"] ?? "{}");
2437
- const result2 = await chunk7ZFSDBM6_cjs.executeBuiltinTool(funcName, args, this._call);
2599
+ const result2 = await chunkMQXG2CWP_cjs.executeBuiltinTool(funcName, args, this._call);
2438
2600
  if (result2 !== null) {
2439
2601
  if (funcName === "hang_up") return;
2440
2602
  if (controller.signal.aborted) return;
@@ -2451,7 +2613,7 @@ var OpenAIRealtime = class {
2451
2613
  return;
2452
2614
  }
2453
2615
  }
2454
- if (chunk7ZFSDBM6_cjs.BUILTIN_TOOL_NAMES.has(funcName) && this._call instanceof chunk7ZFSDBM6_cjs.BufferingCall) {
2616
+ if (chunkMQXG2CWP_cjs.BUILTIN_TOOL_NAMES.has(funcName) && this._call instanceof chunkMQXG2CWP_cjs.BufferingCall) {
2455
2617
  this._log.warn("Builtin tool %s called before answer \u2014 deferring", funcName);
2456
2618
  await this._waitForResponseDone();
2457
2619
  this._send({
@@ -2459,7 +2621,7 @@ var OpenAIRealtime = class {
2459
2621
  item: {
2460
2622
  type: "function_call_output",
2461
2623
  call_id: callId,
2462
- output: chunk7ZFSDBM6_cjs.CALL_NOT_READY_RESULT
2624
+ output: chunkMQXG2CWP_cjs.CALL_NOT_READY_RESULT
2463
2625
  }
2464
2626
  });
2465
2627
  this._send({ type: "response.create" });
@@ -2480,7 +2642,7 @@ var OpenAIRealtime = class {
2480
2642
  return;
2481
2643
  }
2482
2644
  let result;
2483
- const player = this._holdAudioChunks && this._call && !(this._call instanceof chunk7ZFSDBM6_cjs.BufferingCall) ? new HoldAudioPlayer(this._call, this._holdAudioChunks) : null;
2645
+ const player = this._holdAudioChunks && this._call && !(this._call instanceof chunkMQXG2CWP_cjs.BufferingCall) ? new HoldAudioPlayer(this._call, this._holdAudioChunks) : null;
2484
2646
  player?.start();
2485
2647
  try {
2486
2648
  const args = JSON.parse(item["arguments"] ?? "{}");
@@ -2629,7 +2791,7 @@ var GeminiRealtime = class _GeminiRealtime {
2629
2791
  _toolDrainTimer = null;
2630
2792
  _lastAudioTime = 0;
2631
2793
  _holdAudioChunks = null;
2632
- _log = chunk7ZFSDBM6_cjs.NOOP_LOGGER;
2794
+ _log = chunkMQXG2CWP_cjs.NOOP_LOGGER;
2633
2795
  constructor(options = {}) {
2634
2796
  this._apiKey = options.apiKey ?? process.env["GOOGLE_API_KEY"] ?? "";
2635
2797
  this._systemPrompt = options.systemPrompt ?? "";
@@ -2675,7 +2837,7 @@ var GeminiRealtime = class _GeminiRealtime {
2675
2837
  /** Open Live session (no CallSession). Audio deltas accumulate into BufferingCall until attach(). */
2676
2838
  async prewarm(tools) {
2677
2839
  if (tools) this._tools = tools;
2678
- this._call = new chunk7ZFSDBM6_cjs.BufferingCall();
2840
+ this._call = new chunkMQXG2CWP_cjs.BufferingCall();
2679
2841
  this._closed = false;
2680
2842
  this._sentAudioChunks = 0;
2681
2843
  this._audioRemainder = Buffer.alloc(0);
@@ -2732,7 +2894,7 @@ var GeminiRealtime = class _GeminiRealtime {
2732
2894
  async attach(callSession) {
2733
2895
  const prev = this._call;
2734
2896
  this._call = callSession;
2735
- chunk7ZFSDBM6_cjs.attachBuffered(prev, callSession);
2897
+ chunkMQXG2CWP_cjs.attachBuffered(prev, callSession);
2736
2898
  }
2737
2899
  async start(callSession, tools) {
2738
2900
  if (tools) this._tools = tools;
@@ -2741,8 +2903,8 @@ var GeminiRealtime = class _GeminiRealtime {
2741
2903
  }
2742
2904
  feedAudio(audio) {
2743
2905
  if (this._session && !this._closed) {
2744
- const pcm8k = chunk7ZFSDBM6_cjs.ulawToPcm16(audio);
2745
- const pcm16k = chunk7ZFSDBM6_cjs.resamplePcm16(pcm8k, 8e3, 16e3);
2906
+ const pcm8k = chunkMQXG2CWP_cjs.ulawToPcm16(audio);
2907
+ const pcm16k = chunkMQXG2CWP_cjs.resamplePcm16(pcm8k, 8e3, 16e3);
2746
2908
  this._session.sendRealtimeInput({
2747
2909
  audio: {
2748
2910
  data: Buffer.from(pcm16k).toString("base64"),
@@ -2786,7 +2948,7 @@ var GeminiRealtime = class _GeminiRealtime {
2786
2948
  t.function.parameters ?? { type: "object", properties: {} }
2787
2949
  )
2788
2950
  })) : [];
2789
- toolDefs.push(...chunk7ZFSDBM6_cjs.getBuiltinToolSchemas(this._builtinTools, "gemini"));
2951
+ toolDefs.push(...chunkMQXG2CWP_cjs.getBuiltinToolSchemas(this._builtinTools, "gemini"));
2790
2952
  return toolDefs;
2791
2953
  }
2792
2954
  _handleMessage(msg) {
@@ -2846,8 +3008,8 @@ var GeminiRealtime = class _GeminiRealtime {
2846
3008
  _handleAudioData(b64Data) {
2847
3009
  if (!this._call) return;
2848
3010
  const pcm24k = Buffer.from(b64Data, "base64");
2849
- const pcm8k = chunk7ZFSDBM6_cjs.resamplePcm16(pcm24k, 24e3, 8e3);
2850
- const ulaw = chunk7ZFSDBM6_cjs.pcm16ToUlaw(pcm8k);
3011
+ const pcm8k = chunkMQXG2CWP_cjs.resamplePcm16(pcm24k, 24e3, 8e3);
3012
+ const ulaw = chunkMQXG2CWP_cjs.pcm16ToUlaw(pcm8k);
2851
3013
  const combined = Buffer.concat([this._audioRemainder, ulaw]);
2852
3014
  const chunkSize = 160;
2853
3015
  const fullEnd = Math.floor(combined.length / chunkSize) * chunkSize;
@@ -2890,7 +3052,7 @@ var GeminiRealtime = class _GeminiRealtime {
2890
3052
  const functionCalls = toolCall.functionCalls;
2891
3053
  if (!functionCalls) return;
2892
3054
  const responses = [];
2893
- const player = this._holdAudioChunks && this._call && !(this._call instanceof chunk7ZFSDBM6_cjs.BufferingCall) ? new HoldAudioPlayer(this._call, this._holdAudioChunks) : null;
3055
+ const player = this._holdAudioChunks && this._call && !(this._call instanceof chunkMQXG2CWP_cjs.BufferingCall) ? new HoldAudioPlayer(this._call, this._holdAudioChunks) : null;
2894
3056
  player?.start();
2895
3057
  try {
2896
3058
  for (const fc of functionCalls) {
@@ -2898,8 +3060,8 @@ var GeminiRealtime = class _GeminiRealtime {
2898
3060
  const fcId = fc.id ?? "";
2899
3061
  const args = fc.args ?? {};
2900
3062
  this._log.info({ tool: name, args }, "Tool call: %s", name);
2901
- if (chunk7ZFSDBM6_cjs.BUILTIN_TOOL_NAMES.has(name) && this._call && !(this._call instanceof chunk7ZFSDBM6_cjs.BufferingCall)) {
2902
- const result = await chunk7ZFSDBM6_cjs.executeBuiltinTool(
3063
+ if (chunkMQXG2CWP_cjs.BUILTIN_TOOL_NAMES.has(name) && this._call && !(this._call instanceof chunkMQXG2CWP_cjs.BufferingCall)) {
3064
+ const result = await chunkMQXG2CWP_cjs.executeBuiltinTool(
2903
3065
  name,
2904
3066
  args,
2905
3067
  this._call
@@ -2914,9 +3076,9 @@ var GeminiRealtime = class _GeminiRealtime {
2914
3076
  continue;
2915
3077
  }
2916
3078
  }
2917
- if (chunk7ZFSDBM6_cjs.BUILTIN_TOOL_NAMES.has(name) && this._call instanceof chunk7ZFSDBM6_cjs.BufferingCall) {
3079
+ if (chunkMQXG2CWP_cjs.BUILTIN_TOOL_NAMES.has(name) && this._call instanceof chunkMQXG2CWP_cjs.BufferingCall) {
2918
3080
  this._log.warn("Builtin tool %s called before answer \u2014 deferring", name);
2919
- responses.push({ id: fcId, name, response: { result: chunk7ZFSDBM6_cjs.CALL_NOT_READY_RESULT } });
3081
+ responses.push({ id: fcId, name, response: { result: chunkMQXG2CWP_cjs.CALL_NOT_READY_RESULT } });
2920
3082
  continue;
2921
3083
  }
2922
3084
  if (!this._tools || !this._tools.has(name)) {
@@ -2961,7 +3123,7 @@ var GeminiRealtime = class _GeminiRealtime {
2961
3123
  // src/agent/pipeline/stt/deepgram-stt.ts
2962
3124
  var DeepgramSTT = class {
2963
3125
  _options;
2964
- _log = chunk7ZFSDBM6_cjs.NOOP_LOGGER;
3126
+ _log = chunkMQXG2CWP_cjs.NOOP_LOGGER;
2965
3127
  get provider() {
2966
3128
  return "deepgram";
2967
3129
  }
@@ -3088,7 +3250,7 @@ var DeepgramSTT = class {
3088
3250
  // src/agent/pipeline/tts/elevenlabs-tts.ts
3089
3251
  var ElevenLabsTTS = class {
3090
3252
  _options;
3091
- _log = chunk7ZFSDBM6_cjs.NOOP_LOGGER;
3253
+ _log = chunkMQXG2CWP_cjs.NOOP_LOGGER;
3092
3254
  get provider() {
3093
3255
  return "elevenlabs";
3094
3256
  }
@@ -3834,55 +3996,55 @@ function mcpServerHTTP(options) {
3834
3996
 
3835
3997
  Object.defineProperty(exports, "BUILTIN_TOOL_NAMES", {
3836
3998
  enumerable: true,
3837
- get: function () { return chunk7ZFSDBM6_cjs.BUILTIN_TOOL_NAMES; }
3999
+ get: function () { return chunkMQXG2CWP_cjs.BUILTIN_TOOL_NAMES; }
3838
4000
  });
3839
4001
  Object.defineProperty(exports, "BuiltinTool", {
3840
4002
  enumerable: true,
3841
- get: function () { return chunk7ZFSDBM6_cjs.BuiltinTool; }
4003
+ get: function () { return chunkMQXG2CWP_cjs.BuiltinTool; }
3842
4004
  });
3843
4005
  Object.defineProperty(exports, "CallSession", {
3844
4006
  enumerable: true,
3845
- get: function () { return chunk7ZFSDBM6_cjs.CallSession; }
4007
+ get: function () { return chunkMQXG2CWP_cjs.CallSession; }
3846
4008
  });
3847
4009
  Object.defineProperty(exports, "DECODE_TABLE", {
3848
4010
  enumerable: true,
3849
- get: function () { return chunk7ZFSDBM6_cjs.DECODE_TABLE; }
4011
+ get: function () { return chunkMQXG2CWP_cjs.DECODE_TABLE; }
3850
4012
  });
3851
4013
  Object.defineProperty(exports, "DtmfCollectorBusyError", {
3852
4014
  enumerable: true,
3853
- get: function () { return chunk7ZFSDBM6_cjs.DtmfCollectorBusyError; }
4015
+ get: function () { return chunkMQXG2CWP_cjs.DtmfCollectorBusyError; }
3854
4016
  });
3855
4017
  Object.defineProperty(exports, "createAgentLogger", {
3856
4018
  enumerable: true,
3857
- get: function () { return chunk7ZFSDBM6_cjs.createAgentLogger; }
4019
+ get: function () { return chunkMQXG2CWP_cjs.createAgentLogger; }
3858
4020
  });
3859
4021
  Object.defineProperty(exports, "createPipelineLogger", {
3860
4022
  enumerable: true,
3861
- get: function () { return chunk7ZFSDBM6_cjs.createPipelineLogger; }
4023
+ get: function () { return chunkMQXG2CWP_cjs.createPipelineLogger; }
3862
4024
  });
3863
4025
  Object.defineProperty(exports, "executeBuiltinTool", {
3864
4026
  enumerable: true,
3865
- get: function () { return chunk7ZFSDBM6_cjs.executeBuiltinTool; }
4027
+ get: function () { return chunkMQXG2CWP_cjs.executeBuiltinTool; }
3866
4028
  });
3867
4029
  Object.defineProperty(exports, "getBuiltinToolSchemas", {
3868
4030
  enumerable: true,
3869
- get: function () { return chunk7ZFSDBM6_cjs.getBuiltinToolSchemas; }
4031
+ get: function () { return chunkMQXG2CWP_cjs.getBuiltinToolSchemas; }
3870
4032
  });
3871
4033
  Object.defineProperty(exports, "isBuiltinTool", {
3872
4034
  enumerable: true,
3873
- get: function () { return chunk7ZFSDBM6_cjs.isBuiltinTool; }
4035
+ get: function () { return chunkMQXG2CWP_cjs.isBuiltinTool; }
3874
4036
  });
3875
4037
  Object.defineProperty(exports, "pcm16ToUlaw", {
3876
4038
  enumerable: true,
3877
- get: function () { return chunk7ZFSDBM6_cjs.pcm16ToUlaw; }
4039
+ get: function () { return chunkMQXG2CWP_cjs.pcm16ToUlaw; }
3878
4040
  });
3879
4041
  Object.defineProperty(exports, "resamplePcm16", {
3880
4042
  enumerable: true,
3881
- get: function () { return chunk7ZFSDBM6_cjs.resamplePcm16; }
4043
+ get: function () { return chunkMQXG2CWP_cjs.resamplePcm16; }
3882
4044
  });
3883
4045
  Object.defineProperty(exports, "ulawToPcm16", {
3884
4046
  enumerable: true,
3885
- get: function () { return chunk7ZFSDBM6_cjs.ulawToPcm16; }
4047
+ get: function () { return chunkMQXG2CWP_cjs.ulawToPcm16; }
3886
4048
  });
3887
4049
  exports.AnthropicLLM = AnthropicLLM;
3888
4050
  exports.AudioRecorder = AudioRecorder;