@livekit/agents 0.7.4 → 0.7.6

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.
package/dist/cli.cjs CHANGED
@@ -82,6 +82,8 @@ const runApp = (opts) => {
82
82
  new import_commander.Option("--api-secret <string>", "LiveKit server or Cloud project's API secret").env(
83
83
  "LIVEKIT_API_SECRET"
84
84
  )
85
+ ).addOption(
86
+ new import_commander.Option("--worker-token <string>", "Internal use only").env("LIVEKIT_WORKER_TOKEN").hideHelp()
85
87
  ).action(() => {
86
88
  if (
87
89
  // do not run CLI if origin file is agents/ipc/job_main.js
@@ -96,6 +98,7 @@ const runApp = (opts) => {
96
98
  opts.apiKey = options.apiKey || opts.apiKey;
97
99
  opts.apiSecret = options.apiSecret || opts.apiSecret;
98
100
  opts.logLevel = options.logLevel || opts.logLevel;
101
+ opts.workerToken = options.workerToken || opts.workerToken;
99
102
  runWorker({
100
103
  opts,
101
104
  production: true,
@@ -110,6 +113,7 @@ const runApp = (opts) => {
110
113
  opts.apiKey = options.apiKey || opts.apiKey;
111
114
  opts.apiSecret = options.apiSecret || opts.apiSecret;
112
115
  opts.logLevel = options.logLevel || opts.logLevel;
116
+ opts.workerToken = options.workerToken || opts.workerToken;
113
117
  runWorker({
114
118
  opts,
115
119
  production: false,
@@ -124,6 +128,7 @@ const runApp = (opts) => {
124
128
  opts.apiKey = options.apiKey || opts.apiKey;
125
129
  opts.apiSecret = options.apiSecret || opts.apiSecret;
126
130
  opts.logLevel = options.logLevel || opts.logLevel;
131
+ opts.workerToken = options.workerToken || opts.workerToken;
127
132
  runWorker({
128
133
  opts,
129
134
  production: false,
package/dist/cli.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../../node_modules/.pnpm/tsup@8.4.0_@microsoft+api-extractor@7.43.7_@types+node@22.5.5__postcss@8.4.38_tsx@4.19.2_typescript@5.4.5/node_modules/tsup/assets/cjs_shims.js"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Command, Option } from 'commander';\nimport type { EventEmitter } from 'node:events';\nimport { initializeLogger, log } from './log.js';\nimport { version } from './version.js';\nimport { Worker, WorkerOptions } from './worker.js';\n\ntype CliArgs = {\n opts: WorkerOptions;\n production: boolean;\n watch: boolean;\n event?: EventEmitter;\n room?: string;\n participantIdentity?: string;\n};\n\nconst runWorker = async (args: CliArgs) => {\n initializeLogger({ pretty: !args.production, level: args.opts.logLevel });\n const logger = log();\n\n // though `production` is defined in WorkerOptions, it will always be overriddden by CLI.\n const { production: _, ...opts } = args.opts; // eslint-disable-line @typescript-eslint/no-unused-vars\n const worker = new Worker(new WorkerOptions({ production: args.production, ...opts }));\n\n if (args.room) {\n worker.event.once('worker_registered', () => {\n logger.info(`connecting to room ${args.room}`);\n worker.simulateJob(args.room!, args.participantIdentity);\n });\n }\n\n process.once('SIGINT', async () => {\n logger.info('SIGINT received in CLI');\n // allow C-c C-c for force interrupt\n process.once('SIGINT', () => {\n logger.info('worker closed forcefully due to SIGINT.');\n process.exit(130); // SIGINT exit code\n });\n if (args.production) {\n await worker.drain();\n }\n await worker.close();\n logger.info('worker closed due to SIGINT.');\n process.exit(130); // SIGINT exit code\n });\n\n process.once('SIGTERM', async () => {\n logger.info('SIGTERM received in CLI.');\n if (args.production) {\n await worker.drain();\n }\n await worker.close();\n logger.info('worker closed due to SIGTERM.');\n process.exit(143); // SIGTERM exit code\n });\n\n try {\n await worker.run();\n } catch {\n logger.fatal('closing worker due to error.');\n process.exit(1);\n }\n};\n\n/**\n * Exposes a CLI for creating a new worker, in development or production mode.\n *\n * @param opts - Options to launch the worker with\n * @example\n * ```\n * if (process.argv[1] === fileURLToPath(import.meta.url)) {\n * cli.runApp(new WorkerOptions({ agent: import.meta.filename }));\n * }\n * ```\n */\nexport const runApp = (opts: WorkerOptions) => {\n const program = new Command()\n .name('agents')\n .description('LiveKit Agents CLI')\n .version(version)\n .addOption(\n new Option('--log-level <level>', 'Set the logging level')\n .choices(['trace', 'debug', 'info', 'warn', 'error', 'fatal'])\n .default('info')\n .env('LOG_LEVEL'),\n )\n .addOption(\n new Option('--url <string>', 'LiveKit server or Cloud project websocket URL').env(\n 'LIVEKIT_URL',\n ),\n )\n .addOption(\n new Option('--api-key <string>', \"LiveKit server or Cloud project's API key\").env(\n 'LIVEKIT_API_KEY',\n ),\n )\n .addOption(\n new Option('--api-secret <string>', \"LiveKit server or Cloud project's API secret\").env(\n 'LIVEKIT_API_SECRET',\n ),\n )\n .action(() => {\n if (\n // do not run CLI if origin file is agents/ipc/job_main.js\n process.argv[1] !== new URL('ipc/job_main.js', import.meta.url).pathname &&\n process.argv.length < 3\n ) {\n program.help();\n }\n });\n\n program\n .command('start')\n .description('Start the worker in production mode')\n .action(() => {\n const options = program.optsWithGlobals();\n opts.wsURL = options.url || opts.wsURL;\n opts.apiKey = options.apiKey || opts.apiKey;\n opts.apiSecret = options.apiSecret || opts.apiSecret;\n opts.logLevel = options.logLevel || opts.logLevel;\n runWorker({\n opts,\n production: true,\n watch: false,\n });\n });\n\n program\n .command('dev')\n .description('Start the worker in development mode')\n .addOption(\n new Option('--log-level <level>', 'Set the logging level')\n .choices(['trace', 'debug', 'info', 'warn', 'error', 'fatal'])\n .default('debug')\n .env('LOG_LEVEL'),\n )\n .action(() => {\n const options = program.optsWithGlobals();\n opts.wsURL = options.url || opts.wsURL;\n opts.apiKey = options.apiKey || opts.apiKey;\n opts.apiSecret = options.apiSecret || opts.apiSecret;\n opts.logLevel = options.logLevel || opts.logLevel;\n runWorker({\n opts,\n production: false,\n watch: false,\n });\n });\n\n program\n .command('connect')\n .description('Connect to a specific room')\n .requiredOption('--room <string>', 'Room name to connect to')\n .option('--participant-identity <string>', 'Identity of user to listen to')\n .addOption(\n new Option('--log-level <level>', 'Set the logging level')\n .choices(['trace', 'debug', 'info', 'warn', 'error', 'fatal'])\n .default('debug')\n .env('LOG_LEVEL'),\n )\n .action((...[, command]) => {\n const options = command.optsWithGlobals();\n opts.wsURL = options.url || opts.wsURL;\n opts.apiKey = options.apiKey || opts.apiKey;\n opts.apiSecret = options.apiSecret || opts.apiSecret;\n opts.logLevel = options.logLevel || opts.logLevel;\n runWorker({\n opts,\n production: false,\n watch: false,\n room: options.room,\n participantIdentity: options.participantIdentity,\n });\n });\n\n program.parse();\n};\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () =>\n typeof document === 'undefined'\n ? new URL(`file:${__filename}`).href\n : (document.currentScript && document.currentScript.src) ||\n new URL('main.js', document.baseURI).href\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cli.ts","../../node_modules/.pnpm/tsup@8.4.0_@microsoft+api-extractor@7.43.7_@types+node@22.5.5__postcss@8.4.38_tsx@4.19.2_typescript@5.4.5/node_modules/tsup/assets/cjs_shims.js"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Command, Option } from 'commander';\nimport type { EventEmitter } from 'node:events';\nimport { initializeLogger, log } from './log.js';\nimport { version } from './version.js';\nimport { Worker, WorkerOptions } from './worker.js';\n\ntype CliArgs = {\n opts: WorkerOptions;\n production: boolean;\n watch: boolean;\n event?: EventEmitter;\n room?: string;\n participantIdentity?: string;\n};\n\nconst runWorker = async (args: CliArgs) => {\n initializeLogger({ pretty: !args.production, level: args.opts.logLevel });\n const logger = log();\n\n // though `production` is defined in WorkerOptions, it will always be overriddden by CLI.\n const { production: _, ...opts } = args.opts; // eslint-disable-line @typescript-eslint/no-unused-vars\n const worker = new Worker(new WorkerOptions({ production: args.production, ...opts }));\n\n if (args.room) {\n worker.event.once('worker_registered', () => {\n logger.info(`connecting to room ${args.room}`);\n worker.simulateJob(args.room!, args.participantIdentity);\n });\n }\n\n process.once('SIGINT', async () => {\n logger.info('SIGINT received in CLI');\n // allow C-c C-c for force interrupt\n process.once('SIGINT', () => {\n logger.info('worker closed forcefully due to SIGINT.');\n process.exit(130); // SIGINT exit code\n });\n if (args.production) {\n await worker.drain();\n }\n await worker.close();\n logger.info('worker closed due to SIGINT.');\n process.exit(130); // SIGINT exit code\n });\n\n process.once('SIGTERM', async () => {\n logger.info('SIGTERM received in CLI.');\n if (args.production) {\n await worker.drain();\n }\n await worker.close();\n logger.info('worker closed due to SIGTERM.');\n process.exit(143); // SIGTERM exit code\n });\n\n try {\n await worker.run();\n } catch {\n logger.fatal('closing worker due to error.');\n process.exit(1);\n }\n};\n\n/**\n * Exposes a CLI for creating a new worker, in development or production mode.\n *\n * @param opts - Options to launch the worker with\n * @example\n * ```\n * if (process.argv[1] === fileURLToPath(import.meta.url)) {\n * cli.runApp(new WorkerOptions({ agent: import.meta.filename }));\n * }\n * ```\n */\nexport const runApp = (opts: WorkerOptions) => {\n const program = new Command()\n .name('agents')\n .description('LiveKit Agents CLI')\n .version(version)\n .addOption(\n new Option('--log-level <level>', 'Set the logging level')\n .choices(['trace', 'debug', 'info', 'warn', 'error', 'fatal'])\n .default('info')\n .env('LOG_LEVEL'),\n )\n .addOption(\n new Option('--url <string>', 'LiveKit server or Cloud project websocket URL').env(\n 'LIVEKIT_URL',\n ),\n )\n .addOption(\n new Option('--api-key <string>', \"LiveKit server or Cloud project's API key\").env(\n 'LIVEKIT_API_KEY',\n ),\n )\n .addOption(\n new Option('--api-secret <string>', \"LiveKit server or Cloud project's API secret\").env(\n 'LIVEKIT_API_SECRET',\n ),\n )\n .addOption(\n new Option('--worker-token <string>', 'Internal use only')\n .env('LIVEKIT_WORKER_TOKEN')\n .hideHelp(),\n )\n .action(() => {\n if (\n // do not run CLI if origin file is agents/ipc/job_main.js\n process.argv[1] !== new URL('ipc/job_main.js', import.meta.url).pathname &&\n process.argv.length < 3\n ) {\n program.help();\n }\n });\n\n program\n .command('start')\n .description('Start the worker in production mode')\n .action(() => {\n const options = program.optsWithGlobals();\n opts.wsURL = options.url || opts.wsURL;\n opts.apiKey = options.apiKey || opts.apiKey;\n opts.apiSecret = options.apiSecret || opts.apiSecret;\n opts.logLevel = options.logLevel || opts.logLevel;\n opts.workerToken = options.workerToken || opts.workerToken;\n runWorker({\n opts,\n production: true,\n watch: false,\n });\n });\n\n program\n .command('dev')\n .description('Start the worker in development mode')\n .addOption(\n new Option('--log-level <level>', 'Set the logging level')\n .choices(['trace', 'debug', 'info', 'warn', 'error', 'fatal'])\n .default('debug')\n .env('LOG_LEVEL'),\n )\n .action(() => {\n const options = program.optsWithGlobals();\n opts.wsURL = options.url || opts.wsURL;\n opts.apiKey = options.apiKey || opts.apiKey;\n opts.apiSecret = options.apiSecret || opts.apiSecret;\n opts.logLevel = options.logLevel || opts.logLevel;\n opts.workerToken = options.workerToken || opts.workerToken;\n runWorker({\n opts,\n production: false,\n watch: false,\n });\n });\n\n program\n .command('connect')\n .description('Connect to a specific room')\n .requiredOption('--room <string>', 'Room name to connect to')\n .option('--participant-identity <string>', 'Identity of user to listen to')\n .addOption(\n new Option('--log-level <level>', 'Set the logging level')\n .choices(['trace', 'debug', 'info', 'warn', 'error', 'fatal'])\n .default('debug')\n .env('LOG_LEVEL'),\n )\n .action((...[, command]) => {\n const options = command.optsWithGlobals();\n opts.wsURL = options.url || opts.wsURL;\n opts.apiKey = options.apiKey || opts.apiKey;\n opts.apiSecret = options.apiSecret || opts.apiSecret;\n opts.logLevel = options.logLevel || opts.logLevel;\n opts.workerToken = options.workerToken || opts.workerToken;\n runWorker({\n opts,\n production: false,\n watch: false,\n room: options.room,\n participantIdentity: options.participantIdentity,\n });\n });\n\n program.parse();\n};\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () =>\n typeof document === 'undefined'\n ? new URL(`file:${__filename}`).href\n : (document.currentScript && document.currentScript.src) ||\n new URL('main.js', document.baseURI).href\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n"],"mappings":"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","names":[]}
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAOA,OAAO,EAAU,aAAa,EAAE,MAAM,aAAa,CAAC;AA2DpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,MAAM,SAAU,aAAa,SAqGzC,CAAC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAOA,OAAO,EAAU,aAAa,EAAE,MAAM,aAAa,CAAC;AA2DpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,MAAM,SAAU,aAAa,SA6GzC,CAAC"}
package/dist/cli.js CHANGED
@@ -57,6 +57,8 @@ const runApp = (opts) => {
57
57
  new Option("--api-secret <string>", "LiveKit server or Cloud project's API secret").env(
58
58
  "LIVEKIT_API_SECRET"
59
59
  )
60
+ ).addOption(
61
+ new Option("--worker-token <string>", "Internal use only").env("LIVEKIT_WORKER_TOKEN").hideHelp()
60
62
  ).action(() => {
61
63
  if (
62
64
  // do not run CLI if origin file is agents/ipc/job_main.js
@@ -71,6 +73,7 @@ const runApp = (opts) => {
71
73
  opts.apiKey = options.apiKey || opts.apiKey;
72
74
  opts.apiSecret = options.apiSecret || opts.apiSecret;
73
75
  opts.logLevel = options.logLevel || opts.logLevel;
76
+ opts.workerToken = options.workerToken || opts.workerToken;
74
77
  runWorker({
75
78
  opts,
76
79
  production: true,
@@ -85,6 +88,7 @@ const runApp = (opts) => {
85
88
  opts.apiKey = options.apiKey || opts.apiKey;
86
89
  opts.apiSecret = options.apiSecret || opts.apiSecret;
87
90
  opts.logLevel = options.logLevel || opts.logLevel;
91
+ opts.workerToken = options.workerToken || opts.workerToken;
88
92
  runWorker({
89
93
  opts,
90
94
  production: false,
@@ -99,6 +103,7 @@ const runApp = (opts) => {
99
103
  opts.apiKey = options.apiKey || opts.apiKey;
100
104
  opts.apiSecret = options.apiSecret || opts.apiSecret;
101
105
  opts.logLevel = options.logLevel || opts.logLevel;
106
+ opts.workerToken = options.workerToken || opts.workerToken;
102
107
  runWorker({
103
108
  opts,
104
109
  production: false,
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Command, Option } from 'commander';\nimport type { EventEmitter } from 'node:events';\nimport { initializeLogger, log } from './log.js';\nimport { version } from './version.js';\nimport { Worker, WorkerOptions } from './worker.js';\n\ntype CliArgs = {\n opts: WorkerOptions;\n production: boolean;\n watch: boolean;\n event?: EventEmitter;\n room?: string;\n participantIdentity?: string;\n};\n\nconst runWorker = async (args: CliArgs) => {\n initializeLogger({ pretty: !args.production, level: args.opts.logLevel });\n const logger = log();\n\n // though `production` is defined in WorkerOptions, it will always be overriddden by CLI.\n const { production: _, ...opts } = args.opts; // eslint-disable-line @typescript-eslint/no-unused-vars\n const worker = new Worker(new WorkerOptions({ production: args.production, ...opts }));\n\n if (args.room) {\n worker.event.once('worker_registered', () => {\n logger.info(`connecting to room ${args.room}`);\n worker.simulateJob(args.room!, args.participantIdentity);\n });\n }\n\n process.once('SIGINT', async () => {\n logger.info('SIGINT received in CLI');\n // allow C-c C-c for force interrupt\n process.once('SIGINT', () => {\n logger.info('worker closed forcefully due to SIGINT.');\n process.exit(130); // SIGINT exit code\n });\n if (args.production) {\n await worker.drain();\n }\n await worker.close();\n logger.info('worker closed due to SIGINT.');\n process.exit(130); // SIGINT exit code\n });\n\n process.once('SIGTERM', async () => {\n logger.info('SIGTERM received in CLI.');\n if (args.production) {\n await worker.drain();\n }\n await worker.close();\n logger.info('worker closed due to SIGTERM.');\n process.exit(143); // SIGTERM exit code\n });\n\n try {\n await worker.run();\n } catch {\n logger.fatal('closing worker due to error.');\n process.exit(1);\n }\n};\n\n/**\n * Exposes a CLI for creating a new worker, in development or production mode.\n *\n * @param opts - Options to launch the worker with\n * @example\n * ```\n * if (process.argv[1] === fileURLToPath(import.meta.url)) {\n * cli.runApp(new WorkerOptions({ agent: import.meta.filename }));\n * }\n * ```\n */\nexport const runApp = (opts: WorkerOptions) => {\n const program = new Command()\n .name('agents')\n .description('LiveKit Agents CLI')\n .version(version)\n .addOption(\n new Option('--log-level <level>', 'Set the logging level')\n .choices(['trace', 'debug', 'info', 'warn', 'error', 'fatal'])\n .default('info')\n .env('LOG_LEVEL'),\n )\n .addOption(\n new Option('--url <string>', 'LiveKit server or Cloud project websocket URL').env(\n 'LIVEKIT_URL',\n ),\n )\n .addOption(\n new Option('--api-key <string>', \"LiveKit server or Cloud project's API key\").env(\n 'LIVEKIT_API_KEY',\n ),\n )\n .addOption(\n new Option('--api-secret <string>', \"LiveKit server or Cloud project's API secret\").env(\n 'LIVEKIT_API_SECRET',\n ),\n )\n .action(() => {\n if (\n // do not run CLI if origin file is agents/ipc/job_main.js\n process.argv[1] !== new URL('ipc/job_main.js', import.meta.url).pathname &&\n process.argv.length < 3\n ) {\n program.help();\n }\n });\n\n program\n .command('start')\n .description('Start the worker in production mode')\n .action(() => {\n const options = program.optsWithGlobals();\n opts.wsURL = options.url || opts.wsURL;\n opts.apiKey = options.apiKey || opts.apiKey;\n opts.apiSecret = options.apiSecret || opts.apiSecret;\n opts.logLevel = options.logLevel || opts.logLevel;\n runWorker({\n opts,\n production: true,\n watch: false,\n });\n });\n\n program\n .command('dev')\n .description('Start the worker in development mode')\n .addOption(\n new Option('--log-level <level>', 'Set the logging level')\n .choices(['trace', 'debug', 'info', 'warn', 'error', 'fatal'])\n .default('debug')\n .env('LOG_LEVEL'),\n )\n .action(() => {\n const options = program.optsWithGlobals();\n opts.wsURL = options.url || opts.wsURL;\n opts.apiKey = options.apiKey || opts.apiKey;\n opts.apiSecret = options.apiSecret || opts.apiSecret;\n opts.logLevel = options.logLevel || opts.logLevel;\n runWorker({\n opts,\n production: false,\n watch: false,\n });\n });\n\n program\n .command('connect')\n .description('Connect to a specific room')\n .requiredOption('--room <string>', 'Room name to connect to')\n .option('--participant-identity <string>', 'Identity of user to listen to')\n .addOption(\n new Option('--log-level <level>', 'Set the logging level')\n .choices(['trace', 'debug', 'info', 'warn', 'error', 'fatal'])\n .default('debug')\n .env('LOG_LEVEL'),\n )\n .action((...[, command]) => {\n const options = command.optsWithGlobals();\n opts.wsURL = options.url || opts.wsURL;\n opts.apiKey = options.apiKey || opts.apiKey;\n opts.apiSecret = options.apiSecret || opts.apiSecret;\n opts.logLevel = options.logLevel || opts.logLevel;\n runWorker({\n opts,\n production: false,\n watch: false,\n room: options.room,\n participantIdentity: options.participantIdentity,\n });\n });\n\n program.parse();\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Command, Option } from 'commander';\nimport type { EventEmitter } from 'node:events';\nimport { initializeLogger, log } from './log.js';\nimport { version } from './version.js';\nimport { Worker, WorkerOptions } from './worker.js';\n\ntype CliArgs = {\n opts: WorkerOptions;\n production: boolean;\n watch: boolean;\n event?: EventEmitter;\n room?: string;\n participantIdentity?: string;\n};\n\nconst runWorker = async (args: CliArgs) => {\n initializeLogger({ pretty: !args.production, level: args.opts.logLevel });\n const logger = log();\n\n // though `production` is defined in WorkerOptions, it will always be overriddden by CLI.\n const { production: _, ...opts } = args.opts; // eslint-disable-line @typescript-eslint/no-unused-vars\n const worker = new Worker(new WorkerOptions({ production: args.production, ...opts }));\n\n if (args.room) {\n worker.event.once('worker_registered', () => {\n logger.info(`connecting to room ${args.room}`);\n worker.simulateJob(args.room!, args.participantIdentity);\n });\n }\n\n process.once('SIGINT', async () => {\n logger.info('SIGINT received in CLI');\n // allow C-c C-c for force interrupt\n process.once('SIGINT', () => {\n logger.info('worker closed forcefully due to SIGINT.');\n process.exit(130); // SIGINT exit code\n });\n if (args.production) {\n await worker.drain();\n }\n await worker.close();\n logger.info('worker closed due to SIGINT.');\n process.exit(130); // SIGINT exit code\n });\n\n process.once('SIGTERM', async () => {\n logger.info('SIGTERM received in CLI.');\n if (args.production) {\n await worker.drain();\n }\n await worker.close();\n logger.info('worker closed due to SIGTERM.');\n process.exit(143); // SIGTERM exit code\n });\n\n try {\n await worker.run();\n } catch {\n logger.fatal('closing worker due to error.');\n process.exit(1);\n }\n};\n\n/**\n * Exposes a CLI for creating a new worker, in development or production mode.\n *\n * @param opts - Options to launch the worker with\n * @example\n * ```\n * if (process.argv[1] === fileURLToPath(import.meta.url)) {\n * cli.runApp(new WorkerOptions({ agent: import.meta.filename }));\n * }\n * ```\n */\nexport const runApp = (opts: WorkerOptions) => {\n const program = new Command()\n .name('agents')\n .description('LiveKit Agents CLI')\n .version(version)\n .addOption(\n new Option('--log-level <level>', 'Set the logging level')\n .choices(['trace', 'debug', 'info', 'warn', 'error', 'fatal'])\n .default('info')\n .env('LOG_LEVEL'),\n )\n .addOption(\n new Option('--url <string>', 'LiveKit server or Cloud project websocket URL').env(\n 'LIVEKIT_URL',\n ),\n )\n .addOption(\n new Option('--api-key <string>', \"LiveKit server or Cloud project's API key\").env(\n 'LIVEKIT_API_KEY',\n ),\n )\n .addOption(\n new Option('--api-secret <string>', \"LiveKit server or Cloud project's API secret\").env(\n 'LIVEKIT_API_SECRET',\n ),\n )\n .addOption(\n new Option('--worker-token <string>', 'Internal use only')\n .env('LIVEKIT_WORKER_TOKEN')\n .hideHelp(),\n )\n .action(() => {\n if (\n // do not run CLI if origin file is agents/ipc/job_main.js\n process.argv[1] !== new URL('ipc/job_main.js', import.meta.url).pathname &&\n process.argv.length < 3\n ) {\n program.help();\n }\n });\n\n program\n .command('start')\n .description('Start the worker in production mode')\n .action(() => {\n const options = program.optsWithGlobals();\n opts.wsURL = options.url || opts.wsURL;\n opts.apiKey = options.apiKey || opts.apiKey;\n opts.apiSecret = options.apiSecret || opts.apiSecret;\n opts.logLevel = options.logLevel || opts.logLevel;\n opts.workerToken = options.workerToken || opts.workerToken;\n runWorker({\n opts,\n production: true,\n watch: false,\n });\n });\n\n program\n .command('dev')\n .description('Start the worker in development mode')\n .addOption(\n new Option('--log-level <level>', 'Set the logging level')\n .choices(['trace', 'debug', 'info', 'warn', 'error', 'fatal'])\n .default('debug')\n .env('LOG_LEVEL'),\n )\n .action(() => {\n const options = program.optsWithGlobals();\n opts.wsURL = options.url || opts.wsURL;\n opts.apiKey = options.apiKey || opts.apiKey;\n opts.apiSecret = options.apiSecret || opts.apiSecret;\n opts.logLevel = options.logLevel || opts.logLevel;\n opts.workerToken = options.workerToken || opts.workerToken;\n runWorker({\n opts,\n production: false,\n watch: false,\n });\n });\n\n program\n .command('connect')\n .description('Connect to a specific room')\n .requiredOption('--room <string>', 'Room name to connect to')\n .option('--participant-identity <string>', 'Identity of user to listen to')\n .addOption(\n new Option('--log-level <level>', 'Set the logging level')\n .choices(['trace', 'debug', 'info', 'warn', 'error', 'fatal'])\n .default('debug')\n .env('LOG_LEVEL'),\n )\n .action((...[, command]) => {\n const options = command.optsWithGlobals();\n opts.wsURL = options.url || opts.wsURL;\n opts.apiKey = options.apiKey || opts.apiKey;\n opts.apiSecret = options.apiSecret || opts.apiSecret;\n opts.logLevel = options.logLevel || opts.logLevel;\n opts.workerToken = options.workerToken || opts.workerToken;\n runWorker({\n opts,\n production: false,\n watch: false,\n room: options.room,\n participantIdentity: options.participantIdentity,\n });\n });\n\n program.parse();\n};\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/inference_runner.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\n/** @internal */\nexport abstract class InferenceRunner {\n static INFERENCE_METHOD: string;\n static registeredRunners: { [id: string]: string } = {};\n\n static registerRunner(method: string, importPath: string) {\n if (InferenceRunner.registeredRunners[method]) {\n throw new Error(`Inference runner ${method} already registered`);\n }\n InferenceRunner.registeredRunners[method] = importPath;\n }\n\n abstract initialize(): Promise<void>;\n abstract run(data: unknown): Promise<unknown>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKO,MAAe,gBAAgB;AAAA,EACpC,OAAO;AAAA,EACP,OAAO,oBAA8C,CAAC;AAAA,EAEtD,OAAO,eAAe,QAAgB,YAAoB;AACxD,QAAI,gBAAgB,kBAAkB,MAAM,GAAG;AAC7C,YAAM,IAAI,MAAM,oBAAoB,MAAM,qBAAqB;AAAA,IACjE;AACA,oBAAgB,kBAAkB,MAAM,IAAI;AAAA,EAC9C;AAIF;","names":[]}
1
+ {"version":3,"sources":["../src/inference_runner.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\n/** @internal */\nexport abstract class InferenceRunner {\n static INFERENCE_METHOD: string;\n static registeredRunners: { [id: string]: string } = {};\n\n static registerRunner(method: string, importPath: string) {\n if (InferenceRunner.registeredRunners[method]) {\n throw new Error(`Inference runner ${method} already registered`);\n }\n InferenceRunner.registeredRunners[method] = importPath;\n }\n\n abstract initialize(): Promise<void>;\n abstract run(data: unknown): Promise<unknown>;\n abstract close(): Promise<void>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKO,MAAe,gBAAgB;AAAA,EACpC,OAAO;AAAA,EACP,OAAO,oBAA8C,CAAC;AAAA,EAEtD,OAAO,eAAe,QAAgB,YAAoB;AACxD,QAAI,gBAAgB,kBAAkB,MAAM,GAAG;AAC7C,YAAM,IAAI,MAAM,oBAAoB,MAAM,qBAAqB;AAAA,IACjE;AACA,oBAAgB,kBAAkB,MAAM,IAAI;AAAA,EAC9C;AAKF;","names":[]}
@@ -7,5 +7,6 @@ export declare abstract class InferenceRunner {
7
7
  static registerRunner(method: string, importPath: string): void;
8
8
  abstract initialize(): Promise<void>;
9
9
  abstract run(data: unknown): Promise<unknown>;
10
+ abstract close(): Promise<void>;
10
11
  }
11
12
  //# sourceMappingURL=inference_runner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"inference_runner.d.ts","sourceRoot":"","sources":["../src/inference_runner.ts"],"names":[],"mappings":"AAIA,gBAAgB;AAChB,8BAAsB,eAAe;IACnC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAChC,MAAM,CAAC,iBAAiB,EAAE;QAAE,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAM;IAExD,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IAOxD,QAAQ,CAAC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IACpC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;CAC9C"}
1
+ {"version":3,"file":"inference_runner.d.ts","sourceRoot":"","sources":["../src/inference_runner.ts"],"names":[],"mappings":"AAIA,gBAAgB;AAChB,8BAAsB,eAAe;IACnC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAChC,MAAM,CAAC,iBAAiB,EAAE;QAAE,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAM;IAExD,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IAOxD,QAAQ,CAAC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IACpC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAC7C,QAAQ,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAChC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/inference_runner.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\n/** @internal */\nexport abstract class InferenceRunner {\n static INFERENCE_METHOD: string;\n static registeredRunners: { [id: string]: string } = {};\n\n static registerRunner(method: string, importPath: string) {\n if (InferenceRunner.registeredRunners[method]) {\n throw new Error(`Inference runner ${method} already registered`);\n }\n InferenceRunner.registeredRunners[method] = importPath;\n }\n\n abstract initialize(): Promise<void>;\n abstract run(data: unknown): Promise<unknown>;\n}\n"],"mappings":"AAKO,MAAe,gBAAgB;AAAA,EACpC,OAAO;AAAA,EACP,OAAO,oBAA8C,CAAC;AAAA,EAEtD,OAAO,eAAe,QAAgB,YAAoB;AACxD,QAAI,gBAAgB,kBAAkB,MAAM,GAAG;AAC7C,YAAM,IAAI,MAAM,oBAAoB,MAAM,qBAAqB;AAAA,IACjE;AACA,oBAAgB,kBAAkB,MAAM,IAAI;AAAA,EAC9C;AAIF;","names":[]}
1
+ {"version":3,"sources":["../src/inference_runner.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\n/** @internal */\nexport abstract class InferenceRunner {\n static INFERENCE_METHOD: string;\n static registeredRunners: { [id: string]: string } = {};\n\n static registerRunner(method: string, importPath: string) {\n if (InferenceRunner.registeredRunners[method]) {\n throw new Error(`Inference runner ${method} already registered`);\n }\n InferenceRunner.registeredRunners[method] = importPath;\n }\n\n abstract initialize(): Promise<void>;\n abstract run(data: unknown): Promise<unknown>;\n abstract close(): Promise<void>;\n}\n"],"mappings":"AAKO,MAAe,gBAAgB;AAAA,EACpC,OAAO;AAAA,EACP,OAAO,oBAA8C,CAAC;AAAA,EAEtD,OAAO,eAAe,QAAgB,YAAoB;AACxD,QAAI,gBAAgB,kBAAkB,MAAM,GAAG;AAC7C,YAAM,IAAI,MAAM,oBAAoB,MAAM,qBAAqB;AAAA,IACjE;AACA,oBAAgB,kBAAkB,MAAM,IAAI;AAAA,EAC9C;AAKF;","names":[]}
@@ -63,10 +63,15 @@ const ORPHANED_TIMEOUT = 15 * 1e3;
63
63
  break;
64
64
  case "shutdownRequest":
65
65
  logger.info("inference process received shutdown request");
66
- process.send({ case: "done" });
67
66
  clearTimeout(orphanedTimeout);
68
67
  process.off("message", messageHandler);
69
- join.resolve();
68
+ Promise.all(Object.values(runners).map((r) => r.close())).then(() => {
69
+ logger.info("Inference runners closed");
70
+ process.send({ case: "done" });
71
+ join.resolve();
72
+ }).catch((err) => {
73
+ logger.error("Error closing inference runners:", err);
74
+ });
70
75
  break;
71
76
  case "inferenceRequest":
72
77
  handleInferenceRequest(msg.value);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ipc/inference_proc_lazy_main.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { once } from 'node:events';\nimport type { InferenceRunner } from '../inference_runner.js';\nimport { initializeLogger, log } from '../log.js';\nimport { Future } from '../utils.js';\nimport type { IPCMessage } from './message.js';\n\nconst ORPHANED_TIMEOUT = 15 * 1000;\n\n(async () => {\n if (process.send) {\n const join = new Future();\n\n // don't do anything on C-c\n // this is handled in cli, triggering a termination of all child processes at once.\n process.on('SIGINT', () => {\n logger.info('SIGINT received in inference proc');\n });\n\n // don't do anything on SIGTERM\n // Render uses SIGTERM in autoscale, this ensures the processes are properly drained if needed\n process.on('SIGTERM', () => {\n logger.info('SIGTERM received in inference proc');\n });\n\n await once(process, 'message').then(([msg]: IPCMessage[]) => {\n msg = msg!;\n if (msg.case !== 'initializeRequest') {\n throw new Error('first message must be InitializeRequest');\n }\n initializeLogger(msg.value.loggerOptions);\n });\n const logger = log().child({ pid: process.pid });\n\n const runners: { [id: string]: InferenceRunner } = await Promise.all(\n Object.entries(JSON.parse(process.argv[2]!)).map(async ([k, v]) => {\n return [k, await import(v as string).then((m) => new m.default())];\n }),\n ).then(Object.fromEntries);\n\n await Promise.all(\n Object.entries(runners).map(async ([runner, v]) => {\n logger.child({ runner }).debug('initializing inference runner');\n await v.initialize();\n }),\n );\n logger.debug('all inference runners initialized');\n process.send({ case: 'initializeResponse' });\n\n const orphanedTimeout = setTimeout(() => {\n logger.warn('inference process orphaned, shutting down.');\n process.exit();\n }, ORPHANED_TIMEOUT);\n\n const handleInferenceRequest = async ({\n method,\n requestId,\n data,\n }: {\n method: string;\n requestId: string;\n data: unknown;\n }) => {\n if (!runners[method]) {\n logger.child({ method }).warn('unknown inference method');\n }\n\n try {\n const resp = await runners[method]!.run(data);\n process.send!({ case: 'inferenceResponse', value: { requestId, data: resp } });\n } catch (error) {\n process.send!({ case: 'inferenceResponse', value: { requestId, error } });\n }\n };\n\n const messageHandler = (msg: IPCMessage) => {\n switch (msg.case) {\n case 'pingRequest':\n orphanedTimeout.refresh();\n process.send!({\n case: 'pongResponse',\n value: { lastTimestamp: msg.value.timestamp, timestamp: Date.now() },\n });\n break;\n case 'shutdownRequest':\n logger.info('inference process received shutdown request');\n process.send!({ case: 'done' });\n clearTimeout(orphanedTimeout);\n // Remove our message handler to stop processing new messages\n process.off('message', messageHandler);\n // Resolve the future to allow the process to continue to completion\n join.resolve();\n break;\n case 'inferenceRequest':\n handleInferenceRequest(msg.value);\n }\n };\n\n process.on('message', messageHandler);\n\n await join.await;\n\n logger.info('Inference process shutdown');\n\n return process.exitCode;\n }\n})();\n"],"mappings":";AAGA,yBAAqB;AAErB,iBAAsC;AACtC,mBAAuB;AAGvB,MAAM,mBAAmB,KAAK;AAAA,CAE7B,YAAY;AACX,MAAI,QAAQ,MAAM;AAChB,UAAM,OAAO,IAAI,oBAAO;AAIxB,YAAQ,GAAG,UAAU,MAAM;AACzB,aAAO,KAAK,mCAAmC;AAAA,IACjD,CAAC;AAID,YAAQ,GAAG,WAAW,MAAM;AAC1B,aAAO,KAAK,oCAAoC;AAAA,IAClD,CAAC;AAED,cAAM,yBAAK,SAAS,SAAS,EAAE,KAAK,CAAC,CAAC,GAAG,MAAoB;AAC3D,YAAM;AACN,UAAI,IAAI,SAAS,qBAAqB;AACpC,cAAM,IAAI,MAAM,yCAAyC;AAAA,MAC3D;AACA,uCAAiB,IAAI,MAAM,aAAa;AAAA,IAC1C,CAAC;AACD,UAAM,aAAS,gBAAI,EAAE,MAAM,EAAE,KAAK,QAAQ,IAAI,CAAC;AAE/C,UAAM,UAA6C,MAAM,QAAQ;AAAA,MAC/D,OAAO,QAAQ,KAAK,MAAM,QAAQ,KAAK,CAAC,CAAE,CAAC,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM;AACjE,eAAO,CAAC,GAAG,MAAM,OAAO,GAAa,KAAK,CAAC,MAAM,IAAI,EAAE,QAAQ,CAAC,CAAC;AAAA,MACnE,CAAC;AAAA,IACH,EAAE,KAAK,OAAO,WAAW;AAEzB,UAAM,QAAQ;AAAA,MACZ,OAAO,QAAQ,OAAO,EAAE,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM;AACjD,eAAO,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,+BAA+B;AAC9D,cAAM,EAAE,WAAW;AAAA,MACrB,CAAC;AAAA,IACH;AACA,WAAO,MAAM,mCAAmC;AAChD,YAAQ,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAE3C,UAAM,kBAAkB,WAAW,MAAM;AACvC,aAAO,KAAK,4CAA4C;AACxD,cAAQ,KAAK;AAAA,IACf,GAAG,gBAAgB;AAEnB,UAAM,yBAAyB,OAAO;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,IACF,MAIM;AACJ,UAAI,CAAC,QAAQ,MAAM,GAAG;AACpB,eAAO,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,0BAA0B;AAAA,MAC1D;AAEA,UAAI;AACF,cAAM,OAAO,MAAM,QAAQ,MAAM,EAAG,IAAI,IAAI;AAC5C,gBAAQ,KAAM,EAAE,MAAM,qBAAqB,OAAO,EAAE,WAAW,MAAM,KAAK,EAAE,CAAC;AAAA,MAC/E,SAAS,OAAO;AACd,gBAAQ,KAAM,EAAE,MAAM,qBAAqB,OAAO,EAAE,WAAW,MAAM,EAAE,CAAC;AAAA,MAC1E;AAAA,IACF;AAEA,UAAM,iBAAiB,CAAC,QAAoB;AAC1C,cAAQ,IAAI,MAAM;AAAA,QAChB,KAAK;AACH,0BAAgB,QAAQ;AACxB,kBAAQ,KAAM;AAAA,YACZ,MAAM;AAAA,YACN,OAAO,EAAE,eAAe,IAAI,MAAM,WAAW,WAAW,KAAK,IAAI,EAAE;AAAA,UACrE,CAAC;AACD;AAAA,QACF,KAAK;AACH,iBAAO,KAAK,6CAA6C;AACzD,kBAAQ,KAAM,EAAE,MAAM,OAAO,CAAC;AAC9B,uBAAa,eAAe;AAE5B,kBAAQ,IAAI,WAAW,cAAc;AAErC,eAAK,QAAQ;AACb;AAAA,QACF,KAAK;AACH,iCAAuB,IAAI,KAAK;AAAA,MACpC;AAAA,IACF;AAEA,YAAQ,GAAG,WAAW,cAAc;AAEpC,UAAM,KAAK;AAEX,WAAO,KAAK,4BAA4B;AAExC,WAAO,QAAQ;AAAA,EACjB;AACF,GAAG;","names":[]}
1
+ {"version":3,"sources":["../../src/ipc/inference_proc_lazy_main.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { once } from 'node:events';\nimport type { InferenceRunner } from '../inference_runner.js';\nimport { initializeLogger, log } from '../log.js';\nimport { Future } from '../utils.js';\nimport type { IPCMessage } from './message.js';\n\nconst ORPHANED_TIMEOUT = 15 * 1000;\n\n(async () => {\n if (process.send) {\n const join = new Future();\n\n // don't do anything on C-c\n // this is handled in cli, triggering a termination of all child processes at once.\n process.on('SIGINT', () => {\n logger.info('SIGINT received in inference proc');\n });\n\n // don't do anything on SIGTERM\n // Render uses SIGTERM in autoscale, this ensures the processes are properly drained if needed\n process.on('SIGTERM', () => {\n logger.info('SIGTERM received in inference proc');\n });\n\n await once(process, 'message').then(([msg]: IPCMessage[]) => {\n msg = msg!;\n if (msg.case !== 'initializeRequest') {\n throw new Error('first message must be InitializeRequest');\n }\n initializeLogger(msg.value.loggerOptions);\n });\n const logger = log().child({ pid: process.pid });\n\n const runners: { [id: string]: InferenceRunner } = await Promise.all(\n Object.entries(JSON.parse(process.argv[2]!)).map(async ([k, v]) => {\n return [k, await import(v as string).then((m) => new m.default())];\n }),\n ).then(Object.fromEntries);\n\n await Promise.all(\n Object.entries(runners).map(async ([runner, v]) => {\n logger.child({ runner }).debug('initializing inference runner');\n await v.initialize();\n }),\n );\n logger.debug('all inference runners initialized');\n process.send({ case: 'initializeResponse' });\n\n const orphanedTimeout = setTimeout(() => {\n logger.warn('inference process orphaned, shutting down.');\n process.exit();\n }, ORPHANED_TIMEOUT);\n\n const handleInferenceRequest = async ({\n method,\n requestId,\n data,\n }: {\n method: string;\n requestId: string;\n data: unknown;\n }) => {\n if (!runners[method]) {\n logger.child({ method }).warn('unknown inference method');\n }\n\n try {\n const resp = await runners[method]!.run(data);\n process.send!({ case: 'inferenceResponse', value: { requestId, data: resp } });\n } catch (error) {\n process.send!({ case: 'inferenceResponse', value: { requestId, error } });\n }\n };\n\n const messageHandler = (msg: IPCMessage) => {\n switch (msg.case) {\n case 'pingRequest':\n orphanedTimeout.refresh();\n process.send!({\n case: 'pongResponse',\n value: { lastTimestamp: msg.value.timestamp, timestamp: Date.now() },\n });\n break;\n case 'shutdownRequest':\n logger.info('inference process received shutdown request');\n clearTimeout(orphanedTimeout);\n // Remove our message handler to stop processing new messages\n process.off('message', messageHandler);\n Promise.all(Object.values(runners).map((r) => r.close()))\n .then(() => {\n logger.info('Inference runners closed');\n process.send!({ case: 'done' });\n join.resolve();\n })\n .catch((err) => {\n logger.error('Error closing inference runners:', err);\n });\n break;\n case 'inferenceRequest':\n handleInferenceRequest(msg.value);\n }\n };\n\n process.on('message', messageHandler);\n\n await join.await;\n\n logger.info('Inference process shutdown');\n\n return process.exitCode;\n }\n})();\n"],"mappings":"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","names":[]}
@@ -62,10 +62,15 @@ const ORPHANED_TIMEOUT = 15 * 1e3;
62
62
  break;
63
63
  case "shutdownRequest":
64
64
  logger.info("inference process received shutdown request");
65
- process.send({ case: "done" });
66
65
  clearTimeout(orphanedTimeout);
67
66
  process.off("message", messageHandler);
68
- join.resolve();
67
+ Promise.all(Object.values(runners).map((r) => r.close())).then(() => {
68
+ logger.info("Inference runners closed");
69
+ process.send({ case: "done" });
70
+ join.resolve();
71
+ }).catch((err) => {
72
+ logger.error("Error closing inference runners:", err);
73
+ });
69
74
  break;
70
75
  case "inferenceRequest":
71
76
  handleInferenceRequest(msg.value);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ipc/inference_proc_lazy_main.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { once } from 'node:events';\nimport type { InferenceRunner } from '../inference_runner.js';\nimport { initializeLogger, log } from '../log.js';\nimport { Future } from '../utils.js';\nimport type { IPCMessage } from './message.js';\n\nconst ORPHANED_TIMEOUT = 15 * 1000;\n\n(async () => {\n if (process.send) {\n const join = new Future();\n\n // don't do anything on C-c\n // this is handled in cli, triggering a termination of all child processes at once.\n process.on('SIGINT', () => {\n logger.info('SIGINT received in inference proc');\n });\n\n // don't do anything on SIGTERM\n // Render uses SIGTERM in autoscale, this ensures the processes are properly drained if needed\n process.on('SIGTERM', () => {\n logger.info('SIGTERM received in inference proc');\n });\n\n await once(process, 'message').then(([msg]: IPCMessage[]) => {\n msg = msg!;\n if (msg.case !== 'initializeRequest') {\n throw new Error('first message must be InitializeRequest');\n }\n initializeLogger(msg.value.loggerOptions);\n });\n const logger = log().child({ pid: process.pid });\n\n const runners: { [id: string]: InferenceRunner } = await Promise.all(\n Object.entries(JSON.parse(process.argv[2]!)).map(async ([k, v]) => {\n return [k, await import(v as string).then((m) => new m.default())];\n }),\n ).then(Object.fromEntries);\n\n await Promise.all(\n Object.entries(runners).map(async ([runner, v]) => {\n logger.child({ runner }).debug('initializing inference runner');\n await v.initialize();\n }),\n );\n logger.debug('all inference runners initialized');\n process.send({ case: 'initializeResponse' });\n\n const orphanedTimeout = setTimeout(() => {\n logger.warn('inference process orphaned, shutting down.');\n process.exit();\n }, ORPHANED_TIMEOUT);\n\n const handleInferenceRequest = async ({\n method,\n requestId,\n data,\n }: {\n method: string;\n requestId: string;\n data: unknown;\n }) => {\n if (!runners[method]) {\n logger.child({ method }).warn('unknown inference method');\n }\n\n try {\n const resp = await runners[method]!.run(data);\n process.send!({ case: 'inferenceResponse', value: { requestId, data: resp } });\n } catch (error) {\n process.send!({ case: 'inferenceResponse', value: { requestId, error } });\n }\n };\n\n const messageHandler = (msg: IPCMessage) => {\n switch (msg.case) {\n case 'pingRequest':\n orphanedTimeout.refresh();\n process.send!({\n case: 'pongResponse',\n value: { lastTimestamp: msg.value.timestamp, timestamp: Date.now() },\n });\n break;\n case 'shutdownRequest':\n logger.info('inference process received shutdown request');\n process.send!({ case: 'done' });\n clearTimeout(orphanedTimeout);\n // Remove our message handler to stop processing new messages\n process.off('message', messageHandler);\n // Resolve the future to allow the process to continue to completion\n join.resolve();\n break;\n case 'inferenceRequest':\n handleInferenceRequest(msg.value);\n }\n };\n\n process.on('message', messageHandler);\n\n await join.await;\n\n logger.info('Inference process shutdown');\n\n return process.exitCode;\n }\n})();\n"],"mappings":"AAGA,SAAS,YAAY;AAErB,SAAS,kBAAkB,WAAW;AACtC,SAAS,cAAc;AAGvB,MAAM,mBAAmB,KAAK;AAAA,CAE7B,YAAY;AACX,MAAI,QAAQ,MAAM;AAChB,UAAM,OAAO,IAAI,OAAO;AAIxB,YAAQ,GAAG,UAAU,MAAM;AACzB,aAAO,KAAK,mCAAmC;AAAA,IACjD,CAAC;AAID,YAAQ,GAAG,WAAW,MAAM;AAC1B,aAAO,KAAK,oCAAoC;AAAA,IAClD,CAAC;AAED,UAAM,KAAK,SAAS,SAAS,EAAE,KAAK,CAAC,CAAC,GAAG,MAAoB;AAC3D,YAAM;AACN,UAAI,IAAI,SAAS,qBAAqB;AACpC,cAAM,IAAI,MAAM,yCAAyC;AAAA,MAC3D;AACA,uBAAiB,IAAI,MAAM,aAAa;AAAA,IAC1C,CAAC;AACD,UAAM,SAAS,IAAI,EAAE,MAAM,EAAE,KAAK,QAAQ,IAAI,CAAC;AAE/C,UAAM,UAA6C,MAAM,QAAQ;AAAA,MAC/D,OAAO,QAAQ,KAAK,MAAM,QAAQ,KAAK,CAAC,CAAE,CAAC,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM;AACjE,eAAO,CAAC,GAAG,MAAM,OAAO,GAAa,KAAK,CAAC,MAAM,IAAI,EAAE,QAAQ,CAAC,CAAC;AAAA,MACnE,CAAC;AAAA,IACH,EAAE,KAAK,OAAO,WAAW;AAEzB,UAAM,QAAQ;AAAA,MACZ,OAAO,QAAQ,OAAO,EAAE,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM;AACjD,eAAO,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,+BAA+B;AAC9D,cAAM,EAAE,WAAW;AAAA,MACrB,CAAC;AAAA,IACH;AACA,WAAO,MAAM,mCAAmC;AAChD,YAAQ,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAE3C,UAAM,kBAAkB,WAAW,MAAM;AACvC,aAAO,KAAK,4CAA4C;AACxD,cAAQ,KAAK;AAAA,IACf,GAAG,gBAAgB;AAEnB,UAAM,yBAAyB,OAAO;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,IACF,MAIM;AACJ,UAAI,CAAC,QAAQ,MAAM,GAAG;AACpB,eAAO,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,0BAA0B;AAAA,MAC1D;AAEA,UAAI;AACF,cAAM,OAAO,MAAM,QAAQ,MAAM,EAAG,IAAI,IAAI;AAC5C,gBAAQ,KAAM,EAAE,MAAM,qBAAqB,OAAO,EAAE,WAAW,MAAM,KAAK,EAAE,CAAC;AAAA,MAC/E,SAAS,OAAO;AACd,gBAAQ,KAAM,EAAE,MAAM,qBAAqB,OAAO,EAAE,WAAW,MAAM,EAAE,CAAC;AAAA,MAC1E;AAAA,IACF;AAEA,UAAM,iBAAiB,CAAC,QAAoB;AAC1C,cAAQ,IAAI,MAAM;AAAA,QAChB,KAAK;AACH,0BAAgB,QAAQ;AACxB,kBAAQ,KAAM;AAAA,YACZ,MAAM;AAAA,YACN,OAAO,EAAE,eAAe,IAAI,MAAM,WAAW,WAAW,KAAK,IAAI,EAAE;AAAA,UACrE,CAAC;AACD;AAAA,QACF,KAAK;AACH,iBAAO,KAAK,6CAA6C;AACzD,kBAAQ,KAAM,EAAE,MAAM,OAAO,CAAC;AAC9B,uBAAa,eAAe;AAE5B,kBAAQ,IAAI,WAAW,cAAc;AAErC,eAAK,QAAQ;AACb;AAAA,QACF,KAAK;AACH,iCAAuB,IAAI,KAAK;AAAA,MACpC;AAAA,IACF;AAEA,YAAQ,GAAG,WAAW,cAAc;AAEpC,UAAM,KAAK;AAEX,WAAO,KAAK,4BAA4B;AAExC,WAAO,QAAQ;AAAA,EACjB;AACF,GAAG;","names":[]}
1
+ {"version":3,"sources":["../../src/ipc/inference_proc_lazy_main.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { once } from 'node:events';\nimport type { InferenceRunner } from '../inference_runner.js';\nimport { initializeLogger, log } from '../log.js';\nimport { Future } from '../utils.js';\nimport type { IPCMessage } from './message.js';\n\nconst ORPHANED_TIMEOUT = 15 * 1000;\n\n(async () => {\n if (process.send) {\n const join = new Future();\n\n // don't do anything on C-c\n // this is handled in cli, triggering a termination of all child processes at once.\n process.on('SIGINT', () => {\n logger.info('SIGINT received in inference proc');\n });\n\n // don't do anything on SIGTERM\n // Render uses SIGTERM in autoscale, this ensures the processes are properly drained if needed\n process.on('SIGTERM', () => {\n logger.info('SIGTERM received in inference proc');\n });\n\n await once(process, 'message').then(([msg]: IPCMessage[]) => {\n msg = msg!;\n if (msg.case !== 'initializeRequest') {\n throw new Error('first message must be InitializeRequest');\n }\n initializeLogger(msg.value.loggerOptions);\n });\n const logger = log().child({ pid: process.pid });\n\n const runners: { [id: string]: InferenceRunner } = await Promise.all(\n Object.entries(JSON.parse(process.argv[2]!)).map(async ([k, v]) => {\n return [k, await import(v as string).then((m) => new m.default())];\n }),\n ).then(Object.fromEntries);\n\n await Promise.all(\n Object.entries(runners).map(async ([runner, v]) => {\n logger.child({ runner }).debug('initializing inference runner');\n await v.initialize();\n }),\n );\n logger.debug('all inference runners initialized');\n process.send({ case: 'initializeResponse' });\n\n const orphanedTimeout = setTimeout(() => {\n logger.warn('inference process orphaned, shutting down.');\n process.exit();\n }, ORPHANED_TIMEOUT);\n\n const handleInferenceRequest = async ({\n method,\n requestId,\n data,\n }: {\n method: string;\n requestId: string;\n data: unknown;\n }) => {\n if (!runners[method]) {\n logger.child({ method }).warn('unknown inference method');\n }\n\n try {\n const resp = await runners[method]!.run(data);\n process.send!({ case: 'inferenceResponse', value: { requestId, data: resp } });\n } catch (error) {\n process.send!({ case: 'inferenceResponse', value: { requestId, error } });\n }\n };\n\n const messageHandler = (msg: IPCMessage) => {\n switch (msg.case) {\n case 'pingRequest':\n orphanedTimeout.refresh();\n process.send!({\n case: 'pongResponse',\n value: { lastTimestamp: msg.value.timestamp, timestamp: Date.now() },\n });\n break;\n case 'shutdownRequest':\n logger.info('inference process received shutdown request');\n clearTimeout(orphanedTimeout);\n // Remove our message handler to stop processing new messages\n process.off('message', messageHandler);\n Promise.all(Object.values(runners).map((r) => r.close()))\n .then(() => {\n logger.info('Inference runners closed');\n process.send!({ case: 'done' });\n join.resolve();\n })\n .catch((err) => {\n logger.error('Error closing inference runners:', err);\n });\n break;\n case 'inferenceRequest':\n handleInferenceRequest(msg.value);\n }\n };\n\n process.on('message', messageHandler);\n\n await join.await;\n\n logger.info('Inference process shutdown');\n\n return process.exitCode;\n }\n})();\n"],"mappings":"AAGA,SAAS,YAAY;AAErB,SAAS,kBAAkB,WAAW;AACtC,SAAS,cAAc;AAGvB,MAAM,mBAAmB,KAAK;AAAA,CAE7B,YAAY;AACX,MAAI,QAAQ,MAAM;AAChB,UAAM,OAAO,IAAI,OAAO;AAIxB,YAAQ,GAAG,UAAU,MAAM;AACzB,aAAO,KAAK,mCAAmC;AAAA,IACjD,CAAC;AAID,YAAQ,GAAG,WAAW,MAAM;AAC1B,aAAO,KAAK,oCAAoC;AAAA,IAClD,CAAC;AAED,UAAM,KAAK,SAAS,SAAS,EAAE,KAAK,CAAC,CAAC,GAAG,MAAoB;AAC3D,YAAM;AACN,UAAI,IAAI,SAAS,qBAAqB;AACpC,cAAM,IAAI,MAAM,yCAAyC;AAAA,MAC3D;AACA,uBAAiB,IAAI,MAAM,aAAa;AAAA,IAC1C,CAAC;AACD,UAAM,SAAS,IAAI,EAAE,MAAM,EAAE,KAAK,QAAQ,IAAI,CAAC;AAE/C,UAAM,UAA6C,MAAM,QAAQ;AAAA,MAC/D,OAAO,QAAQ,KAAK,MAAM,QAAQ,KAAK,CAAC,CAAE,CAAC,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM;AACjE,eAAO,CAAC,GAAG,MAAM,OAAO,GAAa,KAAK,CAAC,MAAM,IAAI,EAAE,QAAQ,CAAC,CAAC;AAAA,MACnE,CAAC;AAAA,IACH,EAAE,KAAK,OAAO,WAAW;AAEzB,UAAM,QAAQ;AAAA,MACZ,OAAO,QAAQ,OAAO,EAAE,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM;AACjD,eAAO,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,+BAA+B;AAC9D,cAAM,EAAE,WAAW;AAAA,MACrB,CAAC;AAAA,IACH;AACA,WAAO,MAAM,mCAAmC;AAChD,YAAQ,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAE3C,UAAM,kBAAkB,WAAW,MAAM;AACvC,aAAO,KAAK,4CAA4C;AACxD,cAAQ,KAAK;AAAA,IACf,GAAG,gBAAgB;AAEnB,UAAM,yBAAyB,OAAO;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,IACF,MAIM;AACJ,UAAI,CAAC,QAAQ,MAAM,GAAG;AACpB,eAAO,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,0BAA0B;AAAA,MAC1D;AAEA,UAAI;AACF,cAAM,OAAO,MAAM,QAAQ,MAAM,EAAG,IAAI,IAAI;AAC5C,gBAAQ,KAAM,EAAE,MAAM,qBAAqB,OAAO,EAAE,WAAW,MAAM,KAAK,EAAE,CAAC;AAAA,MAC/E,SAAS,OAAO;AACd,gBAAQ,KAAM,EAAE,MAAM,qBAAqB,OAAO,EAAE,WAAW,MAAM,EAAE,CAAC;AAAA,MAC1E;AAAA,IACF;AAEA,UAAM,iBAAiB,CAAC,QAAoB;AAC1C,cAAQ,IAAI,MAAM;AAAA,QAChB,KAAK;AACH,0BAAgB,QAAQ;AACxB,kBAAQ,KAAM;AAAA,YACZ,MAAM;AAAA,YACN,OAAO,EAAE,eAAe,IAAI,MAAM,WAAW,WAAW,KAAK,IAAI,EAAE;AAAA,UACrE,CAAC;AACD;AAAA,QACF,KAAK;AACH,iBAAO,KAAK,6CAA6C;AACzD,uBAAa,eAAe;AAE5B,kBAAQ,IAAI,WAAW,cAAc;AACrC,kBAAQ,IAAI,OAAO,OAAO,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACrD,KAAK,MAAM;AACV,mBAAO,KAAK,0BAA0B;AACtC,oBAAQ,KAAM,EAAE,MAAM,OAAO,CAAC;AAC9B,iBAAK,QAAQ;AAAA,UACf,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,mBAAO,MAAM,oCAAoC,GAAG;AAAA,UACtD,CAAC;AACH;AAAA,QACF,KAAK;AACH,iCAAuB,IAAI,KAAK;AAAA,MACpC;AAAA,IACF;AAEA,YAAQ,GAAG,WAAW,cAAc;AAEpC,UAAM,KAAK;AAEX,WAAO,KAAK,4BAA4B;AAExC,WAAO,QAAQ;AAAA,EACjB;AACF,GAAG;","names":[]}
@@ -167,7 +167,7 @@ const startJob = (proc, func, info, closeEvent, logger, joinFuture) => {
167
167
  process.on("message", messageHandler);
168
168
  await join.await;
169
169
  logger.info("Job process shutdown");
170
- return process.exitCode;
170
+ process.exit(0);
171
171
  }
172
172
  })();
173
173
  //# sourceMappingURL=job_proc_lazy_main.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ipc/job_proc_lazy_main.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Room, RoomEvent } from '@livekit/rtc-node';\nimport { randomUUID } from 'node:crypto';\nimport { EventEmitter, once } from 'node:events';\nimport { pathToFileURL } from 'node:url';\nimport type { Logger } from 'pino';\nimport { type Agent, isAgent } from '../generator.js';\nimport { CurrentJobContext, JobContext, JobProcess, type RunningJobInfo } from '../job.js';\nimport { initializeLogger, log } from '../log.js';\nimport { Future } from '../utils.js';\nimport { defaultInitializeProcessFunc } from '../worker.js';\nimport type { InferenceExecutor } from './inference_executor.js';\nimport type { IPCMessage } from './message.js';\n\nconst ORPHANED_TIMEOUT = 15 * 1000;\n\ntype JobTask = {\n ctx: JobContext;\n task: Promise<void>;\n};\n\nclass PendingInference {\n promise = new Promise<{ requestId: string; data: unknown; error?: Error }>((resolve) => {\n this.resolve = resolve; // this is how JavaScript lets you resolve promises externally\n });\n resolve(arg: { requestId: string; data: unknown; error?: Error }) {\n arg; // useless call to counteract TypeScript E6133\n }\n}\n\nclass InfClient implements InferenceExecutor {\n #requests: { [id: string]: PendingInference } = {};\n\n constructor() {\n process.on('message', (msg: IPCMessage) => {\n switch (msg.case) {\n case 'inferenceResponse':\n const fut = this.#requests[msg.value.requestId];\n delete this.#requests[msg.value.requestId];\n if (!fut) {\n log().child({ resp: msg.value }).warn('received unexpected inference response');\n return;\n }\n fut.resolve(msg.value);\n break;\n }\n });\n }\n\n async doInference(method: string, data: unknown): Promise<unknown> {\n const requestId = 'inference_job_' + randomUUID;\n process.send!({ case: 'inferenceRequest', value: { requestId, method, data } });\n this.#requests[requestId] = new PendingInference();\n const resp = await this.#requests[requestId]!.promise;\n if (resp.error) {\n throw new Error(`inference of ${method} failed: ${resp.error.message}`);\n }\n return resp.data;\n }\n}\n\nconst startJob = (\n proc: JobProcess,\n func: (ctx: JobContext) => Promise<void>,\n info: RunningJobInfo,\n closeEvent: EventEmitter,\n logger: Logger,\n joinFuture: Future,\n): JobTask => {\n let connect = false;\n let shutdown = false;\n\n const room = new Room();\n room.on(RoomEvent.Disconnected, () => {\n if (!shutdown) {\n closeEvent.emit('close', false);\n }\n });\n\n const onConnect = () => {\n connect = true;\n };\n const onShutdown = (reason: string) => {\n shutdown = true;\n closeEvent.emit('close', true, reason);\n };\n\n const ctx = new JobContext(proc, info, room, onConnect, onShutdown, new InfClient());\n new CurrentJobContext(ctx);\n\n const task = new Promise<void>(async () => {\n const unconnectedTimeout = setTimeout(() => {\n if (!(connect || shutdown)) {\n logger.warn(\n 'room not connect after job_entry was called after 10 seconds, ',\n 'did you forget to call ctx.connect()?',\n );\n }\n }, 10000);\n func(ctx).finally(() => clearTimeout(unconnectedTimeout));\n\n await once(closeEvent, 'close').then((close) => {\n logger.debug('shutting down');\n shutdown = true;\n process.send!({ case: 'exiting', value: { reason: close[1] } });\n });\n\n await room.disconnect();\n logger.debug('disconnected from room');\n\n const shutdownTasks = [];\n for (const callback of ctx.shutdownCallbacks) {\n shutdownTasks.push(callback());\n }\n await Promise.all(shutdownTasks).catch((error) =>\n logger.error('error while shutting down the job', error),\n );\n\n process.send!({ case: 'done' });\n logger.info('job completed.');\n joinFuture.resolve();\n });\n\n return { ctx, task };\n};\n\n(async () => {\n if (process.send) {\n const join = new Future();\n\n // process.argv:\n // [0] `node'\n // [1] import.meta.filename\n // [2] import.meta.filename of function containing entry file\n const moduleFile = process.argv[2];\n const agent: Agent = await import(pathToFileURL(moduleFile!).pathname).then((module) => {\n const agent = module.default;\n if (agent === undefined || !isAgent(agent)) {\n throw new Error(`Unable to load agent: Missing or invalid default export in ${moduleFile}`);\n }\n return agent;\n });\n if (!agent.prewarm) {\n agent.prewarm = defaultInitializeProcessFunc;\n }\n\n // don't do anything on C-c\n // this is handled in cli, triggering a termination of all child processes at once.\n process.on('SIGINT', () => {\n logger.info('SIGINT received in job proc');\n });\n\n // don't do anything on SIGTERM\n // Render uses SIGTERM in autoscale, this ensures the processes are properly drained if needed\n process.on('SIGTERM', () => {\n logger.info('SIGTERM received in job proc');\n });\n\n await once(process, 'message').then(([msg]: IPCMessage[]) => {\n msg = msg!;\n if (msg.case !== 'initializeRequest') {\n throw new Error('first message must be InitializeRequest');\n }\n initializeLogger(msg.value.loggerOptions);\n });\n const proc = new JobProcess();\n let logger = log().child({ pid: proc.pid });\n\n process.on('unhandledRejection', (reason) => {\n logger.error(reason);\n });\n\n logger.debug('initializing job runner');\n agent.prewarm(proc);\n logger.debug('job runner initialized');\n process.send({ case: 'initializeResponse' });\n\n let job: JobTask | undefined = undefined;\n const closeEvent = new EventEmitter();\n\n const orphanedTimeout = setTimeout(() => {\n logger.warn('job process orphaned, shutting down.');\n join.resolve();\n }, ORPHANED_TIMEOUT);\n\n const messageHandler = (msg: IPCMessage) => {\n switch (msg.case) {\n case 'pingRequest': {\n orphanedTimeout.refresh();\n process.send!({\n case: 'pongResponse',\n value: { lastTimestamp: msg.value.timestamp, timestamp: Date.now() },\n });\n break;\n }\n case 'startJobRequest': {\n if (job) {\n throw new Error('job task already running');\n }\n\n logger = logger.child({ jobID: msg.value.runningJob.job.id });\n\n job = startJob(proc, agent.entry, msg.value.runningJob, closeEvent, logger, join);\n logger.debug('job started');\n break;\n }\n case 'shutdownRequest': {\n if (!job) {\n join.resolve();\n }\n closeEvent.emit('close', 'shutdownRequest');\n clearTimeout(orphanedTimeout);\n process.off('message', messageHandler);\n }\n }\n };\n\n process.on('message', messageHandler);\n\n await join.await;\n\n logger.info('Job process shutdown');\n return process.exitCode;\n }\n})();\n"],"mappings":"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","names":["module","agent"]}
1
+ {"version":3,"sources":["../../src/ipc/job_proc_lazy_main.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Room, RoomEvent } from '@livekit/rtc-node';\nimport { randomUUID } from 'node:crypto';\nimport { EventEmitter, once } from 'node:events';\nimport { pathToFileURL } from 'node:url';\nimport type { Logger } from 'pino';\nimport { type Agent, isAgent } from '../generator.js';\nimport { CurrentJobContext, JobContext, JobProcess, type RunningJobInfo } from '../job.js';\nimport { initializeLogger, log } from '../log.js';\nimport { Future } from '../utils.js';\nimport { defaultInitializeProcessFunc } from '../worker.js';\nimport type { InferenceExecutor } from './inference_executor.js';\nimport type { IPCMessage } from './message.js';\n\nconst ORPHANED_TIMEOUT = 15 * 1000;\n\ntype JobTask = {\n ctx: JobContext;\n task: Promise<void>;\n};\n\nclass PendingInference {\n promise = new Promise<{ requestId: string; data: unknown; error?: Error }>((resolve) => {\n this.resolve = resolve; // this is how JavaScript lets you resolve promises externally\n });\n resolve(arg: { requestId: string; data: unknown; error?: Error }) {\n arg; // useless call to counteract TypeScript E6133\n }\n}\n\nclass InfClient implements InferenceExecutor {\n #requests: { [id: string]: PendingInference } = {};\n\n constructor() {\n process.on('message', (msg: IPCMessage) => {\n switch (msg.case) {\n case 'inferenceResponse':\n const fut = this.#requests[msg.value.requestId];\n delete this.#requests[msg.value.requestId];\n if (!fut) {\n log().child({ resp: msg.value }).warn('received unexpected inference response');\n return;\n }\n fut.resolve(msg.value);\n break;\n }\n });\n }\n\n async doInference(method: string, data: unknown): Promise<unknown> {\n const requestId = 'inference_job_' + randomUUID;\n process.send!({ case: 'inferenceRequest', value: { requestId, method, data } });\n this.#requests[requestId] = new PendingInference();\n const resp = await this.#requests[requestId]!.promise;\n if (resp.error) {\n throw new Error(`inference of ${method} failed: ${resp.error.message}`);\n }\n return resp.data;\n }\n}\n\nconst startJob = (\n proc: JobProcess,\n func: (ctx: JobContext) => Promise<void>,\n info: RunningJobInfo,\n closeEvent: EventEmitter,\n logger: Logger,\n joinFuture: Future,\n): JobTask => {\n let connect = false;\n let shutdown = false;\n\n const room = new Room();\n room.on(RoomEvent.Disconnected, () => {\n if (!shutdown) {\n closeEvent.emit('close', false);\n }\n });\n\n const onConnect = () => {\n connect = true;\n };\n const onShutdown = (reason: string) => {\n shutdown = true;\n closeEvent.emit('close', true, reason);\n };\n\n const ctx = new JobContext(proc, info, room, onConnect, onShutdown, new InfClient());\n new CurrentJobContext(ctx);\n\n const task = new Promise<void>(async () => {\n const unconnectedTimeout = setTimeout(() => {\n if (!(connect || shutdown)) {\n logger.warn(\n 'room not connect after job_entry was called after 10 seconds, ',\n 'did you forget to call ctx.connect()?',\n );\n }\n }, 10000);\n func(ctx).finally(() => clearTimeout(unconnectedTimeout));\n\n await once(closeEvent, 'close').then((close) => {\n logger.debug('shutting down');\n shutdown = true;\n process.send!({ case: 'exiting', value: { reason: close[1] } });\n });\n\n await room.disconnect();\n logger.debug('disconnected from room');\n\n const shutdownTasks = [];\n for (const callback of ctx.shutdownCallbacks) {\n shutdownTasks.push(callback());\n }\n await Promise.all(shutdownTasks).catch((error) =>\n logger.error('error while shutting down the job', error),\n );\n\n process.send!({ case: 'done' });\n logger.info('job completed.');\n joinFuture.resolve();\n });\n\n return { ctx, task };\n};\n\n(async () => {\n if (process.send) {\n const join = new Future();\n\n // process.argv:\n // [0] `node'\n // [1] import.meta.filename\n // [2] import.meta.filename of function containing entry file\n const moduleFile = process.argv[2];\n const agent: Agent = await import(pathToFileURL(moduleFile!).pathname).then((module) => {\n const agent = module.default;\n if (agent === undefined || !isAgent(agent)) {\n throw new Error(`Unable to load agent: Missing or invalid default export in ${moduleFile}`);\n }\n return agent;\n });\n if (!agent.prewarm) {\n agent.prewarm = defaultInitializeProcessFunc;\n }\n\n // don't do anything on C-c\n // this is handled in cli, triggering a termination of all child processes at once.\n process.on('SIGINT', () => {\n logger.info('SIGINT received in job proc');\n });\n\n // don't do anything on SIGTERM\n // Render uses SIGTERM in autoscale, this ensures the processes are properly drained if needed\n process.on('SIGTERM', () => {\n logger.info('SIGTERM received in job proc');\n });\n\n await once(process, 'message').then(([msg]: IPCMessage[]) => {\n msg = msg!;\n if (msg.case !== 'initializeRequest') {\n throw new Error('first message must be InitializeRequest');\n }\n initializeLogger(msg.value.loggerOptions);\n });\n const proc = new JobProcess();\n let logger = log().child({ pid: proc.pid });\n\n process.on('unhandledRejection', (reason) => {\n logger.error(reason);\n });\n\n logger.debug('initializing job runner');\n agent.prewarm(proc);\n logger.debug('job runner initialized');\n process.send({ case: 'initializeResponse' });\n\n let job: JobTask | undefined = undefined;\n const closeEvent = new EventEmitter();\n\n const orphanedTimeout = setTimeout(() => {\n logger.warn('job process orphaned, shutting down.');\n join.resolve();\n }, ORPHANED_TIMEOUT);\n\n const messageHandler = (msg: IPCMessage) => {\n switch (msg.case) {\n case 'pingRequest': {\n orphanedTimeout.refresh();\n process.send!({\n case: 'pongResponse',\n value: { lastTimestamp: msg.value.timestamp, timestamp: Date.now() },\n });\n break;\n }\n case 'startJobRequest': {\n if (job) {\n throw new Error('job task already running');\n }\n\n logger = logger.child({ jobID: msg.value.runningJob.job.id });\n\n job = startJob(proc, agent.entry, msg.value.runningJob, closeEvent, logger, join);\n logger.debug('job started');\n break;\n }\n case 'shutdownRequest': {\n if (!job) {\n join.resolve();\n }\n closeEvent.emit('close', 'shutdownRequest');\n clearTimeout(orphanedTimeout);\n process.off('message', messageHandler);\n }\n }\n };\n\n process.on('message', messageHandler);\n\n await join.await;\n\n logger.info('Job process shutdown');\n process.exit(0);\n }\n})();\n"],"mappings":";AAGA,sBAAgC;AAChC,yBAA2B;AAC3B,yBAAmC;AACnC,sBAA8B;AAE9B,uBAAoC;AACpC,iBAA+E;AAC/E,iBAAsC;AACtC,mBAAuB;AACvB,oBAA6C;AAI7C,MAAM,mBAAmB,KAAK;AAO9B,MAAM,iBAAiB;AAAA,EACrB,UAAU,IAAI,QAA6D,CAAC,YAAY;AACtF,SAAK,UAAU;AAAA,EACjB,CAAC;AAAA,EACD,QAAQ,KAA0D;AAChE;AAAA,EACF;AACF;AAEA,MAAM,UAAuC;AAAA,EAC3C,YAAgD,CAAC;AAAA,EAEjD,cAAc;AACZ,YAAQ,GAAG,WAAW,CAAC,QAAoB;AACzC,cAAQ,IAAI,MAAM;AAAA,QAChB,KAAK;AACH,gBAAM,MAAM,KAAK,UAAU,IAAI,MAAM,SAAS;AAC9C,iBAAO,KAAK,UAAU,IAAI,MAAM,SAAS;AACzC,cAAI,CAAC,KAAK;AACR,gCAAI,EAAE,MAAM,EAAE,MAAM,IAAI,MAAM,CAAC,EAAE,KAAK,wCAAwC;AAC9E;AAAA,UACF;AACA,cAAI,QAAQ,IAAI,KAAK;AACrB;AAAA,MACJ;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,YAAY,QAAgB,MAAiC;AACjE,UAAM,YAAY,mBAAmB;AACrC,YAAQ,KAAM,EAAE,MAAM,oBAAoB,OAAO,EAAE,WAAW,QAAQ,KAAK,EAAE,CAAC;AAC9E,SAAK,UAAU,SAAS,IAAI,IAAI,iBAAiB;AACjD,UAAM,OAAO,MAAM,KAAK,UAAU,SAAS,EAAG;AAC9C,QAAI,KAAK,OAAO;AACd,YAAM,IAAI,MAAM,gBAAgB,MAAM,YAAY,KAAK,MAAM,OAAO,EAAE;AAAA,IACxE;AACA,WAAO,KAAK;AAAA,EACd;AACF;AAEA,MAAM,WAAW,CACf,MACA,MACA,MACA,YACA,QACA,eACY;AACZ,MAAI,UAAU;AACd,MAAI,WAAW;AAEf,QAAM,OAAO,IAAI,qBAAK;AACtB,OAAK,GAAG,0BAAU,cAAc,MAAM;AACpC,QAAI,CAAC,UAAU;AACb,iBAAW,KAAK,SAAS,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,QAAM,YAAY,MAAM;AACtB,cAAU;AAAA,EACZ;AACA,QAAM,aAAa,CAAC,WAAmB;AACrC,eAAW;AACX,eAAW,KAAK,SAAS,MAAM,MAAM;AAAA,EACvC;AAEA,QAAM,MAAM,IAAI,sBAAW,MAAM,MAAM,MAAM,WAAW,YAAY,IAAI,UAAU,CAAC;AACnF,MAAI,6BAAkB,GAAG;AAEzB,QAAM,OAAO,IAAI,QAAc,YAAY;AACzC,UAAM,qBAAqB,WAAW,MAAM;AAC1C,UAAI,EAAE,WAAW,WAAW;AAC1B,eAAO;AAAA,UACL;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF,GAAG,GAAK;AACR,SAAK,GAAG,EAAE,QAAQ,MAAM,aAAa,kBAAkB,CAAC;AAExD,cAAM,yBAAK,YAAY,OAAO,EAAE,KAAK,CAAC,UAAU;AAC9C,aAAO,MAAM,eAAe;AAC5B,iBAAW;AACX,cAAQ,KAAM,EAAE,MAAM,WAAW,OAAO,EAAE,QAAQ,MAAM,CAAC,EAAE,EAAE,CAAC;AAAA,IAChE,CAAC;AAED,UAAM,KAAK,WAAW;AACtB,WAAO,MAAM,wBAAwB;AAErC,UAAM,gBAAgB,CAAC;AACvB,eAAW,YAAY,IAAI,mBAAmB;AAC5C,oBAAc,KAAK,SAAS,CAAC;AAAA,IAC/B;AACA,UAAM,QAAQ,IAAI,aAAa,EAAE;AAAA,MAAM,CAAC,UACtC,OAAO,MAAM,qCAAqC,KAAK;AAAA,IACzD;AAEA,YAAQ,KAAM,EAAE,MAAM,OAAO,CAAC;AAC9B,WAAO,KAAK,gBAAgB;AAC5B,eAAW,QAAQ;AAAA,EACrB,CAAC;AAED,SAAO,EAAE,KAAK,KAAK;AACrB;AAAA,CAEC,YAAY;AACX,MAAI,QAAQ,MAAM;AAChB,UAAM,OAAO,IAAI,oBAAO;AAMxB,UAAM,aAAa,QAAQ,KAAK,CAAC;AACjC,UAAM,QAAe,MAAM,WAAO,+BAAc,UAAW,EAAE,UAAU,KAAK,CAACA,YAAW;AACtF,YAAMC,SAAQD,QAAO;AACrB,UAAIC,WAAU,UAAa,KAAC,0BAAQA,MAAK,GAAG;AAC1C,cAAM,IAAI,MAAM,8DAA8D,UAAU,EAAE;AAAA,MAC5F;AACA,aAAOA;AAAA,IACT,CAAC;AACD,QAAI,CAAC,MAAM,SAAS;AAClB,YAAM,UAAU;AAAA,IAClB;AAIA,YAAQ,GAAG,UAAU,MAAM;AACzB,aAAO,KAAK,6BAA6B;AAAA,IAC3C,CAAC;AAID,YAAQ,GAAG,WAAW,MAAM;AAC1B,aAAO,KAAK,8BAA8B;AAAA,IAC5C,CAAC;AAED,cAAM,yBAAK,SAAS,SAAS,EAAE,KAAK,CAAC,CAAC,GAAG,MAAoB;AAC3D,YAAM;AACN,UAAI,IAAI,SAAS,qBAAqB;AACpC,cAAM,IAAI,MAAM,yCAAyC;AAAA,MAC3D;AACA,uCAAiB,IAAI,MAAM,aAAa;AAAA,IAC1C,CAAC;AACD,UAAM,OAAO,IAAI,sBAAW;AAC5B,QAAI,aAAS,gBAAI,EAAE,MAAM,EAAE,KAAK,KAAK,IAAI,CAAC;AAE1C,YAAQ,GAAG,sBAAsB,CAAC,WAAW;AAC3C,aAAO,MAAM,MAAM;AAAA,IACrB,CAAC;AAED,WAAO,MAAM,yBAAyB;AACtC,UAAM,QAAQ,IAAI;AAClB,WAAO,MAAM,wBAAwB;AACrC,YAAQ,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAE3C,QAAI,MAA2B;AAC/B,UAAM,aAAa,IAAI,gCAAa;AAEpC,UAAM,kBAAkB,WAAW,MAAM;AACvC,aAAO,KAAK,sCAAsC;AAClD,WAAK,QAAQ;AAAA,IACf,GAAG,gBAAgB;AAEnB,UAAM,iBAAiB,CAAC,QAAoB;AAC1C,cAAQ,IAAI,MAAM;AAAA,QAChB,KAAK,eAAe;AAClB,0BAAgB,QAAQ;AACxB,kBAAQ,KAAM;AAAA,YACZ,MAAM;AAAA,YACN,OAAO,EAAE,eAAe,IAAI,MAAM,WAAW,WAAW,KAAK,IAAI,EAAE;AAAA,UACrE,CAAC;AACD;AAAA,QACF;AAAA,QACA,KAAK,mBAAmB;AACtB,cAAI,KAAK;AACP,kBAAM,IAAI,MAAM,0BAA0B;AAAA,UAC5C;AAEA,mBAAS,OAAO,MAAM,EAAE,OAAO,IAAI,MAAM,WAAW,IAAI,GAAG,CAAC;AAE5D,gBAAM,SAAS,MAAM,MAAM,OAAO,IAAI,MAAM,YAAY,YAAY,QAAQ,IAAI;AAChF,iBAAO,MAAM,aAAa;AAC1B;AAAA,QACF;AAAA,QACA,KAAK,mBAAmB;AACtB,cAAI,CAAC,KAAK;AACR,iBAAK,QAAQ;AAAA,UACf;AACA,qBAAW,KAAK,SAAS,iBAAiB;AAC1C,uBAAa,eAAe;AAC5B,kBAAQ,IAAI,WAAW,cAAc;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AAEA,YAAQ,GAAG,WAAW,cAAc;AAEpC,UAAM,KAAK;AAEX,WAAO,KAAK,sBAAsB;AAClC,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,GAAG;","names":["module","agent"]}
@@ -166,7 +166,7 @@ const startJob = (proc, func, info, closeEvent, logger, joinFuture) => {
166
166
  process.on("message", messageHandler);
167
167
  await join.await;
168
168
  logger.info("Job process shutdown");
169
- return process.exitCode;
169
+ process.exit(0);
170
170
  }
171
171
  })();
172
172
  //# sourceMappingURL=job_proc_lazy_main.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ipc/job_proc_lazy_main.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Room, RoomEvent } from '@livekit/rtc-node';\nimport { randomUUID } from 'node:crypto';\nimport { EventEmitter, once } from 'node:events';\nimport { pathToFileURL } from 'node:url';\nimport type { Logger } from 'pino';\nimport { type Agent, isAgent } from '../generator.js';\nimport { CurrentJobContext, JobContext, JobProcess, type RunningJobInfo } from '../job.js';\nimport { initializeLogger, log } from '../log.js';\nimport { Future } from '../utils.js';\nimport { defaultInitializeProcessFunc } from '../worker.js';\nimport type { InferenceExecutor } from './inference_executor.js';\nimport type { IPCMessage } from './message.js';\n\nconst ORPHANED_TIMEOUT = 15 * 1000;\n\ntype JobTask = {\n ctx: JobContext;\n task: Promise<void>;\n};\n\nclass PendingInference {\n promise = new Promise<{ requestId: string; data: unknown; error?: Error }>((resolve) => {\n this.resolve = resolve; // this is how JavaScript lets you resolve promises externally\n });\n resolve(arg: { requestId: string; data: unknown; error?: Error }) {\n arg; // useless call to counteract TypeScript E6133\n }\n}\n\nclass InfClient implements InferenceExecutor {\n #requests: { [id: string]: PendingInference } = {};\n\n constructor() {\n process.on('message', (msg: IPCMessage) => {\n switch (msg.case) {\n case 'inferenceResponse':\n const fut = this.#requests[msg.value.requestId];\n delete this.#requests[msg.value.requestId];\n if (!fut) {\n log().child({ resp: msg.value }).warn('received unexpected inference response');\n return;\n }\n fut.resolve(msg.value);\n break;\n }\n });\n }\n\n async doInference(method: string, data: unknown): Promise<unknown> {\n const requestId = 'inference_job_' + randomUUID;\n process.send!({ case: 'inferenceRequest', value: { requestId, method, data } });\n this.#requests[requestId] = new PendingInference();\n const resp = await this.#requests[requestId]!.promise;\n if (resp.error) {\n throw new Error(`inference of ${method} failed: ${resp.error.message}`);\n }\n return resp.data;\n }\n}\n\nconst startJob = (\n proc: JobProcess,\n func: (ctx: JobContext) => Promise<void>,\n info: RunningJobInfo,\n closeEvent: EventEmitter,\n logger: Logger,\n joinFuture: Future,\n): JobTask => {\n let connect = false;\n let shutdown = false;\n\n const room = new Room();\n room.on(RoomEvent.Disconnected, () => {\n if (!shutdown) {\n closeEvent.emit('close', false);\n }\n });\n\n const onConnect = () => {\n connect = true;\n };\n const onShutdown = (reason: string) => {\n shutdown = true;\n closeEvent.emit('close', true, reason);\n };\n\n const ctx = new JobContext(proc, info, room, onConnect, onShutdown, new InfClient());\n new CurrentJobContext(ctx);\n\n const task = new Promise<void>(async () => {\n const unconnectedTimeout = setTimeout(() => {\n if (!(connect || shutdown)) {\n logger.warn(\n 'room not connect after job_entry was called after 10 seconds, ',\n 'did you forget to call ctx.connect()?',\n );\n }\n }, 10000);\n func(ctx).finally(() => clearTimeout(unconnectedTimeout));\n\n await once(closeEvent, 'close').then((close) => {\n logger.debug('shutting down');\n shutdown = true;\n process.send!({ case: 'exiting', value: { reason: close[1] } });\n });\n\n await room.disconnect();\n logger.debug('disconnected from room');\n\n const shutdownTasks = [];\n for (const callback of ctx.shutdownCallbacks) {\n shutdownTasks.push(callback());\n }\n await Promise.all(shutdownTasks).catch((error) =>\n logger.error('error while shutting down the job', error),\n );\n\n process.send!({ case: 'done' });\n logger.info('job completed.');\n joinFuture.resolve();\n });\n\n return { ctx, task };\n};\n\n(async () => {\n if (process.send) {\n const join = new Future();\n\n // process.argv:\n // [0] `node'\n // [1] import.meta.filename\n // [2] import.meta.filename of function containing entry file\n const moduleFile = process.argv[2];\n const agent: Agent = await import(pathToFileURL(moduleFile!).pathname).then((module) => {\n const agent = module.default;\n if (agent === undefined || !isAgent(agent)) {\n throw new Error(`Unable to load agent: Missing or invalid default export in ${moduleFile}`);\n }\n return agent;\n });\n if (!agent.prewarm) {\n agent.prewarm = defaultInitializeProcessFunc;\n }\n\n // don't do anything on C-c\n // this is handled in cli, triggering a termination of all child processes at once.\n process.on('SIGINT', () => {\n logger.info('SIGINT received in job proc');\n });\n\n // don't do anything on SIGTERM\n // Render uses SIGTERM in autoscale, this ensures the processes are properly drained if needed\n process.on('SIGTERM', () => {\n logger.info('SIGTERM received in job proc');\n });\n\n await once(process, 'message').then(([msg]: IPCMessage[]) => {\n msg = msg!;\n if (msg.case !== 'initializeRequest') {\n throw new Error('first message must be InitializeRequest');\n }\n initializeLogger(msg.value.loggerOptions);\n });\n const proc = new JobProcess();\n let logger = log().child({ pid: proc.pid });\n\n process.on('unhandledRejection', (reason) => {\n logger.error(reason);\n });\n\n logger.debug('initializing job runner');\n agent.prewarm(proc);\n logger.debug('job runner initialized');\n process.send({ case: 'initializeResponse' });\n\n let job: JobTask | undefined = undefined;\n const closeEvent = new EventEmitter();\n\n const orphanedTimeout = setTimeout(() => {\n logger.warn('job process orphaned, shutting down.');\n join.resolve();\n }, ORPHANED_TIMEOUT);\n\n const messageHandler = (msg: IPCMessage) => {\n switch (msg.case) {\n case 'pingRequest': {\n orphanedTimeout.refresh();\n process.send!({\n case: 'pongResponse',\n value: { lastTimestamp: msg.value.timestamp, timestamp: Date.now() },\n });\n break;\n }\n case 'startJobRequest': {\n if (job) {\n throw new Error('job task already running');\n }\n\n logger = logger.child({ jobID: msg.value.runningJob.job.id });\n\n job = startJob(proc, agent.entry, msg.value.runningJob, closeEvent, logger, join);\n logger.debug('job started');\n break;\n }\n case 'shutdownRequest': {\n if (!job) {\n join.resolve();\n }\n closeEvent.emit('close', 'shutdownRequest');\n clearTimeout(orphanedTimeout);\n process.off('message', messageHandler);\n }\n }\n };\n\n process.on('message', messageHandler);\n\n await join.await;\n\n logger.info('Job process shutdown');\n return process.exitCode;\n }\n})();\n"],"mappings":"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","names":["agent"]}
1
+ {"version":3,"sources":["../../src/ipc/job_proc_lazy_main.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Room, RoomEvent } from '@livekit/rtc-node';\nimport { randomUUID } from 'node:crypto';\nimport { EventEmitter, once } from 'node:events';\nimport { pathToFileURL } from 'node:url';\nimport type { Logger } from 'pino';\nimport { type Agent, isAgent } from '../generator.js';\nimport { CurrentJobContext, JobContext, JobProcess, type RunningJobInfo } from '../job.js';\nimport { initializeLogger, log } from '../log.js';\nimport { Future } from '../utils.js';\nimport { defaultInitializeProcessFunc } from '../worker.js';\nimport type { InferenceExecutor } from './inference_executor.js';\nimport type { IPCMessage } from './message.js';\n\nconst ORPHANED_TIMEOUT = 15 * 1000;\n\ntype JobTask = {\n ctx: JobContext;\n task: Promise<void>;\n};\n\nclass PendingInference {\n promise = new Promise<{ requestId: string; data: unknown; error?: Error }>((resolve) => {\n this.resolve = resolve; // this is how JavaScript lets you resolve promises externally\n });\n resolve(arg: { requestId: string; data: unknown; error?: Error }) {\n arg; // useless call to counteract TypeScript E6133\n }\n}\n\nclass InfClient implements InferenceExecutor {\n #requests: { [id: string]: PendingInference } = {};\n\n constructor() {\n process.on('message', (msg: IPCMessage) => {\n switch (msg.case) {\n case 'inferenceResponse':\n const fut = this.#requests[msg.value.requestId];\n delete this.#requests[msg.value.requestId];\n if (!fut) {\n log().child({ resp: msg.value }).warn('received unexpected inference response');\n return;\n }\n fut.resolve(msg.value);\n break;\n }\n });\n }\n\n async doInference(method: string, data: unknown): Promise<unknown> {\n const requestId = 'inference_job_' + randomUUID;\n process.send!({ case: 'inferenceRequest', value: { requestId, method, data } });\n this.#requests[requestId] = new PendingInference();\n const resp = await this.#requests[requestId]!.promise;\n if (resp.error) {\n throw new Error(`inference of ${method} failed: ${resp.error.message}`);\n }\n return resp.data;\n }\n}\n\nconst startJob = (\n proc: JobProcess,\n func: (ctx: JobContext) => Promise<void>,\n info: RunningJobInfo,\n closeEvent: EventEmitter,\n logger: Logger,\n joinFuture: Future,\n): JobTask => {\n let connect = false;\n let shutdown = false;\n\n const room = new Room();\n room.on(RoomEvent.Disconnected, () => {\n if (!shutdown) {\n closeEvent.emit('close', false);\n }\n });\n\n const onConnect = () => {\n connect = true;\n };\n const onShutdown = (reason: string) => {\n shutdown = true;\n closeEvent.emit('close', true, reason);\n };\n\n const ctx = new JobContext(proc, info, room, onConnect, onShutdown, new InfClient());\n new CurrentJobContext(ctx);\n\n const task = new Promise<void>(async () => {\n const unconnectedTimeout = setTimeout(() => {\n if (!(connect || shutdown)) {\n logger.warn(\n 'room not connect after job_entry was called after 10 seconds, ',\n 'did you forget to call ctx.connect()?',\n );\n }\n }, 10000);\n func(ctx).finally(() => clearTimeout(unconnectedTimeout));\n\n await once(closeEvent, 'close').then((close) => {\n logger.debug('shutting down');\n shutdown = true;\n process.send!({ case: 'exiting', value: { reason: close[1] } });\n });\n\n await room.disconnect();\n logger.debug('disconnected from room');\n\n const shutdownTasks = [];\n for (const callback of ctx.shutdownCallbacks) {\n shutdownTasks.push(callback());\n }\n await Promise.all(shutdownTasks).catch((error) =>\n logger.error('error while shutting down the job', error),\n );\n\n process.send!({ case: 'done' });\n logger.info('job completed.');\n joinFuture.resolve();\n });\n\n return { ctx, task };\n};\n\n(async () => {\n if (process.send) {\n const join = new Future();\n\n // process.argv:\n // [0] `node'\n // [1] import.meta.filename\n // [2] import.meta.filename of function containing entry file\n const moduleFile = process.argv[2];\n const agent: Agent = await import(pathToFileURL(moduleFile!).pathname).then((module) => {\n const agent = module.default;\n if (agent === undefined || !isAgent(agent)) {\n throw new Error(`Unable to load agent: Missing or invalid default export in ${moduleFile}`);\n }\n return agent;\n });\n if (!agent.prewarm) {\n agent.prewarm = defaultInitializeProcessFunc;\n }\n\n // don't do anything on C-c\n // this is handled in cli, triggering a termination of all child processes at once.\n process.on('SIGINT', () => {\n logger.info('SIGINT received in job proc');\n });\n\n // don't do anything on SIGTERM\n // Render uses SIGTERM in autoscale, this ensures the processes are properly drained if needed\n process.on('SIGTERM', () => {\n logger.info('SIGTERM received in job proc');\n });\n\n await once(process, 'message').then(([msg]: IPCMessage[]) => {\n msg = msg!;\n if (msg.case !== 'initializeRequest') {\n throw new Error('first message must be InitializeRequest');\n }\n initializeLogger(msg.value.loggerOptions);\n });\n const proc = new JobProcess();\n let logger = log().child({ pid: proc.pid });\n\n process.on('unhandledRejection', (reason) => {\n logger.error(reason);\n });\n\n logger.debug('initializing job runner');\n agent.prewarm(proc);\n logger.debug('job runner initialized');\n process.send({ case: 'initializeResponse' });\n\n let job: JobTask | undefined = undefined;\n const closeEvent = new EventEmitter();\n\n const orphanedTimeout = setTimeout(() => {\n logger.warn('job process orphaned, shutting down.');\n join.resolve();\n }, ORPHANED_TIMEOUT);\n\n const messageHandler = (msg: IPCMessage) => {\n switch (msg.case) {\n case 'pingRequest': {\n orphanedTimeout.refresh();\n process.send!({\n case: 'pongResponse',\n value: { lastTimestamp: msg.value.timestamp, timestamp: Date.now() },\n });\n break;\n }\n case 'startJobRequest': {\n if (job) {\n throw new Error('job task already running');\n }\n\n logger = logger.child({ jobID: msg.value.runningJob.job.id });\n\n job = startJob(proc, agent.entry, msg.value.runningJob, closeEvent, logger, join);\n logger.debug('job started');\n break;\n }\n case 'shutdownRequest': {\n if (!job) {\n join.resolve();\n }\n closeEvent.emit('close', 'shutdownRequest');\n clearTimeout(orphanedTimeout);\n process.off('message', messageHandler);\n }\n }\n };\n\n process.on('message', messageHandler);\n\n await join.await;\n\n logger.info('Job process shutdown');\n process.exit(0);\n }\n})();\n"],"mappings":"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","names":["agent"]}
package/dist/worker.cjs CHANGED
@@ -141,6 +141,7 @@ class WorkerOptions {
141
141
  wsURL;
142
142
  apiKey;
143
143
  apiSecret;
144
+ workerToken;
144
145
  host;
145
146
  port;
146
147
  logLevel;
@@ -163,6 +164,7 @@ class WorkerOptions {
163
164
  wsURL = "ws://localhost:7880",
164
165
  apiKey = void 0,
165
166
  apiSecret = void 0,
167
+ workerToken = void 0,
166
168
  host = "0.0.0.0",
167
169
  port = void 0,
168
170
  logLevel = "info",
@@ -187,6 +189,7 @@ class WorkerOptions {
187
189
  this.wsURL = wsURL;
188
190
  this.apiKey = apiKey;
189
191
  this.apiSecret = apiSecret;
192
+ this.workerToken = workerToken;
190
193
  this.host = host;
191
194
  this.port = port || Default.port(production);
192
195
  this.logLevel = logLevel;
@@ -284,7 +287,11 @@ class Worker {
284
287
  const token = new import_livekit_server_sdk.AccessToken(this.#opts.apiKey, this.#opts.apiSecret);
285
288
  token.addGrant({ agent: true });
286
289
  const jwt = await token.toJwt();
287
- this.#session = new import_ws.WebSocket(url + "agent", {
290
+ const wsUrl = new URL(url + "agent");
291
+ if (this.#opts.workerToken) {
292
+ wsUrl.searchParams.append("worker_token", this.#opts.workerToken);
293
+ }
294
+ this.#session = new import_ws.WebSocket(wsUrl, {
288
295
  headers: { authorization: "Bearer " + jwt }
289
296
  });
290
297
  try {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/worker.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type {\n JobAssignment,\n JobTermination,\n ParticipantInfo,\n TrackSource,\n} from '@livekit/protocol';\nimport {\n type AvailabilityRequest,\n JobType,\n ParticipantPermission,\n ServerMessage,\n WorkerMessage,\n WorkerStatus,\n} from '@livekit/protocol';\nimport { AccessToken, RoomServiceClient } from 'livekit-server-sdk';\nimport { EventEmitter } from 'node:events';\nimport os from 'node:os';\nimport { WebSocket } from 'ws';\nimport { HTTPServer } from './http_server.js';\nimport { InferenceRunner } from './inference_runner.js';\nimport { InferenceProcExecutor } from './ipc/inference_proc_executor.js';\nimport { ProcPool } from './ipc/proc_pool.js';\nimport type { JobAcceptArguments, JobProcess, RunningJobInfo } from './job.js';\nimport { JobRequest } from './job.js';\nimport { log } from './log.js';\nimport { Future } from './utils.js';\nimport { version } from './version.js';\n\nconst MAX_RECONNECT_ATTEMPTS = 10;\nconst ASSIGNMENT_TIMEOUT = 7.5 * 1000;\nconst UPDATE_LOAD_INTERVAL = 2.5 * 1000;\n\nclass Default {\n static loadThreshold(production: boolean): number {\n if (production) {\n return 0.65;\n } else {\n return Infinity;\n }\n }\n\n static numIdleProcesses(production: boolean): number {\n if (production) {\n return 3;\n } else {\n return 0;\n }\n }\n\n static port(production: boolean): number {\n if (production) {\n return 8081;\n } else {\n return 0;\n }\n }\n}\n\n/** Necessary credentials not provided and not found in an appropriate environmental variable. */\nexport class MissingCredentialsError extends Error {\n constructor(msg?: string) {\n super(msg);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Worker did not run as expected. */\nexport class WorkerError extends Error {\n constructor(msg?: string) {\n super(msg);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** @internal */\nexport const defaultInitializeProcessFunc = (_: JobProcess) => _;\nconst defaultRequestFunc = async (ctx: JobRequest) => {\n await ctx.accept();\n};\nconst defaultCpuLoad = async (): Promise<number> => {\n return new Promise((resolve) => {\n const cpus1 = os.cpus();\n\n setTimeout(() => {\n const cpus2 = os.cpus();\n\n let idle = 0;\n let total = 0;\n\n for (let i = 0; i < cpus1.length; i++) {\n const cpu1 = cpus1[i]!.times;\n const cpu2 = cpus2[i]!.times;\n\n idle += cpu2.idle - cpu1.idle;\n\n const total1 = Object.values(cpu1).reduce((acc, i) => acc + i, 0);\n const total2 = Object.values(cpu2).reduce((acc, i) => acc + i, 0);\n\n total += total2 - total1;\n }\n\n resolve(+(1 - idle / total).toFixed(2));\n }, UPDATE_LOAD_INTERVAL);\n });\n};\n\n/** Participant permissions to pass to every agent spun up by this worker. */\nexport class WorkerPermissions {\n canPublish: boolean;\n canSubscribe: boolean;\n canPublishData: boolean;\n canUpdateMetadata: boolean;\n canPublishSources: TrackSource[];\n hidden: boolean;\n\n constructor(\n canPublish = true,\n canSubscribe = true,\n canPublishData = true,\n canUpdateMetadata = true,\n canPublishSources: TrackSource[] = [],\n hidden = false,\n ) {\n this.canPublish = canPublish;\n this.canSubscribe = canSubscribe;\n this.canPublishData = canPublishData;\n this.canUpdateMetadata = canUpdateMetadata;\n this.canPublishSources = canPublishSources;\n this.hidden = hidden;\n }\n}\n\n/**\n * Data class describing worker behaviour.\n *\n * @remarks\n * The Agents framework provides sane worker defaults, and works out-of-the-box with no tweaking\n * necessary. The only mandatory parameter is `agent`, which points to the entry function.\n *\n * This class is mostly useful in conjunction with {@link cli.runApp}.\n */\nexport class WorkerOptions {\n agent: string;\n requestFunc: (job: JobRequest) => Promise<void>;\n loadFunc: () => Promise<number>;\n loadThreshold: number;\n numIdleProcesses: number;\n shutdownProcessTimeout: number;\n initializeProcessTimeout: number;\n permissions: WorkerPermissions;\n agentName: string;\n workerType: JobType;\n maxRetry: number;\n wsURL: string;\n apiKey?: string;\n apiSecret?: string;\n host: string;\n port: number;\n logLevel: string;\n production: boolean;\n jobMemoryWarnMB: number;\n jobMemoryLimitMB: number;\n\n /** @param options */\n constructor({\n agent,\n requestFunc = defaultRequestFunc,\n loadFunc = defaultCpuLoad,\n loadThreshold = undefined,\n numIdleProcesses = undefined,\n shutdownProcessTimeout = 60 * 1000,\n initializeProcessTimeout = 10 * 1000,\n permissions = new WorkerPermissions(),\n agentName = '',\n workerType = JobType.JT_ROOM,\n maxRetry = MAX_RECONNECT_ATTEMPTS,\n wsURL = 'ws://localhost:7880',\n apiKey = undefined,\n apiSecret = undefined,\n host = '0.0.0.0',\n port = undefined,\n logLevel = 'info',\n production = false,\n jobMemoryWarnMB = 300,\n jobMemoryLimitMB = 0,\n }: {\n /**\n * Path to a file that has {@link Agent} as a default export, dynamically imported later for\n * entrypoint and prewarm functions\n */\n agent: string;\n requestFunc?: (job: JobRequest) => Promise<void>;\n /** Called to determine the current load of the worker. Should return a value between 0 and 1. */\n loadFunc?: () => Promise<number>;\n /** When the load exceeds this threshold, the worker will be marked as unavailable. */\n loadThreshold?: number;\n numIdleProcesses?: number;\n shutdownProcessTimeout?: number;\n initializeProcessTimeout?: number;\n permissions?: WorkerPermissions;\n agentName?: string;\n workerType?: JobType;\n maxRetry?: number;\n wsURL?: string;\n apiKey?: string;\n apiSecret?: string;\n host?: string;\n port?: number;\n logLevel?: string;\n production?: boolean;\n jobMemoryWarnMB?: number;\n jobMemoryLimitMB?: number;\n }) {\n this.agent = agent;\n if (!this.agent) {\n throw new Error('No Agent file was passed to the worker');\n }\n this.requestFunc = requestFunc;\n this.loadFunc = loadFunc;\n this.loadThreshold = loadThreshold || Default.loadThreshold(production);\n this.numIdleProcesses = numIdleProcesses || Default.numIdleProcesses(production);\n this.shutdownProcessTimeout = shutdownProcessTimeout;\n this.initializeProcessTimeout = initializeProcessTimeout;\n this.permissions = permissions;\n this.agentName = agentName;\n this.workerType = workerType;\n this.maxRetry = maxRetry;\n this.wsURL = wsURL;\n this.apiKey = apiKey;\n this.apiSecret = apiSecret;\n this.host = host;\n this.port = port || Default.port(production);\n this.logLevel = logLevel;\n this.production = production;\n this.jobMemoryWarnMB = jobMemoryWarnMB;\n this.jobMemoryLimitMB = jobMemoryLimitMB;\n }\n}\n\nclass PendingAssignment {\n promise = new Promise<JobAssignment>((resolve) => {\n this.resolve = resolve; // this is how JavaScript lets you resolve promises externally\n });\n resolve(arg: JobAssignment) {\n arg; // useless call to counteract TypeScript E6133\n }\n}\n\n/**\n * Central orchestrator for all processes and job requests.\n *\n * @remarks\n * For most usecases, Worker should not be initialized or handled directly; you should instead call\n * for its creation through {@link cli.runApp}. This could, however, be useful in situations where\n * you don't have access to a command line, such as a headless program, or one that uses Agents\n * behind a wrapper.\n */\nexport class Worker {\n #opts: WorkerOptions;\n #procPool: ProcPool;\n\n #id = 'unregistered';\n #closed = true;\n #draining = false;\n #connecting = false;\n #tasks: Promise<void>[] = [];\n #pending: { [id: string]: PendingAssignment } = {};\n #close = new Future();\n\n event = new EventEmitter();\n #session: WebSocket | undefined = undefined;\n #httpServer: HTTPServer;\n #logger = log().child({ version });\n #inferenceExecutor?: InferenceProcExecutor;\n\n /* @throws {@link MissingCredentialsError} if URL, API key or API secret are missing */\n constructor(opts: WorkerOptions) {\n opts.wsURL = opts.wsURL || process.env.LIVEKIT_URL || '';\n opts.apiKey = opts.apiKey || process.env.LIVEKIT_API_KEY || '';\n opts.apiSecret = opts.apiSecret || process.env.LIVEKIT_API_SECRET || '';\n\n if (opts.wsURL === '')\n throw new MissingCredentialsError(\n 'URL is required: Set LIVEKIT_URL, run with --url, or pass wsURL in WorkerOptions',\n );\n if (opts.apiKey === '')\n throw new MissingCredentialsError(\n 'API Key is required: Set LIVEKIT_API_KEY, run with --api-key, or pass apiKey in WorkerOptions',\n );\n if (opts.apiSecret === '')\n throw new MissingCredentialsError(\n 'API Secret is required: Set LIVEKIT_API_SECRET, run with --api-secret, or pass apiSecret in WorkerOptions',\n );\n\n if (Object.entries(InferenceRunner.registeredRunners).length) {\n this.#inferenceExecutor = new InferenceProcExecutor({\n runners: InferenceRunner.registeredRunners,\n initializeTimeout: 30000,\n closeTimeout: 5000,\n memoryWarnMB: 2000,\n memoryLimitMB: 0,\n pingInterval: 5000,\n pingTimeout: 60000,\n highPingThreshold: 2500,\n });\n }\n\n this.#procPool = new ProcPool(\n opts.agent,\n opts.numIdleProcesses,\n opts.initializeProcessTimeout,\n opts.shutdownProcessTimeout,\n this.#inferenceExecutor,\n opts.jobMemoryWarnMB,\n opts.jobMemoryLimitMB,\n );\n\n this.#opts = opts;\n this.#httpServer = new HTTPServer(opts.host, opts.port, () => ({\n agent_name: opts.agentName,\n worker_type: JobType[opts.workerType],\n active_jobs: this.activeJobs.length,\n }));\n }\n\n /* @throws {@link WorkerError} if worker failed to connect or already running */\n async run() {\n if (!this.#closed) {\n throw new WorkerError('worker is already running');\n }\n\n if (this.#inferenceExecutor) {\n await this.#inferenceExecutor.start();\n await this.#inferenceExecutor.initialize();\n }\n\n this.#logger.info('starting worker');\n this.#closed = false;\n this.#procPool.start();\n\n const workerWS = async () => {\n let retries = 0;\n this.#connecting = true;\n\n while (!this.#closed) {\n const url = new URL(this.#opts.wsURL);\n url.protocol = url.protocol.replace('http', 'ws');\n const token = new AccessToken(this.#opts.apiKey, this.#opts.apiSecret);\n token.addGrant({ agent: true });\n const jwt = await token.toJwt();\n this.#session = new WebSocket(url + 'agent', {\n headers: { authorization: 'Bearer ' + jwt },\n });\n\n try {\n await new Promise((resolve, reject) => {\n this.#session!.on('open', resolve);\n this.#session!.on('error', (error) => reject(error.message));\n this.#session!.on('close', (code) => reject(`WebSocket returned ${code}`));\n });\n\n retries = 0;\n this.#logger.debug('connected to LiveKit server');\n await this.#runWS(this.#session);\n } catch (e: unknown) {\n if (e instanceof Error || e instanceof ErrorEvent) {\n e = e.message;\n }\n\n if (this.#closed) return;\n if (retries >= this.#opts.maxRetry) {\n throw new WorkerError(\n `failed to connect to LiveKit server after ${retries} attempts: ${e}`,\n );\n }\n\n retries++;\n const delay = Math.min(retries * 2, 10);\n\n this.#logger.warn(\n `failed to connect to LiveKit server, retrying in ${delay} seconds: ${e} (${retries}/${this.#opts.maxRetry})`,\n );\n\n await new Promise((resolve) => setTimeout(resolve, delay * 1000));\n }\n }\n };\n\n await Promise.all([workerWS(), this.#httpServer.run()]);\n this.#close.resolve();\n }\n\n get id(): string {\n return this.#id;\n }\n\n get activeJobs(): RunningJobInfo[] {\n return this.#procPool.processes\n .filter((proc) => proc.runningJob)\n .map((proc) => proc.runningJob!);\n }\n\n /* @throws {@link WorkerError} if worker did not drain in time */\n async drain(timeout?: number) {\n if (this.#draining) {\n return;\n }\n\n this.#logger.info('draining worker');\n this.#draining = true;\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'updateWorker',\n value: {\n status: WorkerStatus.WS_FULL,\n },\n },\n }),\n );\n\n const joinJobs = async () => {\n return Promise.all(\n this.#procPool.processes.map((proc) => {\n if (!proc.runningJob) {\n proc.close();\n }\n return proc.join();\n }),\n );\n };\n\n let timer: NodeJS.Timeout | undefined;\n if (timeout) {\n timer = setTimeout(() => {\n throw new WorkerError('timed out draining');\n }, timeout);\n }\n await joinJobs().then(() => {\n if (timeout) {\n clearTimeout(timer);\n }\n });\n }\n\n async simulateJob(roomName: string, participantIdentity?: string) {\n const client = new RoomServiceClient(this.#opts.wsURL, this.#opts.apiKey, this.#opts.apiSecret);\n const room = await client.createRoom({ name: roomName });\n let participant: ParticipantInfo | undefined = undefined;\n if (participantIdentity) {\n try {\n participant = await client.getParticipant(roomName, participantIdentity);\n } catch (e) {\n this.#logger.fatal(\n `participant with identity ${participantIdentity} not found in room ${roomName}`,\n );\n throw e;\n }\n }\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'simulateJob',\n value: {\n type: JobType.JT_PUBLISHER,\n room,\n participant,\n },\n },\n }),\n );\n }\n\n async #runWS(ws: WebSocket) {\n let closingWS = false;\n\n const send = (msg: WorkerMessage) => {\n if (closingWS) {\n this.event.off('worker_msg', send);\n return;\n }\n ws.send(msg.toBinary());\n };\n this.event.on('worker_msg', send);\n\n const close = new Promise<void>((resolve) => {\n ws.addEventListener('close', () => {\n closingWS = true;\n if (!this.#closed) {\n this.#logger.error('worker connection closed unexpectedly');\n }\n resolve();\n });\n });\n\n ws.addEventListener('error', (event) => {\n this.#logger.error('worker error:', event.message);\n });\n\n ws.addEventListener('message', (event) => {\n if (event.type !== 'message') {\n this.#logger.warn('unexpected message type: ' + event.type);\n return;\n }\n\n const msg = new ServerMessage();\n msg.fromBinary(event.data as Uint8Array);\n\n // register is the only valid first message, and it is only valid as the\n // first message\n if (this.#connecting && msg.message.case !== 'register') {\n throw new WorkerError('expected register response as first message');\n }\n\n switch (msg.message.case) {\n case 'register': {\n this.#id = msg.message.value.workerId;\n this.#logger\n .child({ id: this.id, server_info: msg.message.value.serverInfo })\n .info('registered worker');\n this.event.emit(\n 'worker_registered',\n msg.message.value.workerId,\n msg.message.value.serverInfo,\n );\n this.#connecting = false;\n break;\n }\n case 'availability': {\n if (!msg.message.value.job) return;\n const task = this.#availability(msg.message.value);\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n break;\n }\n case 'assignment': {\n if (!msg.message.value.job) return;\n const job = msg.message.value.job;\n if (job.id in this.#pending) {\n const task = this.#pending[job.id];\n delete this.#pending[job.id];\n task?.resolve(msg.message.value);\n } else {\n this.#logger.child({ job }).warn('received assignment for unknown job ' + job.id);\n }\n break;\n }\n case 'termination': {\n const task = this.#termination(msg.message.value);\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n break;\n }\n }\n });\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'register',\n value: {\n type: this.#opts.workerType,\n agentName: this.#opts.agentName,\n allowedPermissions: new ParticipantPermission({\n canPublish: this.#opts.permissions.canPublish,\n canSubscribe: this.#opts.permissions.canSubscribe,\n canPublishData: this.#opts.permissions.canPublishData,\n canUpdateMetadata: this.#opts.permissions.canUpdateMetadata,\n hidden: this.#opts.permissions.hidden,\n agent: true,\n }),\n version,\n },\n },\n }),\n );\n\n let currentStatus = WorkerStatus.WS_AVAILABLE;\n const loadMonitor = setInterval(() => {\n if (closingWS) clearInterval(loadMonitor);\n\n const oldStatus = currentStatus;\n this.#opts.loadFunc().then((currentLoad: number) => {\n const isFull = currentLoad >= this.#opts.loadThreshold;\n const currentlyAvailable = !isFull;\n currentStatus = currentlyAvailable ? WorkerStatus.WS_AVAILABLE : WorkerStatus.WS_FULL;\n\n if (oldStatus != currentStatus) {\n const extra = { load: currentLoad, loadThreshold: this.#opts.loadThreshold };\n if (isFull) {\n this.#logger.child(extra).info('worker is at full capacity, marking as unavailable');\n } else {\n this.#logger.child(extra).info('worker is below capacity, marking as available');\n }\n }\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'updateWorker',\n value: {\n load: currentLoad,\n status: currentStatus,\n },\n },\n }),\n );\n });\n }, UPDATE_LOAD_INTERVAL);\n\n await close;\n ws.removeAllListeners();\n }\n\n async #availability(msg: AvailabilityRequest) {\n let answered = false;\n\n const onReject = async () => {\n answered = true;\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'availability',\n value: {\n jobId: msg.job!.id,\n available: false,\n },\n },\n }),\n );\n };\n\n const onAccept = async (args: JobAcceptArguments) => {\n answered = true;\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'availability',\n value: {\n jobId: msg.job!.id,\n available: true,\n participantIdentity: args.identity,\n participantName: args.name,\n participantMetadata: args.metadata,\n participantAttributes: args.attributes,\n },\n },\n }),\n );\n\n this.#pending[req.id] = new PendingAssignment();\n const timer = setTimeout(() => {\n this.#logger.child({ req }).warn(`assignment for job ${req.id} timed out`);\n return;\n }, ASSIGNMENT_TIMEOUT);\n const asgn = await this.#pending[req.id]?.promise.then(async (asgn) => {\n clearTimeout(timer);\n return asgn;\n });\n\n if (asgn) {\n await this.#procPool.launchJob({\n acceptArguments: args,\n job: msg.job!,\n url: asgn.url || this.#opts.wsURL,\n token: asgn.token,\n });\n } else {\n this.#logger.child({ requestId: req.id }).warn('pending assignment not found');\n }\n };\n\n const req = new JobRequest(msg.job!, onReject, onAccept);\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('received job request');\n\n const jobRequestTask = async () => {\n try {\n await this.#opts.requestFunc(req);\n } catch (e) {\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('jobRequestFunc failed');\n await onReject();\n }\n\n if (!answered) {\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('no answer was given inside the jobRequestFunc, automatically rejecting the job');\n }\n };\n\n const task = jobRequestTask();\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n }\n\n async #termination(msg: JobTermination) {\n const proc = this.#procPool.getByJobId(msg.jobId);\n if (proc === null) {\n // safe to ignore\n return;\n }\n await proc.close();\n }\n\n async close() {\n if (this.#closed) {\n await this.#close.await;\n return;\n }\n\n this.#logger.info('shutting down worker');\n\n this.#closed = true;\n\n await this.#inferenceExecutor?.close();\n await this.#procPool.close();\n await this.#httpServer.close();\n await Promise.allSettled(this.#tasks);\n\n this.#session?.close();\n await this.#close.await;\n }\n}\n"],"mappings":"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","names":["os","i","asgn"]}
1
+ {"version":3,"sources":["../src/worker.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type {\n JobAssignment,\n JobTermination,\n ParticipantInfo,\n TrackSource,\n} from '@livekit/protocol';\nimport {\n type AvailabilityRequest,\n JobType,\n ParticipantPermission,\n ServerMessage,\n WorkerMessage,\n WorkerStatus,\n} from '@livekit/protocol';\nimport { AccessToken, RoomServiceClient } from 'livekit-server-sdk';\nimport { EventEmitter } from 'node:events';\nimport os from 'node:os';\nimport { WebSocket } from 'ws';\nimport { HTTPServer } from './http_server.js';\nimport { InferenceRunner } from './inference_runner.js';\nimport { InferenceProcExecutor } from './ipc/inference_proc_executor.js';\nimport { ProcPool } from './ipc/proc_pool.js';\nimport type { JobAcceptArguments, JobProcess, RunningJobInfo } from './job.js';\nimport { JobRequest } from './job.js';\nimport { log } from './log.js';\nimport { Future } from './utils.js';\nimport { version } from './version.js';\n\nconst MAX_RECONNECT_ATTEMPTS = 10;\nconst ASSIGNMENT_TIMEOUT = 7.5 * 1000;\nconst UPDATE_LOAD_INTERVAL = 2.5 * 1000;\n\nclass Default {\n static loadThreshold(production: boolean): number {\n if (production) {\n return 0.65;\n } else {\n return Infinity;\n }\n }\n\n static numIdleProcesses(production: boolean): number {\n if (production) {\n return 3;\n } else {\n return 0;\n }\n }\n\n static port(production: boolean): number {\n if (production) {\n return 8081;\n } else {\n return 0;\n }\n }\n}\n\n/** Necessary credentials not provided and not found in an appropriate environmental variable. */\nexport class MissingCredentialsError extends Error {\n constructor(msg?: string) {\n super(msg);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Worker did not run as expected. */\nexport class WorkerError extends Error {\n constructor(msg?: string) {\n super(msg);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** @internal */\nexport const defaultInitializeProcessFunc = (_: JobProcess) => _;\nconst defaultRequestFunc = async (ctx: JobRequest) => {\n await ctx.accept();\n};\nconst defaultCpuLoad = async (): Promise<number> => {\n return new Promise((resolve) => {\n const cpus1 = os.cpus();\n\n setTimeout(() => {\n const cpus2 = os.cpus();\n\n let idle = 0;\n let total = 0;\n\n for (let i = 0; i < cpus1.length; i++) {\n const cpu1 = cpus1[i]!.times;\n const cpu2 = cpus2[i]!.times;\n\n idle += cpu2.idle - cpu1.idle;\n\n const total1 = Object.values(cpu1).reduce((acc, i) => acc + i, 0);\n const total2 = Object.values(cpu2).reduce((acc, i) => acc + i, 0);\n\n total += total2 - total1;\n }\n\n resolve(+(1 - idle / total).toFixed(2));\n }, UPDATE_LOAD_INTERVAL);\n });\n};\n\n/** Participant permissions to pass to every agent spun up by this worker. */\nexport class WorkerPermissions {\n canPublish: boolean;\n canSubscribe: boolean;\n canPublishData: boolean;\n canUpdateMetadata: boolean;\n canPublishSources: TrackSource[];\n hidden: boolean;\n\n constructor(\n canPublish = true,\n canSubscribe = true,\n canPublishData = true,\n canUpdateMetadata = true,\n canPublishSources: TrackSource[] = [],\n hidden = false,\n ) {\n this.canPublish = canPublish;\n this.canSubscribe = canSubscribe;\n this.canPublishData = canPublishData;\n this.canUpdateMetadata = canUpdateMetadata;\n this.canPublishSources = canPublishSources;\n this.hidden = hidden;\n }\n}\n\n/**\n * Data class describing worker behaviour.\n *\n * @remarks\n * The Agents framework provides sane worker defaults, and works out-of-the-box with no tweaking\n * necessary. The only mandatory parameter is `agent`, which points to the entry function.\n *\n * This class is mostly useful in conjunction with {@link cli.runApp}.\n */\nexport class WorkerOptions {\n agent: string;\n requestFunc: (job: JobRequest) => Promise<void>;\n loadFunc: () => Promise<number>;\n loadThreshold: number;\n numIdleProcesses: number;\n shutdownProcessTimeout: number;\n initializeProcessTimeout: number;\n permissions: WorkerPermissions;\n agentName: string;\n workerType: JobType;\n maxRetry: number;\n wsURL: string;\n apiKey?: string;\n apiSecret?: string;\n workerToken?: string;\n host: string;\n port: number;\n logLevel: string;\n production: boolean;\n jobMemoryWarnMB: number;\n jobMemoryLimitMB: number;\n\n /** @param options */\n constructor({\n agent,\n requestFunc = defaultRequestFunc,\n loadFunc = defaultCpuLoad,\n loadThreshold = undefined,\n numIdleProcesses = undefined,\n shutdownProcessTimeout = 60 * 1000,\n initializeProcessTimeout = 10 * 1000,\n permissions = new WorkerPermissions(),\n agentName = '',\n workerType = JobType.JT_ROOM,\n maxRetry = MAX_RECONNECT_ATTEMPTS,\n wsURL = 'ws://localhost:7880',\n apiKey = undefined,\n apiSecret = undefined,\n 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?: () => 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 (Object.entries(InferenceRunner.registeredRunners).length) {\n this.#inferenceExecutor = new InferenceProcExecutor({\n runners: InferenceRunner.registeredRunners,\n initializeTimeout: 30000,\n closeTimeout: 5000,\n memoryWarnMB: 2000,\n memoryLimitMB: 0,\n pingInterval: 5000,\n pingTimeout: 60000,\n highPingThreshold: 2500,\n });\n }\n\n this.#procPool = new ProcPool(\n opts.agent,\n opts.numIdleProcesses,\n opts.initializeProcessTimeout,\n opts.shutdownProcessTimeout,\n this.#inferenceExecutor,\n opts.jobMemoryWarnMB,\n opts.jobMemoryLimitMB,\n );\n\n this.#opts = opts;\n this.#httpServer = new HTTPServer(opts.host, opts.port, () => ({\n agent_name: opts.agentName,\n worker_type: JobType[opts.workerType],\n active_jobs: this.activeJobs.length,\n }));\n }\n\n /* @throws {@link WorkerError} if worker failed to connect or already running */\n async run() {\n if (!this.#closed) {\n throw new WorkerError('worker is already running');\n }\n\n if (this.#inferenceExecutor) {\n await this.#inferenceExecutor.start();\n await this.#inferenceExecutor.initialize();\n }\n\n this.#logger.info('starting worker');\n this.#closed = false;\n this.#procPool.start();\n\n const workerWS = async () => {\n let retries = 0;\n this.#connecting = true;\n\n while (!this.#closed) {\n const url = new URL(this.#opts.wsURL);\n url.protocol = url.protocol.replace('http', 'ws');\n const token = new AccessToken(this.#opts.apiKey, this.#opts.apiSecret);\n token.addGrant({ agent: true });\n const jwt = await token.toJwt();\n 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.info('draining worker');\n this.#draining = true;\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'updateWorker',\n value: {\n status: WorkerStatus.WS_FULL,\n },\n },\n }),\n );\n\n const joinJobs = async () => {\n return Promise.all(\n this.#procPool.processes.map((proc) => {\n if (!proc.runningJob) {\n proc.close();\n }\n return proc.join();\n }),\n );\n };\n\n let timer: NodeJS.Timeout | undefined;\n if (timeout) {\n timer = setTimeout(() => {\n throw new WorkerError('timed out draining');\n }, timeout);\n }\n await joinJobs().then(() => {\n if (timeout) {\n clearTimeout(timer);\n }\n });\n }\n\n async simulateJob(roomName: string, participantIdentity?: string) {\n const client = new RoomServiceClient(this.#opts.wsURL, this.#opts.apiKey, this.#opts.apiSecret);\n const room = await client.createRoom({ name: roomName });\n let participant: ParticipantInfo | undefined = undefined;\n if (participantIdentity) {\n try {\n participant = await client.getParticipant(roomName, participantIdentity);\n } catch (e) {\n this.#logger.fatal(\n `participant with identity ${participantIdentity} not found in room ${roomName}`,\n );\n throw e;\n }\n }\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'simulateJob',\n value: {\n type: JobType.JT_PUBLISHER,\n room,\n participant,\n },\n },\n }),\n );\n }\n\n async #runWS(ws: WebSocket) {\n let closingWS = false;\n\n const send = (msg: WorkerMessage) => {\n if (closingWS) {\n this.event.off('worker_msg', send);\n return;\n }\n ws.send(msg.toBinary());\n };\n this.event.on('worker_msg', send);\n\n const close = new Promise<void>((resolve) => {\n ws.addEventListener('close', () => {\n closingWS = true;\n if (!this.#closed) {\n this.#logger.error('worker connection closed unexpectedly');\n }\n resolve();\n });\n });\n\n ws.addEventListener('error', (event) => {\n this.#logger.error('worker error:', event.message);\n });\n\n ws.addEventListener('message', (event) => {\n if (event.type !== 'message') {\n this.#logger.warn('unexpected message type: ' + event.type);\n return;\n }\n\n const msg = new ServerMessage();\n msg.fromBinary(event.data as Uint8Array);\n\n // register is the only valid first message, and it is only valid as the\n // first message\n if (this.#connecting && msg.message.case !== 'register') {\n throw new WorkerError('expected register response as first message');\n }\n\n switch (msg.message.case) {\n case 'register': {\n this.#id = msg.message.value.workerId;\n this.#logger\n .child({ id: this.id, server_info: msg.message.value.serverInfo })\n .info('registered worker');\n this.event.emit(\n 'worker_registered',\n msg.message.value.workerId,\n msg.message.value.serverInfo,\n );\n this.#connecting = false;\n break;\n }\n case 'availability': {\n if (!msg.message.value.job) return;\n const task = this.#availability(msg.message.value);\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n break;\n }\n case 'assignment': {\n if (!msg.message.value.job) return;\n const job = msg.message.value.job;\n if (job.id in this.#pending) {\n const task = this.#pending[job.id];\n delete this.#pending[job.id];\n task?.resolve(msg.message.value);\n } else {\n this.#logger.child({ job }).warn('received assignment for unknown job ' + job.id);\n }\n break;\n }\n case 'termination': {\n const task = this.#termination(msg.message.value);\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n break;\n }\n }\n });\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'register',\n value: {\n type: this.#opts.workerType,\n agentName: this.#opts.agentName,\n allowedPermissions: new ParticipantPermission({\n canPublish: this.#opts.permissions.canPublish,\n canSubscribe: this.#opts.permissions.canSubscribe,\n canPublishData: this.#opts.permissions.canPublishData,\n canUpdateMetadata: this.#opts.permissions.canUpdateMetadata,\n hidden: this.#opts.permissions.hidden,\n agent: true,\n }),\n version,\n },\n },\n }),\n );\n\n let currentStatus = WorkerStatus.WS_AVAILABLE;\n const loadMonitor = setInterval(() => {\n if (closingWS) clearInterval(loadMonitor);\n\n const oldStatus = currentStatus;\n this.#opts.loadFunc().then((currentLoad: number) => {\n const isFull = currentLoad >= this.#opts.loadThreshold;\n const currentlyAvailable = !isFull;\n currentStatus = currentlyAvailable ? WorkerStatus.WS_AVAILABLE : WorkerStatus.WS_FULL;\n\n if (oldStatus != currentStatus) {\n const extra = { load: currentLoad, loadThreshold: this.#opts.loadThreshold };\n if (isFull) {\n this.#logger.child(extra).info('worker is at full capacity, marking as unavailable');\n } else {\n this.#logger.child(extra).info('worker is below capacity, marking as available');\n }\n }\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'updateWorker',\n value: {\n load: currentLoad,\n status: currentStatus,\n },\n },\n }),\n );\n });\n }, UPDATE_LOAD_INTERVAL);\n\n await close;\n ws.removeAllListeners();\n }\n\n async #availability(msg: AvailabilityRequest) {\n let answered = false;\n\n const onReject = async () => {\n answered = true;\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'availability',\n value: {\n jobId: msg.job!.id,\n available: false,\n },\n },\n }),\n );\n };\n\n const onAccept = async (args: JobAcceptArguments) => {\n answered = true;\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'availability',\n value: {\n jobId: msg.job!.id,\n available: true,\n participantIdentity: args.identity,\n participantName: args.name,\n participantMetadata: args.metadata,\n participantAttributes: args.attributes,\n },\n },\n }),\n );\n\n this.#pending[req.id] = new PendingAssignment();\n const timer = setTimeout(() => {\n this.#logger.child({ req }).warn(`assignment for job ${req.id} timed out`);\n return;\n }, ASSIGNMENT_TIMEOUT);\n const asgn = await this.#pending[req.id]?.promise.then(async (asgn) => {\n clearTimeout(timer);\n return asgn;\n });\n\n if (asgn) {\n await this.#procPool.launchJob({\n acceptArguments: args,\n job: msg.job!,\n url: asgn.url || this.#opts.wsURL,\n token: asgn.token,\n });\n } else {\n this.#logger.child({ requestId: req.id }).warn('pending assignment not found');\n }\n };\n\n const req = new JobRequest(msg.job!, onReject, onAccept);\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('received job request');\n\n const jobRequestTask = async () => {\n try {\n await this.#opts.requestFunc(req);\n } catch (e) {\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('jobRequestFunc failed');\n await onReject();\n }\n\n if (!answered) {\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('no answer was given inside the jobRequestFunc, automatically rejecting the job');\n }\n };\n\n const task = jobRequestTask();\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n }\n\n async #termination(msg: JobTermination) {\n const proc = this.#procPool.getByJobId(msg.jobId);\n if (proc === null) {\n // safe to ignore\n return;\n }\n await proc.close();\n }\n\n async close() {\n if (this.#closed) {\n await this.#close.await;\n return;\n }\n\n this.#logger.info('shutting down worker');\n\n this.#closed = true;\n\n await this.#inferenceExecutor?.close();\n await this.#procPool.close();\n await this.#httpServer.close();\n await Promise.allSettled(this.#tasks);\n\n this.#session?.close();\n await this.#close.await;\n }\n}\n"],"mappings":"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","names":["os","i","asgn"]}
package/dist/worker.d.ts CHANGED
@@ -48,6 +48,7 @@ export declare class WorkerOptions {
48
48
  wsURL: string;
49
49
  apiKey?: string;
50
50
  apiSecret?: string;
51
+ workerToken?: string;
51
52
  host: string;
52
53
  port: number;
53
54
  logLevel: string;
@@ -55,7 +56,7 @@ export declare class WorkerOptions {
55
56
  jobMemoryWarnMB: number;
56
57
  jobMemoryLimitMB: number;
57
58
  /** @param options */
58
- constructor({ agent, requestFunc, loadFunc, loadThreshold, numIdleProcesses, shutdownProcessTimeout, initializeProcessTimeout, permissions, agentName, workerType, maxRetry, wsURL, apiKey, apiSecret, host, port, logLevel, production, jobMemoryWarnMB, jobMemoryLimitMB, }: {
59
+ constructor({ agent, requestFunc, loadFunc, loadThreshold, numIdleProcesses, shutdownProcessTimeout, initializeProcessTimeout, permissions, agentName, workerType, maxRetry, wsURL, apiKey, apiSecret, workerToken, host, port, logLevel, production, jobMemoryWarnMB, jobMemoryLimitMB, }: {
59
60
  /**
60
61
  * Path to a file that has {@link Agent} as a default export, dynamically imported later for
61
62
  * entrypoint and prewarm functions
@@ -76,6 +77,7 @@ export declare class WorkerOptions {
76
77
  wsURL?: string;
77
78
  apiKey?: string;
78
79
  apiSecret?: string;
80
+ workerToken?: string;
79
81
  host?: string;
80
82
  port?: number;
81
83
  logLevel?: string;
@@ -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
@@ -109,6 +109,7 @@ class WorkerOptions {
109
109
  wsURL;
110
110
  apiKey;
111
111
  apiSecret;
112
+ workerToken;
112
113
  host;
113
114
  port;
114
115
  logLevel;
@@ -131,6 +132,7 @@ class WorkerOptions {
131
132
  wsURL = "ws://localhost:7880",
132
133
  apiKey = void 0,
133
134
  apiSecret = void 0,
135
+ workerToken = void 0,
134
136
  host = "0.0.0.0",
135
137
  port = void 0,
136
138
  logLevel = "info",
@@ -155,6 +157,7 @@ class WorkerOptions {
155
157
  this.wsURL = wsURL;
156
158
  this.apiKey = apiKey;
157
159
  this.apiSecret = apiSecret;
160
+ this.workerToken = workerToken;
158
161
  this.host = host;
159
162
  this.port = port || Default.port(production);
160
163
  this.logLevel = logLevel;
@@ -252,7 +255,11 @@ class Worker {
252
255
  const token = new AccessToken(this.#opts.apiKey, this.#opts.apiSecret);
253
256
  token.addGrant({ agent: true });
254
257
  const jwt = await token.toJwt();
255
- this.#session = new WebSocket(url + "agent", {
258
+ const wsUrl = new URL(url + "agent");
259
+ if (this.#opts.workerToken) {
260
+ wsUrl.searchParams.append("worker_token", this.#opts.workerToken);
261
+ }
262
+ this.#session = new WebSocket(wsUrl, {
256
263
  headers: { authorization: "Bearer " + jwt }
257
264
  });
258
265
  try {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/worker.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type {\n JobAssignment,\n JobTermination,\n ParticipantInfo,\n TrackSource,\n} from '@livekit/protocol';\nimport {\n type AvailabilityRequest,\n JobType,\n ParticipantPermission,\n ServerMessage,\n WorkerMessage,\n WorkerStatus,\n} from '@livekit/protocol';\nimport { AccessToken, RoomServiceClient } from 'livekit-server-sdk';\nimport { EventEmitter } from 'node:events';\nimport os from 'node:os';\nimport { WebSocket } from 'ws';\nimport { HTTPServer } from './http_server.js';\nimport { InferenceRunner } from './inference_runner.js';\nimport { InferenceProcExecutor } from './ipc/inference_proc_executor.js';\nimport { ProcPool } from './ipc/proc_pool.js';\nimport type { JobAcceptArguments, JobProcess, RunningJobInfo } from './job.js';\nimport { JobRequest } from './job.js';\nimport { log } from './log.js';\nimport { Future } from './utils.js';\nimport { version } from './version.js';\n\nconst MAX_RECONNECT_ATTEMPTS = 10;\nconst ASSIGNMENT_TIMEOUT = 7.5 * 1000;\nconst UPDATE_LOAD_INTERVAL = 2.5 * 1000;\n\nclass Default {\n static loadThreshold(production: boolean): number {\n if (production) {\n return 0.65;\n } else {\n return Infinity;\n }\n }\n\n static numIdleProcesses(production: boolean): number {\n if (production) {\n return 3;\n } else {\n return 0;\n }\n }\n\n static port(production: boolean): number {\n if (production) {\n return 8081;\n } else {\n return 0;\n }\n }\n}\n\n/** Necessary credentials not provided and not found in an appropriate environmental variable. */\nexport class MissingCredentialsError extends Error {\n constructor(msg?: string) {\n super(msg);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Worker did not run as expected. */\nexport class WorkerError extends Error {\n constructor(msg?: string) {\n super(msg);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** @internal */\nexport const defaultInitializeProcessFunc = (_: JobProcess) => _;\nconst defaultRequestFunc = async (ctx: JobRequest) => {\n await ctx.accept();\n};\nconst defaultCpuLoad = async (): Promise<number> => {\n return new Promise((resolve) => {\n const cpus1 = os.cpus();\n\n setTimeout(() => {\n const cpus2 = os.cpus();\n\n let idle = 0;\n let total = 0;\n\n for (let i = 0; i < cpus1.length; i++) {\n const cpu1 = cpus1[i]!.times;\n const cpu2 = cpus2[i]!.times;\n\n idle += cpu2.idle - cpu1.idle;\n\n const total1 = Object.values(cpu1).reduce((acc, i) => acc + i, 0);\n const total2 = Object.values(cpu2).reduce((acc, i) => acc + i, 0);\n\n total += total2 - total1;\n }\n\n resolve(+(1 - idle / total).toFixed(2));\n }, UPDATE_LOAD_INTERVAL);\n });\n};\n\n/** Participant permissions to pass to every agent spun up by this worker. */\nexport class WorkerPermissions {\n canPublish: boolean;\n canSubscribe: boolean;\n canPublishData: boolean;\n canUpdateMetadata: boolean;\n canPublishSources: TrackSource[];\n hidden: boolean;\n\n constructor(\n canPublish = true,\n canSubscribe = true,\n canPublishData = true,\n canUpdateMetadata = true,\n canPublishSources: TrackSource[] = [],\n hidden = false,\n ) {\n this.canPublish = canPublish;\n this.canSubscribe = canSubscribe;\n this.canPublishData = canPublishData;\n this.canUpdateMetadata = canUpdateMetadata;\n this.canPublishSources = canPublishSources;\n this.hidden = hidden;\n }\n}\n\n/**\n * Data class describing worker behaviour.\n *\n * @remarks\n * The Agents framework provides sane worker defaults, and works out-of-the-box with no tweaking\n * necessary. The only mandatory parameter is `agent`, which points to the entry function.\n *\n * This class is mostly useful in conjunction with {@link cli.runApp}.\n */\nexport class WorkerOptions {\n agent: string;\n requestFunc: (job: JobRequest) => Promise<void>;\n loadFunc: () => Promise<number>;\n loadThreshold: number;\n numIdleProcesses: number;\n shutdownProcessTimeout: number;\n initializeProcessTimeout: number;\n permissions: WorkerPermissions;\n agentName: string;\n workerType: JobType;\n maxRetry: number;\n wsURL: string;\n apiKey?: string;\n apiSecret?: string;\n host: string;\n port: number;\n logLevel: string;\n production: boolean;\n jobMemoryWarnMB: number;\n jobMemoryLimitMB: number;\n\n /** @param options */\n constructor({\n agent,\n requestFunc = defaultRequestFunc,\n loadFunc = defaultCpuLoad,\n loadThreshold = undefined,\n numIdleProcesses = undefined,\n shutdownProcessTimeout = 60 * 1000,\n initializeProcessTimeout = 10 * 1000,\n permissions = new WorkerPermissions(),\n agentName = '',\n workerType = JobType.JT_ROOM,\n maxRetry = MAX_RECONNECT_ATTEMPTS,\n wsURL = 'ws://localhost:7880',\n apiKey = undefined,\n apiSecret = undefined,\n host = '0.0.0.0',\n port = undefined,\n logLevel = 'info',\n production = false,\n jobMemoryWarnMB = 300,\n jobMemoryLimitMB = 0,\n }: {\n /**\n * Path to a file that has {@link Agent} as a default export, dynamically imported later for\n * entrypoint and prewarm functions\n */\n agent: string;\n requestFunc?: (job: JobRequest) => Promise<void>;\n /** Called to determine the current load of the worker. Should return a value between 0 and 1. */\n loadFunc?: () => Promise<number>;\n /** When the load exceeds this threshold, the worker will be marked as unavailable. */\n loadThreshold?: number;\n numIdleProcesses?: number;\n shutdownProcessTimeout?: number;\n initializeProcessTimeout?: number;\n permissions?: WorkerPermissions;\n agentName?: string;\n workerType?: JobType;\n maxRetry?: number;\n wsURL?: string;\n apiKey?: string;\n apiSecret?: string;\n host?: string;\n port?: number;\n logLevel?: string;\n production?: boolean;\n jobMemoryWarnMB?: number;\n jobMemoryLimitMB?: number;\n }) {\n this.agent = agent;\n if (!this.agent) {\n throw new Error('No Agent file was passed to the worker');\n }\n this.requestFunc = requestFunc;\n this.loadFunc = loadFunc;\n this.loadThreshold = loadThreshold || Default.loadThreshold(production);\n this.numIdleProcesses = numIdleProcesses || Default.numIdleProcesses(production);\n this.shutdownProcessTimeout = shutdownProcessTimeout;\n this.initializeProcessTimeout = initializeProcessTimeout;\n this.permissions = permissions;\n this.agentName = agentName;\n this.workerType = workerType;\n this.maxRetry = maxRetry;\n this.wsURL = wsURL;\n this.apiKey = apiKey;\n this.apiSecret = apiSecret;\n this.host = host;\n this.port = port || Default.port(production);\n this.logLevel = logLevel;\n this.production = production;\n this.jobMemoryWarnMB = jobMemoryWarnMB;\n this.jobMemoryLimitMB = jobMemoryLimitMB;\n }\n}\n\nclass PendingAssignment {\n promise = new Promise<JobAssignment>((resolve) => {\n this.resolve = resolve; // this is how JavaScript lets you resolve promises externally\n });\n resolve(arg: JobAssignment) {\n arg; // useless call to counteract TypeScript E6133\n }\n}\n\n/**\n * Central orchestrator for all processes and job requests.\n *\n * @remarks\n * For most usecases, Worker should not be initialized or handled directly; you should instead call\n * for its creation through {@link cli.runApp}. This could, however, be useful in situations where\n * you don't have access to a command line, such as a headless program, or one that uses Agents\n * behind a wrapper.\n */\nexport class Worker {\n #opts: WorkerOptions;\n #procPool: ProcPool;\n\n #id = 'unregistered';\n #closed = true;\n #draining = false;\n #connecting = false;\n #tasks: Promise<void>[] = [];\n #pending: { [id: string]: PendingAssignment } = {};\n #close = new Future();\n\n event = new EventEmitter();\n #session: WebSocket | undefined = undefined;\n #httpServer: HTTPServer;\n #logger = log().child({ version });\n #inferenceExecutor?: InferenceProcExecutor;\n\n /* @throws {@link MissingCredentialsError} if URL, API key or API secret are missing */\n constructor(opts: WorkerOptions) {\n opts.wsURL = opts.wsURL || process.env.LIVEKIT_URL || '';\n opts.apiKey = opts.apiKey || process.env.LIVEKIT_API_KEY || '';\n opts.apiSecret = opts.apiSecret || process.env.LIVEKIT_API_SECRET || '';\n\n if (opts.wsURL === '')\n throw new MissingCredentialsError(\n 'URL is required: Set LIVEKIT_URL, run with --url, or pass wsURL in WorkerOptions',\n );\n if (opts.apiKey === '')\n throw new MissingCredentialsError(\n 'API Key is required: Set LIVEKIT_API_KEY, run with --api-key, or pass apiKey in WorkerOptions',\n );\n if (opts.apiSecret === '')\n throw new MissingCredentialsError(\n 'API Secret is required: Set LIVEKIT_API_SECRET, run with --api-secret, or pass apiSecret in WorkerOptions',\n );\n\n if (Object.entries(InferenceRunner.registeredRunners).length) {\n this.#inferenceExecutor = new InferenceProcExecutor({\n runners: InferenceRunner.registeredRunners,\n initializeTimeout: 30000,\n closeTimeout: 5000,\n memoryWarnMB: 2000,\n memoryLimitMB: 0,\n pingInterval: 5000,\n pingTimeout: 60000,\n highPingThreshold: 2500,\n });\n }\n\n this.#procPool = new ProcPool(\n opts.agent,\n opts.numIdleProcesses,\n opts.initializeProcessTimeout,\n opts.shutdownProcessTimeout,\n this.#inferenceExecutor,\n opts.jobMemoryWarnMB,\n opts.jobMemoryLimitMB,\n );\n\n this.#opts = opts;\n this.#httpServer = new HTTPServer(opts.host, opts.port, () => ({\n agent_name: opts.agentName,\n worker_type: JobType[opts.workerType],\n active_jobs: this.activeJobs.length,\n }));\n }\n\n /* @throws {@link WorkerError} if worker failed to connect or already running */\n async run() {\n if (!this.#closed) {\n throw new WorkerError('worker is already running');\n }\n\n if (this.#inferenceExecutor) {\n await this.#inferenceExecutor.start();\n await this.#inferenceExecutor.initialize();\n }\n\n this.#logger.info('starting worker');\n this.#closed = false;\n this.#procPool.start();\n\n const workerWS = async () => {\n let retries = 0;\n this.#connecting = true;\n\n while (!this.#closed) {\n const url = new URL(this.#opts.wsURL);\n url.protocol = url.protocol.replace('http', 'ws');\n const token = new AccessToken(this.#opts.apiKey, this.#opts.apiSecret);\n token.addGrant({ agent: true });\n const jwt = await token.toJwt();\n this.#session = new WebSocket(url + 'agent', {\n headers: { authorization: 'Bearer ' + jwt },\n });\n\n try {\n await new Promise((resolve, reject) => {\n this.#session!.on('open', resolve);\n this.#session!.on('error', (error) => reject(error.message));\n this.#session!.on('close', (code) => reject(`WebSocket returned ${code}`));\n });\n\n retries = 0;\n this.#logger.debug('connected to LiveKit server');\n await this.#runWS(this.#session);\n } catch (e: unknown) {\n if (e instanceof Error || e instanceof ErrorEvent) {\n e = e.message;\n }\n\n if (this.#closed) return;\n if (retries >= this.#opts.maxRetry) {\n throw new WorkerError(\n `failed to connect to LiveKit server after ${retries} attempts: ${e}`,\n );\n }\n\n retries++;\n const delay = Math.min(retries * 2, 10);\n\n this.#logger.warn(\n `failed to connect to LiveKit server, retrying in ${delay} seconds: ${e} (${retries}/${this.#opts.maxRetry})`,\n );\n\n await new Promise((resolve) => setTimeout(resolve, delay * 1000));\n }\n }\n };\n\n await Promise.all([workerWS(), this.#httpServer.run()]);\n this.#close.resolve();\n }\n\n get id(): string {\n return this.#id;\n }\n\n get activeJobs(): RunningJobInfo[] {\n return this.#procPool.processes\n .filter((proc) => proc.runningJob)\n .map((proc) => proc.runningJob!);\n }\n\n /* @throws {@link WorkerError} if worker did not drain in time */\n async drain(timeout?: number) {\n if (this.#draining) {\n return;\n }\n\n this.#logger.info('draining worker');\n this.#draining = true;\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'updateWorker',\n value: {\n status: WorkerStatus.WS_FULL,\n },\n },\n }),\n );\n\n const joinJobs = async () => {\n return Promise.all(\n this.#procPool.processes.map((proc) => {\n if (!proc.runningJob) {\n proc.close();\n }\n return proc.join();\n }),\n );\n };\n\n let timer: NodeJS.Timeout | undefined;\n if (timeout) {\n timer = setTimeout(() => {\n throw new WorkerError('timed out draining');\n }, timeout);\n }\n await joinJobs().then(() => {\n if (timeout) {\n clearTimeout(timer);\n }\n });\n }\n\n async simulateJob(roomName: string, participantIdentity?: string) {\n const client = new RoomServiceClient(this.#opts.wsURL, this.#opts.apiKey, this.#opts.apiSecret);\n const room = await client.createRoom({ name: roomName });\n let participant: ParticipantInfo | undefined = undefined;\n if (participantIdentity) {\n try {\n participant = await client.getParticipant(roomName, participantIdentity);\n } catch (e) {\n this.#logger.fatal(\n `participant with identity ${participantIdentity} not found in room ${roomName}`,\n );\n throw e;\n }\n }\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'simulateJob',\n value: {\n type: JobType.JT_PUBLISHER,\n room,\n participant,\n },\n },\n }),\n );\n }\n\n async #runWS(ws: WebSocket) {\n let closingWS = false;\n\n const send = (msg: WorkerMessage) => {\n if (closingWS) {\n this.event.off('worker_msg', send);\n return;\n }\n ws.send(msg.toBinary());\n };\n this.event.on('worker_msg', send);\n\n const close = new Promise<void>((resolve) => {\n ws.addEventListener('close', () => {\n closingWS = true;\n if (!this.#closed) {\n this.#logger.error('worker connection closed unexpectedly');\n }\n resolve();\n });\n });\n\n ws.addEventListener('error', (event) => {\n this.#logger.error('worker error:', event.message);\n });\n\n ws.addEventListener('message', (event) => {\n if (event.type !== 'message') {\n this.#logger.warn('unexpected message type: ' + event.type);\n return;\n }\n\n const msg = new ServerMessage();\n msg.fromBinary(event.data as Uint8Array);\n\n // register is the only valid first message, and it is only valid as the\n // first message\n if (this.#connecting && msg.message.case !== 'register') {\n throw new WorkerError('expected register response as first message');\n }\n\n switch (msg.message.case) {\n case 'register': {\n this.#id = msg.message.value.workerId;\n this.#logger\n .child({ id: this.id, server_info: msg.message.value.serverInfo })\n .info('registered worker');\n this.event.emit(\n 'worker_registered',\n msg.message.value.workerId,\n msg.message.value.serverInfo,\n );\n this.#connecting = false;\n break;\n }\n case 'availability': {\n if (!msg.message.value.job) return;\n const task = this.#availability(msg.message.value);\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n break;\n }\n case 'assignment': {\n if (!msg.message.value.job) return;\n const job = msg.message.value.job;\n if (job.id in this.#pending) {\n const task = this.#pending[job.id];\n delete this.#pending[job.id];\n task?.resolve(msg.message.value);\n } else {\n this.#logger.child({ job }).warn('received assignment for unknown job ' + job.id);\n }\n break;\n }\n case 'termination': {\n const task = this.#termination(msg.message.value);\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n break;\n }\n }\n });\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'register',\n value: {\n type: this.#opts.workerType,\n agentName: this.#opts.agentName,\n allowedPermissions: new ParticipantPermission({\n canPublish: this.#opts.permissions.canPublish,\n canSubscribe: this.#opts.permissions.canSubscribe,\n canPublishData: this.#opts.permissions.canPublishData,\n canUpdateMetadata: this.#opts.permissions.canUpdateMetadata,\n hidden: this.#opts.permissions.hidden,\n agent: true,\n }),\n version,\n },\n },\n }),\n );\n\n let currentStatus = WorkerStatus.WS_AVAILABLE;\n const loadMonitor = setInterval(() => {\n if (closingWS) clearInterval(loadMonitor);\n\n const oldStatus = currentStatus;\n this.#opts.loadFunc().then((currentLoad: number) => {\n const isFull = currentLoad >= this.#opts.loadThreshold;\n const currentlyAvailable = !isFull;\n currentStatus = currentlyAvailable ? WorkerStatus.WS_AVAILABLE : WorkerStatus.WS_FULL;\n\n if (oldStatus != currentStatus) {\n const extra = { load: currentLoad, loadThreshold: this.#opts.loadThreshold };\n if (isFull) {\n this.#logger.child(extra).info('worker is at full capacity, marking as unavailable');\n } else {\n this.#logger.child(extra).info('worker is below capacity, marking as available');\n }\n }\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'updateWorker',\n value: {\n load: currentLoad,\n status: currentStatus,\n },\n },\n }),\n );\n });\n }, UPDATE_LOAD_INTERVAL);\n\n await close;\n ws.removeAllListeners();\n }\n\n async #availability(msg: AvailabilityRequest) {\n let answered = false;\n\n const onReject = async () => {\n answered = true;\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'availability',\n value: {\n jobId: msg.job!.id,\n available: false,\n },\n },\n }),\n );\n };\n\n const onAccept = async (args: JobAcceptArguments) => {\n answered = true;\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'availability',\n value: {\n jobId: msg.job!.id,\n available: true,\n participantIdentity: args.identity,\n participantName: args.name,\n participantMetadata: args.metadata,\n participantAttributes: args.attributes,\n },\n },\n }),\n );\n\n this.#pending[req.id] = new PendingAssignment();\n const timer = setTimeout(() => {\n this.#logger.child({ req }).warn(`assignment for job ${req.id} timed out`);\n return;\n }, ASSIGNMENT_TIMEOUT);\n const asgn = await this.#pending[req.id]?.promise.then(async (asgn) => {\n clearTimeout(timer);\n return asgn;\n });\n\n if (asgn) {\n await this.#procPool.launchJob({\n acceptArguments: args,\n job: msg.job!,\n url: asgn.url || this.#opts.wsURL,\n token: asgn.token,\n });\n } else {\n this.#logger.child({ requestId: req.id }).warn('pending assignment not found');\n }\n };\n\n const req = new JobRequest(msg.job!, onReject, onAccept);\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('received job request');\n\n const jobRequestTask = async () => {\n try {\n await this.#opts.requestFunc(req);\n } catch (e) {\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('jobRequestFunc failed');\n await onReject();\n }\n\n if (!answered) {\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('no answer was given inside the jobRequestFunc, automatically rejecting the job');\n }\n };\n\n const task = jobRequestTask();\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n }\n\n async #termination(msg: JobTermination) {\n const proc = this.#procPool.getByJobId(msg.jobId);\n if (proc === null) {\n // safe to ignore\n return;\n }\n await proc.close();\n }\n\n async close() {\n if (this.#closed) {\n await this.#close.await;\n return;\n }\n\n this.#logger.info('shutting down worker');\n\n this.#closed = true;\n\n await this.#inferenceExecutor?.close();\n await this.#procPool.close();\n await this.#httpServer.close();\n await Promise.allSettled(this.#tasks);\n\n this.#session?.close();\n await this.#close.await;\n }\n}\n"],"mappings":"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","names":["i","asgn"]}
1
+ {"version":3,"sources":["../src/worker.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type {\n JobAssignment,\n JobTermination,\n ParticipantInfo,\n TrackSource,\n} from '@livekit/protocol';\nimport {\n type AvailabilityRequest,\n JobType,\n ParticipantPermission,\n ServerMessage,\n WorkerMessage,\n WorkerStatus,\n} from '@livekit/protocol';\nimport { AccessToken, RoomServiceClient } from 'livekit-server-sdk';\nimport { EventEmitter } from 'node:events';\nimport os from 'node:os';\nimport { WebSocket } from 'ws';\nimport { HTTPServer } from './http_server.js';\nimport { InferenceRunner } from './inference_runner.js';\nimport { InferenceProcExecutor } from './ipc/inference_proc_executor.js';\nimport { ProcPool } from './ipc/proc_pool.js';\nimport type { JobAcceptArguments, JobProcess, RunningJobInfo } from './job.js';\nimport { JobRequest } from './job.js';\nimport { log } from './log.js';\nimport { Future } from './utils.js';\nimport { version } from './version.js';\n\nconst MAX_RECONNECT_ATTEMPTS = 10;\nconst ASSIGNMENT_TIMEOUT = 7.5 * 1000;\nconst UPDATE_LOAD_INTERVAL = 2.5 * 1000;\n\nclass Default {\n static loadThreshold(production: boolean): number {\n if (production) {\n return 0.65;\n } else {\n return Infinity;\n }\n }\n\n static numIdleProcesses(production: boolean): number {\n if (production) {\n return 3;\n } else {\n return 0;\n }\n }\n\n static port(production: boolean): number {\n if (production) {\n return 8081;\n } else {\n return 0;\n }\n }\n}\n\n/** Necessary credentials not provided and not found in an appropriate environmental variable. */\nexport class MissingCredentialsError extends Error {\n constructor(msg?: string) {\n super(msg);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Worker did not run as expected. */\nexport class WorkerError extends Error {\n constructor(msg?: string) {\n super(msg);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** @internal */\nexport const defaultInitializeProcessFunc = (_: JobProcess) => _;\nconst defaultRequestFunc = async (ctx: JobRequest) => {\n await ctx.accept();\n};\nconst defaultCpuLoad = async (): Promise<number> => {\n return new Promise((resolve) => {\n const cpus1 = os.cpus();\n\n setTimeout(() => {\n const cpus2 = os.cpus();\n\n let idle = 0;\n let total = 0;\n\n for (let i = 0; i < cpus1.length; i++) {\n const cpu1 = cpus1[i]!.times;\n const cpu2 = cpus2[i]!.times;\n\n idle += cpu2.idle - cpu1.idle;\n\n const total1 = Object.values(cpu1).reduce((acc, i) => acc + i, 0);\n const total2 = Object.values(cpu2).reduce((acc, i) => acc + i, 0);\n\n total += total2 - total1;\n }\n\n resolve(+(1 - idle / total).toFixed(2));\n }, UPDATE_LOAD_INTERVAL);\n });\n};\n\n/** Participant permissions to pass to every agent spun up by this worker. */\nexport class WorkerPermissions {\n canPublish: boolean;\n canSubscribe: boolean;\n canPublishData: boolean;\n canUpdateMetadata: boolean;\n canPublishSources: TrackSource[];\n hidden: boolean;\n\n constructor(\n canPublish = true,\n canSubscribe = true,\n canPublishData = true,\n canUpdateMetadata = true,\n canPublishSources: TrackSource[] = [],\n hidden = false,\n ) {\n this.canPublish = canPublish;\n this.canSubscribe = canSubscribe;\n this.canPublishData = canPublishData;\n this.canUpdateMetadata = canUpdateMetadata;\n this.canPublishSources = canPublishSources;\n this.hidden = hidden;\n }\n}\n\n/**\n * Data class describing worker behaviour.\n *\n * @remarks\n * The Agents framework provides sane worker defaults, and works out-of-the-box with no tweaking\n * necessary. The only mandatory parameter is `agent`, which points to the entry function.\n *\n * This class is mostly useful in conjunction with {@link cli.runApp}.\n */\nexport class WorkerOptions {\n agent: string;\n requestFunc: (job: JobRequest) => Promise<void>;\n loadFunc: () => Promise<number>;\n loadThreshold: number;\n numIdleProcesses: number;\n shutdownProcessTimeout: number;\n initializeProcessTimeout: number;\n permissions: WorkerPermissions;\n agentName: string;\n workerType: JobType;\n maxRetry: number;\n wsURL: string;\n apiKey?: string;\n apiSecret?: string;\n workerToken?: string;\n host: string;\n port: number;\n logLevel: string;\n production: boolean;\n jobMemoryWarnMB: number;\n jobMemoryLimitMB: number;\n\n /** @param options */\n constructor({\n agent,\n requestFunc = defaultRequestFunc,\n loadFunc = defaultCpuLoad,\n loadThreshold = undefined,\n numIdleProcesses = undefined,\n shutdownProcessTimeout = 60 * 1000,\n initializeProcessTimeout = 10 * 1000,\n permissions = new WorkerPermissions(),\n agentName = '',\n workerType = JobType.JT_ROOM,\n maxRetry = MAX_RECONNECT_ATTEMPTS,\n wsURL = 'ws://localhost:7880',\n apiKey = undefined,\n apiSecret = undefined,\n 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?: () => 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 (Object.entries(InferenceRunner.registeredRunners).length) {\n this.#inferenceExecutor = new InferenceProcExecutor({\n runners: InferenceRunner.registeredRunners,\n initializeTimeout: 30000,\n closeTimeout: 5000,\n memoryWarnMB: 2000,\n memoryLimitMB: 0,\n pingInterval: 5000,\n pingTimeout: 60000,\n highPingThreshold: 2500,\n });\n }\n\n this.#procPool = new ProcPool(\n opts.agent,\n opts.numIdleProcesses,\n opts.initializeProcessTimeout,\n opts.shutdownProcessTimeout,\n this.#inferenceExecutor,\n opts.jobMemoryWarnMB,\n opts.jobMemoryLimitMB,\n );\n\n this.#opts = opts;\n this.#httpServer = new HTTPServer(opts.host, opts.port, () => ({\n agent_name: opts.agentName,\n worker_type: JobType[opts.workerType],\n active_jobs: this.activeJobs.length,\n }));\n }\n\n /* @throws {@link WorkerError} if worker failed to connect or already running */\n async run() {\n if (!this.#closed) {\n throw new WorkerError('worker is already running');\n }\n\n if (this.#inferenceExecutor) {\n await this.#inferenceExecutor.start();\n await this.#inferenceExecutor.initialize();\n }\n\n this.#logger.info('starting worker');\n this.#closed = false;\n this.#procPool.start();\n\n const workerWS = async () => {\n let retries = 0;\n this.#connecting = true;\n\n while (!this.#closed) {\n const url = new URL(this.#opts.wsURL);\n url.protocol = url.protocol.replace('http', 'ws');\n const token = new AccessToken(this.#opts.apiKey, this.#opts.apiSecret);\n token.addGrant({ agent: true });\n const jwt = await token.toJwt();\n 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.info('draining worker');\n this.#draining = true;\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'updateWorker',\n value: {\n status: WorkerStatus.WS_FULL,\n },\n },\n }),\n );\n\n const joinJobs = async () => {\n return Promise.all(\n this.#procPool.processes.map((proc) => {\n if (!proc.runningJob) {\n proc.close();\n }\n return proc.join();\n }),\n );\n };\n\n let timer: NodeJS.Timeout | undefined;\n if (timeout) {\n timer = setTimeout(() => {\n throw new WorkerError('timed out draining');\n }, timeout);\n }\n await joinJobs().then(() => {\n if (timeout) {\n clearTimeout(timer);\n }\n });\n }\n\n async simulateJob(roomName: string, participantIdentity?: string) {\n const client = new RoomServiceClient(this.#opts.wsURL, this.#opts.apiKey, this.#opts.apiSecret);\n const room = await client.createRoom({ name: roomName });\n let participant: ParticipantInfo | undefined = undefined;\n if (participantIdentity) {\n try {\n participant = await client.getParticipant(roomName, participantIdentity);\n } catch (e) {\n this.#logger.fatal(\n `participant with identity ${participantIdentity} not found in room ${roomName}`,\n );\n throw e;\n }\n }\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'simulateJob',\n value: {\n type: JobType.JT_PUBLISHER,\n room,\n participant,\n },\n },\n }),\n );\n }\n\n async #runWS(ws: WebSocket) {\n let closingWS = false;\n\n const send = (msg: WorkerMessage) => {\n if (closingWS) {\n this.event.off('worker_msg', send);\n return;\n }\n ws.send(msg.toBinary());\n };\n this.event.on('worker_msg', send);\n\n const close = new Promise<void>((resolve) => {\n ws.addEventListener('close', () => {\n closingWS = true;\n if (!this.#closed) {\n this.#logger.error('worker connection closed unexpectedly');\n }\n resolve();\n });\n });\n\n ws.addEventListener('error', (event) => {\n this.#logger.error('worker error:', event.message);\n });\n\n ws.addEventListener('message', (event) => {\n if (event.type !== 'message') {\n this.#logger.warn('unexpected message type: ' + event.type);\n return;\n }\n\n const msg = new ServerMessage();\n msg.fromBinary(event.data as Uint8Array);\n\n // register is the only valid first message, and it is only valid as the\n // first message\n if (this.#connecting && msg.message.case !== 'register') {\n throw new WorkerError('expected register response as first message');\n }\n\n switch (msg.message.case) {\n case 'register': {\n this.#id = msg.message.value.workerId;\n this.#logger\n .child({ id: this.id, server_info: msg.message.value.serverInfo })\n .info('registered worker');\n this.event.emit(\n 'worker_registered',\n msg.message.value.workerId,\n msg.message.value.serverInfo,\n );\n this.#connecting = false;\n break;\n }\n case 'availability': {\n if (!msg.message.value.job) return;\n const task = this.#availability(msg.message.value);\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n break;\n }\n case 'assignment': {\n if (!msg.message.value.job) return;\n const job = msg.message.value.job;\n if (job.id in this.#pending) {\n const task = this.#pending[job.id];\n delete this.#pending[job.id];\n task?.resolve(msg.message.value);\n } else {\n this.#logger.child({ job }).warn('received assignment for unknown job ' + job.id);\n }\n break;\n }\n case 'termination': {\n const task = this.#termination(msg.message.value);\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n break;\n }\n }\n });\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'register',\n value: {\n type: this.#opts.workerType,\n agentName: this.#opts.agentName,\n allowedPermissions: new ParticipantPermission({\n canPublish: this.#opts.permissions.canPublish,\n canSubscribe: this.#opts.permissions.canSubscribe,\n canPublishData: this.#opts.permissions.canPublishData,\n canUpdateMetadata: this.#opts.permissions.canUpdateMetadata,\n hidden: this.#opts.permissions.hidden,\n agent: true,\n }),\n version,\n },\n },\n }),\n );\n\n let currentStatus = WorkerStatus.WS_AVAILABLE;\n const loadMonitor = setInterval(() => {\n if (closingWS) clearInterval(loadMonitor);\n\n const oldStatus = currentStatus;\n this.#opts.loadFunc().then((currentLoad: number) => {\n const isFull = currentLoad >= this.#opts.loadThreshold;\n const currentlyAvailable = !isFull;\n currentStatus = currentlyAvailable ? WorkerStatus.WS_AVAILABLE : WorkerStatus.WS_FULL;\n\n if (oldStatus != currentStatus) {\n const extra = { load: currentLoad, loadThreshold: this.#opts.loadThreshold };\n if (isFull) {\n this.#logger.child(extra).info('worker is at full capacity, marking as unavailable');\n } else {\n this.#logger.child(extra).info('worker is below capacity, marking as available');\n }\n }\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'updateWorker',\n value: {\n load: currentLoad,\n status: currentStatus,\n },\n },\n }),\n );\n });\n }, UPDATE_LOAD_INTERVAL);\n\n await close;\n ws.removeAllListeners();\n }\n\n async #availability(msg: AvailabilityRequest) {\n let answered = false;\n\n const onReject = async () => {\n answered = true;\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'availability',\n value: {\n jobId: msg.job!.id,\n available: false,\n },\n },\n }),\n );\n };\n\n const onAccept = async (args: JobAcceptArguments) => {\n answered = true;\n\n this.event.emit(\n 'worker_msg',\n new WorkerMessage({\n message: {\n case: 'availability',\n value: {\n jobId: msg.job!.id,\n available: true,\n participantIdentity: args.identity,\n participantName: args.name,\n participantMetadata: args.metadata,\n participantAttributes: args.attributes,\n },\n },\n }),\n );\n\n this.#pending[req.id] = new PendingAssignment();\n const timer = setTimeout(() => {\n this.#logger.child({ req }).warn(`assignment for job ${req.id} timed out`);\n return;\n }, ASSIGNMENT_TIMEOUT);\n const asgn = await this.#pending[req.id]?.promise.then(async (asgn) => {\n clearTimeout(timer);\n return asgn;\n });\n\n if (asgn) {\n await this.#procPool.launchJob({\n acceptArguments: args,\n job: msg.job!,\n url: asgn.url || this.#opts.wsURL,\n token: asgn.token,\n });\n } else {\n this.#logger.child({ requestId: req.id }).warn('pending assignment not found');\n }\n };\n\n const req = new JobRequest(msg.job!, onReject, onAccept);\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('received job request');\n\n const jobRequestTask = async () => {\n try {\n await this.#opts.requestFunc(req);\n } catch (e) {\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('jobRequestFunc failed');\n await onReject();\n }\n\n if (!answered) {\n this.#logger\n .child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })\n .info('no answer was given inside the jobRequestFunc, automatically rejecting the job');\n }\n };\n\n const task = jobRequestTask();\n this.#tasks.push(task);\n task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));\n }\n\n async #termination(msg: JobTermination) {\n const proc = this.#procPool.getByJobId(msg.jobId);\n if (proc === null) {\n // safe to ignore\n return;\n }\n await proc.close();\n }\n\n async close() {\n if (this.#closed) {\n await this.#close.await;\n return;\n }\n\n this.#logger.info('shutting down worker');\n\n this.#closed = true;\n\n await this.#inferenceExecutor?.close();\n await this.#procPool.close();\n await this.#httpServer.close();\n await Promise.allSettled(this.#tasks);\n\n this.#session?.close();\n await this.#close.await;\n }\n}\n"],"mappings":"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","names":["i","asgn"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@livekit/agents",
3
- "version": "0.7.4",
3
+ "version": "0.7.6",
4
4
  "description": "LiveKit Agents - Node.js",
5
5
  "main": "dist/index.js",
6
6
  "require": "dist/index.cjs",
@@ -22,7 +22,7 @@
22
22
  "README.md"
23
23
  ],
24
24
  "devDependencies": {
25
- "@livekit/rtc-node": "^0.13.11",
25
+ "@livekit/rtc-node": "^0.13.12",
26
26
  "@microsoft/api-extractor": "^7.35.0",
27
27
  "@types/node": "^22.5.5",
28
28
  "@types/ws": "^8.5.10",
@@ -41,7 +41,7 @@
41
41
  "zod": "^3.23.8"
42
42
  },
43
43
  "peerDependencies": {
44
- "@livekit/rtc-node": "^0.13.11"
44
+ "@livekit/rtc-node": "^0.13.12"
45
45
  },
46
46
  "scripts": {
47
47
  "build": "tsup --onSuccess \"tsc --declaration --emitDeclarationOnly\"",
package/src/cli.ts CHANGED
@@ -101,6 +101,11 @@ export const runApp = (opts: WorkerOptions) => {
101
101
  'LIVEKIT_API_SECRET',
102
102
  ),
103
103
  )
104
+ .addOption(
105
+ new Option('--worker-token <string>', 'Internal use only')
106
+ .env('LIVEKIT_WORKER_TOKEN')
107
+ .hideHelp(),
108
+ )
104
109
  .action(() => {
105
110
  if (
106
111
  // do not run CLI if origin file is agents/ipc/job_main.js
@@ -120,6 +125,7 @@ export const runApp = (opts: WorkerOptions) => {
120
125
  opts.apiKey = options.apiKey || opts.apiKey;
121
126
  opts.apiSecret = options.apiSecret || opts.apiSecret;
122
127
  opts.logLevel = options.logLevel || opts.logLevel;
128
+ opts.workerToken = options.workerToken || opts.workerToken;
123
129
  runWorker({
124
130
  opts,
125
131
  production: true,
@@ -142,6 +148,7 @@ export const runApp = (opts: WorkerOptions) => {
142
148
  opts.apiKey = options.apiKey || opts.apiKey;
143
149
  opts.apiSecret = options.apiSecret || opts.apiSecret;
144
150
  opts.logLevel = options.logLevel || opts.logLevel;
151
+ opts.workerToken = options.workerToken || opts.workerToken;
145
152
  runWorker({
146
153
  opts,
147
154
  production: false,
@@ -166,6 +173,7 @@ export const runApp = (opts: WorkerOptions) => {
166
173
  opts.apiKey = options.apiKey || opts.apiKey;
167
174
  opts.apiSecret = options.apiSecret || opts.apiSecret;
168
175
  opts.logLevel = options.logLevel || opts.logLevel;
176
+ opts.workerToken = options.workerToken || opts.workerToken;
169
177
  runWorker({
170
178
  opts,
171
179
  production: false,
@@ -16,4 +16,5 @@ export abstract class InferenceRunner {
16
16
 
17
17
  abstract initialize(): Promise<void>;
18
18
  abstract run(data: unknown): Promise<unknown>;
19
+ abstract close(): Promise<void>;
19
20
  }
@@ -86,12 +86,18 @@ const ORPHANED_TIMEOUT = 15 * 1000;
86
86
  break;
87
87
  case 'shutdownRequest':
88
88
  logger.info('inference process received shutdown request');
89
- process.send!({ case: 'done' });
90
89
  clearTimeout(orphanedTimeout);
91
90
  // Remove our message handler to stop processing new messages
92
91
  process.off('message', messageHandler);
93
- // Resolve the future to allow the process to continue to completion
94
- join.resolve();
92
+ Promise.all(Object.values(runners).map((r) => r.close()))
93
+ .then(() => {
94
+ logger.info('Inference runners closed');
95
+ process.send!({ case: 'done' });
96
+ join.resolve();
97
+ })
98
+ .catch((err) => {
99
+ logger.error('Error closing inference runners:', err);
100
+ });
95
101
  break;
96
102
  case 'inferenceRequest':
97
103
  handleInferenceRequest(msg.value);
@@ -222,6 +222,6 @@ const startJob = (
222
222
  await join.await;
223
223
 
224
224
  logger.info('Job process shutdown');
225
- return process.exitCode;
225
+ process.exit(0);
226
226
  }
227
227
  })();
package/src/worker.ts CHANGED
@@ -157,6 +157,7 @@ export class WorkerOptions {
157
157
  wsURL: string;
158
158
  apiKey?: string;
159
159
  apiSecret?: string;
160
+ workerToken?: string;
160
161
  host: string;
161
162
  port: number;
162
163
  logLevel: string;
@@ -180,6 +181,7 @@ export class WorkerOptions {
180
181
  wsURL = 'ws://localhost:7880',
181
182
  apiKey = undefined,
182
183
  apiSecret = undefined,
184
+ workerToken = undefined,
183
185
  host = '0.0.0.0',
184
186
  port = undefined,
185
187
  logLevel = 'info',
@@ -207,6 +209,7 @@ export class WorkerOptions {
207
209
  wsURL?: string;
208
210
  apiKey?: string;
209
211
  apiSecret?: string;
212
+ workerToken?: string;
210
213
  host?: string;
211
214
  port?: number;
212
215
  logLevel?: string;
@@ -231,6 +234,7 @@ export class WorkerOptions {
231
234
  this.wsURL = wsURL;
232
235
  this.apiKey = apiKey;
233
236
  this.apiSecret = apiSecret;
237
+ this.workerToken = workerToken;
234
238
  this.host = host;
235
239
  this.port = port || Default.port(production);
236
240
  this.logLevel = logLevel;
@@ -351,7 +355,11 @@ export class Worker {
351
355
  const token = new AccessToken(this.#opts.apiKey, this.#opts.apiSecret);
352
356
  token.addGrant({ agent: true });
353
357
  const jwt = await token.toJwt();
354
- this.#session = new WebSocket(url + 'agent', {
358
+ const wsUrl = new URL(url + 'agent');
359
+ if (this.#opts.workerToken) {
360
+ wsUrl.searchParams.append('worker_token', this.#opts.workerToken);
361
+ }
362
+ this.#session = new WebSocket(wsUrl, {
355
363
  headers: { authorization: 'Bearer ' + jwt },
356
364
  });
357
365