@livekit/agents 1.0.1 → 1.0.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 (58) hide show
  1. package/dist/ipc/job_proc_lazy_main.cjs +4 -4
  2. package/dist/ipc/job_proc_lazy_main.cjs.map +1 -1
  3. package/dist/ipc/job_proc_lazy_main.js +6 -6
  4. package/dist/ipc/job_proc_lazy_main.js.map +1 -1
  5. package/dist/ipc/proc_pool.cjs +14 -2
  6. package/dist/ipc/proc_pool.cjs.map +1 -1
  7. package/dist/ipc/proc_pool.d.ts.map +1 -1
  8. package/dist/ipc/proc_pool.js +14 -2
  9. package/dist/ipc/proc_pool.js.map +1 -1
  10. package/dist/ipc/supervised_proc.cjs +32 -10
  11. package/dist/ipc/supervised_proc.cjs.map +1 -1
  12. package/dist/ipc/supervised_proc.d.cts +2 -0
  13. package/dist/ipc/supervised_proc.d.ts +2 -0
  14. package/dist/ipc/supervised_proc.d.ts.map +1 -1
  15. package/dist/ipc/supervised_proc.js +22 -10
  16. package/dist/ipc/supervised_proc.js.map +1 -1
  17. package/dist/job.cjs +20 -14
  18. package/dist/job.cjs.map +1 -1
  19. package/dist/job.d.cts +11 -5
  20. package/dist/job.d.ts +11 -5
  21. package/dist/job.d.ts.map +1 -1
  22. package/dist/job.js +17 -12
  23. package/dist/job.js.map +1 -1
  24. package/dist/llm/llm.cjs +4 -1
  25. package/dist/llm/llm.cjs.map +1 -1
  26. package/dist/llm/llm.d.ts.map +1 -1
  27. package/dist/llm/llm.js +4 -1
  28. package/dist/llm/llm.js.map +1 -1
  29. package/dist/vad.cjs +3 -0
  30. package/dist/vad.cjs.map +1 -1
  31. package/dist/vad.d.ts.map +1 -1
  32. package/dist/vad.js +3 -0
  33. package/dist/vad.js.map +1 -1
  34. package/dist/voice/agent_session.cjs +9 -2
  35. package/dist/voice/agent_session.cjs.map +1 -1
  36. package/dist/voice/agent_session.d.ts.map +1 -1
  37. package/dist/voice/agent_session.js +9 -2
  38. package/dist/voice/agent_session.js.map +1 -1
  39. package/dist/voice/audio_recognition.cjs +3 -0
  40. package/dist/voice/audio_recognition.cjs.map +1 -1
  41. package/dist/voice/audio_recognition.d.ts.map +1 -1
  42. package/dist/voice/audio_recognition.js +3 -0
  43. package/dist/voice/audio_recognition.js.map +1 -1
  44. package/dist/worker.cjs +25 -4
  45. package/dist/worker.cjs.map +1 -1
  46. package/dist/worker.d.ts.map +1 -1
  47. package/dist/worker.js +25 -4
  48. package/dist/worker.js.map +1 -1
  49. package/package.json +3 -1
  50. package/src/ipc/job_proc_lazy_main.ts +8 -6
  51. package/src/ipc/proc_pool.ts +14 -2
  52. package/src/ipc/supervised_proc.ts +23 -10
  53. package/src/job.ts +27 -12
  54. package/src/llm/llm.ts +4 -2
  55. package/src/vad.ts +3 -0
  56. package/src/voice/agent_session.ts +11 -2
  57. package/src/voice/audio_recognition.ts +5 -0
  58. package/src/worker.ts +25 -4
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/voice/audio_recognition.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { AudioFrame } from '@livekit/rtc-node';\nimport type { WritableStreamDefaultWriter } from 'node:stream/web';\nimport { ReadableStream } from 'node:stream/web';\nimport { type ChatContext } from '../llm/chat_context.js';\nimport { log } from '../log.js';\nimport { DeferredReadableStream, isStreamReaderReleaseError } from '../stream/deferred_stream.js';\nimport { IdentityTransform } from '../stream/identity_transform.js';\nimport { mergeReadableStreams } from '../stream/merge_readable_streams.js';\nimport { type SpeechEvent, SpeechEventType } from '../stt/stt.js';\nimport { Task, delay } from '../utils.js';\nimport { type VAD, type VADEvent, VADEventType } from '../vad.js';\nimport type { TurnDetectionMode } from './agent_session.js';\nimport type { STTNode } from './io.js';\n\nexport interface EndOfTurnInfo {\n newTranscript: string;\n transcriptionDelay: number;\n endOfUtteranceDelay: number;\n}\n\nexport interface RecognitionHooks {\n onStartOfSpeech: (ev: VADEvent) => void;\n onVADInferenceDone: (ev: VADEvent) => void;\n onEndOfSpeech: (ev: VADEvent) => void;\n onInterimTranscript: (ev: SpeechEvent) => void;\n onFinalTranscript: (ev: SpeechEvent) => void;\n onEndOfTurn: (info: EndOfTurnInfo) => Promise<boolean>;\n\n retrieveChatCtx: () => ChatContext;\n}\n\nexport interface _TurnDetector {\n unlikelyThreshold: (language?: string) => Promise<number | undefined>;\n supportsLanguage: (language?: string) => Promise<boolean>;\n predictEndOfTurn(chatCtx: ChatContext): Promise<number>;\n}\n\nexport interface AudioRecognitionOptions {\n recognitionHooks: RecognitionHooks;\n stt?: STTNode;\n vad?: VAD;\n turnDetector?: _TurnDetector;\n turnDetectionMode?: Exclude<TurnDetectionMode, _TurnDetector>;\n minEndpointingDelay: number;\n maxEndpointingDelay: number;\n}\n\nexport class AudioRecognition {\n private hooks: RecognitionHooks;\n private stt?: STTNode;\n private vad?: VAD;\n private turnDetector?: _TurnDetector;\n private turnDetectionMode?: Exclude<TurnDetectionMode, _TurnDetector>;\n private minEndpointingDelay: number;\n private maxEndpointingDelay: number;\n private lastLanguage?: string;\n\n private deferredInputStream: DeferredReadableStream<AudioFrame>;\n private logger = log();\n private lastFinalTranscriptTime = 0;\n private audioTranscript = '';\n private audioInterimTranscript = '';\n private lastSpeakingTime = 0;\n private userTurnCommitted = false;\n private speaking = false;\n private sampleRate?: number;\n\n private vadInputStream: ReadableStream<AudioFrame>;\n private sttInputStream: ReadableStream<AudioFrame>;\n private silenceAudioTransform = new IdentityTransform<AudioFrame>();\n private silenceAudioWriter: WritableStreamDefaultWriter<AudioFrame>;\n\n // all cancellable tasks\n private bounceEOUTask?: Task<void>;\n private commitUserTurnTask?: Task<void>;\n private vadTask?: Task<void>;\n private sttTask?: Task<void>;\n\n constructor(opts: AudioRecognitionOptions) {\n this.hooks = opts.recognitionHooks;\n this.stt = opts.stt;\n this.vad = opts.vad;\n this.turnDetector = opts.turnDetector;\n this.turnDetectionMode = opts.turnDetectionMode;\n this.minEndpointingDelay = opts.minEndpointingDelay;\n this.maxEndpointingDelay = opts.maxEndpointingDelay;\n this.lastLanguage = undefined;\n\n this.deferredInputStream = new DeferredReadableStream<AudioFrame>();\n const [vadInputStream, sttInputStream] = this.deferredInputStream.stream.tee();\n this.vadInputStream = vadInputStream;\n this.sttInputStream = mergeReadableStreams(sttInputStream, this.silenceAudioTransform.readable);\n this.silenceAudioWriter = this.silenceAudioTransform.writable.getWriter();\n }\n\n /**\n * Current transcript of the user's speech, including interim transcript if available.\n */\n get currentTranscript(): string {\n if (this.audioInterimTranscript) {\n return `${this.audioTranscript} ${this.audioInterimTranscript}`.trim();\n }\n return this.audioTranscript;\n }\n\n async start() {\n this.vadTask = Task.from(({ signal }) => this.createVadTask(this.vad, signal));\n this.vadTask.result.catch((err) => {\n this.logger.error(`Error running VAD task: ${err}`);\n });\n\n this.sttTask = Task.from(({ signal }) => this.createSttTask(this.stt, signal));\n this.sttTask.result.catch((err) => {\n this.logger.error(`Error running STT task: ${err}`);\n });\n }\n\n private async onSTTEvent(ev: SpeechEvent) {\n if (\n this.turnDetectionMode === 'manual' &&\n this.userTurnCommitted &&\n (this.bounceEOUTask === undefined ||\n this.bounceEOUTask.done ||\n ev.type == SpeechEventType.INTERIM_TRANSCRIPT)\n ) {\n // ignore stt event if user turn already committed and EOU task is done\n // or it's an interim transcript\n this.logger.debug(\n {\n userTurnCommitted: this.userTurnCommitted,\n eouTaskDone: this.bounceEOUTask?.done,\n evType: ev.type,\n turnDetectionMode: this.turnDetectionMode,\n },\n 'ignoring stt event',\n );\n return;\n }\n\n switch (ev.type) {\n case SpeechEventType.FINAL_TRANSCRIPT:\n this.hooks.onFinalTranscript(ev);\n const transcript = ev.alternatives?.[0]?.text;\n this.lastLanguage = ev.alternatives?.[0]?.language;\n\n if (!transcript) {\n // stt final transcript received but no transcript\n return;\n }\n\n this.logger.debug(\n {\n user_transcript: transcript,\n language: this.lastLanguage,\n },\n 'received user transcript',\n );\n\n this.lastFinalTranscriptTime = Date.now();\n this.audioTranscript += ` ${transcript}`;\n this.audioTranscript = this.audioTranscript.trimStart();\n this.audioInterimTranscript = '';\n\n if (!this.speaking) {\n if (!this.vad) {\n // Copied from python agents:\n // vad disabled, use stt timestamp\n // TODO: this would screw up transcription latency metrics\n // but we'll live with it for now.\n // the correct way is to ensure STT fires SpeechEventType.END_OF_SPEECH\n // and using that timestamp for _last_speaking_time\n this.lastSpeakingTime = Date.now();\n }\n\n if (this.vadBaseTurnDetection || this.userTurnCommitted) {\n const chatCtx = this.hooks.retrieveChatCtx();\n this.logger.debug('running EOU detection on stt FINAL_TRANSCRIPT');\n this.runEOUDetection(chatCtx);\n }\n }\n break;\n case SpeechEventType.INTERIM_TRANSCRIPT:\n this.logger.debug({ transcript: ev.alternatives?.[0]?.text }, 'interim transcript');\n this.hooks.onInterimTranscript(ev);\n this.audioInterimTranscript = ev.alternatives?.[0]?.text ?? '';\n break;\n case SpeechEventType.END_OF_SPEECH:\n if (this.turnDetectionMode !== 'stt') break;\n this.userTurnCommitted = true;\n\n if (!this.speaking) {\n const chatCtx = this.hooks.retrieveChatCtx();\n this.logger.debug('running EOU detection on stt END_OF_SPEECH');\n this.runEOUDetection(chatCtx);\n }\n }\n }\n\n private runEOUDetection(chatCtx: ChatContext) {\n this.logger.debug(\n {\n stt: this.stt,\n audioTranscript: this.audioTranscript,\n turnDetectionMode: this.turnDetectionMode,\n },\n 'running EOU detection',\n );\n\n if (this.stt && !this.audioTranscript && this.turnDetectionMode !== 'manual') {\n // stt enabled but no transcript yet\n this.logger.debug('skipping EOU detection');\n return;\n }\n\n chatCtx = chatCtx.copy();\n chatCtx.addMessage({ role: 'user', content: this.audioTranscript });\n\n const turnDetector =\n // disable EOU model if manual turn detection enabled\n this.audioTranscript && this.turnDetectionMode !== 'manual' ? this.turnDetector : undefined;\n\n const bounceEOUTask = (lastSpeakingTime: number) => async (controller: AbortController) => {\n let endpointingDelay = this.minEndpointingDelay;\n\n // TODO(AJS-74): need to support actual turn detection model plugins for following code to run\n if (turnDetector) {\n this.logger.debug('Running turn detector model');\n if (!turnDetector.supportsLanguage(this.lastLanguage)) {\n this.logger.debug(`Turn detector does not support language ${this.lastLanguage}`);\n } else {\n const endOfTurnProbability = await turnDetector.predictEndOfTurn(chatCtx);\n this.logger.debug(\n { endOfTurnProbability, language: this.lastLanguage },\n 'end of turn probability',\n );\n\n const unlikelyThreshold = await turnDetector.unlikelyThreshold(this.lastLanguage);\n this.logger.debug(\n {\n unlikelyThreshold,\n endOfTurnProbability,\n language: this.lastLanguage,\n transcript: this.audioTranscript,\n },\n 'EOU Detection',\n );\n\n if (unlikelyThreshold && endOfTurnProbability < unlikelyThreshold) {\n endpointingDelay = this.maxEndpointingDelay;\n }\n }\n }\n\n const extraSleep = lastSpeakingTime + endpointingDelay - Date.now();\n // add delay to see if there's a potential upcoming EOU task that cancels this one\n await delay(Math.max(extraSleep, 0), { signal: controller.signal });\n\n this.logger.debug({ transcript: this.audioTranscript }, 'end of user turn');\n\n const committed = await this.hooks.onEndOfTurn({\n newTranscript: this.audioTranscript,\n transcriptionDelay: Math.max(this.lastFinalTranscriptTime - lastSpeakingTime, 0),\n endOfUtteranceDelay: Date.now() - lastSpeakingTime,\n });\n\n if (committed) {\n // clear the transcript if the user turn was committed\n this.audioTranscript = '';\n }\n\n this.userTurnCommitted = false;\n };\n\n // cancel any existing EOU task\n this.bounceEOUTask?.cancel();\n this.bounceEOUTask = Task.from(bounceEOUTask(this.lastSpeakingTime));\n\n this.bounceEOUTask.result\n .then(() => {\n this.logger.debug('EOU detection task completed');\n })\n .catch((err: unknown) => {\n if (err instanceof Error && err.message.includes('This operation was aborted')) {\n // ignore aborted errors\n return;\n }\n this.logger.error(err, 'Error in EOU detection task:');\n });\n }\n\n private async createSttTask(stt: STTNode | undefined, signal: AbortSignal) {\n if (!stt) return;\n\n this.logger.debug('createSttTask: create stt stream from stt node');\n\n const sttStream = await stt(this.sttInputStream, {});\n\n if (signal.aborted || sttStream === null) return;\n\n if (sttStream instanceof ReadableStream) {\n const reader = sttStream.getReader();\n\n signal.addEventListener('abort', async () => {\n try {\n reader.releaseLock();\n await sttStream?.cancel();\n } catch (e) {\n this.logger.debug('createSttTask: error during abort handler:', e);\n }\n });\n\n try {\n while (true) {\n if (signal.aborted) break;\n\n const { done, value: ev } = await reader.read();\n if (done) break;\n\n if (typeof ev === 'string') {\n throw new Error('STT node must yield SpeechEvent');\n } else {\n await this.onSTTEvent(ev);\n }\n }\n } catch (e) {\n if (isStreamReaderReleaseError(e)) {\n return;\n }\n this.logger.error({ error: e }, 'createSttTask: error reading sttStream');\n } finally {\n reader.releaseLock();\n try {\n await sttStream.cancel();\n } catch (e) {\n this.logger.debug(\n 'createSttTask: error cancelling sttStream (may already be cancelled):',\n e,\n );\n }\n }\n }\n }\n\n private async createVadTask(vad: VAD | undefined, signal: AbortSignal) {\n if (!vad) return;\n\n const vadStream = vad.stream();\n vadStream.updateInputStream(this.vadInputStream);\n\n const abortHandler = () => {\n vadStream.detachInputStream();\n vadStream.close();\n signal.removeEventListener('abort', abortHandler);\n };\n signal.addEventListener('abort', abortHandler);\n\n try {\n for await (const ev of vadStream) {\n if (signal.aborted) break;\n\n switch (ev.type) {\n case VADEventType.START_OF_SPEECH:\n this.logger.debug('VAD task: START_OF_SPEECH');\n this.hooks.onStartOfSpeech(ev);\n this.speaking = true;\n\n this.bounceEOUTask?.cancel();\n break;\n case VADEventType.INFERENCE_DONE:\n this.hooks.onVADInferenceDone(ev);\n break;\n case VADEventType.END_OF_SPEECH:\n this.logger.debug('VAD task: END_OF_SPEECH');\n this.hooks.onEndOfSpeech(ev);\n this.speaking = false;\n // when VAD fires END_OF_SPEECH, it already waited for the silence_duration\n this.lastSpeakingTime = Date.now() - ev.silenceDuration;\n\n if (\n this.vadBaseTurnDetection ||\n (this.turnDetectionMode === 'stt' && this.userTurnCommitted)\n ) {\n const chatCtx = this.hooks.retrieveChatCtx();\n this.runEOUDetection(chatCtx);\n }\n break;\n }\n }\n } catch (e) {\n this.logger.error(e, 'Error in VAD task');\n } finally {\n this.logger.debug('VAD task closed');\n }\n }\n\n setInputAudioStream(audioStream: ReadableStream<AudioFrame>) {\n this.deferredInputStream.setSource(audioStream);\n }\n\n detachInputAudioStream() {\n this.deferredInputStream.detachSource();\n }\n\n clearUserTurn() {\n this.audioTranscript = '';\n this.audioInterimTranscript = '';\n this.userTurnCommitted = false;\n\n this.sttTask?.cancelAndWait().finally(() => {\n this.sttTask = Task.from(({ signal }) => this.createSttTask(this.stt, signal));\n this.sttTask.result.catch((err) => {\n this.logger.error(`Error running STT task: ${err}`);\n });\n });\n }\n\n commitUserTurn(audioDetached: boolean) {\n const commitUserTurnTask =\n (delayDuration: number = 500) =>\n async (controller: AbortController) => {\n if (Date.now() - this.lastFinalTranscriptTime > delayDuration) {\n // flush the stt by pushing silence\n if (audioDetached && this.sampleRate !== undefined) {\n const numSamples = Math.floor(this.sampleRate * 0.5);\n const silence = new Int16Array(numSamples * 2);\n const silenceFrame = new AudioFrame(silence, this.sampleRate, 1, numSamples);\n this.silenceAudioWriter.write(silenceFrame);\n }\n\n // wait for the final transcript to be available\n await delay(delayDuration, { signal: controller.signal });\n }\n\n if (this.audioInterimTranscript) {\n // append interim transcript in case the final transcript is not ready\n this.audioTranscript = `${this.audioTranscript} ${this.audioInterimTranscript}`.trim();\n }\n this.audioInterimTranscript = '';\n\n const chatCtx = this.hooks.retrieveChatCtx();\n this.logger.debug('running EOU detection on commitUserTurn');\n this.runEOUDetection(chatCtx);\n this.userTurnCommitted = true;\n };\n\n // cancel any existing commit user turn task\n this.commitUserTurnTask?.cancel();\n this.commitUserTurnTask = Task.from(commitUserTurnTask());\n\n this.commitUserTurnTask.result\n .then(() => {\n this.logger.debug('User turn committed');\n })\n .catch((err: unknown) => {\n this.logger.error(err, 'Error in user turn commit task:');\n });\n }\n\n async close() {\n this.detachInputAudioStream();\n await this.commitUserTurnTask?.cancelAndWait();\n await this.sttTask?.cancelAndWait();\n await this.vadTask?.cancelAndWait();\n await this.bounceEOUTask?.cancelAndWait();\n }\n\n private get vadBaseTurnDetection() {\n return ['vad', undefined].includes(this.turnDetectionMode);\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/voice/audio_recognition.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { AudioFrame } from '@livekit/rtc-node';\nimport type { WritableStreamDefaultWriter } from 'node:stream/web';\nimport { ReadableStream } from 'node:stream/web';\nimport { type ChatContext } from '../llm/chat_context.js';\nimport { log } from '../log.js';\nimport { DeferredReadableStream, isStreamReaderReleaseError } from '../stream/deferred_stream.js';\nimport { IdentityTransform } from '../stream/identity_transform.js';\nimport { mergeReadableStreams } from '../stream/merge_readable_streams.js';\nimport { type SpeechEvent, SpeechEventType } from '../stt/stt.js';\nimport { Task, delay } from '../utils.js';\nimport { type VAD, type VADEvent, VADEventType } from '../vad.js';\nimport type { TurnDetectionMode } from './agent_session.js';\nimport type { STTNode } from './io.js';\n\nexport interface EndOfTurnInfo {\n newTranscript: string;\n transcriptionDelay: number;\n endOfUtteranceDelay: number;\n}\n\nexport interface RecognitionHooks {\n onStartOfSpeech: (ev: VADEvent) => void;\n onVADInferenceDone: (ev: VADEvent) => void;\n onEndOfSpeech: (ev: VADEvent) => void;\n onInterimTranscript: (ev: SpeechEvent) => void;\n onFinalTranscript: (ev: SpeechEvent) => void;\n onEndOfTurn: (info: EndOfTurnInfo) => Promise<boolean>;\n\n retrieveChatCtx: () => ChatContext;\n}\n\nexport interface _TurnDetector {\n unlikelyThreshold: (language?: string) => Promise<number | undefined>;\n supportsLanguage: (language?: string) => Promise<boolean>;\n predictEndOfTurn(chatCtx: ChatContext): Promise<number>;\n}\n\nexport interface AudioRecognitionOptions {\n recognitionHooks: RecognitionHooks;\n stt?: STTNode;\n vad?: VAD;\n turnDetector?: _TurnDetector;\n turnDetectionMode?: Exclude<TurnDetectionMode, _TurnDetector>;\n minEndpointingDelay: number;\n maxEndpointingDelay: number;\n}\n\nexport class AudioRecognition {\n private hooks: RecognitionHooks;\n private stt?: STTNode;\n private vad?: VAD;\n private turnDetector?: _TurnDetector;\n private turnDetectionMode?: Exclude<TurnDetectionMode, _TurnDetector>;\n private minEndpointingDelay: number;\n private maxEndpointingDelay: number;\n private lastLanguage?: string;\n\n private deferredInputStream: DeferredReadableStream<AudioFrame>;\n private logger = log();\n private lastFinalTranscriptTime = 0;\n private audioTranscript = '';\n private audioInterimTranscript = '';\n private lastSpeakingTime = 0;\n private userTurnCommitted = false;\n private speaking = false;\n private sampleRate?: number;\n\n private vadInputStream: ReadableStream<AudioFrame>;\n private sttInputStream: ReadableStream<AudioFrame>;\n private silenceAudioTransform = new IdentityTransform<AudioFrame>();\n private silenceAudioWriter: WritableStreamDefaultWriter<AudioFrame>;\n\n // all cancellable tasks\n private bounceEOUTask?: Task<void>;\n private commitUserTurnTask?: Task<void>;\n private vadTask?: Task<void>;\n private sttTask?: Task<void>;\n\n constructor(opts: AudioRecognitionOptions) {\n this.hooks = opts.recognitionHooks;\n this.stt = opts.stt;\n this.vad = opts.vad;\n this.turnDetector = opts.turnDetector;\n this.turnDetectionMode = opts.turnDetectionMode;\n this.minEndpointingDelay = opts.minEndpointingDelay;\n this.maxEndpointingDelay = opts.maxEndpointingDelay;\n this.lastLanguage = undefined;\n\n this.deferredInputStream = new DeferredReadableStream<AudioFrame>();\n const [vadInputStream, sttInputStream] = this.deferredInputStream.stream.tee();\n this.vadInputStream = vadInputStream;\n this.sttInputStream = mergeReadableStreams(sttInputStream, this.silenceAudioTransform.readable);\n this.silenceAudioWriter = this.silenceAudioTransform.writable.getWriter();\n }\n\n /**\n * Current transcript of the user's speech, including interim transcript if available.\n */\n get currentTranscript(): string {\n if (this.audioInterimTranscript) {\n return `${this.audioTranscript} ${this.audioInterimTranscript}`.trim();\n }\n return this.audioTranscript;\n }\n\n async start() {\n this.vadTask = Task.from(({ signal }) => this.createVadTask(this.vad, signal));\n this.vadTask.result.catch((err) => {\n this.logger.error(`Error running VAD task: ${err}`);\n });\n\n this.sttTask = Task.from(({ signal }) => this.createSttTask(this.stt, signal));\n this.sttTask.result.catch((err) => {\n this.logger.error(`Error running STT task: ${err}`);\n });\n }\n\n private async onSTTEvent(ev: SpeechEvent) {\n if (\n this.turnDetectionMode === 'manual' &&\n this.userTurnCommitted &&\n (this.bounceEOUTask === undefined ||\n this.bounceEOUTask.done ||\n ev.type == SpeechEventType.INTERIM_TRANSCRIPT)\n ) {\n // ignore stt event if user turn already committed and EOU task is done\n // or it's an interim transcript\n this.logger.debug(\n {\n userTurnCommitted: this.userTurnCommitted,\n eouTaskDone: this.bounceEOUTask?.done,\n evType: ev.type,\n turnDetectionMode: this.turnDetectionMode,\n },\n 'ignoring stt event',\n );\n return;\n }\n\n switch (ev.type) {\n case SpeechEventType.FINAL_TRANSCRIPT:\n this.hooks.onFinalTranscript(ev);\n const transcript = ev.alternatives?.[0]?.text;\n this.lastLanguage = ev.alternatives?.[0]?.language;\n\n if (!transcript) {\n // stt final transcript received but no transcript\n return;\n }\n\n this.logger.debug(\n {\n user_transcript: transcript,\n language: this.lastLanguage,\n },\n 'received user transcript',\n );\n\n this.lastFinalTranscriptTime = Date.now();\n this.audioTranscript += ` ${transcript}`;\n this.audioTranscript = this.audioTranscript.trimStart();\n this.audioInterimTranscript = '';\n\n if (!this.speaking) {\n if (!this.vad) {\n // Copied from python agents:\n // vad disabled, use stt timestamp\n // TODO: this would screw up transcription latency metrics\n // but we'll live with it for now.\n // the correct way is to ensure STT fires SpeechEventType.END_OF_SPEECH\n // and using that timestamp for _last_speaking_time\n this.lastSpeakingTime = Date.now();\n }\n\n if (this.vadBaseTurnDetection || this.userTurnCommitted) {\n const chatCtx = this.hooks.retrieveChatCtx();\n this.logger.debug('running EOU detection on stt FINAL_TRANSCRIPT');\n this.runEOUDetection(chatCtx);\n }\n }\n break;\n case SpeechEventType.INTERIM_TRANSCRIPT:\n this.logger.debug({ transcript: ev.alternatives?.[0]?.text }, 'interim transcript');\n this.hooks.onInterimTranscript(ev);\n this.audioInterimTranscript = ev.alternatives?.[0]?.text ?? '';\n break;\n case SpeechEventType.END_OF_SPEECH:\n if (this.turnDetectionMode !== 'stt') break;\n this.userTurnCommitted = true;\n\n if (!this.speaking) {\n const chatCtx = this.hooks.retrieveChatCtx();\n this.logger.debug('running EOU detection on stt END_OF_SPEECH');\n this.runEOUDetection(chatCtx);\n }\n }\n }\n\n private runEOUDetection(chatCtx: ChatContext) {\n this.logger.debug(\n {\n stt: this.stt,\n audioTranscript: this.audioTranscript,\n turnDetectionMode: this.turnDetectionMode,\n },\n 'running EOU detection',\n );\n\n if (this.stt && !this.audioTranscript && this.turnDetectionMode !== 'manual') {\n // stt enabled but no transcript yet\n this.logger.debug('skipping EOU detection');\n return;\n }\n\n chatCtx = chatCtx.copy();\n chatCtx.addMessage({ role: 'user', content: this.audioTranscript });\n\n const turnDetector =\n // disable EOU model if manual turn detection enabled\n this.audioTranscript && this.turnDetectionMode !== 'manual' ? this.turnDetector : undefined;\n\n const bounceEOUTask = (lastSpeakingTime: number) => async (controller: AbortController) => {\n let endpointingDelay = this.minEndpointingDelay;\n\n // TODO(AJS-74): need to support actual turn detection model plugins for following code to run\n if (turnDetector) {\n this.logger.debug('Running turn detector model');\n if (!turnDetector.supportsLanguage(this.lastLanguage)) {\n this.logger.debug(`Turn detector does not support language ${this.lastLanguage}`);\n } else {\n const endOfTurnProbability = await turnDetector.predictEndOfTurn(chatCtx);\n this.logger.debug(\n { endOfTurnProbability, language: this.lastLanguage },\n 'end of turn probability',\n );\n\n const unlikelyThreshold = await turnDetector.unlikelyThreshold(this.lastLanguage);\n this.logger.debug(\n {\n unlikelyThreshold,\n endOfTurnProbability,\n language: this.lastLanguage,\n transcript: this.audioTranscript,\n },\n 'EOU Detection',\n );\n\n if (unlikelyThreshold && endOfTurnProbability < unlikelyThreshold) {\n endpointingDelay = this.maxEndpointingDelay;\n }\n }\n }\n\n const extraSleep = lastSpeakingTime + endpointingDelay - Date.now();\n // add delay to see if there's a potential upcoming EOU task that cancels this one\n await delay(Math.max(extraSleep, 0), { signal: controller.signal });\n\n this.logger.debug({ transcript: this.audioTranscript }, 'end of user turn');\n\n const committed = await this.hooks.onEndOfTurn({\n newTranscript: this.audioTranscript,\n transcriptionDelay: Math.max(this.lastFinalTranscriptTime - lastSpeakingTime, 0),\n endOfUtteranceDelay: Date.now() - lastSpeakingTime,\n });\n\n if (committed) {\n // clear the transcript if the user turn was committed\n this.audioTranscript = '';\n }\n\n this.userTurnCommitted = false;\n };\n\n // cancel any existing EOU task\n this.bounceEOUTask?.cancel();\n this.bounceEOUTask = Task.from(bounceEOUTask(this.lastSpeakingTime));\n\n this.bounceEOUTask.result\n .then(() => {\n this.logger.debug('EOU detection task completed');\n })\n .catch((err: unknown) => {\n if (err instanceof Error && err.message.includes('This operation was aborted')) {\n // ignore aborted errors\n return;\n }\n this.logger.error(err, 'Error in EOU detection task:');\n });\n }\n\n private async createSttTask(stt: STTNode | undefined, signal: AbortSignal) {\n if (!stt) return;\n\n this.logger.debug('createSttTask: create stt stream from stt node');\n\n const sttStream = await stt(this.sttInputStream, {});\n\n if (signal.aborted || sttStream === null) return;\n\n if (sttStream instanceof ReadableStream) {\n const reader = sttStream.getReader();\n\n signal.addEventListener('abort', async () => {\n try {\n reader.releaseLock();\n await sttStream?.cancel();\n } catch (e) {\n this.logger.debug('createSttTask: error during abort handler:', e);\n }\n });\n\n try {\n while (true) {\n if (signal.aborted) break;\n\n const { done, value: ev } = await reader.read();\n if (done) break;\n\n if (typeof ev === 'string') {\n throw new Error('STT node must yield SpeechEvent');\n } else {\n await this.onSTTEvent(ev);\n }\n }\n } catch (e) {\n if (isStreamReaderReleaseError(e)) {\n return;\n }\n this.logger.error({ error: e }, 'createSttTask: error reading sttStream');\n } finally {\n reader.releaseLock();\n try {\n await sttStream.cancel();\n } catch (e) {\n this.logger.debug(\n 'createSttTask: error cancelling sttStream (may already be cancelled):',\n e,\n );\n }\n }\n }\n }\n\n private async createVadTask(vad: VAD | undefined, signal: AbortSignal) {\n if (!vad) return;\n\n const vadStream = vad.stream();\n vadStream.updateInputStream(this.vadInputStream);\n\n const abortHandler = () => {\n vadStream.detachInputStream();\n vadStream.close();\n signal.removeEventListener('abort', abortHandler);\n };\n signal.addEventListener('abort', abortHandler);\n\n try {\n for await (const ev of vadStream) {\n if (signal.aborted) break;\n\n switch (ev.type) {\n case VADEventType.START_OF_SPEECH:\n this.logger.debug('VAD task: START_OF_SPEECH');\n this.hooks.onStartOfSpeech(ev);\n this.speaking = true;\n\n // Capture sample rate from the first VAD event if not already set\n if (ev.frames.length > 0 && ev.frames[0]) {\n this.sampleRate = ev.frames[0].sampleRate;\n }\n\n this.bounceEOUTask?.cancel();\n break;\n case VADEventType.INFERENCE_DONE:\n this.hooks.onVADInferenceDone(ev);\n break;\n case VADEventType.END_OF_SPEECH:\n this.logger.debug('VAD task: END_OF_SPEECH');\n this.hooks.onEndOfSpeech(ev);\n this.speaking = false;\n // when VAD fires END_OF_SPEECH, it already waited for the silence_duration\n this.lastSpeakingTime = Date.now() - ev.silenceDuration;\n\n if (\n this.vadBaseTurnDetection ||\n (this.turnDetectionMode === 'stt' && this.userTurnCommitted)\n ) {\n const chatCtx = this.hooks.retrieveChatCtx();\n this.runEOUDetection(chatCtx);\n }\n break;\n }\n }\n } catch (e) {\n this.logger.error(e, 'Error in VAD task');\n } finally {\n this.logger.debug('VAD task closed');\n }\n }\n\n setInputAudioStream(audioStream: ReadableStream<AudioFrame>) {\n this.deferredInputStream.setSource(audioStream);\n }\n\n detachInputAudioStream() {\n this.deferredInputStream.detachSource();\n }\n\n clearUserTurn() {\n this.audioTranscript = '';\n this.audioInterimTranscript = '';\n this.userTurnCommitted = false;\n\n this.sttTask?.cancelAndWait().finally(() => {\n this.sttTask = Task.from(({ signal }) => this.createSttTask(this.stt, signal));\n this.sttTask.result.catch((err) => {\n this.logger.error(`Error running STT task: ${err}`);\n });\n });\n }\n\n commitUserTurn(audioDetached: boolean) {\n const commitUserTurnTask =\n (delayDuration: number = 500) =>\n async (controller: AbortController) => {\n if (Date.now() - this.lastFinalTranscriptTime > delayDuration) {\n // flush the stt by pushing silence\n if (audioDetached && this.sampleRate !== undefined) {\n const numSamples = Math.floor(this.sampleRate * 0.5);\n const silence = new Int16Array(numSamples * 2);\n const silenceFrame = new AudioFrame(silence, this.sampleRate, 1, numSamples);\n this.silenceAudioWriter.write(silenceFrame);\n }\n\n // wait for the final transcript to be available\n await delay(delayDuration, { signal: controller.signal });\n }\n\n if (this.audioInterimTranscript) {\n // append interim transcript in case the final transcript is not ready\n this.audioTranscript = `${this.audioTranscript} ${this.audioInterimTranscript}`.trim();\n }\n this.audioInterimTranscript = '';\n\n const chatCtx = this.hooks.retrieveChatCtx();\n this.logger.debug('running EOU detection on commitUserTurn');\n this.runEOUDetection(chatCtx);\n this.userTurnCommitted = true;\n };\n\n // cancel any existing commit user turn task\n this.commitUserTurnTask?.cancel();\n this.commitUserTurnTask = Task.from(commitUserTurnTask());\n\n this.commitUserTurnTask.result\n .then(() => {\n this.logger.debug('User turn committed');\n })\n .catch((err: unknown) => {\n this.logger.error(err, 'Error in user turn commit task:');\n });\n }\n\n async close() {\n this.detachInputAudioStream();\n await this.commitUserTurnTask?.cancelAndWait();\n await this.sttTask?.cancelAndWait();\n await this.vadTask?.cancelAndWait();\n await this.bounceEOUTask?.cancelAndWait();\n }\n\n private get vadBaseTurnDetection() {\n return ['vad', undefined].includes(this.turnDetectionMode);\n }\n}\n"],"mappings":"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","names":[]}
package/dist/worker.cjs CHANGED
@@ -170,7 +170,7 @@ class WorkerOptions {
170
170
  port = void 0,
171
171
  logLevel = "info",
172
172
  production = false,
173
- jobMemoryWarnMB = 300,
173
+ jobMemoryWarnMB = 500,
174
174
  jobMemoryLimitMB = 0
175
175
  }) {
176
176
  this.agent = agent;
@@ -465,7 +465,14 @@ class Worker {
465
465
  if (!msg.message.value.job) return;
466
466
  const task = this.#availability(msg.message.value);
467
467
  this.#tasks.push(task);
468
- task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));
468
+ task.finally(() => {
469
+ const taskIndex = this.#tasks.indexOf(task);
470
+ if (taskIndex !== -1) {
471
+ this.#tasks.splice(taskIndex, 1);
472
+ } else {
473
+ throw new Error(`task ${task} not found in tasks`);
474
+ }
475
+ });
469
476
  break;
470
477
  }
471
478
  case "assignment": {
@@ -483,7 +490,14 @@ class Worker {
483
490
  case "termination": {
484
491
  const task = this.#termination(msg.message.value);
485
492
  this.#tasks.push(task);
486
- task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));
493
+ task.finally(() => {
494
+ const taskIndex = this.#tasks.indexOf(task);
495
+ if (taskIndex !== -1) {
496
+ this.#tasks.splice(taskIndex, 1);
497
+ } else {
498
+ throw new Error(`task ${task} not found in tasks`);
499
+ }
500
+ });
487
501
  break;
488
502
  }
489
503
  }
@@ -614,7 +628,14 @@ class Worker {
614
628
  };
615
629
  const task = jobRequestTask();
616
630
  this.#tasks.push(task);
617
- task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));
631
+ task.finally(() => {
632
+ const taskIndex = this.#tasks.indexOf(task);
633
+ if (taskIndex !== -1) {
634
+ this.#tasks.splice(taskIndex, 1);
635
+ } else {
636
+ throw new Error(`task ${task} not found in tasks`);
637
+ }
638
+ });
618
639
  }
619
640
  async #termination(msg) {
620
641
  const proc = this.#procPool.getByJobId(msg.jobId);
@@ -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;\nconst PROJECT_TYPE = 'nodejs';\n\nclass Default {\n static loadThreshold(production: boolean): number {\n if (production) {\n return 0.7;\n } else {\n return Infinity;\n }\n }\n\n static numIdleProcesses(production: boolean): number {\n if (production) {\n // TODO: use number of cores\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 environment 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};\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst defaultCpuLoad = async (worker: Worker): 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: (worker: Worker) => 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 workerToken?: string;\n host: string;\n port: number;\n logLevel: string;\n production: boolean;\n jobMemoryWarnMB: number;\n jobMemoryLimitMB: number;\n\n /** @param options - Worker 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 workerToken = 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?: (worker: Worker) => 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 workerToken?: 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.workerToken = workerToken;\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 (opts.workerToken) {\n if (opts.loadFunc !== defaultCpuLoad) {\n this.#logger.warn(\n 'custom loadFunc is not supported when deploying to Cloud, using defaults',\n );\n opts.loadFunc = defaultCpuLoad;\n }\n const loadThreshold = Default.loadThreshold(opts.production);\n if (opts.loadThreshold !== loadThreshold) {\n this.#logger.warn(\n 'custom loadThreshold is not supported when deploying to Cloud, using defaults',\n );\n opts.loadThreshold = loadThreshold;\n }\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 sdk_version: version,\n project_type: PROJECT_TYPE,\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 const wsUrl = new URL(url + 'agent');\n if (this.#opts.workerToken) {\n wsUrl.searchParams.append('worker_token', this.#opts.workerToken);\n }\n this.#session = new WebSocket(wsUrl, {\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.debug('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(this).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 workerId: this.id,\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.debug('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;\nconst PROJECT_TYPE = 'nodejs';\n\nclass Default {\n static loadThreshold(production: boolean): number {\n if (production) {\n return 0.7;\n } else {\n return Infinity;\n }\n }\n\n static numIdleProcesses(production: boolean): number {\n if (production) {\n // TODO: use number of cores\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 environment 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};\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst defaultCpuLoad = async (worker: Worker): 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: (worker: Worker) => 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 workerToken?: string;\n host: string;\n port: number;\n logLevel: string;\n production: boolean;\n jobMemoryWarnMB: number;\n jobMemoryLimitMB: number;\n\n /** @param options - Worker 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 workerToken = undefined,\n host = '0.0.0.0',\n port = undefined,\n logLevel = 'info',\n production = false,\n jobMemoryWarnMB = 500,\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?: (worker: Worker) => 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 workerToken?: 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.workerToken = workerToken;\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 (opts.workerToken) {\n if (opts.loadFunc !== defaultCpuLoad) {\n this.#logger.warn(\n 'custom loadFunc is not supported when deploying to Cloud, using defaults',\n );\n opts.loadFunc = defaultCpuLoad;\n }\n const loadThreshold = Default.loadThreshold(opts.production);\n if (opts.loadThreshold !== loadThreshold) {\n this.#logger.warn(\n 'custom loadThreshold is not supported when deploying to Cloud, using defaults',\n );\n opts.loadThreshold = loadThreshold;\n }\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 sdk_version: version,\n project_type: PROJECT_TYPE,\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 const wsUrl = new URL(url + 'agent');\n if (this.#opts.workerToken) {\n wsUrl.searchParams.append('worker_token', this.#opts.workerToken);\n }\n this.#session = new WebSocket(wsUrl, {\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.debug('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(() => {\n const taskIndex = this.#tasks.indexOf(task);\n if (taskIndex !== -1) {\n this.#tasks.splice(taskIndex, 1);\n } else {\n throw new Error(`task ${task} not found in tasks`);\n }\n });\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(() => {\n const taskIndex = this.#tasks.indexOf(task);\n if (taskIndex !== -1) {\n this.#tasks.splice(taskIndex, 1);\n } else {\n throw new Error(`task ${task} not found in tasks`);\n }\n });\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(this).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 workerId: this.id,\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(() => {\n const taskIndex = this.#tasks.indexOf(task);\n if (taskIndex !== -1) {\n this.#tasks.splice(taskIndex, 1);\n } else {\n throw new Error(`task ${task} not found in tasks`);\n }\n });\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.debug('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
@@ -138,7 +138,7 @@ class WorkerOptions {
138
138
  port = void 0,
139
139
  logLevel = "info",
140
140
  production = false,
141
- jobMemoryWarnMB = 300,
141
+ jobMemoryWarnMB = 500,
142
142
  jobMemoryLimitMB = 0
143
143
  }) {
144
144
  this.agent = agent;
@@ -433,7 +433,14 @@ class Worker {
433
433
  if (!msg.message.value.job) return;
434
434
  const task = this.#availability(msg.message.value);
435
435
  this.#tasks.push(task);
436
- task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));
436
+ task.finally(() => {
437
+ const taskIndex = this.#tasks.indexOf(task);
438
+ if (taskIndex !== -1) {
439
+ this.#tasks.splice(taskIndex, 1);
440
+ } else {
441
+ throw new Error(`task ${task} not found in tasks`);
442
+ }
443
+ });
437
444
  break;
438
445
  }
439
446
  case "assignment": {
@@ -451,7 +458,14 @@ class Worker {
451
458
  case "termination": {
452
459
  const task = this.#termination(msg.message.value);
453
460
  this.#tasks.push(task);
454
- task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));
461
+ task.finally(() => {
462
+ const taskIndex = this.#tasks.indexOf(task);
463
+ if (taskIndex !== -1) {
464
+ this.#tasks.splice(taskIndex, 1);
465
+ } else {
466
+ throw new Error(`task ${task} not found in tasks`);
467
+ }
468
+ });
455
469
  break;
456
470
  }
457
471
  }
@@ -582,7 +596,14 @@ class Worker {
582
596
  };
583
597
  const task = jobRequestTask();
584
598
  this.#tasks.push(task);
585
- task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));
599
+ task.finally(() => {
600
+ const taskIndex = this.#tasks.indexOf(task);
601
+ if (taskIndex !== -1) {
602
+ this.#tasks.splice(taskIndex, 1);
603
+ } else {
604
+ throw new Error(`task ${task} not found in tasks`);
605
+ }
606
+ });
586
607
  }
587
608
  async #termination(msg) {
588
609
  const proc = this.#procPool.getByJobId(msg.jobId);
@@ -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;\nconst PROJECT_TYPE = 'nodejs';\n\nclass Default {\n static loadThreshold(production: boolean): number {\n if (production) {\n return 0.7;\n } else {\n return Infinity;\n }\n }\n\n static numIdleProcesses(production: boolean): number {\n if (production) {\n // TODO: use number of cores\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 environment 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};\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst defaultCpuLoad = async (worker: Worker): 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: (worker: Worker) => 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 workerToken?: string;\n host: string;\n port: number;\n logLevel: string;\n production: boolean;\n jobMemoryWarnMB: number;\n jobMemoryLimitMB: number;\n\n /** @param options - Worker 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 workerToken = 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?: (worker: Worker) => 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 workerToken?: 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.workerToken = workerToken;\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 (opts.workerToken) {\n if (opts.loadFunc !== defaultCpuLoad) {\n this.#logger.warn(\n 'custom loadFunc is not supported when deploying to Cloud, using defaults',\n );\n opts.loadFunc = defaultCpuLoad;\n }\n const loadThreshold = Default.loadThreshold(opts.production);\n if (opts.loadThreshold !== loadThreshold) {\n this.#logger.warn(\n 'custom loadThreshold is not supported when deploying to Cloud, using defaults',\n );\n opts.loadThreshold = loadThreshold;\n }\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 sdk_version: version,\n project_type: PROJECT_TYPE,\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 const wsUrl = new URL(url + 'agent');\n if (this.#opts.workerToken) {\n wsUrl.searchParams.append('worker_token', this.#opts.workerToken);\n }\n this.#session = new WebSocket(wsUrl, {\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.debug('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(this).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 workerId: this.id,\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.debug('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":["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;\nconst PROJECT_TYPE = 'nodejs';\n\nclass Default {\n static loadThreshold(production: boolean): number {\n if (production) {\n return 0.7;\n } else {\n return Infinity;\n }\n }\n\n static numIdleProcesses(production: boolean): number {\n if (production) {\n // TODO: use number of cores\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 environment 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};\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst defaultCpuLoad = async (worker: Worker): 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: (worker: Worker) => 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 workerToken?: string;\n host: string;\n port: number;\n logLevel: string;\n production: boolean;\n jobMemoryWarnMB: number;\n jobMemoryLimitMB: number;\n\n /** @param options - Worker 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 workerToken = undefined,\n host = '0.0.0.0',\n port = undefined,\n logLevel = 'info',\n production = false,\n jobMemoryWarnMB = 500,\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?: (worker: Worker) => 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 workerToken?: 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.workerToken = workerToken;\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 (opts.workerToken) {\n if (opts.loadFunc !== defaultCpuLoad) {\n this.#logger.warn(\n 'custom loadFunc is not supported when deploying to Cloud, using defaults',\n );\n opts.loadFunc = defaultCpuLoad;\n }\n const loadThreshold = Default.loadThreshold(opts.production);\n if (opts.loadThreshold !== loadThreshold) {\n this.#logger.warn(\n 'custom loadThreshold is not supported when deploying to Cloud, using defaults',\n );\n opts.loadThreshold = loadThreshold;\n }\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 sdk_version: version,\n project_type: PROJECT_TYPE,\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 const wsUrl = new URL(url + 'agent');\n if (this.#opts.workerToken) {\n wsUrl.searchParams.append('worker_token', this.#opts.workerToken);\n }\n this.#session = new WebSocket(wsUrl, {\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.debug('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(() => {\n const taskIndex = this.#tasks.indexOf(task);\n if (taskIndex !== -1) {\n this.#tasks.splice(taskIndex, 1);\n } else {\n throw new Error(`task ${task} not found in tasks`);\n }\n });\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(() => {\n const taskIndex = this.#tasks.indexOf(task);\n if (taskIndex !== -1) {\n this.#tasks.splice(taskIndex, 1);\n } else {\n throw new Error(`task ${task} not found in tasks`);\n }\n });\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(this).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 workerId: this.id,\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(() => {\n const taskIndex = this.#tasks.indexOf(task);\n if (taskIndex !== -1) {\n this.#tasks.splice(taskIndex, 1);\n } else {\n throw new Error(`task ${task} not found in tasks`);\n }\n });\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.debug('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":"AASA;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAa,yBAAyB;AAC/C,SAAS,oBAAoB;AAC7B,OAAO,QAAQ;AACf,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAC3B,SAAS,uBAAuB;AAChC,SAAS,6BAA6B;AACtC,SAAS,gBAAgB;AAEzB,SAAS,kBAAkB;AAC3B,SAAS,WAAW;AACpB,SAAS,cAAc;AACvB,SAAS,eAAe;AAExB,MAAM,yBAAyB;AAC/B,MAAM,qBAAqB,MAAM;AACjC,MAAM,uBAAuB,MAAM;AACnC,MAAM,eAAe;AAErB,MAAM,QAAQ;AAAA,EACZ,OAAO,cAAc,YAA6B;AAChD,QAAI,YAAY;AACd,aAAO;AAAA,IACT,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,OAAO,iBAAiB,YAA6B;AACnD,QAAI,YAAY;AAEd,aAAO;AAAA,IACT,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,OAAO,KAAK,YAA6B;AACvC,QAAI,YAAY;AACd,aAAO;AAAA,IACT,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAGO,MAAM,gCAAgC,MAAM;AAAA,EACjD,YAAY,KAAc;AACxB,UAAM,GAAG;AACT,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EAClD;AACF;AAGO,MAAM,oBAAoB,MAAM;AAAA,EACrC,YAAY,KAAc;AACxB,UAAM,GAAG;AACT,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EAClD;AACF;AAGO,MAAM,+BAA+B,CAAC,MAAkB;AAC/D,MAAM,qBAAqB,OAAO,QAAoB;AACpD,QAAM,IAAI,OAAO;AACnB;AAGA,MAAM,iBAAiB,OAAO,WAAoC;AAChE,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,QAAQ,GAAG,KAAK;AAEtB,eAAW,MAAM;AACf,YAAM,QAAQ,GAAG,KAAK;AAEtB,UAAI,OAAO;AACX,UAAI,QAAQ;AAEZ,eAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,cAAM,OAAO,MAAM,CAAC,EAAG;AACvB,cAAM,OAAO,MAAM,CAAC,EAAG;AAEvB,gBAAQ,KAAK,OAAO,KAAK;AAEzB,cAAM,SAAS,OAAO,OAAO,IAAI,EAAE,OAAO,CAAC,KAAKA,OAAM,MAAMA,IAAG,CAAC;AAChE,cAAM,SAAS,OAAO,OAAO,IAAI,EAAE,OAAO,CAAC,KAAKA,OAAM,MAAMA,IAAG,CAAC;AAEhE,iBAAS,SAAS;AAAA,MACpB;AAEA,cAAQ,EAAE,IAAI,OAAO,OAAO,QAAQ,CAAC,CAAC;AAAA,IACxC,GAAG,oBAAoB;AAAA,EACzB,CAAC;AACH;AAGO,MAAM,kBAAkB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YACE,aAAa,MACb,eAAe,MACf,iBAAiB,MACjB,oBAAoB,MACpB,oBAAmC,CAAC,GACpC,SAAS,OACT;AACA,SAAK,aAAa;AAClB,SAAK,eAAe;AACpB,SAAK,iBAAiB;AACtB,SAAK,oBAAoB;AACzB,SAAK,oBAAoB;AACzB,SAAK,SAAS;AAAA,EAChB;AACF;AAWO,MAAM,cAAc;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA,YAAY;AAAA,IACV;AAAA,IACA,cAAc;AAAA,IACd,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,IACnB,yBAAyB,KAAK;AAAA,IAC9B,2BAA2B,KAAK;AAAA,IAChC,cAAc,IAAI,kBAAkB;AAAA,IACpC,YAAY;AAAA,IACZ,aAAa,QAAQ;AAAA,IACrB,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,OAAO;AAAA,IACP,OAAO;AAAA,IACP,WAAW;AAAA,IACX,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,mBAAmB;AAAA,EACrB,GA4BG;AACD,SAAK,QAAQ;AACb,QAAI,CAAC,KAAK,OAAO;AACf,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AACA,SAAK,cAAc;AACnB,SAAK,WAAW;AAChB,SAAK,gBAAgB,iBAAiB,QAAQ,cAAc,UAAU;AACtE,SAAK,mBAAmB,oBAAoB,QAAQ,iBAAiB,UAAU;AAC/E,SAAK,yBAAyB;AAC9B,SAAK,2BAA2B;AAChC,SAAK,cAAc;AACnB,SAAK,YAAY;AACjB,SAAK,aAAa;AAClB,SAAK,WAAW;AAChB,SAAK,QAAQ;AACb,SAAK,SAAS;AACd,SAAK,YAAY;AACjB,SAAK,cAAc;AACnB,SAAK,OAAO;AACZ,SAAK,OAAO,QAAQ,QAAQ,KAAK,UAAU;AAC3C,SAAK,WAAW;AAChB,SAAK,aAAa;AAClB,SAAK,kBAAkB;AACvB,SAAK,mBAAmB;AAAA,EAC1B;AACF;AAEA,MAAM,kBAAkB;AAAA,EACtB,UAAU,IAAI,QAAuB,CAAC,YAAY;AAChD,SAAK,UAAU;AAAA,EACjB,CAAC;AAAA,EACD,QAAQ,KAAoB;AAC1B;AAAA,EACF;AACF;AAWO,MAAM,OAAO;AAAA,EAClB;AAAA,EACA;AAAA,EAEA,MAAM;AAAA,EACN,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,SAA0B,CAAC;AAAA,EAC3B,WAAgD,CAAC;AAAA,EACjD,SAAS,IAAI,OAAO;AAAA,EAEpB,QAAQ,IAAI,aAAa;AAAA,EACzB,WAAkC;AAAA,EAClC;AAAA,EACA,UAAU,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC;AAAA,EACjC;AAAA;AAAA,EAGA,YAAY,MAAqB;AAC/B,SAAK,QAAQ,KAAK,SAAS,QAAQ,IAAI,eAAe;AACtD,SAAK,SAAS,KAAK,UAAU,QAAQ,IAAI,mBAAmB;AAC5D,SAAK,YAAY,KAAK,aAAa,QAAQ,IAAI,sBAAsB;AAErE,QAAI,KAAK,UAAU;AACjB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AACF,QAAI,KAAK,WAAW;AAClB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AACF,QAAI,KAAK,cAAc;AACrB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAEF,QAAI,KAAK,aAAa;AACpB,UAAI,KAAK,aAAa,gBAAgB;AACpC,aAAK,QAAQ;AAAA,UACX;AAAA,QACF;AACA,aAAK,WAAW;AAAA,MAClB;AACA,YAAM,gBAAgB,QAAQ,cAAc,KAAK,UAAU;AAC3D,UAAI,KAAK,kBAAkB,eAAe;AACxC,aAAK,QAAQ;AAAA,UACX;AAAA,QACF;AACA,aAAK,gBAAgB;AAAA,MACvB;AAAA,IACF;AAEA,QAAI,OAAO,QAAQ,gBAAgB,iBAAiB,EAAE,QAAQ;AAC5D,WAAK,qBAAqB,IAAI,sBAAsB;AAAA,QAClD,SAAS,gBAAgB;AAAA,QACzB,mBAAmB;AAAA,QACnB,cAAc;AAAA,QACd,cAAc;AAAA,QACd,eAAe;AAAA,QACf,cAAc;AAAA,QACd,aAAa;AAAA,QACb,mBAAmB;AAAA,MACrB,CAAC;AAAA,IACH;AAEA,SAAK,YAAY,IAAI;AAAA,MACnB,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,IACP;AAEA,SAAK,QAAQ;AACb,SAAK,cAAc,IAAI,WAAW,KAAK,MAAM,KAAK,MAAM,OAAO;AAAA,MAC7D,YAAY,KAAK;AAAA,MACjB,aAAa,QAAQ,KAAK,UAAU;AAAA,MACpC,aAAa,KAAK,WAAW;AAAA,MAC7B,aAAa;AAAA,MACb,cAAc;AAAA,IAChB,EAAE;AAAA,EACJ;AAAA;AAAA,EAGA,MAAM,MAAM;AACV,QAAI,CAAC,KAAK,SAAS;AACjB,YAAM,IAAI,YAAY,2BAA2B;AAAA,IACnD;AAEA,QAAI,KAAK,oBAAoB;AAC3B,YAAM,KAAK,mBAAmB,MAAM;AACpC,YAAM,KAAK,mBAAmB,WAAW;AAAA,IAC3C;AAEA,SAAK,QAAQ,KAAK,iBAAiB;AACnC,SAAK,UAAU;AACf,SAAK,UAAU,MAAM;AAErB,UAAM,WAAW,YAAY;AAC3B,UAAI,UAAU;AACd,WAAK,cAAc;AAEnB,aAAO,CAAC,KAAK,SAAS;AACpB,cAAM,MAAM,IAAI,IAAI,KAAK,MAAM,KAAK;AACpC,YAAI,WAAW,IAAI,SAAS,QAAQ,QAAQ,IAAI;AAChD,cAAM,QAAQ,IAAI,YAAY,KAAK,MAAM,QAAQ,KAAK,MAAM,SAAS;AACrE,cAAM,SAAS,EAAE,OAAO,KAAK,CAAC;AAC9B,cAAM,MAAM,MAAM,MAAM,MAAM;AAC9B,cAAM,QAAQ,IAAI,IAAI,MAAM,OAAO;AACnC,YAAI,KAAK,MAAM,aAAa;AAC1B,gBAAM,aAAa,OAAO,gBAAgB,KAAK,MAAM,WAAW;AAAA,QAClE;AACA,aAAK,WAAW,IAAI,UAAU,OAAO;AAAA,UACnC,SAAS,EAAE,eAAe,YAAY,IAAI;AAAA,QAC5C,CAAC;AAED,YAAI;AACF,gBAAM,IAAI,QAAQ,CAAC,SAAS,WAAW;AACrC,iBAAK,SAAU,GAAG,QAAQ,OAAO;AACjC,iBAAK,SAAU,GAAG,SAAS,CAAC,UAAU,OAAO,MAAM,OAAO,CAAC;AAC3D,iBAAK,SAAU,GAAG,SAAS,CAAC,SAAS,OAAO,sBAAsB,IAAI,EAAE,CAAC;AAAA,UAC3E,CAAC;AAED,oBAAU;AACV,eAAK,QAAQ,MAAM,6BAA6B;AAChD,gBAAM,KAAK,OAAO,KAAK,QAAQ;AAAA,QACjC,SAAS,GAAY;AACnB,cAAI,aAAa,SAAS,aAAa,YAAY;AACjD,gBAAI,EAAE;AAAA,UACR;AAEA,cAAI,KAAK,QAAS;AAClB,cAAI,WAAW,KAAK,MAAM,UAAU;AAClC,kBAAM,IAAI;AAAA,cACR,6CAA6C,OAAO,cAAc,CAAC;AAAA,YACrE;AAAA,UACF;AAEA;AACA,gBAAM,QAAQ,KAAK,IAAI,UAAU,GAAG,EAAE;AAEtC,eAAK,QAAQ;AAAA,YACX,oDAAoD,KAAK,aAAa,CAAC,KAAK,OAAO,IAAI,KAAK,MAAM,QAAQ;AAAA,UAC5G;AAEA,gBAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,QAAQ,GAAI,CAAC;AAAA,QAClE;AAAA,MACF;AAAA,IACF;AAEA,UAAM,QAAQ,IAAI,CAAC,SAAS,GAAG,KAAK,YAAY,IAAI,CAAC,CAAC;AACtD,SAAK,OAAO,QAAQ;AAAA,EACtB;AAAA,EAEA,IAAI,KAAa;AACf,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,aAA+B;AACjC,WAAO,KAAK,UAAU,UACnB,OAAO,CAAC,SAAS,KAAK,UAAU,EAChC,IAAI,CAAC,SAAS,KAAK,UAAW;AAAA,EACnC;AAAA;AAAA,EAGA,MAAM,MAAM,SAAkB;AAC5B,QAAI,KAAK,WAAW;AAClB;AAAA,IACF;AAEA,SAAK,QAAQ,MAAM,iBAAiB;AACpC,SAAK,YAAY;AAEjB,SAAK,MAAM;AAAA,MACT;AAAA,MACA,IAAI,cAAc;AAAA,QAChB,SAAS;AAAA,UACP,MAAM;AAAA,UACN,OAAO;AAAA,YACL,QAAQ,aAAa;AAAA,UACvB;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,WAAW,YAAY;AAC3B,aAAO,QAAQ;AAAA,QACb,KAAK,UAAU,UAAU,IAAI,CAAC,SAAS;AACrC,cAAI,CAAC,KAAK,YAAY;AACpB,iBAAK,MAAM;AAAA,UACb;AACA,iBAAO,KAAK,KAAK;AAAA,QACnB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,QAAI;AACJ,QAAI,SAAS;AACX,cAAQ,WAAW,MAAM;AACvB,cAAM,IAAI,YAAY,oBAAoB;AAAA,MAC5C,GAAG,OAAO;AAAA,IACZ;AACA,UAAM,SAAS,EAAE,KAAK,MAAM;AAC1B,UAAI,SAAS;AACX,qBAAa,KAAK;AAAA,MACpB;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,YAAY,UAAkB,qBAA8B;AAChE,UAAM,SAAS,IAAI,kBAAkB,KAAK,MAAM,OAAO,KAAK,MAAM,QAAQ,KAAK,MAAM,SAAS;AAC9F,UAAM,OAAO,MAAM,OAAO,WAAW,EAAE,MAAM,SAAS,CAAC;AACvD,QAAI,cAA2C;AAC/C,QAAI,qBAAqB;AACvB,UAAI;AACF,sBAAc,MAAM,OAAO,eAAe,UAAU,mBAAmB;AAAA,MACzE,SAAS,GAAG;AACV,aAAK,QAAQ;AAAA,UACX,6BAA6B,mBAAmB,sBAAsB,QAAQ;AAAA,QAChF;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAEA,SAAK,MAAM;AAAA,MACT;AAAA,MACA,IAAI,cAAc;AAAA,QAChB,SAAS;AAAA,UACP,MAAM;AAAA,UACN,OAAO;AAAA,YACL,MAAM,QAAQ;AAAA,YACd;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,IAAe;AAC1B,QAAI,YAAY;AAEhB,UAAM,OAAO,CAAC,QAAuB;AACnC,UAAI,WAAW;AACb,aAAK,MAAM,IAAI,cAAc,IAAI;AACjC;AAAA,MACF;AACA,SAAG,KAAK,IAAI,SAAS,CAAC;AAAA,IACxB;AACA,SAAK,MAAM,GAAG,cAAc,IAAI;AAEhC,UAAM,QAAQ,IAAI,QAAc,CAAC,YAAY;AAC3C,SAAG,iBAAiB,SAAS,MAAM;AACjC,oBAAY;AACZ,YAAI,CAAC,KAAK,SAAS;AACjB,eAAK,QAAQ,MAAM,uCAAuC;AAAA,QAC5D;AACA,gBAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAED,OAAG,iBAAiB,SAAS,CAAC,UAAU;AACtC,WAAK,QAAQ,MAAM,iBAAiB,MAAM,OAAO;AAAA,IACnD,CAAC;AAED,OAAG,iBAAiB,WAAW,CAAC,UAAU;AACxC,UAAI,MAAM,SAAS,WAAW;AAC5B,aAAK,QAAQ,KAAK,8BAA8B,MAAM,IAAI;AAC1D;AAAA,MACF;AAEA,YAAM,MAAM,IAAI,cAAc;AAC9B,UAAI,WAAW,MAAM,IAAkB;AAIvC,UAAI,KAAK,eAAe,IAAI,QAAQ,SAAS,YAAY;AACvD,cAAM,IAAI,YAAY,6CAA6C;AAAA,MACrE;AAEA,cAAQ,IAAI,QAAQ,MAAM;AAAA,QACxB,KAAK,YAAY;AACf,eAAK,MAAM,IAAI,QAAQ,MAAM;AAC7B,eAAK,QACF,MAAM,EAAE,IAAI,KAAK,IAAI,aAAa,IAAI,QAAQ,MAAM,WAAW,CAAC,EAChE,KAAK,mBAAmB;AAC3B,eAAK,MAAM;AAAA,YACT;AAAA,YACA,IAAI,QAAQ,MAAM;AAAA,YAClB,IAAI,QAAQ,MAAM;AAAA,UACpB;AACA,eAAK,cAAc;AACnB;AAAA,QACF;AAAA,QACA,KAAK,gBAAgB;AACnB,cAAI,CAAC,IAAI,QAAQ,MAAM,IAAK;AAC5B,gBAAM,OAAO,KAAK,cAAc,IAAI,QAAQ,KAAK;AACjD,eAAK,OAAO,KAAK,IAAI;AACrB,eAAK,QAAQ,MAAM;AACjB,kBAAM,YAAY,KAAK,OAAO,QAAQ,IAAI;AAC1C,gBAAI,cAAc,IAAI;AACpB,mBAAK,OAAO,OAAO,WAAW,CAAC;AAAA,YACjC,OAAO;AACL,oBAAM,IAAI,MAAM,QAAQ,IAAI,qBAAqB;AAAA,YACnD;AAAA,UACF,CAAC;AACD;AAAA,QACF;AAAA,QACA,KAAK,cAAc;AACjB,cAAI,CAAC,IAAI,QAAQ,MAAM,IAAK;AAC5B,gBAAM,MAAM,IAAI,QAAQ,MAAM;AAC9B,cAAI,IAAI,MAAM,KAAK,UAAU;AAC3B,kBAAM,OAAO,KAAK,SAAS,IAAI,EAAE;AACjC,mBAAO,KAAK,SAAS,IAAI,EAAE;AAC3B,yCAAM,QAAQ,IAAI,QAAQ;AAAA,UAC5B,OAAO;AACL,iBAAK,QAAQ,MAAM,EAAE,IAAI,CAAC,EAAE,KAAK,yCAAyC,IAAI,EAAE;AAAA,UAClF;AACA;AAAA,QACF;AAAA,QACA,KAAK,eAAe;AAClB,gBAAM,OAAO,KAAK,aAAa,IAAI,QAAQ,KAAK;AAChD,eAAK,OAAO,KAAK,IAAI;AACrB,eAAK,QAAQ,MAAM;AACjB,kBAAM,YAAY,KAAK,OAAO,QAAQ,IAAI;AAC1C,gBAAI,cAAc,IAAI;AACpB,mBAAK,OAAO,OAAO,WAAW,CAAC;AAAA,YACjC,OAAO;AACL,oBAAM,IAAI,MAAM,QAAQ,IAAI,qBAAqB;AAAA,YACnD;AAAA,UACF,CAAC;AACD;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAED,SAAK,MAAM;AAAA,MACT;AAAA,MACA,IAAI,cAAc;AAAA,QAChB,SAAS;AAAA,UACP,MAAM;AAAA,UACN,OAAO;AAAA,YACL,MAAM,KAAK,MAAM;AAAA,YACjB,WAAW,KAAK,MAAM;AAAA,YACtB,oBAAoB,IAAI,sBAAsB;AAAA,cAC5C,YAAY,KAAK,MAAM,YAAY;AAAA,cACnC,cAAc,KAAK,MAAM,YAAY;AAAA,cACrC,gBAAgB,KAAK,MAAM,YAAY;AAAA,cACvC,mBAAmB,KAAK,MAAM,YAAY;AAAA,cAC1C,QAAQ,KAAK,MAAM,YAAY;AAAA,cAC/B,OAAO;AAAA,YACT,CAAC;AAAA,YACD;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAEA,QAAI,gBAAgB,aAAa;AACjC,UAAM,cAAc,YAAY,MAAM;AACpC,UAAI,UAAW,eAAc,WAAW;AAExC,YAAM,YAAY;AAClB,WAAK,MAAM,SAAS,IAAI,EAAE,KAAK,CAAC,gBAAwB;AACtD,cAAM,SAAS,eAAe,KAAK,MAAM;AACzC,cAAM,qBAAqB,CAAC;AAC5B,wBAAgB,qBAAqB,aAAa,eAAe,aAAa;AAE9E,YAAI,aAAa,eAAe;AAC9B,gBAAM,QAAQ,EAAE,MAAM,aAAa,eAAe,KAAK,MAAM,cAAc;AAC3E,cAAI,QAAQ;AACV,iBAAK,QAAQ,MAAM,KAAK,EAAE,KAAK,oDAAoD;AAAA,UACrF,OAAO;AACL,iBAAK,QAAQ,MAAM,KAAK,EAAE,KAAK,gDAAgD;AAAA,UACjF;AAAA,QACF;AAEA,aAAK,MAAM;AAAA,UACT;AAAA,UACA,IAAI,cAAc;AAAA,YAChB,SAAS;AAAA,cACP,MAAM;AAAA,cACN,OAAO;AAAA,gBACL,MAAM;AAAA,gBACN,QAAQ;AAAA,cACV;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH,GAAG,oBAAoB;AAEvB,UAAM;AACN,OAAG,mBAAmB;AAAA,EACxB;AAAA,EAEA,MAAM,cAAc,KAA0B;AAC5C,QAAI,WAAW;AAEf,UAAM,WAAW,YAAY;AAC3B,iBAAW;AACX,WAAK,MAAM;AAAA,QACT;AAAA,QACA,IAAI,cAAc;AAAA,UAChB,SAAS;AAAA,YACP,MAAM;AAAA,YACN,OAAO;AAAA,cACL,OAAO,IAAI,IAAK;AAAA,cAChB,WAAW;AAAA,YACb;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,WAAW,OAAO,SAA6B;AA9qBzD;AA+qBM,iBAAW;AAEX,WAAK,MAAM;AAAA,QACT;AAAA,QACA,IAAI,cAAc;AAAA,UAChB,SAAS;AAAA,YACP,MAAM;AAAA,YACN,OAAO;AAAA,cACL,OAAO,IAAI,IAAK;AAAA,cAChB,WAAW;AAAA,cACX,qBAAqB,KAAK;AAAA,cAC1B,iBAAiB,KAAK;AAAA,cACtB,qBAAqB,KAAK;AAAA,cAC1B,uBAAuB,KAAK;AAAA,YAC9B;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AAEA,WAAK,SAAS,IAAI,EAAE,IAAI,IAAI,kBAAkB;AAC9C,YAAM,QAAQ,WAAW,MAAM;AAC7B,aAAK,QAAQ,MAAM,EAAE,IAAI,CAAC,EAAE,KAAK,sBAAsB,IAAI,EAAE,YAAY;AACzE;AAAA,MACF,GAAG,kBAAkB;AACrB,YAAM,OAAO,QAAM,UAAK,SAAS,IAAI,EAAE,MAApB,mBAAuB,QAAQ,KAAK,OAAOC,UAAS;AACrE,qBAAa,KAAK;AAClB,eAAOA;AAAA,MACT;AAEA,UAAI,MAAM;AACR,cAAM,KAAK,UAAU,UAAU;AAAA,UAC7B,iBAAiB;AAAA,UACjB,KAAK,IAAI;AAAA,UACT,KAAK,KAAK,OAAO,KAAK,MAAM;AAAA,UAC5B,OAAO,KAAK;AAAA,UACZ,UAAU,KAAK;AAAA,QACjB,CAAC;AAAA,MACH,OAAO;AACL,aAAK,QAAQ,MAAM,EAAE,WAAW,IAAI,GAAG,CAAC,EAAE,KAAK,8BAA8B;AAAA,MAC/E;AAAA,IACF;AAEA,UAAM,MAAM,IAAI,WAAW,IAAI,KAAM,UAAU,QAAQ;AACvD,SAAK,QACF,MAAM,EAAE,KAAK,IAAI,KAAK,UAAU,IAAI,UAAU,WAAW,KAAK,MAAM,UAAU,CAAC,EAC/E,KAAK,sBAAsB;AAE9B,UAAM,iBAAiB,YAAY;AACjC,UAAI;AACF,cAAM,KAAK,MAAM,YAAY,GAAG;AAAA,MAClC,SAAS,GAAG;AACV,aAAK,QACF,MAAM,EAAE,KAAK,IAAI,KAAK,UAAU,IAAI,UAAU,WAAW,KAAK,MAAM,UAAU,CAAC,EAC/E,KAAK,uBAAuB;AAC/B,cAAM,SAAS;AAAA,MACjB;AAEA,UAAI,CAAC,UAAU;AACb,aAAK,QACF,MAAM,EAAE,KAAK,IAAI,KAAK,UAAU,IAAI,UAAU,WAAW,KAAK,MAAM,UAAU,CAAC,EAC/E,KAAK,gFAAgF;AAAA,MAC1F;AAAA,IACF;AAEA,UAAM,OAAO,eAAe;AAC5B,SAAK,OAAO,KAAK,IAAI;AACrB,SAAK,QAAQ,MAAM;AACjB,YAAM,YAAY,KAAK,OAAO,QAAQ,IAAI;AAC1C,UAAI,cAAc,IAAI;AACpB,aAAK,OAAO,OAAO,WAAW,CAAC;AAAA,MACjC,OAAO;AACL,cAAM,IAAI,MAAM,QAAQ,IAAI,qBAAqB;AAAA,MACnD;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,aAAa,KAAqB;AACtC,UAAM,OAAO,KAAK,UAAU,WAAW,IAAI,KAAK;AAChD,QAAI,SAAS,MAAM;AAEjB;AAAA,IACF;AACA,UAAM,KAAK,MAAM;AAAA,EACnB;AAAA,EAEA,MAAM,QAAQ;AApwBhB;AAqwBI,QAAI,KAAK,SAAS;AAChB,YAAM,KAAK,OAAO;AAClB;AAAA,IACF;AAEA,SAAK,QAAQ,MAAM,sBAAsB;AAEzC,SAAK,UAAU;AAEf,YAAM,UAAK,uBAAL,mBAAyB;AAC/B,UAAM,KAAK,UAAU,MAAM;AAC3B,UAAM,KAAK,YAAY,MAAM;AAC7B,UAAM,QAAQ,WAAW,KAAK,MAAM;AAEpC,eAAK,aAAL,mBAAe;AACf,UAAM,KAAK,OAAO;AAAA,EACpB;AACF;","names":["i","asgn"]}