@teamlearners/clawops 0.36.0 → 0.37.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.
Files changed (35) hide show
  1. package/dist/agent/index.cjs +78 -409
  2. package/dist/agent/index.cjs.map +1 -1
  3. package/dist/agent/index.d.cts +2 -2
  4. package/dist/agent/index.d.ts +2 -2
  5. package/dist/agent/index.js +5 -340
  6. package/dist/agent/index.js.map +1 -1
  7. package/dist/agent/livekit/index.cjs +9 -8
  8. package/dist/agent/livekit/index.cjs.map +1 -1
  9. package/dist/agent/livekit/index.d.cts +1 -1
  10. package/dist/agent/livekit/index.d.ts +1 -1
  11. package/dist/agent/livekit/index.js +2 -1
  12. package/dist/agent/livekit/index.js.map +1 -1
  13. package/dist/{base-C3yzF1e0.d.cts → base-BalWsEyb.d.cts} +31 -2
  14. package/dist/{base-C3yzF1e0.d.ts → base-BalWsEyb.d.ts} +31 -2
  15. package/dist/{chunk-4YLSDMLL.js → chunk-2OGQSWTW.js} +372 -3
  16. package/dist/chunk-2OGQSWTW.js.map +1 -0
  17. package/dist/{chunk-XL2VWU36.js → chunk-35XJNMFU.js} +3 -6
  18. package/dist/chunk-35XJNMFU.js.map +1 -0
  19. package/dist/{chunk-QD2ZY4UP.cjs → chunk-7TEOYLZI.cjs} +375 -2
  20. package/dist/chunk-7TEOYLZI.cjs.map +1 -0
  21. package/dist/chunk-CKPVV6SZ.js +6 -0
  22. package/dist/chunk-CKPVV6SZ.js.map +1 -0
  23. package/dist/chunk-EYI3ULDU.cjs +8 -0
  24. package/dist/chunk-EYI3ULDU.cjs.map +1 -0
  25. package/dist/{chunk-LKFNV2GI.cjs → chunk-LLPMUDNE.cjs} +2 -6
  26. package/dist/chunk-LLPMUDNE.cjs.map +1 -0
  27. package/dist/index.cjs +12 -11
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.js +3 -2
  30. package/dist/index.js.map +1 -1
  31. package/package.json +1 -1
  32. package/dist/chunk-4YLSDMLL.js.map +0 -1
  33. package/dist/chunk-LKFNV2GI.cjs.map +0 -1
  34. package/dist/chunk-QD2ZY4UP.cjs.map +0 -1
  35. package/dist/chunk-XL2VWU36.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import { F as FunctionTool, S as Session, B as BuiltinTool, C as CallSession, a as STT, L as LLM, T as TTS, b as ToolRegistry, c as SessionTelemetry, d as SpeechEvent, e as ConversationMessage, f as LLMChunk } from '../base-C3yzF1e0.cjs';
2
- export { g as CallDirection, h as CallStatus, O as OpenAIToolDefinition, i as ToolCallRequest, j as functionTool, z as zodToToolParams } from '../base-C3yzF1e0.cjs';
1
+ import { F as FunctionTool, S as Session, B as BuiltinTool, C as CallSession, a as STT, L as LLM, T as TTS, b as ToolRegistry, c as SessionTelemetry, d as SpeechEvent, e as ConversationMessage, f as LLMChunk } from '../base-BalWsEyb.cjs';
2
+ export { g as CallDirection, h as CallStatus, D as DtmfCollectorBusyError, O as OpenAIToolDefinition, i as ToolCallRequest, j as functionTool, z as zodToToolParams } from '../base-BalWsEyb.cjs';
3
3
  import { Logger } from 'pino';
4
4
  export { Logger } from 'pino';
5
5
  import 'zod';
@@ -1,5 +1,5 @@
1
- import { F as FunctionTool, S as Session, B as BuiltinTool, C as CallSession, a as STT, L as LLM, T as TTS, b as ToolRegistry, c as SessionTelemetry, d as SpeechEvent, e as ConversationMessage, f as LLMChunk } from '../base-C3yzF1e0.js';
2
- export { g as CallDirection, h as CallStatus, O as OpenAIToolDefinition, i as ToolCallRequest, j as functionTool, z as zodToToolParams } from '../base-C3yzF1e0.js';
1
+ import { F as FunctionTool, S as Session, B as BuiltinTool, C as CallSession, a as STT, L as LLM, T as TTS, b as ToolRegistry, c as SessionTelemetry, d as SpeechEvent, e as ConversationMessage, f as LLMChunk } from '../base-BalWsEyb.js';
2
+ export { g as CallDirection, h as CallStatus, D as DtmfCollectorBusyError, O as OpenAIToolDefinition, i as ToolCallRequest, j as functionTool, z as zodToToolParams } from '../base-BalWsEyb.js';
3
3
  import { Logger } from 'pino';
4
4
  export { Logger } from 'pino';
5
5
  import 'zod';
@@ -1,10 +1,10 @@
1
- import { DEFAULT_BASE_URL, VERSION } from '../chunk-XL2VWU36.js';
1
+ import { DEFAULT_BASE_URL } from '../chunk-35XJNMFU.js';
2
2
  import { AgentError, AgentConnectionError } from '../chunk-VYGIWHRU.js';
3
- import { NOOP_LOGGER, resolveBuiltinTools, createAgentLogger, createPipelineLogger, BufferingCall, attachBuffered, ulawToPcm16, resamplePcm16, getBuiltinToolSchemas, BUILTIN_TOOL_NAMES, executeBuiltinTool, CALL_NOT_READY_RESULT, pcm16ToUlaw, applyUlawGain } from '../chunk-4YLSDMLL.js';
4
- export { BUILTIN_TOOL_NAMES, BuiltinTool, DECODE_TABLE, createAgentLogger, createPipelineLogger, executeBuiltinTool, getBuiltinToolSchemas, isBuiltinTool, pcm16ToUlaw, resamplePcm16, ulawToPcm16 } from '../chunk-4YLSDMLL.js';
3
+ import { NOOP_LOGGER, resolveBuiltinTools, createAgentLogger, createPipelineLogger, getSdkInfo, CallSession, BufferingCall, attachBuffered, ulawToPcm16, resamplePcm16, getBuiltinToolSchemas, BUILTIN_TOOL_NAMES, executeBuiltinTool, CALL_NOT_READY_RESULT, pcm16ToUlaw, applyUlawGain } from '../chunk-2OGQSWTW.js';
4
+ export { BUILTIN_TOOL_NAMES, BuiltinTool, CallSession, DECODE_TABLE, DtmfCollectorBusyError, createAgentLogger, createPipelineLogger, executeBuiltinTool, getBuiltinToolSchemas, isBuiltinTool, pcm16ToUlaw, resamplePcm16, ulawToPcm16 } from '../chunk-2OGQSWTW.js';
5
+ import '../chunk-CKPVV6SZ.js';
5
6
  import * as fs from 'fs';
6
7
  import * as path from 'path';
7
- import os from 'os';
8
8
 
9
9
  // src/agent/control-ws.ts
10
10
  var INITIAL_RECONNECT_DELAY = 1e3;
@@ -699,341 +699,6 @@ var AudioRecorder = class {
699
699
  }
700
700
  }
701
701
  };
702
- var MAX_ERRORS = 20;
703
- var MAX_ERROR_MESSAGE_LENGTH = 200;
704
- function getSdkInfo() {
705
- return {
706
- name: "clawops-node",
707
- version: VERSION,
708
- runtime: `node/${process.versions.node}`,
709
- os: `${process.platform}/${os.arch()}`
710
- };
711
- }
712
- function createCallMetrics() {
713
- return {
714
- firstResponseMs: null,
715
- turnCount: 0,
716
- toolCallCount: 0,
717
- toolErrorCount: 0,
718
- bargeInCount: 0,
719
- endReason: null,
720
- errors: []
721
- };
722
- }
723
- function addMetricError(metrics, err) {
724
- metrics.toolErrorCount++;
725
- if (metrics.errors.length < MAX_ERRORS) {
726
- metrics.errors.push({
727
- type: err.name || "Error",
728
- message: (err.message || "").slice(0, MAX_ERROR_MESSAGE_LENGTH)
729
- });
730
- }
731
- }
732
-
733
- // src/agent/session.ts
734
- var CallSession = class {
735
- callId;
736
- fromNumber;
737
- toNumber;
738
- accountId;
739
- direction;
740
- startTime;
741
- metadata;
742
- _status;
743
- _endedStatus = null;
744
- _endedDuration = null;
745
- _sendAudioFn = null;
746
- _clearAudioFn = null;
747
- _hangupFn = null;
748
- /** @internal */
749
- _sendDtmfFn = null;
750
- /** @internal */
751
- _transferFn = null;
752
- /** @internal */
753
- _isTransportConnected = null;
754
- /**
755
- * @internal Media WS playout 마커 훅. LiveKit(`ClawOpsAudioOutput`)이 재생 완료
756
- * 판정(mark echo)과 barge-in 절단 위치 계산에 쓴다. 다른 세션 타입은 읽지 않는다.
757
- * prewarm 중(BufferingCall)에는 바인딩되지 않아 null 이다.
758
- */
759
- /** @internal */
760
- _sendMark = null;
761
- /** @internal */
762
- _waitForMark = null;
763
- /** @internal */
764
- _flushTransport = null;
765
- _dtmfCollectorActive = false;
766
- _dtmfResolvers = [];
767
- _dtmfBuffer = [];
768
- _log = NOOP_LOGGER;
769
- _handlers = /* @__PURE__ */ new Map();
770
- _endedPromise;
771
- _resolveEnded;
772
- _metrics = createCallMetrics();
773
- _firstResponseSent = false;
774
- constructor(options) {
775
- this.callId = options.callId;
776
- this.fromNumber = options.fromNumber;
777
- this.toNumber = options.toNumber;
778
- this.accountId = options.accountId;
779
- this.direction = options.direction;
780
- this.metadata = options.metadata ?? {};
781
- this._status = "ringing";
782
- this.startTime = /* @__PURE__ */ new Date();
783
- this._endedPromise = new Promise((resolve) => {
784
- this._resolveEnded = resolve;
785
- });
786
- }
787
- setLogger(logger) {
788
- this._log = logger;
789
- }
790
- get status() {
791
- return this._status;
792
- }
793
- /**
794
- * 서버가 통보한 최종 종료 상태. 통화가 끝나기 전에는 null.
795
- *
796
- * `completed`(성사) / `no-answer`(벨은 울렸으나 무응답) / `busy`(통화중) /
797
- * `rejected`(수신 거절) / `canceled`(응답 전 발신 측 취소) / `failed`(시스템·망 오류).
798
- * `status` 는 SDK 내부 수명주기(ringing→active→ended)이므로 통화 성사 여부는
799
- * 이 값이나 `call_failed` 이벤트로 판단한다.
800
- */
801
- get endedStatus() {
802
- return this._endedStatus;
803
- }
804
- /**
805
- * 서버가 확정한 통화 시간(초). 통화가 끝나기 전에는 `null`.
806
- *
807
- * ⚠️ `duration` 과 다르다 — 그쪽은 SDK 가 로컬 시계로 재는 **경과 시간**이라 통화 중에도
808
- * 읽히고, 세션이 붙기 전후의 오차를 포함한다. 기록·정산에 쓸 값은 이쪽이다.
809
- */
810
- get endedDuration() {
811
- return this._endedDuration;
812
- }
813
- get duration() {
814
- return (Date.now() - this.startTime.getTime()) / 1e3;
815
- }
816
- /** @internal 서버가 통보한 통화 시간을 확정한다. */
817
- _setEndedDuration(seconds) {
818
- this._endedDuration = seconds;
819
- }
820
- get metrics() {
821
- return this._metrics;
822
- }
823
- recordFirstResponse() {
824
- if (!this._firstResponseSent) {
825
- this._firstResponseSent = true;
826
- this._metrics.firstResponseMs = Date.now() - this.startTime.getTime();
827
- }
828
- }
829
- recordTurn() {
830
- this._metrics.turnCount++;
831
- }
832
- recordToolCall() {
833
- this._metrics.toolCallCount++;
834
- }
835
- recordToolError(err) {
836
- addMetricError(this._metrics, err);
837
- }
838
- recordBargeIn() {
839
- this._metrics.bargeInCount++;
840
- }
841
- recordEndReason(reason) {
842
- this._metrics.endReason = reason;
843
- }
844
- /** Bind transport functions (called internally by the agent). */
845
- _bindTransport(send, clear, hangup, sendDtmf, isConnected) {
846
- this._sendAudioFn = send;
847
- this._clearAudioFn = clear;
848
- this._hangupFn = hangup;
849
- if (sendDtmf) this._sendDtmfFn = sendDtmf;
850
- if (isConnected) this._isTransportConnected = isConnected;
851
- this._status = "active";
852
- }
853
- /**
854
- * Send G.711 μ-law audio (8kHz, mono) to the caller.
855
- *
856
- * NOT PCM16. The transport applies μ-law gain and forwards the bytes as-is,
857
- * so PCM16 input is reinterpreted as μ-law and plays as noise. Convert first.
858
- */
859
- sendAudio(audio) {
860
- if (this._sendAudioFn) {
861
- this._sendAudioFn(audio);
862
- }
863
- }
864
- /** Clear any queued outbound audio. */
865
- clearAudio() {
866
- if (this._clearAudioFn) {
867
- this._clearAudioFn();
868
- }
869
- }
870
- /** Hang up the call, waiting for pending audio to finish. */
871
- async hangup() {
872
- if (this._hangupFn) {
873
- await this._hangupFn();
874
- }
875
- }
876
- /** @internal Route a received DTMF digit to an active collector or buffer. */
877
- _routeDtmf(digit) {
878
- if (this._dtmfCollectorActive && this._dtmfResolvers.length > 0) {
879
- const resolve = this._dtmfResolvers.shift();
880
- resolve(digit);
881
- } else {
882
- this._dtmfBuffer.push(digit);
883
- }
884
- }
885
- /** Collect DTMF digits from the caller. */
886
- async collectDtmf(options) {
887
- if (this._dtmfCollectorActive) {
888
- throw new Error("\uC774\uBBF8 DTMF \uC218\uC9D1 \uC911\uC785\uB2C8\uB2E4");
889
- }
890
- const { maxDigits, finishOnKey = "#", timeout = 5 } = options;
891
- this._dtmfCollectorActive = true;
892
- const collected = [];
893
- try {
894
- while (collected.length < maxDigits) {
895
- if (this._dtmfBuffer.length > 0) {
896
- const digit2 = this._dtmfBuffer.shift();
897
- if (digit2 === finishOnKey) break;
898
- collected.push(digit2);
899
- continue;
900
- }
901
- const digit = await Promise.race([
902
- new Promise((resolve) => {
903
- this._dtmfResolvers.push(resolve);
904
- }),
905
- new Promise((resolve) => {
906
- setTimeout(() => resolve(null), timeout * 1e3);
907
- })
908
- ]);
909
- if (digit === null) break;
910
- if (digit === finishOnKey) break;
911
- collected.push(digit);
912
- }
913
- } finally {
914
- this._dtmfCollectorActive = false;
915
- this._dtmfResolvers = [];
916
- this._dtmfBuffer = [];
917
- }
918
- const result = collected.join("");
919
- this._log.info("DTMF collected: %s", result);
920
- return result;
921
- }
922
- /** Send a sequence of DTMF digits. */
923
- async sendDtmfSequence(digits) {
924
- if (!this._sendDtmfFn) {
925
- throw new Error("DTMF \uC804\uC1A1 \uD568\uC218\uAC00 \uBC14\uC778\uB529\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4");
926
- }
927
- for (const ch of digits) {
928
- if (this._isTransportConnected && !this._isTransportConnected()) {
929
- throw new Error("DTMF \uC804\uC1A1 \uC911 \uC5F0\uACB0\uC774 \uB04A\uC5B4\uC84C\uC2B5\uB2C8\uB2E4");
930
- }
931
- if (ch === "w") {
932
- await new Promise((r) => setTimeout(r, 500));
933
- } else if (ch === "W") {
934
- await new Promise((r) => setTimeout(r, 1e3));
935
- } else if ("0123456789*#".includes(ch)) {
936
- if (this._sendDtmfFn) {
937
- await this._sendDtmfFn(ch);
938
- }
939
- } else {
940
- throw new Error(`\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 DTMF \uBB38\uC790: ${ch}`);
941
- }
942
- }
943
- }
944
- /**
945
- * Transfer the call to a phone number or SIP endpoint.
946
- *
947
- * destinationType='pstn' (default): `to` is a phone number dialed via carrier.
948
- * destinationType='sip': `to` is a SIP URI (e.g. `sip:user@host`) connected
949
- * directly to a SIP endpoint without going through the PSTN carrier. Requires the
950
- * account to have an active `sip_trunk` add-on; otherwise the transfer fails and
951
- * the call continues with the AI (result `{ status: 'failed', ... }`).
952
- *
953
- * 전환받는 쪽에 표시되는 발신번호는 기본이 **계정 보유번호**(인바운드면 착신 070)다.
954
- *
955
- * `callerIdMode: 'original'` 은 인바운드 통화의 **원 발신자 번호를 승계하려는 선호**다.
956
- * 승계할 수 없는 통화(KCT 직결 인입이 아니거나 국내 번호로 정규화되지 않는 발신번호)면
957
- * 조용히 계정 보유번호로 내려앉고 **전환은 그대로 성사된다**.
958
- *
959
- * `callerId` 는 번호를 직접 주는 **지시**라 성격이 다르다. 허용 범위(계정 보유번호 또는
960
- * KCT 직결 인입의 원 발신자)를 벗어나면 전환 자체가 실패한다. 둘 다 주면 `callerId` 가
961
- * 이기고 `callerIdMode` 는 무시된다 — 우선순위 판단은 서버가 한다.
962
- */
963
- async transfer(to, options) {
964
- if (!this._transferFn) {
965
- throw new Error("transfer not available");
966
- }
967
- const callerIdMode = options?.callerIdMode;
968
- if (callerIdMode !== void 0 && callerIdMode !== "account" && callerIdMode !== "original") {
969
- throw new Error(
970
- `callerIdMode must be 'account' or 'original', got ${JSON.stringify(callerIdMode)}`
971
- );
972
- }
973
- return this._transferFn({
974
- to,
975
- destinationType: options?.destinationType ?? "pstn",
976
- mode: options?.mode ?? "blind",
977
- afterTransfer: options?.afterTransfer ?? "terminate",
978
- holdMedia: options?.holdMedia ?? "ringback",
979
- whisper: options?.whisper ?? null,
980
- context: options?.context ?? null,
981
- callerId: options?.callerId ?? null,
982
- timeout: options?.timeout ?? 30,
983
- // 안 주면 키를 붙이지 않는다 — 구 서버와 기존 동작을 그대로 둔다(additive).
984
- ...callerIdMode !== void 0 ? { callerIdMode } : {}
985
- });
986
- }
987
- /** Register an event handler. */
988
- on(event, handler) {
989
- let list = this._handlers.get(event);
990
- if (!list) {
991
- list = [];
992
- this._handlers.set(event, list);
993
- }
994
- list.push(handler);
995
- }
996
- /** Wait for the call to end. */
997
- async wait() {
998
- return this._endedPromise;
999
- }
1000
- /**
1001
- * Mark the session as ended (called internally).
1002
- *
1003
- * @param status 서버가 통보한 최종 상태(completed/no-answer/busy/rejected/canceled/
1004
- * failed). 주어지면 `endedStatus` 로 확정한다 — 상대가 받지 않은 통화를 성사된 통화와
1005
- * 구분하기 위함이다. 생략하면 미디어 세션 정리 경로에서의 호출이므로, 아직 종료 전일
1006
- * 때만 'completed' 로 채우고 이미 확정된 서버 상태는 덮어쓰지 않는다.
1007
- */
1008
- _markEnded(status) {
1009
- if (status !== void 0) {
1010
- this._endedStatus = status;
1011
- } else if (this._status !== "ended") {
1012
- this._endedStatus = "completed";
1013
- }
1014
- this._status = "ended";
1015
- this._resolveEnded();
1016
- }
1017
- /** Emit an event to registered handlers. Matches Python SDK: _emit(event, ...args) */
1018
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1019
- _emit(event, ...args) {
1020
- const handlers = this._handlers.get(event);
1021
- if (handlers) {
1022
- for (const handler of handlers) {
1023
- try {
1024
- const result = handler(this, ...args);
1025
- if (result && typeof result.catch === "function") {
1026
- result.catch((err) => {
1027
- this._log.error({ err }, "CallSession handler error: %s", event);
1028
- });
1029
- }
1030
- } catch (err) {
1031
- this._log.error({ err }, "CallSession handler error: %s", event);
1032
- }
1033
- }
1034
- }
1035
- }
1036
- };
1037
702
  var CHUNK_SIZE = 160;
1038
703
  var SAMPLE_RATE2 = 8e3;
1039
704
  var BELL_PARTIALS = [
@@ -4145,6 +3810,6 @@ function mcpServerHTTP(options) {
4145
3810
  };
4146
3811
  }
4147
3812
 
4148
- export { AnthropicLLM, AudioRecorder, CallSession, ClawOpsAgent, ControlWebSocket, DeepSeekLLM, DeepgramSTT, ElevenLabsTTS, FireworksLLM, GeminiLLM, GeminiRealtime, GroqLLM, MCPClient, MediaWebSocket, MistralLLM, OllamaLLM, OpenAICompatLLM, OpenAILLM, OpenAIRealtime, PerplexityLLM, PipelineSession, TogetherLLM, ToolRegistry, XaiLLM, buildControlWsUrl, functionTool, getTracingConfig, mcpServerHTTP, mcpServerStdio, resetTracingConfig, setTracingConfig, zodToToolParams };
3813
+ export { AnthropicLLM, AudioRecorder, ClawOpsAgent, ControlWebSocket, DeepSeekLLM, DeepgramSTT, ElevenLabsTTS, FireworksLLM, GeminiLLM, GeminiRealtime, GroqLLM, MCPClient, MediaWebSocket, MistralLLM, OllamaLLM, OpenAICompatLLM, OpenAILLM, OpenAIRealtime, PerplexityLLM, PipelineSession, TogetherLLM, ToolRegistry, XaiLLM, buildControlWsUrl, functionTool, getTracingConfig, mcpServerHTTP, mcpServerStdio, resetTracingConfig, setTracingConfig, zodToToolParams };
4149
3814
  //# sourceMappingURL=index.js.map
4150
3815
  //# sourceMappingURL=index.js.map