@dxos/plugin-transcription 0.8.2-main.36232bc → 0.8.2-main.5ca3450

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 (139) hide show
  1. package/dist/lib/browser/{TranscriptContainer-2VFHUHLE.mjs → TranscriptContainer-3LU3XBEB.mjs} +2 -2
  2. package/dist/lib/browser/{app-graph-builder-TDP6PYV6.mjs → app-graph-builder-YXELPN6F.mjs} +19 -20
  3. package/dist/lib/browser/app-graph-builder-YXELPN6F.mjs.map +7 -0
  4. package/dist/lib/browser/{chunk-KSUYWWIU.mjs → chunk-GWY2Q2NE.mjs} +6 -6
  5. package/dist/lib/browser/chunk-GWY2Q2NE.mjs.map +7 -0
  6. package/dist/lib/browser/{chunk-NFVDICSJ.mjs → chunk-HNIKXVCG.mjs} +8 -7
  7. package/dist/lib/browser/chunk-HNIKXVCG.mjs.map +7 -0
  8. package/dist/lib/browser/{chunk-O6RY7FNK.mjs → chunk-HRDAILQX.mjs} +2 -2
  9. package/dist/lib/browser/{chunk-YRWBY6UK.mjs → chunk-TGOKX32G.mjs} +17 -15
  10. package/dist/lib/browser/chunk-TGOKX32G.mjs.map +7 -0
  11. package/dist/lib/browser/index.mjs +6 -6
  12. package/dist/lib/browser/index.mjs.map +3 -3
  13. package/dist/lib/browser/{intent-resolver-ZWKYRFE7.mjs → intent-resolver-BBB3DWV4.mjs} +2 -2
  14. package/dist/lib/browser/meta.json +1 -1
  15. package/dist/lib/browser/{react-surface-F32UNCKZ.mjs → react-surface-R277DACJ.mjs} +4 -4
  16. package/dist/lib/browser/{settings-6YAHKVKX.mjs → settings-I226DZ27.mjs} +2 -2
  17. package/dist/lib/browser/{transcriber-MSBS4VBI.mjs → transcriber-QRSS6X6S.mjs} +3 -3
  18. package/dist/lib/browser/types/index.mjs +1 -1
  19. package/dist/lib/node/{TranscriptContainer-E2D7PKO3.cjs → TranscriptContainer-DICOMZLM.cjs} +7 -7
  20. package/dist/lib/node/{TranscriptContainer-E2D7PKO3.cjs.map → TranscriptContainer-DICOMZLM.cjs.map} +2 -2
  21. package/dist/lib/node/{app-graph-builder-W4VDMVGV.cjs → app-graph-builder-I6LYVIYY.cjs} +28 -29
  22. package/dist/lib/node/app-graph-builder-I6LYVIYY.cjs.map +7 -0
  23. package/dist/lib/node/{chunk-IXU57SCA.cjs → chunk-34WFY7M7.cjs} +18 -16
  24. package/dist/lib/node/chunk-34WFY7M7.cjs.map +7 -0
  25. package/dist/lib/node/{chunk-NBC6V3M2.cjs → chunk-4JOJCZPJ.cjs} +11 -10
  26. package/dist/lib/node/chunk-4JOJCZPJ.cjs.map +7 -0
  27. package/dist/lib/node/{chunk-TJMZ26GS.cjs → chunk-K553L7CZ.cjs} +5 -5
  28. package/dist/lib/node/{chunk-7XIIUVN3.cjs → chunk-RK4BEN5E.cjs} +9 -9
  29. package/dist/lib/node/chunk-RK4BEN5E.cjs.map +7 -0
  30. package/dist/lib/node/index.cjs +27 -27
  31. package/dist/lib/node/index.cjs.map +3 -3
  32. package/dist/lib/node/{intent-resolver-RM4JOCDV.cjs → intent-resolver-7XY3WITN.cjs} +7 -7
  33. package/dist/lib/node/meta.json +1 -1
  34. package/dist/lib/node/{react-surface-YQHBGPOC.cjs → react-surface-HUSWAORU.cjs} +10 -10
  35. package/dist/lib/node/{settings-ZMB4XRWS.cjs → settings-NDMU3EWQ.cjs} +7 -7
  36. package/dist/lib/node/{transcriber-55OE4X6I.cjs → transcriber-UZJMG44C.cjs} +8 -8
  37. package/dist/lib/node/types/index.cjs +7 -7
  38. package/dist/lib/node/types/index.cjs.map +1 -1
  39. package/dist/lib/node-esm/{TranscriptContainer-5N3BSK2S.mjs → TranscriptContainer-K4E4P5T6.mjs} +2 -2
  40. package/dist/lib/node-esm/{app-graph-builder-DDDVKUHS.mjs → app-graph-builder-6FY2UQOH.mjs} +19 -20
  41. package/dist/lib/node-esm/app-graph-builder-6FY2UQOH.mjs.map +7 -0
  42. package/dist/lib/node-esm/{chunk-HZBSWUJH.mjs → chunk-3I7AC3D3.mjs} +2 -2
  43. package/dist/lib/node-esm/{chunk-4RMJO6QQ.mjs → chunk-6C34FO4C.mjs} +8 -7
  44. package/dist/lib/node-esm/chunk-6C34FO4C.mjs.map +7 -0
  45. package/dist/lib/node-esm/{chunk-UWF6LM27.mjs → chunk-CKANLRS4.mjs} +6 -6
  46. package/dist/lib/node-esm/chunk-CKANLRS4.mjs.map +7 -0
  47. package/dist/lib/node-esm/{chunk-OS2ITZUL.mjs → chunk-KUQ3ZTRX.mjs} +17 -15
  48. package/dist/lib/node-esm/chunk-KUQ3ZTRX.mjs.map +7 -0
  49. package/dist/lib/node-esm/index.mjs +6 -6
  50. package/dist/lib/node-esm/index.mjs.map +3 -3
  51. package/dist/lib/node-esm/{intent-resolver-HDRFXMKP.mjs → intent-resolver-ACGAPLDZ.mjs} +2 -2
  52. package/dist/lib/node-esm/meta.json +1 -1
  53. package/dist/lib/node-esm/{react-surface-DRDNXTFZ.mjs → react-surface-G2OY4MWL.mjs} +4 -4
  54. package/dist/lib/node-esm/{settings-I35TVDUG.mjs → settings-O7X2UQQG.mjs} +2 -2
  55. package/dist/lib/node-esm/{transcriber-HH7EMCGH.mjs → transcriber-NVVFH7IF.mjs} +3 -3
  56. package/dist/lib/node-esm/types/index.mjs +1 -1
  57. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  58. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  59. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  60. package/dist/types/src/components/Transcript/Transcript.d.ts +3 -3
  61. package/dist/types/src/components/Transcript/Transcript.d.ts.map +1 -1
  62. package/dist/types/src/components/Transcript/Transcript.stories.d.ts +2 -2
  63. package/dist/types/src/components/Transcript/Transcript.stories.d.ts.map +1 -1
  64. package/dist/types/src/components/Transcript/deprecated/OldTranscript.d.ts +10 -10
  65. package/dist/types/src/components/Transcript/deprecated/OldTranscript.d.ts.map +1 -1
  66. package/dist/types/src/components/Transcript/transcript-extension.d.ts +2 -2
  67. package/dist/types/src/components/Transcript/transcript-extension.d.ts.map +1 -1
  68. package/dist/types/src/components/TranscriptionSettings/TranscriptionSettings.d.ts.map +1 -1
  69. package/dist/types/src/components/transcription.stories.d.ts.map +1 -1
  70. package/dist/types/src/entity-extraction/entity-extraction.d.ts +3 -3
  71. package/dist/types/src/entity-extraction/entity-extraction.d.ts.map +1 -1
  72. package/dist/types/src/hooks/useAudioFile.d.ts.map +1 -1
  73. package/dist/types/src/hooks/useAudioTrack.d.ts.map +1 -1
  74. package/dist/types/src/hooks/useQueueModelAdapter.d.ts.map +1 -1
  75. package/dist/types/src/hooks/useTranscriber.d.ts.map +1 -1
  76. package/dist/types/src/hooks/useVoiceInput.d.ts.map +1 -1
  77. package/dist/types/src/testing/testing.d.ts +11 -10
  78. package/dist/types/src/testing/testing.d.ts.map +1 -1
  79. package/dist/types/src/transcriber/transcriber.d.ts +2 -2
  80. package/dist/types/src/transcriber/transcriber.d.ts.map +1 -1
  81. package/dist/types/src/transcriber/transcription-manager.d.ts +2 -2
  82. package/dist/types/src/transcriber/transcription-manager.d.ts.map +1 -1
  83. package/dist/types/src/translations.d.ts +2 -20
  84. package/dist/types/src/translations.d.ts.map +1 -1
  85. package/dist/types/src/types/schema.d.ts +26 -19
  86. package/dist/types/src/types/schema.d.ts.map +1 -1
  87. package/dist/types/src/types/types.d.ts +10 -10
  88. package/dist/types/src/types/types.d.ts.map +1 -1
  89. package/dist/types/src/util/array.d.ts.map +1 -1
  90. package/dist/types/src/util/get-time-str.d.ts.map +1 -1
  91. package/dist/types/src/util/monitor-audio-level.d.ts.map +1 -1
  92. package/dist/types/tsconfig.tsbuildinfo +1 -1
  93. package/package.json +51 -49
  94. package/src/TranscriptionPlugin.tsx +2 -2
  95. package/src/capabilities/app-graph-builder.ts +10 -10
  96. package/src/components/Transcript/Transcript.stories.tsx +5 -5
  97. package/src/components/Transcript/Transcript.tsx +10 -4
  98. package/src/components/Transcript/deprecated/OldTranscript.tsx +19 -13
  99. package/src/components/Transcript/transcript-extension.ts +3 -3
  100. package/src/components/TranscriptContainer.tsx +2 -2
  101. package/src/components/transcription.stories.tsx +14 -8
  102. package/src/entity-extraction/entity-extraction.test.ts +23 -4
  103. package/src/entity-extraction/entity-extraction.ts +11 -6
  104. package/src/model/model.test.ts +14 -10
  105. package/src/testing/testing.ts +34 -21
  106. package/src/transcriber/transcriber.browser.test.ts +3 -3
  107. package/src/transcriber/transcriber.ts +6 -3
  108. package/src/transcriber/transcription-manager.ts +8 -8
  109. package/src/types/schema.ts +10 -8
  110. package/src/types/types.ts +12 -10
  111. package/dist/lib/browser/app-graph-builder-TDP6PYV6.mjs.map +0 -7
  112. package/dist/lib/browser/chunk-KSUYWWIU.mjs.map +0 -7
  113. package/dist/lib/browser/chunk-NFVDICSJ.mjs.map +0 -7
  114. package/dist/lib/browser/chunk-YRWBY6UK.mjs.map +0 -7
  115. package/dist/lib/node/app-graph-builder-W4VDMVGV.cjs.map +0 -7
  116. package/dist/lib/node/chunk-7XIIUVN3.cjs.map +0 -7
  117. package/dist/lib/node/chunk-IXU57SCA.cjs.map +0 -7
  118. package/dist/lib/node/chunk-NBC6V3M2.cjs.map +0 -7
  119. package/dist/lib/node-esm/app-graph-builder-DDDVKUHS.mjs.map +0 -7
  120. package/dist/lib/node-esm/chunk-4RMJO6QQ.mjs.map +0 -7
  121. package/dist/lib/node-esm/chunk-OS2ITZUL.mjs.map +0 -7
  122. package/dist/lib/node-esm/chunk-UWF6LM27.mjs.map +0 -7
  123. /package/dist/lib/browser/{TranscriptContainer-2VFHUHLE.mjs.map → TranscriptContainer-3LU3XBEB.mjs.map} +0 -0
  124. /package/dist/lib/browser/{chunk-O6RY7FNK.mjs.map → chunk-HRDAILQX.mjs.map} +0 -0
  125. /package/dist/lib/browser/{intent-resolver-ZWKYRFE7.mjs.map → intent-resolver-BBB3DWV4.mjs.map} +0 -0
  126. /package/dist/lib/browser/{react-surface-F32UNCKZ.mjs.map → react-surface-R277DACJ.mjs.map} +0 -0
  127. /package/dist/lib/browser/{settings-6YAHKVKX.mjs.map → settings-I226DZ27.mjs.map} +0 -0
  128. /package/dist/lib/browser/{transcriber-MSBS4VBI.mjs.map → transcriber-QRSS6X6S.mjs.map} +0 -0
  129. /package/dist/lib/node/{chunk-TJMZ26GS.cjs.map → chunk-K553L7CZ.cjs.map} +0 -0
  130. /package/dist/lib/node/{intent-resolver-RM4JOCDV.cjs.map → intent-resolver-7XY3WITN.cjs.map} +0 -0
  131. /package/dist/lib/node/{react-surface-YQHBGPOC.cjs.map → react-surface-HUSWAORU.cjs.map} +0 -0
  132. /package/dist/lib/node/{settings-ZMB4XRWS.cjs.map → settings-NDMU3EWQ.cjs.map} +0 -0
  133. /package/dist/lib/node/{transcriber-55OE4X6I.cjs.map → transcriber-UZJMG44C.cjs.map} +0 -0
  134. /package/dist/lib/node-esm/{TranscriptContainer-5N3BSK2S.mjs.map → TranscriptContainer-K4E4P5T6.mjs.map} +0 -0
  135. /package/dist/lib/node-esm/{chunk-HZBSWUJH.mjs.map → chunk-3I7AC3D3.mjs.map} +0 -0
  136. /package/dist/lib/node-esm/{intent-resolver-HDRFXMKP.mjs.map → intent-resolver-ACGAPLDZ.mjs.map} +0 -0
  137. /package/dist/lib/node-esm/{react-surface-DRDNXTFZ.mjs.map → react-surface-G2OY4MWL.mjs.map} +0 -0
  138. /package/dist/lib/node-esm/{settings-I35TVDUG.mjs.map → settings-O7X2UQQG.mjs.map} +0 -0
  139. /package/dist/lib/node-esm/{transcriber-HH7EMCGH.mjs.map → transcriber-NVVFH7IF.mjs.map} +0 -0
@@ -20,7 +20,7 @@ import { useMembers, useSpace } from '@dxos/react-client/echo';
20
20
  import { IconButton, Toolbar } from '@dxos/react-ui';
21
21
  import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
22
22
  import { defaultTx } from '@dxos/react-ui-theme';
23
- import { Contact, Organization, type MessageType } from '@dxos/schema';
23
+ import { DataType } from '@dxos/schema';
24
24
  import { Testing } from '@dxos/schema/testing';
25
25
  import { withLayout } from '@dxos/storybook-utils';
26
26
 
@@ -69,7 +69,7 @@ const TranscriptContainer: FC<
69
69
  );
70
70
  };
71
71
 
72
- type StoryProps = { messages?: MessageType[] } & Pick<TranscriptProps, 'ignoreAttention' | 'attendableId'>;
72
+ type StoryProps = { messages?: DataType.Message[] } & Pick<TranscriptProps, 'ignoreAttention' | 'attendableId'>;
73
73
 
74
74
  /**
75
75
  * Basic story mutates array of messages.
@@ -78,11 +78,11 @@ const BasicStory = ({ messages: initialMessages = [], ...props }: StoryProps) =>
78
78
  const [reset, setReset] = useState({});
79
79
  const builder = useMemo(() => new MessageBuilder(), []);
80
80
  const model = useMemo(
81
- () => new SerializationModel<MessageType>(renderMarkdown([]), initialMessages),
81
+ () => new SerializationModel<DataType.Message>(renderMarkdown([]), initialMessages),
82
82
  [initialMessages, reset],
83
83
  );
84
84
  const [running, setRunning] = useState(true);
85
- const [currentMessage, setCurrentMessage] = useState<MessageType | null>(null);
85
+ const [currentMessage, setCurrentMessage] = useState<DataType.Message | null>(null);
86
86
  useEffect(() => {
87
87
  if (!running) {
88
88
  return;
@@ -186,7 +186,7 @@ const meta: Meta<typeof QueueStory> = {
186
186
  ThemePlugin({ tx: defaultTx }),
187
187
  StorybookLayoutPlugin(),
188
188
  ClientPlugin({
189
- types: [TestItem, Testing.DocumentType, Contact, Organization],
189
+ types: [TestItem, Testing.DocumentType, DataType.Person, DataType.Organization],
190
190
  onClientInitialized: async (_, client) => {
191
191
  await client.halo.createIdentity();
192
192
  },
@@ -18,7 +18,7 @@ import {
18
18
  useTextEditor,
19
19
  } from '@dxos/react-ui-editor';
20
20
  import { mx } from '@dxos/react-ui-theme';
21
- import { type MessageType } from '@dxos/schema';
21
+ import { type DataType } from '@dxos/schema';
22
22
  import { isNotFalsy } from '@dxos/util';
23
23
 
24
24
  import { transcript } from './transcript-extension';
@@ -27,7 +27,7 @@ import { type TranscriptType } from '../../types';
27
27
 
28
28
  export const renderMarkdown =
29
29
  (identities: Identity[]) =>
30
- (message: MessageType, index: number, debug = false): string[] => {
30
+ (message: DataType.Message, index: number, debug = false): string[] => {
31
31
  if (message.sender.role === 'assistant') {
32
32
  // Start/stop block.
33
33
  return [message.blocks.find((block) => block.type === 'transcription')?.text ?? '', ''];
@@ -53,7 +53,7 @@ export const renderMarkdown =
53
53
  export type TranscriptProps = ThemedClassName<{
54
54
  transcript?: TranscriptType;
55
55
  space?: Space;
56
- model: SerializationModel<MessageType>;
56
+ model: SerializationModel<DataType.Message>;
57
57
  // TODO(wittjosiah): Move to container.
58
58
  attendableId?: string;
59
59
  ignoreAttention?: boolean;
@@ -90,5 +90,11 @@ export const Transcript = ({
90
90
  };
91
91
  }, [space, model]);
92
92
 
93
- return <div ref={parentRef} className={mx('flex grow overflow-hidden', editorWidth, classNames)} />;
93
+ return (
94
+ <div
95
+ ref={parentRef}
96
+ className={mx('flex grow overflow-hidden', editorWidth, classNames)}
97
+ data-popover-collision-boundary={true}
98
+ />
99
+ );
94
100
  };
@@ -3,11 +3,12 @@
3
3
  //
4
4
 
5
5
  import { intervalToDuration } from 'date-fns/intervalToDuration';
6
+ import { Schema } from 'effect';
6
7
  import { yieldOrContinue } from 'main-thread-scheduling';
7
8
  import React, { type FC, useCallback, useEffect, useMemo, useRef, useState, type WheelEvent } from 'react';
8
9
  import { type OnResizeCallback, useResizeDetector } from 'react-resize-detector';
9
10
 
10
- import { EchoObject, S } from '@dxos/echo-schema';
11
+ import { Type } from '@dxos/echo';
11
12
  import { IconButton, type ThemedClassName, useTranslation } from '@dxos/react-ui';
12
13
  import { useAttention } from '@dxos/react-ui-attention';
13
14
  import {
@@ -25,25 +26,30 @@ import { TRANSCRIPTION_PLUGIN } from '../../../meta';
25
26
  /**
26
27
  * Transcription fragment.
27
28
  */
28
- const TranscriptSegment = S.Struct({
29
+ const TranscriptSegment = Schema.Struct({
29
30
  // TODO(burdon): TS from service is not Unix TS (x1000).
30
- started: S.String,
31
- text: S.String,
31
+ started: Schema.String,
32
+ text: Schema.String,
32
33
  });
33
34
 
34
- type TranscriptSegment = S.Schema.Type<typeof TranscriptSegment>;
35
+ type TranscriptSegment = Schema.Schema.Type<typeof TranscriptSegment>;
35
36
 
36
37
  /**
37
38
  * Transcription block (from single speaker).
38
39
  */
39
- const TranscriptBlock = S.Struct({
40
- id: S.String,
41
- authorName: S.optional(S.String), // TODO(burdon): Replace with identityDid.
42
- authorHue: S.optional(S.String), // TOOD(burdon): Remove.
43
- segments: S.Array(TranscriptSegment),
44
- }).pipe(EchoObject({ typename: 'dxos.org/type/TranscriptBlock', version: '0.1.0' }));
45
-
46
- type TranscriptBlock = S.Schema.Type<typeof TranscriptBlock>;
40
+ const TranscriptBlock = Schema.Struct({
41
+ id: Schema.String,
42
+ authorName: Schema.optional(Schema.String), // TODO(burdon): Replace with identityDid.
43
+ authorHue: Schema.optional(Schema.String), // TOOD(burdon): Remove.
44
+ segments: Schema.Array(TranscriptSegment),
45
+ }).pipe(
46
+ Type.def({
47
+ typename: 'dxos.org/type/TranscriptBlock',
48
+ version: '0.1.0',
49
+ }),
50
+ );
51
+
52
+ type TranscriptBlock = Schema.Schema.Type<typeof TranscriptBlock>;
47
53
 
48
54
  // TODO(burdon): Actions (e.g., mark, summarize, translate, label, delete).
49
55
 
@@ -9,7 +9,7 @@ import { intervalToDuration } from 'date-fns/intervalToDuration';
9
9
 
10
10
  import { type CleanupFn, addEventListener, combine } from '@dxos/async';
11
11
  import { type RenderCallback } from '@dxos/react-ui-editor';
12
- import { type MessageType } from '@dxos/schema';
12
+ import { type DataType } from '@dxos/schema';
13
13
 
14
14
  import { DocumentAdapter, type SerializationModel } from '../../model';
15
15
 
@@ -17,7 +17,7 @@ import { DocumentAdapter, type SerializationModel } from '../../model';
17
17
  * Data structure that maps Chunks queue to lines with transcript state.
18
18
  */
19
19
  export type TranscriptOptions = {
20
- model: SerializationModel<MessageType>;
20
+ model: SerializationModel<DataType.Message>;
21
21
  started?: Date;
22
22
  renderButton?: RenderCallback<{ onClick: () => void }>;
23
23
  };
@@ -213,7 +213,7 @@ class TimestampMarker extends GutterMarker {
213
213
  }
214
214
  }
215
215
 
216
- const getStartTime = (started?: Date, message?: MessageType): Date | undefined => {
216
+ const getStartTime = (started?: Date, message?: DataType.Message): Date | undefined => {
217
217
  if (started) {
218
218
  return started;
219
219
  }
@@ -7,7 +7,7 @@ import React, { type FC } from 'react';
7
7
  import { fullyQualifiedId, getSpace } from '@dxos/client/echo';
8
8
  import { useMembers, useQueue } from '@dxos/react-client/echo';
9
9
  import { StackItem } from '@dxos/react-ui-stack';
10
- import { type MessageType } from '@dxos/schema';
10
+ import { type DataType } from '@dxos/schema';
11
11
 
12
12
  import { Transcript, renderMarkdown } from './Transcript';
13
13
  import { useQueueModelAdapter } from '../hooks';
@@ -17,7 +17,7 @@ export const TranscriptionContainer: FC<{ role: string; transcript: TranscriptTy
17
17
  const attendableId = fullyQualifiedId(transcript);
18
18
  const space = getSpace(transcript);
19
19
  const members = useMembers(space?.key).map((member) => member.identity);
20
- const queue = useQueue<MessageType>(transcript.queue.dxn, { pollInterval: 1_000 });
20
+ const queue = useQueue<DataType.Message>(transcript.queue.dxn, { pollInterval: 1_000 });
21
21
  const model = useQueueModelAdapter(renderMarkdown(members), queue);
22
22
 
23
23
  return (
@@ -33,7 +33,7 @@ import { createQueueDxn, useQueue, useSpace } from '@dxos/react-client/echo';
33
33
  import { IconButton, Toolbar } from '@dxos/react-ui';
34
34
  import { ScrollContainer } from '@dxos/react-ui-components';
35
35
  import { defaultTx } from '@dxos/react-ui-theme';
36
- import { Contact, MessageType, Organization } from '@dxos/schema';
36
+ import { DataType } from '@dxos/schema';
37
37
  import { seedTestData, Testing } from '@dxos/schema/testing';
38
38
  import { withLayout, withTheme } from '@dxos/storybook-utils';
39
39
 
@@ -46,7 +46,7 @@ import { TestItem } from '../testing';
46
46
  import { type TranscriberParams } from '../transcriber';
47
47
 
48
48
  const TranscriptionStory: FC<{
49
- model: SerializationModel<MessageType>;
49
+ model: SerializationModel<DataType.Message>;
50
50
  running: boolean;
51
51
  onRunningChange: Dispatch<SetStateAction<boolean>>;
52
52
  }> = ({ model, running, onRunningChange }) => {
@@ -81,14 +81,14 @@ const Microphone = ({ entityExtraction }: { entityExtraction?: boolean }) => {
81
81
 
82
82
  // Queue.
83
83
  const queueDxn = useMemo(() => createQueueDxn(), []);
84
- const queue = useMemo(() => new MemoryQueue<MessageType>(queueDxn), [queueDxn]);
84
+ const queue = useMemo(() => new MemoryQueue<DataType.Message>(queueDxn), [queueDxn]);
85
85
  const model = useQueueModelAdapter(renderMarkdown([]), queue);
86
86
  const space = useSpace();
87
87
 
88
88
  // Transcriber.
89
89
  const handleSegments = useCallback<TranscriberParams['onSegments']>(
90
90
  async (blocks) => {
91
- const message = create(MessageType, { sender: { name: 'You' }, created: new Date().toISOString(), blocks });
91
+ const message = create(DataType.Message, { sender: { name: 'You' }, created: new Date().toISOString(), blocks });
92
92
 
93
93
  if (entityExtraction) {
94
94
  if (!space) {
@@ -97,7 +97,13 @@ const Microphone = ({ entityExtraction }: { entityExtraction?: boolean }) => {
97
97
  }
98
98
  // TODO(dmaretskyi): Move to vector search index.
99
99
  const { objects } = await space.db
100
- .query(Filter.or(Filter.schema(Contact), Filter.schema(Organization), Filter.schema(Testing.DocumentType)))
100
+ .query(
101
+ Filter.or(
102
+ Filter.schema(DataType.Person),
103
+ Filter.schema(DataType.Organization),
104
+ Filter.schema(Testing.DocumentType),
105
+ ),
106
+ )
101
107
  .run();
102
108
 
103
109
  log.info('context', { objects });
@@ -176,11 +182,11 @@ const AudioFile = ({ queueDxn, audioUrl }: { queueDxn: DXN; audioUrl: string; tr
176
182
  }, [audio, running]);
177
183
 
178
184
  // Transcriber.
179
- const queue = useQueue<MessageType>(queueDxn, { pollInterval: 500 });
185
+ const queue = useQueue<DataType.Message>(queueDxn, { pollInterval: 500 });
180
186
  const model = useQueueModelAdapter(renderMarkdown([]), queue);
181
187
  const handleSegments = useCallback<TranscriberParams['onSegments']>(
182
188
  async (blocks) => {
183
- const message = create(MessageType, { sender: { name: 'You' }, created: new Date().toISOString(), blocks });
189
+ const message = create(DataType.Message, { sender: { name: 'You' }, created: new Date().toISOString(), blocks });
184
190
  void queue?.append([message]);
185
191
  },
186
192
  [queue],
@@ -224,7 +230,7 @@ const meta: Meta<typeof AudioFile> = {
224
230
  ThemePlugin({ tx: defaultTx }),
225
231
  StorybookLayoutPlugin(),
226
232
  ClientPlugin({
227
- types: [TestItem, Contact, Organization, Testing.DocumentType],
233
+ types: [TestItem, DataType.Person, DataType.Organization, Testing.DocumentType],
228
234
  onClientInitialized: async (_, client) => {
229
235
  await client.halo.createIdentity();
230
236
  await client.spaces.waitUntilReady();
@@ -17,7 +17,7 @@ const aiService = new AIServiceEdgeClient({
17
17
  });
18
18
 
19
19
  describe.skip('EntityExtraction', { timeout: 180_000 }, () => {
20
- test('should process a transcript block', async () => {
20
+ test.skip('should process a transcript block', async () => {
21
21
  const { transcriptMessages, documents, contacts } = await createTestData();
22
22
 
23
23
  log.info('context', { documents, contacts });
@@ -35,11 +35,11 @@ describe.skip('EntityExtraction', { timeout: 180_000 }, () => {
35
35
  }
36
36
  });
37
37
 
38
- test.skip('computational irreducibility', async () => {
39
- const { transcriptMessages, documents, contacts } = await createTestData();
38
+ test.only('computational irreducibility', async () => {
39
+ const { transcriptWoflram, documents, contacts } = await createTestData();
40
40
 
41
41
  log.info('context', { documents, contacts });
42
- const message = transcriptMessages[0];
42
+ const message = transcriptWoflram[0];
43
43
  log.info('input', message);
44
44
 
45
45
  await Promise.all(
@@ -55,6 +55,25 @@ describe.skip('EntityExtraction', { timeout: 180_000 }, () => {
55
55
  }),
56
56
  );
57
57
  });
58
+
59
+ test('org and document linking', async () => {
60
+ const { transcriptJosiah, documents, contacts, organizations } = await createTestData();
61
+
62
+ log.info('context', { contacts, organizations, documents });
63
+
64
+ for (const message of transcriptJosiah) {
65
+ log.info('input', message);
66
+
67
+ const { message: enhancedMessage } = await processTranscriptMessage({
68
+ message,
69
+ aiService,
70
+ context: {
71
+ objects: [...documents, ...Object.values(contacts), ...Object.values(organizations)],
72
+ },
73
+ });
74
+ log.info('output', enhancedMessage);
75
+ }
76
+ });
58
77
  });
59
78
 
60
79
  describe('postprocessText', () => {
@@ -8,14 +8,15 @@ import { createTemplate, Message, structuredOutputParser } from '@dxos/artifact'
8
8
  import type { AIServiceClient } from '@dxos/assistant';
9
9
  import { MixedStreamParser } from '@dxos/assistant';
10
10
  import { asyncTimeout } from '@dxos/async';
11
- import { type BaseEchoObject, create } from '@dxos/echo-schema';
11
+ import { type BaseEchoObject, create, ObjectId } from '@dxos/echo-schema';
12
+ import { DXN } from '@dxos/keys';
12
13
  import { log } from '@dxos/log';
13
- import { MessageType } from '@dxos/schema';
14
+ import { DataType } from '@dxos/schema';
14
15
 
15
16
  import SYSTEM_PROMPT from './system-prompt.tpl?raw';
16
17
 
17
18
  type ProcessTranscriptMessageParams = {
18
- message: MessageType;
19
+ message: DataType.Message;
19
20
  aiService: AIServiceClient;
20
21
  context: {
21
22
  objects?: BaseEchoObject[];
@@ -37,7 +38,7 @@ type ProcessTranscriptMessageParams = {
37
38
  };
38
39
 
39
40
  type ProcessTranscriptMessageResult = {
40
- message: MessageType;
41
+ message: DataType.Message;
41
42
  timeElapsed: number;
42
43
  };
43
44
 
@@ -97,7 +98,7 @@ export const processTranscriptMessage = async (
97
98
  log.info('entity extraction result', { refs: result.references });
98
99
 
99
100
  return {
100
- message: create(MessageType, {
101
+ message: create(DataType.Message, {
101
102
  ...params.message,
102
103
  blocks: params.message.blocks.map((block, i) =>
103
104
  block.type !== 'transcription'
@@ -136,9 +137,13 @@ export const processTranscriptMessage = async (
136
137
  // TODO(dmaretskyi): Lookup and verifiy ids from provided context.
137
138
  export const postprocessText = (text: string, quotes: ReferencedQuotes) => {
138
139
  for (const quote of quotes.references) {
140
+ if (!ObjectId.isValid(quote.id)) {
141
+ continue;
142
+ }
143
+
139
144
  // Use a case-insensitive regular expression to replace the quote
140
145
  const regex = new RegExp(quote.quote.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
141
- text = text.replace(regex, `[${quote.quote}][dxn:echo:@:${quote.id}]`);
146
+ text = text.replace(regex, `[${quote.quote}][${DXN.fromLocalObjectId(quote.id).toString()}]`);
142
147
  }
143
148
  return text;
144
149
  };
@@ -5,11 +5,15 @@
5
5
  import { EditorView } from '@codemirror/view';
6
6
  import { describe, test } from 'vitest';
7
7
 
8
- import { type MessageType } from '@dxos/schema';
8
+ import { type DataType } from '@dxos/schema';
9
9
 
10
10
  import { SerializationModel, DocumentAdapter, type ChunkRenderer } from './model';
11
11
 
12
- const blockToMarkdown: ChunkRenderer<MessageType> = (message: MessageType, index: number, debug = true): string[] => {
12
+ const blockToMarkdown: ChunkRenderer<DataType.Message> = (
13
+ message: DataType.Message,
14
+ index: number,
15
+ debug = true,
16
+ ): string[] => {
13
17
  return [
14
18
  `###### ${message.sender.name}`,
15
19
  ...message.blocks.filter((block) => block.type === 'transcription').map((block) => block.text),
@@ -21,12 +25,12 @@ const createDate = () => new Date().toISOString();
21
25
 
22
26
  describe('SerializationModel', () => {
23
27
  test('basic', ({ expect }) => {
24
- const model = new SerializationModel<MessageType>(blockToMarkdown);
28
+ const model = new SerializationModel<DataType.Message>(blockToMarkdown);
25
29
  expect(model.chunks.length).to.eq(0);
26
30
  expect(model.doc.toString()).to.eq('');
27
31
 
28
32
  // Create message.
29
- const message: MessageType = {
33
+ const message: DataType.Message = {
30
34
  id: '1',
31
35
  created: createDate(),
32
36
  sender: { name: 'Alice' },
@@ -57,14 +61,14 @@ describe('SerializationModel', () => {
57
61
 
58
62
  test('sync - append', ({ expect }) => {
59
63
  const view = new EditorView({ extensions: [], doc: '' });
60
- const model = new SerializationModel<MessageType>(blockToMarkdown);
64
+ const model = new SerializationModel<DataType.Message>(blockToMarkdown);
61
65
  const adapter = new DocumentAdapter(view);
62
66
  expect(adapter.lineCount()).to.eq(0);
63
67
  expect(view.state.doc.toString()).to.eq('');
64
68
 
65
69
  // Append message.
66
70
  {
67
- const message: MessageType = {
71
+ const message: DataType.Message = {
68
72
  id: '1',
69
73
  created: createDate(),
70
74
  sender: { name: 'Alice' },
@@ -83,7 +87,7 @@ describe('SerializationModel', () => {
83
87
 
84
88
  // Append message.
85
89
  {
86
- const message: MessageType = {
90
+ const message: DataType.Message = {
87
91
  id: '2',
88
92
  created: createDate(),
89
93
  sender: { name: 'Bob' },
@@ -103,13 +107,13 @@ describe('SerializationModel', () => {
103
107
 
104
108
  test('sync - append, update, delete', ({ expect }) => {
105
109
  const view = new EditorView({ extensions: [], doc: '' });
106
- const model = new SerializationModel<MessageType>(blockToMarkdown);
110
+ const model = new SerializationModel<DataType.Message>(blockToMarkdown);
107
111
  const adapter = new DocumentAdapter(view);
108
112
  expect(adapter.lineCount()).to.eq(0);
109
113
 
110
114
  // Append message.
111
115
  {
112
- const message: MessageType = {
116
+ const message: DataType.Message = {
113
117
  id: '1',
114
118
  created: createDate(),
115
119
  sender: { name: 'Alice' },
@@ -142,7 +146,7 @@ describe('SerializationModel', () => {
142
146
 
143
147
  // Append message.
144
148
  {
145
- const message: MessageType = {
149
+ const message: DataType.Message = {
146
150
  id: '2',
147
151
  created: createDate(),
148
152
  sender: { name: 'Bob' },
@@ -2,6 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ import { Schema, SchemaAST } from 'effect';
5
6
  import { useEffect, useMemo, useState } from 'react';
6
7
 
7
8
  import { AIServiceEdgeClient } from '@dxos/assistant';
@@ -9,32 +10,38 @@ import { AI_SERVICE_ENDPOINT } from '@dxos/assistant/testing';
9
10
  import { scheduleTaskInterval } from '@dxos/async';
10
11
  import { createQueueDxn, Filter, type Queue } from '@dxos/client/echo';
11
12
  import { Context } from '@dxos/context';
12
- import { AST, create, EchoObject, ObjectId, S } from '@dxos/echo-schema';
13
+ import { Type } from '@dxos/echo';
14
+ import { create, ObjectId } from '@dxos/echo-schema';
13
15
  import { IdentityDid } from '@dxos/keys';
14
16
  import { log } from '@dxos/log';
15
17
  import { faker } from '@dxos/random';
16
18
  import { live, makeRef, useQueue, type Space } from '@dxos/react-client/echo';
17
- import { Contact, MessageType, Organization, type TranscriptionContentBlock } from '@dxos/schema';
19
+ import { DataType } from '@dxos/schema';
18
20
  import { Testing, seedTestData } from '@dxos/schema/testing';
19
21
 
20
22
  import { processTranscriptMessage } from '../entity-extraction';
21
23
 
22
24
  // TODO(burdon): Reconcile with plugin-markdown. Move to @dxos/schema/testing.
23
25
 
24
- export const TestItem = S.Struct({
25
- title: S.String.annotations({
26
- [AST.TitleAnnotationId]: 'Title',
27
- [AST.DescriptionAnnotationId]: 'Product title',
26
+ export const TestItem = Schema.Struct({
27
+ title: Schema.String.annotations({
28
+ [SchemaAST.TitleAnnotationId]: 'Title',
29
+ [SchemaAST.DescriptionAnnotationId]: 'Product title',
28
30
  }),
29
- description: S.String.annotations({
30
- [AST.TitleAnnotationId]: 'Description',
31
- [AST.DescriptionAnnotationId]: 'Product description',
31
+ description: Schema.String.annotations({
32
+ [SchemaAST.TitleAnnotationId]: 'Description',
33
+ [SchemaAST.DescriptionAnnotationId]: 'Product description',
32
34
  }),
33
- }).pipe(EchoObject({ typename: 'dxos.org/type/Test', version: '0.1.0' }));
35
+ }).pipe(
36
+ Type.def({
37
+ typename: 'dxos.org/type/Test',
38
+ version: '0.1.0',
39
+ }),
40
+ );
34
41
 
35
42
  // TODO(wittjosiah): Make builder generic and reuse for all message types.
36
43
  abstract class AbstractMessageBuilder {
37
- abstract createMessage(numSegments?: number): Promise<MessageType>;
44
+ abstract createMessage(numSegments?: number): Promise<DataType.Message>;
38
45
  }
39
46
 
40
47
  /**
@@ -55,7 +62,7 @@ export class MessageBuilder extends AbstractMessageBuilder {
55
62
  super();
56
63
  }
57
64
 
58
- override async createMessage(numSegments = 1): Promise<MessageType> {
65
+ override async createMessage(numSegments = 1): Promise<DataType.Message> {
59
66
  return {
60
67
  id: ObjectId.random().toString(),
61
68
  created: this.next().toISOString(),
@@ -64,7 +71,7 @@ export class MessageBuilder extends AbstractMessageBuilder {
64
71
  };
65
72
  }
66
73
 
67
- createBlock(): TranscriptionContentBlock {
74
+ createBlock(): DataType.MessageBlock.Transcription {
68
75
  let text = faker.lorem.paragraph();
69
76
  if (this._space) {
70
77
  const label = faker.commerce.productName();
@@ -96,7 +103,7 @@ class EntityExtractionMessageBuilder extends AbstractMessageBuilder {
96
103
 
97
104
  space: Space | undefined;
98
105
  currentMessage: number = 0;
99
- transcriptMessages: MessageType[] = [];
106
+ transcriptMessages: DataType.Message[] = [];
100
107
 
101
108
  async connect(space: Space) {
102
109
  this.space = space;
@@ -104,13 +111,19 @@ class EntityExtractionMessageBuilder extends AbstractMessageBuilder {
104
111
  this.transcriptMessages = transcriptMessages;
105
112
  }
106
113
 
107
- override async createMessage(): Promise<MessageType> {
114
+ override async createMessage(): Promise<DataType.Message> {
108
115
  if (!this.space) {
109
116
  throw new Error('Space not connected');
110
117
  }
111
118
 
112
119
  const { objects } = await this.space.db
113
- .query(Filter.or(Filter.schema(Contact), Filter.schema(Organization), Filter.schema(Testing.DocumentType)))
120
+ .query(
121
+ Filter.or(
122
+ Filter.schema(DataType.Person),
123
+ Filter.schema(DataType.Organization),
124
+ Filter.schema(Testing.DocumentType),
125
+ ),
126
+ )
114
127
  .run();
115
128
 
116
129
  log.info('context', { objects });
@@ -135,7 +148,7 @@ type UseTestTranscriptionQueue = (
135
148
  queueId?: ObjectId,
136
149
  running?: boolean,
137
150
  interval?: number,
138
- ) => Queue<MessageType> | undefined;
151
+ ) => Queue<DataType.Message> | undefined;
139
152
 
140
153
  /**
141
154
  * Test transcriptionqueue.
@@ -147,7 +160,7 @@ export const useTestTranscriptionQueue: UseTestTranscriptionQueue = (
147
160
  interval = 1_000,
148
161
  ) => {
149
162
  const queueDxn = useMemo(() => (space ? createQueueDxn(space.id, queueId) : undefined), [space, queueId]);
150
- const queue = useQueue<MessageType>(queueDxn);
163
+ const queue = useQueue<DataType.Message>(queueDxn);
151
164
  const builder = useMemo(() => new MessageBuilder(space), [space]);
152
165
 
153
166
  useEffect(() => {
@@ -157,7 +170,7 @@ export const useTestTranscriptionQueue: UseTestTranscriptionQueue = (
157
170
 
158
171
  const i = setInterval(() => {
159
172
  void builder.createMessage(Math.ceil(Math.random() * 3)).then((message) => {
160
- queue.append([create(MessageType, message)]);
173
+ queue.append([create(DataType.Message, message)]);
161
174
  });
162
175
  }, interval);
163
176
  return () => clearInterval(i);
@@ -177,7 +190,7 @@ export const useTestTranscriptionQueueWithEntityExtraction: UseTestTranscription
177
190
  interval = 1_000,
178
191
  ) => {
179
192
  const queueDxn = useMemo(() => (space ? createQueueDxn(space.id, queueId) : undefined), [space, queueId]);
180
- const queue = useQueue<MessageType>(queueDxn);
193
+ const queue = useQueue<DataType.Message>(queueDxn);
181
194
  const [builder] = useState(() => new EntityExtractionMessageBuilder());
182
195
 
183
196
  useEffect(() => {
@@ -194,7 +207,7 @@ export const useTestTranscriptionQueueWithEntityExtraction: UseTestTranscription
194
207
  ctx,
195
208
  async () => {
196
209
  const message = await builder.createMessage();
197
- queue.append([create(MessageType, message)]);
210
+ queue.append([create(DataType.Message, message)]);
198
211
  },
199
212
  interval,
200
213
  );
@@ -9,7 +9,7 @@ import { WaveFile } from 'wavefile';
9
9
 
10
10
  import { Trigger } from '@dxos/async';
11
11
  import { log } from '@dxos/log';
12
- import { type TranscriptionContentBlock } from '@dxos/schema';
12
+ import { type DataType } from '@dxos/schema';
13
13
  import { openAndClose } from '@dxos/test-utils';
14
14
  import { trace, TRACE_PROCESSOR } from '@dxos/tracing';
15
15
 
@@ -93,7 +93,7 @@ describe.skip('Transcriber', () => {
93
93
  });
94
94
 
95
95
  test.skip('transcription of audio recording', { timeout: 10_000 }, async () => {
96
- const trigger = new Trigger<TranscriptionContentBlock[]>({ autoReset: true });
96
+ const trigger = new Trigger<DataType.MessageBlock.Transcription[]>({ autoReset: true });
97
97
  const recorder = new MockAudioRecorder({
98
98
  buffer: await readFile('test.wav'),
99
99
  chunkDuration: 3_000,
@@ -127,7 +127,7 @@ describe.skip('Transcriber', () => {
127
127
  });
128
128
 
129
129
  test.skip('transcription of audio recording with overlapping chunks', { timeout: 20_000 }, async () => {
130
- const trigger = new Trigger<TranscriptionContentBlock[]>({ autoReset: true });
130
+ const trigger = new Trigger<DataType.MessageBlock.Transcription[]>({ autoReset: true });
131
131
  const recorder = new MockAudioRecorder({
132
132
  buffer: await readFile('test.wav'),
133
133
  chunkDuration: 3_000,
@@ -7,7 +7,7 @@ import { WaveFile } from 'wavefile';
7
7
  import { DeferredTask, Trigger } from '@dxos/async';
8
8
  import { type Context, LifecycleState, Resource } from '@dxos/context';
9
9
  import { log } from '@dxos/log';
10
- import { type TranscriptionContentBlock } from '@dxos/schema';
10
+ import { type DataType } from '@dxos/schema';
11
11
  import { trace } from '@dxos/tracing';
12
12
 
13
13
  import { type AudioRecorder, type AudioChunk } from './audio-recorder';
@@ -65,7 +65,7 @@ export type TranscribeConfig = {
65
65
  export type TranscriberParams = {
66
66
  config: TranscribeConfig;
67
67
  recorder: AudioRecorder;
68
- onSegments: (segments: TranscriptionContentBlock[]) => Promise<void>;
68
+ onSegments: (segments: DataType.MessageBlock.Transcription[]) => Promise<void>;
69
69
  };
70
70
 
71
71
  /**
@@ -216,7 +216,10 @@ export class Transcriber extends Resource {
216
216
  return segments;
217
217
  }
218
218
 
219
- private _alignSegments(segments: WhisperSegment[], originalChunks: AudioChunk[]): TranscriptionContentBlock[] {
219
+ private _alignSegments(
220
+ segments: WhisperSegment[],
221
+ originalChunks: AudioChunk[],
222
+ ): DataType.MessageBlock.Transcription[] {
220
223
  // Absolute zero for all relative timestamps in the segments.
221
224
  const zeroTimestamp = originalChunks.at(0)!.timestamp;
222
225