@teamlearners/clawops 0.16.6 → 0.17.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.
@@ -317,8 +317,20 @@ interface LLMChunk {
317
317
  * Implementations: OpenAIRealtime, GeminiRealtime
318
318
  */
319
319
  interface Session {
320
- /** Start the realtime session with the call session and tools. */
320
+ /** Start the realtime session with the call session and tools. Thin wrapper over prewarm + attach. */
321
321
  start(callSession: CallSession, tools?: ToolRegistry): Promise<void>;
322
+ /**
323
+ * Open LLM connection (and session.update + optional greeting trigger) without a CallSession.
324
+ *
325
+ * Audio deltas produced during the prewarm window accumulate in an internal BufferingCall.
326
+ * attach() then replaces the BufferingCall with the real CallSession and flushes the buffer.
327
+ *
328
+ * Tools may optionally be injected here (alternative to calling setToolRegistry separately);
329
+ * the Session is free to ignore the argument if tools are already set.
330
+ */
331
+ prewarm(tools?: ToolRegistry): Promise<void>;
332
+ /** Attach a real CallSession to a prewarmed session and flush any buffered audio. */
333
+ attach(callSession: CallSession): Promise<void>;
322
334
  /** Feed raw audio into the session. */
323
335
  feedAudio(audio: Buffer, timestamp?: number): void;
324
336
  /** Feed DTMF digits into the LLM context and trigger a response. */
@@ -440,6 +452,12 @@ interface ClawOpsAgentOptions {
440
452
  * The caller hears the gained audio, and recording captures it post-gain.
441
453
  */
442
454
  txGain?: number;
455
+ /**
456
+ * outbound_ready 시점에 session.prewarm() 을 백그라운드로 시작할지 여부.
457
+ * false 면 기존 start() 단일 경로로 동작 (prewarm 비활성). Default: true.
458
+ * Python SDK 의 `prewarm_enabled` 과 mirror.
459
+ */
460
+ prewarmEnabled?: boolean;
443
461
  }
444
462
  declare class ClawOpsAgent {
445
463
  private _apiKey;
@@ -466,6 +484,11 @@ declare class ClawOpsAgent {
466
484
  private _holdAudioChunks;
467
485
  private _rxGain;
468
486
  private _txGain;
487
+ private _prewarmTasks;
488
+ private _prewarmFailed;
489
+ /** prewarm 세션이 실제 CallSession 에 attach 완료된 callId. attached 이후의 stop() 은 정상 종료 경로가 책임진다. */
490
+ private _prewarmAttached;
491
+ private _prewarmEnabled;
469
492
  constructor(options: ClawOpsAgentOptions);
470
493
  private static _validateGain;
471
494
  /**
@@ -502,7 +525,24 @@ declare class ClawOpsAgent {
502
525
  }): Promise<CallSession>;
503
526
  private _handleIncoming;
504
527
  private _handleEnded;
528
+ /**
529
+ * Drop prewarm bookkeeping for a callId. Used on hangup/failure paths.
530
+ *
531
+ * prewarm 이 진행 중이거나 완료됐지만 attach 전에 호출되면 LLM WS 가 leak 되므로
532
+ * race 후 session.stop() 으로 정리한다. (TS 에는 Promise.cancel 이 없어 Python
533
+ * 의 task.cancel() 등가물은 _session.stop() 호출이다.)
534
+ *
535
+ * 이미 attach 된 callId 면 stop() 을 호출하지 않는다 — 정상 종료 경로 (call-session
536
+ * finally) 가 책임지기 때문이다.
537
+ */
538
+ private _cleanupPrewarm;
505
539
  private _handleOutboundReady;
540
+ /**
541
+ * Start the LLM session prewarm task for the given callId. Safe to call
542
+ * multiple times — only the first invocation starts the task. Failures are
543
+ * recorded in _prewarmFailed so the call-session path can fall back to start().
544
+ */
545
+ private _startPrewarm;
506
546
  private _handleRinging;
507
547
  private _handleFailed;
508
548
  private _onDtmfEvent;
@@ -734,6 +774,14 @@ declare class PipelineSession implements Session {
734
774
  setHoldAudio(chunks: Buffer[]): void;
735
775
  getTelemetry(): SessionTelemetry;
736
776
  setLogger(logger: Logger): void;
777
+ /**
778
+ * Pre-bootstrap conversation state and (optionally) trigger greeting synthesis
779
+ * before a real CallSession is attached. Audio chunks are buffered into a
780
+ * BufferingCall until attach() flushes them.
781
+ */
782
+ prewarm(tools?: ToolRegistry): Promise<void>;
783
+ /** Attach a real CallSession to the prewarmed session and flush buffered audio. */
784
+ attach(callSession: CallSession): Promise<void>;
737
785
  start(callSession: CallSession, tools?: ToolRegistry): Promise<void>;
738
786
  feedAudio(audio: Buffer): void;
739
787
  feedDtmf(digits: string): Promise<void>;
@@ -806,6 +854,10 @@ declare class OpenAIRealtime implements Session {
806
854
  setRecorder(recorder: AudioRecorder): void;
807
855
  /** Tool 실행 중 재생할 hold audio 청크를 설정한다. */
808
856
  setHoldAudio(chunks: Buffer[]): void;
857
+ /** Open WS + session.update + (optional) response.create without a CallSession. */
858
+ prewarm(tools?: ToolRegistry): Promise<void>;
859
+ /** Attach a real CallSession to the prewarmed session and flush buffered audio. */
860
+ attach(callSession: CallSession): Promise<void>;
809
861
  start(callSession: CallSession, tools?: ToolRegistry): Promise<void>;
810
862
  feedDtmf(digits: string): Promise<void>;
811
863
  feedAudio(audio: Buffer, timestamp?: number): void;
@@ -873,6 +925,10 @@ declare class GeminiRealtime implements Session {
873
925
  setHoldAudio(chunks: Buffer[]): void;
874
926
  setLogger(logger: Logger): void;
875
927
  getTelemetry(): SessionTelemetry;
928
+ /** Open Live session (no CallSession). Audio deltas accumulate into BufferingCall until attach(). */
929
+ prewarm(tools?: ToolRegistry): Promise<void>;
930
+ /** Attach a real CallSession to the prewarmed session and flush buffered audio. */
931
+ attach(callSession: CallSession): Promise<void>;
876
932
  start(callSession: CallSession, tools?: ToolRegistry): Promise<void>;
877
933
  feedAudio(audio: Buffer): void;
878
934
  feedDtmf(digits: string): Promise<void>;
@@ -317,8 +317,20 @@ interface LLMChunk {
317
317
  * Implementations: OpenAIRealtime, GeminiRealtime
318
318
  */
319
319
  interface Session {
320
- /** Start the realtime session with the call session and tools. */
320
+ /** Start the realtime session with the call session and tools. Thin wrapper over prewarm + attach. */
321
321
  start(callSession: CallSession, tools?: ToolRegistry): Promise<void>;
322
+ /**
323
+ * Open LLM connection (and session.update + optional greeting trigger) without a CallSession.
324
+ *
325
+ * Audio deltas produced during the prewarm window accumulate in an internal BufferingCall.
326
+ * attach() then replaces the BufferingCall with the real CallSession and flushes the buffer.
327
+ *
328
+ * Tools may optionally be injected here (alternative to calling setToolRegistry separately);
329
+ * the Session is free to ignore the argument if tools are already set.
330
+ */
331
+ prewarm(tools?: ToolRegistry): Promise<void>;
332
+ /** Attach a real CallSession to a prewarmed session and flush any buffered audio. */
333
+ attach(callSession: CallSession): Promise<void>;
322
334
  /** Feed raw audio into the session. */
323
335
  feedAudio(audio: Buffer, timestamp?: number): void;
324
336
  /** Feed DTMF digits into the LLM context and trigger a response. */
@@ -440,6 +452,12 @@ interface ClawOpsAgentOptions {
440
452
  * The caller hears the gained audio, and recording captures it post-gain.
441
453
  */
442
454
  txGain?: number;
455
+ /**
456
+ * outbound_ready 시점에 session.prewarm() 을 백그라운드로 시작할지 여부.
457
+ * false 면 기존 start() 단일 경로로 동작 (prewarm 비활성). Default: true.
458
+ * Python SDK 의 `prewarm_enabled` 과 mirror.
459
+ */
460
+ prewarmEnabled?: boolean;
443
461
  }
444
462
  declare class ClawOpsAgent {
445
463
  private _apiKey;
@@ -466,6 +484,11 @@ declare class ClawOpsAgent {
466
484
  private _holdAudioChunks;
467
485
  private _rxGain;
468
486
  private _txGain;
487
+ private _prewarmTasks;
488
+ private _prewarmFailed;
489
+ /** prewarm 세션이 실제 CallSession 에 attach 완료된 callId. attached 이후의 stop() 은 정상 종료 경로가 책임진다. */
490
+ private _prewarmAttached;
491
+ private _prewarmEnabled;
469
492
  constructor(options: ClawOpsAgentOptions);
470
493
  private static _validateGain;
471
494
  /**
@@ -502,7 +525,24 @@ declare class ClawOpsAgent {
502
525
  }): Promise<CallSession>;
503
526
  private _handleIncoming;
504
527
  private _handleEnded;
528
+ /**
529
+ * Drop prewarm bookkeeping for a callId. Used on hangup/failure paths.
530
+ *
531
+ * prewarm 이 진행 중이거나 완료됐지만 attach 전에 호출되면 LLM WS 가 leak 되므로
532
+ * race 후 session.stop() 으로 정리한다. (TS 에는 Promise.cancel 이 없어 Python
533
+ * 의 task.cancel() 등가물은 _session.stop() 호출이다.)
534
+ *
535
+ * 이미 attach 된 callId 면 stop() 을 호출하지 않는다 — 정상 종료 경로 (call-session
536
+ * finally) 가 책임지기 때문이다.
537
+ */
538
+ private _cleanupPrewarm;
505
539
  private _handleOutboundReady;
540
+ /**
541
+ * Start the LLM session prewarm task for the given callId. Safe to call
542
+ * multiple times — only the first invocation starts the task. Failures are
543
+ * recorded in _prewarmFailed so the call-session path can fall back to start().
544
+ */
545
+ private _startPrewarm;
506
546
  private _handleRinging;
507
547
  private _handleFailed;
508
548
  private _onDtmfEvent;
@@ -734,6 +774,14 @@ declare class PipelineSession implements Session {
734
774
  setHoldAudio(chunks: Buffer[]): void;
735
775
  getTelemetry(): SessionTelemetry;
736
776
  setLogger(logger: Logger): void;
777
+ /**
778
+ * Pre-bootstrap conversation state and (optionally) trigger greeting synthesis
779
+ * before a real CallSession is attached. Audio chunks are buffered into a
780
+ * BufferingCall until attach() flushes them.
781
+ */
782
+ prewarm(tools?: ToolRegistry): Promise<void>;
783
+ /** Attach a real CallSession to the prewarmed session and flush buffered audio. */
784
+ attach(callSession: CallSession): Promise<void>;
737
785
  start(callSession: CallSession, tools?: ToolRegistry): Promise<void>;
738
786
  feedAudio(audio: Buffer): void;
739
787
  feedDtmf(digits: string): Promise<void>;
@@ -806,6 +854,10 @@ declare class OpenAIRealtime implements Session {
806
854
  setRecorder(recorder: AudioRecorder): void;
807
855
  /** Tool 실행 중 재생할 hold audio 청크를 설정한다. */
808
856
  setHoldAudio(chunks: Buffer[]): void;
857
+ /** Open WS + session.update + (optional) response.create without a CallSession. */
858
+ prewarm(tools?: ToolRegistry): Promise<void>;
859
+ /** Attach a real CallSession to the prewarmed session and flush buffered audio. */
860
+ attach(callSession: CallSession): Promise<void>;
809
861
  start(callSession: CallSession, tools?: ToolRegistry): Promise<void>;
810
862
  feedDtmf(digits: string): Promise<void>;
811
863
  feedAudio(audio: Buffer, timestamp?: number): void;
@@ -873,6 +925,10 @@ declare class GeminiRealtime implements Session {
873
925
  setHoldAudio(chunks: Buffer[]): void;
874
926
  setLogger(logger: Logger): void;
875
927
  getTelemetry(): SessionTelemetry;
928
+ /** Open Live session (no CallSession). Audio deltas accumulate into BufferingCall until attach(). */
929
+ prewarm(tools?: ToolRegistry): Promise<void>;
930
+ /** Attach a real CallSession to the prewarmed session and flush buffered audio. */
931
+ attach(callSession: CallSession): Promise<void>;
876
932
  start(callSession: CallSession, tools?: ToolRegistry): Promise<void>;
877
933
  feedAudio(audio: Buffer): void;
878
934
  feedDtmf(digits: string): Promise<void>;