@teamlearners/clawops 0.3.1 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkJNSHMKDI_cjs = require('../chunk-JNSHMKDI.cjs');
3
+ var chunk6IQN5RQD_cjs = require('../chunk-6IQN5RQD.cjs');
4
4
  var fs = require('fs');
5
5
  var path = require('path');
6
6
 
@@ -1167,7 +1167,7 @@ var ClawOpsAgent = class {
1167
1167
  constructor(options) {
1168
1168
  this._apiKey = options.apiKey ?? process.env["CLAWOPS_API_KEY"] ?? "";
1169
1169
  this._accountId = options.accountId ?? process.env["CLAWOPS_ACCOUNT_ID"] ?? "";
1170
- this._baseUrl = options.baseUrl ?? chunkJNSHMKDI_cjs.DEFAULT_BASE_URL;
1170
+ this._baseUrl = options.baseUrl ?? chunk6IQN5RQD_cjs.DEFAULT_BASE_URL;
1171
1171
  this._fromNumber = options.from;
1172
1172
  this._session = options.session;
1173
1173
  this._recording = options.recording ?? false;
@@ -1187,7 +1187,7 @@ var ClawOpsAgent = class {
1187
1187
  tool(nameOrTool, description, parameters, handler) {
1188
1188
  if (typeof nameOrTool === "string") {
1189
1189
  if (!description || !parameters || !handler) {
1190
- throw new chunkJNSHMKDI_cjs.AgentError("tool(name, description, parameters, handler) requires all arguments.");
1190
+ throw new chunk6IQN5RQD_cjs.AgentError("tool(name, description, parameters, handler) requires all arguments.");
1191
1191
  }
1192
1192
  this._tools.register({
1193
1193
  name: nameOrTool,
@@ -1220,10 +1220,10 @@ var ClawOpsAgent = class {
1220
1220
  /** Connect to the ClawOps platform and start listening for calls. */
1221
1221
  async connect() {
1222
1222
  if (!this._apiKey) {
1223
- throw new chunkJNSHMKDI_cjs.AgentError("API key is required. Set CLAWOPS_API_KEY or pass apiKey option.");
1223
+ throw new chunk6IQN5RQD_cjs.AgentError("API key is required. Set CLAWOPS_API_KEY or pass apiKey option.");
1224
1224
  }
1225
1225
  if (!this._accountId) {
1226
- throw new chunkJNSHMKDI_cjs.AgentError("Account ID is required. Set CLAWOPS_ACCOUNT_ID or pass accountId option.");
1226
+ throw new chunk6IQN5RQD_cjs.AgentError("Account ID is required. Set CLAWOPS_ACCOUNT_ID or pass accountId option.");
1227
1227
  }
1228
1228
  this._controlWs = new ControlWebSocket({
1229
1229
  baseUrl: this._baseUrl,
@@ -1240,7 +1240,7 @@ var ClawOpsAgent = class {
1240
1240
  await this._controlWs.connect();
1241
1241
  await this._controlWs.waitConnected();
1242
1242
  } catch (err) {
1243
- throw new chunkJNSHMKDI_cjs.AgentConnectionError(
1243
+ throw new chunk6IQN5RQD_cjs.AgentConnectionError(
1244
1244
  `Failed to connect to ClawOps: ${err instanceof Error ? err.message : String(err)}`
1245
1245
  );
1246
1246
  }
@@ -1290,7 +1290,7 @@ var ClawOpsAgent = class {
1290
1290
  });
1291
1291
  if (resp.status !== 201) {
1292
1292
  const error = await resp.json();
1293
- throw new chunkJNSHMKDI_cjs.AgentError(`\uBC1C\uC2E0 \uC2E4\uD328 (${resp.status}): ${error["error"] ?? ""}`);
1293
+ throw new chunk6IQN5RQD_cjs.AgentError(`\uBC1C\uC2E0 \uC2E4\uD328 (${resp.status}): ${error["error"] ?? ""}`);
1294
1294
  }
1295
1295
  const data = await resp.json();
1296
1296
  const callSession = new CallSession({
@@ -1815,8 +1815,8 @@ var GeminiRealtime = class {
1815
1815
  _voice;
1816
1816
  _language;
1817
1817
  _greeting;
1818
- _generationConfig;
1819
- _ws = null;
1818
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1819
+ _session = null;
1820
1820
  _call = null;
1821
1821
  _tools = null;
1822
1822
  _recorder = null;
@@ -1830,7 +1830,6 @@ var GeminiRealtime = class {
1830
1830
  this._voice = options.voice ?? "Kore";
1831
1831
  this._language = options.language ?? "ko";
1832
1832
  this._greeting = options.greeting ?? true;
1833
- this._generationConfig = options.generationConfig;
1834
1833
  }
1835
1834
  /** Inject per-call ToolRegistry. */
1836
1835
  setToolRegistry(registry) {
@@ -1849,83 +1848,78 @@ var GeminiRealtime = class {
1849
1848
  if (!this._apiKey) {
1850
1849
  throw new Error("Google API key is required. Set GOOGLE_API_KEY or pass apiKey option.");
1851
1850
  }
1852
- const { WebSocket } = await import('ws');
1853
- const url = `wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent?key=${this._apiKey}`;
1854
- this._ws = new WebSocket(url);
1855
- return new Promise((resolve, reject) => {
1856
- const ws = this._ws;
1857
- ws.on("open", () => {
1858
- this._sendSetup();
1859
- this._waitSetupComplete().then(() => {
1860
- if (this._greeting) {
1861
- this._sendGreeting();
1851
+ const { GoogleGenAI } = await import('@google/genai/node');
1852
+ const client = new GoogleGenAI({ apiKey: this._apiKey });
1853
+ const config = {
1854
+ responseModalities: ["AUDIO"],
1855
+ speechConfig: {
1856
+ voiceConfig: {
1857
+ prebuiltVoiceConfig: {
1858
+ voiceName: this._voice
1862
1859
  }
1863
- this._receiveLoop();
1864
- resolve();
1865
- }).catch(reject);
1866
- });
1867
- ws.on("close", () => {
1868
- this._closed = true;
1869
- });
1870
- ws.on("error", (err) => {
1871
- if (!this._ws) {
1872
- reject(err);
1873
1860
  }
1874
- console.error("[GeminiRealtime] WebSocket error:", err.message);
1875
- });
1861
+ },
1862
+ inputAudioTranscription: {},
1863
+ outputAudioTranscription: {}
1864
+ };
1865
+ if (this._systemPrompt) {
1866
+ config["systemInstruction"] = this._systemPrompt;
1867
+ }
1868
+ const toolSchemas = this._buildToolSchemas();
1869
+ if (toolSchemas.length > 0) {
1870
+ config["tools"] = [{ functionDeclarations: toolSchemas }];
1871
+ }
1872
+ this._session = await client.live.connect({
1873
+ model: this._model,
1874
+ config,
1875
+ callbacks: {
1876
+ onmessage: (msg) => this._handleMessage(msg),
1877
+ onerror: (err) => {
1878
+ console.error("[GeminiRealtime] SDK error:", err);
1879
+ },
1880
+ onclose: () => {
1881
+ this._closed = true;
1882
+ }
1883
+ }
1876
1884
  });
1885
+ if (this._greeting) {
1886
+ this._session.sendClientContent({
1887
+ turns: [
1888
+ {
1889
+ role: "user",
1890
+ parts: [{ text: "\uC778\uC0AC\uD574 \uC8FC\uC138\uC694." }]
1891
+ }
1892
+ ],
1893
+ turnComplete: true
1894
+ });
1895
+ }
1877
1896
  }
1878
1897
  feedAudio(audio) {
1879
- if (this._ws && this._ws.readyState === 1 && !this._closed) {
1898
+ if (this._session && !this._closed) {
1880
1899
  const pcm8k = ulawToPcm16(audio);
1900
+ if (this._recorder) {
1901
+ this._recorder.writeInbound(pcm8k);
1902
+ }
1881
1903
  const pcm16k = resamplePcm16(pcm8k, 8e3, 16e3);
1882
- this._ws.send(
1883
- JSON.stringify({
1884
- realtimeInput: {
1885
- mediaChunks: [
1886
- {
1887
- mimeType: "audio/pcm;rate=16000",
1888
- data: pcm16k.toString("base64")
1889
- }
1890
- ]
1891
- }
1892
- })
1893
- );
1904
+ this._session.sendRealtimeInput({
1905
+ audio: {
1906
+ data: Buffer.from(pcm16k).toString("base64"),
1907
+ mimeType: "audio/pcm;rate=16000"
1908
+ }
1909
+ });
1894
1910
  }
1895
1911
  }
1896
1912
  async stop() {
1897
1913
  this._closed = true;
1898
- if (this._ws) {
1899
- this._ws.close();
1900
- this._ws = null;
1901
- }
1902
- }
1903
- _sendSetup() {
1904
- if (!this._ws || this._ws.readyState !== 1) return;
1905
- const setupConfig = {
1906
- model: `models/${this._model}`,
1907
- generationConfig: {
1908
- responseModalities: ["AUDIO"],
1909
- speechConfig: {
1910
- voiceConfig: {
1911
- prebuiltVoiceConfig: {
1912
- voiceName: this._voice
1913
- }
1914
- }
1915
- },
1916
- ...this._generationConfig
1917
- },
1918
- realtimeInputConfig: {
1919
- automaticActivityDetection: {
1920
- disabled: false
1921
- }
1914
+ if (this._session) {
1915
+ try {
1916
+ this._session.close();
1917
+ } catch {
1922
1918
  }
1923
- };
1924
- if (this._systemPrompt) {
1925
- setupConfig["systemInstruction"] = {
1926
- parts: [{ text: this._systemPrompt }]
1927
- };
1919
+ this._session = null;
1928
1920
  }
1921
+ }
1922
+ _buildToolSchemas() {
1929
1923
  const toolDefs = this._tools ? this._tools.toOpenAITools().map((t) => ({
1930
1924
  name: t.function.name,
1931
1925
  description: t.function.description,
@@ -1934,107 +1928,46 @@ var GeminiRealtime = class {
1934
1928
  )
1935
1929
  })) : [];
1936
1930
  toolDefs.push(HANG_UP_TOOL2);
1937
- setupConfig["tools"] = [{ functionDeclarations: toolDefs }];
1938
- this._ws.send(JSON.stringify({ setup: setupConfig }));
1939
- }
1940
- _waitSetupComplete() {
1941
- return new Promise((resolve, reject) => {
1942
- if (!this._ws) {
1943
- reject(new Error("WebSocket not connected"));
1944
- return;
1945
- }
1946
- const onMessage = (data) => {
1947
- try {
1948
- const msg = JSON.parse(data.toString());
1949
- if ("setupComplete" in msg) {
1950
- this._ws?.removeListener("message", onMessage);
1951
- resolve();
1952
- }
1953
- } catch {
1954
- }
1955
- };
1956
- this._ws.on("message", onMessage);
1957
- });
1958
- }
1959
- _sendGreeting() {
1960
- if (!this._ws || this._ws.readyState !== 1) return;
1961
- this._ws.send(
1962
- JSON.stringify({
1963
- clientContent: {
1964
- turns: [
1965
- {
1966
- role: "user",
1967
- parts: [{ text: "\uC778\uC0AC\uD574 \uC8FC\uC138\uC694." }]
1968
- }
1969
- ],
1970
- turnComplete: true
1971
- }
1972
- })
1973
- );
1974
- }
1975
- _receiveLoop() {
1976
- if (!this._ws) return;
1977
- this._ws.on("message", (data) => {
1978
- try {
1979
- const msg = JSON.parse(data.toString());
1980
- this._handleMessage(msg);
1981
- } catch {
1982
- }
1983
- });
1931
+ return toolDefs;
1984
1932
  }
1985
1933
  _handleMessage(msg) {
1986
1934
  if (!this._call) return;
1987
- const serverContent = msg["serverContent"];
1935
+ const serverContent = msg.serverContent;
1988
1936
  if (serverContent) {
1989
- const modelTurn = serverContent["modelTurn"];
1937
+ const modelTurn = serverContent.modelTurn;
1990
1938
  if (modelTurn) {
1991
- const parts = modelTurn["parts"];
1992
- if (parts) {
1993
- for (const part of parts) {
1994
- const inlineData = part["inlineData"];
1995
- if (inlineData && inlineData["data"]) {
1996
- const mimeType = inlineData["mimeType"] ?? "";
1997
- if (mimeType.includes("audio")) {
1998
- this._handleAudioData(inlineData["data"]);
1999
- }
2000
- }
2001
- const text = part["text"];
2002
- if (text && this._call) {
2003
- this._call._emit("transcript", "assistant", text);
1939
+ for (const part of modelTurn.parts ?? []) {
1940
+ const inlineData = part.inlineData;
1941
+ if (inlineData?.data) {
1942
+ const mimeType = inlineData.mimeType ?? "";
1943
+ if (mimeType.includes("audio")) {
1944
+ this._handleAudioData(inlineData.data);
2004
1945
  }
2005
1946
  }
2006
1947
  }
2007
1948
  }
2008
- if (serverContent["turnComplete"]) {
1949
+ if (serverContent.turnComplete) {
2009
1950
  this._flushAudioRemainder();
2010
1951
  }
2011
- if (serverContent["interrupted"]) {
1952
+ if (serverContent.interrupted) {
2012
1953
  if (this._call) {
2013
1954
  this._call.clearAudio();
2014
1955
  }
2015
1956
  this._sentAudioChunks = 0;
2016
1957
  this._audioRemainder = Buffer.alloc(0);
2017
1958
  }
2018
- }
2019
- const inputTranscription = msg["inputTranscription"];
2020
- if (inputTranscription) {
2021
- const text = inputTranscription["text"];
2022
- if (text && this._call) {
2023
- this._call._emit("transcript", "user", text);
1959
+ const inputText = serverContent.inputTranscription?.text;
1960
+ if (inputText && this._call) {
1961
+ this._call._emit("transcript", "user", inputText);
2024
1962
  }
2025
- }
2026
- const outputTranscription = msg["outputTranscription"];
2027
- if (outputTranscription) {
2028
- const text = outputTranscription["text"];
2029
- if (text && this._call) {
2030
- this._call._emit("transcript", "assistant", text);
1963
+ const outputText = serverContent.outputTranscription?.text;
1964
+ if (outputText && this._call) {
1965
+ this._call._emit("transcript", "assistant", outputText);
2031
1966
  }
2032
1967
  }
2033
- const toolCall = msg["toolCall"];
2034
- if (toolCall) {
2035
- this._handleToolCall(toolCall);
1968
+ if (msg.toolCall) {
1969
+ this._handleToolCall(msg.toolCall);
2036
1970
  }
2037
- if (msg["toolCallCancellation"]) ;
2038
1971
  }
2039
1972
  _handleAudioData(b64Data) {
2040
1973
  if (!this._call) return;
@@ -2065,13 +1998,13 @@ var GeminiRealtime = class {
2065
1998
  }
2066
1999
  }
2067
2000
  async _handleToolCall(toolCall) {
2068
- const functionCalls = toolCall["functionCalls"];
2001
+ const functionCalls = toolCall.functionCalls;
2069
2002
  if (!functionCalls) return;
2070
2003
  const responses = [];
2071
2004
  for (const fc of functionCalls) {
2072
- const name = fc["name"];
2073
- const fcId = fc["id"] ?? "";
2074
- const args = fc["args"] ?? {};
2005
+ const name = fc.name ?? "";
2006
+ const fcId = fc.id ?? "";
2007
+ const args = fc.args ?? {};
2075
2008
  if (name === "hang_up") {
2076
2009
  if (this._call) {
2077
2010
  this._call.hangup();
@@ -2099,14 +2032,10 @@ var GeminiRealtime = class {
2099
2032
  });
2100
2033
  }
2101
2034
  }
2102
- if (this._ws && this._ws.readyState === 1) {
2103
- this._ws.send(
2104
- JSON.stringify({
2105
- toolResponse: {
2106
- functionResponses: responses
2107
- }
2108
- })
2109
- );
2035
+ if (this._session) {
2036
+ this._session.sendToolResponse({
2037
+ functionResponses: responses
2038
+ });
2110
2039
  }
2111
2040
  }
2112
2041
  };