@teamlearners/clawops 0.5.5 → 0.5.8
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 +581 -627
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +99 -74
- package/dist/agent/index.d.ts +99 -74
- package/dist/agent/index.js +578 -628
- package/dist/agent/index.js.map +1 -1
- package/package.json +2 -2
package/dist/agent/index.js
CHANGED
|
@@ -1459,6 +1459,7 @@ var ClawOpsAgent = class {
|
|
|
1459
1459
|
}
|
|
1460
1460
|
/** Connect to the ClawOps platform and start listening for calls. */
|
|
1461
1461
|
async connect() {
|
|
1462
|
+
if (this._controlWs) return;
|
|
1462
1463
|
if (!this._apiKey) {
|
|
1463
1464
|
throw new AgentError("API key is required. Set CLAWOPS_API_KEY or pass apiKey option.");
|
|
1464
1465
|
}
|
|
@@ -1773,20 +1774,13 @@ var ClawOpsAgent = class {
|
|
|
1773
1774
|
}
|
|
1774
1775
|
};
|
|
1775
1776
|
|
|
1776
|
-
// src/agent/pipeline/
|
|
1777
|
-
var
|
|
1778
|
-
var HANG_UP_TOOL = {
|
|
1779
|
-
type: "function",
|
|
1777
|
+
// src/agent/pipeline/builtin-tool-schemas.ts
|
|
1778
|
+
var HANG_UP = {
|
|
1780
1779
|
name: "hang_up",
|
|
1781
1780
|
description: "End the phone call. Use when the conversation is finished or the caller says goodbye.",
|
|
1782
|
-
parameters: {
|
|
1783
|
-
type: "object",
|
|
1784
|
-
properties: {},
|
|
1785
|
-
required: []
|
|
1786
|
-
}
|
|
1781
|
+
parameters: { type: "object", properties: {} }
|
|
1787
1782
|
};
|
|
1788
|
-
var
|
|
1789
|
-
type: "function",
|
|
1783
|
+
var COLLECT_DTMF = {
|
|
1790
1784
|
name: "collect_dtmf",
|
|
1791
1785
|
description: "\uC0AC\uC6A9\uC790\uB85C\uBD80\uD130 DTMF(\uC804\uD654 \uD0A4\uD328\uB4DC) \uC785\uB825\uC744 \uC218\uC9D1\uD569\uB2C8\uB2E4. \uBC18\uB4DC\uC2DC \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBB34\uC5C7\uC744 \uC785\uB825\uD574\uC57C \uD558\uB294\uC9C0 \uC548\uB0B4\uD55C \uD6C4 \uD638\uCD9C\uD558\uC138\uC694.",
|
|
1792
1786
|
parameters: {
|
|
@@ -1799,8 +1793,7 @@ var COLLECT_DTMF_TOOL = {
|
|
|
1799
1793
|
required: ["max_digits"]
|
|
1800
1794
|
}
|
|
1801
1795
|
};
|
|
1802
|
-
var
|
|
1803
|
-
type: "function",
|
|
1796
|
+
var SEND_DTMF = {
|
|
1804
1797
|
name: "send_dtmf",
|
|
1805
1798
|
description: "DTMF \uC2E0\uD638\uB97C \uC804\uC1A1\uD569\uB2C8\uB2E4. ARS \uBA54\uB274 \uD0D0\uC0C9\uC774\uB098 \uB0B4\uC120\uBC88\uD638 \uC785\uB825 \uC2DC \uC0AC\uC6A9\uD569\uB2C8\uB2E4.",
|
|
1806
1799
|
parameters: {
|
|
@@ -1808,181 +1801,512 @@ var SEND_DTMF_TOOL = {
|
|
|
1808
1801
|
properties: {
|
|
1809
1802
|
digits: {
|
|
1810
1803
|
type: "string",
|
|
1811
|
-
description: "\uC804\uC1A1\uD560 \uBC88\uD638 (0-9, *, #). 'w'\uB294 500ms \uB300\uAE30, 'W'\uB294 1000ms \uB300\uAE30."
|
|
1804
|
+
description: "\uC804\uC1A1\uD560 \uBC88\uD638 (0-9, *, #). 'w'\uB294 500ms \uB300\uAE30, 'W'\uB294 1000ms \uB300\uAE30. \uC608: '1', '1234#', '1w2'"
|
|
1812
1805
|
}
|
|
1813
1806
|
},
|
|
1814
1807
|
required: ["digits"]
|
|
1815
1808
|
}
|
|
1816
1809
|
};
|
|
1817
|
-
var
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1810
|
+
var TOOL_MAP = /* @__PURE__ */ new Map([
|
|
1811
|
+
["hang_up" /* HANG_UP */, HANG_UP],
|
|
1812
|
+
["collect_dtmf" /* COLLECT_DTMF */, COLLECT_DTMF],
|
|
1813
|
+
["send_dtmf" /* SEND_DTMF */, SEND_DTMF]
|
|
1814
|
+
]);
|
|
1815
|
+
var BUILTIN_TOOL_NAMES = new Set(
|
|
1816
|
+
Array.from(TOOL_MAP.values()).map((s) => s.name)
|
|
1817
|
+
);
|
|
1818
|
+
function toChatCompletions(schema) {
|
|
1819
|
+
return {
|
|
1820
|
+
type: "function",
|
|
1821
|
+
function: {
|
|
1822
|
+
name: schema.name,
|
|
1823
|
+
description: schema.description,
|
|
1824
|
+
parameters: schema.parameters
|
|
1825
|
+
}
|
|
1826
|
+
};
|
|
1827
|
+
}
|
|
1828
|
+
function toRealtime(schema) {
|
|
1829
|
+
return {
|
|
1830
|
+
type: "function",
|
|
1831
|
+
name: schema.name,
|
|
1832
|
+
description: schema.description,
|
|
1833
|
+
parameters: schema.parameters
|
|
1834
|
+
};
|
|
1835
|
+
}
|
|
1836
|
+
function toGemini(schema) {
|
|
1837
|
+
return {
|
|
1838
|
+
name: schema.name,
|
|
1839
|
+
description: schema.description,
|
|
1840
|
+
parameters: schema.parameters
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1843
|
+
var CONVERTERS = {
|
|
1844
|
+
chat: toChatCompletions,
|
|
1845
|
+
realtime: toRealtime,
|
|
1846
|
+
gemini: toGemini
|
|
1847
|
+
};
|
|
1848
|
+
function getBuiltinToolSchemas(builtinTools, fmt) {
|
|
1849
|
+
const converter = CONVERTERS[fmt];
|
|
1850
|
+
const result = [];
|
|
1851
|
+
for (const [toolEnum, schema] of TOOL_MAP) {
|
|
1852
|
+
if (builtinTools === null || builtinTools.has(toolEnum)) {
|
|
1853
|
+
result.push(converter(schema));
|
|
1854
|
+
}
|
|
1829
1855
|
}
|
|
1830
|
-
|
|
1831
|
-
|
|
1856
|
+
return result;
|
|
1857
|
+
}
|
|
1858
|
+
function isBuiltinTool(name) {
|
|
1859
|
+
return BUILTIN_TOOL_NAMES.has(name);
|
|
1860
|
+
}
|
|
1861
|
+
async function executeBuiltinTool(funcName, args, call) {
|
|
1862
|
+
if (funcName === "hang_up") {
|
|
1863
|
+
await call.hangup();
|
|
1864
|
+
return "";
|
|
1832
1865
|
}
|
|
1833
|
-
|
|
1834
|
-
|
|
1866
|
+
if (funcName === "collect_dtmf") {
|
|
1867
|
+
try {
|
|
1868
|
+
const result = await call.collectDtmf({
|
|
1869
|
+
maxDigits: args["max_digits"] ?? 4,
|
|
1870
|
+
finishOnKey: args["finish_on_key"] ?? "#",
|
|
1871
|
+
timeout: args["timeout"] ?? 5
|
|
1872
|
+
});
|
|
1873
|
+
return result || "(\uD0C0\uC784\uC544\uC6C3 - \uC785\uB825 \uC5C6\uC74C)";
|
|
1874
|
+
} catch (e) {
|
|
1875
|
+
return `Error: ${e}`;
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
if (funcName === "send_dtmf") {
|
|
1879
|
+
try {
|
|
1880
|
+
await call.sendDtmfSequence(args["digits"] ?? "");
|
|
1881
|
+
return "sent";
|
|
1882
|
+
} catch (e) {
|
|
1883
|
+
return `Error: ${e}`;
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
return null;
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
// src/agent/pipeline/pipeline-session.ts
|
|
1890
|
+
var PipelineSession = class {
|
|
1891
|
+
_stt;
|
|
1892
|
+
_llm;
|
|
1893
|
+
_tts;
|
|
1894
|
+
_systemPrompt;
|
|
1895
|
+
_greeting;
|
|
1896
|
+
_language;
|
|
1897
|
+
_temperature;
|
|
1898
|
+
_maxTokens;
|
|
1899
|
+
_sampleRate;
|
|
1900
|
+
_interruptOnSpeech;
|
|
1901
|
+
_callSession = null;
|
|
1835
1902
|
_tools = null;
|
|
1836
1903
|
_recorder = null;
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
this.
|
|
1848
|
-
this._systemPrompt = options.systemPrompt ?? "";
|
|
1849
|
-
this._model = options.model ?? "gpt-realtime-1.5";
|
|
1850
|
-
this._voice = options.voice ?? "marin";
|
|
1851
|
-
this._language = options.language ?? "ko";
|
|
1852
|
-
this._eagerness = options.eagerness ?? "high";
|
|
1904
|
+
_conversation = [];
|
|
1905
|
+
_audioBuffer = [];
|
|
1906
|
+
_running = false;
|
|
1907
|
+
_speaking = false;
|
|
1908
|
+
_builtinTools = null;
|
|
1909
|
+
_log = NOOP_LOGGER;
|
|
1910
|
+
constructor(options) {
|
|
1911
|
+
this._stt = options.stt;
|
|
1912
|
+
this._llm = options.llm;
|
|
1913
|
+
this._tts = options.tts;
|
|
1914
|
+
this._systemPrompt = options.systemPrompt;
|
|
1853
1915
|
this._greeting = options.greeting ?? true;
|
|
1916
|
+
this._language = options.language ?? "ko";
|
|
1917
|
+
this._temperature = options.temperature;
|
|
1918
|
+
this._maxTokens = options.maxTokens;
|
|
1919
|
+
this._sampleRate = options.sampleRate ?? 8e3;
|
|
1920
|
+
this._interruptOnSpeech = options.interruptOnSpeech ?? true;
|
|
1921
|
+
if (options.toolRegistry) this._tools = options.toolRegistry;
|
|
1922
|
+
if (options.recorder) this._recorder = options.recorder;
|
|
1854
1923
|
}
|
|
1855
|
-
/** Inject per-call ToolRegistry. */
|
|
1856
1924
|
setToolRegistry(registry) {
|
|
1857
1925
|
this._tools = registry;
|
|
1858
1926
|
}
|
|
1859
|
-
/** Inject per-call AudioRecorder. */
|
|
1860
1927
|
setRecorder(recorder) {
|
|
1861
1928
|
this._recorder = recorder;
|
|
1862
1929
|
}
|
|
1863
|
-
|
|
1864
|
-
this.
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
this.
|
|
1868
|
-
this.
|
|
1869
|
-
|
|
1870
|
-
this._audioRemainder = Buffer.alloc(0);
|
|
1871
|
-
if (!this._apiKey) {
|
|
1872
|
-
throw new Error("OpenAI API key is required. Set OPENAI_API_KEY or pass apiKey option.");
|
|
1930
|
+
setBuiltinTools(tools) {
|
|
1931
|
+
this._builtinTools = tools;
|
|
1932
|
+
}
|
|
1933
|
+
setLogger(logger) {
|
|
1934
|
+
this._log = logger;
|
|
1935
|
+
if ("setLogger" in this._stt && typeof this._stt.setLogger === "function") {
|
|
1936
|
+
this._stt.setLogger(logger);
|
|
1873
1937
|
}
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
this._send({ type: "response.create" });
|
|
1889
|
-
}
|
|
1890
|
-
resolve();
|
|
1891
|
-
});
|
|
1892
|
-
ws.on("message", (data) => {
|
|
1893
|
-
try {
|
|
1894
|
-
const msg = JSON.parse(data.toString());
|
|
1895
|
-
this._handleMessage(msg);
|
|
1896
|
-
} catch {
|
|
1897
|
-
}
|
|
1898
|
-
});
|
|
1899
|
-
ws.on("close", () => {
|
|
1900
|
-
this._closed = true;
|
|
1938
|
+
if ("setLogger" in this._tts && typeof this._tts.setLogger === "function") {
|
|
1939
|
+
this._tts.setLogger(logger);
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
async start(callSession, tools) {
|
|
1943
|
+
this._callSession = callSession;
|
|
1944
|
+
this._tools = tools ?? null;
|
|
1945
|
+
this._running = true;
|
|
1946
|
+
this._log.info("PipelineSession started");
|
|
1947
|
+
this._conversation = [];
|
|
1948
|
+
if (this._systemPrompt) {
|
|
1949
|
+
this._conversation.push({
|
|
1950
|
+
role: "system",
|
|
1951
|
+
content: this._systemPrompt
|
|
1901
1952
|
});
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
}
|
|
1906
|
-
this._log.error({ err }, "OpenAI Realtime WS error");
|
|
1953
|
+
}
|
|
1954
|
+
if (this._greeting) {
|
|
1955
|
+
this._generateGreeting().catch((err) => {
|
|
1956
|
+
this._log.error({ err }, "Greeting error");
|
|
1907
1957
|
});
|
|
1958
|
+
}
|
|
1959
|
+
this._runSttLoop().catch((err) => {
|
|
1960
|
+
this._log.error({ err }, "STT loop error");
|
|
1908
1961
|
});
|
|
1909
1962
|
}
|
|
1910
|
-
async feedDtmf(digits) {
|
|
1911
|
-
await this._waitForResponseDone();
|
|
1912
|
-
this._send({
|
|
1913
|
-
type: "conversation.item.create",
|
|
1914
|
-
item: {
|
|
1915
|
-
type: "message",
|
|
1916
|
-
role: "user",
|
|
1917
|
-
content: [{ type: "input_text", text: `[DTMF \uC785\uB825: ${digits}]` }]
|
|
1918
|
-
}
|
|
1919
|
-
});
|
|
1920
|
-
this._send({ type: "response.create" });
|
|
1921
|
-
}
|
|
1922
1963
|
feedAudio(audio) {
|
|
1923
|
-
if (this.
|
|
1924
|
-
this.
|
|
1925
|
-
type: "input_audio_buffer.append",
|
|
1926
|
-
audio: audio.toString("base64")
|
|
1927
|
-
});
|
|
1964
|
+
if (this._running) {
|
|
1965
|
+
this._audioBuffer.push(audio);
|
|
1928
1966
|
}
|
|
1929
1967
|
}
|
|
1968
|
+
async feedDtmf(digits) {
|
|
1969
|
+
this._conversation.push({
|
|
1970
|
+
role: "user",
|
|
1971
|
+
content: `[DTMF \uC785\uB825: ${digits}]`
|
|
1972
|
+
});
|
|
1973
|
+
await this._respond();
|
|
1974
|
+
}
|
|
1930
1975
|
async stop() {
|
|
1931
|
-
this.
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1976
|
+
this._running = false;
|
|
1977
|
+
this._log.info("PipelineSession stopped");
|
|
1978
|
+
this._audioBuffer = [];
|
|
1979
|
+
}
|
|
1980
|
+
async _runSttLoop() {
|
|
1981
|
+
const audioStream = this._createAudioStream();
|
|
1982
|
+
for await (const event of this._stt.transcribe(audioStream, {
|
|
1983
|
+
sampleRate: this._sampleRate
|
|
1984
|
+
})) {
|
|
1985
|
+
if (!this._running) break;
|
|
1986
|
+
if (event.type === "interim" && this._speaking && this._interruptOnSpeech) {
|
|
1987
|
+
this._speaking = false;
|
|
1988
|
+
if (this._callSession) {
|
|
1989
|
+
this._callSession.clearAudio();
|
|
1990
|
+
}
|
|
1991
|
+
this._log.info('Barge-in: "%s"', event.transcript.substring(0, 30));
|
|
1992
|
+
}
|
|
1993
|
+
if (event.type === "final" && event.transcript.trim()) {
|
|
1994
|
+
this._log.info("STT: %s", event.transcript);
|
|
1995
|
+
await this._handleUserSpeech(event.transcript);
|
|
1996
|
+
}
|
|
1935
1997
|
}
|
|
1936
1998
|
}
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
this._send({
|
|
1947
|
-
type: "session.update",
|
|
1948
|
-
session: {
|
|
1949
|
-
modalities: ["text", "audio"],
|
|
1950
|
-
voice: this._voice,
|
|
1951
|
-
instructions: this._systemPrompt,
|
|
1952
|
-
input_audio_format: "g711_ulaw",
|
|
1953
|
-
output_audio_format: "g711_ulaw",
|
|
1954
|
-
input_audio_transcription: {
|
|
1955
|
-
model: "whisper-1",
|
|
1956
|
-
language: this._language
|
|
1957
|
-
},
|
|
1958
|
-
input_audio_noise_reduction: { type: "far_field" },
|
|
1959
|
-
turn_detection: {
|
|
1960
|
-
type: "semantic_vad",
|
|
1961
|
-
interrupt_response: true,
|
|
1962
|
-
eagerness: this._eagerness
|
|
1963
|
-
},
|
|
1964
|
-
tools: toolSchemas
|
|
1999
|
+
async *_createAudioStream() {
|
|
2000
|
+
while (this._running) {
|
|
2001
|
+
if (this._audioBuffer.length > 0) {
|
|
2002
|
+
const ulaw = this._audioBuffer.shift();
|
|
2003
|
+
const pcm8k = ulawToPcm16(ulaw);
|
|
2004
|
+
const pcm16k = resamplePcm16(pcm8k, 8e3, 16e3);
|
|
2005
|
+
yield pcm16k;
|
|
2006
|
+
} else {
|
|
2007
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
1965
2008
|
}
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
async _generateGreeting() {
|
|
2012
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
2013
|
+
await this._respond();
|
|
2014
|
+
}
|
|
2015
|
+
async _handleUserSpeech(transcript) {
|
|
2016
|
+
this._conversation.push({ role: "user", content: transcript });
|
|
2017
|
+
await this._respond();
|
|
2018
|
+
}
|
|
2019
|
+
_buildEffectiveTools() {
|
|
2020
|
+
const builtinSchemas = getBuiltinToolSchemas(this._builtinTools, "chat");
|
|
2021
|
+
const dtmfSchemas = builtinSchemas.filter((s) => {
|
|
2022
|
+
const name = s["function"]?.["name"];
|
|
2023
|
+
return name === "collect_dtmf" || name === "send_dtmf";
|
|
1966
2024
|
});
|
|
2025
|
+
if (dtmfSchemas.length === 0) return this._tools ?? void 0;
|
|
2026
|
+
const base = this._tools ? this._tools.fork() : new ToolRegistry();
|
|
2027
|
+
for (const schema of dtmfSchemas) {
|
|
2028
|
+
const fn = schema["function"];
|
|
2029
|
+
const params = fn["parameters"];
|
|
2030
|
+
base.register({
|
|
2031
|
+
name: fn["name"],
|
|
2032
|
+
description: fn["description"],
|
|
2033
|
+
parameters: params["properties"] ?? {},
|
|
2034
|
+
required: params["required"] ?? [],
|
|
2035
|
+
handler: async () => ""
|
|
2036
|
+
});
|
|
2037
|
+
}
|
|
2038
|
+
return base;
|
|
1967
2039
|
}
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
2040
|
+
async _respond() {
|
|
2041
|
+
let fullResponse = "";
|
|
2042
|
+
const textChunks = [];
|
|
2043
|
+
const effectiveTools = this._buildEffectiveTools();
|
|
2044
|
+
const llmStream = this._llm.generate(this._conversation, {
|
|
2045
|
+
tools: effectiveTools,
|
|
2046
|
+
temperature: this._temperature,
|
|
2047
|
+
maxTokens: this._maxTokens
|
|
2048
|
+
});
|
|
2049
|
+
for await (const chunk of llmStream) {
|
|
2050
|
+
if (!this._running) break;
|
|
2051
|
+
if (chunk.type === "text" && chunk.text) {
|
|
2052
|
+
textChunks.push(chunk.text);
|
|
2053
|
+
fullResponse += chunk.text;
|
|
2054
|
+
} else if (chunk.type === "tool_call" && chunk.toolCall) {
|
|
2055
|
+
await this._handleToolCall(chunk);
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
if (fullResponse.trim()) {
|
|
2059
|
+
this._log.info("Assistant: %s", fullResponse.substring(0, 100));
|
|
2060
|
+
this._conversation.push({ role: "assistant", content: fullResponse });
|
|
2061
|
+
await this._synthesizeAndSend(fullResponse);
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
async _handleToolCall(chunk) {
|
|
2065
|
+
if (!chunk.toolCall) return;
|
|
2066
|
+
const { id, name, arguments: argsStr } = chunk.toolCall;
|
|
2067
|
+
try {
|
|
2068
|
+
const args = JSON.parse(argsStr);
|
|
2069
|
+
if (BUILTIN_TOOL_NAMES.has(name) && this._callSession) {
|
|
2070
|
+
const result2 = await executeBuiltinTool(name, args, this._callSession);
|
|
2071
|
+
if (result2 !== null) {
|
|
2072
|
+
if (name === "hang_up") return;
|
|
2073
|
+
this._conversation.push({ role: "tool", content: result2, tool_call_id: id, name });
|
|
2074
|
+
await this._respond();
|
|
2075
|
+
return;
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
if (!this._tools) return;
|
|
2079
|
+
const result = await this._tools.call(name, args);
|
|
2080
|
+
this._conversation.push({
|
|
2081
|
+
role: "assistant",
|
|
2082
|
+
content: ""
|
|
2083
|
+
// Tool call info stored in the message flow
|
|
2084
|
+
});
|
|
2085
|
+
this._conversation.push({
|
|
2086
|
+
role: "tool",
|
|
2087
|
+
content: typeof result === "string" ? result : JSON.stringify(result),
|
|
2088
|
+
tool_call_id: id,
|
|
2089
|
+
name
|
|
2090
|
+
});
|
|
2091
|
+
const effectiveTools = this._buildEffectiveTools();
|
|
2092
|
+
let followUpText = "";
|
|
2093
|
+
const followUpStream = this._llm.generate(this._conversation, {
|
|
2094
|
+
tools: effectiveTools,
|
|
2095
|
+
temperature: this._temperature,
|
|
2096
|
+
maxTokens: this._maxTokens
|
|
2097
|
+
});
|
|
2098
|
+
for await (const followChunk of followUpStream) {
|
|
2099
|
+
if (!this._running) break;
|
|
2100
|
+
if (followChunk.type === "text" && followChunk.text) {
|
|
2101
|
+
followUpText += followChunk.text;
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
if (followUpText.trim()) {
|
|
2105
|
+
this._conversation.push({ role: "assistant", content: followUpText });
|
|
2106
|
+
await this._synthesizeAndSend(followUpText);
|
|
2107
|
+
}
|
|
2108
|
+
} catch (err) {
|
|
2109
|
+
this._log.error({ err }, "Tool call failed: %s", name);
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
async _synthesizeAndSend(text) {
|
|
2113
|
+
if (!this._callSession || !this._running) return;
|
|
2114
|
+
this._speaking = true;
|
|
2115
|
+
try {
|
|
2116
|
+
for await (const audioChunk of this._tts.synthesize(text, {
|
|
2117
|
+
sampleRate: this._sampleRate
|
|
2118
|
+
})) {
|
|
2119
|
+
if (!this._running || !this._speaking) break;
|
|
2120
|
+
if (this._recorder) {
|
|
2121
|
+
const pcm8k2 = this._sampleRate !== 8e3 ? resamplePcm16(audioChunk, this._sampleRate, 8e3) : audioChunk;
|
|
2122
|
+
this._recorder.writeOutbound(pcm8k2);
|
|
2123
|
+
}
|
|
2124
|
+
const pcm8k = resamplePcm16(audioChunk, this._sampleRate, 8e3);
|
|
2125
|
+
const ulaw = pcm16ToUlaw(pcm8k);
|
|
2126
|
+
for (let off = 0; off < ulaw.length; off += 160) {
|
|
2127
|
+
let chunk = ulaw.subarray(off, off + 160);
|
|
2128
|
+
if (chunk.length < 160) {
|
|
2129
|
+
chunk = Buffer.concat([chunk, Buffer.alloc(160 - chunk.length, 255)]);
|
|
2130
|
+
}
|
|
2131
|
+
this._callSession.sendAudio(chunk);
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
} catch (err) {
|
|
2135
|
+
this._log.error({ err }, "TTS error");
|
|
2136
|
+
} finally {
|
|
2137
|
+
this._speaking = false;
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
};
|
|
2141
|
+
|
|
2142
|
+
// src/agent/pipeline/realtime/openai-realtime.ts
|
|
2143
|
+
var OPENAI_REALTIME_URL = "wss://api.openai.com/v1/realtime?model=";
|
|
2144
|
+
var OpenAIRealtime = class {
|
|
2145
|
+
_apiKey;
|
|
2146
|
+
_systemPrompt;
|
|
2147
|
+
_model;
|
|
2148
|
+
_voice;
|
|
2149
|
+
_language;
|
|
2150
|
+
_turnDetection;
|
|
2151
|
+
_greeting;
|
|
2152
|
+
_log = NOOP_LOGGER;
|
|
2153
|
+
_builtinTools = null;
|
|
2154
|
+
setLogger(logger) {
|
|
2155
|
+
this._log = logger;
|
|
2156
|
+
}
|
|
2157
|
+
setBuiltinTools(tools) {
|
|
2158
|
+
this._builtinTools = tools;
|
|
2159
|
+
}
|
|
2160
|
+
_ws = null;
|
|
2161
|
+
_call = null;
|
|
2162
|
+
_tools = null;
|
|
2163
|
+
_recorder = null;
|
|
2164
|
+
_closed = false;
|
|
2165
|
+
// PlaybackState — 현재 재생 중인 응답 상태
|
|
2166
|
+
_playback = null;
|
|
2167
|
+
_latestMediaTs = 0;
|
|
2168
|
+
// Pending tool call tracking — 인터럽트 시 취소용
|
|
2169
|
+
_pendingToolCalls = /* @__PURE__ */ new Map();
|
|
2170
|
+
// Response state tracking — prevent sending response.create while one is active
|
|
2171
|
+
_responseInProgress = false;
|
|
2172
|
+
_onResponseDone = null;
|
|
2173
|
+
constructor(options = {}) {
|
|
2174
|
+
this._apiKey = options.apiKey ?? process.env["OPENAI_API_KEY"] ?? "";
|
|
2175
|
+
this._systemPrompt = options.systemPrompt ?? "";
|
|
2176
|
+
this._model = options.model ?? "gpt-realtime-1.5";
|
|
2177
|
+
this._voice = options.voice ?? "marin";
|
|
2178
|
+
this._language = options.language ?? "ko";
|
|
2179
|
+
this._turnDetection = options.turnDetection !== void 0 ? options.turnDetection : { type: "semantic_vad", eagerness: "medium", interrupt_response: true };
|
|
2180
|
+
this._greeting = options.greeting ?? true;
|
|
2181
|
+
}
|
|
2182
|
+
/** Inject per-call ToolRegistry. */
|
|
2183
|
+
setToolRegistry(registry) {
|
|
2184
|
+
this._tools = registry;
|
|
2185
|
+
}
|
|
2186
|
+
/** Inject per-call AudioRecorder. */
|
|
2187
|
+
setRecorder(recorder) {
|
|
2188
|
+
this._recorder = recorder;
|
|
2189
|
+
}
|
|
2190
|
+
async start(callSession, tools) {
|
|
2191
|
+
this._call = callSession;
|
|
2192
|
+
if (tools) this._tools = tools;
|
|
2193
|
+
this._closed = false;
|
|
2194
|
+
this._playback = null;
|
|
2195
|
+
this._latestMediaTs = 0;
|
|
2196
|
+
if (!this._apiKey) {
|
|
2197
|
+
throw new Error("OpenAI API key is required. Set OPENAI_API_KEY or pass apiKey option.");
|
|
2198
|
+
}
|
|
2199
|
+
const { WebSocket } = await import('ws');
|
|
2200
|
+
const url = `${OPENAI_REALTIME_URL}${this._model}`;
|
|
2201
|
+
this._ws = new WebSocket(url, {
|
|
2202
|
+
headers: {
|
|
2203
|
+
Authorization: `Bearer ${this._apiKey}`,
|
|
2204
|
+
"OpenAI-Beta": "realtime=v1"
|
|
2205
|
+
}
|
|
2206
|
+
});
|
|
2207
|
+
return new Promise((resolve, reject) => {
|
|
2208
|
+
const ws = this._ws;
|
|
2209
|
+
ws.on("open", () => {
|
|
2210
|
+
this._sendSessionUpdate();
|
|
2211
|
+
this._log.info("OpenAI Realtime connected");
|
|
2212
|
+
if (this._greeting) {
|
|
2213
|
+
this._send({ type: "response.create" });
|
|
2214
|
+
}
|
|
2215
|
+
resolve();
|
|
2216
|
+
});
|
|
2217
|
+
ws.on("message", (data) => {
|
|
2218
|
+
try {
|
|
2219
|
+
const msg = JSON.parse(data.toString());
|
|
2220
|
+
this._handleMessage(msg);
|
|
2221
|
+
} catch {
|
|
2222
|
+
}
|
|
2223
|
+
});
|
|
2224
|
+
ws.on("close", () => {
|
|
2225
|
+
this._closed = true;
|
|
2226
|
+
});
|
|
2227
|
+
ws.on("error", (err) => {
|
|
2228
|
+
if (!this._ws) {
|
|
2229
|
+
reject(err);
|
|
2230
|
+
}
|
|
2231
|
+
this._log.error({ err }, "OpenAI Realtime WS error");
|
|
2232
|
+
});
|
|
2233
|
+
});
|
|
2234
|
+
}
|
|
2235
|
+
async feedDtmf(digits) {
|
|
2236
|
+
await this._waitForResponseDone();
|
|
2237
|
+
this._send({
|
|
2238
|
+
type: "conversation.item.create",
|
|
2239
|
+
item: {
|
|
2240
|
+
type: "message",
|
|
2241
|
+
role: "user",
|
|
2242
|
+
content: [{ type: "input_text", text: `[DTMF \uC785\uB825: ${digits}]` }]
|
|
2243
|
+
}
|
|
2244
|
+
});
|
|
2245
|
+
this._send({ type: "response.create" });
|
|
2246
|
+
}
|
|
2247
|
+
feedAudio(audio) {
|
|
2248
|
+
this._latestMediaTs = Date.now();
|
|
2249
|
+
if (this._ws && this._ws.readyState === 1 && !this._closed) {
|
|
2250
|
+
this._send({
|
|
2251
|
+
type: "input_audio_buffer.append",
|
|
2252
|
+
audio: audio.toString("base64")
|
|
2253
|
+
});
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
async stop() {
|
|
2257
|
+
this._closed = true;
|
|
2258
|
+
for (const [, controller] of this._pendingToolCalls) {
|
|
2259
|
+
controller.abort();
|
|
2260
|
+
}
|
|
2261
|
+
this._pendingToolCalls.clear();
|
|
2262
|
+
if (this._ws) {
|
|
2263
|
+
this._ws.close();
|
|
2264
|
+
this._ws = null;
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
_sendSessionUpdate() {
|
|
2268
|
+
if (!this._ws || this._ws.readyState !== 1) return;
|
|
2269
|
+
const toolSchemas = this._tools ? this._tools.toOpenAITools().map((t) => ({ type: "function", ...t.function })) : [];
|
|
2270
|
+
toolSchemas.push(...getBuiltinToolSchemas(this._builtinTools, "realtime"));
|
|
2271
|
+
this._send({
|
|
2272
|
+
type: "session.update",
|
|
2273
|
+
session: {
|
|
2274
|
+
modalities: ["text", "audio"],
|
|
2275
|
+
voice: this._voice,
|
|
2276
|
+
instructions: this._systemPrompt,
|
|
2277
|
+
input_audio_format: "g711_ulaw",
|
|
2278
|
+
output_audio_format: "g711_ulaw",
|
|
2279
|
+
input_audio_transcription: {
|
|
2280
|
+
model: "whisper-1",
|
|
2281
|
+
language: this._language
|
|
2282
|
+
},
|
|
2283
|
+
input_audio_noise_reduction: { type: "far_field" },
|
|
2284
|
+
turn_detection: this._turnDetection,
|
|
2285
|
+
tools: toolSchemas
|
|
2286
|
+
}
|
|
2287
|
+
});
|
|
2288
|
+
}
|
|
2289
|
+
_handleMessage(msg) {
|
|
2290
|
+
const type = msg["type"];
|
|
2291
|
+
switch (type) {
|
|
1971
2292
|
case "response.audio.delta": {
|
|
1972
2293
|
this._handleAudioDelta(msg);
|
|
1973
2294
|
break;
|
|
1974
2295
|
}
|
|
1975
2296
|
case "response.audio.done": {
|
|
1976
|
-
if (this.
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
Buffer.
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
2297
|
+
if (this._playback) {
|
|
2298
|
+
this._playback.generating = false;
|
|
2299
|
+
if (this._playback.audioRemainder.length > 0) {
|
|
2300
|
+
const padded = Buffer.concat([
|
|
2301
|
+
this._playback.audioRemainder,
|
|
2302
|
+
Buffer.alloc(160 - this._playback.audioRemainder.length, 255)
|
|
2303
|
+
]);
|
|
2304
|
+
if (this._call) {
|
|
2305
|
+
this._call.sendAudio(padded);
|
|
2306
|
+
}
|
|
2307
|
+
this._playback.sentChunks++;
|
|
2308
|
+
this._playback.audioRemainder = Buffer.alloc(0);
|
|
1983
2309
|
}
|
|
1984
|
-
this._sentAudioChunks++;
|
|
1985
|
-
this._audioRemainder = Buffer.alloc(0);
|
|
1986
2310
|
}
|
|
1987
2311
|
break;
|
|
1988
2312
|
}
|
|
@@ -2029,128 +2353,121 @@ var OpenAIRealtime = class {
|
|
|
2029
2353
|
}
|
|
2030
2354
|
}
|
|
2031
2355
|
_handleAudioDelta(msg) {
|
|
2032
|
-
if (this.
|
|
2033
|
-
this.
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2356
|
+
if (this._playback === null) {
|
|
2357
|
+
this._playback = {
|
|
2358
|
+
itemId: msg["item_id"] || "",
|
|
2359
|
+
startTs: this._latestMediaTs || Date.now(),
|
|
2360
|
+
sentChunks: 0,
|
|
2361
|
+
generating: true,
|
|
2362
|
+
audioRemainder: Buffer.alloc(0)
|
|
2363
|
+
};
|
|
2364
|
+
} else if (msg["item_id"]) {
|
|
2365
|
+
this._playback.itemId = msg["item_id"];
|
|
2038
2366
|
}
|
|
2367
|
+
const pb = this._playback;
|
|
2039
2368
|
const ulaw = Buffer.from(msg["delta"], "base64");
|
|
2040
2369
|
if (this._recorder) {
|
|
2041
2370
|
this._recorder.writeOutbound(ulawToPcm16(ulaw));
|
|
2042
2371
|
}
|
|
2043
|
-
const combined = Buffer.concat([
|
|
2372
|
+
const combined = Buffer.concat([pb.audioRemainder, ulaw]);
|
|
2044
2373
|
const chunkSize = 160;
|
|
2045
2374
|
const fullEnd = Math.floor(combined.length / chunkSize) * chunkSize;
|
|
2046
2375
|
for (let off = 0; off < fullEnd; off += chunkSize) {
|
|
2047
2376
|
if (this._call) {
|
|
2048
2377
|
this._call.sendAudio(combined.subarray(off, off + chunkSize));
|
|
2049
2378
|
}
|
|
2050
|
-
|
|
2379
|
+
pb.sentChunks++;
|
|
2051
2380
|
}
|
|
2052
|
-
|
|
2381
|
+
pb.audioRemainder = combined.subarray(fullEnd);
|
|
2053
2382
|
}
|
|
2054
2383
|
_handleTruncation() {
|
|
2055
|
-
|
|
2056
|
-
|
|
2384
|
+
for (const [, controller] of this._pendingToolCalls) {
|
|
2385
|
+
controller.abort();
|
|
2057
2386
|
}
|
|
2058
|
-
|
|
2059
|
-
this._send({
|
|
2060
|
-
type: "conversation.item.truncate",
|
|
2061
|
-
item_id: this._lastAssistantItem,
|
|
2062
|
-
content_index: 0,
|
|
2063
|
-
audio_end_ms: audioEndMs
|
|
2064
|
-
});
|
|
2387
|
+
this._pendingToolCalls.clear();
|
|
2065
2388
|
if (this._call) {
|
|
2066
2389
|
this._call.clearAudio();
|
|
2067
2390
|
}
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2391
|
+
const pb = this._playback;
|
|
2392
|
+
if (pb === null) {
|
|
2393
|
+
return;
|
|
2394
|
+
}
|
|
2395
|
+
const playedMs = Math.max(0, (this._latestMediaTs || Date.now()) - pb.startTs);
|
|
2396
|
+
this._log.info(
|
|
2397
|
+
"[Interrupt] item=%s played=%dms total=%dms",
|
|
2398
|
+
pb.itemId,
|
|
2399
|
+
playedMs,
|
|
2400
|
+
pb.sentChunks * 20
|
|
2401
|
+
);
|
|
2402
|
+
this._playback = null;
|
|
2072
2403
|
}
|
|
2073
2404
|
async _handleToolCall(item) {
|
|
2074
2405
|
const funcName = item["name"];
|
|
2075
2406
|
const callId = item["call_id"];
|
|
2076
2407
|
this._log.info("Tool call: %s", funcName);
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2408
|
+
const controller = new AbortController();
|
|
2409
|
+
this._pendingToolCalls.set(callId, controller);
|
|
2410
|
+
try {
|
|
2411
|
+
if (BUILTIN_TOOL_NAMES.has(funcName) && this._call) {
|
|
2412
|
+
const args = JSON.parse(item["arguments"] ?? "{}");
|
|
2413
|
+
const result2 = await executeBuiltinTool(funcName, args, this._call);
|
|
2414
|
+
if (result2 !== null) {
|
|
2415
|
+
if (funcName === "hang_up") return;
|
|
2416
|
+
if (controller.signal.aborted) return;
|
|
2417
|
+
await this._waitForResponseDone();
|
|
2418
|
+
this._send({
|
|
2419
|
+
type: "conversation.item.create",
|
|
2420
|
+
item: {
|
|
2421
|
+
type: "function_call_output",
|
|
2422
|
+
call_id: callId,
|
|
2423
|
+
output: result2
|
|
2424
|
+
}
|
|
2092
2425
|
});
|
|
2093
|
-
|
|
2094
|
-
|
|
2426
|
+
this._send({ type: "response.create" });
|
|
2427
|
+
return;
|
|
2095
2428
|
}
|
|
2429
|
+
}
|
|
2430
|
+
if (!this._tools || !this._tools.has(funcName)) {
|
|
2431
|
+
this._log.error("Unknown tool: %s", funcName);
|
|
2096
2432
|
await this._waitForResponseDone();
|
|
2097
2433
|
this._send({
|
|
2098
2434
|
type: "conversation.item.create",
|
|
2099
2435
|
item: {
|
|
2100
2436
|
type: "function_call_output",
|
|
2101
2437
|
call_id: callId,
|
|
2102
|
-
output:
|
|
2438
|
+
output: JSON.stringify({ error: `Unknown tool: ${funcName}` })
|
|
2103
2439
|
}
|
|
2104
2440
|
});
|
|
2105
2441
|
this._send({ type: "response.create" });
|
|
2442
|
+
return;
|
|
2106
2443
|
}
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
await this._call.sendDtmfSequence(args["digits"] ?? "");
|
|
2115
|
-
result2 = "sent";
|
|
2116
|
-
} catch (err) {
|
|
2117
|
-
result2 = `Error: ${err}`;
|
|
2118
|
-
}
|
|
2119
|
-
await this._waitForResponseDone();
|
|
2120
|
-
this._send({
|
|
2121
|
-
type: "conversation.item.create",
|
|
2122
|
-
item: {
|
|
2123
|
-
type: "function_call_output",
|
|
2124
|
-
call_id: callId,
|
|
2125
|
-
output: result2
|
|
2126
|
-
}
|
|
2127
|
-
});
|
|
2128
|
-
this._send({ type: "response.create" });
|
|
2444
|
+
let result;
|
|
2445
|
+
try {
|
|
2446
|
+
const args = JSON.parse(item["arguments"] ?? "{}");
|
|
2447
|
+
result = await this._tools.call(funcName, args);
|
|
2448
|
+
} catch (err) {
|
|
2449
|
+
this._log.error({ err }, "Tool call failed: %s", funcName);
|
|
2450
|
+
result = `Error: ${err}`;
|
|
2129
2451
|
}
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
this._log.error("Unknown tool: %s", funcName);
|
|
2134
|
-
return;
|
|
2135
|
-
}
|
|
2136
|
-
let result;
|
|
2137
|
-
try {
|
|
2138
|
-
const args = JSON.parse(item["arguments"] ?? "{}");
|
|
2139
|
-
result = await this._tools.call(funcName, args);
|
|
2140
|
-
} catch (err) {
|
|
2141
|
-
this._log.error({ err }, "Tool call failed: %s", funcName);
|
|
2142
|
-
result = `Error: ${err}`;
|
|
2143
|
-
}
|
|
2144
|
-
await this._waitForResponseDone();
|
|
2145
|
-
this._send({
|
|
2146
|
-
type: "conversation.item.create",
|
|
2147
|
-
item: {
|
|
2148
|
-
type: "function_call_output",
|
|
2149
|
-
call_id: callId,
|
|
2150
|
-
output: typeof result === "string" ? result : JSON.stringify(result)
|
|
2452
|
+
if (controller.signal.aborted) {
|
|
2453
|
+
this._log.info("Tool call cancelled (user interrupted): %s", funcName);
|
|
2454
|
+
return;
|
|
2151
2455
|
}
|
|
2152
|
-
|
|
2153
|
-
|
|
2456
|
+
const resultStr = typeof result === "string" ? result : JSON.stringify(result);
|
|
2457
|
+
await this._waitForResponseDone();
|
|
2458
|
+
this._send({
|
|
2459
|
+
type: "conversation.item.create",
|
|
2460
|
+
item: {
|
|
2461
|
+
type: "function_call_output",
|
|
2462
|
+
call_id: callId,
|
|
2463
|
+
output: resultStr
|
|
2464
|
+
}
|
|
2465
|
+
});
|
|
2466
|
+
this._log.info("[ToolResult] %s call_id=%s len=%d", funcName, callId, resultStr.length);
|
|
2467
|
+
this._send({ type: "response.create" });
|
|
2468
|
+
} finally {
|
|
2469
|
+
this._pendingToolCalls.delete(callId);
|
|
2470
|
+
}
|
|
2154
2471
|
}
|
|
2155
2472
|
_waitForResponseDone() {
|
|
2156
2473
|
if (!this._responseInProgress) return Promise.resolve();
|
|
@@ -2165,39 +2482,7 @@ var OpenAIRealtime = class {
|
|
|
2165
2482
|
}
|
|
2166
2483
|
};
|
|
2167
2484
|
|
|
2168
|
-
// src/agent/pipeline/gemini-realtime.ts
|
|
2169
|
-
var HANG_UP_TOOL2 = {
|
|
2170
|
-
name: "hang_up",
|
|
2171
|
-
description: "End the phone call. Use when the conversation is finished or the caller says goodbye.",
|
|
2172
|
-
parameters: { type: "object", properties: {} }
|
|
2173
|
-
};
|
|
2174
|
-
var COLLECT_DTMF_TOOL2 = {
|
|
2175
|
-
name: "collect_dtmf",
|
|
2176
|
-
description: "\uC0AC\uC6A9\uC790\uB85C\uBD80\uD130 DTMF(\uC804\uD654 \uD0A4\uD328\uB4DC) \uC785\uB825\uC744 \uC218\uC9D1\uD569\uB2C8\uB2E4. \uBC18\uB4DC\uC2DC \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBB34\uC5C7\uC744 \uC785\uB825\uD574\uC57C \uD558\uB294\uC9C0 \uC548\uB0B4\uD55C \uD6C4 \uD638\uCD9C\uD558\uC138\uC694.",
|
|
2177
|
-
parameters: {
|
|
2178
|
-
type: "object",
|
|
2179
|
-
properties: {
|
|
2180
|
-
max_digits: { type: "integer", description: "\uC218\uC9D1\uD560 \uCD5C\uB300 \uC790\uB9BF\uC218" },
|
|
2181
|
-
finish_on_key: { type: "string", description: "\uC785\uB825 \uC885\uB8CC \uD0A4 (\uAE30\uBCF8: #)" },
|
|
2182
|
-
timeout: { type: "integer", description: "\uC785\uB825 \uB300\uAE30 \uC2DC\uAC04(\uCD08, \uAE30\uBCF8: 5)" }
|
|
2183
|
-
},
|
|
2184
|
-
required: ["max_digits"]
|
|
2185
|
-
}
|
|
2186
|
-
};
|
|
2187
|
-
var SEND_DTMF_TOOL2 = {
|
|
2188
|
-
name: "send_dtmf",
|
|
2189
|
-
description: "DTMF \uC2E0\uD638\uB97C \uC804\uC1A1\uD569\uB2C8\uB2E4. ARS \uBA54\uB274 \uD0D0\uC0C9\uC774\uB098 \uB0B4\uC120\uBC88\uD638 \uC785\uB825 \uC2DC \uC0AC\uC6A9\uD569\uB2C8\uB2E4.",
|
|
2190
|
-
parameters: {
|
|
2191
|
-
type: "object",
|
|
2192
|
-
properties: {
|
|
2193
|
-
digits: {
|
|
2194
|
-
type: "string",
|
|
2195
|
-
description: "\uC804\uC1A1\uD560 \uBC88\uD638 (0-9, *, #). 'w'\uB294 500ms \uB300\uAE30, 'W'\uB294 1000ms \uB300\uAE30."
|
|
2196
|
-
}
|
|
2197
|
-
},
|
|
2198
|
-
required: ["digits"]
|
|
2199
|
-
}
|
|
2200
|
-
};
|
|
2485
|
+
// src/agent/pipeline/realtime/gemini-realtime.ts
|
|
2201
2486
|
function resolveRef(ref, defs) {
|
|
2202
2487
|
const parts = ref.replace(/^#\//, "").split("/");
|
|
2203
2488
|
let result = defs;
|
|
@@ -2407,9 +2692,7 @@ var GeminiRealtime = class {
|
|
|
2407
2692
|
t.function.parameters ?? { type: "object", properties: {} }
|
|
2408
2693
|
)
|
|
2409
2694
|
})) : [];
|
|
2410
|
-
|
|
2411
|
-
if (!this._builtinTools || this._builtinTools.has("collect_dtmf" /* COLLECT_DTMF */)) toolDefs.push(COLLECT_DTMF_TOOL2);
|
|
2412
|
-
if (!this._builtinTools || this._builtinTools.has("send_dtmf" /* SEND_DTMF */)) toolDefs.push(SEND_DTMF_TOOL2);
|
|
2695
|
+
toolDefs.push(...getBuiltinToolSchemas(this._builtinTools, "gemini"));
|
|
2413
2696
|
return toolDefs;
|
|
2414
2697
|
}
|
|
2415
2698
|
_handleMessage(msg) {
|
|
@@ -2497,51 +2780,17 @@ var GeminiRealtime = class {
|
|
|
2497
2780
|
const fcId = fc.id ?? "";
|
|
2498
2781
|
const args = fc.args ?? {};
|
|
2499
2782
|
this._log.info({ tool: name, args }, "Tool call: %s", name);
|
|
2500
|
-
if (name
|
|
2501
|
-
|
|
2502
|
-
if (
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
}
|
|
2507
|
-
if (name === "collect_dtmf") {
|
|
2508
|
-
if (this._call) {
|
|
2509
|
-
let result;
|
|
2510
|
-
try {
|
|
2511
|
-
this._log.info({ maxDigits: args["max_digits"] ?? 4, timeout: args["timeout"] ?? 5 }, "collect_dtmf: waiting for digits");
|
|
2512
|
-
result = await this._call.collectDtmf({
|
|
2513
|
-
maxDigits: args["max_digits"] ?? 4,
|
|
2514
|
-
finishOnKey: args["finish_on_key"] ?? "#",
|
|
2515
|
-
timeout: args["timeout"] ?? 5
|
|
2516
|
-
});
|
|
2517
|
-
this._log.info("DTMF collected: %s", result || "(empty)");
|
|
2518
|
-
} catch (err) {
|
|
2519
|
-
this._log.error({ err }, "collect_dtmf error");
|
|
2520
|
-
result = `Error: ${err}`;
|
|
2521
|
-
}
|
|
2522
|
-
responses.push({
|
|
2523
|
-
id: fcId,
|
|
2524
|
-
name,
|
|
2525
|
-
response: { result: result || "(\uD0C0\uC784\uC544\uC6C3 - \uC785\uB825 \uC5C6\uC74C)" }
|
|
2526
|
-
});
|
|
2527
|
-
}
|
|
2528
|
-
continue;
|
|
2529
|
-
}
|
|
2530
|
-
if (name === "send_dtmf") {
|
|
2531
|
-
if (this._call) {
|
|
2532
|
-
let result;
|
|
2533
|
-
try {
|
|
2534
|
-
this._log.info('send_dtmf: digits="%s"', args["digits"] ?? "");
|
|
2535
|
-
await this._call.sendDtmfSequence(args["digits"] ?? "");
|
|
2536
|
-
result = "sent";
|
|
2537
|
-
this._log.info("send_dtmf: sent");
|
|
2538
|
-
} catch (err) {
|
|
2539
|
-
this._log.error({ err }, "send_dtmf error");
|
|
2540
|
-
result = `Error: ${err}`;
|
|
2783
|
+
if (BUILTIN_TOOL_NAMES.has(name) && this._call) {
|
|
2784
|
+
const result = await executeBuiltinTool(name, args, this._call);
|
|
2785
|
+
if (result !== null) {
|
|
2786
|
+
if (name === "hang_up") {
|
|
2787
|
+
this._log.info("hang_up: ending call");
|
|
2788
|
+
return;
|
|
2541
2789
|
}
|
|
2790
|
+
this._log.info("Builtin tool result: %s -> %s", name, result);
|
|
2542
2791
|
responses.push({ id: fcId, name, response: { result } });
|
|
2792
|
+
continue;
|
|
2543
2793
|
}
|
|
2544
|
-
continue;
|
|
2545
2794
|
}
|
|
2546
2795
|
if (!this._tools || !this._tools.has(name)) {
|
|
2547
2796
|
this._log.error("Unknown tool: %s", name);
|
|
@@ -2576,306 +2825,7 @@ var GeminiRealtime = class {
|
|
|
2576
2825
|
}
|
|
2577
2826
|
};
|
|
2578
2827
|
|
|
2579
|
-
// src/agent/pipeline/
|
|
2580
|
-
var COLLECT_DTMF_TOOL3 = {
|
|
2581
|
-
function: {
|
|
2582
|
-
description: "\uC0AC\uC6A9\uC790\uB85C\uBD80\uD130 DTMF(\uC804\uD654 \uD0A4\uD328\uB4DC) \uC785\uB825\uC744 \uC218\uC9D1\uD569\uB2C8\uB2E4.",
|
|
2583
|
-
parameters: {
|
|
2584
|
-
properties: {
|
|
2585
|
-
max_digits: { type: "integer", description: "\uC218\uC9D1\uD560 \uCD5C\uB300 \uC790\uB9BF\uC218" },
|
|
2586
|
-
finish_on_key: { type: "string", description: "\uC785\uB825 \uC885\uB8CC \uD0A4 (\uAE30\uBCF8: #)" },
|
|
2587
|
-
timeout: { type: "integer", description: "\uC785\uB825 \uB300\uAE30 \uC2DC\uAC04(\uCD08, \uAE30\uBCF8: 5)" }
|
|
2588
|
-
},
|
|
2589
|
-
required: ["max_digits"]
|
|
2590
|
-
}
|
|
2591
|
-
}
|
|
2592
|
-
};
|
|
2593
|
-
var SEND_DTMF_TOOL3 = {
|
|
2594
|
-
function: {
|
|
2595
|
-
description: "DTMF \uC2E0\uD638\uB97C \uC804\uC1A1\uD569\uB2C8\uB2E4. ARS \uBA54\uB274 \uD0D0\uC0C9\uC774\uB098 \uB0B4\uC120\uBC88\uD638 \uC785\uB825 \uC2DC \uC0AC\uC6A9\uD569\uB2C8\uB2E4.",
|
|
2596
|
-
parameters: {
|
|
2597
|
-
properties: {
|
|
2598
|
-
digits: { type: "string", description: "\uC804\uC1A1\uD560 \uBC88\uD638 (0-9, *, #). 'w'\uB294 500ms \uB300\uAE30, 'W'\uB294 1000ms \uB300\uAE30." }
|
|
2599
|
-
},
|
|
2600
|
-
required: ["digits"]
|
|
2601
|
-
}
|
|
2602
|
-
}
|
|
2603
|
-
};
|
|
2604
|
-
var PipelineSession = class {
|
|
2605
|
-
_stt;
|
|
2606
|
-
_llm;
|
|
2607
|
-
_tts;
|
|
2608
|
-
_systemPrompt;
|
|
2609
|
-
_greeting;
|
|
2610
|
-
_language;
|
|
2611
|
-
_temperature;
|
|
2612
|
-
_maxTokens;
|
|
2613
|
-
_sampleRate;
|
|
2614
|
-
_interruptOnSpeech;
|
|
2615
|
-
_callSession = null;
|
|
2616
|
-
_tools = null;
|
|
2617
|
-
_recorder = null;
|
|
2618
|
-
_conversation = [];
|
|
2619
|
-
_audioBuffer = [];
|
|
2620
|
-
_running = false;
|
|
2621
|
-
_speaking = false;
|
|
2622
|
-
_builtinTools = null;
|
|
2623
|
-
_log = NOOP_LOGGER;
|
|
2624
|
-
constructor(options) {
|
|
2625
|
-
this._stt = options.stt;
|
|
2626
|
-
this._llm = options.llm;
|
|
2627
|
-
this._tts = options.tts;
|
|
2628
|
-
this._systemPrompt = options.systemPrompt;
|
|
2629
|
-
this._greeting = options.greeting ?? true;
|
|
2630
|
-
this._language = options.language ?? "ko";
|
|
2631
|
-
this._temperature = options.temperature;
|
|
2632
|
-
this._maxTokens = options.maxTokens;
|
|
2633
|
-
this._sampleRate = options.sampleRate ?? 8e3;
|
|
2634
|
-
this._interruptOnSpeech = options.interruptOnSpeech ?? true;
|
|
2635
|
-
if (options.toolRegistry) this._tools = options.toolRegistry;
|
|
2636
|
-
if (options.recorder) this._recorder = options.recorder;
|
|
2637
|
-
}
|
|
2638
|
-
setToolRegistry(registry) {
|
|
2639
|
-
this._tools = registry;
|
|
2640
|
-
}
|
|
2641
|
-
setRecorder(recorder) {
|
|
2642
|
-
this._recorder = recorder;
|
|
2643
|
-
}
|
|
2644
|
-
setBuiltinTools(tools) {
|
|
2645
|
-
this._builtinTools = tools;
|
|
2646
|
-
}
|
|
2647
|
-
setLogger(logger) {
|
|
2648
|
-
this._log = logger;
|
|
2649
|
-
if ("setLogger" in this._stt && typeof this._stt.setLogger === "function") {
|
|
2650
|
-
this._stt.setLogger(logger);
|
|
2651
|
-
}
|
|
2652
|
-
if ("setLogger" in this._tts && typeof this._tts.setLogger === "function") {
|
|
2653
|
-
this._tts.setLogger(logger);
|
|
2654
|
-
}
|
|
2655
|
-
}
|
|
2656
|
-
async start(callSession, tools) {
|
|
2657
|
-
this._callSession = callSession;
|
|
2658
|
-
this._tools = tools ?? null;
|
|
2659
|
-
this._running = true;
|
|
2660
|
-
this._log.info("PipelineSession started");
|
|
2661
|
-
this._conversation = [];
|
|
2662
|
-
if (this._systemPrompt) {
|
|
2663
|
-
this._conversation.push({
|
|
2664
|
-
role: "system",
|
|
2665
|
-
content: this._systemPrompt
|
|
2666
|
-
});
|
|
2667
|
-
}
|
|
2668
|
-
if (this._greeting) {
|
|
2669
|
-
this._generateGreeting().catch((err) => {
|
|
2670
|
-
this._log.error({ err }, "Greeting error");
|
|
2671
|
-
});
|
|
2672
|
-
}
|
|
2673
|
-
this._runSttLoop().catch((err) => {
|
|
2674
|
-
this._log.error({ err }, "STT loop error");
|
|
2675
|
-
});
|
|
2676
|
-
}
|
|
2677
|
-
feedAudio(audio) {
|
|
2678
|
-
if (this._running) {
|
|
2679
|
-
this._audioBuffer.push(audio);
|
|
2680
|
-
}
|
|
2681
|
-
}
|
|
2682
|
-
async feedDtmf(digits) {
|
|
2683
|
-
this._conversation.push({
|
|
2684
|
-
role: "user",
|
|
2685
|
-
content: `[DTMF \uC785\uB825: ${digits}]`
|
|
2686
|
-
});
|
|
2687
|
-
await this._respond();
|
|
2688
|
-
}
|
|
2689
|
-
async stop() {
|
|
2690
|
-
this._running = false;
|
|
2691
|
-
this._log.info("PipelineSession stopped");
|
|
2692
|
-
this._audioBuffer = [];
|
|
2693
|
-
}
|
|
2694
|
-
async _runSttLoop() {
|
|
2695
|
-
const audioStream = this._createAudioStream();
|
|
2696
|
-
for await (const event of this._stt.transcribe(audioStream, {
|
|
2697
|
-
sampleRate: this._sampleRate
|
|
2698
|
-
})) {
|
|
2699
|
-
if (!this._running) break;
|
|
2700
|
-
if (event.type === "interim" && this._speaking && this._interruptOnSpeech) {
|
|
2701
|
-
this._speaking = false;
|
|
2702
|
-
if (this._callSession) {
|
|
2703
|
-
this._callSession.clearAudio();
|
|
2704
|
-
}
|
|
2705
|
-
this._log.info('Barge-in: "%s"', event.transcript.substring(0, 30));
|
|
2706
|
-
}
|
|
2707
|
-
if (event.type === "final" && event.transcript.trim()) {
|
|
2708
|
-
this._log.info("STT: %s", event.transcript);
|
|
2709
|
-
await this._handleUserSpeech(event.transcript);
|
|
2710
|
-
}
|
|
2711
|
-
}
|
|
2712
|
-
}
|
|
2713
|
-
async *_createAudioStream() {
|
|
2714
|
-
while (this._running) {
|
|
2715
|
-
if (this._audioBuffer.length > 0) {
|
|
2716
|
-
const ulaw = this._audioBuffer.shift();
|
|
2717
|
-
const pcm8k = ulawToPcm16(ulaw);
|
|
2718
|
-
const pcm16k = resamplePcm16(pcm8k, 8e3, 16e3);
|
|
2719
|
-
yield pcm16k;
|
|
2720
|
-
} else {
|
|
2721
|
-
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
2722
|
-
}
|
|
2723
|
-
}
|
|
2724
|
-
}
|
|
2725
|
-
async _generateGreeting() {
|
|
2726
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
2727
|
-
await this._respond();
|
|
2728
|
-
}
|
|
2729
|
-
async _handleUserSpeech(transcript) {
|
|
2730
|
-
this._conversation.push({ role: "user", content: transcript });
|
|
2731
|
-
await this._respond();
|
|
2732
|
-
}
|
|
2733
|
-
_buildEffectiveTools() {
|
|
2734
|
-
const includeCollectDtmf = !this._builtinTools || this._builtinTools.has("collect_dtmf" /* COLLECT_DTMF */);
|
|
2735
|
-
const includeSendDtmf = !this._builtinTools || this._builtinTools.has("send_dtmf" /* SEND_DTMF */);
|
|
2736
|
-
if (!includeCollectDtmf && !includeSendDtmf) return this._tools ?? void 0;
|
|
2737
|
-
const base = this._tools ? this._tools.fork() : new ToolRegistry();
|
|
2738
|
-
if (includeCollectDtmf) {
|
|
2739
|
-
base.register({
|
|
2740
|
-
name: "collect_dtmf",
|
|
2741
|
-
description: COLLECT_DTMF_TOOL3.function.description,
|
|
2742
|
-
parameters: COLLECT_DTMF_TOOL3.function.parameters.properties,
|
|
2743
|
-
required: COLLECT_DTMF_TOOL3.function.parameters.required,
|
|
2744
|
-
handler: async () => ""
|
|
2745
|
-
});
|
|
2746
|
-
}
|
|
2747
|
-
if (includeSendDtmf) {
|
|
2748
|
-
base.register({
|
|
2749
|
-
name: "send_dtmf",
|
|
2750
|
-
description: SEND_DTMF_TOOL3.function.description,
|
|
2751
|
-
parameters: SEND_DTMF_TOOL3.function.parameters.properties,
|
|
2752
|
-
required: SEND_DTMF_TOOL3.function.parameters.required,
|
|
2753
|
-
handler: async () => ""
|
|
2754
|
-
});
|
|
2755
|
-
}
|
|
2756
|
-
return base;
|
|
2757
|
-
}
|
|
2758
|
-
async _respond() {
|
|
2759
|
-
let fullResponse = "";
|
|
2760
|
-
const textChunks = [];
|
|
2761
|
-
const effectiveTools = this._buildEffectiveTools();
|
|
2762
|
-
const llmStream = this._llm.generate(this._conversation, {
|
|
2763
|
-
tools: effectiveTools,
|
|
2764
|
-
temperature: this._temperature,
|
|
2765
|
-
maxTokens: this._maxTokens
|
|
2766
|
-
});
|
|
2767
|
-
for await (const chunk of llmStream) {
|
|
2768
|
-
if (!this._running) break;
|
|
2769
|
-
if (chunk.type === "text" && chunk.text) {
|
|
2770
|
-
textChunks.push(chunk.text);
|
|
2771
|
-
fullResponse += chunk.text;
|
|
2772
|
-
} else if (chunk.type === "tool_call" && chunk.toolCall) {
|
|
2773
|
-
await this._handleToolCall(chunk);
|
|
2774
|
-
}
|
|
2775
|
-
}
|
|
2776
|
-
if (fullResponse.trim()) {
|
|
2777
|
-
this._log.info("Assistant: %s", fullResponse.substring(0, 100));
|
|
2778
|
-
this._conversation.push({ role: "assistant", content: fullResponse });
|
|
2779
|
-
await this._synthesizeAndSend(fullResponse);
|
|
2780
|
-
}
|
|
2781
|
-
}
|
|
2782
|
-
async _handleToolCall(chunk) {
|
|
2783
|
-
if (!chunk.toolCall) return;
|
|
2784
|
-
const { id, name, arguments: argsStr } = chunk.toolCall;
|
|
2785
|
-
try {
|
|
2786
|
-
const args = JSON.parse(argsStr);
|
|
2787
|
-
if (name === "collect_dtmf" && this._callSession) {
|
|
2788
|
-
let result2;
|
|
2789
|
-
try {
|
|
2790
|
-
result2 = await this._callSession.collectDtmf({
|
|
2791
|
-
maxDigits: args["max_digits"] ?? 4,
|
|
2792
|
-
finishOnKey: args["finish_on_key"] ?? "#",
|
|
2793
|
-
timeout: args["timeout"] ?? 5
|
|
2794
|
-
});
|
|
2795
|
-
} catch (err) {
|
|
2796
|
-
result2 = `Error: ${err}`;
|
|
2797
|
-
}
|
|
2798
|
-
this._conversation.push({ role: "tool", content: result2 || "(\uD0C0\uC784\uC544\uC6C3 - \uC785\uB825 \uC5C6\uC74C)", tool_call_id: id, name });
|
|
2799
|
-
await this._respond();
|
|
2800
|
-
return;
|
|
2801
|
-
}
|
|
2802
|
-
if (name === "send_dtmf" && this._callSession) {
|
|
2803
|
-
let result2;
|
|
2804
|
-
try {
|
|
2805
|
-
await this._callSession.sendDtmfSequence(args["digits"] ?? "");
|
|
2806
|
-
result2 = "sent";
|
|
2807
|
-
} catch (err) {
|
|
2808
|
-
result2 = `Error: ${err}`;
|
|
2809
|
-
}
|
|
2810
|
-
this._conversation.push({ role: "tool", content: result2, tool_call_id: id, name });
|
|
2811
|
-
await this._respond();
|
|
2812
|
-
return;
|
|
2813
|
-
}
|
|
2814
|
-
if (!this._tools) return;
|
|
2815
|
-
const result = await this._tools.call(name, args);
|
|
2816
|
-
this._conversation.push({
|
|
2817
|
-
role: "assistant",
|
|
2818
|
-
content: ""
|
|
2819
|
-
// Tool call info stored in the message flow
|
|
2820
|
-
});
|
|
2821
|
-
this._conversation.push({
|
|
2822
|
-
role: "tool",
|
|
2823
|
-
content: typeof result === "string" ? result : JSON.stringify(result),
|
|
2824
|
-
tool_call_id: id,
|
|
2825
|
-
name
|
|
2826
|
-
});
|
|
2827
|
-
const effectiveTools = this._buildEffectiveTools();
|
|
2828
|
-
let followUpText = "";
|
|
2829
|
-
const followUpStream = this._llm.generate(this._conversation, {
|
|
2830
|
-
tools: effectiveTools,
|
|
2831
|
-
temperature: this._temperature,
|
|
2832
|
-
maxTokens: this._maxTokens
|
|
2833
|
-
});
|
|
2834
|
-
for await (const followChunk of followUpStream) {
|
|
2835
|
-
if (!this._running) break;
|
|
2836
|
-
if (followChunk.type === "text" && followChunk.text) {
|
|
2837
|
-
followUpText += followChunk.text;
|
|
2838
|
-
}
|
|
2839
|
-
}
|
|
2840
|
-
if (followUpText.trim()) {
|
|
2841
|
-
this._conversation.push({ role: "assistant", content: followUpText });
|
|
2842
|
-
await this._synthesizeAndSend(followUpText);
|
|
2843
|
-
}
|
|
2844
|
-
} catch (err) {
|
|
2845
|
-
this._log.error({ err }, "Tool call failed: %s", name);
|
|
2846
|
-
}
|
|
2847
|
-
}
|
|
2848
|
-
async _synthesizeAndSend(text) {
|
|
2849
|
-
if (!this._callSession || !this._running) return;
|
|
2850
|
-
this._speaking = true;
|
|
2851
|
-
try {
|
|
2852
|
-
for await (const audioChunk of this._tts.synthesize(text, {
|
|
2853
|
-
sampleRate: this._sampleRate
|
|
2854
|
-
})) {
|
|
2855
|
-
if (!this._running || !this._speaking) break;
|
|
2856
|
-
if (this._recorder) {
|
|
2857
|
-
const pcm8k2 = this._sampleRate !== 8e3 ? resamplePcm16(audioChunk, this._sampleRate, 8e3) : audioChunk;
|
|
2858
|
-
this._recorder.writeOutbound(pcm8k2);
|
|
2859
|
-
}
|
|
2860
|
-
const pcm8k = resamplePcm16(audioChunk, this._sampleRate, 8e3);
|
|
2861
|
-
const ulaw = pcm16ToUlaw(pcm8k);
|
|
2862
|
-
for (let off = 0; off < ulaw.length; off += 160) {
|
|
2863
|
-
let chunk = ulaw.subarray(off, off + 160);
|
|
2864
|
-
if (chunk.length < 160) {
|
|
2865
|
-
chunk = Buffer.concat([chunk, Buffer.alloc(160 - chunk.length, 255)]);
|
|
2866
|
-
}
|
|
2867
|
-
this._callSession.sendAudio(chunk);
|
|
2868
|
-
}
|
|
2869
|
-
}
|
|
2870
|
-
} catch (err) {
|
|
2871
|
-
this._log.error({ err }, "TTS error");
|
|
2872
|
-
} finally {
|
|
2873
|
-
this._speaking = false;
|
|
2874
|
-
}
|
|
2875
|
-
}
|
|
2876
|
-
};
|
|
2877
|
-
|
|
2878
|
-
// src/agent/pipeline/deepgram-stt.ts
|
|
2828
|
+
// src/agent/pipeline/stt/deepgram-stt.ts
|
|
2879
2829
|
var DeepgramSTT = class {
|
|
2880
2830
|
_options;
|
|
2881
2831
|
_log = NOOP_LOGGER;
|
|
@@ -2996,7 +2946,7 @@ var DeepgramSTT = class {
|
|
|
2996
2946
|
}
|
|
2997
2947
|
};
|
|
2998
2948
|
|
|
2999
|
-
// src/agent/pipeline/elevenlabs-tts.ts
|
|
2949
|
+
// src/agent/pipeline/tts/elevenlabs-tts.ts
|
|
3000
2950
|
var ElevenLabsTTS = class {
|
|
3001
2951
|
_options;
|
|
3002
2952
|
_log = NOOP_LOGGER;
|
|
@@ -3149,7 +3099,7 @@ var ElevenLabsTTS = class {
|
|
|
3149
3099
|
}
|
|
3150
3100
|
};
|
|
3151
3101
|
|
|
3152
|
-
// src/agent/pipeline/openai-llm.ts
|
|
3102
|
+
// src/agent/pipeline/llm/openai-llm.ts
|
|
3153
3103
|
var OpenAILLM = class {
|
|
3154
3104
|
_options;
|
|
3155
3105
|
constructor(options = {}) {
|
|
@@ -3235,7 +3185,7 @@ var OpenAILLM = class {
|
|
|
3235
3185
|
}
|
|
3236
3186
|
};
|
|
3237
3187
|
|
|
3238
|
-
// src/agent/pipeline/anthropic-llm.ts
|
|
3188
|
+
// src/agent/pipeline/llm/anthropic-llm.ts
|
|
3239
3189
|
var AnthropicLLM = class {
|
|
3240
3190
|
_options;
|
|
3241
3191
|
constructor(options = {}) {
|
|
@@ -3340,7 +3290,7 @@ var AnthropicLLM = class {
|
|
|
3340
3290
|
}
|
|
3341
3291
|
};
|
|
3342
3292
|
|
|
3343
|
-
// src/agent/pipeline/gemini-llm.ts
|
|
3293
|
+
// src/agent/pipeline/llm/gemini-llm.ts
|
|
3344
3294
|
var GeminiLLM = class {
|
|
3345
3295
|
_options;
|
|
3346
3296
|
constructor(options = {}) {
|
|
@@ -3424,7 +3374,7 @@ var GeminiLLM = class {
|
|
|
3424
3374
|
}
|
|
3425
3375
|
};
|
|
3426
3376
|
|
|
3427
|
-
// src/agent/pipeline/openai-compat-llm.ts
|
|
3377
|
+
// src/agent/pipeline/llm/openai-compat-llm.ts
|
|
3428
3378
|
var OpenAICompatLLM = class {
|
|
3429
3379
|
_options;
|
|
3430
3380
|
constructor(options) {
|
|
@@ -3507,7 +3457,7 @@ var OpenAICompatLLM = class {
|
|
|
3507
3457
|
}
|
|
3508
3458
|
};
|
|
3509
3459
|
|
|
3510
|
-
// src/agent/pipeline/ollama-llm.ts
|
|
3460
|
+
// src/agent/pipeline/llm/ollama-llm.ts
|
|
3511
3461
|
var OllamaLLM = class {
|
|
3512
3462
|
_inner;
|
|
3513
3463
|
constructor(options = {}) {
|
|
@@ -3525,7 +3475,7 @@ var OllamaLLM = class {
|
|
|
3525
3475
|
}
|
|
3526
3476
|
};
|
|
3527
3477
|
|
|
3528
|
-
// src/agent/pipeline/mistral-llm.ts
|
|
3478
|
+
// src/agent/pipeline/llm/mistral-llm.ts
|
|
3529
3479
|
var MistralLLM = class {
|
|
3530
3480
|
_inner;
|
|
3531
3481
|
constructor(options = {}) {
|
|
@@ -3542,7 +3492,7 @@ var MistralLLM = class {
|
|
|
3542
3492
|
}
|
|
3543
3493
|
};
|
|
3544
3494
|
|
|
3545
|
-
// src/agent/pipeline/groq-llm.ts
|
|
3495
|
+
// src/agent/pipeline/llm/groq-llm.ts
|
|
3546
3496
|
var GroqLLM = class {
|
|
3547
3497
|
_inner;
|
|
3548
3498
|
constructor(options = {}) {
|
|
@@ -3559,7 +3509,7 @@ var GroqLLM = class {
|
|
|
3559
3509
|
}
|
|
3560
3510
|
};
|
|
3561
3511
|
|
|
3562
|
-
// src/agent/pipeline/perplexity-llm.ts
|
|
3512
|
+
// src/agent/pipeline/llm/perplexity-llm.ts
|
|
3563
3513
|
var PerplexityLLM = class {
|
|
3564
3514
|
_inner;
|
|
3565
3515
|
constructor(options = {}) {
|
|
@@ -3576,7 +3526,7 @@ var PerplexityLLM = class {
|
|
|
3576
3526
|
}
|
|
3577
3527
|
};
|
|
3578
3528
|
|
|
3579
|
-
// src/agent/pipeline/together-llm.ts
|
|
3529
|
+
// src/agent/pipeline/llm/together-llm.ts
|
|
3580
3530
|
var TogetherLLM = class {
|
|
3581
3531
|
_inner;
|
|
3582
3532
|
constructor(options = {}) {
|
|
@@ -3593,7 +3543,7 @@ var TogetherLLM = class {
|
|
|
3593
3543
|
}
|
|
3594
3544
|
};
|
|
3595
3545
|
|
|
3596
|
-
// src/agent/pipeline/fireworks-llm.ts
|
|
3546
|
+
// src/agent/pipeline/llm/fireworks-llm.ts
|
|
3597
3547
|
var FireworksLLM = class {
|
|
3598
3548
|
_inner;
|
|
3599
3549
|
constructor(options = {}) {
|
|
@@ -3610,7 +3560,7 @@ var FireworksLLM = class {
|
|
|
3610
3560
|
}
|
|
3611
3561
|
};
|
|
3612
3562
|
|
|
3613
|
-
// src/agent/pipeline/deepseek-llm.ts
|
|
3563
|
+
// src/agent/pipeline/llm/deepseek-llm.ts
|
|
3614
3564
|
var DeepSeekLLM = class {
|
|
3615
3565
|
_inner;
|
|
3616
3566
|
constructor(options = {}) {
|
|
@@ -3627,7 +3577,7 @@ var DeepSeekLLM = class {
|
|
|
3627
3577
|
}
|
|
3628
3578
|
};
|
|
3629
3579
|
|
|
3630
|
-
// src/agent/pipeline/xai-llm.ts
|
|
3580
|
+
// src/agent/pipeline/llm/xai-llm.ts
|
|
3631
3581
|
var XaiLLM = class {
|
|
3632
3582
|
_inner;
|
|
3633
3583
|
constructor(options = {}) {
|
|
@@ -3663,6 +3613,6 @@ function mcpServerHTTP(options) {
|
|
|
3663
3613
|
};
|
|
3664
3614
|
}
|
|
3665
3615
|
|
|
3666
|
-
export { AnthropicLLM, AudioRecorder, BuiltinTool, CallSession, ClawOpsAgent, DECODE_TABLE, DeepSeekLLM, DeepgramSTT, ElevenLabsTTS, FireworksLLM, GeminiLLM, GeminiRealtime, GroqLLM, MCPClient, MistralLLM, OllamaLLM, OpenAICompatLLM, OpenAILLM, OpenAIRealtime, PerplexityLLM, PipelineSession, TogetherLLM, ToolRegistry, XaiLLM, createAgentLogger, createPipelineLogger, functionTool, getTracingConfig, mcpServerHTTP, mcpServerStdio, pcm16ToUlaw, resamplePcm16, resetTracingConfig, setTracingConfig, ulawToPcm16, zodToToolParams };
|
|
3616
|
+
export { AnthropicLLM, AudioRecorder, BUILTIN_TOOL_NAMES, BuiltinTool, CallSession, ClawOpsAgent, DECODE_TABLE, DeepSeekLLM, DeepgramSTT, ElevenLabsTTS, FireworksLLM, GeminiLLM, GeminiRealtime, GroqLLM, MCPClient, MistralLLM, OllamaLLM, OpenAICompatLLM, OpenAILLM, OpenAIRealtime, PerplexityLLM, PipelineSession, TogetherLLM, ToolRegistry, XaiLLM, createAgentLogger, createPipelineLogger, executeBuiltinTool, functionTool, getBuiltinToolSchemas, getTracingConfig, isBuiltinTool, mcpServerHTTP, mcpServerStdio, pcm16ToUlaw, resamplePcm16, resetTracingConfig, setTracingConfig, ulawToPcm16, zodToToolParams };
|
|
3667
3617
|
//# sourceMappingURL=index.js.map
|
|
3668
3618
|
//# sourceMappingURL=index.js.map
|