@livekit/agents 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/dist/index.cjs +2 -5
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +2 -3
  4. package/dist/index.d.ts +2 -3
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +1 -3
  7. package/dist/index.js.map +1 -1
  8. package/dist/ipc/job_proc_lazy_main.cjs +3 -2
  9. package/dist/ipc/job_proc_lazy_main.cjs.map +1 -1
  10. package/dist/ipc/job_proc_lazy_main.js +4 -3
  11. package/dist/ipc/job_proc_lazy_main.js.map +1 -1
  12. package/dist/job.cjs +20 -14
  13. package/dist/job.cjs.map +1 -1
  14. package/dist/job.d.cts +11 -5
  15. package/dist/job.d.ts +11 -5
  16. package/dist/job.d.ts.map +1 -1
  17. package/dist/job.js +17 -12
  18. package/dist/job.js.map +1 -1
  19. package/dist/tokenize/basic/hyphenator.cjs.map +1 -1
  20. package/dist/tokenize/basic/hyphenator.js.map +1 -1
  21. package/dist/utils.cjs +77 -0
  22. package/dist/utils.cjs.map +1 -1
  23. package/dist/utils.d.cts +21 -0
  24. package/dist/utils.d.ts +21 -0
  25. package/dist/utils.d.ts.map +1 -1
  26. package/dist/utils.js +76 -1
  27. package/dist/utils.js.map +1 -1
  28. package/dist/voice/agent_activity.cjs +112 -71
  29. package/dist/voice/agent_activity.cjs.map +1 -1
  30. package/dist/voice/agent_activity.d.ts.map +1 -1
  31. package/dist/voice/agent_activity.js +112 -71
  32. package/dist/voice/agent_activity.js.map +1 -1
  33. package/dist/voice/agent_session.cjs +9 -2
  34. package/dist/voice/agent_session.cjs.map +1 -1
  35. package/dist/voice/agent_session.d.ts.map +1 -1
  36. package/dist/voice/agent_session.js +9 -2
  37. package/dist/voice/agent_session.js.map +1 -1
  38. package/dist/voice/avatar/datastream_io.cjs +204 -0
  39. package/dist/voice/avatar/datastream_io.cjs.map +1 -0
  40. package/dist/voice/avatar/datastream_io.d.cts +37 -0
  41. package/dist/voice/avatar/datastream_io.d.ts +37 -0
  42. package/dist/voice/avatar/datastream_io.d.ts.map +1 -0
  43. package/dist/voice/avatar/datastream_io.js +188 -0
  44. package/dist/voice/avatar/datastream_io.js.map +1 -0
  45. package/dist/{multimodal → voice/avatar}/index.cjs +4 -4
  46. package/dist/voice/avatar/index.cjs.map +1 -0
  47. package/dist/voice/avatar/index.d.cts +2 -0
  48. package/dist/voice/avatar/index.d.ts +2 -0
  49. package/dist/voice/avatar/index.d.ts.map +1 -0
  50. package/dist/voice/avatar/index.js +2 -0
  51. package/dist/voice/avatar/index.js.map +1 -0
  52. package/dist/voice/index.cjs +2 -0
  53. package/dist/voice/index.cjs.map +1 -1
  54. package/dist/voice/index.d.cts +1 -0
  55. package/dist/voice/index.d.ts +1 -0
  56. package/dist/voice/index.d.ts.map +1 -1
  57. package/dist/voice/index.js +1 -0
  58. package/dist/voice/index.js.map +1 -1
  59. package/dist/voice/io.cjs.map +1 -1
  60. package/dist/voice/io.d.cts +1 -1
  61. package/dist/voice/io.d.ts +1 -1
  62. package/dist/voice/io.d.ts.map +1 -1
  63. package/dist/voice/io.js.map +1 -1
  64. package/dist/voice/room_io/_input.cjs +2 -1
  65. package/dist/voice/room_io/_input.cjs.map +1 -1
  66. package/dist/voice/room_io/_input.d.ts.map +1 -1
  67. package/dist/voice/room_io/_input.js +2 -1
  68. package/dist/voice/room_io/_input.js.map +1 -1
  69. package/dist/voice/run_context.cjs +13 -0
  70. package/dist/voice/run_context.cjs.map +1 -1
  71. package/dist/voice/run_context.d.cts +10 -0
  72. package/dist/voice/run_context.d.ts +10 -0
  73. package/dist/voice/run_context.d.ts.map +1 -1
  74. package/dist/voice/run_context.js +13 -0
  75. package/dist/voice/run_context.js.map +1 -1
  76. package/dist/voice/speech_handle.cjs +152 -30
  77. package/dist/voice/speech_handle.cjs.map +1 -1
  78. package/dist/voice/speech_handle.d.cts +67 -16
  79. package/dist/voice/speech_handle.d.ts +67 -16
  80. package/dist/voice/speech_handle.d.ts.map +1 -1
  81. package/dist/voice/speech_handle.js +153 -31
  82. package/dist/voice/speech_handle.js.map +1 -1
  83. package/dist/worker.cjs +4 -1
  84. package/dist/worker.cjs.map +1 -1
  85. package/dist/worker.d.ts.map +1 -1
  86. package/dist/worker.js +4 -1
  87. package/dist/worker.js.map +1 -1
  88. package/package.json +2 -2
  89. package/src/index.ts +2 -3
  90. package/src/ipc/job_proc_lazy_main.ts +6 -3
  91. package/src/job.ts +27 -12
  92. package/src/tokenize/basic/hyphenator.ts +1 -1
  93. package/src/utils.ts +121 -1
  94. package/src/voice/agent_activity.ts +128 -78
  95. package/src/voice/agent_session.ts +11 -2
  96. package/src/voice/avatar/datastream_io.ts +247 -0
  97. package/src/voice/avatar/index.ts +4 -0
  98. package/src/voice/index.ts +2 -0
  99. package/src/voice/io.ts +1 -1
  100. package/src/voice/room_io/_input.ts +8 -3
  101. package/src/voice/run_context.ts +16 -2
  102. package/src/voice/speech_handle.ts +183 -38
  103. package/src/worker.ts +5 -1
  104. package/dist/multimodal/agent_playout.cjs +0 -233
  105. package/dist/multimodal/agent_playout.cjs.map +0 -1
  106. package/dist/multimodal/agent_playout.d.cts +0 -34
  107. package/dist/multimodal/agent_playout.d.ts +0 -34
  108. package/dist/multimodal/agent_playout.d.ts.map +0 -1
  109. package/dist/multimodal/agent_playout.js +0 -207
  110. package/dist/multimodal/agent_playout.js.map +0 -1
  111. package/dist/multimodal/index.cjs.map +0 -1
  112. package/dist/multimodal/index.d.cts +0 -2
  113. package/dist/multimodal/index.d.ts +0 -2
  114. package/dist/multimodal/index.d.ts.map +0 -1
  115. package/dist/multimodal/index.js +0 -2
  116. package/dist/multimodal/index.js.map +0 -1
  117. package/src/multimodal/agent_playout.ts +0 -266
  118. package/src/multimodal/index.ts +0 -4
package/dist/index.cjs CHANGED
@@ -33,7 +33,6 @@ __export(index_exports, {
33
33
  ipc: () => ipc,
34
34
  llm: () => llm,
35
35
  metrics: () => metrics,
36
- multimodal: () => multimodal,
37
36
  stream: () => stream,
38
37
  stt: () => stt,
39
38
  tokenize: () => tokenize,
@@ -45,14 +44,13 @@ var cli = __toESM(require("./cli.cjs"), 1);
45
44
  var ipc = __toESM(require("./ipc/index.cjs"), 1);
46
45
  var llm = __toESM(require("./llm/index.cjs"), 1);
47
46
  var metrics = __toESM(require("./metrics/index.cjs"), 1);
48
- var multimodal = __toESM(require("./multimodal/index.cjs"), 1);
49
47
  var stream = __toESM(require("./stream/index.cjs"), 1);
50
48
  var stt = __toESM(require("./stt/index.cjs"), 1);
51
49
  var tokenize = __toESM(require("./tokenize/index.cjs"), 1);
52
50
  var tts = __toESM(require("./tts/index.cjs"), 1);
53
51
  var voice = __toESM(require("./voice/index.cjs"), 1);
54
- __reExport(index_exports, require("./audio.cjs"), module.exports);
55
52
  __reExport(index_exports, require("./_exceptions.cjs"), module.exports);
53
+ __reExport(index_exports, require("./audio.cjs"), module.exports);
56
54
  __reExport(index_exports, require("./generator.cjs"), module.exports);
57
55
  __reExport(index_exports, require("./inference_runner.cjs"), module.exports);
58
56
  __reExport(index_exports, require("./job.cjs"), module.exports);
@@ -70,14 +68,13 @@ __reExport(index_exports, require("./worker.cjs"), module.exports);
70
68
  ipc,
71
69
  llm,
72
70
  metrics,
73
- multimodal,
74
71
  stream,
75
72
  stt,
76
73
  tokenize,
77
74
  tts,
78
75
  voice,
79
- ...require("./audio.cjs"),
80
76
  ...require("./_exceptions.cjs"),
77
+ ...require("./audio.cjs"),
81
78
  ...require("./generator.cjs"),
82
79
  ...require("./inference_runner.cjs"),
83
80
  ...require("./job.cjs"),
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * LiveKit Agents is a framework for building realtime programmable participants that run on\n * servers.\n *\n * @see {@link https://docs.livekit.io/agents/overview | LiveKit Agents documentation}\n * @packageDocumentation\n */\nimport * as cli from './cli.js';\nimport * as ipc from './ipc/index.js';\nimport * as llm from './llm/index.js';\nimport * as metrics from './metrics/index.js';\nimport * as multimodal from './multimodal/index.js';\nimport * as stream from './stream/index.js';\nimport * as stt from './stt/index.js';\nimport * as tokenize from './tokenize/index.js';\nimport * as tts from './tts/index.js';\nimport * as voice from './voice/index.js';\n\nexport * from './audio.js';\nexport * from './_exceptions.js';\nexport * from './generator.js';\nexport * from './inference_runner.js';\nexport * from './job.js';\nexport * from './log.js';\nexport * from './plugin.js';\nexport * from './transcription.js';\nexport * from './types.js';\nexport * from './utils.js';\nexport * from './vad.js';\nexport * from './version.js';\nexport * from './worker.js';\n\nexport { cli, ipc, llm, metrics, multimodal, stream, stt, tokenize, tts, voice };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA,UAAqB;AACrB,UAAqB;AACrB,UAAqB;AACrB,cAAyB;AACzB,iBAA4B;AAC5B,aAAwB;AACxB,UAAqB;AACrB,eAA0B;AAC1B,UAAqB;AACrB,YAAuB;AAEvB,0BAAc,uBAtBd;AAuBA,0BAAc,6BAvBd;AAwBA,0BAAc,2BAxBd;AAyBA,0BAAc,kCAzBd;AA0BA,0BAAc,qBA1Bd;AA2BA,0BAAc,qBA3Bd;AA4BA,0BAAc,wBA5Bd;AA6BA,0BAAc,+BA7Bd;AA8BA,0BAAc,uBA9Bd;AA+BA,0BAAc,uBA/Bd;AAgCA,0BAAc,qBAhCd;AAiCA,0BAAc,yBAjCd;AAkCA,0BAAc,wBAlCd;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * LiveKit Agents is a framework for building realtime programmable participants that run on\n * servers.\n *\n * @see {@link https://docs.livekit.io/agents/overview | LiveKit Agents documentation}\n * @packageDocumentation\n */\nimport * as cli from './cli.js';\nimport * as ipc from './ipc/index.js';\nimport * as llm from './llm/index.js';\nimport * as metrics from './metrics/index.js';\nimport * as stream from './stream/index.js';\nimport * as stt from './stt/index.js';\nimport * as tokenize from './tokenize/index.js';\nimport * as tts from './tts/index.js';\nimport * as voice from './voice/index.js';\n\nexport * from './_exceptions.js';\nexport * from './audio.js';\nexport * from './generator.js';\nexport * from './inference_runner.js';\nexport * from './job.js';\nexport * from './log.js';\nexport * from './plugin.js';\nexport * from './transcription.js';\nexport * from './types.js';\nexport * from './utils.js';\nexport * from './vad.js';\nexport * from './version.js';\nexport * from './worker.js';\n\nexport { cli, ipc, llm, metrics, stream, stt, tokenize, tts, voice };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA,UAAqB;AACrB,UAAqB;AACrB,UAAqB;AACrB,cAAyB;AACzB,aAAwB;AACxB,UAAqB;AACrB,eAA0B;AAC1B,UAAqB;AACrB,YAAuB;AAEvB,0BAAc,6BArBd;AAsBA,0BAAc,uBAtBd;AAuBA,0BAAc,2BAvBd;AAwBA,0BAAc,kCAxBd;AAyBA,0BAAc,qBAzBd;AA0BA,0BAAc,qBA1Bd;AA2BA,0BAAc,wBA3Bd;AA4BA,0BAAc,+BA5Bd;AA6BA,0BAAc,uBA7Bd;AA8BA,0BAAc,uBA9Bd;AA+BA,0BAAc,qBA/Bd;AAgCA,0BAAc,yBAhCd;AAiCA,0BAAc,wBAjCd;","names":[]}
package/dist/index.d.cts CHANGED
@@ -9,14 +9,13 @@ import * as cli from './cli.js';
9
9
  import * as ipc from './ipc/index.js';
10
10
  import * as llm from './llm/index.js';
11
11
  import * as metrics from './metrics/index.js';
12
- import * as multimodal from './multimodal/index.js';
13
12
  import * as stream from './stream/index.js';
14
13
  import * as stt from './stt/index.js';
15
14
  import * as tokenize from './tokenize/index.js';
16
15
  import * as tts from './tts/index.js';
17
16
  import * as voice from './voice/index.js';
18
- export * from './audio.js';
19
17
  export * from './_exceptions.js';
18
+ export * from './audio.js';
20
19
  export * from './generator.js';
21
20
  export * from './inference_runner.js';
22
21
  export * from './job.js';
@@ -28,5 +27,5 @@ export * from './utils.js';
28
27
  export * from './vad.js';
29
28
  export * from './version.js';
30
29
  export * from './worker.js';
31
- export { cli, ipc, llm, metrics, multimodal, stream, stt, tokenize, tts, voice };
30
+ export { cli, ipc, llm, metrics, stream, stt, tokenize, tts, voice };
32
31
  //# sourceMappingURL=index.d.ts.map
package/dist/index.d.ts CHANGED
@@ -9,14 +9,13 @@ import * as cli from './cli.js';
9
9
  import * as ipc from './ipc/index.js';
10
10
  import * as llm from './llm/index.js';
11
11
  import * as metrics from './metrics/index.js';
12
- import * as multimodal from './multimodal/index.js';
13
12
  import * as stream from './stream/index.js';
14
13
  import * as stt from './stt/index.js';
15
14
  import * as tokenize from './tokenize/index.js';
16
15
  import * as tts from './tts/index.js';
17
16
  import * as voice from './voice/index.js';
18
- export * from './audio.js';
19
17
  export * from './_exceptions.js';
18
+ export * from './audio.js';
20
19
  export * from './generator.js';
21
20
  export * from './inference_runner.js';
22
21
  export * from './job.js';
@@ -28,5 +27,5 @@ export * from './utils.js';
28
27
  export * from './vad.js';
29
28
  export * from './version.js';
30
29
  export * from './worker.js';
31
- export { cli, ipc, llm, metrics, multimodal, stream, stt, tokenize, tts, voice };
30
+ export { cli, ipc, llm, metrics, stream, stt, tokenize, tts, voice };
32
31
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAE1C,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAE5B,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAE1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAE5B,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC"}
package/dist/index.js CHANGED
@@ -2,14 +2,13 @@ import * as cli from "./cli.js";
2
2
  import * as ipc from "./ipc/index.js";
3
3
  import * as llm from "./llm/index.js";
4
4
  import * as metrics from "./metrics/index.js";
5
- import * as multimodal from "./multimodal/index.js";
6
5
  import * as stream from "./stream/index.js";
7
6
  import * as stt from "./stt/index.js";
8
7
  import * as tokenize from "./tokenize/index.js";
9
8
  import * as tts from "./tts/index.js";
10
9
  import * as voice from "./voice/index.js";
11
- export * from "./audio.js";
12
10
  export * from "./_exceptions.js";
11
+ export * from "./audio.js";
13
12
  export * from "./generator.js";
14
13
  export * from "./inference_runner.js";
15
14
  export * from "./job.js";
@@ -26,7 +25,6 @@ export {
26
25
  ipc,
27
26
  llm,
28
27
  metrics,
29
- multimodal,
30
28
  stream,
31
29
  stt,
32
30
  tokenize,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * LiveKit Agents is a framework for building realtime programmable participants that run on\n * servers.\n *\n * @see {@link https://docs.livekit.io/agents/overview | LiveKit Agents documentation}\n * @packageDocumentation\n */\nimport * as cli from './cli.js';\nimport * as ipc from './ipc/index.js';\nimport * as llm from './llm/index.js';\nimport * as metrics from './metrics/index.js';\nimport * as multimodal from './multimodal/index.js';\nimport * as stream from './stream/index.js';\nimport * as stt from './stt/index.js';\nimport * as tokenize from './tokenize/index.js';\nimport * as tts from './tts/index.js';\nimport * as voice from './voice/index.js';\n\nexport * from './audio.js';\nexport * from './_exceptions.js';\nexport * from './generator.js';\nexport * from './inference_runner.js';\nexport * from './job.js';\nexport * from './log.js';\nexport * from './plugin.js';\nexport * from './transcription.js';\nexport * from './types.js';\nexport * from './utils.js';\nexport * from './vad.js';\nexport * from './version.js';\nexport * from './worker.js';\n\nexport { cli, ipc, llm, metrics, multimodal, stream, stt, tokenize, tts, voice };\n"],"mappings":"AAWA,YAAY,SAAS;AACrB,YAAY,SAAS;AACrB,YAAY,SAAS;AACrB,YAAY,aAAa;AACzB,YAAY,gBAAgB;AAC5B,YAAY,YAAY;AACxB,YAAY,SAAS;AACrB,YAAY,cAAc;AAC1B,YAAY,SAAS;AACrB,YAAY,WAAW;AAEvB,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * LiveKit Agents is a framework for building realtime programmable participants that run on\n * servers.\n *\n * @see {@link https://docs.livekit.io/agents/overview | LiveKit Agents documentation}\n * @packageDocumentation\n */\nimport * as cli from './cli.js';\nimport * as ipc from './ipc/index.js';\nimport * as llm from './llm/index.js';\nimport * as metrics from './metrics/index.js';\nimport * as stream from './stream/index.js';\nimport * as stt from './stt/index.js';\nimport * as tokenize from './tokenize/index.js';\nimport * as tts from './tts/index.js';\nimport * as voice from './voice/index.js';\n\nexport * from './_exceptions.js';\nexport * from './audio.js';\nexport * from './generator.js';\nexport * from './inference_runner.js';\nexport * from './job.js';\nexport * from './log.js';\nexport * from './plugin.js';\nexport * from './transcription.js';\nexport * from './types.js';\nexport * from './utils.js';\nexport * from './vad.js';\nexport * from './version.js';\nexport * from './worker.js';\n\nexport { cli, ipc, llm, metrics, stream, stt, tokenize, tts, voice };\n"],"mappings":"AAWA,YAAY,SAAS;AACrB,YAAY,SAAS;AACrB,YAAY,SAAS;AACrB,YAAY,aAAa;AACzB,YAAY,YAAY;AACxB,YAAY,SAAS;AACrB,YAAY,cAAc;AAC1B,YAAY,SAAS;AACrB,YAAY,WAAW;AAEvB,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
@@ -61,7 +61,6 @@ const startJob = (proc, func, info, closeEvent, logger, joinFuture) => {
61
61
  closeEvent.emit("close", true, reason);
62
62
  };
63
63
  const ctx = new import_job.JobContext(proc, info, room, onConnect, onShutdown, new InfClient());
64
- new import_job.CurrentJobContext(ctx);
65
64
  const task = new Promise(async () => {
66
65
  const unconnectedTimeout = setTimeout(() => {
67
66
  if (!(connect || shutdown)) {
@@ -71,7 +70,9 @@ const startJob = (proc, func, info, closeEvent, logger, joinFuture) => {
71
70
  );
72
71
  }
73
72
  }, 1e4);
74
- func(ctx).finally(() => clearTimeout(unconnectedTimeout));
73
+ await (0, import_job.runWithJobContextAsync)(ctx, () => func(ctx)).finally(() => {
74
+ clearTimeout(unconnectedTimeout);
75
+ });
75
76
  await (0, import_node_events.once)(closeEvent, "close").then((close) => {
76
77
  logger.debug("shutting down");
77
78
  shutdown = true;
@@ -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 { 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, shortuuid } 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 = shortuuid('inference_job_');\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 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.debug('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.debug('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.debug('Job process shutdown');\n process.exit(0);\n }\n})();\n"],"mappings":";AAGA,sBAAgC;AAChC,yBAAmC;AACnC,sBAA8B;AAE9B,uBAAoC;AACpC,iBAA+E;AAC/E,iBAAsC;AACtC,mBAAkC;AAClC,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,gBAAY,wBAAU,gBAAgB;AAC5C,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,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,MAAM,6BAA6B;AAAA,IAC5C,CAAC;AAID,YAAQ,GAAG,WAAW,MAAM;AAC1B,aAAO,MAAM,8BAA8B;AAAA,IAC7C,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,MAAM,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,GAAG;","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 { EventEmitter, once } from 'node:events';\nimport { pathToFileURL } from 'node:url';\nimport type { Logger } from 'pino';\nimport { type Agent, isAgent } from '../generator.js';\nimport { JobContext, JobProcess, type RunningJobInfo, runWithJobContextAsync } from '../job.js';\nimport { initializeLogger, log } from '../log.js';\nimport { Future, shortuuid } 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 = shortuuid('inference_job_');\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\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\n // Run the job function within the AsyncLocalStorage context\n await runWithJobContextAsync(ctx, () => func(ctx)).finally(() => {\n clearTimeout(unconnectedTimeout);\n });\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 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.debug('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.debug('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.debug('Job process shutdown');\n process.exit(0);\n }\n})();\n"],"mappings":"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","names":["module","agent"]}
@@ -2,7 +2,7 @@ import { Room, RoomEvent } from "@livekit/rtc-node";
2
2
  import { EventEmitter, once } from "node:events";
3
3
  import { pathToFileURL } from "node:url";
4
4
  import { isAgent } from "../generator.js";
5
- import { CurrentJobContext, JobContext, JobProcess } from "../job.js";
5
+ import { JobContext, JobProcess, runWithJobContextAsync } from "../job.js";
6
6
  import { initializeLogger, log } from "../log.js";
7
7
  import { Future, shortuuid } from "../utils.js";
8
8
  import { defaultInitializeProcessFunc } from "../worker.js";
@@ -60,7 +60,6 @@ const startJob = (proc, func, info, closeEvent, logger, joinFuture) => {
60
60
  closeEvent.emit("close", true, reason);
61
61
  };
62
62
  const ctx = new JobContext(proc, info, room, onConnect, onShutdown, new InfClient());
63
- new CurrentJobContext(ctx);
64
63
  const task = new Promise(async () => {
65
64
  const unconnectedTimeout = setTimeout(() => {
66
65
  if (!(connect || shutdown)) {
@@ -70,7 +69,9 @@ const startJob = (proc, func, info, closeEvent, logger, joinFuture) => {
70
69
  );
71
70
  }
72
71
  }, 1e4);
73
- func(ctx).finally(() => clearTimeout(unconnectedTimeout));
72
+ await runWithJobContextAsync(ctx, () => func(ctx)).finally(() => {
73
+ clearTimeout(unconnectedTimeout);
74
+ });
74
75
  await once(closeEvent, "close").then((close) => {
75
76
  logger.debug("shutting down");
76
77
  shutdown = true;
@@ -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 { 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, shortuuid } 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 = shortuuid('inference_job_');\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 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.debug('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.debug('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.debug('Job process shutdown');\n process.exit(0);\n }\n})();\n"],"mappings":"AAGA,SAAS,MAAM,iBAAiB;AAChC,SAAS,cAAc,YAAY;AACnC,SAAS,qBAAqB;AAE9B,SAAqB,eAAe;AACpC,SAAS,mBAAmB,YAAY,kBAAuC;AAC/E,SAAS,kBAAkB,WAAW;AACtC,SAAS,QAAQ,iBAAiB;AAClC,SAAS,oCAAoC;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,gBAAI,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,UAAU,gBAAgB;AAC5C,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,KAAK;AACtB,OAAK,GAAG,UAAU,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,WAAW,MAAM,MAAM,MAAM,WAAW,YAAY,IAAI,UAAU,CAAC;AACnF,MAAI,kBAAkB,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,UAAM,KAAK,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,eAAW,QAAQ;AAAA,EACrB,CAAC;AAED,SAAO,EAAE,KAAK,KAAK;AACrB;AAAA,CAEC,YAAY;AACX,MAAI,QAAQ,MAAM;AAChB,UAAM,OAAO,IAAI,OAAO;AAMxB,UAAM,aAAa,QAAQ,KAAK,CAAC;AACjC,UAAM,QAAe,MAAM,OAAO,cAAc,UAAW,EAAE,UAAU,KAAK,CAAC,WAAW;AACtF,YAAMA,SAAQ,OAAO;AACrB,UAAIA,WAAU,UAAa,CAAC,QAAQA,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,MAAM,6BAA6B;AAAA,IAC5C,CAAC;AAID,YAAQ,GAAG,WAAW,MAAM;AAC1B,aAAO,MAAM,8BAA8B;AAAA,IAC7C,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,OAAO,IAAI,WAAW;AAC5B,QAAI,SAAS,IAAI,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,aAAa;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,MAAM,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,GAAG;","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 { EventEmitter, once } from 'node:events';\nimport { pathToFileURL } from 'node:url';\nimport type { Logger } from 'pino';\nimport { type Agent, isAgent } from '../generator.js';\nimport { JobContext, JobProcess, type RunningJobInfo, runWithJobContextAsync } from '../job.js';\nimport { initializeLogger, log } from '../log.js';\nimport { Future, shortuuid } 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 = shortuuid('inference_job_');\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\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\n // Run the job function within the AsyncLocalStorage context\n await runWithJobContextAsync(ctx, () => func(ctx)).finally(() => {\n clearTimeout(unconnectedTimeout);\n });\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 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.debug('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.debug('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.debug('Job process shutdown');\n process.exit(0);\n }\n})();\n"],"mappings":"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","names":["agent"]}
package/dist/job.cjs CHANGED
@@ -19,32 +19,32 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  var job_exports = {};
20
20
  __export(job_exports, {
21
21
  AutoSubscribe: () => AutoSubscribe,
22
- CurrentJobContext: () => CurrentJobContext,
23
22
  FunctionExistsError: () => FunctionExistsError,
24
23
  JobContext: () => JobContext,
25
24
  JobProcess: () => JobProcess,
26
25
  JobRequest: () => JobRequest,
27
- getJobContext: () => getJobContext
26
+ getJobContext: () => getJobContext,
27
+ runWithJobContext: () => runWithJobContext,
28
+ runWithJobContextAsync: () => runWithJobContextAsync
28
29
  });
29
30
  module.exports = __toCommonJS(job_exports);
30
31
  var import_rtc_node = require("@livekit/rtc-node");
32
+ var import_node_async_hooks = require("node:async_hooks");
31
33
  var import_log = require("./log.cjs");
32
- class CurrentJobContext {
33
- static #current;
34
- constructor(proc) {
35
- CurrentJobContext.#current = proc;
36
- }
37
- static getCurrent() {
38
- return CurrentJobContext.#current;
39
- }
40
- }
34
+ const jobContextStorage = new import_node_async_hooks.AsyncLocalStorage();
41
35
  function getJobContext() {
42
- const ctx = CurrentJobContext.getCurrent();
36
+ const ctx = jobContextStorage.getStore();
43
37
  if (!ctx) {
44
38
  throw new Error("no job context found, are you running this code inside a job entrypoint?");
45
39
  }
46
40
  return ctx;
47
41
  }
42
+ function runWithJobContext(context, fn) {
43
+ return jobContextStorage.run(context, fn);
44
+ }
45
+ function runWithJobContextAsync(context, fn) {
46
+ return jobContextStorage.run(context, fn);
47
+ }
48
48
  var AutoSubscribe = /* @__PURE__ */ ((AutoSubscribe2) => {
49
49
  AutoSubscribe2[AutoSubscribe2["SUBSCRIBE_ALL"] = 0] = "SUBSCRIBE_ALL";
50
50
  AutoSubscribe2[AutoSubscribe2["SUBSCRIBE_NONE"] = 1] = "SUBSCRIBE_NONE";
@@ -70,6 +70,7 @@ class JobContext {
70
70
  #participantTasks = {};
71
71
  #logger;
72
72
  #inferenceExecutor;
73
+ connected = false;
73
74
  constructor(proc, info, room, onConnect, onShutdown, inferenceExecutor) {
74
75
  this.#proc = proc;
75
76
  this.#info = info;
@@ -145,6 +146,9 @@ class JobContext {
145
146
  * @livekit/rtc-node} for more information about the parameters.
146
147
  */
147
148
  async connect(e2ee, autoSubscribe = 0 /* SUBSCRIBE_ALL */, rtcConfig) {
149
+ if (this.connected) {
150
+ return;
151
+ }
148
152
  const opts = {
149
153
  e2ee,
150
154
  autoSubscribe: autoSubscribe == 0 /* SUBSCRIBE_ALL */,
@@ -163,6 +167,7 @@ class JobContext {
163
167
  });
164
168
  });
165
169
  }
170
+ this.connected = true;
166
171
  }
167
172
  /**
168
173
  * Gracefully shuts down the job, and runs all shutdown promises.
@@ -249,11 +254,12 @@ class JobRequest {
249
254
  // Annotate the CommonJS export names for ESM import in node:
250
255
  0 && (module.exports = {
251
256
  AutoSubscribe,
252
- CurrentJobContext,
253
257
  FunctionExistsError,
254
258
  JobContext,
255
259
  JobProcess,
256
260
  JobRequest,
257
- getJobContext
261
+ getJobContext,
262
+ runWithJobContext,
263
+ runWithJobContextAsync
258
264
  });
259
265
  //# sourceMappingURL=job.cjs.map
package/dist/job.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/job.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type * as proto from '@livekit/protocol';\nimport type {\n E2EEOptions,\n LocalParticipant,\n RemoteParticipant,\n Room,\n RtcConfiguration,\n} from '@livekit/rtc-node';\nimport { ParticipantKind, RoomEvent, TrackKind } from '@livekit/rtc-node';\nimport type { Logger } from 'pino';\nimport type { InferenceExecutor } from './ipc/inference_executor.js';\nimport { log } from './log.js';\n\nexport class CurrentJobContext {\n static #current: JobContext;\n\n constructor(proc: JobContext) {\n CurrentJobContext.#current = proc;\n }\n\n static getCurrent(): JobContext {\n return CurrentJobContext.#current;\n }\n}\n\n/**\n * Returns the current job context.\n *\n * @throws {Error} if no job context is found\n */\nexport function getJobContext(): JobContext {\n const ctx = CurrentJobContext.getCurrent();\n if (!ctx) {\n throw new Error('no job context found, are you running this code inside a job entrypoint?');\n }\n return ctx;\n}\n\n/** Which tracks, if any, should the agent automatically subscribe to? */\nexport enum AutoSubscribe {\n SUBSCRIBE_ALL,\n SUBSCRIBE_NONE,\n VIDEO_ONLY,\n AUDIO_ONLY,\n}\n\nexport type JobAcceptArguments = {\n name: string;\n identity: string;\n metadata: string;\n attributes?: { [key: string]: string };\n};\n\nexport type RunningJobInfo = {\n acceptArguments: JobAcceptArguments;\n job: proto.Job;\n url: string;\n token: string;\n workerId: string;\n};\n\n/** Attempted to add a function callback, but the function already exists. */\nexport class FunctionExistsError extends Error {\n constructor(msg?: string) {\n super(msg);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** The job and environment context as seen by the agent, accessible by the entrypoint function. */\nexport class JobContext {\n #proc: JobProcess;\n #info: RunningJobInfo;\n #room: Room;\n #onConnect: () => void;\n #onShutdown: (s: string) => void;\n /** @internal */\n shutdownCallbacks: (() => Promise<void>)[] = [];\n #participantEntrypoints: ((job: JobContext, p: RemoteParticipant) => Promise<void>)[] = [];\n #participantTasks: {\n [id: string]: {\n callback: (job: JobContext, p: RemoteParticipant) => Promise<void>;\n result: Promise<void>;\n };\n } = {};\n #logger: Logger;\n #inferenceExecutor: InferenceExecutor;\n\n constructor(\n proc: JobProcess,\n info: RunningJobInfo,\n room: Room,\n onConnect: () => void,\n onShutdown: (s: string) => void,\n inferenceExecutor: InferenceExecutor,\n ) {\n this.#proc = proc;\n this.#info = info;\n this.#room = room;\n this.#onConnect = onConnect;\n this.#onShutdown = onShutdown;\n this.onParticipantConnected = this.onParticipantConnected.bind(this);\n this.#room.on(RoomEvent.ParticipantConnected, this.onParticipantConnected);\n this.#logger = log().child({ info: this.#info });\n this.#inferenceExecutor = inferenceExecutor;\n }\n\n get proc(): JobProcess {\n return this.#proc;\n }\n\n get job(): proto.Job {\n return this.#info.job;\n }\n\n get workerId(): string {\n return this.#info.workerId;\n }\n\n /** @returns The room the agent was called into */\n get room(): Room {\n return this.#room;\n }\n\n /** @returns The agent's participant if connected to the room, otherwise `undefined` */\n get agent(): LocalParticipant | undefined {\n return this.#room.localParticipant;\n }\n\n /** @returns The global inference executor */\n get inferenceExecutor(): InferenceExecutor {\n return this.#inferenceExecutor;\n }\n\n /** Adds a promise to be awaited when {@link JobContext.shutdown | shutdown} is called. */\n addShutdownCallback(callback: () => Promise<void>) {\n this.shutdownCallbacks.push(callback);\n }\n\n async waitForParticipant(identity?: string): Promise<RemoteParticipant> {\n if (!this.#room.isConnected) {\n throw new Error('room is not connected');\n }\n\n for (const p of this.#room.remoteParticipants.values()) {\n if ((!identity || p.identity === identity) && p.info.kind != ParticipantKind.AGENT) {\n return p;\n }\n }\n\n return new Promise((resolve, reject) => {\n const onParticipantConnected = (participant: RemoteParticipant) => {\n if (\n (!identity || participant.identity === identity) &&\n participant.info.kind != ParticipantKind.AGENT\n ) {\n clearHandlers();\n resolve(participant);\n }\n };\n const onDisconnected = () => {\n clearHandlers();\n reject(new Error('Room disconnected while waiting for participant'));\n };\n\n const clearHandlers = () => {\n this.#room.off(RoomEvent.ParticipantConnected, onParticipantConnected);\n this.#room.off(RoomEvent.Disconnected, onDisconnected);\n };\n\n this.#room.on(RoomEvent.ParticipantConnected, onParticipantConnected);\n this.#room.on(RoomEvent.Disconnected, onDisconnected);\n });\n }\n\n /**\n * Connects the agent to the room.\n *\n * @remarks\n * It is recommended to run this command as early in the function as possible, as executing it\n * later may cause noticeable delay between user and agent joins.\n *\n * @see {@link https://github.com/livekit/node-sdks/tree/main/packages/livekit-rtc#readme |\n * @livekit/rtc-node} for more information about the parameters.\n */\n async connect(\n e2ee?: E2EEOptions,\n autoSubscribe: AutoSubscribe = AutoSubscribe.SUBSCRIBE_ALL,\n rtcConfig?: RtcConfiguration,\n ) {\n const opts = {\n e2ee,\n autoSubscribe: autoSubscribe == AutoSubscribe.SUBSCRIBE_ALL,\n rtcConfig,\n dynacast: false,\n };\n\n await this.#room.connect(this.#info.url, this.#info.token, opts);\n this.#onConnect();\n\n this.#room.remoteParticipants.forEach(this.onParticipantConnected);\n\n if ([AutoSubscribe.AUDIO_ONLY, AutoSubscribe.VIDEO_ONLY].includes(autoSubscribe)) {\n this.#room.remoteParticipants.forEach((p) => {\n p.trackPublications.forEach((pub) => {\n if (\n (autoSubscribe === AutoSubscribe.AUDIO_ONLY && pub.kind === TrackKind.KIND_AUDIO) ||\n (autoSubscribe === AutoSubscribe.VIDEO_ONLY && pub.kind === TrackKind.KIND_VIDEO)\n ) {\n pub.setSubscribed(true);\n }\n });\n });\n }\n }\n\n /**\n * Gracefully shuts down the job, and runs all shutdown promises.\n *\n * @param reason - Optional reason for shutdown\n */\n shutdown(reason = '') {\n this.#onShutdown(reason);\n }\n\n /** @internal */\n onParticipantConnected(p: RemoteParticipant) {\n for (const callback of this.#participantEntrypoints) {\n if (this.#participantTasks[p.identity!]?.callback == callback) {\n this.#logger.warn(\n 'a participant has joined before a prior prticipant task matching the same identity has finished:',\n p.identity,\n );\n }\n const result = callback(this, p);\n result.finally(() => delete this.#participantTasks[p.identity!]);\n this.#participantTasks[p.identity!] = { callback, result };\n }\n }\n\n /**\n * Adds a promise to be awaited whenever a new participant joins the room.\n *\n * @throws {@link FunctionExistsError} if an entrypoint already exists\n */\n addParticipantEntrypoint(callback: (job: JobContext, p: RemoteParticipant) => Promise<void>) {\n if (this.#participantEntrypoints.includes(callback)) {\n throw new FunctionExistsError('entrypoints cannot be added more than once');\n }\n\n this.#participantEntrypoints.push(callback);\n }\n}\n\nexport class JobProcess {\n #pid = process.pid;\n userData: { [id: string]: unknown } = {};\n\n get pid(): number {\n return this.#pid;\n }\n}\n\n/**\n * A request sent by the server to spawn a new agent job.\n *\n * @remarks\n * For most applications, this is best left to the default, which simply accepts the job and\n * handles the logic inside the entrypoint function. This class is useful for vetting which\n * requests should fill idle processes and which should be outright rejected.\n */\nexport class JobRequest {\n #job: proto.Job;\n #onReject: () => Promise<void>;\n #onAccept: (args: JobAcceptArguments) => Promise<void>;\n\n /** @internal */\n constructor(\n job: proto.Job,\n onReject: () => Promise<void>,\n onAccept: (args: JobAcceptArguments) => Promise<void>,\n ) {\n this.#job = job;\n this.#onReject = onReject;\n this.#onAccept = onAccept;\n }\n\n /** @returns The ID of the job, set by the LiveKit server */\n get id(): string {\n return this.#job.id;\n }\n\n /** @see {@link https://www.npmjs.com/package/@livekit/protocol | @livekit/protocol} */\n get job(): proto.Job {\n return this.#job;\n }\n\n /** @see {@link https://www.npmjs.com/package/@livekit/protocol | @livekit/protocol} */\n get room(): proto.Room | undefined {\n return this.#job.room;\n }\n\n /** @see {@link https://www.npmjs.com/package/@livekit/protocol | @livekit/protocol} */\n get publisher(): proto.ParticipantInfo | undefined {\n return this.#job.participant;\n }\n\n /** @returns The agent's name, as set in {@link WorkerOptions} */\n get agentName(): string {\n return this.#job.agentName;\n }\n\n /** Rejects the job. */\n async reject() {\n await this.#onReject();\n }\n\n /** Accepts the job, launching it on an idle child process. */\n async accept(name = '', identity = '', metadata = '', attributes?: { [key: string]: string }) {\n if (identity === '') identity = 'agent-' + this.id;\n\n this.#onAccept({ name, identity, metadata, attributes });\n }\n}\n"],"mappings":"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","names":["AutoSubscribe"]}
1
+ {"version":3,"sources":["../src/job.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type * as proto from '@livekit/protocol';\nimport type {\n E2EEOptions,\n LocalParticipant,\n RemoteParticipant,\n Room,\n RtcConfiguration,\n} from '@livekit/rtc-node';\nimport { ParticipantKind, RoomEvent, TrackKind } from '@livekit/rtc-node';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport type { Logger } from 'pino';\nimport type { InferenceExecutor } from './ipc/inference_executor.js';\nimport { log } from './log.js';\n\n// AsyncLocalStorage for job context, similar to Python's contextvars\nconst jobContextStorage = new AsyncLocalStorage<JobContext>();\n\n/**\n * Returns the current job context.\n *\n * @throws {Error} if no job context is found\n */\nexport function getJobContext(): JobContext {\n const ctx = jobContextStorage.getStore();\n if (!ctx) {\n throw new Error('no job context found, are you running this code inside a job entrypoint?');\n }\n return ctx;\n}\n\n/**\n * Runs a function within a job context, similar to Python's contextvars.\n * @internal\n */\nexport function runWithJobContext<T>(context: JobContext, fn: () => T): T {\n return jobContextStorage.run(context, fn);\n}\n\n/**\n * Runs an async function within a job context, similar to Python's contextvars.\n * @internal\n */\nexport function runWithJobContextAsync<T>(context: JobContext, fn: () => Promise<T>): Promise<T> {\n return jobContextStorage.run(context, fn);\n}\n\n/** Which tracks, if any, should the agent automatically subscribe to? */\nexport enum AutoSubscribe {\n SUBSCRIBE_ALL,\n SUBSCRIBE_NONE,\n VIDEO_ONLY,\n AUDIO_ONLY,\n}\n\nexport type JobAcceptArguments = {\n name: string;\n identity: string;\n metadata: string;\n attributes?: { [key: string]: string };\n};\n\nexport type RunningJobInfo = {\n acceptArguments: JobAcceptArguments;\n job: proto.Job;\n url: string;\n token: string;\n workerId: string;\n};\n\n/** Attempted to add a function callback, but the function already exists. */\nexport class FunctionExistsError extends Error {\n constructor(msg?: string) {\n super(msg);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** The job and environment context as seen by the agent, accessible by the entrypoint function. */\nexport class JobContext {\n #proc: JobProcess;\n #info: RunningJobInfo;\n #room: Room;\n #onConnect: () => void;\n #onShutdown: (s: string) => void;\n /** @internal */\n shutdownCallbacks: (() => Promise<void>)[] = [];\n #participantEntrypoints: ((job: JobContext, p: RemoteParticipant) => Promise<void>)[] = [];\n #participantTasks: {\n [id: string]: {\n callback: (job: JobContext, p: RemoteParticipant) => Promise<void>;\n result: Promise<void>;\n };\n } = {};\n #logger: Logger;\n #inferenceExecutor: InferenceExecutor;\n\n private connected: boolean = false;\n\n constructor(\n proc: JobProcess,\n info: RunningJobInfo,\n room: Room,\n onConnect: () => void,\n onShutdown: (s: string) => void,\n inferenceExecutor: InferenceExecutor,\n ) {\n this.#proc = proc;\n this.#info = info;\n this.#room = room;\n this.#onConnect = onConnect;\n this.#onShutdown = onShutdown;\n this.onParticipantConnected = this.onParticipantConnected.bind(this);\n this.#room.on(RoomEvent.ParticipantConnected, this.onParticipantConnected);\n this.#logger = log().child({ info: this.#info });\n this.#inferenceExecutor = inferenceExecutor;\n }\n\n get proc(): JobProcess {\n return this.#proc;\n }\n\n get job(): proto.Job {\n return this.#info.job;\n }\n\n get workerId(): string {\n return this.#info.workerId;\n }\n\n /** @returns The room the agent was called into */\n get room(): Room {\n return this.#room;\n }\n\n /** @returns The agent's participant if connected to the room, otherwise `undefined` */\n get agent(): LocalParticipant | undefined {\n return this.#room.localParticipant;\n }\n\n /** @returns The global inference executor */\n get inferenceExecutor(): InferenceExecutor {\n return this.#inferenceExecutor;\n }\n\n /** Adds a promise to be awaited when {@link JobContext.shutdown | shutdown} is called. */\n addShutdownCallback(callback: () => Promise<void>) {\n this.shutdownCallbacks.push(callback);\n }\n\n async waitForParticipant(identity?: string): Promise<RemoteParticipant> {\n if (!this.#room.isConnected) {\n throw new Error('room is not connected');\n }\n\n for (const p of this.#room.remoteParticipants.values()) {\n if ((!identity || p.identity === identity) && p.info.kind != ParticipantKind.AGENT) {\n return p;\n }\n }\n\n return new Promise((resolve, reject) => {\n const onParticipantConnected = (participant: RemoteParticipant) => {\n if (\n (!identity || participant.identity === identity) &&\n participant.info.kind != ParticipantKind.AGENT\n ) {\n clearHandlers();\n resolve(participant);\n }\n };\n const onDisconnected = () => {\n clearHandlers();\n reject(new Error('Room disconnected while waiting for participant'));\n };\n\n const clearHandlers = () => {\n this.#room.off(RoomEvent.ParticipantConnected, onParticipantConnected);\n this.#room.off(RoomEvent.Disconnected, onDisconnected);\n };\n\n this.#room.on(RoomEvent.ParticipantConnected, onParticipantConnected);\n this.#room.on(RoomEvent.Disconnected, onDisconnected);\n });\n }\n\n /**\n * Connects the agent to the room.\n *\n * @remarks\n * It is recommended to run this command as early in the function as possible, as executing it\n * later may cause noticeable delay between user and agent joins.\n *\n * @see {@link https://github.com/livekit/node-sdks/tree/main/packages/livekit-rtc#readme |\n * @livekit/rtc-node} for more information about the parameters.\n */\n async connect(\n e2ee?: E2EEOptions,\n autoSubscribe: AutoSubscribe = AutoSubscribe.SUBSCRIBE_ALL,\n rtcConfig?: RtcConfiguration,\n ) {\n if (this.connected) {\n return;\n }\n\n const opts = {\n e2ee,\n autoSubscribe: autoSubscribe == AutoSubscribe.SUBSCRIBE_ALL,\n rtcConfig,\n dynacast: false,\n };\n\n await this.#room.connect(this.#info.url, this.#info.token, opts);\n this.#onConnect();\n\n this.#room.remoteParticipants.forEach(this.onParticipantConnected);\n\n if ([AutoSubscribe.AUDIO_ONLY, AutoSubscribe.VIDEO_ONLY].includes(autoSubscribe)) {\n this.#room.remoteParticipants.forEach((p) => {\n p.trackPublications.forEach((pub) => {\n if (\n (autoSubscribe === AutoSubscribe.AUDIO_ONLY && pub.kind === TrackKind.KIND_AUDIO) ||\n (autoSubscribe === AutoSubscribe.VIDEO_ONLY && pub.kind === TrackKind.KIND_VIDEO)\n ) {\n pub.setSubscribed(true);\n }\n });\n });\n }\n this.connected = true;\n }\n\n /**\n * Gracefully shuts down the job, and runs all shutdown promises.\n *\n * @param reason - Optional reason for shutdown\n */\n shutdown(reason = '') {\n this.#onShutdown(reason);\n }\n\n /** @internal */\n onParticipantConnected(p: RemoteParticipant) {\n for (const callback of this.#participantEntrypoints) {\n if (this.#participantTasks[p.identity!]?.callback == callback) {\n this.#logger.warn(\n 'a participant has joined before a prior prticipant task matching the same identity has finished:',\n p.identity,\n );\n }\n const result = callback(this, p);\n result.finally(() => delete this.#participantTasks[p.identity!]);\n this.#participantTasks[p.identity!] = { callback, result };\n }\n }\n\n /**\n * Adds a promise to be awaited whenever a new participant joins the room.\n *\n * @throws {@link FunctionExistsError} if an entrypoint already exists\n */\n addParticipantEntrypoint(callback: (job: JobContext, p: RemoteParticipant) => Promise<void>) {\n if (this.#participantEntrypoints.includes(callback)) {\n throw new FunctionExistsError('entrypoints cannot be added more than once');\n }\n\n this.#participantEntrypoints.push(callback);\n }\n}\n\nexport class JobProcess {\n #pid = process.pid;\n userData: { [id: string]: unknown } = {};\n\n get pid(): number {\n return this.#pid;\n }\n}\n\n/**\n * A request sent by the server to spawn a new agent job.\n *\n * @remarks\n * For most applications, this is best left to the default, which simply accepts the job and\n * handles the logic inside the entrypoint function. This class is useful for vetting which\n * requests should fill idle processes and which should be outright rejected.\n */\nexport class JobRequest {\n #job: proto.Job;\n #onReject: () => Promise<void>;\n #onAccept: (args: JobAcceptArguments) => Promise<void>;\n\n /** @internal */\n constructor(\n job: proto.Job,\n onReject: () => Promise<void>,\n onAccept: (args: JobAcceptArguments) => Promise<void>,\n ) {\n this.#job = job;\n this.#onReject = onReject;\n this.#onAccept = onAccept;\n }\n\n /** @returns The ID of the job, set by the LiveKit server */\n get id(): string {\n return this.#job.id;\n }\n\n /** @see {@link https://www.npmjs.com/package/@livekit/protocol | @livekit/protocol} */\n get job(): proto.Job {\n return this.#job;\n }\n\n /** @see {@link https://www.npmjs.com/package/@livekit/protocol | @livekit/protocol} */\n get room(): proto.Room | undefined {\n return this.#job.room;\n }\n\n /** @see {@link https://www.npmjs.com/package/@livekit/protocol | @livekit/protocol} */\n get publisher(): proto.ParticipantInfo | undefined {\n return this.#job.participant;\n }\n\n /** @returns The agent's name, as set in {@link WorkerOptions} */\n get agentName(): string {\n return this.#job.agentName;\n }\n\n /** Rejects the job. */\n async reject() {\n await this.#onReject();\n }\n\n /** Accepts the job, launching it on an idle child process. */\n async accept(name = '', identity = '', metadata = '', attributes?: { [key: string]: string }) {\n if (identity === '') identity = 'agent-' + this.id;\n\n this.#onAccept({ name, identity, metadata, attributes });\n }\n}\n"],"mappings":"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","names":["AutoSubscribe"]}
package/dist/job.d.cts CHANGED
@@ -1,17 +1,22 @@
1
1
  import type * as proto from '@livekit/protocol';
2
2
  import type { E2EEOptions, LocalParticipant, RemoteParticipant, Room, RtcConfiguration } from '@livekit/rtc-node';
3
3
  import type { InferenceExecutor } from './ipc/inference_executor.js';
4
- export declare class CurrentJobContext {
5
- #private;
6
- constructor(proc: JobContext);
7
- static getCurrent(): JobContext;
8
- }
9
4
  /**
10
5
  * Returns the current job context.
11
6
  *
12
7
  * @throws {Error} if no job context is found
13
8
  */
14
9
  export declare function getJobContext(): JobContext;
10
+ /**
11
+ * Runs a function within a job context, similar to Python's contextvars.
12
+ * @internal
13
+ */
14
+ export declare function runWithJobContext<T>(context: JobContext, fn: () => T): T;
15
+ /**
16
+ * Runs an async function within a job context, similar to Python's contextvars.
17
+ * @internal
18
+ */
19
+ export declare function runWithJobContextAsync<T>(context: JobContext, fn: () => Promise<T>): Promise<T>;
15
20
  /** Which tracks, if any, should the agent automatically subscribe to? */
16
21
  export declare enum AutoSubscribe {
17
22
  SUBSCRIBE_ALL = 0,
@@ -43,6 +48,7 @@ export declare class JobContext {
43
48
  #private;
44
49
  /** @internal */
45
50
  shutdownCallbacks: (() => Promise<void>)[];
51
+ private connected;
46
52
  constructor(proc: JobProcess, info: RunningJobInfo, room: Room, onConnect: () => void, onShutdown: (s: string) => void, inferenceExecutor: InferenceExecutor);
47
53
  get proc(): JobProcess;
48
54
  get job(): proto.Job;
package/dist/job.d.ts CHANGED
@@ -1,17 +1,22 @@
1
1
  import type * as proto from '@livekit/protocol';
2
2
  import type { E2EEOptions, LocalParticipant, RemoteParticipant, Room, RtcConfiguration } from '@livekit/rtc-node';
3
3
  import type { InferenceExecutor } from './ipc/inference_executor.js';
4
- export declare class CurrentJobContext {
5
- #private;
6
- constructor(proc: JobContext);
7
- static getCurrent(): JobContext;
8
- }
9
4
  /**
10
5
  * Returns the current job context.
11
6
  *
12
7
  * @throws {Error} if no job context is found
13
8
  */
14
9
  export declare function getJobContext(): JobContext;
10
+ /**
11
+ * Runs a function within a job context, similar to Python's contextvars.
12
+ * @internal
13
+ */
14
+ export declare function runWithJobContext<T>(context: JobContext, fn: () => T): T;
15
+ /**
16
+ * Runs an async function within a job context, similar to Python's contextvars.
17
+ * @internal
18
+ */
19
+ export declare function runWithJobContextAsync<T>(context: JobContext, fn: () => Promise<T>): Promise<T>;
15
20
  /** Which tracks, if any, should the agent automatically subscribe to? */
16
21
  export declare enum AutoSubscribe {
17
22
  SUBSCRIBE_ALL = 0,
@@ -43,6 +48,7 @@ export declare class JobContext {
43
48
  #private;
44
49
  /** @internal */
45
50
  shutdownCallbacks: (() => Promise<void>)[];
51
+ private connected;
46
52
  constructor(proc: JobProcess, info: RunningJobInfo, room: Room, onConnect: () => void, onShutdown: (s: string) => void, inferenceExecutor: InferenceExecutor);
47
53
  get proc(): JobProcess;
48
54
  get job(): proto.Job;
package/dist/job.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"job.d.ts","sourceRoot":"","sources":["../src/job.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"job.d.ts","sourceRoot":"","sources":["../src/job.ts"],"names":[],"mappings":"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"}
package/dist/job.js CHANGED
@@ -1,21 +1,20 @@
1
1
  import { ParticipantKind, RoomEvent, TrackKind } from "@livekit/rtc-node";
2
+ import { AsyncLocalStorage } from "node:async_hooks";
2
3
  import { log } from "./log.js";
3
- class CurrentJobContext {
4
- static #current;
5
- constructor(proc) {
6
- CurrentJobContext.#current = proc;
7
- }
8
- static getCurrent() {
9
- return CurrentJobContext.#current;
10
- }
11
- }
4
+ const jobContextStorage = new AsyncLocalStorage();
12
5
  function getJobContext() {
13
- const ctx = CurrentJobContext.getCurrent();
6
+ const ctx = jobContextStorage.getStore();
14
7
  if (!ctx) {
15
8
  throw new Error("no job context found, are you running this code inside a job entrypoint?");
16
9
  }
17
10
  return ctx;
18
11
  }
12
+ function runWithJobContext(context, fn) {
13
+ return jobContextStorage.run(context, fn);
14
+ }
15
+ function runWithJobContextAsync(context, fn) {
16
+ return jobContextStorage.run(context, fn);
17
+ }
19
18
  var AutoSubscribe = /* @__PURE__ */ ((AutoSubscribe2) => {
20
19
  AutoSubscribe2[AutoSubscribe2["SUBSCRIBE_ALL"] = 0] = "SUBSCRIBE_ALL";
21
20
  AutoSubscribe2[AutoSubscribe2["SUBSCRIBE_NONE"] = 1] = "SUBSCRIBE_NONE";
@@ -41,6 +40,7 @@ class JobContext {
41
40
  #participantTasks = {};
42
41
  #logger;
43
42
  #inferenceExecutor;
43
+ connected = false;
44
44
  constructor(proc, info, room, onConnect, onShutdown, inferenceExecutor) {
45
45
  this.#proc = proc;
46
46
  this.#info = info;
@@ -116,6 +116,9 @@ class JobContext {
116
116
  * @livekit/rtc-node} for more information about the parameters.
117
117
  */
118
118
  async connect(e2ee, autoSubscribe = 0 /* SUBSCRIBE_ALL */, rtcConfig) {
119
+ if (this.connected) {
120
+ return;
121
+ }
119
122
  const opts = {
120
123
  e2ee,
121
124
  autoSubscribe: autoSubscribe == 0 /* SUBSCRIBE_ALL */,
@@ -134,6 +137,7 @@ class JobContext {
134
137
  });
135
138
  });
136
139
  }
140
+ this.connected = true;
137
141
  }
138
142
  /**
139
143
  * Gracefully shuts down the job, and runs all shutdown promises.
@@ -219,11 +223,12 @@ class JobRequest {
219
223
  }
220
224
  export {
221
225
  AutoSubscribe,
222
- CurrentJobContext,
223
226
  FunctionExistsError,
224
227
  JobContext,
225
228
  JobProcess,
226
229
  JobRequest,
227
- getJobContext
230
+ getJobContext,
231
+ runWithJobContext,
232
+ runWithJobContextAsync
228
233
  };
229
234
  //# sourceMappingURL=job.js.map