@teamlearners/clawops 0.25.0 → 0.26.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/README.md +0 -13
- package/dist/agent/index.cjs +171 -83
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +29 -0
- package/dist/agent/index.d.ts +29 -0
- package/dist/agent/index.js +108 -20
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/livekit/index.cjs +8 -8
- package/dist/agent/livekit/index.js +1 -1
- package/dist/{chunk-IVJXHNUN.cjs → chunk-AF2MNFN4.cjs} +3 -3
- package/dist/{chunk-IVJXHNUN.cjs.map → chunk-AF2MNFN4.cjs.map} +1 -1
- package/dist/{chunk-THZNZBP2.js → chunk-WIA54H3X.js} +3 -3
- package/dist/{chunk-THZNZBP2.js.map → chunk-WIA54H3X.js.map} +1 -1
- package/dist/{chunk-2BAYUQ7O.js → chunk-WKGTY7QT.js} +4 -3
- package/dist/chunk-WKGTY7QT.js.map +1 -0
- package/dist/{chunk-U4UFTVLX.cjs → chunk-XAOA3XFQ.cjs} +4 -2
- package/dist/chunk-XAOA3XFQ.cjs.map +1 -0
- package/dist/index.cjs +35 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -62
- package/dist/index.d.ts +1 -62
- package/dist/index.js +2 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-2BAYUQ7O.js.map +0 -1
- package/dist/chunk-U4UFTVLX.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -195,19 +195,6 @@ const done = await client.calls.get(amdCall.callId);
|
|
|
195
195
|
console.log(done.answeredBy);
|
|
196
196
|
// statusCallback 을 설정했다면 completed 이벤트 payload 의 AnsweredBy 로도 통보됩니다.
|
|
197
197
|
|
|
198
|
-
// AI Completion 모드 — AI가 직접 통화를 처리
|
|
199
|
-
const aiCall = await client.calls.create({
|
|
200
|
-
to: '01012345678',
|
|
201
|
-
from: '07052358010',
|
|
202
|
-
ai: {
|
|
203
|
-
provider: 'openai',
|
|
204
|
-
model: 'gpt-realtime',
|
|
205
|
-
apiKey: process.env.OPENAI_API_KEY!,
|
|
206
|
-
voice: 'marin',
|
|
207
|
-
messages: [{ role: 'system', content: '당신은 예약 확인 AI입니다.' }],
|
|
208
|
-
},
|
|
209
|
-
});
|
|
210
|
-
|
|
211
198
|
// 통화 목록 조회 (페이지네이션)
|
|
212
199
|
const page = await client.calls.list({ status: 'completed', page: 0, pageSize: 20 });
|
|
213
200
|
for (const call of page) {
|
package/dist/agent/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkAF2MNFN4_cjs = require('../chunk-AF2MNFN4.cjs');
|
|
4
|
+
var chunkXAOA3XFQ_cjs = require('../chunk-XAOA3XFQ.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 = chunkXAOA3XFQ_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 = chunkXAOA3XFQ_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 = chunkXAOA3XFQ_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 = chunkXAOA3XFQ_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: chunkAF2MNFN4_cjs.VERSION,
|
|
732
732
|
runtime: `node/${process.versions.node}`,
|
|
733
733
|
os: `${process.platform}/${os__default.default.arch()}`
|
|
734
734
|
};
|
|
@@ -788,7 +788,7 @@ var CallSession = class {
|
|
|
788
788
|
_dtmfCollectorActive = false;
|
|
789
789
|
_dtmfResolvers = [];
|
|
790
790
|
_dtmfBuffer = [];
|
|
791
|
-
_log =
|
|
791
|
+
_log = chunkXAOA3XFQ_cjs.NOOP_LOGGER;
|
|
792
792
|
_handlers = /* @__PURE__ */ new Map();
|
|
793
793
|
_endedPromise;
|
|
794
794
|
_resolveEnded;
|
|
@@ -1105,7 +1105,7 @@ function generateComfortTone(volume = 0.12) {
|
|
|
1105
1105
|
}
|
|
1106
1106
|
}
|
|
1107
1107
|
const pcm = int16ArrayToBuffer(concatInt16Arrays(...parts));
|
|
1108
|
-
const ulaw =
|
|
1108
|
+
const ulaw = chunkXAOA3XFQ_cjs.pcm16ToUlaw(pcm);
|
|
1109
1109
|
const chunks = [];
|
|
1110
1110
|
for (let i = 0; i < ulaw.length; i += CHUNK_SIZE) {
|
|
1111
1111
|
chunks.push(ulaw.subarray(i, i + CHUNK_SIZE));
|
|
@@ -1162,9 +1162,9 @@ function loadHoldAudio(source) {
|
|
|
1162
1162
|
pcmData = mono;
|
|
1163
1163
|
}
|
|
1164
1164
|
if (sampleRate !== SAMPLE_RATE2) {
|
|
1165
|
-
pcmData =
|
|
1165
|
+
pcmData = chunkXAOA3XFQ_cjs.resamplePcm16(pcmData, sampleRate, SAMPLE_RATE2);
|
|
1166
1166
|
}
|
|
1167
|
-
const ulaw =
|
|
1167
|
+
const ulaw = chunkXAOA3XFQ_cjs.pcm16ToUlaw(pcmData);
|
|
1168
1168
|
const chunks = [];
|
|
1169
1169
|
for (let i = 0; i < ulaw.length; i += CHUNK_SIZE) {
|
|
1170
1170
|
chunks.push(ulaw.subarray(i, i + CHUNK_SIZE));
|
|
@@ -1433,13 +1433,13 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1433
1433
|
constructor(options) {
|
|
1434
1434
|
this._apiKey = options.apiKey ?? process.env["CLAWOPS_API_KEY"] ?? "";
|
|
1435
1435
|
this._accountId = options.accountId ?? process.env["CLAWOPS_ACCOUNT_ID"] ?? "";
|
|
1436
|
-
this._baseUrl = options.baseUrl ??
|
|
1436
|
+
this._baseUrl = options.baseUrl ?? chunkAF2MNFN4_cjs.DEFAULT_BASE_URL;
|
|
1437
1437
|
this._fromNumber = options.from;
|
|
1438
1438
|
this._session = options.session;
|
|
1439
1439
|
this._recording = options.recording ?? false;
|
|
1440
1440
|
this._recordingPath = options.recordingPath ?? "./recordings";
|
|
1441
1441
|
this._mcpServers = options.mcpServers ?? [];
|
|
1442
|
-
this._builtinTools =
|
|
1442
|
+
this._builtinTools = chunkXAOA3XFQ_cjs.resolveBuiltinTools(options.builtinTools ?? "all" /* ALL */);
|
|
1443
1443
|
this._passiveDtmfDebounceMs = options.passiveDtmfDebounceMs ?? 500;
|
|
1444
1444
|
this._rxGain = _ClawOpsAgent._validateGain("rxGain", options.rxGain ?? 1);
|
|
1445
1445
|
this._txGain = _ClawOpsAgent._validateGain("txGain", options.txGain ?? 1);
|
|
@@ -1448,8 +1448,8 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1448
1448
|
if (options.tracing) {
|
|
1449
1449
|
setTracingConfig(options.tracing);
|
|
1450
1450
|
}
|
|
1451
|
-
this._log =
|
|
1452
|
-
this._pipelineLog =
|
|
1451
|
+
this._log = chunkXAOA3XFQ_cjs.createAgentLogger(options.logger);
|
|
1452
|
+
this._pipelineLog = chunkXAOA3XFQ_cjs.createPipelineLogger(this._log);
|
|
1453
1453
|
this._isPipelineSession = "_stt" in this._session && "_llm" in this._session;
|
|
1454
1454
|
if (options.toolConfig?.holdAudio) {
|
|
1455
1455
|
this._holdAudioChunks = loadHoldAudio(options.toolConfig.holdAudio);
|
|
@@ -1457,7 +1457,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1457
1457
|
}
|
|
1458
1458
|
static _validateGain(name, gain) {
|
|
1459
1459
|
if (typeof gain !== "number" || !Number.isFinite(gain) || gain < 0) {
|
|
1460
|
-
throw new
|
|
1460
|
+
throw new chunkAF2MNFN4_cjs.AgentError(`${name}=${gain} must be a finite number >= 0`);
|
|
1461
1461
|
}
|
|
1462
1462
|
return gain;
|
|
1463
1463
|
}
|
|
@@ -1471,7 +1471,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1471
1471
|
tool(nameOrTool, description, parameters, handler) {
|
|
1472
1472
|
if (typeof nameOrTool === "string") {
|
|
1473
1473
|
if (!description || !parameters || !handler) {
|
|
1474
|
-
throw new
|
|
1474
|
+
throw new chunkAF2MNFN4_cjs.AgentError(
|
|
1475
1475
|
"tool(name, description, parameters, handler) requires all arguments."
|
|
1476
1476
|
);
|
|
1477
1477
|
}
|
|
@@ -1507,10 +1507,10 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1507
1507
|
async connect() {
|
|
1508
1508
|
if (this._controlWs) return;
|
|
1509
1509
|
if (!this._apiKey) {
|
|
1510
|
-
throw new
|
|
1510
|
+
throw new chunkAF2MNFN4_cjs.AgentError("API key is required. Set CLAWOPS_API_KEY or pass apiKey option.");
|
|
1511
1511
|
}
|
|
1512
1512
|
if (!this._accountId) {
|
|
1513
|
-
throw new
|
|
1513
|
+
throw new chunkAF2MNFN4_cjs.AgentError(
|
|
1514
1514
|
"Account ID is required. Set CLAWOPS_ACCOUNT_ID or pass accountId option."
|
|
1515
1515
|
);
|
|
1516
1516
|
}
|
|
@@ -1534,7 +1534,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1534
1534
|
} catch {
|
|
1535
1535
|
}
|
|
1536
1536
|
} catch (err) {
|
|
1537
|
-
throw new
|
|
1537
|
+
throw new chunkAF2MNFN4_cjs.AgentConnectionError(
|
|
1538
1538
|
`Failed to connect to ClawOps: ${err instanceof Error ? err.message : String(err)}`
|
|
1539
1539
|
);
|
|
1540
1540
|
}
|
|
@@ -1598,7 +1598,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1598
1598
|
});
|
|
1599
1599
|
if (resp.status !== 201) {
|
|
1600
1600
|
const error = await resp.json();
|
|
1601
|
-
throw new
|
|
1601
|
+
throw new chunkAF2MNFN4_cjs.AgentError(`\uBC1C\uC2E0 \uC2E4\uD328 (${resp.status}): ${error["error"] ?? ""}`);
|
|
1602
1602
|
}
|
|
1603
1603
|
const data = await resp.json();
|
|
1604
1604
|
const callSession = new CallSession({
|
|
@@ -1722,10 +1722,43 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1722
1722
|
* multiple times — only the first invocation starts the task. Failures are
|
|
1723
1723
|
* recorded in _prewarmFailed so the call-session path can fall back to start().
|
|
1724
1724
|
*/
|
|
1725
|
+
/**
|
|
1726
|
+
* 세션에 콜별 의존성(도구·내장도구·hold audio·recorder·logger)을 주입한다.
|
|
1727
|
+
*
|
|
1728
|
+
* prewarm 과 _startCallSession 양쪽에서 부른다. prewarm 은 세션이 LLM 에 보낼
|
|
1729
|
+
* tool 스키마를 그 시점에 확정하므로(OpenAI session.update / Gemini live connect
|
|
1730
|
+
* config), prewarm **전에** 최소 한 번은 도구가 들어가 있어야 한다.
|
|
1731
|
+
*/
|
|
1732
|
+
_injectSessionDeps(tools, recorder) {
|
|
1733
|
+
const sessionHandler = this._session;
|
|
1734
|
+
if ("setToolRegistry" in sessionHandler && typeof sessionHandler.setToolRegistry === "function") {
|
|
1735
|
+
sessionHandler.setToolRegistry(tools);
|
|
1736
|
+
}
|
|
1737
|
+
if (recorder && "setRecorder" in sessionHandler && typeof sessionHandler.setRecorder === "function") {
|
|
1738
|
+
sessionHandler.setRecorder(recorder);
|
|
1739
|
+
}
|
|
1740
|
+
if ("setBuiltinTools" in sessionHandler && typeof sessionHandler.setBuiltinTools === "function") {
|
|
1741
|
+
sessionHandler.setBuiltinTools(this._builtinTools);
|
|
1742
|
+
}
|
|
1743
|
+
if ("setLogger" in sessionHandler && typeof sessionHandler.setLogger === "function") {
|
|
1744
|
+
sessionHandler.setLogger(this._isPipelineSession ? this._pipelineLog : this._log);
|
|
1745
|
+
}
|
|
1746
|
+
if (this._holdAudioChunks && "setHoldAudio" in sessionHandler && typeof sessionHandler.setHoldAudio === "function") {
|
|
1747
|
+
sessionHandler.setHoldAudio(this._holdAudioChunks);
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1725
1750
|
_startPrewarm(callId) {
|
|
1726
1751
|
if (this._prewarmTasks.has(callId)) return;
|
|
1727
1752
|
const sessionHandler = this._session;
|
|
1728
1753
|
if (typeof sessionHandler.prewarm !== "function") return;
|
|
1754
|
+
if (this._mcpServers.length > 0 && sessionHandler.toolsFrozenAfterPrewarm) {
|
|
1755
|
+
this._log.info(
|
|
1756
|
+
{ callId },
|
|
1757
|
+
"Skipping prewarm \u2014 \uC138\uC158\uC774 \uC5F0\uACB0 \uD6C4 \uB3C4\uAD6C \uBCC0\uACBD\uC744 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC544 MCP \uB3C4\uAD6C\uAC00 \uB204\uB77D\uB41C\uB2E4."
|
|
1758
|
+
);
|
|
1759
|
+
return;
|
|
1760
|
+
}
|
|
1761
|
+
this._injectSessionDeps(this._tools.fork());
|
|
1729
1762
|
const PREWARM_TIMEOUT_MS = 1e4;
|
|
1730
1763
|
const t0 = Date.now();
|
|
1731
1764
|
this._log.info(`[PREWARM-T] start call_id=${callId} t=${(t0 / 1e3).toFixed(3)}`);
|
|
@@ -1863,9 +1896,9 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1863
1896
|
let latestMediaTs = 0;
|
|
1864
1897
|
session._bindTransport(
|
|
1865
1898
|
(audio) => {
|
|
1866
|
-
const gained =
|
|
1899
|
+
const gained = chunkXAOA3XFQ_cjs.applyUlawGain(audio, this._txGain);
|
|
1867
1900
|
if (recorder) {
|
|
1868
|
-
recorder.writeOutbound(
|
|
1901
|
+
recorder.writeOutbound(chunkXAOA3XFQ_cjs.ulawToPcm16(gained), latestMediaTs);
|
|
1869
1902
|
}
|
|
1870
1903
|
mediaWs.sendAudio(gained.toString("base64"));
|
|
1871
1904
|
session.recordFirstResponse();
|
|
@@ -1891,27 +1924,13 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1891
1924
|
session._waitForMark = (name, timeoutMs) => mediaWs.waitForMark(name, timeoutMs);
|
|
1892
1925
|
session._flushTransport = () => mediaWs.flush();
|
|
1893
1926
|
const sessionHandler = this._session;
|
|
1894
|
-
|
|
1895
|
-
sessionHandler.setToolRegistry(sessionTools);
|
|
1896
|
-
}
|
|
1897
|
-
if (recorder && "setRecorder" in sessionHandler && typeof sessionHandler.setRecorder === "function") {
|
|
1898
|
-
sessionHandler.setRecorder(recorder);
|
|
1899
|
-
}
|
|
1900
|
-
if ("setBuiltinTools" in sessionHandler && typeof sessionHandler.setBuiltinTools === "function") {
|
|
1901
|
-
sessionHandler.setBuiltinTools(this._builtinTools);
|
|
1902
|
-
}
|
|
1903
|
-
if ("setLogger" in sessionHandler && typeof sessionHandler.setLogger === "function") {
|
|
1904
|
-
sessionHandler.setLogger(this._isPipelineSession ? this._pipelineLog : this._log);
|
|
1905
|
-
}
|
|
1906
|
-
if (this._holdAudioChunks && "setHoldAudio" in sessionHandler && typeof sessionHandler.setHoldAudio === "function") {
|
|
1907
|
-
sessionHandler.setHoldAudio(this._holdAudioChunks);
|
|
1908
|
-
}
|
|
1927
|
+
this._injectSessionDeps(sessionTools, recorder);
|
|
1909
1928
|
this._callSessions.set(session.callId, sessionHandler);
|
|
1910
1929
|
mediaWs.onAudio((ulawAudio, timestamp) => {
|
|
1911
1930
|
latestMediaTs = timestamp;
|
|
1912
|
-
const gained =
|
|
1931
|
+
const gained = chunkXAOA3XFQ_cjs.applyUlawGain(ulawAudio, this._rxGain);
|
|
1913
1932
|
if (recorder) {
|
|
1914
|
-
recorder.writeInbound(
|
|
1933
|
+
recorder.writeInbound(chunkXAOA3XFQ_cjs.ulawToPcm16(gained), timestamp);
|
|
1915
1934
|
}
|
|
1916
1935
|
if (sessionHandler) {
|
|
1917
1936
|
sessionHandler.feedAudio(gained, timestamp);
|
|
@@ -2026,7 +2045,7 @@ var PipelineSession = class {
|
|
|
2026
2045
|
_speaking = false;
|
|
2027
2046
|
_builtinTools = null;
|
|
2028
2047
|
_holdAudioChunks = null;
|
|
2029
|
-
_log =
|
|
2048
|
+
_log = chunkXAOA3XFQ_cjs.NOOP_LOGGER;
|
|
2030
2049
|
constructor(options) {
|
|
2031
2050
|
this._stt = options.stt;
|
|
2032
2051
|
this._llm = options.llm;
|
|
@@ -2088,7 +2107,7 @@ var PipelineSession = class {
|
|
|
2088
2107
|
*/
|
|
2089
2108
|
async prewarm(tools) {
|
|
2090
2109
|
if (tools) this._tools = tools;
|
|
2091
|
-
this._callSession = new
|
|
2110
|
+
this._callSession = new chunkXAOA3XFQ_cjs.BufferingCall();
|
|
2092
2111
|
this._running = true;
|
|
2093
2112
|
this._conversation = [];
|
|
2094
2113
|
this._log.info("PipelineSession prewarmed");
|
|
@@ -2111,7 +2130,7 @@ var PipelineSession = class {
|
|
|
2111
2130
|
async attach(callSession) {
|
|
2112
2131
|
const prev = this._callSession;
|
|
2113
2132
|
this._callSession = callSession;
|
|
2114
|
-
|
|
2133
|
+
chunkXAOA3XFQ_cjs.attachBuffered(prev, callSession);
|
|
2115
2134
|
}
|
|
2116
2135
|
async start(callSession, tools) {
|
|
2117
2136
|
this._tools = tools ?? null;
|
|
@@ -2158,8 +2177,8 @@ var PipelineSession = class {
|
|
|
2158
2177
|
while (this._running) {
|
|
2159
2178
|
if (this._audioBuffer.length > 0) {
|
|
2160
2179
|
const ulaw = this._audioBuffer.shift();
|
|
2161
|
-
const pcm8k =
|
|
2162
|
-
const pcm16k =
|
|
2180
|
+
const pcm8k = chunkXAOA3XFQ_cjs.ulawToPcm16(ulaw);
|
|
2181
|
+
const pcm16k = chunkXAOA3XFQ_cjs.resamplePcm16(pcm8k, 8e3, 16e3);
|
|
2163
2182
|
yield pcm16k;
|
|
2164
2183
|
} else {
|
|
2165
2184
|
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
@@ -2175,7 +2194,7 @@ var PipelineSession = class {
|
|
|
2175
2194
|
await this._respond();
|
|
2176
2195
|
}
|
|
2177
2196
|
_buildEffectiveTools() {
|
|
2178
|
-
const builtinSchemas =
|
|
2197
|
+
const builtinSchemas = chunkXAOA3XFQ_cjs.getBuiltinToolSchemas(this._builtinTools, "chat");
|
|
2179
2198
|
const dtmfSchemas = builtinSchemas.filter((s) => {
|
|
2180
2199
|
const name = s["function"]?.["name"];
|
|
2181
2200
|
return name === "collect_dtmf" || name === "send_dtmf";
|
|
@@ -2224,8 +2243,8 @@ var PipelineSession = class {
|
|
|
2224
2243
|
const { id, name, arguments: argsStr } = chunk.toolCall;
|
|
2225
2244
|
try {
|
|
2226
2245
|
const args = JSON.parse(argsStr);
|
|
2227
|
-
if (
|
|
2228
|
-
const result2 = await
|
|
2246
|
+
if (chunkXAOA3XFQ_cjs.BUILTIN_TOOL_NAMES.has(name) && this._callSession && !(this._callSession instanceof chunkXAOA3XFQ_cjs.BufferingCall)) {
|
|
2247
|
+
const result2 = await chunkXAOA3XFQ_cjs.executeBuiltinTool(name, args, this._callSession);
|
|
2229
2248
|
if (result2 !== null) {
|
|
2230
2249
|
if (name === "hang_up") return;
|
|
2231
2250
|
this._conversation.push({ role: "tool", content: result2, tool_call_id: id, name });
|
|
@@ -2233,9 +2252,20 @@ var PipelineSession = class {
|
|
|
2233
2252
|
return;
|
|
2234
2253
|
}
|
|
2235
2254
|
}
|
|
2255
|
+
if (chunkXAOA3XFQ_cjs.BUILTIN_TOOL_NAMES.has(name) && this._callSession instanceof chunkXAOA3XFQ_cjs.BufferingCall) {
|
|
2256
|
+
this._log.warn("Builtin tool %s called before answer \u2014 deferring", name);
|
|
2257
|
+
this._conversation.push({
|
|
2258
|
+
role: "tool",
|
|
2259
|
+
content: chunkXAOA3XFQ_cjs.CALL_NOT_READY_RESULT,
|
|
2260
|
+
tool_call_id: id,
|
|
2261
|
+
name
|
|
2262
|
+
});
|
|
2263
|
+
await this._respond();
|
|
2264
|
+
return;
|
|
2265
|
+
}
|
|
2236
2266
|
if (!this._tools) return;
|
|
2237
2267
|
this._callSession?.recordToolCall();
|
|
2238
|
-
const player = this._holdAudioChunks && this._callSession && !(this._callSession instanceof
|
|
2268
|
+
const player = this._holdAudioChunks && this._callSession && !(this._callSession instanceof chunkXAOA3XFQ_cjs.BufferingCall) ? new HoldAudioPlayer(this._callSession, this._holdAudioChunks) : null;
|
|
2239
2269
|
player?.start();
|
|
2240
2270
|
let result;
|
|
2241
2271
|
try {
|
|
@@ -2286,8 +2316,8 @@ var PipelineSession = class {
|
|
|
2286
2316
|
sampleRate: this._sampleRate
|
|
2287
2317
|
})) {
|
|
2288
2318
|
if (!this._running || !this._speaking) break;
|
|
2289
|
-
const pcm8k =
|
|
2290
|
-
const ulaw =
|
|
2319
|
+
const pcm8k = chunkXAOA3XFQ_cjs.resamplePcm16(audioChunk, this._sampleRate, 8e3);
|
|
2320
|
+
const ulaw = chunkXAOA3XFQ_cjs.pcm16ToUlaw(pcm8k);
|
|
2291
2321
|
for (let off = 0; off < ulaw.length; off += 160) {
|
|
2292
2322
|
let chunk = ulaw.subarray(off, off + 160);
|
|
2293
2323
|
if (chunk.length < 160) {
|
|
@@ -2314,8 +2344,13 @@ var OpenAIRealtime = class {
|
|
|
2314
2344
|
_language;
|
|
2315
2345
|
_turnDetection;
|
|
2316
2346
|
_greeting;
|
|
2317
|
-
_log =
|
|
2347
|
+
_log = chunkXAOA3XFQ_cjs.NOOP_LOGGER;
|
|
2318
2348
|
_builtinTools = null;
|
|
2349
|
+
/**
|
|
2350
|
+
* 마지막 session.update 로 LLM 에 알린 tool 이름들. attach() 가 이 값과 현재
|
|
2351
|
+
* registry 를 비교해 달라졌을 때만(=MCP 도구 등 뒤늦게 붙은 경우) 재전송한다.
|
|
2352
|
+
*/
|
|
2353
|
+
_sentToolNames = null;
|
|
2319
2354
|
setLogger(logger) {
|
|
2320
2355
|
this._log = logger;
|
|
2321
2356
|
}
|
|
@@ -2386,7 +2421,7 @@ var OpenAIRealtime = class {
|
|
|
2386
2421
|
/** Open WS + session.update + (optional) response.create without a CallSession. */
|
|
2387
2422
|
async prewarm(tools) {
|
|
2388
2423
|
if (tools) this._tools = tools;
|
|
2389
|
-
this._call = new
|
|
2424
|
+
this._call = new chunkXAOA3XFQ_cjs.BufferingCall();
|
|
2390
2425
|
this._closed = false;
|
|
2391
2426
|
this._playback = null;
|
|
2392
2427
|
this._latestMediaTs = 0;
|
|
@@ -2425,9 +2460,10 @@ var OpenAIRealtime = class {
|
|
|
2425
2460
|
}
|
|
2426
2461
|
/** Attach a real CallSession to the prewarmed session and flush buffered audio. */
|
|
2427
2462
|
async attach(callSession) {
|
|
2463
|
+
this._resyncTools();
|
|
2428
2464
|
const prev = this._call;
|
|
2429
2465
|
this._call = callSession;
|
|
2430
|
-
|
|
2466
|
+
chunkXAOA3XFQ_cjs.attachBuffered(prev, callSession);
|
|
2431
2467
|
}
|
|
2432
2468
|
async start(callSession, tools) {
|
|
2433
2469
|
if (tools) this._tools = tools;
|
|
@@ -2485,10 +2521,36 @@ var OpenAIRealtime = class {
|
|
|
2485
2521
|
});
|
|
2486
2522
|
}
|
|
2487
2523
|
}
|
|
2524
|
+
/** Current tool schemas: user tools + builtin tools (flat realtime format). */
|
|
2525
|
+
_currentToolSchemas() {
|
|
2526
|
+
const toolSchemas = this._tools ? this._tools.toOpenAITools().map((t) => ({ type: "function", ...t.function })) : [];
|
|
2527
|
+
toolSchemas.push(...chunkXAOA3XFQ_cjs.getBuiltinToolSchemas(this._builtinTools, "realtime"));
|
|
2528
|
+
return toolSchemas;
|
|
2529
|
+
}
|
|
2530
|
+
/**
|
|
2531
|
+
* prewarm 이후 도구가 바뀌었으면 session.update 로 재전송한다.
|
|
2532
|
+
*
|
|
2533
|
+
* MCP 도구는 통화 시작 시점에 registry 에 붙으므로 prewarm 시점의 스키마에는
|
|
2534
|
+
* 없다. 여기서 맞춰주지 않으면 발신 통화에서 MCP 도구를 영영 못 쓴다.
|
|
2535
|
+
*/
|
|
2536
|
+
_resyncTools() {
|
|
2537
|
+
if (!this._ws || this._ws.readyState !== 1) return;
|
|
2538
|
+
const toolSchemas = this._currentToolSchemas();
|
|
2539
|
+
const names = toolSchemas.map((t) => String(t["name"] ?? ""));
|
|
2540
|
+
if (this._sentToolNames && names.length === this._sentToolNames.length && names.every((n, i) => n === this._sentToolNames[i])) {
|
|
2541
|
+
return;
|
|
2542
|
+
}
|
|
2543
|
+
this._send({
|
|
2544
|
+
type: "session.update",
|
|
2545
|
+
session: { type: "realtime", tools: toolSchemas }
|
|
2546
|
+
});
|
|
2547
|
+
this._sentToolNames = names;
|
|
2548
|
+
this._log.info("Tool schema resynced after prewarm: %s", names.join(", "));
|
|
2549
|
+
}
|
|
2488
2550
|
_sendSessionUpdate() {
|
|
2489
2551
|
if (!this._ws || this._ws.readyState !== 1) return;
|
|
2490
|
-
const toolSchemas = this.
|
|
2491
|
-
toolSchemas.
|
|
2552
|
+
const toolSchemas = this._currentToolSchemas();
|
|
2553
|
+
this._sentToolNames = toolSchemas.map((t) => String(t["name"] ?? ""));
|
|
2492
2554
|
this._send({
|
|
2493
2555
|
type: "session.update",
|
|
2494
2556
|
session: {
|
|
@@ -2633,9 +2695,9 @@ var OpenAIRealtime = class {
|
|
|
2633
2695
|
const controller = new AbortController();
|
|
2634
2696
|
this._pendingToolCalls.set(callId, controller);
|
|
2635
2697
|
try {
|
|
2636
|
-
if (
|
|
2698
|
+
if (chunkXAOA3XFQ_cjs.BUILTIN_TOOL_NAMES.has(funcName) && this._call && !(this._call instanceof chunkXAOA3XFQ_cjs.BufferingCall)) {
|
|
2637
2699
|
const args = JSON.parse(item["arguments"] ?? "{}");
|
|
2638
|
-
const result2 = await
|
|
2700
|
+
const result2 = await chunkXAOA3XFQ_cjs.executeBuiltinTool(funcName, args, this._call);
|
|
2639
2701
|
if (result2 !== null) {
|
|
2640
2702
|
if (funcName === "hang_up") return;
|
|
2641
2703
|
if (controller.signal.aborted) return;
|
|
@@ -2652,6 +2714,20 @@ var OpenAIRealtime = class {
|
|
|
2652
2714
|
return;
|
|
2653
2715
|
}
|
|
2654
2716
|
}
|
|
2717
|
+
if (chunkXAOA3XFQ_cjs.BUILTIN_TOOL_NAMES.has(funcName) && this._call instanceof chunkXAOA3XFQ_cjs.BufferingCall) {
|
|
2718
|
+
this._log.warn("Builtin tool %s called before answer \u2014 deferring", funcName);
|
|
2719
|
+
await this._waitForResponseDone();
|
|
2720
|
+
this._send({
|
|
2721
|
+
type: "conversation.item.create",
|
|
2722
|
+
item: {
|
|
2723
|
+
type: "function_call_output",
|
|
2724
|
+
call_id: callId,
|
|
2725
|
+
output: chunkXAOA3XFQ_cjs.CALL_NOT_READY_RESULT
|
|
2726
|
+
}
|
|
2727
|
+
});
|
|
2728
|
+
this._send({ type: "response.create" });
|
|
2729
|
+
return;
|
|
2730
|
+
}
|
|
2655
2731
|
if (!this._tools || !this._tools.has(funcName)) {
|
|
2656
2732
|
this._log.error("Unknown tool: %s", funcName);
|
|
2657
2733
|
await this._waitForResponseDone();
|
|
@@ -2667,7 +2743,7 @@ var OpenAIRealtime = class {
|
|
|
2667
2743
|
return;
|
|
2668
2744
|
}
|
|
2669
2745
|
let result;
|
|
2670
|
-
const player = this._holdAudioChunks && this._call && !(this._call instanceof
|
|
2746
|
+
const player = this._holdAudioChunks && this._call && !(this._call instanceof chunkXAOA3XFQ_cjs.BufferingCall) ? new HoldAudioPlayer(this._call, this._holdAudioChunks) : null;
|
|
2671
2747
|
player?.start();
|
|
2672
2748
|
try {
|
|
2673
2749
|
const args = JSON.parse(item["arguments"] ?? "{}");
|
|
@@ -2789,6 +2865,13 @@ function sanitizeSchemaForGemini(schema, defs, depth = 0) {
|
|
|
2789
2865
|
return result;
|
|
2790
2866
|
}
|
|
2791
2867
|
var GeminiRealtime = class _GeminiRealtime {
|
|
2868
|
+
/**
|
|
2869
|
+
* Gemini Live 는 connect 시점의 config 로 도구가 고정되어 세션 도중 변경할 수 없다.
|
|
2870
|
+
*
|
|
2871
|
+
* 통화 시작 시점에야 붙는 MCP 도구는 prewarm 된 세션에 넣을 방법이 없으므로,
|
|
2872
|
+
* `ClawOpsAgent` 가 MCP 서버 설정과 이 플래그를 보고 prewarm 을 건너뛴다.
|
|
2873
|
+
*/
|
|
2874
|
+
toolsFrozenAfterPrewarm = true;
|
|
2792
2875
|
_apiKey;
|
|
2793
2876
|
_systemPrompt;
|
|
2794
2877
|
_model;
|
|
@@ -2809,7 +2892,7 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
2809
2892
|
_toolDrainTimer = null;
|
|
2810
2893
|
_lastAudioTime = 0;
|
|
2811
2894
|
_holdAudioChunks = null;
|
|
2812
|
-
_log =
|
|
2895
|
+
_log = chunkXAOA3XFQ_cjs.NOOP_LOGGER;
|
|
2813
2896
|
constructor(options = {}) {
|
|
2814
2897
|
this._apiKey = options.apiKey ?? process.env["GOOGLE_API_KEY"] ?? "";
|
|
2815
2898
|
this._systemPrompt = options.systemPrompt ?? "";
|
|
@@ -2855,7 +2938,7 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
2855
2938
|
/** Open Live session (no CallSession). Audio deltas accumulate into BufferingCall until attach(). */
|
|
2856
2939
|
async prewarm(tools) {
|
|
2857
2940
|
if (tools) this._tools = tools;
|
|
2858
|
-
this._call = new
|
|
2941
|
+
this._call = new chunkXAOA3XFQ_cjs.BufferingCall();
|
|
2859
2942
|
this._closed = false;
|
|
2860
2943
|
this._sentAudioChunks = 0;
|
|
2861
2944
|
this._audioRemainder = Buffer.alloc(0);
|
|
@@ -2912,7 +2995,7 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
2912
2995
|
async attach(callSession) {
|
|
2913
2996
|
const prev = this._call;
|
|
2914
2997
|
this._call = callSession;
|
|
2915
|
-
|
|
2998
|
+
chunkXAOA3XFQ_cjs.attachBuffered(prev, callSession);
|
|
2916
2999
|
}
|
|
2917
3000
|
async start(callSession, tools) {
|
|
2918
3001
|
if (tools) this._tools = tools;
|
|
@@ -2921,8 +3004,8 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
2921
3004
|
}
|
|
2922
3005
|
feedAudio(audio) {
|
|
2923
3006
|
if (this._session && !this._closed) {
|
|
2924
|
-
const pcm8k =
|
|
2925
|
-
const pcm16k =
|
|
3007
|
+
const pcm8k = chunkXAOA3XFQ_cjs.ulawToPcm16(audio);
|
|
3008
|
+
const pcm16k = chunkXAOA3XFQ_cjs.resamplePcm16(pcm8k, 8e3, 16e3);
|
|
2926
3009
|
this._session.sendRealtimeInput({
|
|
2927
3010
|
audio: {
|
|
2928
3011
|
data: Buffer.from(pcm16k).toString("base64"),
|
|
@@ -2966,7 +3049,7 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
2966
3049
|
t.function.parameters ?? { type: "object", properties: {} }
|
|
2967
3050
|
)
|
|
2968
3051
|
})) : [];
|
|
2969
|
-
toolDefs.push(...
|
|
3052
|
+
toolDefs.push(...chunkXAOA3XFQ_cjs.getBuiltinToolSchemas(this._builtinTools, "gemini"));
|
|
2970
3053
|
return toolDefs;
|
|
2971
3054
|
}
|
|
2972
3055
|
_handleMessage(msg) {
|
|
@@ -3026,8 +3109,8 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
3026
3109
|
_handleAudioData(b64Data) {
|
|
3027
3110
|
if (!this._call) return;
|
|
3028
3111
|
const pcm24k = Buffer.from(b64Data, "base64");
|
|
3029
|
-
const pcm8k =
|
|
3030
|
-
const ulaw =
|
|
3112
|
+
const pcm8k = chunkXAOA3XFQ_cjs.resamplePcm16(pcm24k, 24e3, 8e3);
|
|
3113
|
+
const ulaw = chunkXAOA3XFQ_cjs.pcm16ToUlaw(pcm8k);
|
|
3031
3114
|
const combined = Buffer.concat([this._audioRemainder, ulaw]);
|
|
3032
3115
|
const chunkSize = 160;
|
|
3033
3116
|
const fullEnd = Math.floor(combined.length / chunkSize) * chunkSize;
|
|
@@ -3070,7 +3153,7 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
3070
3153
|
const functionCalls = toolCall.functionCalls;
|
|
3071
3154
|
if (!functionCalls) return;
|
|
3072
3155
|
const responses = [];
|
|
3073
|
-
const player = this._holdAudioChunks && this._call && !(this._call instanceof
|
|
3156
|
+
const player = this._holdAudioChunks && this._call && !(this._call instanceof chunkXAOA3XFQ_cjs.BufferingCall) ? new HoldAudioPlayer(this._call, this._holdAudioChunks) : null;
|
|
3074
3157
|
player?.start();
|
|
3075
3158
|
try {
|
|
3076
3159
|
for (const fc of functionCalls) {
|
|
@@ -3078,8 +3161,8 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
3078
3161
|
const fcId = fc.id ?? "";
|
|
3079
3162
|
const args = fc.args ?? {};
|
|
3080
3163
|
this._log.info({ tool: name, args }, "Tool call: %s", name);
|
|
3081
|
-
if (
|
|
3082
|
-
const result = await
|
|
3164
|
+
if (chunkXAOA3XFQ_cjs.BUILTIN_TOOL_NAMES.has(name) && this._call && !(this._call instanceof chunkXAOA3XFQ_cjs.BufferingCall)) {
|
|
3165
|
+
const result = await chunkXAOA3XFQ_cjs.executeBuiltinTool(
|
|
3083
3166
|
name,
|
|
3084
3167
|
args,
|
|
3085
3168
|
this._call
|
|
@@ -3094,6 +3177,11 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
3094
3177
|
continue;
|
|
3095
3178
|
}
|
|
3096
3179
|
}
|
|
3180
|
+
if (chunkXAOA3XFQ_cjs.BUILTIN_TOOL_NAMES.has(name) && this._call instanceof chunkXAOA3XFQ_cjs.BufferingCall) {
|
|
3181
|
+
this._log.warn("Builtin tool %s called before answer \u2014 deferring", name);
|
|
3182
|
+
responses.push({ id: fcId, name, response: { result: chunkXAOA3XFQ_cjs.CALL_NOT_READY_RESULT } });
|
|
3183
|
+
continue;
|
|
3184
|
+
}
|
|
3097
3185
|
if (!this._tools || !this._tools.has(name)) {
|
|
3098
3186
|
this._log.error("Unknown tool: %s", name);
|
|
3099
3187
|
responses.push({ id: fcId, name, response: { error: `Unknown tool: ${name}` } });
|
|
@@ -3136,7 +3224,7 @@ var GeminiRealtime = class _GeminiRealtime {
|
|
|
3136
3224
|
// src/agent/pipeline/stt/deepgram-stt.ts
|
|
3137
3225
|
var DeepgramSTT = class {
|
|
3138
3226
|
_options;
|
|
3139
|
-
_log =
|
|
3227
|
+
_log = chunkXAOA3XFQ_cjs.NOOP_LOGGER;
|
|
3140
3228
|
get provider() {
|
|
3141
3229
|
return "deepgram";
|
|
3142
3230
|
}
|
|
@@ -3263,7 +3351,7 @@ var DeepgramSTT = class {
|
|
|
3263
3351
|
// src/agent/pipeline/tts/elevenlabs-tts.ts
|
|
3264
3352
|
var ElevenLabsTTS = class {
|
|
3265
3353
|
_options;
|
|
3266
|
-
_log =
|
|
3354
|
+
_log = chunkXAOA3XFQ_cjs.NOOP_LOGGER;
|
|
3267
3355
|
get provider() {
|
|
3268
3356
|
return "elevenlabs";
|
|
3269
3357
|
}
|
|
@@ -4009,47 +4097,47 @@ function mcpServerHTTP(options) {
|
|
|
4009
4097
|
|
|
4010
4098
|
Object.defineProperty(exports, "BUILTIN_TOOL_NAMES", {
|
|
4011
4099
|
enumerable: true,
|
|
4012
|
-
get: function () { return
|
|
4100
|
+
get: function () { return chunkXAOA3XFQ_cjs.BUILTIN_TOOL_NAMES; }
|
|
4013
4101
|
});
|
|
4014
4102
|
Object.defineProperty(exports, "BuiltinTool", {
|
|
4015
4103
|
enumerable: true,
|
|
4016
|
-
get: function () { return
|
|
4104
|
+
get: function () { return chunkXAOA3XFQ_cjs.BuiltinTool; }
|
|
4017
4105
|
});
|
|
4018
4106
|
Object.defineProperty(exports, "DECODE_TABLE", {
|
|
4019
4107
|
enumerable: true,
|
|
4020
|
-
get: function () { return
|
|
4108
|
+
get: function () { return chunkXAOA3XFQ_cjs.DECODE_TABLE; }
|
|
4021
4109
|
});
|
|
4022
4110
|
Object.defineProperty(exports, "createAgentLogger", {
|
|
4023
4111
|
enumerable: true,
|
|
4024
|
-
get: function () { return
|
|
4112
|
+
get: function () { return chunkXAOA3XFQ_cjs.createAgentLogger; }
|
|
4025
4113
|
});
|
|
4026
4114
|
Object.defineProperty(exports, "createPipelineLogger", {
|
|
4027
4115
|
enumerable: true,
|
|
4028
|
-
get: function () { return
|
|
4116
|
+
get: function () { return chunkXAOA3XFQ_cjs.createPipelineLogger; }
|
|
4029
4117
|
});
|
|
4030
4118
|
Object.defineProperty(exports, "executeBuiltinTool", {
|
|
4031
4119
|
enumerable: true,
|
|
4032
|
-
get: function () { return
|
|
4120
|
+
get: function () { return chunkXAOA3XFQ_cjs.executeBuiltinTool; }
|
|
4033
4121
|
});
|
|
4034
4122
|
Object.defineProperty(exports, "getBuiltinToolSchemas", {
|
|
4035
4123
|
enumerable: true,
|
|
4036
|
-
get: function () { return
|
|
4124
|
+
get: function () { return chunkXAOA3XFQ_cjs.getBuiltinToolSchemas; }
|
|
4037
4125
|
});
|
|
4038
4126
|
Object.defineProperty(exports, "isBuiltinTool", {
|
|
4039
4127
|
enumerable: true,
|
|
4040
|
-
get: function () { return
|
|
4128
|
+
get: function () { return chunkXAOA3XFQ_cjs.isBuiltinTool; }
|
|
4041
4129
|
});
|
|
4042
4130
|
Object.defineProperty(exports, "pcm16ToUlaw", {
|
|
4043
4131
|
enumerable: true,
|
|
4044
|
-
get: function () { return
|
|
4132
|
+
get: function () { return chunkXAOA3XFQ_cjs.pcm16ToUlaw; }
|
|
4045
4133
|
});
|
|
4046
4134
|
Object.defineProperty(exports, "resamplePcm16", {
|
|
4047
4135
|
enumerable: true,
|
|
4048
|
-
get: function () { return
|
|
4136
|
+
get: function () { return chunkXAOA3XFQ_cjs.resamplePcm16; }
|
|
4049
4137
|
});
|
|
4050
4138
|
Object.defineProperty(exports, "ulawToPcm16", {
|
|
4051
4139
|
enumerable: true,
|
|
4052
|
-
get: function () { return
|
|
4140
|
+
get: function () { return chunkXAOA3XFQ_cjs.ulawToPcm16; }
|
|
4053
4141
|
});
|
|
4054
4142
|
exports.AnthropicLLM = AnthropicLLM;
|
|
4055
4143
|
exports.AudioRecorder = AudioRecorder;
|