@teamlearners/clawops 0.30.0 → 0.32.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.
- package/dist/agent/index.cjs +143 -74
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +15 -2
- package/dist/agent/index.d.ts +15 -2
- package/dist/agent/index.js +73 -4
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/livekit/index.cjs +8 -8
- package/dist/agent/livekit/index.d.cts +1 -1
- package/dist/agent/livekit/index.d.ts +1 -1
- package/dist/agent/livekit/index.js +1 -1
- package/dist/{base-Cje1TDJi.d.cts → base-B6S9WQRN.d.cts} +21 -0
- package/dist/{base-Cje1TDJi.d.ts → base-B6S9WQRN.d.ts} +21 -0
- package/dist/{chunk-WKGTY7QT.js → chunk-4YLSDMLL.js} +10 -4
- package/dist/chunk-4YLSDMLL.js.map +1 -0
- package/dist/{chunk-IGFGK3XZ.cjs → chunk-HKXRJRAW.cjs} +3 -3
- package/dist/{chunk-IGFGK3XZ.cjs.map → chunk-HKXRJRAW.cjs.map} +1 -1
- package/dist/{chunk-622J6BJ5.js → chunk-MXJ2LM6R.js} +3 -3
- package/dist/{chunk-622J6BJ5.js.map → chunk-MXJ2LM6R.js.map} +1 -1
- package/dist/{chunk-XAOA3XFQ.cjs → chunk-QD2ZY4UP.cjs} +10 -4
- package/dist/chunk-QD2ZY4UP.cjs.map +1 -0
- package/dist/index.cjs +35 -35
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-WKGTY7QT.js.map +0 -1
- package/dist/chunk-XAOA3XFQ.cjs.map +0 -1
package/dist/agent/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkHKXRJRAW_cjs = require('../chunk-HKXRJRAW.cjs');
|
|
4
|
+
var chunkQD2ZY4UP_cjs = require('../chunk-QD2ZY4UP.cjs');
|
|
5
5
|
var fs = require('fs');
|
|
6
6
|
var path = require('path');
|
|
7
7
|
var os = require('os');
|
|
@@ -59,7 +59,7 @@ var ControlWebSocket = class {
|
|
|
59
59
|
_closed = false;
|
|
60
60
|
_connectedResolve = null;
|
|
61
61
|
_connectedPromise;
|
|
62
|
-
_log =
|
|
62
|
+
_log = chunkQD2ZY4UP_cjs.NOOP_LOGGER;
|
|
63
63
|
_pingTimer = null;
|
|
64
64
|
setLogger(logger) {
|
|
65
65
|
this._log = logger;
|
|
@@ -224,7 +224,7 @@ var ControlWebSocket = class {
|
|
|
224
224
|
var MCPClient = class {
|
|
225
225
|
_servers = /* @__PURE__ */ new Map();
|
|
226
226
|
_clients = /* @__PURE__ */ new Map();
|
|
227
|
-
_log =
|
|
227
|
+
_log = chunkQD2ZY4UP_cjs.NOOP_LOGGER;
|
|
228
228
|
setLogger(logger) {
|
|
229
229
|
this._log = logger;
|
|
230
230
|
}
|
|
@@ -366,7 +366,7 @@ var MediaWebSocket = class {
|
|
|
366
366
|
_onClose = null;
|
|
367
367
|
_onDtmf = null;
|
|
368
368
|
_markWaiters = /* @__PURE__ */ new Map();
|
|
369
|
-
_log =
|
|
369
|
+
_log = chunkQD2ZY4UP_cjs.NOOP_LOGGER;
|
|
370
370
|
setLogger(logger) {
|
|
371
371
|
this._log = logger;
|
|
372
372
|
}
|
|
@@ -592,7 +592,7 @@ var AudioRecorder = class {
|
|
|
592
592
|
_started = false;
|
|
593
593
|
_baseTs = null;
|
|
594
594
|
_outCursor = 0;
|
|
595
|
-
_log =
|
|
595
|
+
_log = chunkQD2ZY4UP_cjs.NOOP_LOGGER;
|
|
596
596
|
setLogger(logger) {
|
|
597
597
|
this._log = logger;
|
|
598
598
|
}
|
|
@@ -728,7 +728,7 @@ var MAX_ERROR_MESSAGE_LENGTH = 200;
|
|
|
728
728
|
function getSdkInfo() {
|
|
729
729
|
return {
|
|
730
730
|
name: "clawops-node",
|
|
731
|
-
version:
|
|
731
|
+
version: chunkHKXRJRAW_cjs.VERSION,
|
|
732
732
|
runtime: `node/${process.versions.node}`,
|
|
733
733
|
os: `${process.platform}/${os__default.default.arch()}`
|
|
734
734
|
};
|
|
@@ -765,6 +765,7 @@ var CallSession = class {
|
|
|
765
765
|
metadata;
|
|
766
766
|
_status;
|
|
767
767
|
_endedStatus = null;
|
|
768
|
+
_endedDuration = null;
|
|
768
769
|
_sendAudioFn = null;
|
|
769
770
|
_clearAudioFn = null;
|
|
770
771
|
_hangupFn = null;
|
|
@@ -788,7 +789,7 @@ var CallSession = class {
|
|
|
788
789
|
_dtmfCollectorActive = false;
|
|
789
790
|
_dtmfResolvers = [];
|
|
790
791
|
_dtmfBuffer = [];
|
|
791
|
-
_log =
|
|
792
|
+
_log = chunkQD2ZY4UP_cjs.NOOP_LOGGER;
|
|
792
793
|
_handlers = /* @__PURE__ */ new Map();
|
|
793
794
|
_endedPromise;
|
|
794
795
|
_resolveEnded;
|
|
@@ -824,9 +825,22 @@ var CallSession = class {
|
|
|
824
825
|
get endedStatus() {
|
|
825
826
|
return this._endedStatus;
|
|
826
827
|
}
|
|
828
|
+
/**
|
|
829
|
+
* 서버가 확정한 통화 시간(초). 통화가 끝나기 전에는 `null`.
|
|
830
|
+
*
|
|
831
|
+
* ⚠️ `duration` 과 다르다 — 그쪽은 SDK 가 로컬 시계로 재는 **경과 시간**이라 통화 중에도
|
|
832
|
+
* 읽히고, 세션이 붙기 전후의 오차를 포함한다. 기록·정산에 쓸 값은 이쪽이다.
|
|
833
|
+
*/
|
|
834
|
+
get endedDuration() {
|
|
835
|
+
return this._endedDuration;
|
|
836
|
+
}
|
|
827
837
|
get duration() {
|
|
828
838
|
return (Date.now() - this.startTime.getTime()) / 1e3;
|
|
829
839
|
}
|
|
840
|
+
/** @internal 서버가 통보한 통화 시간을 확정한다. */
|
|
841
|
+
_setEndedDuration(seconds) {
|
|
842
|
+
this._endedDuration = seconds;
|
|
843
|
+
}
|
|
830
844
|
get metrics() {
|
|
831
845
|
return this._metrics;
|
|
832
846
|
}
|
|
@@ -954,11 +968,27 @@ var CallSession = class {
|
|
|
954
968
|
* directly to a SIP endpoint without going through the PSTN carrier. Requires the
|
|
955
969
|
* account to have an active `sip_trunk` add-on; otherwise the transfer fails and
|
|
956
970
|
* the call continues with the AI (result `{ status: 'failed', ... }`).
|
|
971
|
+
*
|
|
972
|
+
* 전환받는 쪽에 표시되는 발신번호는 기본이 **계정 보유번호**(인바운드면 착신 070)다.
|
|
973
|
+
*
|
|
974
|
+
* `callerIdMode: 'original'` 은 인바운드 통화의 **원 발신자 번호를 승계하려는 선호**다.
|
|
975
|
+
* 승계할 수 없는 통화(KCT 직결 인입이 아니거나 국내 번호로 정규화되지 않는 발신번호)면
|
|
976
|
+
* 조용히 계정 보유번호로 내려앉고 **전환은 그대로 성사된다**.
|
|
977
|
+
*
|
|
978
|
+
* `callerId` 는 번호를 직접 주는 **지시**라 성격이 다르다. 허용 범위(계정 보유번호 또는
|
|
979
|
+
* KCT 직결 인입의 원 발신자)를 벗어나면 전환 자체가 실패한다. 둘 다 주면 `callerId` 가
|
|
980
|
+
* 이기고 `callerIdMode` 는 무시된다 — 우선순위 판단은 서버가 한다.
|
|
957
981
|
*/
|
|
958
982
|
async transfer(to, options) {
|
|
959
983
|
if (!this._transferFn) {
|
|
960
984
|
throw new Error("transfer not available");
|
|
961
985
|
}
|
|
986
|
+
const callerIdMode = options?.callerIdMode;
|
|
987
|
+
if (callerIdMode !== void 0 && callerIdMode !== "account" && callerIdMode !== "original") {
|
|
988
|
+
throw new Error(
|
|
989
|
+
`callerIdMode must be 'account' or 'original', got ${JSON.stringify(callerIdMode)}`
|
|
990
|
+
);
|
|
991
|
+
}
|
|
962
992
|
return this._transferFn({
|
|
963
993
|
to,
|
|
964
994
|
destinationType: options?.destinationType ?? "pstn",
|
|
@@ -968,7 +998,9 @@ var CallSession = class {
|
|
|
968
998
|
whisper: options?.whisper ?? null,
|
|
969
999
|
context: options?.context ?? null,
|
|
970
1000
|
callerId: options?.callerId ?? null,
|
|
971
|
-
timeout: options?.timeout ?? 30
|
|
1001
|
+
timeout: options?.timeout ?? 30,
|
|
1002
|
+
// 안 주면 키를 붙이지 않는다 — 구 서버와 기존 동작을 그대로 둔다(additive).
|
|
1003
|
+
...callerIdMode !== void 0 ? { callerIdMode } : {}
|
|
972
1004
|
});
|
|
973
1005
|
}
|
|
974
1006
|
/** Register an event handler. */
|
|
@@ -1105,7 +1137,7 @@ function generateComfortTone(volume = 0.12) {
|
|
|
1105
1137
|
}
|
|
1106
1138
|
}
|
|
1107
1139
|
const pcm = int16ArrayToBuffer(concatInt16Arrays(...parts));
|
|
1108
|
-
const ulaw =
|
|
1140
|
+
const ulaw = chunkQD2ZY4UP_cjs.pcm16ToUlaw(pcm);
|
|
1109
1141
|
const chunks = [];
|
|
1110
1142
|
for (let i = 0; i < ulaw.length; i += CHUNK_SIZE) {
|
|
1111
1143
|
chunks.push(ulaw.subarray(i, i + CHUNK_SIZE));
|
|
@@ -1162,9 +1194,9 @@ function loadHoldAudio(source) {
|
|
|
1162
1194
|
pcmData = mono;
|
|
1163
1195
|
}
|
|
1164
1196
|
if (sampleRate !== SAMPLE_RATE2) {
|
|
1165
|
-
pcmData =
|
|
1197
|
+
pcmData = chunkQD2ZY4UP_cjs.resamplePcm16(pcmData, sampleRate, SAMPLE_RATE2);
|
|
1166
1198
|
}
|
|
1167
|
-
const ulaw =
|
|
1199
|
+
const ulaw = chunkQD2ZY4UP_cjs.pcm16ToUlaw(pcmData);
|
|
1168
1200
|
const chunks = [];
|
|
1169
1201
|
for (let i = 0; i < ulaw.length; i += CHUNK_SIZE) {
|
|
1170
1202
|
chunks.push(ulaw.subarray(i, i + CHUNK_SIZE));
|
|
@@ -1398,6 +1430,7 @@ var ATTR_CALL_DIRECTION = "clawops.call.direction";
|
|
|
1398
1430
|
var ATTR_AGENT_ID = "clawops.agent.id";
|
|
1399
1431
|
|
|
1400
1432
|
// src/agent/agent.ts
|
|
1433
|
+
var TERMINAL_FRAME_GRACE_MS = 2e3;
|
|
1401
1434
|
var ClawOpsAgent = class _ClawOpsAgent {
|
|
1402
1435
|
_apiKey;
|
|
1403
1436
|
_accountId;
|
|
@@ -1411,6 +1444,8 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1411
1444
|
_recording;
|
|
1412
1445
|
_recordingPath;
|
|
1413
1446
|
_activeSessions = /* @__PURE__ */ new Map();
|
|
1447
|
+
/** 미디어 정리를 마친 통화가 서버 종료 프레임을 기다리는 자리. callId → resolve. */
|
|
1448
|
+
_terminalWaiters = /* @__PURE__ */ new Map();
|
|
1414
1449
|
_builtinTools;
|
|
1415
1450
|
_passiveDtmfDebounceMs;
|
|
1416
1451
|
_passiveDtmfBuffer = [];
|
|
@@ -1433,13 +1468,13 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1433
1468
|
constructor(options) {
|
|
1434
1469
|
this._apiKey = options.apiKey ?? process.env["CLAWOPS_API_KEY"] ?? "";
|
|
1435
1470
|
this._accountId = options.accountId ?? process.env["CLAWOPS_ACCOUNT_ID"] ?? "";
|
|
1436
|
-
this._baseUrl = options.baseUrl ??
|
|
1471
|
+
this._baseUrl = options.baseUrl ?? chunkHKXRJRAW_cjs.DEFAULT_BASE_URL;
|
|
1437
1472
|
this._fromNumber = options.from;
|
|
1438
1473
|
this._session = options.session;
|
|
1439
1474
|
this._recording = options.recording ?? false;
|
|
1440
1475
|
this._recordingPath = options.recordingPath ?? "./recordings";
|
|
1441
1476
|
this._mcpServers = options.mcpServers ?? [];
|
|
1442
|
-
this._builtinTools =
|
|
1477
|
+
this._builtinTools = chunkQD2ZY4UP_cjs.resolveBuiltinTools(options.builtinTools ?? "all" /* ALL */);
|
|
1443
1478
|
this._passiveDtmfDebounceMs = options.passiveDtmfDebounceMs ?? 500;
|
|
1444
1479
|
this._rxGain = _ClawOpsAgent._validateGain("rxGain", options.rxGain ?? 1);
|
|
1445
1480
|
this._txGain = _ClawOpsAgent._validateGain("txGain", options.txGain ?? 1);
|
|
@@ -1448,8 +1483,8 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1448
1483
|
if (options.tracing) {
|
|
1449
1484
|
setTracingConfig(options.tracing);
|
|
1450
1485
|
}
|
|
1451
|
-
this._log =
|
|
1452
|
-
this._pipelineLog =
|
|
1486
|
+
this._log = chunkQD2ZY4UP_cjs.createAgentLogger(options.logger);
|
|
1487
|
+
this._pipelineLog = chunkQD2ZY4UP_cjs.createPipelineLogger(this._log);
|
|
1453
1488
|
this._isPipelineSession = "_stt" in this._session && "_llm" in this._session;
|
|
1454
1489
|
if (options.toolConfig?.holdAudio) {
|
|
1455
1490
|
this._holdAudioChunks = loadHoldAudio(options.toolConfig.holdAudio);
|
|
@@ -1457,7 +1492,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1457
1492
|
}
|
|
1458
1493
|
static _validateGain(name, gain) {
|
|
1459
1494
|
if (typeof gain !== "number" || !Number.isFinite(gain) || gain < 0) {
|
|
1460
|
-
throw new
|
|
1495
|
+
throw new chunkHKXRJRAW_cjs.AgentError(`${name}=${gain} must be a finite number >= 0`);
|
|
1461
1496
|
}
|
|
1462
1497
|
return gain;
|
|
1463
1498
|
}
|
|
@@ -1471,7 +1506,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1471
1506
|
tool(nameOrTool, description, parameters, handler) {
|
|
1472
1507
|
if (typeof nameOrTool === "string") {
|
|
1473
1508
|
if (!description || !parameters || !handler) {
|
|
1474
|
-
throw new
|
|
1509
|
+
throw new chunkHKXRJRAW_cjs.AgentError(
|
|
1475
1510
|
"tool(name, description, parameters, handler) requires all arguments."
|
|
1476
1511
|
);
|
|
1477
1512
|
}
|
|
@@ -1507,10 +1542,10 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1507
1542
|
async connect() {
|
|
1508
1543
|
if (this._controlWs) return;
|
|
1509
1544
|
if (!this._apiKey) {
|
|
1510
|
-
throw new
|
|
1545
|
+
throw new chunkHKXRJRAW_cjs.AgentError("API key is required. Set CLAWOPS_API_KEY or pass apiKey option.");
|
|
1511
1546
|
}
|
|
1512
1547
|
if (!this._accountId) {
|
|
1513
|
-
throw new
|
|
1548
|
+
throw new chunkHKXRJRAW_cjs.AgentError(
|
|
1514
1549
|
"Account ID is required. Set CLAWOPS_ACCOUNT_ID or pass accountId option."
|
|
1515
1550
|
);
|
|
1516
1551
|
}
|
|
@@ -1534,7 +1569,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1534
1569
|
} catch {
|
|
1535
1570
|
}
|
|
1536
1571
|
} catch (err) {
|
|
1537
|
-
throw new
|
|
1572
|
+
throw new chunkHKXRJRAW_cjs.AgentConnectionError(
|
|
1538
1573
|
`Failed to connect to ClawOps: ${err instanceof Error ? err.message : String(err)}`
|
|
1539
1574
|
);
|
|
1540
1575
|
}
|
|
@@ -1560,6 +1595,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1560
1595
|
this._controlWs.close();
|
|
1561
1596
|
this._controlWs = null;
|
|
1562
1597
|
}
|
|
1598
|
+
for (const wake of [...this._terminalWaiters.values()]) wake();
|
|
1563
1599
|
for (const session of this._activeSessions.values()) {
|
|
1564
1600
|
session._markEnded();
|
|
1565
1601
|
}
|
|
@@ -1598,7 +1634,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1598
1634
|
});
|
|
1599
1635
|
if (resp.status !== 201) {
|
|
1600
1636
|
const error = await resp.json();
|
|
1601
|
-
throw new
|
|
1637
|
+
throw new chunkHKXRJRAW_cjs.AgentError(`\uBC1C\uC2E0 \uC2E4\uD328 (${resp.status}): ${error["error"] ?? ""}`);
|
|
1602
1638
|
}
|
|
1603
1639
|
const data = await resp.json();
|
|
1604
1640
|
const callSession = new CallSession({
|
|
@@ -1647,12 +1683,43 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1647
1683
|
this._safeStartCallSession(session, mediaUrl, callId);
|
|
1648
1684
|
}
|
|
1649
1685
|
}
|
|
1686
|
+
/**
|
|
1687
|
+
* 서버 종료 프레임을 짧게 기다린다. 미디어 정리 직후에만 부른다.
|
|
1688
|
+
*
|
|
1689
|
+
* 왜 기다리나: `call_end` 는 인바운드 사용자가 통화 결과를 받는 **유일한 통로**인데, 서버는
|
|
1690
|
+
* 미디어 WS 를 먼저 닫고 자원 정리를 마친 뒤에야 control 종료 프레임을 보낸다. 안 기다리면
|
|
1691
|
+
* 그 핸들러 안에서 `endedDuration` 은 영영 null 이다.
|
|
1692
|
+
*
|
|
1693
|
+
* 상한을 다 쓰는 경우는 제어 연결이 죽어 프레임이 아예 안 오는 때뿐이다 — 그 프레임은
|
|
1694
|
+
* 예전부터 늘 오던 것이고(이번에 바뀐 건 내용뿐), 정상 경로에서는 밀리초 안에 풀린다.
|
|
1695
|
+
*/
|
|
1696
|
+
async _awaitServerTerminal(session) {
|
|
1697
|
+
if (session.endedDuration !== null) return;
|
|
1698
|
+
await new Promise((resolve) => {
|
|
1699
|
+
const done = () => {
|
|
1700
|
+
clearTimeout(timer);
|
|
1701
|
+
this._terminalWaiters.delete(session.callId);
|
|
1702
|
+
resolve();
|
|
1703
|
+
};
|
|
1704
|
+
const timer = setTimeout(() => {
|
|
1705
|
+
this._log.debug(
|
|
1706
|
+
"\uC11C\uBC84 \uC885\uB8CC \uD504\uB808\uC784\uC774 %dms \uC548\uC5D0 \uC624\uC9C0 \uC54A\uC558\uB2E4 \u2014 endedDuration \uC5C6\uC774 \uC9C4\uD589: %s",
|
|
1707
|
+
TERMINAL_FRAME_GRACE_MS,
|
|
1708
|
+
session.callId
|
|
1709
|
+
);
|
|
1710
|
+
done();
|
|
1711
|
+
}, TERMINAL_FRAME_GRACE_MS);
|
|
1712
|
+
this._terminalWaiters.set(session.callId, done);
|
|
1713
|
+
});
|
|
1714
|
+
}
|
|
1650
1715
|
_handleEnded(event) {
|
|
1651
1716
|
const callId = event["callId"];
|
|
1652
1717
|
const status = event["status"] || "completed";
|
|
1718
|
+
const endedDuration = event["duration"];
|
|
1653
1719
|
const session = this._activeSessions.get(callId);
|
|
1654
1720
|
if (session) {
|
|
1655
1721
|
this._log.info("Call ended (server): %s (status=%s)", callId, status);
|
|
1722
|
+
if (typeof endedDuration === "number") session._setEndedDuration(endedDuration);
|
|
1656
1723
|
if (status !== "completed") {
|
|
1657
1724
|
this._log.info("Outbound call not connected: %s (%s)", callId, status);
|
|
1658
1725
|
session._emit("call_failed", status);
|
|
@@ -1660,6 +1727,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1660
1727
|
session._markEnded(status);
|
|
1661
1728
|
this._activeSessions.delete(callId);
|
|
1662
1729
|
}
|
|
1730
|
+
this._terminalWaiters.get(callId)?.();
|
|
1663
1731
|
void this._cleanupPrewarm(callId);
|
|
1664
1732
|
}
|
|
1665
1733
|
/**
|
|
@@ -1896,9 +1964,9 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1896
1964
|
let latestMediaTs = 0;
|
|
1897
1965
|
session._bindTransport(
|
|
1898
1966
|
(audio) => {
|
|
1899
|
-
const gained =
|
|
1967
|
+
const gained = chunkQD2ZY4UP_cjs.applyUlawGain(audio, this._txGain);
|
|
1900
1968
|
if (recorder) {
|
|
1901
|
-
recorder.writeOutbound(
|
|
1969
|
+
recorder.writeOutbound(chunkQD2ZY4UP_cjs.ulawToPcm16(gained), latestMediaTs);
|
|
1902
1970
|
}
|
|
1903
1971
|
mediaWs.sendAudio(gained.toString("base64"));
|
|
1904
1972
|
session.recordFirstResponse();
|
|
@@ -1928,9 +1996,9 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1928
1996
|
this._callSessions.set(session.callId, sessionHandler);
|
|
1929
1997
|
mediaWs.onAudio((ulawAudio, timestamp) => {
|
|
1930
1998
|
latestMediaTs = timestamp;
|
|
1931
|
-
const gained =
|
|
1999
|
+
const gained = chunkQD2ZY4UP_cjs.applyUlawGain(ulawAudio, this._rxGain);
|
|
1932
2000
|
if (recorder) {
|
|
1933
|
-
recorder.writeInbound(
|
|
2001
|
+
recorder.writeInbound(chunkQD2ZY4UP_cjs.ulawToPcm16(gained), timestamp);
|
|
1934
2002
|
}
|
|
1935
2003
|
if (sessionHandler) {
|
|
1936
2004
|
sessionHandler.feedAudio(gained, timestamp);
|
|
@@ -2014,6 +2082,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
2014
2082
|
this._controlWs?.send({ event: "call.metrics", callId: session.callId, metrics: session.metrics });
|
|
2015
2083
|
} catch {
|
|
2016
2084
|
}
|
|
2085
|
+
await this._awaitServerTerminal(session);
|
|
2017
2086
|
session._emit("call_end");
|
|
2018
2087
|
session._markEnded();
|
|
2019
2088
|
this._activeSessions.delete(session.callId);
|
|
@@ -2045,7 +2114,7 @@ var PipelineSession = class {
|
|
|
2045
2114
|
_speaking = false;
|
|
2046
2115
|
_builtinTools = null;
|
|
2047
2116
|
_holdAudioChunks = null;
|
|
2048
|
-
_log =
|
|
2117
|
+
_log = chunkQD2ZY4UP_cjs.NOOP_LOGGER;
|
|
2049
2118
|
constructor(options) {
|
|
2050
2119
|
this._stt = options.stt;
|
|
2051
2120
|
this._llm = options.llm;
|
|
@@ -2107,7 +2176,7 @@ var PipelineSession = class {
|
|
|
2107
2176
|
*/
|
|
2108
2177
|
async prewarm(tools) {
|
|
2109
2178
|
if (tools) this._tools = tools;
|
|
2110
|
-
this._callSession = new
|
|
2179
|
+
this._callSession = new chunkQD2ZY4UP_cjs.BufferingCall();
|
|
2111
2180
|
this._running = true;
|
|
2112
2181
|
this._conversation = [];
|
|
2113
2182
|
this._log.info("PipelineSession prewarmed");
|
|
@@ -2130,7 +2199,7 @@ var PipelineSession = class {
|
|
|
2130
2199
|
async attach(callSession) {
|
|
2131
2200
|
const prev = this._callSession;
|
|
2132
2201
|
this._callSession = callSession;
|
|
2133
|
-
|
|
2202
|
+
chunkQD2ZY4UP_cjs.attachBuffered(prev, callSession);
|
|
2134
2203
|
}
|
|
2135
2204
|
async start(callSession, tools) {
|
|
2136
2205
|
this._tools = tools ?? null;
|
|
@@ -2177,8 +2246,8 @@ var PipelineSession = class {
|
|
|
2177
2246
|
while (this._running) {
|
|
2178
2247
|
if (this._audioBuffer.length > 0) {
|
|
2179
2248
|
const ulaw = this._audioBuffer.shift();
|
|
2180
|
-
const pcm8k =
|
|
2181
|
-
const pcm16k =
|
|
2249
|
+
const pcm8k = chunkQD2ZY4UP_cjs.ulawToPcm16(ulaw);
|
|
2250
|
+
const pcm16k = chunkQD2ZY4UP_cjs.resamplePcm16(pcm8k, 8e3, 16e3);
|
|
2182
2251
|
yield pcm16k;
|
|
2183
2252
|
} else {
|
|
2184
2253
|
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
@@ -2194,7 +2263,7 @@ var PipelineSession = class {
|
|
|
2194
2263
|
await this._respond();
|
|
2195
2264
|
}
|
|
2196
2265
|
_buildEffectiveTools() {
|
|
2197
|
-
const builtinSchemas =
|
|
2266
|
+
const builtinSchemas = chunkQD2ZY4UP_cjs.getBuiltinToolSchemas(this._builtinTools, "chat");
|
|
2198
2267
|
const dtmfSchemas = builtinSchemas.filter((s) => {
|
|
2199
2268
|
const name = s["function"]?.["name"];
|
|
2200
2269
|
return name === "collect_dtmf" || name === "send_dtmf";
|
|
@@ -2243,8 +2312,8 @@ var PipelineSession = class {
|
|
|
2243
2312
|
const { id, name, arguments: argsStr } = chunk.toolCall;
|
|
2244
2313
|
try {
|
|
2245
2314
|
const args = JSON.parse(argsStr);
|
|
2246
|
-
if (
|
|
2247
|
-
const result2 = await
|
|
2315
|
+
if (chunkQD2ZY4UP_cjs.BUILTIN_TOOL_NAMES.has(name) && this._callSession && !(this._callSession instanceof chunkQD2ZY4UP_cjs.BufferingCall)) {
|
|
2316
|
+
const result2 = await chunkQD2ZY4UP_cjs.executeBuiltinTool(name, args, this._callSession);
|
|
2248
2317
|
if (result2 !== null) {
|
|
2249
2318
|
if (name === "hang_up") return;
|
|
2250
2319
|
this._conversation.push({ role: "tool", content: result2, tool_call_id: id, name });
|
|
@@ -2252,11 +2321,11 @@ var PipelineSession = class {
|
|
|
2252
2321
|
return;
|
|
2253
2322
|
}
|
|
2254
2323
|
}
|
|
2255
|
-
if (
|
|
2324
|
+
if (chunkQD2ZY4UP_cjs.BUILTIN_TOOL_NAMES.has(name) && this._callSession instanceof chunkQD2ZY4UP_cjs.BufferingCall) {
|
|
2256
2325
|
this._log.warn("Builtin tool %s called before answer \u2014 deferring", name);
|
|
2257
2326
|
this._conversation.push({
|
|
2258
2327
|
role: "tool",
|
|
2259
|
-
content:
|
|
2328
|
+
content: chunkQD2ZY4UP_cjs.CALL_NOT_READY_RESULT,
|
|
2260
2329
|
tool_call_id: id,
|
|
2261
2330
|
name
|
|
2262
2331
|
});
|
|
@@ -2265,7 +2334,7 @@ var PipelineSession = class {
|
|
|
2265
2334
|
}
|
|
2266
2335
|
if (!this._tools) return;
|
|
2267
2336
|
this._callSession?.recordToolCall();
|
|
2268
|
-
const player = this._holdAudioChunks && this._callSession && !(this._callSession instanceof
|
|
2337
|
+
const player = this._holdAudioChunks && this._callSession && !(this._callSession instanceof chunkQD2ZY4UP_cjs.BufferingCall) ? new HoldAudioPlayer(this._callSession, this._holdAudioChunks) : null;
|
|
2269
2338
|
player?.start();
|
|
2270
2339
|
let result;
|
|
2271
2340
|
try {
|
|
@@ -2316,8 +2385,8 @@ var PipelineSession = class {
|
|
|
2316
2385
|
sampleRate: this._sampleRate
|
|
2317
2386
|
})) {
|
|
2318
2387
|
if (!this._running || !this._speaking) break;
|
|
2319
|
-
const pcm8k =
|
|
2320
|
-
const ulaw =
|
|
2388
|
+
const pcm8k = chunkQD2ZY4UP_cjs.resamplePcm16(audioChunk, this._sampleRate, 8e3);
|
|
2389
|
+
const ulaw = chunkQD2ZY4UP_cjs.pcm16ToUlaw(pcm8k);
|
|
2321
2390
|
for (let off = 0; off < ulaw.length; off += 160) {
|
|
2322
2391
|
let chunk = ulaw.subarray(off, off + 160);
|
|
2323
2392
|
if (chunk.length < 160) {
|
|
@@ -2344,7 +2413,7 @@ var OpenAIRealtime = class {
|
|
|
2344
2413
|
_language;
|
|
2345
2414
|
_turnDetection;
|
|
2346
2415
|
_greeting;
|
|
2347
|
-
_log =
|
|
2416
|
+
_log = chunkQD2ZY4UP_cjs.NOOP_LOGGER;
|
|
2348
2417
|
_builtinTools = null;
|
|
2349
2418
|
/**
|
|
2350
2419
|
* 마지막 session.update 로 LLM 에 알린 tool 이름들. attach() 가 이 값과 현재
|
|
@@ -2421,7 +2490,7 @@ var OpenAIRealtime = class {
|
|
|
2421
2490
|
/** Open WS + session.update + (optional) response.create without a CallSession. */
|
|
2422
2491
|
async prewarm(tools) {
|
|
2423
2492
|
if (tools) this._tools = tools;
|
|
2424
|
-
this._call = new
|
|
2493
|
+
this._call = new chunkQD2ZY4UP_cjs.BufferingCall();
|
|
2425
2494
|
this._closed = false;
|
|
2426
2495
|
this._playback = null;
|
|
2427
2496
|
this._latestMediaTs = 0;
|
|
@@ -2463,7 +2532,7 @@ var OpenAIRealtime = class {
|
|
|
2463
2532
|
this._resyncTools();
|
|
2464
2533
|
const prev = this._call;
|
|
2465
2534
|
this._call = callSession;
|
|
2466
|
-
|
|
2535
|
+
chunkQD2ZY4UP_cjs.attachBuffered(prev, callSession);
|
|
2467
2536
|
}
|
|
2468
2537
|
async start(callSession, tools) {
|
|
2469
2538
|
if (tools) this._tools = tools;
|
|
@@ -2524,7 +2593,7 @@ var OpenAIRealtime = class {
|
|
|
2524
2593
|
/** Current tool schemas: user tools + builtin tools (flat realtime format). */
|
|
2525
2594
|
_currentToolSchemas() {
|
|
2526
2595
|
const toolSchemas = this._tools ? this._tools.toOpenAITools().map((t) => ({ type: "function", ...t.function })) : [];
|
|
2527
|
-
toolSchemas.push(...
|
|
2596
|
+
toolSchemas.push(...chunkQD2ZY4UP_cjs.getBuiltinToolSchemas(this._builtinTools, "realtime"));
|
|
2528
2597
|
return toolSchemas;
|
|
2529
2598
|
}
|
|
2530
2599
|
/**
|
|
@@ -2695,9 +2764,9 @@ var OpenAIRealtime = class {
|
|
|
2695
2764
|
const controller = new AbortController();
|
|
2696
2765
|
this._pendingToolCalls.set(callId, controller);
|
|
2697
2766
|
try {
|
|
2698
|
-
if (
|
|
2767
|
+
if (chunkQD2ZY4UP_cjs.BUILTIN_TOOL_NAMES.has(funcName) && this._call && !(this._call instanceof chunkQD2ZY4UP_cjs.BufferingCall)) {
|
|
2699
2768
|
const args = JSON.parse(item["arguments"] ?? "{}");
|
|
2700
|
-
const result2 = await
|
|
2769
|
+
const result2 = await chunkQD2ZY4UP_cjs.executeBuiltinTool(funcName, args, this._call);
|
|
2701
2770
|
if (result2 !== null) {
|
|
2702
2771
|
if (funcName === "hang_up") return;
|
|
2703
2772
|
if (controller.signal.aborted) return;
|
|
@@ -2714,7 +2783,7 @@ var OpenAIRealtime = class {
|
|
|
2714
2783
|
return;
|
|
2715
2784
|
}
|
|
2716
2785
|
}
|
|
2717
|
-
if (
|
|
2786
|
+
if (chunkQD2ZY4UP_cjs.BUILTIN_TOOL_NAMES.has(funcName) && this._call instanceof chunkQD2ZY4UP_cjs.BufferingCall) {
|
|
2718
2787
|
this._log.warn("Builtin tool %s called before answer \u2014 deferring", funcName);
|
|
2719
2788
|
await this._waitForResponseDone();
|
|
2720
2789
|
this._send({
|
|
@@ -2722,7 +2791,7 @@ var OpenAIRealtime = class {
|
|
|
2722
2791
|
item: {
|
|
2723
2792
|
type: "function_call_output",
|
|
2724
2793
|
call_id: callId,
|
|
2725
|
-
output:
|
|
2794
|
+
output: chunkQD2ZY4UP_cjs.CALL_NOT_READY_RESULT
|
|
2726
2795
|
}
|
|
2727
2796
|
});
|
|
2728
2797
|
this._send({ type: "response.create" });
|
|
@@ -2743,7 +2812,7 @@ var OpenAIRealtime = class {
|
|
|
2743
2812
|
return;
|
|
2744
2813
|
}
|
|
2745
2814
|
let result;
|
|
2746
|
-
const player = this._holdAudioChunks && this._call && !(this._call instanceof
|
|
2815
|
+
const player = this._holdAudioChunks && this._call && !(this._call instanceof chunkQD2ZY4UP_cjs.BufferingCall) ? new HoldAudioPlayer(this._call, this._holdAudioChunks) : null;
|
|
2747
2816
|
player?.start();
|
|
2748
2817
|
try {
|
|
2749
2818
|
const args = JSON.parse(item["arguments"] ?? "{}");
|
|
@@ -2892,7 +2961,7 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
2892
2961
|
_toolDrainTimer = null;
|
|
2893
2962
|
_lastAudioTime = 0;
|
|
2894
2963
|
_holdAudioChunks = null;
|
|
2895
|
-
_log =
|
|
2964
|
+
_log = chunkQD2ZY4UP_cjs.NOOP_LOGGER;
|
|
2896
2965
|
constructor(options = {}) {
|
|
2897
2966
|
this._apiKey = options.apiKey ?? process.env["GOOGLE_API_KEY"] ?? "";
|
|
2898
2967
|
this._systemPrompt = options.systemPrompt ?? "";
|
|
@@ -2938,7 +3007,7 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
2938
3007
|
/** Open Live session (no CallSession). Audio deltas accumulate into BufferingCall until attach(). */
|
|
2939
3008
|
async prewarm(tools) {
|
|
2940
3009
|
if (tools) this._tools = tools;
|
|
2941
|
-
this._call = new
|
|
3010
|
+
this._call = new chunkQD2ZY4UP_cjs.BufferingCall();
|
|
2942
3011
|
this._closed = false;
|
|
2943
3012
|
this._sentAudioChunks = 0;
|
|
2944
3013
|
this._audioRemainder = Buffer.alloc(0);
|
|
@@ -2995,7 +3064,7 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
2995
3064
|
async attach(callSession) {
|
|
2996
3065
|
const prev = this._call;
|
|
2997
3066
|
this._call = callSession;
|
|
2998
|
-
|
|
3067
|
+
chunkQD2ZY4UP_cjs.attachBuffered(prev, callSession);
|
|
2999
3068
|
}
|
|
3000
3069
|
async start(callSession, tools) {
|
|
3001
3070
|
if (tools) this._tools = tools;
|
|
@@ -3004,8 +3073,8 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
3004
3073
|
}
|
|
3005
3074
|
feedAudio(audio) {
|
|
3006
3075
|
if (this._session && !this._closed) {
|
|
3007
|
-
const pcm8k =
|
|
3008
|
-
const pcm16k =
|
|
3076
|
+
const pcm8k = chunkQD2ZY4UP_cjs.ulawToPcm16(audio);
|
|
3077
|
+
const pcm16k = chunkQD2ZY4UP_cjs.resamplePcm16(pcm8k, 8e3, 16e3);
|
|
3009
3078
|
this._session.sendRealtimeInput({
|
|
3010
3079
|
audio: {
|
|
3011
3080
|
data: Buffer.from(pcm16k).toString("base64"),
|
|
@@ -3049,7 +3118,7 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
3049
3118
|
t.function.parameters ?? { type: "object", properties: {} }
|
|
3050
3119
|
)
|
|
3051
3120
|
})) : [];
|
|
3052
|
-
toolDefs.push(...
|
|
3121
|
+
toolDefs.push(...chunkQD2ZY4UP_cjs.getBuiltinToolSchemas(this._builtinTools, "gemini"));
|
|
3053
3122
|
return toolDefs;
|
|
3054
3123
|
}
|
|
3055
3124
|
_handleMessage(msg) {
|
|
@@ -3109,8 +3178,8 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
3109
3178
|
_handleAudioData(b64Data) {
|
|
3110
3179
|
if (!this._call) return;
|
|
3111
3180
|
const pcm24k = Buffer.from(b64Data, "base64");
|
|
3112
|
-
const pcm8k =
|
|
3113
|
-
const ulaw =
|
|
3181
|
+
const pcm8k = chunkQD2ZY4UP_cjs.resamplePcm16(pcm24k, 24e3, 8e3);
|
|
3182
|
+
const ulaw = chunkQD2ZY4UP_cjs.pcm16ToUlaw(pcm8k);
|
|
3114
3183
|
const combined = Buffer.concat([this._audioRemainder, ulaw]);
|
|
3115
3184
|
const chunkSize = 160;
|
|
3116
3185
|
const fullEnd = Math.floor(combined.length / chunkSize) * chunkSize;
|
|
@@ -3153,7 +3222,7 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
3153
3222
|
const functionCalls = toolCall.functionCalls;
|
|
3154
3223
|
if (!functionCalls) return;
|
|
3155
3224
|
const responses = [];
|
|
3156
|
-
const player = this._holdAudioChunks && this._call && !(this._call instanceof
|
|
3225
|
+
const player = this._holdAudioChunks && this._call && !(this._call instanceof chunkQD2ZY4UP_cjs.BufferingCall) ? new HoldAudioPlayer(this._call, this._holdAudioChunks) : null;
|
|
3157
3226
|
player?.start();
|
|
3158
3227
|
try {
|
|
3159
3228
|
for (const fc of functionCalls) {
|
|
@@ -3161,8 +3230,8 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
3161
3230
|
const fcId = fc.id ?? "";
|
|
3162
3231
|
const args = fc.args ?? {};
|
|
3163
3232
|
this._log.info({ tool: name, args }, "Tool call: %s", name);
|
|
3164
|
-
if (
|
|
3165
|
-
const result = await
|
|
3233
|
+
if (chunkQD2ZY4UP_cjs.BUILTIN_TOOL_NAMES.has(name) && this._call && !(this._call instanceof chunkQD2ZY4UP_cjs.BufferingCall)) {
|
|
3234
|
+
const result = await chunkQD2ZY4UP_cjs.executeBuiltinTool(
|
|
3166
3235
|
name,
|
|
3167
3236
|
args,
|
|
3168
3237
|
this._call
|
|
@@ -3177,9 +3246,9 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
3177
3246
|
continue;
|
|
3178
3247
|
}
|
|
3179
3248
|
}
|
|
3180
|
-
if (
|
|
3249
|
+
if (chunkQD2ZY4UP_cjs.BUILTIN_TOOL_NAMES.has(name) && this._call instanceof chunkQD2ZY4UP_cjs.BufferingCall) {
|
|
3181
3250
|
this._log.warn("Builtin tool %s called before answer \u2014 deferring", name);
|
|
3182
|
-
responses.push({ id: fcId, name, response: { result:
|
|
3251
|
+
responses.push({ id: fcId, name, response: { result: chunkQD2ZY4UP_cjs.CALL_NOT_READY_RESULT } });
|
|
3183
3252
|
continue;
|
|
3184
3253
|
}
|
|
3185
3254
|
if (!this._tools || !this._tools.has(name)) {
|
|
@@ -3224,7 +3293,7 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
3224
3293
|
// src/agent/pipeline/stt/deepgram-stt.ts
|
|
3225
3294
|
var DeepgramSTT = class {
|
|
3226
3295
|
_options;
|
|
3227
|
-
_log =
|
|
3296
|
+
_log = chunkQD2ZY4UP_cjs.NOOP_LOGGER;
|
|
3228
3297
|
get provider() {
|
|
3229
3298
|
return "deepgram";
|
|
3230
3299
|
}
|
|
@@ -3351,7 +3420,7 @@ var DeepgramSTT = class {
|
|
|
3351
3420
|
// src/agent/pipeline/tts/elevenlabs-tts.ts
|
|
3352
3421
|
var ElevenLabsTTS = class {
|
|
3353
3422
|
_options;
|
|
3354
|
-
_log =
|
|
3423
|
+
_log = chunkQD2ZY4UP_cjs.NOOP_LOGGER;
|
|
3355
3424
|
get provider() {
|
|
3356
3425
|
return "elevenlabs";
|
|
3357
3426
|
}
|
|
@@ -4097,47 +4166,47 @@ function mcpServerHTTP(options) {
|
|
|
4097
4166
|
|
|
4098
4167
|
Object.defineProperty(exports, "BUILTIN_TOOL_NAMES", {
|
|
4099
4168
|
enumerable: true,
|
|
4100
|
-
get: function () { return
|
|
4169
|
+
get: function () { return chunkQD2ZY4UP_cjs.BUILTIN_TOOL_NAMES; }
|
|
4101
4170
|
});
|
|
4102
4171
|
Object.defineProperty(exports, "BuiltinTool", {
|
|
4103
4172
|
enumerable: true,
|
|
4104
|
-
get: function () { return
|
|
4173
|
+
get: function () { return chunkQD2ZY4UP_cjs.BuiltinTool; }
|
|
4105
4174
|
});
|
|
4106
4175
|
Object.defineProperty(exports, "DECODE_TABLE", {
|
|
4107
4176
|
enumerable: true,
|
|
4108
|
-
get: function () { return
|
|
4177
|
+
get: function () { return chunkQD2ZY4UP_cjs.DECODE_TABLE; }
|
|
4109
4178
|
});
|
|
4110
4179
|
Object.defineProperty(exports, "createAgentLogger", {
|
|
4111
4180
|
enumerable: true,
|
|
4112
|
-
get: function () { return
|
|
4181
|
+
get: function () { return chunkQD2ZY4UP_cjs.createAgentLogger; }
|
|
4113
4182
|
});
|
|
4114
4183
|
Object.defineProperty(exports, "createPipelineLogger", {
|
|
4115
4184
|
enumerable: true,
|
|
4116
|
-
get: function () { return
|
|
4185
|
+
get: function () { return chunkQD2ZY4UP_cjs.createPipelineLogger; }
|
|
4117
4186
|
});
|
|
4118
4187
|
Object.defineProperty(exports, "executeBuiltinTool", {
|
|
4119
4188
|
enumerable: true,
|
|
4120
|
-
get: function () { return
|
|
4189
|
+
get: function () { return chunkQD2ZY4UP_cjs.executeBuiltinTool; }
|
|
4121
4190
|
});
|
|
4122
4191
|
Object.defineProperty(exports, "getBuiltinToolSchemas", {
|
|
4123
4192
|
enumerable: true,
|
|
4124
|
-
get: function () { return
|
|
4193
|
+
get: function () { return chunkQD2ZY4UP_cjs.getBuiltinToolSchemas; }
|
|
4125
4194
|
});
|
|
4126
4195
|
Object.defineProperty(exports, "isBuiltinTool", {
|
|
4127
4196
|
enumerable: true,
|
|
4128
|
-
get: function () { return
|
|
4197
|
+
get: function () { return chunkQD2ZY4UP_cjs.isBuiltinTool; }
|
|
4129
4198
|
});
|
|
4130
4199
|
Object.defineProperty(exports, "pcm16ToUlaw", {
|
|
4131
4200
|
enumerable: true,
|
|
4132
|
-
get: function () { return
|
|
4201
|
+
get: function () { return chunkQD2ZY4UP_cjs.pcm16ToUlaw; }
|
|
4133
4202
|
});
|
|
4134
4203
|
Object.defineProperty(exports, "resamplePcm16", {
|
|
4135
4204
|
enumerable: true,
|
|
4136
|
-
get: function () { return
|
|
4205
|
+
get: function () { return chunkQD2ZY4UP_cjs.resamplePcm16; }
|
|
4137
4206
|
});
|
|
4138
4207
|
Object.defineProperty(exports, "ulawToPcm16", {
|
|
4139
4208
|
enumerable: true,
|
|
4140
|
-
get: function () { return
|
|
4209
|
+
get: function () { return chunkQD2ZY4UP_cjs.ulawToPcm16; }
|
|
4141
4210
|
});
|
|
4142
4211
|
exports.AnthropicLLM = AnthropicLLM;
|
|
4143
4212
|
exports.AudioRecorder = AudioRecorder;
|