@dxos/plugin-transcription 0.8.2-main.fbd8ed0 → 0.8.2-staging.4d6ad0f

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 (243) hide show
  1. package/dist/lib/browser/TranscriptContainer-PFKLKRPQ.mjs +11 -0
  2. package/dist/lib/browser/{chunk-3TKXI6TQ.mjs → chunk-4KCUYW2F.mjs} +43 -26
  3. package/dist/lib/browser/chunk-4KCUYW2F.mjs.map +7 -0
  4. package/dist/lib/browser/{chunk-6ZR5MDK3.mjs → chunk-GOF7MJNV.mjs} +3 -3
  5. package/dist/lib/browser/{chunk-6ZR5MDK3.mjs.map → chunk-GOF7MJNV.mjs.map} +1 -1
  6. package/dist/lib/browser/chunk-IGEKO7ZU.mjs +8 -0
  7. package/dist/lib/browser/chunk-IGEKO7ZU.mjs.map +7 -0
  8. package/dist/lib/browser/{chunk-JHWEZRWC.mjs → chunk-NODIXNQP.mjs} +6 -15
  9. package/dist/lib/browser/chunk-NODIXNQP.mjs.map +7 -0
  10. package/dist/lib/browser/{chunk-K2LS2QOM.mjs → chunk-TJPJBE45.mjs} +136 -92
  11. package/dist/lib/browser/chunk-TJPJBE45.mjs.map +7 -0
  12. package/dist/lib/browser/{chunk-LTIQFX4W.mjs → chunk-W2KNYJD6.mjs} +4 -4
  13. package/dist/lib/browser/chunk-W2KNYJD6.mjs.map +7 -0
  14. package/dist/lib/browser/index.mjs +8 -31
  15. package/dist/lib/browser/index.mjs.map +3 -3
  16. package/dist/lib/browser/{intent-resolver-DZ62CJPC.mjs → intent-resolver-I2LJSQDR.mjs} +4 -8
  17. package/dist/lib/browser/intent-resolver-I2LJSQDR.mjs.map +7 -0
  18. package/dist/lib/browser/meta.json +1 -1
  19. package/dist/lib/browser/react-surface-ID2MLJHZ.mjs +34 -0
  20. package/dist/lib/browser/react-surface-ID2MLJHZ.mjs.map +7 -0
  21. package/dist/lib/browser/transcriber-NA7CIFIT.mjs +56 -0
  22. package/dist/lib/browser/transcriber-NA7CIFIT.mjs.map +7 -0
  23. package/dist/lib/browser/types/index.mjs +4 -8
  24. package/dist/lib/node/{TranscriptContainer-SSJVLRM6.cjs → TranscriptContainer-LHMC7553.cjs} +9 -9
  25. package/dist/lib/node/{TranscriptContainer-SSJVLRM6.cjs.map → TranscriptContainer-LHMC7553.cjs.map} +2 -2
  26. package/dist/lib/node/{chunk-EVE3H46F.cjs → chunk-3GS5UNO5.cjs} +141 -100
  27. package/dist/lib/node/chunk-3GS5UNO5.cjs.map +7 -0
  28. package/dist/lib/node/{chunk-L27AK6FQ.cjs → chunk-5J3FBCON.cjs} +8 -23
  29. package/dist/lib/node/chunk-5J3FBCON.cjs.map +7 -0
  30. package/dist/lib/node/{chunk-NVZWGFJL.cjs → chunk-AFUZI63A.cjs} +6 -6
  31. package/dist/lib/node/{chunk-NVZWGFJL.cjs.map → chunk-AFUZI63A.cjs.map} +1 -1
  32. package/dist/lib/node/{chunk-EJWB53WK.cjs → chunk-EIMUQYCZ.cjs} +10 -21
  33. package/dist/lib/node/chunk-EIMUQYCZ.cjs.map +7 -0
  34. package/dist/lib/node/{chunk-JUGOXWES.cjs → chunk-FKDJNJ57.cjs} +8 -8
  35. package/dist/lib/node/chunk-FKDJNJ57.cjs.map +7 -0
  36. package/dist/lib/node/{chunk-WKZLGVEJ.cjs → chunk-ZFTXJZXH.cjs} +44 -29
  37. package/dist/lib/node/chunk-ZFTXJZXH.cjs.map +7 -0
  38. package/dist/lib/node/index.cjs +36 -56
  39. package/dist/lib/node/index.cjs.map +3 -3
  40. package/dist/lib/node/{intent-resolver-TRBKI24D.cjs → intent-resolver-LLMGF5I5.cjs} +9 -11
  41. package/dist/lib/node/intent-resolver-LLMGF5I5.cjs.map +7 -0
  42. package/dist/lib/node/meta.json +1 -1
  43. package/dist/lib/node/{react-surface-SZAMHCX7.cjs → react-surface-SEQLEL4K.cjs} +13 -21
  44. package/dist/lib/node/react-surface-SEQLEL4K.cjs.map +7 -0
  45. package/dist/lib/node/transcriber-RKKN7LDU.cjs +68 -0
  46. package/dist/lib/node/transcriber-RKKN7LDU.cjs.map +7 -0
  47. package/dist/lib/node/types/index.cjs +7 -11
  48. package/dist/lib/node/types/index.cjs.map +2 -2
  49. package/dist/lib/node-esm/{TranscriptContainer-M53LI2TX.mjs → TranscriptContainer-DLNRFVTA.mjs} +4 -4
  50. package/dist/lib/node-esm/{chunk-QYG2FOXA.mjs → chunk-BRPFVRAD.mjs} +6 -15
  51. package/dist/lib/node-esm/chunk-BRPFVRAD.mjs.map +7 -0
  52. package/dist/lib/node-esm/{chunk-V5IWBPYO.mjs → chunk-EFIWBQDF.mjs} +43 -26
  53. package/dist/lib/node-esm/chunk-EFIWBQDF.mjs.map +7 -0
  54. package/dist/lib/node-esm/chunk-KUWWHMOA.mjs +10 -0
  55. package/dist/lib/node-esm/chunk-KUWWHMOA.mjs.map +7 -0
  56. package/dist/lib/node-esm/{chunk-5E2MR5XK.mjs → chunk-MFJPEIVB.mjs} +4 -4
  57. package/dist/lib/node-esm/chunk-MFJPEIVB.mjs.map +7 -0
  58. package/dist/lib/node-esm/{chunk-4KC3E5T4.mjs → chunk-PR7EYODX.mjs} +136 -92
  59. package/dist/lib/node-esm/chunk-PR7EYODX.mjs.map +7 -0
  60. package/dist/lib/node-esm/{chunk-X4DDJIVL.mjs → chunk-TXMDLLBR.mjs} +3 -3
  61. package/dist/lib/node-esm/{chunk-X4DDJIVL.mjs.map → chunk-TXMDLLBR.mjs.map} +1 -1
  62. package/dist/lib/node-esm/index.mjs +8 -31
  63. package/dist/lib/node-esm/index.mjs.map +3 -3
  64. package/dist/lib/node-esm/{intent-resolver-HFVAL274.mjs → intent-resolver-WOZKOEBW.mjs} +4 -8
  65. package/dist/lib/node-esm/intent-resolver-WOZKOEBW.mjs.map +7 -0
  66. package/dist/lib/node-esm/meta.json +1 -1
  67. package/dist/lib/node-esm/{react-surface-UEJELL7I.mjs → react-surface-7MXUUTAL.mjs} +9 -19
  68. package/dist/lib/node-esm/react-surface-7MXUUTAL.mjs.map +7 -0
  69. package/dist/lib/node-esm/transcriber-5WSI6DYK.mjs +57 -0
  70. package/dist/lib/node-esm/transcriber-5WSI6DYK.mjs.map +7 -0
  71. package/dist/lib/node-esm/types/index.mjs +4 -8
  72. package/dist/types/src/TranscriptionPlugin.d.ts.map +1 -1
  73. package/dist/types/src/capabilities/capabilities.d.ts +8 -8
  74. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  75. package/dist/types/src/capabilities/index.d.ts +1 -4
  76. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  77. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  78. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  79. package/dist/types/src/capabilities/transcriber.d.ts +2 -1
  80. package/dist/types/src/capabilities/transcriber.d.ts.map +1 -1
  81. package/dist/types/src/components/index.d.ts +0 -1
  82. package/dist/types/src/components/index.d.ts.map +1 -1
  83. package/dist/types/src/components/stories/FileTranscription.stories.d.ts +17 -0
  84. package/dist/types/src/components/stories/FileTranscription.stories.d.ts.map +1 -0
  85. package/dist/types/src/components/stories/KeyWordRecognition.stories.d.ts +10 -0
  86. package/dist/types/src/components/stories/KeyWordRecognition.stories.d.ts.map +1 -0
  87. package/dist/types/src/components/stories/MicrophoneTranscription.stories.d.ts +19 -0
  88. package/dist/types/src/components/stories/MicrophoneTranscription.stories.d.ts.map +1 -0
  89. package/dist/types/src/components/stories/TranscriptionStory.d.ts +11 -0
  90. package/dist/types/src/components/stories/TranscriptionStory.d.ts.map +1 -0
  91. package/dist/types/src/components/stories/useIsSpeaking.d.ts +3 -0
  92. package/dist/types/src/components/stories/useIsSpeaking.d.ts.map +1 -0
  93. package/dist/types/src/hooks/useAudioFile.d.ts +1 -1
  94. package/dist/types/src/hooks/useAudioFile.d.ts.map +1 -1
  95. package/dist/types/src/hooks/useAudioTrack.d.ts +1 -1
  96. package/dist/types/src/hooks/useAudioTrack.d.ts.map +1 -1
  97. package/dist/types/src/hooks/useQueueModelAdapter.d.ts.map +1 -1
  98. package/dist/types/src/hooks/useTranscriber.d.ts +1 -1
  99. package/dist/types/src/hooks/useTranscriber.d.ts.map +1 -1
  100. package/dist/types/src/model/model.d.ts.map +1 -1
  101. package/dist/types/src/segments-normalization/index.d.ts +4 -0
  102. package/dist/types/src/segments-normalization/index.d.ts.map +1 -0
  103. package/dist/types/src/segments-normalization/message-normalizer.d.ts +26 -0
  104. package/dist/types/src/segments-normalization/message-normalizer.d.ts.map +1 -0
  105. package/dist/types/src/segments-normalization/normalization.d.ts +520 -0
  106. package/dist/types/src/segments-normalization/normalization.d.ts.map +1 -0
  107. package/dist/types/src/segments-normalization/normalization.test.d.ts +2 -0
  108. package/dist/types/src/segments-normalization/normalization.test.d.ts.map +1 -0
  109. package/dist/types/src/segments-normalization/utils.d.ts +3 -0
  110. package/dist/types/src/segments-normalization/utils.d.ts.map +1 -0
  111. package/dist/types/src/testing/testing.d.ts.map +1 -1
  112. package/dist/types/src/transcriber/media-stream-recorder.d.ts +8 -5
  113. package/dist/types/src/transcriber/media-stream-recorder.d.ts.map +1 -1
  114. package/dist/types/src/transcriber/transcriber.d.ts +4 -0
  115. package/dist/types/src/transcriber/transcriber.d.ts.map +1 -1
  116. package/dist/types/src/transcriber/transcription-manager.d.ts +2 -0
  117. package/dist/types/src/transcriber/transcription-manager.d.ts.map +1 -1
  118. package/dist/types/src/translations.d.ts +0 -2
  119. package/dist/types/src/translations.d.ts.map +1 -1
  120. package/dist/types/src/types/schema.d.ts +0 -3
  121. package/dist/types/src/types/schema.d.ts.map +1 -1
  122. package/dist/types/src/types/types.d.ts +1 -5
  123. package/dist/types/src/types/types.d.ts.map +1 -1
  124. package/package.json +54 -50
  125. package/src/TranscriptionPlugin.tsx +2 -24
  126. package/src/capabilities/capabilities.ts +15 -9
  127. package/src/capabilities/index.ts +0 -3
  128. package/src/capabilities/intent-resolver.ts +0 -2
  129. package/src/capabilities/react-surface.tsx +4 -11
  130. package/src/capabilities/transcriber.ts +34 -7
  131. package/src/components/Transcript/deprecated/OldTranscript.tsx +1 -1
  132. package/src/components/Transcript/transcript-extension.ts +2 -2
  133. package/src/components/index.ts +0 -1
  134. package/src/components/stories/FileTranscription.stories.tsx +240 -0
  135. package/src/components/stories/KeyWordRecognition.stories.tsx +128 -0
  136. package/src/components/stories/MicrophoneTranscription.stories.tsx +274 -0
  137. package/src/components/stories/TranscriptionStory.tsx +41 -0
  138. package/src/components/stories/useIsSpeaking.tsx +40 -0
  139. package/src/hooks/useAudioFile.ts +39 -9
  140. package/src/hooks/useAudioTrack.ts +2 -2
  141. package/src/hooks/useQueueModelAdapter.ts +7 -5
  142. package/src/hooks/useTranscriber.ts +4 -3
  143. package/src/meta.ts +2 -2
  144. package/src/model/model.ts +1 -1
  145. package/src/segments-normalization/index.ts +7 -0
  146. package/src/segments-normalization/message-normalizer.ts +108 -0
  147. package/src/segments-normalization/normalization.test.ts +142 -0
  148. package/src/segments-normalization/normalization.ts +103 -0
  149. package/src/segments-normalization/utils.ts +9 -0
  150. package/src/testing/testing.ts +17 -17
  151. package/src/transcriber/media-stream-recorder.ts +14 -7
  152. package/src/transcriber/transcriber.browser.test.ts +4 -4
  153. package/src/transcriber/transcriber.ts +13 -9
  154. package/src/transcriber/transcription-manager.ts +21 -14
  155. package/src/translations.ts +0 -3
  156. package/src/types/schema.ts +1 -2
  157. package/src/types/types.ts +1 -15
  158. package/dist/lib/browser/TranscriptContainer-CXA4ZBHW.mjs +0 -11
  159. package/dist/lib/browser/app-graph-builder-REQZ5SC5.mjs +0 -351
  160. package/dist/lib/browser/app-graph-builder-REQZ5SC5.mjs.map +0 -7
  161. package/dist/lib/browser/chunk-3TKXI6TQ.mjs.map +0 -7
  162. package/dist/lib/browser/chunk-JHWEZRWC.mjs.map +0 -7
  163. package/dist/lib/browser/chunk-K2LS2QOM.mjs.map +0 -7
  164. package/dist/lib/browser/chunk-KLD7O5GJ.mjs +0 -25
  165. package/dist/lib/browser/chunk-KLD7O5GJ.mjs.map +0 -7
  166. package/dist/lib/browser/chunk-LCTMCTYY.mjs +0 -27
  167. package/dist/lib/browser/chunk-LCTMCTYY.mjs.map +0 -7
  168. package/dist/lib/browser/chunk-LTIQFX4W.mjs.map +0 -7
  169. package/dist/lib/browser/intent-resolver-DZ62CJPC.mjs.map +0 -7
  170. package/dist/lib/browser/meeting-transcription-state-MNA2XROE.mjs +0 -18
  171. package/dist/lib/browser/meeting-transcription-state-MNA2XROE.mjs.map +0 -7
  172. package/dist/lib/browser/react-surface-PUXZNAZL.mjs +0 -44
  173. package/dist/lib/browser/react-surface-PUXZNAZL.mjs.map +0 -7
  174. package/dist/lib/browser/settings-JWDS4J3F.mjs +0 -24
  175. package/dist/lib/browser/settings-JWDS4J3F.mjs.map +0 -7
  176. package/dist/lib/browser/transcriber-YWWIV6KP.mjs +0 -37
  177. package/dist/lib/browser/transcriber-YWWIV6KP.mjs.map +0 -7
  178. package/dist/lib/node/app-graph-builder-OAPU4GDH.cjs +0 -352
  179. package/dist/lib/node/app-graph-builder-OAPU4GDH.cjs.map +0 -7
  180. package/dist/lib/node/chunk-EJWB53WK.cjs.map +0 -7
  181. package/dist/lib/node/chunk-EVE3H46F.cjs.map +0 -7
  182. package/dist/lib/node/chunk-J72PUQ3C.cjs +0 -46
  183. package/dist/lib/node/chunk-J72PUQ3C.cjs.map +0 -7
  184. package/dist/lib/node/chunk-JUGOXWES.cjs.map +0 -7
  185. package/dist/lib/node/chunk-L27AK6FQ.cjs.map +0 -7
  186. package/dist/lib/node/chunk-WKZLGVEJ.cjs.map +0 -7
  187. package/dist/lib/node/intent-resolver-TRBKI24D.cjs.map +0 -7
  188. package/dist/lib/node/meeting-transcription-state-5XLTMWPA.cjs +0 -34
  189. package/dist/lib/node/meeting-transcription-state-5XLTMWPA.cjs.map +0 -7
  190. package/dist/lib/node/react-surface-SZAMHCX7.cjs.map +0 -7
  191. package/dist/lib/node/settings-AWWMOSCV.cjs +0 -38
  192. package/dist/lib/node/settings-AWWMOSCV.cjs.map +0 -7
  193. package/dist/lib/node/transcriber-AFUXFHCR.cjs +0 -50
  194. package/dist/lib/node/transcriber-AFUXFHCR.cjs.map +0 -7
  195. package/dist/lib/node-esm/app-graph-builder-UBP6EOBR.mjs +0 -352
  196. package/dist/lib/node-esm/app-graph-builder-UBP6EOBR.mjs.map +0 -7
  197. package/dist/lib/node-esm/chunk-4KC3E5T4.mjs.map +0 -7
  198. package/dist/lib/node-esm/chunk-5E2MR5XK.mjs.map +0 -7
  199. package/dist/lib/node-esm/chunk-MHQP2PAF.mjs +0 -28
  200. package/dist/lib/node-esm/chunk-MHQP2PAF.mjs.map +0 -7
  201. package/dist/lib/node-esm/chunk-QMHMEKB3.mjs +0 -27
  202. package/dist/lib/node-esm/chunk-QMHMEKB3.mjs.map +0 -7
  203. package/dist/lib/node-esm/chunk-QYG2FOXA.mjs.map +0 -7
  204. package/dist/lib/node-esm/chunk-V5IWBPYO.mjs.map +0 -7
  205. package/dist/lib/node-esm/intent-resolver-HFVAL274.mjs.map +0 -7
  206. package/dist/lib/node-esm/meeting-transcription-state-3WOZ52BQ.mjs +0 -19
  207. package/dist/lib/node-esm/meeting-transcription-state-3WOZ52BQ.mjs.map +0 -7
  208. package/dist/lib/node-esm/react-surface-UEJELL7I.mjs.map +0 -7
  209. package/dist/lib/node-esm/settings-QFNFGFJ5.mjs +0 -25
  210. package/dist/lib/node-esm/settings-QFNFGFJ5.mjs.map +0 -7
  211. package/dist/lib/node-esm/transcriber-7RJEFPDI.mjs +0 -38
  212. package/dist/lib/node-esm/transcriber-7RJEFPDI.mjs.map +0 -7
  213. package/dist/types/src/capabilities/app-graph-builder.d.ts +0 -4
  214. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +0 -1
  215. package/dist/types/src/capabilities/meeting-transcription-state.d.ts +0 -4
  216. package/dist/types/src/capabilities/meeting-transcription-state.d.ts.map +0 -1
  217. package/dist/types/src/capabilities/settings.d.ts +0 -4
  218. package/dist/types/src/capabilities/settings.d.ts.map +0 -1
  219. package/dist/types/src/components/TranscriptionSettings/TranscriptionSettings.d.ts +0 -6
  220. package/dist/types/src/components/TranscriptionSettings/TranscriptionSettings.d.ts.map +0 -1
  221. package/dist/types/src/components/TranscriptionSettings/index.d.ts +0 -2
  222. package/dist/types/src/components/TranscriptionSettings/index.d.ts.map +0 -1
  223. package/dist/types/src/components/transcription.stories.d.ts +0 -18
  224. package/dist/types/src/components/transcription.stories.d.ts.map +0 -1
  225. package/dist/types/src/entity-extraction/entity-extraction.d.ts +0 -42
  226. package/dist/types/src/entity-extraction/entity-extraction.d.ts.map +0 -1
  227. package/dist/types/src/entity-extraction/entity-extraction.test.d.ts +0 -2
  228. package/dist/types/src/entity-extraction/entity-extraction.test.d.ts.map +0 -1
  229. package/dist/types/src/entity-extraction/index.d.ts +0 -2
  230. package/dist/types/src/entity-extraction/index.d.ts.map +0 -1
  231. package/src/capabilities/app-graph-builder.ts +0 -233
  232. package/src/capabilities/meeting-transcription-state.ts +0 -16
  233. package/src/capabilities/settings.ts +0 -20
  234. package/src/components/TranscriptionSettings/TranscriptionSettings.tsx +0 -26
  235. package/src/components/TranscriptionSettings/index.ts +0 -5
  236. package/src/components/transcription.stories.tsx +0 -295
  237. package/src/entity-extraction/entity-extraction.test.ts +0 -97
  238. package/src/entity-extraction/entity-extraction.ts +0 -149
  239. package/src/entity-extraction/index.ts +0 -5
  240. package/src/entity-extraction/system-prompt.tpl +0 -38
  241. package/src/entity-extraction/types.d.ts +0 -8
  242. /package/dist/lib/browser/{TranscriptContainer-CXA4ZBHW.mjs.map → TranscriptContainer-PFKLKRPQ.mjs.map} +0 -0
  243. /package/dist/lib/node-esm/{TranscriptContainer-M53LI2TX.mjs.map → TranscriptContainer-DLNRFVTA.mjs.map} +0 -0
@@ -0,0 +1,40 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import '@dxos-theme';
6
+
7
+ import { useEffect, useMemo, useState } from 'react';
8
+
9
+ import { scheduleTask } from '@dxos/async';
10
+ import { Context } from '@dxos/context';
11
+ import { SpeakingMonitor } from '@dxos/plugin-thread';
12
+
13
+ export const useIsSpeaking = (track?: MediaStreamTrack) => {
14
+ const [isSpeaking, setIsSpeaking] = useState(false);
15
+ const speakingMonitor = useMemo(() => {
16
+ if (!track) {
17
+ return;
18
+ }
19
+ return new SpeakingMonitor(track);
20
+ }, [track]);
21
+
22
+ useEffect(() => {
23
+ if (!speakingMonitor) {
24
+ return;
25
+ }
26
+
27
+ const ctx = new Context();
28
+ scheduleTask(ctx, async () => {
29
+ speakingMonitor.speakingChanged.on(ctx, () => setIsSpeaking(speakingMonitor.isSpeaking));
30
+ await speakingMonitor.open();
31
+ ctx.onDispose(() => speakingMonitor.close());
32
+ });
33
+
34
+ return () => {
35
+ void ctx.dispose();
36
+ };
37
+ }, [speakingMonitor]);
38
+
39
+ return isSpeaking;
40
+ };
@@ -4,6 +4,8 @@
4
4
 
5
5
  import { useEffect, useState } from 'react';
6
6
 
7
+ import { scheduleTask } from '@dxos/async';
8
+ import { Context } from '@dxos/context';
7
9
  import { log } from '@dxos/log';
8
10
 
9
11
  export type UseAudioState = {
@@ -12,14 +14,22 @@ export type UseAudioState = {
12
14
  track?: MediaStreamTrack;
13
15
  };
14
16
 
15
- export const useAudioFile = (audioUrl: string): UseAudioState => {
17
+ export const useAudioFile = (audioUrl: string, constraints?: MediaTrackConstraints): UseAudioState => {
16
18
  const [{ audio, stream, track }, setStream] = useState<UseAudioState>({});
17
19
  useEffect(() => {
18
- const t = setTimeout(async () => {
20
+ const ctx = new Context();
21
+
22
+ scheduleTask(ctx, async () => {
19
23
  const response = await fetch(audioUrl);
20
24
  const blob = await response.blob();
25
+ const objectUrl = URL.createObjectURL(blob);
26
+ ctx.onDispose(() => {
27
+ URL.revokeObjectURL(objectUrl);
28
+ });
29
+
21
30
  const audio = new Audio();
22
- audio.src = URL.createObjectURL(blob);
31
+ audio.src = objectUrl;
32
+
23
33
  await new Promise<void>((resolve, reject) => {
24
34
  audio.addEventListener(
25
35
  'error',
@@ -31,23 +41,41 @@ export const useAudioFile = (audioUrl: string): UseAudioState => {
31
41
  );
32
42
  audio.addEventListener(
33
43
  'canplay',
34
- () => {
44
+ async () => {
35
45
  log.info('starting...');
36
- resolve();
46
+ try {
47
+ // Try to play the audio
48
+ await audio.play();
49
+ resolve();
50
+ } catch (playError) {
51
+ log.error('Play failed', { playError });
52
+ // Still resolve as the audio is ready, even if autoplay failed.
53
+ resolve();
54
+ }
37
55
  },
38
56
  { once: true },
39
57
  );
40
58
  audio.load();
41
59
  });
42
60
 
43
- const ctx = new AudioContext();
61
+ const audioCtx = new AudioContext();
62
+
63
+ // Resume AudioContext if it's suspended.
64
+ if (audioCtx.state === 'suspended') {
65
+ await audioCtx.resume();
66
+ }
44
67
 
45
- const destination = ctx.createMediaStreamDestination();
68
+ const destination = audioCtx.createMediaStreamDestination();
46
69
  destination.channelCount = 1;
47
70
 
48
- const source = ctx.createMediaElementSource(audio);
71
+ const source = audioCtx.createMediaElementSource(audio);
49
72
  source.connect(destination);
73
+ const track = destination.stream.getAudioTracks()[0];
74
+ if (constraints) {
75
+ await track.applyConstraints(constraints).catch((err) => log.catch(err));
76
+ }
50
77
 
78
+ // Also connect to speakers so audio is audible.
51
79
  setStream({
52
80
  audio,
53
81
  stream: destination.stream,
@@ -55,7 +83,9 @@ export const useAudioFile = (audioUrl: string): UseAudioState => {
55
83
  });
56
84
  });
57
85
 
58
- return () => clearTimeout(t);
86
+ return () => {
87
+ void ctx.dispose();
88
+ };
59
89
  }, [audioUrl]);
60
90
 
61
91
  return { audio, stream, track };
@@ -8,7 +8,7 @@ import { useEffect, useState } from 'react';
8
8
  *
9
9
  */
10
10
  // TODO(burdon): Reconcile with react-ui-sfx and plugin-calls.
11
- export const useAudioTrack = (active?: boolean): MediaStreamTrack | undefined => {
11
+ export const useAudioTrack = (active?: boolean, constraints?: MediaTrackConstraints): MediaStreamTrack | undefined => {
12
12
  const [track, setTrack] = useState<MediaStreamTrack>();
13
13
  useEffect(() => {
14
14
  if (!active) {
@@ -19,7 +19,7 @@ export const useAudioTrack = (active?: boolean): MediaStreamTrack | undefined =>
19
19
 
20
20
  const initAudio = async () => {
21
21
  const audio = new Audio();
22
- audio.srcObject = await navigator.mediaDevices.getUserMedia({ audio: true });
22
+ audio.srcObject = await navigator.mediaDevices.getUserMedia({ audio: constraints ?? true });
23
23
  const [track] = audio.srcObject.getAudioTracks();
24
24
  if (track) {
25
25
  setTrack(track);
@@ -26,7 +26,7 @@ export const useQueueModelAdapter = <T extends Chunk>(
26
26
  }
27
27
 
28
28
  const update = () => {
29
- for (const block of queue?.items ?? []) {
29
+ for (const block of queue?.objects ?? []) {
30
30
  model.appendChunk(block);
31
31
  }
32
32
 
@@ -51,13 +51,15 @@ export const useQueueModelAdapter = <T extends Chunk>(
51
51
 
52
52
  // TODO(burdon): Can we listen for queue events?
53
53
  useEffect(() => {
54
- if (!loaded || !queue || model.chunks.length === queue.items.length) {
54
+ if (!loaded || !queue || model.chunks.length === queue.objects.length) {
55
55
  return;
56
56
  }
57
57
 
58
- const chunk = queue.items[queue.items.length - 1];
59
- model.appendChunk(chunk);
60
- }, [model, loaded, queue?.items.length]);
58
+ const chunk = queue.objects.at(-1);
59
+ if (chunk) {
60
+ model.appendChunk(chunk);
61
+ }
62
+ }, [model, loaded, queue?.objects.length]);
61
63
 
62
64
  return model;
63
65
  };
@@ -15,7 +15,8 @@ import { type Transcriber } from '../transcriber';
15
15
  export const useTranscriber = ({
16
16
  audioStreamTrack,
17
17
  onSegments,
18
- config,
18
+ transcriberConfig,
19
+ recorderConfig,
19
20
  }: Partial<TranscriptionCapabilities.GetTranscriberProps>) => {
20
21
  const [getTranscriber] = useCapabilities(TranscriptionCapabilities.Transcriber);
21
22
 
@@ -25,8 +26,8 @@ export const useTranscriber = ({
25
26
  return undefined;
26
27
  }
27
28
 
28
- return getTranscriber({ audioStreamTrack, onSegments, config });
29
- }, [audioStreamTrack, onSegments, getTranscriber, config]);
29
+ return getTranscriber({ audioStreamTrack, onSegments, transcriberConfig, recorderConfig });
30
+ }, [audioStreamTrack, onSegments, getTranscriber, transcriberConfig, recorderConfig]);
30
31
 
31
32
  useEffect(() => {
32
33
  return () => {
package/src/meta.ts CHANGED
@@ -11,7 +11,7 @@ export const meta: PluginMeta = {
11
11
  name: 'Transcription',
12
12
  description: 'Voice transcription.',
13
13
  icon: 'ph--microphone--regular',
14
- source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/experimental/plugin-transcription',
15
- tags: ['experimental'],
14
+ source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-transcription',
15
+ tags: ['labs'],
16
16
  screenshots: [],
17
17
  };
@@ -104,7 +104,7 @@ export class SerializationModel<T extends Chunk> {
104
104
  });
105
105
  }
106
106
 
107
- toJSON() {
107
+ toJSON(): { chunks: number; changes: number } {
108
108
  return {
109
109
  chunks: this._chunks.length,
110
110
  changes: this._changes.length,
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './normalization';
6
+ export * from './message-normalizer';
7
+ export * from './utils';
@@ -0,0 +1,108 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ //
6
+ // Copyright 2025 DXOS.org
7
+ //
8
+
9
+ import { effect } from '@preact/signals-core';
10
+
11
+ import { asyncTimeout, DeferredTask } from '@dxos/async';
12
+ import { LifecycleState, Resource } from '@dxos/context';
13
+ import { type Queue } from '@dxos/echo-db';
14
+ import { type FunctionExecutor } from '@dxos/functions';
15
+ import { log } from '@dxos/log';
16
+ import { type DataType } from '@dxos/schema';
17
+
18
+ import { type MessageWithRangeId, sentenceNormalization } from './normalization';
19
+ import { getActorId } from './utils';
20
+
21
+ const PROCESSING_TIMEOUT = 20_000; // ms
22
+ const MAX_RANGE_ID_COUNT = 10;
23
+
24
+ export type SegmentsNormalizerParams = {
25
+ functionExecutor: FunctionExecutor;
26
+ queue: Queue<DataType.Message>;
27
+ startingCursor: QueueCursor;
28
+ };
29
+
30
+ // TODO(mykola): Use generic queue cursor from @dxos/protocols.
31
+ export type QueueCursor = {
32
+ actorId: string;
33
+ timestamp: string;
34
+ };
35
+
36
+ // TODO(mykola): .
37
+ export class MessageNormalizer extends Resource {
38
+ private readonly _functionExecutor: FunctionExecutor;
39
+ private _queue: Queue<DataType.Message>;
40
+ private _cursor: QueueCursor;
41
+ private _messagesToProcess: MessageWithRangeId[] = [];
42
+ private _normalizationTask?: DeferredTask;
43
+ private _lastProcessedMessageIds?: string[];
44
+
45
+ constructor({ functionExecutor, queue, startingCursor }: SegmentsNormalizerParams) {
46
+ super();
47
+ this._functionExecutor = functionExecutor;
48
+ this._queue = queue;
49
+ this._cursor = startingCursor;
50
+ }
51
+
52
+ protected override async _open(): Promise<void> {
53
+ this._normalizationTask = new DeferredTask(this._ctx, () => this._processMessages());
54
+ const unsubscribe = effect(() => {
55
+ if (this._lifecycleState !== LifecycleState.OPEN) {
56
+ return;
57
+ }
58
+
59
+ this._messagesToProcess = this._queue.objects.filter((message) => {
60
+ const actorId = getActorId(message.sender);
61
+ return actorId === this._cursor.actorId && message.created >= this._cursor.timestamp;
62
+ });
63
+
64
+ this._normalizationTask!.schedule();
65
+ });
66
+ this._ctx.onDispose(() => unsubscribe());
67
+ }
68
+
69
+ // Need to unpack strings from blocks from messages run them through the function and then pack them back into blocks into messages.
70
+ private async _processMessages(): Promise<void> {
71
+ const messages = this._messagesToProcess;
72
+ this._messagesToProcess = [];
73
+ if (
74
+ this._lastProcessedMessageIds &&
75
+ messages.every((message) => this._lastProcessedMessageIds!.includes(message.id))
76
+ ) {
77
+ return;
78
+ }
79
+
80
+ this._lastProcessedMessageIds = messages.map((message) => message.id);
81
+
82
+ try {
83
+ // TODO(mykola): Executor should support timeout.
84
+ const response = await asyncTimeout(
85
+ this._functionExecutor.invoke(sentenceNormalization, { messages }),
86
+ PROCESSING_TIMEOUT,
87
+ );
88
+
89
+ this._writeMessages(response.sentences);
90
+ this._lastProcessedMessageIds.push(...response.sentences.map((sentence) => sentence.id));
91
+ if (response.sentences.length === 1 && response.sentences.at(-1)!.rangeId!.length > MAX_RANGE_ID_COUNT) {
92
+ log.warn('Sentence is too long', { messages });
93
+ this._cursor.timestamp = new Date(new Date(response.sentences[0].created).getTime() + 1).toISOString();
94
+ }
95
+ } catch {
96
+ log.error('Failed to normalize segments', { messages });
97
+ // If processing failed, emit the segments as is.
98
+ this._writeMessages(messages);
99
+ }
100
+ }
101
+
102
+ private _writeMessages(messages: MessageWithRangeId[]): void {
103
+ log.info('writing messages', { messages });
104
+ const lastMessage = messages[messages.length - 1];
105
+ this._cursor.timestamp = lastMessage.created;
106
+ this._queue.append(messages);
107
+ }
108
+ }
@@ -0,0 +1,142 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { effect } from '@preact/signals-core';
6
+ import { describe, test } from 'vitest';
7
+
8
+ import { AIServiceEdgeClient, OllamaClient } from '@dxos/ai';
9
+ import { AI_SERVICE_ENDPOINT } from '@dxos/ai/testing';
10
+ import { scheduleTaskInterval } from '@dxos/async';
11
+ import { Context } from '@dxos/context';
12
+ import { MemoryQueue } from '@dxos/echo-db';
13
+ import { createQueueDxn, ObjectId } from '@dxos/echo-schema';
14
+ import { FunctionExecutor, ServiceContainer } from '@dxos/functions';
15
+ import { log } from '@dxos/log';
16
+ import { type DataType } from '@dxos/schema';
17
+
18
+ import { MessageNormalizer } from './message-normalizer';
19
+ import { type MessageWithRangeId, sentenceNormalization } from './normalization';
20
+ import { getActorId } from './utils';
21
+
22
+ const sender: DataType.Actor = {
23
+ identityDid: 'did:key:123',
24
+ };
25
+
26
+ // Generate bunch of complex messages.
27
+ const messages: MessageWithRangeId[] = [
28
+ // Control message.
29
+ 'Hello, every body. We will talk about quantum entanglement today',
30
+
31
+ // Two sentences in one message.
32
+ 'hello every body we will talk about quantum entanglement today',
33
+
34
+ // Sentence broken into pieces.
35
+ 'quantum entanglement',
36
+ 'is one of the most...',
37
+ 'perplexing and fascinating phenomena',
38
+ 'in modern physics',
39
+
40
+ // Two sentences without separators.
41
+ 'it challenges our classical intuitions about how the universe works and forces us to reconsider our assumptions about space, time, and information',
42
+ 'at its core, quantum entanglement refers to a peculiar connection between two or more particles in such a way that the state of one particle instantly...',
43
+ 'determines the state of the other, no matter how far apart they may be — even if they are light-years away',
44
+
45
+ // 2 sentences are merged.
46
+ 'this seemingly instantaneous correlation between distant particles has baffled physicists since the early 20th century to understand entanglement, we',
47
+ 'first need to touch on the fundamentals of quantum mechanics',
48
+
49
+ // No punctuation.
50
+ 'in classical physics objects have well-defined properties such as position speed and momentum',
51
+ ].map((string, index) => ({
52
+ id: ObjectId.random(),
53
+ created: new Date(Date.now() + 1000 * index).toISOString(),
54
+ sender,
55
+ blocks: [{ type: 'transcription', started: new Date(Date.now() + 1000 * index).toISOString(), text: string }],
56
+ rangeId: [],
57
+ }));
58
+
59
+ const REMOTE_AI = true;
60
+
61
+ describe.skip('SentenceNormalization', () => {
62
+ const getExecutor = () => {
63
+ return new FunctionExecutor(
64
+ new ServiceContainer().setServices({
65
+ ai: {
66
+ client: REMOTE_AI
67
+ ? new AIServiceEdgeClient({
68
+ endpoint: AI_SERVICE_ENDPOINT.REMOTE,
69
+ defaultGenerationOptions: {
70
+ model: '@anthropic/claude-3-5-sonnet-20241022',
71
+ },
72
+ })
73
+ : new OllamaClient({
74
+ overrides: {
75
+ model: 'llama3.1:8b',
76
+ },
77
+ }),
78
+ },
79
+ }),
80
+ );
81
+ };
82
+
83
+ test('messages merging', { timeout: 120_000 }, async () => {
84
+ const executor = getExecutor();
85
+ const sentences: MessageWithRangeId[] = [];
86
+ let buffer: MessageWithRangeId[] = [];
87
+ let activeSentenceIndex = 0;
88
+ for (const message of messages) {
89
+ const result = await executor.invoke(sentenceNormalization, {
90
+ messages: [...buffer, message],
91
+ });
92
+ log.info('BEFORE sentence splicing', { activeSentenceIndex, sentences, inserting: result.sentences });
93
+ sentences.splice(activeSentenceIndex, sentences.length - activeSentenceIndex, ...result.sentences);
94
+ log.info('AFTER sentence splicing', { activeSentenceIndex, sentences });
95
+
96
+ if (sentences.length > 0) {
97
+ activeSentenceIndex = sentences.length - 1;
98
+ buffer = sentences.slice(activeSentenceIndex);
99
+ }
100
+ }
101
+ log.info('sentences', {
102
+ originalMessages: JSON.stringify(messages, null, 2),
103
+ sentences: JSON.stringify(sentences, null, 2),
104
+ });
105
+ throw new Error('test');
106
+ });
107
+
108
+ test.only('queue', { timeout: 120_000 }, async () => {
109
+ // Create queue.
110
+ const queue = new MemoryQueue<DataType.Message>(createQueueDxn());
111
+ const ctx = new Context();
112
+ let idx = 0;
113
+ scheduleTaskInterval(
114
+ ctx,
115
+ async () => {
116
+ if (idx >= messages.length) {
117
+ void ctx.dispose();
118
+ return;
119
+ }
120
+ await queue.append([messages[idx]]);
121
+ idx++;
122
+ },
123
+ 2_000,
124
+ );
125
+
126
+ // Create normalizer.
127
+ const normalizer = new MessageNormalizer({
128
+ functionExecutor: getExecutor(),
129
+ queue,
130
+ startingCursor: { actorId: getActorId(sender), timestamp: '0' },
131
+ });
132
+
133
+ // Start normalizer.
134
+ await normalizer.open();
135
+ effect(() => {
136
+ log.info('normalizer');
137
+ log.info(JSON.stringify(queue.objects, null, 2));
138
+ });
139
+
140
+ await new Promise(() => {});
141
+ });
142
+ });
@@ -0,0 +1,103 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Schema } from 'effect';
6
+
7
+ import { DEFAULT_EDGE_MODEL } from '@dxos/ai';
8
+ import { AISession } from '@dxos/assistant';
9
+ import { AiService, defineFunction } from '@dxos/functions';
10
+ import { ObjectId } from '@dxos/keys';
11
+ import { log } from '@dxos/log';
12
+ import { DataType } from '@dxos/schema';
13
+
14
+ const MessageWithRangeId = Schema.extend(
15
+ DataType.Message,
16
+ Schema.Struct({
17
+ // TODO(mykola): Move to meta in DataType.Message. Use `DataType.Message` instead.
18
+ rangeId: Schema.optional(Schema.Array(Schema.String)).annotations({
19
+ description: 'The IDs of the messages that contain the sentences.',
20
+ }),
21
+ }),
22
+ );
23
+
24
+ export interface MessageWithRangeId extends Schema.Schema.Type<typeof MessageWithRangeId> {}
25
+
26
+ export const NormalizationInput = Schema.Struct({
27
+ // TODO(mykola): Move to meta in DataType.Message. Use `DataType.Message` instead.
28
+ messages: Schema.Array(MessageWithRangeId).annotations({
29
+ description: 'Messages to normalize into sentences.',
30
+ }),
31
+ });
32
+
33
+ export const NormalizationOutput = Schema.Struct({
34
+ sentences: Schema.Array(MessageWithRangeId.pipe(Schema.mutable)).pipe(Schema.mutable).annotations({
35
+ description: 'The sentences of the transcript.',
36
+ }),
37
+ });
38
+
39
+ const prompt = `
40
+ You are observing a real-time transcript of a single person speaking.
41
+ The transcription is delivered in chunks of 10 seconds or less. As a result, individual sentences may be split across multiple messages, or multiple sentences may appear within a single message. Additionally, because this is real-time transcription, punctuation and capitalization may be incorrect or missing.
42
+
43
+ # Task Description:
44
+ - Your task is to detect and reconstruct broken or incomplete sentences by merging segments into coherent, grammatically correct sentences where appropriate.
45
+
46
+ # Input Format:
47
+ - The input is an array of messages that contain transcription blocks.
48
+ - Each message is a DataType.Message, as described in the output format.
49
+
50
+ # Output Format:
51
+ - You have been provided with the tool that defines the output format; make sure to query it.
52
+ - Do not output anything other than the expected format.
53
+
54
+ # Segment Handling Rules:
55
+ - Sort messages by timestamp.
56
+ - Leave ID of the first message in a sentence.
57
+ - Each divided sentence should be added to the output as a separate message or block within existing messages, preserving the original order.
58
+ - If one message contains multiple sentences, you should not split them.
59
+ - The last sentence may be incomplete; it should still be output as a separate block or message.
60
+ - Keep track of the original timestamps of the messages and blocks and, use the timestamp of the first message/block of a sentence as the 'started' field of the merged message.
61
+ - The 'rangeId' field of the merged message should include 'messageId'-s and 'rangeId'-s of all messages that have been used to construct this message.
62
+
63
+ # Punctuation and Capitalization:
64
+ - Do not rely on the original punctuation and capitalization—they may be incorrect.
65
+ - Use logical reasoning to apply appropriate punctuation (e.g., period, comma, question mark, exclamation mark) and capitalization.
66
+
67
+ # Restrictions:
68
+ - Do not alter the order of the original messages; maintain the natural flow of speech.
69
+ - Do not interpret or infer meaning beyond reconstructing sentences.
70
+ - Do not add or remove any words or phrases.
71
+ `;
72
+
73
+ export const sentenceNormalization = defineFunction({
74
+ description: 'Post process of transcription for sentence normalization',
75
+ inputSchema: NormalizationInput,
76
+ outputSchema: NormalizationOutput,
77
+ handler: async ({ data: { messages }, context }) => {
78
+ log.info('input', { messages });
79
+ const ai = context.getService(AiService);
80
+ const session = new AISession({ operationModel: 'configured' });
81
+
82
+ const response = await session.runStructured(NormalizationOutput, {
83
+ generationOptions: { model: DEFAULT_EDGE_MODEL },
84
+ client: ai.client,
85
+ tools: [],
86
+ artifacts: [],
87
+ history: [
88
+ {
89
+ id: ObjectId.random(),
90
+ role: 'user',
91
+ content: messages.map((message) => ({ type: 'text', text: JSON.stringify(message) })),
92
+ },
93
+ ],
94
+ prompt,
95
+ });
96
+
97
+ response.sentences.forEach((sentence) => {
98
+ sentence.id = ObjectId.random();
99
+ });
100
+ log.info('response', { response });
101
+ return response;
102
+ },
103
+ });
@@ -0,0 +1,9 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type DataType } from '@dxos/schema';
6
+
7
+ export const getActorId = (actor: DataType.Actor) => {
8
+ return actor.identityDid || actor.identityKey || actor.email || actor.name || '';
9
+ };
@@ -2,16 +2,18 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Schema, SchemaAST } from 'effect';
5
+ import { Schema } from 'effect';
6
6
  import { useEffect, useMemo, useState } from 'react';
7
7
 
8
- import { AIServiceEdgeClient } from '@dxos/assistant';
9
- import { AI_SERVICE_ENDPOINT } from '@dxos/assistant/testing';
8
+ import { AIServiceEdgeClient } from '@dxos/ai';
9
+ import { AI_SERVICE_ENDPOINT } from '@dxos/ai/testing';
10
+ import { extractionAnthropicFn, processTranscriptMessage } from '@dxos/assistant';
10
11
  import { scheduleTaskInterval } from '@dxos/async';
11
12
  import { Filter, type Queue } from '@dxos/client/echo';
12
13
  import { Context } from '@dxos/context';
13
14
  import { Type } from '@dxos/echo';
14
15
  import { create, createQueueDxn, ObjectId } from '@dxos/echo-schema';
16
+ import { FunctionExecutor, ServiceContainer } from '@dxos/functions';
15
17
  import { IdentityDid } from '@dxos/keys';
16
18
  import { log } from '@dxos/log';
17
19
  import { faker } from '@dxos/random';
@@ -19,20 +21,18 @@ import { live, makeRef, useQueue, type Space } from '@dxos/react-client/echo';
19
21
  import { DataType } from '@dxos/schema';
20
22
  import { Testing, seedTestData } from '@dxos/schema/testing';
21
23
 
22
- import { processTranscriptMessage } from '../entity-extraction';
23
-
24
24
  // TODO(burdon): Reconcile with plugin-markdown. Move to @dxos/schema/testing.
25
25
  export const TestItem = Schema.Struct({
26
26
  title: Schema.String.annotations({
27
- [SchemaAST.TitleAnnotationId]: 'Title',
28
- [SchemaAST.DescriptionAnnotationId]: 'Product title',
27
+ title: 'Title',
28
+ description: 'Product title',
29
29
  }),
30
30
  description: Schema.String.annotations({
31
- [SchemaAST.TitleAnnotationId]: 'Description',
32
- [SchemaAST.DescriptionAnnotationId]: 'Product description',
31
+ title: 'Description',
32
+ description: 'Product description',
33
33
  }),
34
34
  }).pipe(
35
- Type.def({
35
+ Type.Obj({
36
36
  typename: 'dxos.org/type/Test',
37
37
  version: '0.1.0',
38
38
  }),
@@ -88,7 +88,7 @@ export class MessageBuilder extends AbstractMessageBuilder {
88
88
  };
89
89
  }
90
90
 
91
- next() {
91
+ next(): Date {
92
92
  this.start = new Date(this.start.getTime() + Math.random() * 10_000);
93
93
  return this.start;
94
94
  }
@@ -100,11 +100,13 @@ class EntityExtractionMessageBuilder extends AbstractMessageBuilder {
100
100
  endpoint: AI_SERVICE_ENDPOINT.REMOTE,
101
101
  });
102
102
 
103
+ executor = new FunctionExecutor(new ServiceContainer().setServices({ ai: { client: this.aiService } }));
104
+
103
105
  space: Space | undefined;
104
106
  currentMessage: number = 0;
105
107
  transcriptMessages: DataType.Message[] = [];
106
108
 
107
- async connect(space: Space) {
109
+ async connect(space: Space): Promise<void> {
108
110
  this.space = space;
109
111
  const { transcriptMessages } = await seedTestData(space);
110
112
  this.transcriptMessages = transcriptMessages;
@@ -127,11 +129,9 @@ class EntityExtractionMessageBuilder extends AbstractMessageBuilder {
127
129
  this.currentMessage = this.currentMessage % this.transcriptMessages.length;
128
130
 
129
131
  const { message: enhancedMessage } = await processTranscriptMessage({
130
- message,
131
- aiService: this.aiService,
132
- context: {
133
- objects,
134
- },
132
+ input: { message },
133
+ executor: this.executor,
134
+ function: extractionAnthropicFn,
135
135
  });
136
136
 
137
137
  return enhancedMessage;