@teamlearners/clawops 0.4.0 → 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.
@@ -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
  };