@livekit/agents 0.7.2 → 0.7.3

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 (39) hide show
  1. package/dist/cli.cjs.map +1 -1
  2. package/dist/index.cjs +14 -14
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/multimodal/agent_playout.cjs +1 -0
  5. package/dist/multimodal/agent_playout.cjs.map +1 -1
  6. package/dist/multimodal/agent_playout.js +1 -0
  7. package/dist/multimodal/agent_playout.js.map +1 -1
  8. package/dist/multimodal/multimodal_agent.cjs +10 -2
  9. package/dist/multimodal/multimodal_agent.cjs.map +1 -1
  10. package/dist/multimodal/multimodal_agent.d.ts +3 -2
  11. package/dist/multimodal/multimodal_agent.d.ts.map +1 -1
  12. package/dist/multimodal/multimodal_agent.js +10 -2
  13. package/dist/multimodal/multimodal_agent.js.map +1 -1
  14. package/dist/pipeline/human_input.cjs +9 -2
  15. package/dist/pipeline/human_input.cjs.map +1 -1
  16. package/dist/pipeline/human_input.d.ts +2 -2
  17. package/dist/pipeline/human_input.d.ts.map +1 -1
  18. package/dist/pipeline/human_input.js +9 -2
  19. package/dist/pipeline/human_input.js.map +1 -1
  20. package/dist/pipeline/pipeline_agent.cjs +7 -1
  21. package/dist/pipeline/pipeline_agent.cjs.map +1 -1
  22. package/dist/pipeline/pipeline_agent.d.ts +3 -1
  23. package/dist/pipeline/pipeline_agent.d.ts.map +1 -1
  24. package/dist/pipeline/pipeline_agent.js +7 -1
  25. package/dist/pipeline/pipeline_agent.js.map +1 -1
  26. package/dist/worker.cjs +1 -1
  27. package/dist/worker.cjs.map +1 -1
  28. package/dist/worker.d.ts.map +1 -1
  29. package/dist/worker.js +1 -1
  30. package/dist/worker.js.map +1 -1
  31. package/package.json +4 -4
  32. package/src/multimodal/multimodal_agent.ts +11 -3
  33. package/src/pipeline/human_input.ts +17 -3
  34. package/src/pipeline/pipeline_agent.ts +15 -2
  35. package/src/worker.ts +1 -1
  36. package/dist/llm/function_context.test.d.ts +0 -2
  37. package/dist/llm/function_context.test.d.ts.map +0 -1
  38. package/dist/tokenize/tokenizer.test.d.ts +0 -2
  39. package/dist/tokenize/tokenizer.test.d.ts.map +0 -1
@@ -1,4 +1,4 @@
1
- import type { RemoteParticipant, Room } from '@livekit/rtc-node';
1
+ import type { NoiseCancellationOptions, RemoteParticipant, Room } from '@livekit/rtc-node';
2
2
  import type { TypedEventEmitter as TypedEmitter } from '@livekit/typed-emitter';
3
3
  import type { CallableFunctionResult, FunctionCallInfo, FunctionContext, LLM } from '../llm/index.js';
4
4
  import { LLMStream } from '../llm/index.js';
@@ -101,6 +101,8 @@ export interface VPAOptions {
101
101
  transcription: AgentTranscriptionOptions;
102
102
  /** Turn detection model to use. */
103
103
  turnDetector?: TurnDetector;
104
+ /** Noise cancellation options. */
105
+ noiseCancellation?: NoiseCancellationOptions;
104
106
  }
105
107
  declare const VoicePipelineAgent_base: new () => TypedEmitter<VPACallbacks>;
106
108
  /** A pipeline agent (VAD + STT + LLM + TTS) implementation. */
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline_agent.d.ts","sourceRoot":"","sources":["../../src/pipeline/pipeline_agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pipeline_agent.d.ts","sourceRoot":"","sources":["../../src/pipeline/pipeline_agent.ts"],"names":[],"mappings":"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"}
@@ -278,7 +278,13 @@ class VoicePipelineAgent extends EventEmitter {
278
278
  this.#logger.error(`Participant with identity ${participantIdentity} not found`);
279
279
  return;
280
280
  }
281
- this.#humanInput = new HumanInput(this.#room, this.#vad, this.#stt, this.#participant);
281
+ this.#humanInput = new HumanInput(
282
+ this.#room,
283
+ this.#vad,
284
+ this.#stt,
285
+ this.#participant,
286
+ this.#opts.noiseCancellation
287
+ );
282
288
  this.#humanInput.on(HumanInputEvent.START_OF_SPEECH, (event) => {
283
289
  this.emit(0 /* USER_STARTED_SPEAKING */);
284
290
  this.#deferredValidation.onHumanStartOfSpeech(event);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pipeline/pipeline_agent.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { LocalTrackPublication, RemoteParticipant, Room } from '@livekit/rtc-node';\nimport {\n AudioSource,\n LocalAudioTrack,\n RoomEvent,\n TrackPublishOptions,\n TrackSource,\n} from '@livekit/rtc-node';\nimport type { TypedEventEmitter as TypedEmitter } from '@livekit/typed-emitter';\nimport { randomUUID } from 'node:crypto';\nimport EventEmitter from 'node:events';\nimport type {\n CallableFunctionResult,\n FunctionCallInfo,\n FunctionContext,\n LLM,\n} from '../llm/index.js';\nimport { LLMEvent, LLMStream } from '../llm/index.js';\nimport { ChatContext, ChatMessage, ChatRole } from '../llm/index.js';\nimport { log } from '../log.js';\nimport type { AgentMetrics, PipelineEOUMetrics } from '../metrics/base.js';\nimport { type STT, StreamAdapter as STTStreamAdapter, SpeechEventType } from '../stt/index.js';\nimport {\n SentenceTokenizer as BasicSentenceTokenizer,\n WordTokenizer as BasicWordTokenizer,\n hyphenateWord,\n} from '../tokenize/basic/index.js';\nimport type { SentenceTokenizer, WordTokenizer } from '../tokenize/tokenizer.js';\nimport { TextAudioSynchronizer, defaultTextSyncOptions } from '../transcription.js';\nimport type { TTS } from '../tts/index.js';\nimport { TTSEvent, StreamAdapter as TTSStreamAdapter } from '../tts/index.js';\nimport { AsyncIterableQueue, CancellablePromise, Future, gracefullyCancel } from '../utils.js';\nimport { type VAD, type VADEvent, VADEventType } from '../vad.js';\nimport type { SpeechSource, SynthesisHandle } from './agent_output.js';\nimport { AgentOutput } from './agent_output.js';\nimport { AgentPlayout, AgentPlayoutEvent } from './agent_playout.js';\nimport { HumanInput, HumanInputEvent } from './human_input.js';\nimport { SpeechHandle } from './speech_handle.js';\n\nexport type AgentState = 'initializing' | 'thinking' | 'listening' | 'speaking';\nexport const AGENT_STATE_ATTRIBUTE = 'lk.agent.state';\nlet speechData: { sequenceId: string } | undefined;\n\nexport type BeforeLLMCallback = (\n agent: VoicePipelineAgent,\n chatCtx: ChatContext,\n) => LLMStream | false | void | Promise<LLMStream | false | void>;\n\nexport type BeforeTTSCallback = (\n agent: VoicePipelineAgent,\n source: string | AsyncIterable<string>,\n) => SpeechSource;\n\nexport enum VPAEvent {\n USER_STARTED_SPEAKING,\n USER_STOPPED_SPEAKING,\n AGENT_STARTED_SPEAKING,\n AGENT_STOPPED_SPEAKING,\n USER_SPEECH_COMMITTED,\n AGENT_SPEECH_COMMITTED,\n AGENT_SPEECH_INTERRUPTED,\n FUNCTION_CALLS_COLLECTED,\n FUNCTION_CALLS_FINISHED,\n METRICS_COLLECTED,\n}\n\nexport type VPACallbacks = {\n [VPAEvent.USER_STARTED_SPEAKING]: () => void;\n [VPAEvent.USER_STOPPED_SPEAKING]: () => void;\n [VPAEvent.AGENT_STARTED_SPEAKING]: () => void;\n [VPAEvent.AGENT_STOPPED_SPEAKING]: () => void;\n [VPAEvent.USER_SPEECH_COMMITTED]: (msg: ChatMessage) => void;\n [VPAEvent.AGENT_SPEECH_COMMITTED]: (msg: ChatMessage) => void;\n [VPAEvent.AGENT_SPEECH_INTERRUPTED]: (msg: ChatMessage) => void;\n [VPAEvent.FUNCTION_CALLS_COLLECTED]: (funcs: FunctionCallInfo[]) => void;\n [VPAEvent.FUNCTION_CALLS_FINISHED]: (funcs: CallableFunctionResult[]) => void;\n [VPAEvent.METRICS_COLLECTED]: (metrics: AgentMetrics) => void;\n};\n\ninterface TurnDetector {\n unlikelyThreshold: number;\n supportsLanguage: (language?: string) => boolean;\n predictEndOfTurn: (chatCtx: ChatContext) => Promise<number>;\n}\n\nexport class AgentCallContext {\n #agent: VoicePipelineAgent;\n #llmStream: LLMStream;\n #metadata = new Map<string, any>();\n #extraChatMessages: ChatMessage[] = [];\n static #current: AgentCallContext;\n\n constructor(agent: VoicePipelineAgent, llmStream: LLMStream) {\n this.#agent = agent;\n this.#llmStream = llmStream;\n AgentCallContext.#current = this;\n }\n\n static getCurrent(): AgentCallContext {\n return AgentCallContext.#current;\n }\n\n get agent(): VoicePipelineAgent {\n return this.#agent;\n }\n\n storeMetadata(key: string, value: any) {\n this.#metadata.set(key, value);\n }\n\n getMetadata(key: string, orDefault: any = undefined) {\n return this.#metadata.get(key) || orDefault;\n }\n\n get llmStream(): LLMStream {\n return this.#llmStream;\n }\n\n get extraChatMessages() {\n return this.#extraChatMessages;\n }\n\n addExtraChatMessage(message: ChatMessage) {\n this.#extraChatMessages.push(message);\n }\n}\n\nconst defaultBeforeLLMCallback: BeforeLLMCallback = (\n agent: VoicePipelineAgent,\n chatCtx: ChatContext,\n): LLMStream => {\n return agent.llm.chat({ chatCtx, fncCtx: agent.fncCtx });\n};\n\nconst defaultBeforeTTSCallback: BeforeTTSCallback = (\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _: VoicePipelineAgent,\n text: string | AsyncIterable<string>,\n): string | AsyncIterable<string> => {\n return text;\n};\n\nexport interface AgentTranscriptionOptions {\n /** Whether to forward the user transcription to the client */\n userTranscription: boolean;\n /** Whether to forward the agent transcription to the client */\n agentTranscription: boolean;\n /**\n * The speed at which the agent's speech transcription is forwarded to the client.\n * We try to mimic the agent's speech speed by adjusting the transcription speed.\n */\n agentTranscriptionSpeech: number;\n /**\n * The tokenizer used to split the speech into sentences.\n * This is used to decide when to mark a transcript as final for the agent transcription.\n */\n sentenceTokenizer: SentenceTokenizer;\n /**\n * The tokenizer used to split the speech into words.\n * This is used to simulate the \"interim results\" of the agent transcription.\n */\n wordTokenizer: WordTokenizer;\n /**\n * A function that takes a string (word) as input and returns a list of strings,\n * representing the hyphenated parts of the word.\n */\n hyphenateWord: (word: string) => string[];\n}\n\nconst defaultAgentTranscriptionOptions: AgentTranscriptionOptions = {\n userTranscription: true,\n agentTranscription: true,\n agentTranscriptionSpeech: 1,\n sentenceTokenizer: new BasicSentenceTokenizer(),\n wordTokenizer: new BasicWordTokenizer(false),\n hyphenateWord: hyphenateWord,\n};\n\nexport interface VPAOptions {\n /** Chat context for the assistant. */\n chatCtx?: ChatContext;\n /** Function context for the assistant. */\n fncCtx?: FunctionContext;\n /** Whether to allow the user to interrupt the assistant. */\n allowInterruptions: boolean;\n /** Minimum duration of speech to consider for interruption. */\n interruptSpeechDuration: number;\n /** Minimum number of words to consider for interuption. This may increase latency. */\n interruptMinWords: number;\n /** Delay to wait before considering the user speech done. */\n minEndpointingDelay: number;\n maxNestedFncCalls: number;\n /* Whether to preemptively synthesize responses. */\n preemptiveSynthesis: boolean;\n /*\n * Callback called when the assistant is about to synthesize a reply.\n *\n * @remarks\n * Returning void will create a default LLM stream.\n * You can also return your own LLM stream by calling `llm.chat()`.\n * Returning `false` ill cancel the synthesis of the reply.\n */\n beforeLLMCallback: BeforeLLMCallback;\n /*\n * Callback called when the assistant is about to synthesize speech.\n *\n * @remarks\n * This can be used to customize text before synthesis\n * (e.g. editing the pronunciation of a word).\n */\n beforeTTSCallback: BeforeTTSCallback;\n /** Options for assistant transcription. */\n transcription: AgentTranscriptionOptions;\n /** Turn detection model to use. */\n turnDetector?: TurnDetector;\n}\n\nconst defaultVPAOptions: VPAOptions = {\n chatCtx: new ChatContext(),\n allowInterruptions: true,\n interruptSpeechDuration: 50,\n interruptMinWords: 0,\n minEndpointingDelay: 500,\n maxNestedFncCalls: 1,\n preemptiveSynthesis: false,\n beforeLLMCallback: defaultBeforeLLMCallback,\n beforeTTSCallback: defaultBeforeTTSCallback,\n transcription: defaultAgentTranscriptionOptions,\n};\n\n/** A pipeline agent (VAD + STT + LLM + TTS) implementation. */\nexport class VoicePipelineAgent extends (EventEmitter as new () => TypedEmitter<VPACallbacks>) {\n /** Minimum time played for the user speech to be committed to the chat context. */\n readonly MIN_TIME_PLAYED_FOR_COMMIT = 1.5;\n protected static readonly FLUSH_SENTINEL = Symbol('FLUSH_SENTINEL');\n\n #vad: VAD;\n #stt: STT;\n #llm: LLM;\n #tts: TTS;\n #opts: VPAOptions;\n #humanInput?: HumanInput;\n #agentOutput?: AgentOutput;\n #trackPublishedFut = new Future();\n #pendingAgentReply?: SpeechHandle;\n #agentReplyTask?: CancellablePromise<void>;\n #playingSpeech?: SpeechHandle;\n transcribedText = '';\n #transcribedInterimText = '';\n #speechQueueOpen = new Future();\n #speechQueue = new AsyncIterableQueue<SpeechHandle | typeof VoicePipelineAgent.FLUSH_SENTINEL>();\n #updateStateTask?: CancellablePromise<void>;\n #started = false;\n #room?: Room;\n #participant: RemoteParticipant | string | null = null;\n #deferredValidation: DeferredReplyValidation;\n #logger = log();\n #agentPublication?: LocalTrackPublication;\n #lastFinalTranscriptTime?: number;\n #lastSpeechTime?: number;\n #transcriptionId?: string;\n #agentTranscribedText = '';\n\n constructor(\n /** Voice Activity Detection instance. */\n vad: VAD,\n /** Speech-to-Text instance. */\n stt: STT,\n /** Large Language Model instance. */\n llm: LLM,\n /** Text-to-Speech instance. */\n tts: TTS,\n /** Additional VoicePipelineAgent options. */\n opts: Partial<VPAOptions> = defaultVPAOptions,\n ) {\n super();\n\n this.#opts = { ...defaultVPAOptions, ...opts };\n\n if (!stt.capabilities.streaming) {\n stt = new STTStreamAdapter(stt, vad);\n }\n\n if (!tts.capabilities.streaming) {\n tts = new TTSStreamAdapter(tts, new BasicSentenceTokenizer());\n }\n\n this.#vad = vad;\n this.#stt = stt;\n this.#llm = llm;\n this.#tts = tts;\n\n this.#deferredValidation = new DeferredReplyValidation(\n this.#validateReplyIfPossible.bind(this),\n this.#opts.minEndpointingDelay,\n this,\n this.#opts.turnDetector,\n );\n }\n\n get fncCtx(): FunctionContext | undefined {\n return this.#opts.fncCtx;\n }\n\n set fncCtx(ctx: FunctionContext) {\n this.#opts.fncCtx = ctx;\n }\n\n get chatCtx(): ChatContext {\n return this.#opts.chatCtx!;\n }\n\n get llm(): LLM {\n return this.#llm;\n }\n\n get tts(): TTS {\n return this.#tts;\n }\n\n get stt(): STT {\n return this.#stt;\n }\n\n get vad(): VAD {\n return this.#vad;\n }\n\n /** Start the voice assistant. */\n start(\n /** The room to connect to. */\n room: Room,\n /**\n * The participant to listen to.\n *\n * @remarks\n * Can be a participant or an identity.\n * If omitted, the first participant in the room will be selected.\n */\n participant: RemoteParticipant | string | null = null,\n ) {\n if (this.#started) {\n throw new Error('voice assistant already started');\n }\n\n this.#stt.on(SpeechEventType.METRICS_COLLECTED, (metrics) => {\n this.emit(VPAEvent.METRICS_COLLECTED, metrics);\n });\n\n this.#tts.on(TTSEvent.METRICS_COLLECTED, (metrics) => {\n if (!speechData) return;\n this.emit(VPAEvent.METRICS_COLLECTED, { ...metrics, sequenceId: speechData.sequenceId });\n });\n\n this.#llm.on(LLMEvent.METRICS_COLLECTED, (metrics) => {\n if (!speechData) return;\n this.emit(VPAEvent.METRICS_COLLECTED, { ...metrics, sequenceId: speechData.sequenceId });\n });\n\n this.#vad.on(VADEventType.METRICS_COLLECTED, (metrics) => {\n this.emit(VPAEvent.METRICS_COLLECTED, metrics);\n });\n\n room.on(RoomEvent.ParticipantConnected, (participant: RemoteParticipant) => {\n // automatically link to the first participant that connects, if not already linked\n if (this.#participant) {\n return;\n }\n this.#linkParticipant.call(this, participant.identity!);\n });\n\n this.#room = room;\n this.#participant = participant;\n\n if (participant) {\n if (typeof participant === 'string') {\n this.#linkParticipant(participant);\n } else {\n this.#linkParticipant(participant.identity!);\n }\n }\n\n this.#run();\n }\n\n /** Play a speech source through the voice assistant. */\n async say(\n source: string | LLMStream | AsyncIterable<string>,\n allowInterruptions = true,\n addToChatCtx = true,\n ): Promise<SpeechHandle> {\n await this.#trackPublishedFut.await;\n\n let callContext: AgentCallContext | undefined;\n let fncSource: string | AsyncIterable<string> | undefined;\n if (addToChatCtx) {\n callContext = AgentCallContext.getCurrent();\n if (source instanceof LLMStream) {\n this.#logger.warn('LLMStream will be ignored for function call chat context');\n } else if (typeof source === 'string') {\n fncSource = source;\n } else {\n fncSource = source;\n source = new AsyncIterableQueue<string>();\n }\n }\n\n const newHandle = SpeechHandle.createAssistantSpeech(allowInterruptions, addToChatCtx);\n const synthesisHandle = this.#synthesizeAgentSpeech(newHandle.id, source);\n newHandle.initialize(source, synthesisHandle);\n\n if (this.#playingSpeech && !this.#playingSpeech.nestedSpeechFinished) {\n this.#playingSpeech.addNestedSpeech(newHandle);\n } else {\n this.#addSpeechForPlayout(newHandle);\n }\n\n if (callContext && fncSource) {\n let text: string;\n if (typeof source === 'string') {\n text = fncSource as string;\n } else {\n text = '';\n for await (const chunk of fncSource) {\n (source as AsyncIterableQueue<string>).put(chunk);\n text += chunk;\n }\n (source as AsyncIterableQueue<string>).close();\n }\n\n callContext.addExtraChatMessage(ChatMessage.create({ text, role: ChatRole.ASSISTANT }));\n this.#logger.child({ text }).debug('added speech to function call chat context');\n }\n\n return newHandle;\n }\n\n #updateState(state: AgentState, delay = 0) {\n const runTask = (delay: number): CancellablePromise<void> => {\n return new CancellablePromise(async (resolve, _, onCancel) => {\n let cancelled = false;\n onCancel(() => {\n cancelled = true;\n });\n await new Promise((resolve) => setTimeout(resolve, delay));\n if (this.#room?.isConnected) {\n if (!cancelled) {\n await this.#room.localParticipant?.setAttributes({ [AGENT_STATE_ATTRIBUTE]: state });\n }\n }\n resolve();\n });\n };\n\n if (this.#updateStateTask) {\n this.#updateStateTask.cancel();\n }\n\n this.#updateStateTask = runTask(delay);\n }\n\n #linkParticipant(participantIdentity: string): void {\n if (!this.#room) {\n this.#logger.error('Room is not set');\n return;\n }\n\n this.#participant = this.#room.remoteParticipants.get(participantIdentity) || null;\n if (!this.#participant) {\n this.#logger.error(`Participant with identity ${participantIdentity} not found`);\n return;\n }\n\n this.#humanInput = new HumanInput(this.#room, this.#vad, this.#stt, this.#participant);\n this.#humanInput.on(HumanInputEvent.START_OF_SPEECH, (event) => {\n this.emit(VPAEvent.USER_STARTED_SPEAKING);\n this.#deferredValidation.onHumanStartOfSpeech(event);\n });\n this.#humanInput.on(HumanInputEvent.VAD_INFERENCE_DONE, (event) => {\n if (!this.#trackPublishedFut.done) {\n return;\n }\n if (!this.#agentOutput) {\n throw new Error('agent output is undefined');\n }\n\n let tv = 1;\n if (this.#opts.allowInterruptions) {\n tv = Math.max(0, 1 - event.probability);\n this.#agentOutput.playout.targetVolume = tv;\n }\n\n if (event.speechDuration >= this.#opts.interruptSpeechDuration) {\n this.#interruptIfPossible();\n }\n\n if (event.rawAccumulatedSpeech > 0) {\n this.#lastSpeechTime = Date.now() - event.rawAccumulatedSilence;\n }\n });\n this.#humanInput.on(HumanInputEvent.END_OF_SPEECH, (event) => {\n this.emit(VPAEvent.USER_STOPPED_SPEAKING);\n this.#deferredValidation.onHumanEndOfSpeech(event);\n });\n this.#humanInput.on(HumanInputEvent.INTERIM_TRANSCRIPT, (event) => {\n if (!this.#transcriptionId) {\n this.#transcriptionId = randomUUID();\n }\n this.#transcribedInterimText = event.alternatives![0].text;\n\n this.#room!.localParticipant!.publishTranscription({\n participantIdentity: this.#humanInput!.participant.identity,\n trackSid: this.#humanInput!.subscribedTrack!.sid!,\n segments: [\n {\n text: this.#transcribedInterimText,\n id: this.#transcriptionId,\n final: true,\n startTime: BigInt(0),\n endTime: BigInt(0),\n language: '',\n },\n ],\n });\n });\n this.#humanInput.on(HumanInputEvent.FINAL_TRANSCRIPT, (event) => {\n const newTranscript = event.alternatives![0].text;\n if (!newTranscript) return;\n\n if (!this.#transcriptionId) {\n this.#transcriptionId = randomUUID();\n }\n\n this.#lastFinalTranscriptTime = Date.now();\n this.transcribedText += (this.transcribedText ? ' ' : '') + newTranscript;\n\n this.#room!.localParticipant!.publishTranscription({\n participantIdentity: this.#humanInput!.participant.identity,\n trackSid: this.#humanInput!.subscribedTrack!.sid!,\n segments: [\n {\n text: this.transcribedText,\n id: this.#transcriptionId,\n final: true,\n startTime: BigInt(0),\n endTime: BigInt(0),\n language: '',\n },\n ],\n });\n this.#transcriptionId = undefined;\n\n if (\n this.#opts.preemptiveSynthesis &&\n (!this.#playingSpeech || this.#playingSpeech.allowInterruptions)\n ) {\n this.#synthesizeAgentReply();\n }\n\n this.#deferredValidation.onHumanFinalTranscript(newTranscript);\n\n const words = this.#opts.transcription.wordTokenizer.tokenize(newTranscript);\n if (words.length >= 3) {\n // VAD can sometimes not detect that the human is speaking.\n // to make the interruption more reliable, we also interrupt on the final transcript.\n this.#interruptIfPossible();\n }\n });\n }\n\n async #run() {\n this.#updateState('initializing');\n const audioSource = new AudioSource(this.#tts.sampleRate, this.#tts.numChannels);\n const track = LocalAudioTrack.createAudioTrack('assistant_voice', audioSource);\n this.#agentPublication = await this.#room?.localParticipant?.publishTrack(\n track,\n new TrackPublishOptions({ source: TrackSource.SOURCE_MICROPHONE }),\n );\n\n const agentPlayout = new AgentPlayout(audioSource);\n this.#agentOutput = new AgentOutput(agentPlayout, this.#tts);\n\n agentPlayout.on(AgentPlayoutEvent.PLAYOUT_STARTED, () => {\n this.emit(VPAEvent.AGENT_STARTED_SPEAKING);\n this.#updateState('speaking');\n });\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n agentPlayout.on(AgentPlayoutEvent.PLAYOUT_STOPPED, (_) => {\n this.emit(VPAEvent.AGENT_STOPPED_SPEAKING);\n this.#updateState('listening');\n });\n\n this.#trackPublishedFut.resolve();\n\n while (true) {\n await this.#speechQueueOpen.await;\n for await (const speech of this.#speechQueue) {\n if (speech === VoicePipelineAgent.FLUSH_SENTINEL) break;\n this.#playingSpeech = speech;\n await this.#playSpeech(speech);\n this.#playingSpeech = undefined;\n }\n this.#speechQueueOpen = new Future();\n }\n }\n\n #synthesizeAgentReply() {\n this.#pendingAgentReply?.cancel();\n if (this.#humanInput && this.#humanInput.speaking) {\n this.#updateState('thinking', 200);\n }\n\n this.#pendingAgentReply = SpeechHandle.createAssistantReply(\n this.#opts.allowInterruptions,\n true,\n this.transcribedText,\n );\n const newHandle = this.#pendingAgentReply;\n this.#agentReplyTask = this.#synthesizeAnswerTask(this.#agentReplyTask, newHandle);\n }\n\n #synthesizeAnswerTask(\n oldTask: CancellablePromise<void> | undefined,\n handle?: SpeechHandle,\n ): CancellablePromise<void> {\n return new CancellablePromise(async (resolve, _, onCancel) => {\n let cancelled = false;\n onCancel(() => {\n cancelled = true;\n });\n\n if (oldTask) {\n await gracefullyCancel(oldTask);\n }\n\n const copiedCtx = this.chatCtx.copy();\n const playingSpeech = this.#playingSpeech;\n if (playingSpeech && playingSpeech.initialized) {\n if (\n (!playingSpeech.userQuestion || playingSpeech.userCommitted) &&\n !playingSpeech.speechCommitted\n ) {\n // the speech is playing but not committed yet,\n // add it to the chat context for this new reply synthesis\n copiedCtx.messages.push(\n ChatMessage.create({\n text: playingSpeech.synthesisHandle.text,\n role: ChatRole.ASSISTANT,\n }),\n );\n }\n }\n\n copiedCtx.messages.push(\n ChatMessage.create({\n text: handle?.userQuestion,\n role: ChatRole.USER,\n }),\n );\n\n speechData = { sequenceId: handle!.id };\n\n try {\n if (cancelled) resolve();\n let llmStream = await this.#opts.beforeLLMCallback(this, copiedCtx);\n if (llmStream === false) {\n handle?.cancel();\n return;\n }\n\n if (cancelled) resolve();\n // fallback to default impl if no custom/user stream is returned\n if (!(llmStream instanceof LLMStream)) {\n llmStream = (await defaultBeforeLLMCallback(this, copiedCtx)) as LLMStream;\n }\n\n if (handle!.interrupted) {\n return;\n }\n\n const synthesisHandle = this.#synthesizeAgentSpeech(handle!.id, llmStream);\n handle!.initialize(llmStream, synthesisHandle);\n } finally {\n speechData = undefined;\n }\n resolve();\n });\n }\n\n async #playSpeech(handle: SpeechHandle) {\n try {\n await handle.waitForInitialization();\n } catch {\n return;\n }\n await this.#agentPublication!.waitForSubscription();\n const synthesisHandle = handle.synthesisHandle;\n if (synthesisHandle.interrupted) return;\n\n const userQuestion = handle.userQuestion;\n const playHandle = synthesisHandle.play();\n const joinFut = playHandle.join();\n\n const commitUserQuestionIfNeeded = () => {\n if (!userQuestion || synthesisHandle.interrupted || handle.userCommitted) return;\n const isUsingTools =\n handle.source instanceof LLMStream && !!handle.source.functionCalls.length;\n\n // make sure at least some speech was played before committing the user message\n // since we try to validate as fast as possible it is possible the agent gets interrupted\n // really quickly (barely audible), we don't want to mark this question as \"answered\".\n if (\n handle.allowInterruptions &&\n !isUsingTools &&\n playHandle.timePlayed < this.MIN_TIME_PLAYED_FOR_COMMIT &&\n !joinFut.done\n ) {\n return;\n }\n\n this.#logger.child({ userTranscript: userQuestion }).debug('committed user transcript');\n const userMsg = ChatMessage.create({ text: userQuestion, role: ChatRole.USER });\n this.chatCtx.messages.push(userMsg);\n this.emit(VPAEvent.USER_SPEECH_COMMITTED, userMsg);\n\n this.transcribedText = this.transcribedText.slice(userQuestion.length);\n handle.markUserCommitted();\n };\n\n // wait for the playHandle to finish and check every 1s if user question should be committed\n commitUserQuestionIfNeeded();\n\n while (!joinFut.done) {\n await new Promise<void>(async (resolve) => {\n setTimeout(resolve, 500);\n await joinFut.await;\n resolve();\n });\n commitUserQuestionIfNeeded();\n if (handle.interrupted) break;\n }\n commitUserQuestionIfNeeded();\n\n let collectedText = this.#agentTranscribedText;\n const isUsingTools = handle.source instanceof LLMStream && !!handle.source.functionCalls.length;\n const interrupted = handle.interrupted;\n\n if (handle.addToChatCtx && (!userQuestion || handle.userCommitted)) {\n if (handle.extraToolsMessages) {\n this.chatCtx.messages.push(...handle.extraToolsMessages);\n }\n if (interrupted) {\n collectedText += '…';\n }\n\n const msg = ChatMessage.create({ text: collectedText, role: ChatRole.ASSISTANT });\n this.chatCtx.messages.push(msg);\n\n handle.markSpeechCommitted();\n if (interrupted) {\n this.emit(VPAEvent.AGENT_SPEECH_INTERRUPTED, msg);\n } else {\n this.emit(VPAEvent.AGENT_SPEECH_COMMITTED, msg);\n }\n\n this.#logger\n .child({\n agentTranscript: collectedText,\n interrupted,\n speechId: handle.id,\n })\n .debug('committed agent speech');\n\n handle.setDone();\n }\n\n const executeFunctionCalls = async () => {\n // if the answer is using tools, execute the functions and automatically generate\n // a response to the user question from the returned values\n if (!isUsingTools || interrupted) return;\n\n if (handle.fncNestedDepth >= this.#opts.maxNestedFncCalls) {\n this.#logger\n .child({ speechId: handle.id, fncNestedDepth: handle.fncNestedDepth })\n .warn('max function calls nested depth reached');\n return;\n }\n\n if (userQuestion && !handle.userCommitted) {\n throw new Error('user speech should have been committed before using tools');\n }\n const llmStream = handle.source;\n const newFunctionCalls = llmStream.functionCalls;\n\n new AgentCallContext(this, llmStream);\n\n this.emit(VPAEvent.FUNCTION_CALLS_COLLECTED, newFunctionCalls);\n const calledFuncs: FunctionCallInfo[] = [];\n for (const func of newFunctionCalls) {\n const task = func.func.execute(func.params).then(\n (result) => ({ name: func.name, toolCallId: func.toolCallId, result }),\n (error) => ({ name: func.name, toolCallId: func.toolCallId, error }),\n );\n calledFuncs.push({ ...func, task });\n this.#logger\n .child({ function: func.name, speechId: handle.id })\n .debug('executing AI function');\n try {\n await task;\n } catch {\n this.#logger\n .child({ function: func.name, speechId: handle.id })\n .error('error executing AI function');\n }\n }\n\n const toolCallsInfo = [];\n const toolCallsResults = [];\n for (const fnc of calledFuncs) {\n // ignore the function calls that return void\n const task = await fnc.task;\n if (!task || task.result === undefined) continue;\n toolCallsInfo.push(fnc);\n toolCallsResults.push(ChatMessage.createToolFromFunctionResult(task));\n }\n\n if (!toolCallsInfo.length) return;\n\n // generate an answer from the tool calls\n const extraToolsMessages = [ChatMessage.createToolCalls(toolCallsInfo, collectedText)];\n extraToolsMessages.push(...toolCallsResults);\n\n // create a nested speech handle\n const newSpeechHandle = SpeechHandle.createToolSpeech(\n handle.allowInterruptions,\n handle.addToChatCtx,\n handle.fncNestedDepth + 1,\n extraToolsMessages,\n );\n\n // synthesize the tool speech with the chat ctx from llmStream\n const chatCtx = handle.source.chatCtx.copy();\n chatCtx.messages.push(...extraToolsMessages);\n chatCtx.messages.push(...AgentCallContext.getCurrent().extraChatMessages);\n\n const answerLLMStream = this.llm.chat({\n chatCtx,\n fncCtx: this.fncCtx,\n });\n\n const answerSynthesis = this.#synthesizeAgentSpeech(newSpeechHandle.id, answerLLMStream);\n newSpeechHandle.initialize(answerLLMStream, answerSynthesis);\n handle.addNestedSpeech(newSpeechHandle);\n\n this.emit(VPAEvent.FUNCTION_CALLS_FINISHED, calledFuncs);\n };\n\n let finished = false;\n const task = executeFunctionCalls().then(() => {\n finished = true;\n });\n while (!handle.nestedSpeechFinished) {\n const changed = handle.nestedSpeechChanged();\n await Promise.race([changed, task]);\n while (handle.nestedSpeechHandles.length) {\n const speech = handle.nestedSpeechHandles[0]!;\n this.#playingSpeech = speech;\n await this.#playSpeech(speech);\n handle.nestedSpeechHandles.shift();\n this.#playingSpeech = handle;\n }\n\n handle.nestedSpeechHandles.forEach(() => handle.nestedSpeechHandles.pop());\n if (finished) {\n handle.markNestedSpeechFinished();\n }\n }\n handle.setDone();\n }\n\n #synthesizeAgentSpeech(\n speechId: string,\n source: string | LLMStream | AsyncIterable<string>,\n ): SynthesisHandle {\n const synchronizer = new TextAudioSynchronizer(defaultTextSyncOptions);\n synchronizer.on('textUpdated', (text) => {\n this.#agentTranscribedText = text.text;\n this.#room!.localParticipant!.publishTranscription({\n participantIdentity: this.#room!.localParticipant!.identity,\n trackSid: this.#agentPublication!.sid!,\n segments: [text],\n });\n });\n\n if (!this.#agentOutput) {\n throw new Error('agent output should be initialized when ready');\n }\n\n if (source instanceof LLMStream) {\n source = llmStreamToStringIterable(speechId, source);\n }\n\n const ogSource = source;\n if (!(typeof source === 'string')) {\n // TODO(nbsp): itertools.tee\n }\n\n const ttsSource = this.#opts.beforeTTSCallback(this, ogSource);\n if (!ttsSource) {\n throw new Error('beforeTTSCallback must return string or AsyncIterable<string>');\n }\n\n return this.#agentOutput.synthesize(speechId, ttsSource, synchronizer);\n }\n\n async #validateReplyIfPossible() {\n if (this.#playingSpeech && !this.#playingSpeech.allowInterruptions) {\n this.#logger\n .child({ speechId: this.#playingSpeech.id })\n .debug('skipping validation, agent is speaking and does not allow interruptions');\n return;\n }\n\n if (!this.#pendingAgentReply) {\n if (this.#opts.preemptiveSynthesis || !this.transcribedText) {\n return;\n }\n this.#synthesizeAgentReply();\n }\n\n if (!this.#pendingAgentReply) {\n throw new Error('pending agent reply is undefined');\n }\n\n // in some bad timimg, we could end up with two pushed agent replies inside the speech queue.\n // so make sure we directly interrupt every reply when validating a new one\n if (this.#speechQueueOpen.done) {\n for await (const speech of this.#speechQueue) {\n if (speech === VoicePipelineAgent.FLUSH_SENTINEL) break;\n if (!speech.isReply) continue;\n if (speech.allowInterruptions) speech.interrupt();\n }\n }\n\n this.#logger.child({ speechId: this.#pendingAgentReply.id }).debug('validated agent reply');\n\n if (this.#lastSpeechTime) {\n const timeSinceLastSpeech = Date.now() - this.#lastSpeechTime;\n const transcriptionDelay = Math.max(\n (this.#lastFinalTranscriptTime || 0) - this.#lastSpeechTime,\n 0,\n );\n const metrics: PipelineEOUMetrics = {\n timestamp: Date.now(),\n sequenceId: this.#pendingAgentReply.id,\n endOfUtteranceDelay: timeSinceLastSpeech,\n transcriptionDelay,\n };\n this.emit(VPAEvent.METRICS_COLLECTED, metrics);\n }\n\n this.#addSpeechForPlayout(this.#pendingAgentReply);\n this.#pendingAgentReply = undefined;\n this.#transcribedInterimText = '';\n }\n\n #interruptIfPossible() {\n if (\n !this.#playingSpeech ||\n !this.#playingSpeech.allowInterruptions ||\n this.#playingSpeech.interrupted\n ) {\n return;\n }\n\n if (this.#opts.interruptMinWords !== 0) {\n // check the final/interim transcribed text for the minimum word count\n // to interrupt the agent speech\n const interimWords = this.#opts.transcription.wordTokenizer.tokenize(\n this.#transcribedInterimText,\n );\n if (interimWords.length < this.#opts.interruptMinWords) {\n return;\n }\n }\n this.#playingSpeech.interrupt();\n }\n\n #addSpeechForPlayout(handle: SpeechHandle) {\n this.#speechQueue.put(handle);\n this.#speechQueue.put(VoicePipelineAgent.FLUSH_SENTINEL);\n this.#speechQueueOpen.resolve();\n }\n\n /** Close the voice assistant. */\n async close() {\n if (!this.#started) {\n return;\n }\n\n this.#room?.removeAllListeners(RoomEvent.ParticipantConnected);\n // TODO(nbsp): await this.#deferredValidation.close()\n }\n}\n\nasync function* llmStreamToStringIterable(\n speechId: string,\n stream: LLMStream,\n): AsyncIterable<string> {\n const startTime = Date.now();\n let firstFrame = true;\n for await (const chunk of stream) {\n const content = chunk.choices[0]?.delta.content;\n if (!content) continue;\n\n if (firstFrame) {\n firstFrame = false;\n log()\n .child({ speechId, elapsed: Math.round(Date.now() - startTime) })\n .debug('received first LLM token');\n }\n yield content;\n }\n}\n\n/** This class is used to try to find the best time to validate the agent reply. */\nclass DeferredReplyValidation {\n // if the STT gives us punctuation, we can try to validate the reply faster.\n readonly PUNCTUATION = '.!?';\n readonly PUNCTUATION_REDUCE_FACTOR = 0.75;\n readonly LATE_TRANSCRIPT_TOLERANCE = 1.5; // late compared to end of speech\n readonly UNLIKELY_ENDPOINT_DELAY = 6000;\n\n #validateFunc: () => Promise<void>;\n #validatingPromise?: Promise<void>;\n #validatingFuture = new Future();\n #lastFinalTranscript = '';\n #lastRecvEndOfSpeechTime = 0;\n #speaking = false;\n #endOfSpeechDelay: number;\n #finalTranscriptDelay: number;\n #turnDetector?: TurnDetector;\n #agent: VoicePipelineAgent;\n #abort?: AbortController;\n\n constructor(\n validateFunc: () => Promise<void>,\n minEndpointingDelay: number,\n agent: VoicePipelineAgent,\n turnDetector?: TurnDetector,\n ) {\n this.#validateFunc = validateFunc;\n this.#endOfSpeechDelay = minEndpointingDelay;\n this.#finalTranscriptDelay = minEndpointingDelay;\n this.#agent = agent;\n this.#turnDetector = turnDetector;\n }\n\n get validating(): boolean {\n return !this.#validatingFuture.done;\n }\n\n onHumanFinalTranscript(transcript: string) {\n this.#lastFinalTranscript = transcript.trim();\n if (this.#speaking) return;\n\n const hasRecentEndOfSpeech =\n Date.now() - this.#lastRecvEndOfSpeechTime < this.LATE_TRANSCRIPT_TOLERANCE;\n let delay = hasRecentEndOfSpeech ? this.#endOfSpeechDelay : this.#finalTranscriptDelay;\n delay = this.#endWithPunctuation() ? delay * this.PUNCTUATION_REDUCE_FACTOR : 1;\n\n this.#run(delay);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onHumanStartOfSpeech(_: VADEvent) {\n this.#speaking = true;\n if (this.validating) {\n this.#abort?.abort();\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onHumanEndOfSpeech(_: VADEvent) {\n this.#speaking = false;\n this.#lastRecvEndOfSpeechTime = Date.now();\n\n if (this.#lastFinalTranscript) {\n const delay = this.#endWithPunctuation()\n ? this.#endOfSpeechDelay * this.PUNCTUATION_REDUCE_FACTOR\n : 1_000;\n this.#run(delay);\n }\n }\n\n // TODO(nbsp): aclose\n\n #endWithPunctuation(): boolean {\n return (\n this.#lastFinalTranscript.length > 0 &&\n this.PUNCTUATION.includes(this.#lastFinalTranscript[this.#lastFinalTranscript.length - 1]!)\n );\n }\n\n #resetStates() {\n this.#lastFinalTranscript = '';\n this.#lastRecvEndOfSpeechTime = 0;\n }\n\n #run(delay: number) {\n const runTask = async (delay: number, chatCtx: ChatContext, signal: AbortSignal) => {\n if (this.#lastFinalTranscript && !this.#speaking && this.#turnDetector) {\n const startTime = Date.now();\n const eotProb = await this.#turnDetector.predictEndOfTurn(chatCtx);\n const unlikelyThreshold = this.#turnDetector.unlikelyThreshold;\n const elapsed = Date.now() - startTime;\n if (eotProb < unlikelyThreshold) {\n delay = this.UNLIKELY_ENDPOINT_DELAY;\n }\n delay = Math.max(0, delay - elapsed);\n }\n const timeout = setTimeout(() => {\n this.#resetStates();\n this.#validateFunc();\n }, delay);\n signal.addEventListener('abort', () => {\n clearTimeout(timeout);\n });\n };\n\n this.#abort?.abort();\n this.#abort = new AbortController();\n this.#validatingFuture = new Future();\n const detectCtx = this.#agent.chatCtx.copy();\n detectCtx.append({ text: this.#agent.transcribedText, role: ChatRole.USER });\n this.#validatingPromise = runTask(delay, detectCtx, this.#abort.signal);\n }\n}\n"],"mappings":"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","names":["VPAEvent","participant","delay","resolve","isUsingTools","task"]}
1
+ {"version":3,"sources":["../../src/pipeline/pipeline_agent.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type {\n LocalTrackPublication,\n NoiseCancellationOptions,\n RemoteParticipant,\n Room,\n} from '@livekit/rtc-node';\nimport {\n AudioSource,\n LocalAudioTrack,\n RoomEvent,\n TrackPublishOptions,\n TrackSource,\n} from '@livekit/rtc-node';\nimport type { TypedEventEmitter as TypedEmitter } from '@livekit/typed-emitter';\nimport { randomUUID } from 'node:crypto';\nimport EventEmitter from 'node:events';\nimport type {\n CallableFunctionResult,\n FunctionCallInfo,\n FunctionContext,\n LLM,\n} from '../llm/index.js';\nimport { LLMEvent, LLMStream } from '../llm/index.js';\nimport { ChatContext, ChatMessage, ChatRole } from '../llm/index.js';\nimport { log } from '../log.js';\nimport type { AgentMetrics, PipelineEOUMetrics } from '../metrics/base.js';\nimport { type STT, StreamAdapter as STTStreamAdapter, SpeechEventType } from '../stt/index.js';\nimport {\n SentenceTokenizer as BasicSentenceTokenizer,\n WordTokenizer as BasicWordTokenizer,\n hyphenateWord,\n} from '../tokenize/basic/index.js';\nimport type { SentenceTokenizer, WordTokenizer } from '../tokenize/tokenizer.js';\nimport { TextAudioSynchronizer, defaultTextSyncOptions } from '../transcription.js';\nimport type { TTS } from '../tts/index.js';\nimport { TTSEvent, StreamAdapter as TTSStreamAdapter } from '../tts/index.js';\nimport { AsyncIterableQueue, CancellablePromise, Future, gracefullyCancel } from '../utils.js';\nimport { type VAD, type VADEvent, VADEventType } from '../vad.js';\nimport type { SpeechSource, SynthesisHandle } from './agent_output.js';\nimport { AgentOutput } from './agent_output.js';\nimport { AgentPlayout, AgentPlayoutEvent } from './agent_playout.js';\nimport { HumanInput, HumanInputEvent } from './human_input.js';\nimport { SpeechHandle } from './speech_handle.js';\n\nexport type AgentState = 'initializing' | 'thinking' | 'listening' | 'speaking';\nexport const AGENT_STATE_ATTRIBUTE = 'lk.agent.state';\nlet speechData: { sequenceId: string } | undefined;\n\nexport type BeforeLLMCallback = (\n agent: VoicePipelineAgent,\n chatCtx: ChatContext,\n) => LLMStream | false | void | Promise<LLMStream | false | void>;\n\nexport type BeforeTTSCallback = (\n agent: VoicePipelineAgent,\n source: string | AsyncIterable<string>,\n) => SpeechSource;\n\nexport enum VPAEvent {\n USER_STARTED_SPEAKING,\n USER_STOPPED_SPEAKING,\n AGENT_STARTED_SPEAKING,\n AGENT_STOPPED_SPEAKING,\n USER_SPEECH_COMMITTED,\n AGENT_SPEECH_COMMITTED,\n AGENT_SPEECH_INTERRUPTED,\n FUNCTION_CALLS_COLLECTED,\n FUNCTION_CALLS_FINISHED,\n METRICS_COLLECTED,\n}\n\nexport type VPACallbacks = {\n [VPAEvent.USER_STARTED_SPEAKING]: () => void;\n [VPAEvent.USER_STOPPED_SPEAKING]: () => void;\n [VPAEvent.AGENT_STARTED_SPEAKING]: () => void;\n [VPAEvent.AGENT_STOPPED_SPEAKING]: () => void;\n [VPAEvent.USER_SPEECH_COMMITTED]: (msg: ChatMessage) => void;\n [VPAEvent.AGENT_SPEECH_COMMITTED]: (msg: ChatMessage) => void;\n [VPAEvent.AGENT_SPEECH_INTERRUPTED]: (msg: ChatMessage) => void;\n [VPAEvent.FUNCTION_CALLS_COLLECTED]: (funcs: FunctionCallInfo[]) => void;\n [VPAEvent.FUNCTION_CALLS_FINISHED]: (funcs: CallableFunctionResult[]) => void;\n [VPAEvent.METRICS_COLLECTED]: (metrics: AgentMetrics) => void;\n};\n\ninterface TurnDetector {\n unlikelyThreshold: number;\n supportsLanguage: (language?: string) => boolean;\n predictEndOfTurn: (chatCtx: ChatContext) => Promise<number>;\n}\n\nexport class AgentCallContext {\n #agent: VoicePipelineAgent;\n #llmStream: LLMStream;\n #metadata = new Map<string, any>();\n #extraChatMessages: ChatMessage[] = [];\n static #current: AgentCallContext;\n\n constructor(agent: VoicePipelineAgent, llmStream: LLMStream) {\n this.#agent = agent;\n this.#llmStream = llmStream;\n AgentCallContext.#current = this;\n }\n\n static getCurrent(): AgentCallContext {\n return AgentCallContext.#current;\n }\n\n get agent(): VoicePipelineAgent {\n return this.#agent;\n }\n\n storeMetadata(key: string, value: any) {\n this.#metadata.set(key, value);\n }\n\n getMetadata(key: string, orDefault: any = undefined) {\n return this.#metadata.get(key) || orDefault;\n }\n\n get llmStream(): LLMStream {\n return this.#llmStream;\n }\n\n get extraChatMessages() {\n return this.#extraChatMessages;\n }\n\n addExtraChatMessage(message: ChatMessage) {\n this.#extraChatMessages.push(message);\n }\n}\n\nconst defaultBeforeLLMCallback: BeforeLLMCallback = (\n agent: VoicePipelineAgent,\n chatCtx: ChatContext,\n): LLMStream => {\n return agent.llm.chat({ chatCtx, fncCtx: agent.fncCtx });\n};\n\nconst defaultBeforeTTSCallback: BeforeTTSCallback = (\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _: VoicePipelineAgent,\n text: string | AsyncIterable<string>,\n): string | AsyncIterable<string> => {\n return text;\n};\n\nexport interface AgentTranscriptionOptions {\n /** Whether to forward the user transcription to the client */\n userTranscription: boolean;\n /** Whether to forward the agent transcription to the client */\n agentTranscription: boolean;\n /**\n * The speed at which the agent's speech transcription is forwarded to the client.\n * We try to mimic the agent's speech speed by adjusting the transcription speed.\n */\n agentTranscriptionSpeech: number;\n /**\n * The tokenizer used to split the speech into sentences.\n * This is used to decide when to mark a transcript as final for the agent transcription.\n */\n sentenceTokenizer: SentenceTokenizer;\n /**\n * The tokenizer used to split the speech into words.\n * This is used to simulate the \"interim results\" of the agent transcription.\n */\n wordTokenizer: WordTokenizer;\n /**\n * A function that takes a string (word) as input and returns a list of strings,\n * representing the hyphenated parts of the word.\n */\n hyphenateWord: (word: string) => string[];\n}\n\nconst defaultAgentTranscriptionOptions: AgentTranscriptionOptions = {\n userTranscription: true,\n agentTranscription: true,\n agentTranscriptionSpeech: 1,\n sentenceTokenizer: new BasicSentenceTokenizer(),\n wordTokenizer: new BasicWordTokenizer(false),\n hyphenateWord: hyphenateWord,\n};\n\nexport interface VPAOptions {\n /** Chat context for the assistant. */\n chatCtx?: ChatContext;\n /** Function context for the assistant. */\n fncCtx?: FunctionContext;\n /** Whether to allow the user to interrupt the assistant. */\n allowInterruptions: boolean;\n /** Minimum duration of speech to consider for interruption. */\n interruptSpeechDuration: number;\n /** Minimum number of words to consider for interuption. This may increase latency. */\n interruptMinWords: number;\n /** Delay to wait before considering the user speech done. */\n minEndpointingDelay: number;\n maxNestedFncCalls: number;\n /* Whether to preemptively synthesize responses. */\n preemptiveSynthesis: boolean;\n /*\n * Callback called when the assistant is about to synthesize a reply.\n *\n * @remarks\n * Returning void will create a default LLM stream.\n * You can also return your own LLM stream by calling `llm.chat()`.\n * Returning `false` ill cancel the synthesis of the reply.\n */\n beforeLLMCallback: BeforeLLMCallback;\n /*\n * Callback called when the assistant is about to synthesize speech.\n *\n * @remarks\n * This can be used to customize text before synthesis\n * (e.g. editing the pronunciation of a word).\n */\n beforeTTSCallback: BeforeTTSCallback;\n /** Options for assistant transcription. */\n transcription: AgentTranscriptionOptions;\n /** Turn detection model to use. */\n turnDetector?: TurnDetector;\n /** Noise cancellation options. */\n noiseCancellation?: NoiseCancellationOptions;\n}\n\nconst defaultVPAOptions: VPAOptions = {\n chatCtx: new ChatContext(),\n allowInterruptions: true,\n interruptSpeechDuration: 50,\n interruptMinWords: 0,\n minEndpointingDelay: 500,\n maxNestedFncCalls: 1,\n preemptiveSynthesis: false,\n beforeLLMCallback: defaultBeforeLLMCallback,\n beforeTTSCallback: defaultBeforeTTSCallback,\n transcription: defaultAgentTranscriptionOptions,\n};\n\n/** A pipeline agent (VAD + STT + LLM + TTS) implementation. */\nexport class VoicePipelineAgent extends (EventEmitter as new () => TypedEmitter<VPACallbacks>) {\n /** Minimum time played for the user speech to be committed to the chat context. */\n readonly MIN_TIME_PLAYED_FOR_COMMIT = 1.5;\n protected static readonly FLUSH_SENTINEL = Symbol('FLUSH_SENTINEL');\n\n #vad: VAD;\n #stt: STT;\n #llm: LLM;\n #tts: TTS;\n #opts: VPAOptions;\n #humanInput?: HumanInput;\n #agentOutput?: AgentOutput;\n #trackPublishedFut = new Future();\n #pendingAgentReply?: SpeechHandle;\n #agentReplyTask?: CancellablePromise<void>;\n #playingSpeech?: SpeechHandle;\n transcribedText = '';\n #transcribedInterimText = '';\n #speechQueueOpen = new Future();\n #speechQueue = new AsyncIterableQueue<SpeechHandle | typeof VoicePipelineAgent.FLUSH_SENTINEL>();\n #updateStateTask?: CancellablePromise<void>;\n #started = false;\n #room?: Room;\n #participant: RemoteParticipant | string | null = null;\n #deferredValidation: DeferredReplyValidation;\n #logger = log();\n #agentPublication?: LocalTrackPublication;\n #lastFinalTranscriptTime?: number;\n #lastSpeechTime?: number;\n #transcriptionId?: string;\n #agentTranscribedText = '';\n\n constructor(\n /** Voice Activity Detection instance. */\n vad: VAD,\n /** Speech-to-Text instance. */\n stt: STT,\n /** Large Language Model instance. */\n llm: LLM,\n /** Text-to-Speech instance. */\n tts: TTS,\n /** Additional VoicePipelineAgent options. */\n opts: Partial<VPAOptions> = defaultVPAOptions,\n ) {\n super();\n\n this.#opts = { ...defaultVPAOptions, ...opts };\n\n if (!stt.capabilities.streaming) {\n stt = new STTStreamAdapter(stt, vad);\n }\n\n if (!tts.capabilities.streaming) {\n tts = new TTSStreamAdapter(tts, new BasicSentenceTokenizer());\n }\n\n this.#vad = vad;\n this.#stt = stt;\n this.#llm = llm;\n this.#tts = tts;\n\n this.#deferredValidation = new DeferredReplyValidation(\n this.#validateReplyIfPossible.bind(this),\n this.#opts.minEndpointingDelay,\n this,\n this.#opts.turnDetector,\n );\n }\n\n get fncCtx(): FunctionContext | undefined {\n return this.#opts.fncCtx;\n }\n\n set fncCtx(ctx: FunctionContext) {\n this.#opts.fncCtx = ctx;\n }\n\n get chatCtx(): ChatContext {\n return this.#opts.chatCtx!;\n }\n\n get llm(): LLM {\n return this.#llm;\n }\n\n get tts(): TTS {\n return this.#tts;\n }\n\n get stt(): STT {\n return this.#stt;\n }\n\n get vad(): VAD {\n return this.#vad;\n }\n\n /** Start the voice assistant. */\n start(\n /** The room to connect to. */\n room: Room,\n /**\n * The participant to listen to.\n *\n * @remarks\n * Can be a participant or an identity.\n * If omitted, the first participant in the room will be selected.\n */\n participant: RemoteParticipant | string | null = null,\n ) {\n if (this.#started) {\n throw new Error('voice assistant already started');\n }\n\n this.#stt.on(SpeechEventType.METRICS_COLLECTED, (metrics) => {\n this.emit(VPAEvent.METRICS_COLLECTED, metrics);\n });\n\n this.#tts.on(TTSEvent.METRICS_COLLECTED, (metrics) => {\n if (!speechData) return;\n this.emit(VPAEvent.METRICS_COLLECTED, { ...metrics, sequenceId: speechData.sequenceId });\n });\n\n this.#llm.on(LLMEvent.METRICS_COLLECTED, (metrics) => {\n if (!speechData) return;\n this.emit(VPAEvent.METRICS_COLLECTED, { ...metrics, sequenceId: speechData.sequenceId });\n });\n\n this.#vad.on(VADEventType.METRICS_COLLECTED, (metrics) => {\n this.emit(VPAEvent.METRICS_COLLECTED, metrics);\n });\n\n room.on(RoomEvent.ParticipantConnected, (participant: RemoteParticipant) => {\n // automatically link to the first participant that connects, if not already linked\n if (this.#participant) {\n return;\n }\n this.#linkParticipant.call(this, participant.identity!);\n });\n\n this.#room = room;\n this.#participant = participant;\n\n if (participant) {\n if (typeof participant === 'string') {\n this.#linkParticipant(participant);\n } else {\n this.#linkParticipant(participant.identity!);\n }\n }\n\n this.#run();\n }\n\n /** Play a speech source through the voice assistant. */\n async say(\n source: string | LLMStream | AsyncIterable<string>,\n allowInterruptions = true,\n addToChatCtx = true,\n ): Promise<SpeechHandle> {\n await this.#trackPublishedFut.await;\n\n let callContext: AgentCallContext | undefined;\n let fncSource: string | AsyncIterable<string> | undefined;\n if (addToChatCtx) {\n callContext = AgentCallContext.getCurrent();\n if (source instanceof LLMStream) {\n this.#logger.warn('LLMStream will be ignored for function call chat context');\n } else if (typeof source === 'string') {\n fncSource = source;\n } else {\n fncSource = source;\n source = new AsyncIterableQueue<string>();\n }\n }\n\n const newHandle = SpeechHandle.createAssistantSpeech(allowInterruptions, addToChatCtx);\n const synthesisHandle = this.#synthesizeAgentSpeech(newHandle.id, source);\n newHandle.initialize(source, synthesisHandle);\n\n if (this.#playingSpeech && !this.#playingSpeech.nestedSpeechFinished) {\n this.#playingSpeech.addNestedSpeech(newHandle);\n } else {\n this.#addSpeechForPlayout(newHandle);\n }\n\n if (callContext && fncSource) {\n let text: string;\n if (typeof source === 'string') {\n text = fncSource as string;\n } else {\n text = '';\n for await (const chunk of fncSource) {\n (source as AsyncIterableQueue<string>).put(chunk);\n text += chunk;\n }\n (source as AsyncIterableQueue<string>).close();\n }\n\n callContext.addExtraChatMessage(ChatMessage.create({ text, role: ChatRole.ASSISTANT }));\n this.#logger.child({ text }).debug('added speech to function call chat context');\n }\n\n return newHandle;\n }\n\n #updateState(state: AgentState, delay = 0) {\n const runTask = (delay: number): CancellablePromise<void> => {\n return new CancellablePromise(async (resolve, _, onCancel) => {\n let cancelled = false;\n onCancel(() => {\n cancelled = true;\n });\n await new Promise((resolve) => setTimeout(resolve, delay));\n if (this.#room?.isConnected) {\n if (!cancelled) {\n await this.#room.localParticipant?.setAttributes({ [AGENT_STATE_ATTRIBUTE]: state });\n }\n }\n resolve();\n });\n };\n\n if (this.#updateStateTask) {\n this.#updateStateTask.cancel();\n }\n\n this.#updateStateTask = runTask(delay);\n }\n\n #linkParticipant(participantIdentity: string): void {\n if (!this.#room) {\n this.#logger.error('Room is not set');\n return;\n }\n\n this.#participant = this.#room.remoteParticipants.get(participantIdentity) || null;\n if (!this.#participant) {\n this.#logger.error(`Participant with identity ${participantIdentity} not found`);\n return;\n }\n\n this.#humanInput = new HumanInput(\n this.#room,\n this.#vad,\n this.#stt,\n this.#participant,\n this.#opts.noiseCancellation,\n );\n this.#humanInput.on(HumanInputEvent.START_OF_SPEECH, (event) => {\n this.emit(VPAEvent.USER_STARTED_SPEAKING);\n this.#deferredValidation.onHumanStartOfSpeech(event);\n });\n this.#humanInput.on(HumanInputEvent.VAD_INFERENCE_DONE, (event) => {\n if (!this.#trackPublishedFut.done) {\n return;\n }\n if (!this.#agentOutput) {\n throw new Error('agent output is undefined');\n }\n\n let tv = 1;\n if (this.#opts.allowInterruptions) {\n tv = Math.max(0, 1 - event.probability);\n this.#agentOutput.playout.targetVolume = tv;\n }\n\n if (event.speechDuration >= this.#opts.interruptSpeechDuration) {\n this.#interruptIfPossible();\n }\n\n if (event.rawAccumulatedSpeech > 0) {\n this.#lastSpeechTime = Date.now() - event.rawAccumulatedSilence;\n }\n });\n this.#humanInput.on(HumanInputEvent.END_OF_SPEECH, (event) => {\n this.emit(VPAEvent.USER_STOPPED_SPEAKING);\n this.#deferredValidation.onHumanEndOfSpeech(event);\n });\n this.#humanInput.on(HumanInputEvent.INTERIM_TRANSCRIPT, (event) => {\n if (!this.#transcriptionId) {\n this.#transcriptionId = randomUUID();\n }\n this.#transcribedInterimText = event.alternatives![0].text;\n\n this.#room!.localParticipant!.publishTranscription({\n participantIdentity: this.#humanInput!.participant.identity,\n trackSid: this.#humanInput!.subscribedTrack!.sid!,\n segments: [\n {\n text: this.#transcribedInterimText,\n id: this.#transcriptionId,\n final: true,\n startTime: BigInt(0),\n endTime: BigInt(0),\n language: '',\n },\n ],\n });\n });\n this.#humanInput.on(HumanInputEvent.FINAL_TRANSCRIPT, (event) => {\n const newTranscript = event.alternatives![0].text;\n if (!newTranscript) return;\n\n if (!this.#transcriptionId) {\n this.#transcriptionId = randomUUID();\n }\n\n this.#lastFinalTranscriptTime = Date.now();\n this.transcribedText += (this.transcribedText ? ' ' : '') + newTranscript;\n\n this.#room!.localParticipant!.publishTranscription({\n participantIdentity: this.#humanInput!.participant.identity,\n trackSid: this.#humanInput!.subscribedTrack!.sid!,\n segments: [\n {\n text: this.transcribedText,\n id: this.#transcriptionId,\n final: true,\n startTime: BigInt(0),\n endTime: BigInt(0),\n language: '',\n },\n ],\n });\n this.#transcriptionId = undefined;\n\n if (\n this.#opts.preemptiveSynthesis &&\n (!this.#playingSpeech || this.#playingSpeech.allowInterruptions)\n ) {\n this.#synthesizeAgentReply();\n }\n\n this.#deferredValidation.onHumanFinalTranscript(newTranscript);\n\n const words = this.#opts.transcription.wordTokenizer.tokenize(newTranscript);\n if (words.length >= 3) {\n // VAD can sometimes not detect that the human is speaking.\n // to make the interruption more reliable, we also interrupt on the final transcript.\n this.#interruptIfPossible();\n }\n });\n }\n\n async #run() {\n this.#updateState('initializing');\n const audioSource = new AudioSource(this.#tts.sampleRate, this.#tts.numChannels);\n const track = LocalAudioTrack.createAudioTrack('assistant_voice', audioSource);\n this.#agentPublication = await this.#room?.localParticipant?.publishTrack(\n track,\n new TrackPublishOptions({ source: TrackSource.SOURCE_MICROPHONE }),\n );\n\n const agentPlayout = new AgentPlayout(audioSource);\n this.#agentOutput = new AgentOutput(agentPlayout, this.#tts);\n\n agentPlayout.on(AgentPlayoutEvent.PLAYOUT_STARTED, () => {\n this.emit(VPAEvent.AGENT_STARTED_SPEAKING);\n this.#updateState('speaking');\n });\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n agentPlayout.on(AgentPlayoutEvent.PLAYOUT_STOPPED, (_) => {\n this.emit(VPAEvent.AGENT_STOPPED_SPEAKING);\n this.#updateState('listening');\n });\n\n this.#trackPublishedFut.resolve();\n\n while (true) {\n await this.#speechQueueOpen.await;\n for await (const speech of this.#speechQueue) {\n if (speech === VoicePipelineAgent.FLUSH_SENTINEL) break;\n this.#playingSpeech = speech;\n await this.#playSpeech(speech);\n this.#playingSpeech = undefined;\n }\n this.#speechQueueOpen = new Future();\n }\n }\n\n #synthesizeAgentReply() {\n this.#pendingAgentReply?.cancel();\n if (this.#humanInput && this.#humanInput.speaking) {\n this.#updateState('thinking', 200);\n }\n\n this.#pendingAgentReply = SpeechHandle.createAssistantReply(\n this.#opts.allowInterruptions,\n true,\n this.transcribedText,\n );\n const newHandle = this.#pendingAgentReply;\n this.#agentReplyTask = this.#synthesizeAnswerTask(this.#agentReplyTask, newHandle);\n }\n\n #synthesizeAnswerTask(\n oldTask: CancellablePromise<void> | undefined,\n handle?: SpeechHandle,\n ): CancellablePromise<void> {\n return new CancellablePromise(async (resolve, _, onCancel) => {\n let cancelled = false;\n onCancel(() => {\n cancelled = true;\n });\n\n if (oldTask) {\n await gracefullyCancel(oldTask);\n }\n\n const copiedCtx = this.chatCtx.copy();\n const playingSpeech = this.#playingSpeech;\n if (playingSpeech && playingSpeech.initialized) {\n if (\n (!playingSpeech.userQuestion || playingSpeech.userCommitted) &&\n !playingSpeech.speechCommitted\n ) {\n // the speech is playing but not committed yet,\n // add it to the chat context for this new reply synthesis\n copiedCtx.messages.push(\n ChatMessage.create({\n text: playingSpeech.synthesisHandle.text,\n role: ChatRole.ASSISTANT,\n }),\n );\n }\n }\n\n copiedCtx.messages.push(\n ChatMessage.create({\n text: handle?.userQuestion,\n role: ChatRole.USER,\n }),\n );\n\n speechData = { sequenceId: handle!.id };\n\n try {\n if (cancelled) resolve();\n let llmStream = await this.#opts.beforeLLMCallback(this, copiedCtx);\n if (llmStream === false) {\n handle?.cancel();\n return;\n }\n\n if (cancelled) resolve();\n // fallback to default impl if no custom/user stream is returned\n if (!(llmStream instanceof LLMStream)) {\n llmStream = (await defaultBeforeLLMCallback(this, copiedCtx)) as LLMStream;\n }\n\n if (handle!.interrupted) {\n return;\n }\n\n const synthesisHandle = this.#synthesizeAgentSpeech(handle!.id, llmStream);\n handle!.initialize(llmStream, synthesisHandle);\n } finally {\n speechData = undefined;\n }\n resolve();\n });\n }\n\n async #playSpeech(handle: SpeechHandle) {\n try {\n await handle.waitForInitialization();\n } catch {\n return;\n }\n await this.#agentPublication!.waitForSubscription();\n const synthesisHandle = handle.synthesisHandle;\n if (synthesisHandle.interrupted) return;\n\n const userQuestion = handle.userQuestion;\n const playHandle = synthesisHandle.play();\n const joinFut = playHandle.join();\n\n const commitUserQuestionIfNeeded = () => {\n if (!userQuestion || synthesisHandle.interrupted || handle.userCommitted) return;\n const isUsingTools =\n handle.source instanceof LLMStream && !!handle.source.functionCalls.length;\n\n // make sure at least some speech was played before committing the user message\n // since we try to validate as fast as possible it is possible the agent gets interrupted\n // really quickly (barely audible), we don't want to mark this question as \"answered\".\n if (\n handle.allowInterruptions &&\n !isUsingTools &&\n playHandle.timePlayed < this.MIN_TIME_PLAYED_FOR_COMMIT &&\n !joinFut.done\n ) {\n return;\n }\n\n this.#logger.child({ userTranscript: userQuestion }).debug('committed user transcript');\n const userMsg = ChatMessage.create({ text: userQuestion, role: ChatRole.USER });\n this.chatCtx.messages.push(userMsg);\n this.emit(VPAEvent.USER_SPEECH_COMMITTED, userMsg);\n\n this.transcribedText = this.transcribedText.slice(userQuestion.length);\n handle.markUserCommitted();\n };\n\n // wait for the playHandle to finish and check every 1s if user question should be committed\n commitUserQuestionIfNeeded();\n\n while (!joinFut.done) {\n await new Promise<void>(async (resolve) => {\n setTimeout(resolve, 500);\n await joinFut.await;\n resolve();\n });\n commitUserQuestionIfNeeded();\n if (handle.interrupted) break;\n }\n commitUserQuestionIfNeeded();\n\n let collectedText = this.#agentTranscribedText;\n const isUsingTools = handle.source instanceof LLMStream && !!handle.source.functionCalls.length;\n const interrupted = handle.interrupted;\n\n if (handle.addToChatCtx && (!userQuestion || handle.userCommitted)) {\n if (handle.extraToolsMessages) {\n this.chatCtx.messages.push(...handle.extraToolsMessages);\n }\n if (interrupted) {\n collectedText += '…';\n }\n\n const msg = ChatMessage.create({ text: collectedText, role: ChatRole.ASSISTANT });\n this.chatCtx.messages.push(msg);\n\n handle.markSpeechCommitted();\n if (interrupted) {\n this.emit(VPAEvent.AGENT_SPEECH_INTERRUPTED, msg);\n } else {\n this.emit(VPAEvent.AGENT_SPEECH_COMMITTED, msg);\n }\n\n this.#logger\n .child({\n agentTranscript: collectedText,\n interrupted,\n speechId: handle.id,\n })\n .debug('committed agent speech');\n\n handle.setDone();\n }\n\n const executeFunctionCalls = async () => {\n // if the answer is using tools, execute the functions and automatically generate\n // a response to the user question from the returned values\n if (!isUsingTools || interrupted) return;\n\n if (handle.fncNestedDepth >= this.#opts.maxNestedFncCalls) {\n this.#logger\n .child({ speechId: handle.id, fncNestedDepth: handle.fncNestedDepth })\n .warn('max function calls nested depth reached');\n return;\n }\n\n if (userQuestion && !handle.userCommitted) {\n throw new Error('user speech should have been committed before using tools');\n }\n const llmStream = handle.source;\n const newFunctionCalls = llmStream.functionCalls;\n\n new AgentCallContext(this, llmStream);\n\n this.emit(VPAEvent.FUNCTION_CALLS_COLLECTED, newFunctionCalls);\n const calledFuncs: FunctionCallInfo[] = [];\n for (const func of newFunctionCalls) {\n const task = func.func.execute(func.params).then(\n (result) => ({ name: func.name, toolCallId: func.toolCallId, result }),\n (error) => ({ name: func.name, toolCallId: func.toolCallId, error }),\n );\n calledFuncs.push({ ...func, task });\n this.#logger\n .child({ function: func.name, speechId: handle.id })\n .debug('executing AI function');\n try {\n await task;\n } catch {\n this.#logger\n .child({ function: func.name, speechId: handle.id })\n .error('error executing AI function');\n }\n }\n\n const toolCallsInfo = [];\n const toolCallsResults = [];\n for (const fnc of calledFuncs) {\n // ignore the function calls that return void\n const task = await fnc.task;\n if (!task || task.result === undefined) continue;\n toolCallsInfo.push(fnc);\n toolCallsResults.push(ChatMessage.createToolFromFunctionResult(task));\n }\n\n if (!toolCallsInfo.length) return;\n\n // generate an answer from the tool calls\n const extraToolsMessages = [ChatMessage.createToolCalls(toolCallsInfo, collectedText)];\n extraToolsMessages.push(...toolCallsResults);\n\n // create a nested speech handle\n const newSpeechHandle = SpeechHandle.createToolSpeech(\n handle.allowInterruptions,\n handle.addToChatCtx,\n handle.fncNestedDepth + 1,\n extraToolsMessages,\n );\n\n // synthesize the tool speech with the chat ctx from llmStream\n const chatCtx = handle.source.chatCtx.copy();\n chatCtx.messages.push(...extraToolsMessages);\n chatCtx.messages.push(...AgentCallContext.getCurrent().extraChatMessages);\n\n const answerLLMStream = this.llm.chat({\n chatCtx,\n fncCtx: this.fncCtx,\n });\n\n const answerSynthesis = this.#synthesizeAgentSpeech(newSpeechHandle.id, answerLLMStream);\n newSpeechHandle.initialize(answerLLMStream, answerSynthesis);\n handle.addNestedSpeech(newSpeechHandle);\n\n this.emit(VPAEvent.FUNCTION_CALLS_FINISHED, calledFuncs);\n };\n\n let finished = false;\n const task = executeFunctionCalls().then(() => {\n finished = true;\n });\n while (!handle.nestedSpeechFinished) {\n const changed = handle.nestedSpeechChanged();\n await Promise.race([changed, task]);\n while (handle.nestedSpeechHandles.length) {\n const speech = handle.nestedSpeechHandles[0]!;\n this.#playingSpeech = speech;\n await this.#playSpeech(speech);\n handle.nestedSpeechHandles.shift();\n this.#playingSpeech = handle;\n }\n\n handle.nestedSpeechHandles.forEach(() => handle.nestedSpeechHandles.pop());\n if (finished) {\n handle.markNestedSpeechFinished();\n }\n }\n handle.setDone();\n }\n\n #synthesizeAgentSpeech(\n speechId: string,\n source: string | LLMStream | AsyncIterable<string>,\n ): SynthesisHandle {\n const synchronizer = new TextAudioSynchronizer(defaultTextSyncOptions);\n synchronizer.on('textUpdated', (text) => {\n this.#agentTranscribedText = text.text;\n this.#room!.localParticipant!.publishTranscription({\n participantIdentity: this.#room!.localParticipant!.identity,\n trackSid: this.#agentPublication!.sid!,\n segments: [text],\n });\n });\n\n if (!this.#agentOutput) {\n throw new Error('agent output should be initialized when ready');\n }\n\n if (source instanceof LLMStream) {\n source = llmStreamToStringIterable(speechId, source);\n }\n\n const ogSource = source;\n if (!(typeof source === 'string')) {\n // TODO(nbsp): itertools.tee\n }\n\n const ttsSource = this.#opts.beforeTTSCallback(this, ogSource);\n if (!ttsSource) {\n throw new Error('beforeTTSCallback must return string or AsyncIterable<string>');\n }\n\n return this.#agentOutput.synthesize(speechId, ttsSource, synchronizer);\n }\n\n async #validateReplyIfPossible() {\n if (this.#playingSpeech && !this.#playingSpeech.allowInterruptions) {\n this.#logger\n .child({ speechId: this.#playingSpeech.id })\n .debug('skipping validation, agent is speaking and does not allow interruptions');\n return;\n }\n\n if (!this.#pendingAgentReply) {\n if (this.#opts.preemptiveSynthesis || !this.transcribedText) {\n return;\n }\n this.#synthesizeAgentReply();\n }\n\n if (!this.#pendingAgentReply) {\n throw new Error('pending agent reply is undefined');\n }\n\n // in some bad timimg, we could end up with two pushed agent replies inside the speech queue.\n // so make sure we directly interrupt every reply when validating a new one\n if (this.#speechQueueOpen.done) {\n for await (const speech of this.#speechQueue) {\n if (speech === VoicePipelineAgent.FLUSH_SENTINEL) break;\n if (!speech.isReply) continue;\n if (speech.allowInterruptions) speech.interrupt();\n }\n }\n\n this.#logger.child({ speechId: this.#pendingAgentReply.id }).debug('validated agent reply');\n\n if (this.#lastSpeechTime) {\n const timeSinceLastSpeech = Date.now() - this.#lastSpeechTime;\n const transcriptionDelay = Math.max(\n (this.#lastFinalTranscriptTime || 0) - this.#lastSpeechTime,\n 0,\n );\n const metrics: PipelineEOUMetrics = {\n timestamp: Date.now(),\n sequenceId: this.#pendingAgentReply.id,\n endOfUtteranceDelay: timeSinceLastSpeech,\n transcriptionDelay,\n };\n this.emit(VPAEvent.METRICS_COLLECTED, metrics);\n }\n\n this.#addSpeechForPlayout(this.#pendingAgentReply);\n this.#pendingAgentReply = undefined;\n this.#transcribedInterimText = '';\n }\n\n #interruptIfPossible() {\n if (\n !this.#playingSpeech ||\n !this.#playingSpeech.allowInterruptions ||\n this.#playingSpeech.interrupted\n ) {\n return;\n }\n\n if (this.#opts.interruptMinWords !== 0) {\n // check the final/interim transcribed text for the minimum word count\n // to interrupt the agent speech\n const interimWords = this.#opts.transcription.wordTokenizer.tokenize(\n this.#transcribedInterimText,\n );\n if (interimWords.length < this.#opts.interruptMinWords) {\n return;\n }\n }\n this.#playingSpeech.interrupt();\n }\n\n #addSpeechForPlayout(handle: SpeechHandle) {\n this.#speechQueue.put(handle);\n this.#speechQueue.put(VoicePipelineAgent.FLUSH_SENTINEL);\n this.#speechQueueOpen.resolve();\n }\n\n /** Close the voice assistant. */\n async close() {\n if (!this.#started) {\n return;\n }\n\n this.#room?.removeAllListeners(RoomEvent.ParticipantConnected);\n // TODO(nbsp): await this.#deferredValidation.close()\n }\n}\n\nasync function* llmStreamToStringIterable(\n speechId: string,\n stream: LLMStream,\n): AsyncIterable<string> {\n const startTime = Date.now();\n let firstFrame = true;\n for await (const chunk of stream) {\n const content = chunk.choices[0]?.delta.content;\n if (!content) continue;\n\n if (firstFrame) {\n firstFrame = false;\n log()\n .child({ speechId, elapsed: Math.round(Date.now() - startTime) })\n .debug('received first LLM token');\n }\n yield content;\n }\n}\n\n/** This class is used to try to find the best time to validate the agent reply. */\nclass DeferredReplyValidation {\n // if the STT gives us punctuation, we can try to validate the reply faster.\n readonly PUNCTUATION = '.!?';\n readonly PUNCTUATION_REDUCE_FACTOR = 0.75;\n readonly LATE_TRANSCRIPT_TOLERANCE = 1.5; // late compared to end of speech\n readonly UNLIKELY_ENDPOINT_DELAY = 6000;\n\n #validateFunc: () => Promise<void>;\n #validatingPromise?: Promise<void>;\n #validatingFuture = new Future();\n #lastFinalTranscript = '';\n #lastRecvEndOfSpeechTime = 0;\n #speaking = false;\n #endOfSpeechDelay: number;\n #finalTranscriptDelay: number;\n #turnDetector?: TurnDetector;\n #agent: VoicePipelineAgent;\n #abort?: AbortController;\n\n constructor(\n validateFunc: () => Promise<void>,\n minEndpointingDelay: number,\n agent: VoicePipelineAgent,\n turnDetector?: TurnDetector,\n ) {\n this.#validateFunc = validateFunc;\n this.#endOfSpeechDelay = minEndpointingDelay;\n this.#finalTranscriptDelay = minEndpointingDelay;\n this.#agent = agent;\n this.#turnDetector = turnDetector;\n }\n\n get validating(): boolean {\n return !this.#validatingFuture.done;\n }\n\n onHumanFinalTranscript(transcript: string) {\n this.#lastFinalTranscript = transcript.trim();\n if (this.#speaking) return;\n\n const hasRecentEndOfSpeech =\n Date.now() - this.#lastRecvEndOfSpeechTime < this.LATE_TRANSCRIPT_TOLERANCE;\n let delay = hasRecentEndOfSpeech ? this.#endOfSpeechDelay : this.#finalTranscriptDelay;\n delay = this.#endWithPunctuation() ? delay * this.PUNCTUATION_REDUCE_FACTOR : 1;\n\n this.#run(delay);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onHumanStartOfSpeech(_: VADEvent) {\n this.#speaking = true;\n if (this.validating) {\n this.#abort?.abort();\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onHumanEndOfSpeech(_: VADEvent) {\n this.#speaking = false;\n this.#lastRecvEndOfSpeechTime = Date.now();\n\n if (this.#lastFinalTranscript) {\n const delay = this.#endWithPunctuation()\n ? this.#endOfSpeechDelay * this.PUNCTUATION_REDUCE_FACTOR\n : 1_000;\n this.#run(delay);\n }\n }\n\n // TODO(nbsp): aclose\n\n #endWithPunctuation(): boolean {\n return (\n this.#lastFinalTranscript.length > 0 &&\n this.PUNCTUATION.includes(this.#lastFinalTranscript[this.#lastFinalTranscript.length - 1]!)\n );\n }\n\n #resetStates() {\n this.#lastFinalTranscript = '';\n this.#lastRecvEndOfSpeechTime = 0;\n }\n\n #run(delay: number) {\n const runTask = async (delay: number, chatCtx: ChatContext, signal: AbortSignal) => {\n if (this.#lastFinalTranscript && !this.#speaking && this.#turnDetector) {\n const startTime = Date.now();\n const eotProb = await this.#turnDetector.predictEndOfTurn(chatCtx);\n const unlikelyThreshold = this.#turnDetector.unlikelyThreshold;\n const elapsed = Date.now() - startTime;\n if (eotProb < unlikelyThreshold) {\n delay = this.UNLIKELY_ENDPOINT_DELAY;\n }\n delay = Math.max(0, delay - elapsed);\n }\n const timeout = setTimeout(() => {\n this.#resetStates();\n this.#validateFunc();\n }, delay);\n signal.addEventListener('abort', () => {\n clearTimeout(timeout);\n });\n };\n\n this.#abort?.abort();\n this.#abort = new AbortController();\n this.#validatingFuture = new Future();\n const detectCtx = this.#agent.chatCtx.copy();\n detectCtx.append({ text: this.#agent.transcribedText, role: ChatRole.USER });\n this.#validatingPromise = runTask(delay, detectCtx, this.#abort.signal);\n }\n}\n"],"mappings":"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","names":["VPAEvent","participant","delay","resolve","isUsingTools","task"]}
package/dist/worker.cjs CHANGED
@@ -163,7 +163,7 @@ class WorkerOptions {
163
163
  wsURL = "ws://localhost:7880",
164
164
  apiKey = void 0,
165
165
  apiSecret = void 0,
166
- host = "localhost",
166
+ host = "0.0.0.0",
167
167
  port = void 0,
168
168
  logLevel = "info",
169
169
  production = false,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/worker.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type {\n JobAssignment,\n JobTermination,\n ParticipantInfo,\n TrackSource,\n} from '@livekit/protocol';\nimport {\n type AvailabilityRequest,\n JobType,\n ParticipantPermission,\n ServerMessage,\n WorkerMessage,\n WorkerStatus,\n} from '@livekit/protocol';\nimport { AccessToken, RoomServiceClient } from 'livekit-server-sdk';\nimport { EventEmitter } from 'node:events';\nimport os from 'node:os';\nimport { WebSocket } from 'ws';\nimport { HTTPServer } from './http_server.js';\nimport { InferenceRunner } from './inference_runner.js';\nimport { InferenceProcExecutor } from './ipc/inference_proc_executor.js';\nimport { ProcPool } from './ipc/proc_pool.js';\nimport type { JobAcceptArguments, JobProcess, RunningJobInfo } from './job.js';\nimport { JobRequest } from './job.js';\nimport { log } from './log.js';\nimport { Future } from './utils.js';\nimport { version } from './version.js';\n\nconst MAX_RECONNECT_ATTEMPTS = 10;\nconst ASSIGNMENT_TIMEOUT = 7.5 * 1000;\nconst UPDATE_LOAD_INTERVAL = 2.5 * 1000;\n\nclass Default {\n static loadThreshold(production: boolean): number {\n if (production) {\n return 0.65;\n } else {\n return Infinity;\n }\n }\n\n static numIdleProcesses(production: boolean): number {\n if (production) {\n return 3;\n } else {\n return 0;\n }\n }\n\n static port(production: boolean): number {\n if (production) {\n return 8081;\n } else {\n return 0;\n }\n }\n}\n\n/** Necessary credentials not provided and not found in an appropriate environmental variable. */\nexport class MissingCredentialsError extends Error {\n constructor(msg?: string) {\n super(msg);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Worker did not run as expected. */\nexport class WorkerError extends Error {\n constructor(msg?: string) {\n super(msg);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** @internal */\nexport const defaultInitializeProcessFunc = (_: JobProcess) => _;\nconst defaultRequestFunc = async (ctx: JobRequest) => {\n await ctx.accept();\n};\nconst defaultCpuLoad = async (): Promise<number> => {\n return new Promise((resolve) => {\n const cpus1 = os.cpus();\n\n setTimeout(() => {\n const cpus2 = os.cpus();\n\n let idle = 0;\n let total = 0;\n\n for (let i = 0; i < cpus1.length; i++) {\n const cpu1 = cpus1[i]!.times;\n const cpu2 = cpus2[i]!.times;\n\n idle += cpu2.idle - cpu1.idle;\n\n const total1 = Object.values(cpu1).reduce((acc, i) => acc + i, 0);\n const total2 = Object.values(cpu2).reduce((acc, i) => acc + i, 0);\n\n total += total2 - total1;\n }\n\n resolve(+(1 - idle / total).toFixed(2));\n }, UPDATE_LOAD_INTERVAL);\n });\n};\n\n/** Participant permissions to pass to every agent spun up by this worker. */\nexport class WorkerPermissions {\n canPublish: boolean;\n canSubscribe: boolean;\n canPublishData: boolean;\n canUpdateMetadata: boolean;\n canPublishSources: TrackSource[];\n hidden: boolean;\n\n constructor(\n canPublish = true,\n canSubscribe = true,\n canPublishData = true,\n canUpdateMetadata = true,\n canPublishSources: TrackSource[] = [],\n hidden = false,\n ) {\n this.canPublish = canPublish;\n this.canSubscribe = canSubscribe;\n this.canPublishData = canPublishData;\n this.canUpdateMetadata = canUpdateMetadata;\n this.canPublishSources = canPublishSources;\n this.hidden = hidden;\n }\n}\n\n/**\n * Data class describing worker behaviour.\n *\n * @remarks\n * The Agents framework provides sane worker defaults, and works out-of-the-box with no tweaking\n * necessary. The only mandatory parameter is `agent`, which points to the entry function.\n *\n * This class is mostly useful in conjunction with {@link cli.runApp}.\n */\nexport class WorkerOptions {\n agent: string;\n requestFunc: (job: JobRequest) => Promise<void>;\n loadFunc: () => Promise<number>;\n loadThreshold: number;\n numIdleProcesses: number;\n shutdownProcessTimeout: number;\n initializeProcessTimeout: number;\n permissions: WorkerPermissions;\n agentName: string;\n workerType: JobType;\n maxRetry: number;\n wsURL: string;\n apiKey?: string;\n apiSecret?: string;\n host: string;\n port: number;\n logLevel: string;\n production: boolean;\n jobMemoryWarnMB: number;\n jobMemoryLimitMB: number;\n\n /** @param options */\n constructor({\n agent,\n requestFunc = defaultRequestFunc,\n loadFunc = defaultCpuLoad,\n loadThreshold = undefined,\n numIdleProcesses = undefined,\n shutdownProcessTimeout = 60 * 1000,\n initializeProcessTimeout = 10 * 1000,\n permissions = new WorkerPermissions(),\n agentName = '',\n workerType = JobType.JT_ROOM,\n maxRetry = MAX_RECONNECT_ATTEMPTS,\n wsURL = 'ws://localhost:7880',\n apiKey = undefined,\n apiSecret = undefined,\n host = 'localhost',\n port = undefined,\n logLevel = 'info',\n production = false,\n jobMemoryWarnMB = 300,\n jobMemoryLimitMB = 0,\n }: {\n /**\n * Path to a file that has {@link Agent} as a default export, dynamically imported later for\n * entrypoint and prewarm functions\n */\n agent: string;\n requestFunc?: (job: JobRequest) => Promise<void>;\n /** Called to determine the current load of the worker. Should return a value between 0 and 1. */\n loadFunc?: () => Promise<number>;\n /** When the load exceeds this threshold, the worker will be marked as unavailable. */\n loadThreshold?: number;\n numIdleProcesses?: number;\n shutdownProcessTimeout?: number;\n initializeProcessTimeout?: number;\n permissions?: WorkerPermissions;\n agentName?: string;\n workerType?: JobType;\n maxRetry?: number;\n wsURL?: string;\n apiKey?: string;\n apiSecret?: string;\n host?: string;\n port?: number;\n logLevel?: string;\n production?: boolean;\n jobMemoryWarnMB?: number;\n jobMemoryLimitMB?: number;\n }) {\n this.agent = agent;\n if (!this.agent) {\n throw new Error('No Agent file was passed to the worker');\n }\n this.requestFunc = requestFunc;\n this.loadFunc = loadFunc;\n this.loadThreshold = loadThreshold || Default.loadThreshold(production);\n this.numIdleProcesses = numIdleProcesses || Default.numIdleProcesses(production);\n this.shutdownProcessTimeout = shutdownProcessTimeout;\n this.initializeProcessTimeout = initializeProcessTimeout;\n this.permissions = permissions;\n this.agentName = agentName;\n this.workerType = workerType;\n this.maxRetry = maxRetry;\n this.wsURL = wsURL;\n this.apiKey = apiKey;\n this.apiSecret = apiSecret;\n this.host = host;\n this.port = port || Default.port(production);\n this.logLevel = logLevel;\n this.production = production;\n this.jobMemoryWarnMB = jobMemoryWarnMB;\n this.jobMemoryLimitMB = jobMemoryLimitMB;\n }\n}\n\nclass PendingAssignment {\n promise = new Promise<JobAssignment>((resolve) => {\n this.resolve = resolve; // this is how JavaScript lets you resolve promises externally\n });\n resolve(arg: JobAssignment) {\n arg; // useless call to counteract TypeScript E6133\n }\n}\n\n/**\n * Central orchestrator for all processes and job requests.\n *\n * @remarks\n * For most usecases, Worker should not be initialized or handled directly; you should instead call\n * for its creation through {@link cli.runApp}. This could, however, be useful in situations where\n * you don't have access to a command line, such as a headless program, or one that uses Agents\n * behind a wrapper.\n */\nexport class Worker {\n #opts: WorkerOptions;\n #procPool: ProcPool;\n\n #id = 'unregistered';\n #closed = true;\n #draining = false;\n #connecting = false;\n #tasks: Promise<void>[] = [];\n #pending: { [id: string]: PendingAssignment } = {};\n #close = new Future();\n\n event = new EventEmitter();\n #session: WebSocket | undefined = undefined;\n #httpServer: HTTPServer;\n #logger = log().child({ version });\n #inferenceExecutor?: InferenceProcExecutor;\n\n /* @throws {@link MissingCredentialsError} if URL, API key or API secret are missing */\n constructor(opts: WorkerOptions) {\n opts.wsURL = opts.wsURL || process.env.LIVEKIT_URL || '';\n opts.apiKey = opts.apiKey || process.env.LIVEKIT_API_KEY || '';\n opts.apiSecret = opts.apiSecret || process.env.LIVEKIT_API_SECRET || '';\n\n if (opts.wsURL === '')\n throw new MissingCredentialsError(\n 'URL is required: Set LIVEKIT_URL, run with --url, or pass wsURL in WorkerOptions',\n );\n if (opts.apiKey === '')\n throw new MissingCredentialsError(\n 'API Key is required: Set LIVEKIT_API_KEY, run with --api-key, or pass apiKey in WorkerOptions',\n );\n if (opts.apiSecret === '')\n throw new MissingCredentialsError(\n 'API Secret is required: Set LIVEKIT_API_SECRET, run with --api-secret, or pass apiSecret in WorkerOptions',\n );\n\n if (Object.entries(InferenceRunner.registeredRunners).length) {\n this.#inferenceExecutor = new InferenceProcExecutor({\n runners: InferenceRunner.registeredRunners,\n initializeTimeout: 30000,\n closeTimeout: 5000,\n memoryWarnMB: 2000,\n memoryLimitMB: 0,\n pingInterval: 5000,\n pingTimeout: 60000,\n highPingThreshold: 2500,\n });\n }\n\n this.#procPool = new ProcPool(\n opts.agent,\n opts.numIdleProcesses,\n opts.initializeProcessTimeout,\n opts.shutdownProcessTimeout,\n this.#inferenceExecutor,\n opts.jobMemoryWarnMB,\n opts.jobMemoryLimitMB,\n );\n\n this.#opts = opts;\n this.#httpServer = new HTTPServer(opts.host, opts.port, () => ({\n agent_name: opts.agentName,\n worker_type: JobType[opts.workerType],\n active_jobs: this.activeJobs.length,\n }));\n }\n\n /* @throws {@link WorkerError} if worker failed to connect or already running */\n async run() {\n if (!this.#closed) {\n throw new WorkerError('worker is already running');\n }\n\n if (this.#inferenceExecutor) {\n await this.#inferenceExecutor.start();\n await this.#inferenceExecutor.initialize();\n }\n\n this.#logger.info('starting worker');\n this.#closed = false;\n this.#procPool.start();\n\n const workerWS = async () => {\n let retries = 0;\n this.#connecting = true;\n\n while (!this.#closed) {\n const url = new URL(this.#opts.wsURL);\n url.protocol = url.protocol.replace('http', 'ws');\n const token = new AccessToken(this.#opts.apiKey, this.#opts.apiSecret);\n token.addGrant({ agent: true });\n const jwt = await token.toJwt();\n this.#session = new WebSocket(url + 'agent', {\n headers: { authorization: 'Bearer ' + jwt },\n });\n\n try {\n await new Promise((resolve, reject) => {\n this.#session!.on('open', resolve);\n this.#session!.on('error', (error) => reject(error.message));\n this.#session!.on('close', (code) => reject(`WebSocket returned ${code}`));\n });\n\n retries = 0;\n this.#logger.debug('connected to LiveKit server');\n await this.#runWS(this.#session);\n } catch (e: unknown) {\n if (e instanceof Error || e instanceof ErrorEvent) {\n e = e.message;\n }\n\n if (this.#closed) return;\n if (retries >= this.#opts.maxRetry) {\n throw new WorkerError(\n `failed to connect to LiveKit server after ${retries} attempts: ${e}`,\n );\n }\n\n retries++;\n const delay = Math.min(retries * 2, 10);\n\n this.#logger.warn(\n `failed to connect to LiveKit server, retrying in ${delay} seconds: ${e} (${retries}/${this.#opts.maxRetry})`,\n );\n\n await new Promise((resolve) => setTimeout(resolve, delay * 1000));\n }\n }\n };\n\n await Promise.all([workerWS(), this.#httpServer.run()]);\n this.#close.resolve();\n }\n\n get id(): string {\n return this.#id;\n }\n\n get activeJobs(): RunningJobInfo[] {\n return this.#procPool.processes\n .filter((proc) => proc.runningJob)\n .map((proc) => proc.runningJob!);\n }\n\n /* @throws {@link WorkerError} if worker did not drain in time */\n async drain(timeout?: number) {\n if (this.#draining) {\n return;\n }\n\n this.#logger.info('draining worker');\n this.#draining = true;\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'updateWorker',\n value: {\n status: WorkerStatus.WS_FULL,\n },\n },\n }),\n );\n\n const joinJobs = async () => {\n return Promise.all(\n this.#procPool.processes.map((proc) => {\n if (!proc.runningJob) {\n proc.close();\n }\n return proc.join();\n }),\n );\n };\n\n let timer: NodeJS.Timeout | undefined;\n if (timeout) {\n timer = setTimeout(() => {\n throw new WorkerError('timed out draining');\n }, timeout);\n }\n await joinJobs().then(() => {\n if (timeout) {\n clearTimeout(timer);\n }\n });\n }\n\n async simulateJob(roomName: string, participantIdentity?: string) {\n const client = new RoomServiceClient(this.#opts.wsURL, this.#opts.apiKey, this.#opts.apiSecret);\n const room = await client.createRoom({ name: roomName });\n let participant: ParticipantInfo | undefined = undefined;\n if (participantIdentity) {\n try {\n participant = await client.getParticipant(roomName, participantIdentity);\n } catch (e) {\n this.#logger.fatal(\n `participant with identity ${participantIdentity} not found in room ${roomName}`,\n );\n throw e;\n }\n }\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'simulateJob',\n value: {\n type: JobType.JT_PUBLISHER,\n room,\n participant,\n },\n },\n }),\n );\n }\n\n async #runWS(ws: WebSocket) {\n let closingWS = false;\n\n const send = (msg: WorkerMessage) => {\n if (closingWS) {\n this.event.off('worker_msg', send);\n return;\n }\n ws.send(msg.toBinary());\n };\n this.event.on('worker_msg', send);\n\n const close = new Promise<void>((resolve) => {\n ws.addEventListener('close', () => {\n closingWS = true;\n if (!this.#closed) {\n this.#logger.error('worker connection closed unexpectedly');\n }\n resolve();\n });\n });\n\n ws.addEventListener('error', (event) => {\n this.#logger.error('worker error:', event.message);\n });\n\n ws.addEventListener('message', (event) => {\n if (event.type !== 'message') {\n this.#logger.warn('unexpected message type: ' + event.type);\n return;\n }\n\n const msg = new ServerMessage();\n msg.fromBinary(event.data as Uint8Array);\n\n // register is the only valid first message, and it is only valid as the\n // first message\n if (this.#connecting && msg.message.case !== 'register') {\n throw new WorkerError('expected register response as first message');\n }\n\n switch (msg.message.case) {\n case 'register': {\n this.#id = msg.message.value.workerId;\n this.#logger\n .child({ id: this.id, server_info: msg.message.value.serverInfo })\n .info('registered worker');\n this.event.emit(\n 'worker_registered',\n msg.message.value.workerId,\n msg.message.value.serverInfo,\n );\n this.#connecting = false;\n break;\n }\n case 'availability': {\n if (!msg.message.value.job) return;\n const task = this.#availability(msg.message.value);\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n break;\n }\n case 'assignment': {\n if (!msg.message.value.job) return;\n const job = msg.message.value.job;\n if (job.id in this.#pending) {\n const task = this.#pending[job.id];\n delete this.#pending[job.id];\n task?.resolve(msg.message.value);\n } else {\n this.#logger.child({ job }).warn('received assignment for unknown job ' + job.id);\n }\n break;\n }\n case 'termination': {\n const task = this.#termination(msg.message.value);\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n break;\n }\n }\n });\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'register',\n value: {\n type: this.#opts.workerType,\n agentName: this.#opts.agentName,\n allowedPermissions: new ParticipantPermission({\n canPublish: this.#opts.permissions.canPublish,\n canSubscribe: this.#opts.permissions.canSubscribe,\n canPublishData: this.#opts.permissions.canPublishData,\n canUpdateMetadata: this.#opts.permissions.canUpdateMetadata,\n hidden: this.#opts.permissions.hidden,\n agent: true,\n }),\n version,\n },\n },\n }),\n );\n\n let currentStatus = WorkerStatus.WS_AVAILABLE;\n const loadMonitor = setInterval(() => {\n if (closingWS) clearInterval(loadMonitor);\n\n const oldStatus = currentStatus;\n this.#opts.loadFunc().then((currentLoad: number) => {\n const isFull = currentLoad >= this.#opts.loadThreshold;\n const currentlyAvailable = !isFull;\n currentStatus = currentlyAvailable ? WorkerStatus.WS_AVAILABLE : WorkerStatus.WS_FULL;\n\n if (oldStatus != currentStatus) {\n const extra = { load: currentLoad, loadThreshold: this.#opts.loadThreshold };\n if (isFull) {\n this.#logger.child(extra).info('worker is at full capacity, marking as unavailable');\n } else {\n this.#logger.child(extra).info('worker is below capacity, marking as available');\n }\n }\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'updateWorker',\n value: {\n load: currentLoad,\n status: currentStatus,\n },\n },\n }),\n );\n });\n }, UPDATE_LOAD_INTERVAL);\n\n await close;\n ws.removeAllListeners();\n }\n\n async #availability(msg: AvailabilityRequest) {\n let answered = false;\n\n const onReject = async () => {\n answered = true;\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'availability',\n value: {\n jobId: msg.job!.id,\n available: false,\n },\n },\n }),\n );\n };\n\n const onAccept = async (args: JobAcceptArguments) => {\n answered = true;\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'availability',\n value: {\n jobId: msg.job!.id,\n available: true,\n participantIdentity: args.identity,\n participantName: args.name,\n participantMetadata: args.metadata,\n participantAttributes: args.attributes,\n },\n },\n }),\n );\n\n this.#pending[req.id] = new PendingAssignment();\n const timer = setTimeout(() => {\n this.#logger.child({ req }).warn(`assignment for job ${req.id} timed out`);\n return;\n }, ASSIGNMENT_TIMEOUT);\n const asgn = await this.#pending[req.id]?.promise.then(async (asgn) => {\n clearTimeout(timer);\n return asgn;\n });\n\n if (asgn) {\n await this.#procPool.launchJob({\n acceptArguments: args,\n job: msg.job!,\n url: asgn.url || this.#opts.wsURL,\n token: asgn.token,\n });\n } else {\n this.#logger.child({ requestId: req.id }).warn('pending assignment not found');\n }\n };\n\n const req = new JobRequest(msg.job!, onReject, onAccept);\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('received job request');\n\n const jobRequestTask = async () => {\n try {\n await this.#opts.requestFunc(req);\n } catch (e) {\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('jobRequestFunc failed');\n await onReject();\n }\n\n if (!answered) {\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('no answer was given inside the jobRequestFunc, automatically rejecting the job');\n }\n };\n\n const task = jobRequestTask();\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n }\n\n async #termination(msg: JobTermination) {\n const proc = this.#procPool.getByJobId(msg.jobId);\n if (proc === null) {\n // safe to ignore\n return;\n }\n await proc.close();\n }\n\n async close() {\n if (this.#closed) {\n await this.#close.await;\n return;\n }\n\n this.#logger.info('shutting down worker');\n\n this.#closed = true;\n\n await this.#inferenceExecutor?.close();\n await this.#procPool.close();\n await this.#httpServer.close();\n await Promise.allSettled(this.#tasks);\n\n this.#session?.close();\n await this.#close.await;\n }\n}\n"],"mappings":"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","names":["os","i","asgn"]}
1
+ {"version":3,"sources":["../src/worker.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type {\n JobAssignment,\n JobTermination,\n ParticipantInfo,\n TrackSource,\n} from '@livekit/protocol';\nimport {\n type AvailabilityRequest,\n JobType,\n ParticipantPermission,\n ServerMessage,\n WorkerMessage,\n WorkerStatus,\n} from '@livekit/protocol';\nimport { AccessToken, RoomServiceClient } from 'livekit-server-sdk';\nimport { EventEmitter } from 'node:events';\nimport os from 'node:os';\nimport { WebSocket } from 'ws';\nimport { HTTPServer } from './http_server.js';\nimport { InferenceRunner } from './inference_runner.js';\nimport { InferenceProcExecutor } from './ipc/inference_proc_executor.js';\nimport { ProcPool } from './ipc/proc_pool.js';\nimport type { JobAcceptArguments, JobProcess, RunningJobInfo } from './job.js';\nimport { JobRequest } from './job.js';\nimport { log } from './log.js';\nimport { Future } from './utils.js';\nimport { version } from './version.js';\n\nconst MAX_RECONNECT_ATTEMPTS = 10;\nconst ASSIGNMENT_TIMEOUT = 7.5 * 1000;\nconst UPDATE_LOAD_INTERVAL = 2.5 * 1000;\n\nclass Default {\n static loadThreshold(production: boolean): number {\n if (production) {\n return 0.65;\n } else {\n return Infinity;\n }\n }\n\n static numIdleProcesses(production: boolean): number {\n if (production) {\n return 3;\n } else {\n return 0;\n }\n }\n\n static port(production: boolean): number {\n if (production) {\n return 8081;\n } else {\n return 0;\n }\n }\n}\n\n/** Necessary credentials not provided and not found in an appropriate environmental variable. */\nexport class MissingCredentialsError extends Error {\n constructor(msg?: string) {\n super(msg);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Worker did not run as expected. */\nexport class WorkerError extends Error {\n constructor(msg?: string) {\n super(msg);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** @internal */\nexport const defaultInitializeProcessFunc = (_: JobProcess) => _;\nconst defaultRequestFunc = async (ctx: JobRequest) => {\n await ctx.accept();\n};\nconst defaultCpuLoad = async (): Promise<number> => {\n return new Promise((resolve) => {\n const cpus1 = os.cpus();\n\n setTimeout(() => {\n const cpus2 = os.cpus();\n\n let idle = 0;\n let total = 0;\n\n for (let i = 0; i < cpus1.length; i++) {\n const cpu1 = cpus1[i]!.times;\n const cpu2 = cpus2[i]!.times;\n\n idle += cpu2.idle - cpu1.idle;\n\n const total1 = Object.values(cpu1).reduce((acc, i) => acc + i, 0);\n const total2 = Object.values(cpu2).reduce((acc, i) => acc + i, 0);\n\n total += total2 - total1;\n }\n\n resolve(+(1 - idle / total).toFixed(2));\n }, UPDATE_LOAD_INTERVAL);\n });\n};\n\n/** Participant permissions to pass to every agent spun up by this worker. */\nexport class WorkerPermissions {\n canPublish: boolean;\n canSubscribe: boolean;\n canPublishData: boolean;\n canUpdateMetadata: boolean;\n canPublishSources: TrackSource[];\n hidden: boolean;\n\n constructor(\n canPublish = true,\n canSubscribe = true,\n canPublishData = true,\n canUpdateMetadata = true,\n canPublishSources: TrackSource[] = [],\n hidden = false,\n ) {\n this.canPublish = canPublish;\n this.canSubscribe = canSubscribe;\n this.canPublishData = canPublishData;\n this.canUpdateMetadata = canUpdateMetadata;\n this.canPublishSources = canPublishSources;\n this.hidden = hidden;\n }\n}\n\n/**\n * Data class describing worker behaviour.\n *\n * @remarks\n * The Agents framework provides sane worker defaults, and works out-of-the-box with no tweaking\n * necessary. The only mandatory parameter is `agent`, which points to the entry function.\n *\n * This class is mostly useful in conjunction with {@link cli.runApp}.\n */\nexport class WorkerOptions {\n agent: string;\n requestFunc: (job: JobRequest) => Promise<void>;\n loadFunc: () => Promise<number>;\n loadThreshold: number;\n numIdleProcesses: number;\n shutdownProcessTimeout: number;\n initializeProcessTimeout: number;\n permissions: WorkerPermissions;\n agentName: string;\n workerType: JobType;\n maxRetry: number;\n wsURL: string;\n apiKey?: string;\n apiSecret?: string;\n host: string;\n port: number;\n logLevel: string;\n production: boolean;\n jobMemoryWarnMB: number;\n jobMemoryLimitMB: number;\n\n /** @param options */\n constructor({\n agent,\n requestFunc = defaultRequestFunc,\n loadFunc = defaultCpuLoad,\n loadThreshold = undefined,\n numIdleProcesses = undefined,\n shutdownProcessTimeout = 60 * 1000,\n initializeProcessTimeout = 10 * 1000,\n permissions = new WorkerPermissions(),\n agentName = '',\n workerType = JobType.JT_ROOM,\n maxRetry = MAX_RECONNECT_ATTEMPTS,\n wsURL = 'ws://localhost:7880',\n apiKey = undefined,\n apiSecret = undefined,\n host = '0.0.0.0',\n port = undefined,\n logLevel = 'info',\n production = false,\n jobMemoryWarnMB = 300,\n jobMemoryLimitMB = 0,\n }: {\n /**\n * Path to a file that has {@link Agent} as a default export, dynamically imported later for\n * entrypoint and prewarm functions\n */\n agent: string;\n requestFunc?: (job: JobRequest) => Promise<void>;\n /** Called to determine the current load of the worker. Should return a value between 0 and 1. */\n loadFunc?: () => Promise<number>;\n /** When the load exceeds this threshold, the worker will be marked as unavailable. */\n loadThreshold?: number;\n numIdleProcesses?: number;\n shutdownProcessTimeout?: number;\n initializeProcessTimeout?: number;\n permissions?: WorkerPermissions;\n agentName?: string;\n workerType?: JobType;\n maxRetry?: number;\n wsURL?: string;\n apiKey?: string;\n apiSecret?: string;\n host?: string;\n port?: number;\n logLevel?: string;\n production?: boolean;\n jobMemoryWarnMB?: number;\n jobMemoryLimitMB?: number;\n }) {\n this.agent = agent;\n if (!this.agent) {\n throw new Error('No Agent file was passed to the worker');\n }\n this.requestFunc = requestFunc;\n this.loadFunc = loadFunc;\n this.loadThreshold = loadThreshold || Default.loadThreshold(production);\n this.numIdleProcesses = numIdleProcesses || Default.numIdleProcesses(production);\n this.shutdownProcessTimeout = shutdownProcessTimeout;\n this.initializeProcessTimeout = initializeProcessTimeout;\n this.permissions = permissions;\n this.agentName = agentName;\n this.workerType = workerType;\n this.maxRetry = maxRetry;\n this.wsURL = wsURL;\n this.apiKey = apiKey;\n this.apiSecret = apiSecret;\n this.host = host;\n this.port = port || Default.port(production);\n this.logLevel = logLevel;\n this.production = production;\n this.jobMemoryWarnMB = jobMemoryWarnMB;\n this.jobMemoryLimitMB = jobMemoryLimitMB;\n }\n}\n\nclass PendingAssignment {\n promise = new Promise<JobAssignment>((resolve) => {\n this.resolve = resolve; // this is how JavaScript lets you resolve promises externally\n });\n resolve(arg: JobAssignment) {\n arg; // useless call to counteract TypeScript E6133\n }\n}\n\n/**\n * Central orchestrator for all processes and job requests.\n *\n * @remarks\n * For most usecases, Worker should not be initialized or handled directly; you should instead call\n * for its creation through {@link cli.runApp}. This could, however, be useful in situations where\n * you don't have access to a command line, such as a headless program, or one that uses Agents\n * behind a wrapper.\n */\nexport class Worker {\n #opts: WorkerOptions;\n #procPool: ProcPool;\n\n #id = 'unregistered';\n #closed = true;\n #draining = false;\n #connecting = false;\n #tasks: Promise<void>[] = [];\n #pending: { [id: string]: PendingAssignment } = {};\n #close = new Future();\n\n event = new EventEmitter();\n #session: WebSocket | undefined = undefined;\n #httpServer: HTTPServer;\n #logger = log().child({ version });\n #inferenceExecutor?: InferenceProcExecutor;\n\n /* @throws {@link MissingCredentialsError} if URL, API key or API secret are missing */\n constructor(opts: WorkerOptions) {\n opts.wsURL = opts.wsURL || process.env.LIVEKIT_URL || '';\n opts.apiKey = opts.apiKey || process.env.LIVEKIT_API_KEY || '';\n opts.apiSecret = opts.apiSecret || process.env.LIVEKIT_API_SECRET || '';\n\n if (opts.wsURL === '')\n throw new MissingCredentialsError(\n 'URL is required: Set LIVEKIT_URL, run with --url, or pass wsURL in WorkerOptions',\n );\n if (opts.apiKey === '')\n throw new MissingCredentialsError(\n 'API Key is required: Set LIVEKIT_API_KEY, run with --api-key, or pass apiKey in WorkerOptions',\n );\n if (opts.apiSecret === '')\n throw new MissingCredentialsError(\n 'API Secret is required: Set LIVEKIT_API_SECRET, run with --api-secret, or pass apiSecret in WorkerOptions',\n );\n\n if (Object.entries(InferenceRunner.registeredRunners).length) {\n this.#inferenceExecutor = new InferenceProcExecutor({\n runners: InferenceRunner.registeredRunners,\n initializeTimeout: 30000,\n closeTimeout: 5000,\n memoryWarnMB: 2000,\n memoryLimitMB: 0,\n pingInterval: 5000,\n pingTimeout: 60000,\n highPingThreshold: 2500,\n });\n }\n\n this.#procPool = new ProcPool(\n opts.agent,\n opts.numIdleProcesses,\n opts.initializeProcessTimeout,\n opts.shutdownProcessTimeout,\n this.#inferenceExecutor,\n opts.jobMemoryWarnMB,\n opts.jobMemoryLimitMB,\n );\n\n this.#opts = opts;\n this.#httpServer = new HTTPServer(opts.host, opts.port, () => ({\n agent_name: opts.agentName,\n worker_type: JobType[opts.workerType],\n active_jobs: this.activeJobs.length,\n }));\n }\n\n /* @throws {@link WorkerError} if worker failed to connect or already running */\n async run() {\n if (!this.#closed) {\n throw new WorkerError('worker is already running');\n }\n\n if (this.#inferenceExecutor) {\n await this.#inferenceExecutor.start();\n await this.#inferenceExecutor.initialize();\n }\n\n this.#logger.info('starting worker');\n this.#closed = false;\n this.#procPool.start();\n\n const workerWS = async () => {\n let retries = 0;\n this.#connecting = true;\n\n while (!this.#closed) {\n const url = new URL(this.#opts.wsURL);\n url.protocol = url.protocol.replace('http', 'ws');\n const token = new AccessToken(this.#opts.apiKey, this.#opts.apiSecret);\n token.addGrant({ agent: true });\n const jwt = await token.toJwt();\n this.#session = new WebSocket(url + 'agent', {\n headers: { authorization: 'Bearer ' + jwt },\n });\n\n try {\n await new Promise((resolve, reject) => {\n this.#session!.on('open', resolve);\n this.#session!.on('error', (error) => reject(error.message));\n this.#session!.on('close', (code) => reject(`WebSocket returned ${code}`));\n });\n\n retries = 0;\n this.#logger.debug('connected to LiveKit server');\n await this.#runWS(this.#session);\n } catch (e: unknown) {\n if (e instanceof Error || e instanceof ErrorEvent) {\n e = e.message;\n }\n\n if (this.#closed) return;\n if (retries >= this.#opts.maxRetry) {\n throw new WorkerError(\n `failed to connect to LiveKit server after ${retries} attempts: ${e}`,\n );\n }\n\n retries++;\n const delay = Math.min(retries * 2, 10);\n\n this.#logger.warn(\n `failed to connect to LiveKit server, retrying in ${delay} seconds: ${e} (${retries}/${this.#opts.maxRetry})`,\n );\n\n await new Promise((resolve) => setTimeout(resolve, delay * 1000));\n }\n }\n };\n\n await Promise.all([workerWS(), this.#httpServer.run()]);\n this.#close.resolve();\n }\n\n get id(): string {\n return this.#id;\n }\n\n get activeJobs(): RunningJobInfo[] {\n return this.#procPool.processes\n .filter((proc) => proc.runningJob)\n .map((proc) => proc.runningJob!);\n }\n\n /* @throws {@link WorkerError} if worker did not drain in time */\n async drain(timeout?: number) {\n if (this.#draining) {\n return;\n }\n\n this.#logger.info('draining worker');\n this.#draining = true;\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'updateWorker',\n value: {\n status: WorkerStatus.WS_FULL,\n },\n },\n }),\n );\n\n const joinJobs = async () => {\n return Promise.all(\n this.#procPool.processes.map((proc) => {\n if (!proc.runningJob) {\n proc.close();\n }\n return proc.join();\n }),\n );\n };\n\n let timer: NodeJS.Timeout | undefined;\n if (timeout) {\n timer = setTimeout(() => {\n throw new WorkerError('timed out draining');\n }, timeout);\n }\n await joinJobs().then(() => {\n if (timeout) {\n clearTimeout(timer);\n }\n });\n }\n\n async simulateJob(roomName: string, participantIdentity?: string) {\n const client = new RoomServiceClient(this.#opts.wsURL, this.#opts.apiKey, this.#opts.apiSecret);\n const room = await client.createRoom({ name: roomName });\n let participant: ParticipantInfo | undefined = undefined;\n if (participantIdentity) {\n try {\n participant = await client.getParticipant(roomName, participantIdentity);\n } catch (e) {\n this.#logger.fatal(\n `participant with identity ${participantIdentity} not found in room ${roomName}`,\n );\n throw e;\n }\n }\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'simulateJob',\n value: {\n type: JobType.JT_PUBLISHER,\n room,\n participant,\n },\n },\n }),\n );\n }\n\n async #runWS(ws: WebSocket) {\n let closingWS = false;\n\n const send = (msg: WorkerMessage) => {\n if (closingWS) {\n this.event.off('worker_msg', send);\n return;\n }\n ws.send(msg.toBinary());\n };\n this.event.on('worker_msg', send);\n\n const close = new Promise<void>((resolve) => {\n ws.addEventListener('close', () => {\n closingWS = true;\n if (!this.#closed) {\n this.#logger.error('worker connection closed unexpectedly');\n }\n resolve();\n });\n });\n\n ws.addEventListener('error', (event) => {\n this.#logger.error('worker error:', event.message);\n });\n\n ws.addEventListener('message', (event) => {\n if (event.type !== 'message') {\n this.#logger.warn('unexpected message type: ' + event.type);\n return;\n }\n\n const msg = new ServerMessage();\n msg.fromBinary(event.data as Uint8Array);\n\n // register is the only valid first message, and it is only valid as the\n // first message\n if (this.#connecting && msg.message.case !== 'register') {\n throw new WorkerError('expected register response as first message');\n }\n\n switch (msg.message.case) {\n case 'register': {\n this.#id = msg.message.value.workerId;\n this.#logger\n .child({ id: this.id, server_info: msg.message.value.serverInfo })\n .info('registered worker');\n this.event.emit(\n 'worker_registered',\n msg.message.value.workerId,\n msg.message.value.serverInfo,\n );\n this.#connecting = false;\n break;\n }\n case 'availability': {\n if (!msg.message.value.job) return;\n const task = this.#availability(msg.message.value);\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n break;\n }\n case 'assignment': {\n if (!msg.message.value.job) return;\n const job = msg.message.value.job;\n if (job.id in this.#pending) {\n const task = this.#pending[job.id];\n delete this.#pending[job.id];\n task?.resolve(msg.message.value);\n } else {\n this.#logger.child({ job }).warn('received assignment for unknown job ' + job.id);\n }\n break;\n }\n case 'termination': {\n const task = this.#termination(msg.message.value);\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n break;\n }\n }\n });\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'register',\n value: {\n type: this.#opts.workerType,\n agentName: this.#opts.agentName,\n allowedPermissions: new ParticipantPermission({\n canPublish: this.#opts.permissions.canPublish,\n canSubscribe: this.#opts.permissions.canSubscribe,\n canPublishData: this.#opts.permissions.canPublishData,\n canUpdateMetadata: this.#opts.permissions.canUpdateMetadata,\n hidden: this.#opts.permissions.hidden,\n agent: true,\n }),\n version,\n },\n },\n }),\n );\n\n let currentStatus = WorkerStatus.WS_AVAILABLE;\n const loadMonitor = setInterval(() => {\n if (closingWS) clearInterval(loadMonitor);\n\n const oldStatus = currentStatus;\n this.#opts.loadFunc().then((currentLoad: number) => {\n const isFull = currentLoad >= this.#opts.loadThreshold;\n const currentlyAvailable = !isFull;\n currentStatus = currentlyAvailable ? WorkerStatus.WS_AVAILABLE : WorkerStatus.WS_FULL;\n\n if (oldStatus != currentStatus) {\n const extra = { load: currentLoad, loadThreshold: this.#opts.loadThreshold };\n if (isFull) {\n this.#logger.child(extra).info('worker is at full capacity, marking as unavailable');\n } else {\n this.#logger.child(extra).info('worker is below capacity, marking as available');\n }\n }\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'updateWorker',\n value: {\n load: currentLoad,\n status: currentStatus,\n },\n },\n }),\n );\n });\n }, UPDATE_LOAD_INTERVAL);\n\n await close;\n ws.removeAllListeners();\n }\n\n async #availability(msg: AvailabilityRequest) {\n let answered = false;\n\n const onReject = async () => {\n answered = true;\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'availability',\n value: {\n jobId: msg.job!.id,\n available: false,\n },\n },\n }),\n );\n };\n\n const onAccept = async (args: JobAcceptArguments) => {\n answered = true;\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'availability',\n value: {\n jobId: msg.job!.id,\n available: true,\n participantIdentity: args.identity,\n participantName: args.name,\n participantMetadata: args.metadata,\n participantAttributes: args.attributes,\n },\n },\n }),\n );\n\n this.#pending[req.id] = new PendingAssignment();\n const timer = setTimeout(() => {\n this.#logger.child({ req }).warn(`assignment for job ${req.id} timed out`);\n return;\n }, ASSIGNMENT_TIMEOUT);\n const asgn = await this.#pending[req.id]?.promise.then(async (asgn) => {\n clearTimeout(timer);\n return asgn;\n });\n\n if (asgn) {\n await this.#procPool.launchJob({\n acceptArguments: args,\n job: msg.job!,\n url: asgn.url || this.#opts.wsURL,\n token: asgn.token,\n });\n } else {\n this.#logger.child({ requestId: req.id }).warn('pending assignment not found');\n }\n };\n\n const req = new JobRequest(msg.job!, onReject, onAccept);\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('received job request');\n\n const jobRequestTask = async () => {\n try {\n await this.#opts.requestFunc(req);\n } catch (e) {\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('jobRequestFunc failed');\n await onReject();\n }\n\n if (!answered) {\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('no answer was given inside the jobRequestFunc, automatically rejecting the job');\n }\n };\n\n const task = jobRequestTask();\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n }\n\n async #termination(msg: JobTermination) {\n const proc = this.#procPool.getByJobId(msg.jobId);\n if (proc === null) {\n // safe to ignore\n return;\n }\n await proc.close();\n }\n\n async close() {\n if (this.#closed) {\n await this.#close.await;\n return;\n }\n\n this.#logger.info('shutting down worker');\n\n this.#closed = true;\n\n await this.#inferenceExecutor?.close();\n await this.#procPool.close();\n await this.#httpServer.close();\n await Promise.allSettled(this.#tasks);\n\n this.#session?.close();\n await this.#close.await;\n }\n}\n"],"mappings":"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","names":["os","i","asgn"]}
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"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"}
package/dist/worker.js CHANGED
@@ -131,7 +131,7 @@ class WorkerOptions {
131
131
  wsURL = "ws://localhost:7880",
132
132
  apiKey = void 0,
133
133
  apiSecret = void 0,
134
- host = "localhost",
134
+ host = "0.0.0.0",
135
135
  port = void 0,
136
136
  logLevel = "info",
137
137
  production = false,