@dxos/plugin-assistant 0.8.2-main.f11618f → 0.8.2-staging.7ac8446

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 (164) hide show
  1. package/dist/lib/browser/{AssistantDialog-I47GUXWR.mjs → AssistantDialog-YSHMAHW5.mjs} +3 -3
  2. package/dist/lib/browser/{ChatContainer-GAYN3FEF.mjs → ChatContainer-V5GP7DYF.mjs} +3 -3
  3. package/dist/lib/browser/ChatContainer-V5GP7DYF.mjs.map +7 -0
  4. package/dist/lib/browser/TemplateContainer-K4EJNGIL.mjs +78 -0
  5. package/dist/lib/browser/TemplateContainer-K4EJNGIL.mjs.map +7 -0
  6. package/dist/lib/browser/{ai-client-OK5SMYJC.mjs → ai-client-CDZLSNXE.mjs} +1 -1
  7. package/dist/lib/browser/{ai-client-OK5SMYJC.mjs.map → ai-client-CDZLSNXE.mjs.map} +2 -2
  8. package/dist/lib/browser/{app-graph-builder-ZXKGE3H5.mjs → app-graph-builder-MF5EVDWW.mjs} +39 -9
  9. package/dist/lib/browser/app-graph-builder-MF5EVDWW.mjs.map +7 -0
  10. package/dist/lib/browser/{chunk-7CAHKTZQ.mjs → chunk-FMB7RGMP.mjs} +56 -92
  11. package/dist/lib/browser/chunk-FMB7RGMP.mjs.map +7 -0
  12. package/dist/lib/browser/{chunk-E7BN4QKP.mjs → chunk-IAMR2FAE.mjs} +2 -9
  13. package/dist/lib/browser/{chunk-E7BN4QKP.mjs.map → chunk-IAMR2FAE.mjs.map} +3 -3
  14. package/dist/lib/browser/chunk-KYMKVE6M.mjs +128 -0
  15. package/dist/lib/browser/chunk-KYMKVE6M.mjs.map +7 -0
  16. package/dist/lib/browser/index.mjs +11 -14
  17. package/dist/lib/browser/index.mjs.map +3 -3
  18. package/dist/lib/browser/{intent-resolver-W6XREK5F.mjs → intent-resolver-WJGLKKVO.mjs} +5 -5
  19. package/dist/lib/browser/intent-resolver-WJGLKKVO.mjs.map +7 -0
  20. package/dist/lib/browser/meta.json +1 -1
  21. package/dist/lib/browser/{react-surface-QMI5KG4H.mjs → react-surface-57VRDOQT.mjs} +15 -15
  22. package/dist/lib/browser/react-surface-57VRDOQT.mjs.map +7 -0
  23. package/dist/lib/browser/{settings-LAJZQI4H.mjs → settings-U6UFQX32.mjs} +4 -4
  24. package/dist/lib/browser/settings-U6UFQX32.mjs.map +7 -0
  25. package/dist/lib/browser/types/index.mjs +1 -3
  26. package/dist/lib/node/{AssistantDialog-SDS2TE5L.cjs → AssistantDialog-YI2BSGSX.cjs} +7 -7
  27. package/dist/lib/node/{ChatContainer-U6AVMAHY.cjs → ChatContainer-ZJ5JXF6A.cjs} +7 -7
  28. package/dist/lib/node/ChatContainer-ZJ5JXF6A.cjs.map +7 -0
  29. package/dist/lib/node/TemplateContainer-XWFYJB4T.cjs +104 -0
  30. package/dist/lib/node/TemplateContainer-XWFYJB4T.cjs.map +7 -0
  31. package/dist/lib/node/{ai-client-3EVTLXTT.cjs → ai-client-URCCYU6B.cjs} +4 -4
  32. package/dist/lib/node/{ai-client-3EVTLXTT.cjs.map → ai-client-URCCYU6B.cjs.map} +2 -2
  33. package/dist/lib/node/{app-graph-builder-TXHPXIIC.cjs → app-graph-builder-N5ZUUI2Z.cjs} +44 -14
  34. package/dist/lib/node/app-graph-builder-N5ZUUI2Z.cjs.map +7 -0
  35. package/dist/lib/node/{chunk-5UELRDHQ.cjs → chunk-APRU3QWK.cjs} +5 -13
  36. package/dist/lib/node/{chunk-5UELRDHQ.cjs.map → chunk-APRU3QWK.cjs.map} +3 -3
  37. package/dist/lib/node/{chunk-CWHFK36A.cjs → chunk-RPBKMP2E.cjs} +80 -117
  38. package/dist/lib/node/chunk-RPBKMP2E.cjs.map +7 -0
  39. package/dist/lib/node/{chunk-XBJO453B.cjs → chunk-ZKOC4ZFY.cjs} +61 -78
  40. package/dist/lib/node/chunk-ZKOC4ZFY.cjs.map +7 -0
  41. package/dist/lib/node/index.cjs +43 -46
  42. package/dist/lib/node/index.cjs.map +3 -3
  43. package/dist/lib/node/{intent-resolver-MUJMV7II.cjs → intent-resolver-R3OSTIMH.cjs} +9 -9
  44. package/dist/lib/node/intent-resolver-R3OSTIMH.cjs.map +7 -0
  45. package/dist/lib/node/meta.json +1 -1
  46. package/dist/lib/node/{react-surface-SAJF4XBB.cjs → react-surface-NUQTM6MS.cjs} +22 -22
  47. package/dist/lib/node/react-surface-NUQTM6MS.cjs.map +7 -0
  48. package/dist/lib/node/{settings-NPXTE6ND.cjs → settings-TXGRCYAL.cjs} +7 -7
  49. package/dist/lib/node/settings-TXGRCYAL.cjs.map +7 -0
  50. package/dist/lib/node/types/index.cjs +12 -14
  51. package/dist/lib/node/types/index.cjs.map +2 -2
  52. package/dist/lib/node-esm/{AssistantDialog-KGA5HBFO.mjs → AssistantDialog-U2FQX5TD.mjs} +3 -3
  53. package/dist/lib/node-esm/{ChatContainer-XPNXNPSW.mjs → ChatContainer-QW3OOXTT.mjs} +3 -3
  54. package/dist/lib/node-esm/ChatContainer-QW3OOXTT.mjs.map +7 -0
  55. package/dist/lib/node-esm/TemplateContainer-EUM2X65J.mjs +79 -0
  56. package/dist/lib/node-esm/TemplateContainer-EUM2X65J.mjs.map +7 -0
  57. package/dist/lib/node-esm/{ai-client-LYCBXZI7.mjs → ai-client-WMHS5EGV.mjs} +1 -1
  58. package/dist/lib/node-esm/{ai-client-LYCBXZI7.mjs.map → ai-client-WMHS5EGV.mjs.map} +2 -2
  59. package/dist/lib/node-esm/{app-graph-builder-SV4WC2E2.mjs → app-graph-builder-DWBNIMHM.mjs} +39 -9
  60. package/dist/lib/node-esm/app-graph-builder-DWBNIMHM.mjs.map +7 -0
  61. package/dist/lib/node-esm/chunk-GBBXIW5F.mjs +129 -0
  62. package/dist/lib/node-esm/chunk-GBBXIW5F.mjs.map +7 -0
  63. package/dist/lib/node-esm/{chunk-XFUXN5QU.mjs → chunk-MVDAY3CZ.mjs} +56 -92
  64. package/dist/lib/node-esm/chunk-MVDAY3CZ.mjs.map +7 -0
  65. package/dist/lib/node-esm/{chunk-ECYNZYEG.mjs → chunk-MXK2EANZ.mjs} +2 -9
  66. package/dist/lib/node-esm/{chunk-ECYNZYEG.mjs.map → chunk-MXK2EANZ.mjs.map} +3 -3
  67. package/dist/lib/node-esm/index.mjs +11 -14
  68. package/dist/lib/node-esm/index.mjs.map +3 -3
  69. package/dist/lib/node-esm/{intent-resolver-DZY2O2DG.mjs → intent-resolver-H32TL4X6.mjs} +5 -5
  70. package/dist/lib/node-esm/intent-resolver-H32TL4X6.mjs.map +7 -0
  71. package/dist/lib/node-esm/meta.json +1 -1
  72. package/dist/lib/node-esm/{react-surface-R43NHNMC.mjs → react-surface-JBVZF6CP.mjs} +15 -15
  73. package/dist/lib/node-esm/react-surface-JBVZF6CP.mjs.map +7 -0
  74. package/dist/lib/node-esm/{settings-K3JDH2I5.mjs → settings-DZU5PNXM.mjs} +4 -4
  75. package/dist/lib/node-esm/settings-DZU5PNXM.mjs.map +7 -0
  76. package/dist/lib/node-esm/types/index.mjs +1 -3
  77. package/dist/types/src/capabilities/ai-client.d.ts.map +1 -1
  78. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  79. package/dist/types/src/capabilities/index.d.ts +1 -1
  80. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  81. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  82. package/dist/types/src/components/AssistantSettings/AssistantSettings.d.ts.map +1 -1
  83. package/dist/types/src/components/ChatContainer.d.ts +3 -4
  84. package/dist/types/src/components/ChatContainer.d.ts.map +1 -1
  85. package/dist/types/src/components/ServiceRegistry/ServiceRegistry.d.ts +6 -0
  86. package/dist/types/src/components/ServiceRegistry/ServiceRegistry.d.ts.map +1 -0
  87. package/dist/types/src/components/ServiceRegistry/ServiceRegistry.stories.d.ts +8 -0
  88. package/dist/types/src/components/ServiceRegistry/ServiceRegistry.stories.d.ts.map +1 -0
  89. package/dist/types/src/components/ServiceRegistry/index.d.ts +2 -0
  90. package/dist/types/src/components/ServiceRegistry/index.d.ts.map +1 -0
  91. package/dist/types/src/components/TemplateContainer.d.ts.map +1 -1
  92. package/dist/types/src/components/Thread/ThreadContainer.d.ts.map +1 -1
  93. package/dist/types/src/components/Thread/ThreadContainer.stories.d.ts.map +1 -1
  94. package/dist/types/src/components/index.d.ts +6 -2
  95. package/dist/types/src/components/index.d.ts.map +1 -1
  96. package/dist/types/src/hooks/processor.d.ts.map +1 -1
  97. package/dist/types/src/hooks/useChatProcessor.d.ts.map +1 -1
  98. package/dist/types/src/hooks/useMessageQueue.d.ts +3 -0
  99. package/dist/types/src/hooks/useMessageQueue.d.ts.map +1 -1
  100. package/dist/types/src/translations.d.ts +0 -3
  101. package/dist/types/src/translations.d.ts.map +1 -1
  102. package/dist/types/src/types/types.d.ts +1 -3
  103. package/dist/types/src/types/types.d.ts.map +1 -1
  104. package/package.json +57 -57
  105. package/src/AssistantPlugin.tsx +2 -2
  106. package/src/capabilities/ai-client.ts +1 -0
  107. package/src/capabilities/app-graph-builder.ts +38 -6
  108. package/src/capabilities/index.ts +1 -1
  109. package/src/capabilities/intent-resolver.ts +3 -3
  110. package/src/capabilities/react-surface.tsx +9 -11
  111. package/src/capabilities/settings.ts +2 -2
  112. package/src/components/AssistantSettings/AssistantSettings.tsx +6 -28
  113. package/src/components/ChatContainer.tsx +8 -6
  114. package/src/components/ServiceRegistry/ServiceRegistry.stories.tsx +49 -0
  115. package/src/components/ServiceRegistry/ServiceRegistry.tsx +76 -0
  116. package/src/components/ServiceRegistry/index.ts +5 -0
  117. package/src/components/TemplateContainer.tsx +79 -3
  118. package/src/components/TemplateEditor/TemplateEditor.stories.tsx +2 -2
  119. package/src/components/TemplateEditor/TemplateForm.stories.tsx +2 -2
  120. package/src/components/Thread/ThreadContainer.stories.tsx +18 -9
  121. package/src/components/Thread/ThreadContainer.tsx +2 -24
  122. package/src/components/Thread/ThreadMessage.tsx +2 -5
  123. package/src/components/Toolbox/Toolbox.stories.tsx +1 -1
  124. package/src/components/index.ts +1 -1
  125. package/src/hooks/processor.ts +4 -26
  126. package/src/hooks/useChatProcessor.tsx +2 -3
  127. package/src/testing/test-services.ts +6 -6
  128. package/src/translations.ts +4 -5
  129. package/src/types/types.ts +1 -4
  130. package/dist/lib/browser/ChatContainer-GAYN3FEF.mjs.map +0 -7
  131. package/dist/lib/browser/TemplateContainer-WKU5XFSO.mjs +0 -22
  132. package/dist/lib/browser/TemplateContainer-WKU5XFSO.mjs.map +0 -7
  133. package/dist/lib/browser/app-graph-builder-ZXKGE3H5.mjs.map +0 -7
  134. package/dist/lib/browser/chunk-7CAHKTZQ.mjs.map +0 -7
  135. package/dist/lib/browser/chunk-BGMQ2YYP.mjs +0 -143
  136. package/dist/lib/browser/chunk-BGMQ2YYP.mjs.map +0 -7
  137. package/dist/lib/browser/intent-resolver-W6XREK5F.mjs.map +0 -7
  138. package/dist/lib/browser/react-surface-QMI5KG4H.mjs.map +0 -7
  139. package/dist/lib/browser/settings-LAJZQI4H.mjs.map +0 -7
  140. package/dist/lib/node/ChatContainer-U6AVMAHY.cjs.map +0 -7
  141. package/dist/lib/node/TemplateContainer-EQXKHWTF.cjs +0 -52
  142. package/dist/lib/node/TemplateContainer-EQXKHWTF.cjs.map +0 -7
  143. package/dist/lib/node/app-graph-builder-TXHPXIIC.cjs.map +0 -7
  144. package/dist/lib/node/chunk-CWHFK36A.cjs.map +0 -7
  145. package/dist/lib/node/chunk-XBJO453B.cjs.map +0 -7
  146. package/dist/lib/node/intent-resolver-MUJMV7II.cjs.map +0 -7
  147. package/dist/lib/node/react-surface-SAJF4XBB.cjs.map +0 -7
  148. package/dist/lib/node/settings-NPXTE6ND.cjs.map +0 -7
  149. package/dist/lib/node-esm/ChatContainer-XPNXNPSW.mjs.map +0 -7
  150. package/dist/lib/node-esm/TemplateContainer-3LEBT5ZC.mjs +0 -23
  151. package/dist/lib/node-esm/TemplateContainer-3LEBT5ZC.mjs.map +0 -7
  152. package/dist/lib/node-esm/app-graph-builder-SV4WC2E2.mjs.map +0 -7
  153. package/dist/lib/node-esm/chunk-R7Q3OHWG.mjs +0 -144
  154. package/dist/lib/node-esm/chunk-R7Q3OHWG.mjs.map +0 -7
  155. package/dist/lib/node-esm/chunk-XFUXN5QU.mjs.map +0 -7
  156. package/dist/lib/node-esm/intent-resolver-DZY2O2DG.mjs.map +0 -7
  157. package/dist/lib/node-esm/react-surface-R43NHNMC.mjs.map +0 -7
  158. package/dist/lib/node-esm/settings-K3JDH2I5.mjs.map +0 -7
  159. package/dist/types/src/components/PromptSettings.d.ts +0 -6
  160. package/dist/types/src/components/PromptSettings.d.ts.map +0 -1
  161. package/src/components/PromptSettings.tsx +0 -91
  162. /package/dist/lib/browser/{AssistantDialog-I47GUXWR.mjs.map → AssistantDialog-YSHMAHW5.mjs.map} +0 -0
  163. /package/dist/lib/node/{AssistantDialog-SDS2TE5L.cjs.map → AssistantDialog-YI2BSGSX.cjs.map} +0 -0
  164. /package/dist/lib/node-esm/{AssistantDialog-KGA5HBFO.mjs.map → AssistantDialog-U2FQX5TD.mjs.map} +0 -0
@@ -5,11 +5,12 @@
5
5
  import React, { useMemo } from 'react';
6
6
 
7
7
  import { Capabilities, contributes, createSurface } from '@dxos/app-framework';
8
- import { isInstanceOf, getTypename } from '@dxos/echo-schema';
8
+ import { isInstanceOf } from '@dxos/echo-schema';
9
+ import { getTypename } from '@dxos/live-object';
9
10
  import { SettingsStore } from '@dxos/local-storage';
10
- import { fullyQualifiedId, getSpace, isLiveObject, type SpaceId } from '@dxos/react-client/echo';
11
+ import { fullyQualifiedId, isReactiveObject, isSpace, type Space } from '@dxos/react-client/echo';
11
12
 
12
- import { AssistantDialog, AssistantSettings, ChatContainer, PromptSettings, TemplateContainer } from '../components';
13
+ import { AssistantDialog, AssistantSettings, ChatContainer, ServiceRegistry, TemplateContainer } from '../components';
13
14
  import { ASSISTANT_PLUGIN, ASSISTANT_DIALOG } from '../meta';
14
15
  import { AIChatType, type AssistantSettingsProps, TemplateType } from '../types';
15
16
 
@@ -39,15 +40,12 @@ export default () =>
39
40
  id: `${ASSISTANT_PLUGIN}/object-chat`,
40
41
  role: 'article',
41
42
  filter: (data): data is { companionTo: AIChatType; subject: 'assistant-chat' } =>
42
- isLiveObject(data.companionTo) &&
43
- (data as any).companionTo.assistantChatQueue &&
44
- data.subject === 'assistant-chat',
43
+ isReactiveObject(data.companionTo) && data.companionTo.assistantChatQueue && data.subject === 'assistant-chat',
45
44
  component: ({ data, role }) => {
46
45
  const associatedArtifact = useMemo(
47
46
  () => ({
48
47
  id: fullyQualifiedId(data.companionTo),
49
48
  typename: getTypename(data.companionTo) ?? 'unknown',
50
- spaceId: (getSpace(data.companionTo)?.id ?? 'unknown') as SpaceId,
51
49
  }),
52
50
  [data.companionTo],
53
51
  );
@@ -61,9 +59,9 @@ export default () =>
61
59
  component: ({ data, role }) => <TemplateContainer role={role} template={data.subject} />,
62
60
  }),
63
61
  createSurface({
64
- id: `${ASSISTANT_PLUGIN}/prompt-settings`,
65
- role: 'object-settings',
66
- filter: (data): data is { subject: TemplateType } => isInstanceOf(TemplateType, data.subject),
67
- component: ({ data }) => <PromptSettings template={data.subject} />,
62
+ id: `${ASSISTANT_PLUGIN}/service-registry`,
63
+ role: 'deck-companion--service-registry',
64
+ filter: (data): data is { subject: Space } => isSpace(data.subject),
65
+ component: ({ data }) => <ServiceRegistry space={data.subject} />,
68
66
  }),
69
67
  ]);
@@ -3,13 +3,13 @@
3
3
  //
4
4
 
5
5
  import { Capabilities, contributes } from '@dxos/app-framework';
6
- import { live } from '@dxos/live-object';
6
+ import { create } from '@dxos/live-object';
7
7
 
8
8
  import { ASSISTANT_PLUGIN } from '../meta';
9
9
  import { type AssistantSettingsProps, AssistantSettingsSchema } from '../types';
10
10
 
11
11
  export default () => {
12
- const settings = live<AssistantSettingsProps>({});
12
+ const settings = create<AssistantSettingsProps>({});
13
13
 
14
14
  return contributes(Capabilities.Settings, {
15
15
  schema: AssistantSettingsSchema,
@@ -9,17 +9,11 @@ import { Input, Select, useTranslation } from '@dxos/react-ui';
9
9
  import { DeprecatedFormContainer, DeprecatedFormInput } from '@dxos/react-ui-form';
10
10
 
11
11
  import { ASSISTANT_PLUGIN } from '../../meta';
12
- import { LLM_PROVIDERS, type AssistantSettingsProps } from '../../types';
12
+ import { type AssistantSettingsProps } from '../../types';
13
13
 
14
- // TODO(burdon): Factor out default Selector.
14
+ // TODO(burdon): Factor out.
15
15
  const DEFAULT_VALUE = '__default';
16
16
 
17
- const LLM_PROVIDER_LABELS = {
18
- edge: 'DXOS',
19
- ollama: 'Ollama',
20
- lmstudio: 'LM Studio',
21
- } as const;
22
-
23
17
  export const AssistantSettings = ({ settings }: { settings: AssistantSettingsProps }) => {
24
18
  const { t } = useTranslation(ASSISTANT_PLUGIN);
25
19
 
@@ -33,26 +27,10 @@ export const AssistantSettings = ({ settings }: { settings: AssistantSettingsPro
33
27
  </DeprecatedFormInput>
34
28
 
35
29
  <DeprecatedFormInput label={t('settings llm provider label')}>
36
- <Select.Root
37
- value={settings.llmProvider ?? 'edge'}
38
- onValueChange={(value) => {
39
- settings.llmProvider = value === DEFAULT_VALUE ? undefined : (value as any);
40
- }}
41
- >
42
- <Select.TriggerButton placeholder={t('settings llm provider label')} />
43
- <Select.Portal>
44
- <Select.Content>
45
- <Select.Viewport>
46
- <Select.Option value={DEFAULT_VALUE}>{t('settings default label')}</Select.Option>
47
- {LLM_PROVIDERS.map((model) => (
48
- <Select.Option key={model} value={model}>
49
- {LLM_PROVIDER_LABELS[model]}
50
- </Select.Option>
51
- ))}
52
- </Select.Viewport>
53
- </Select.Content>
54
- </Select.Portal>
55
- </Select.Root>
30
+ <Input.Switch
31
+ checked={settings.llmProvider === 'ollama'}
32
+ onCheckedChange={(checked) => (settings.llmProvider = checked ? 'ollama' : 'edge')}
33
+ />
56
34
  </DeprecatedFormInput>
57
35
 
58
36
  <DeprecatedFormInput label={t('settings edge llm model label')}>
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import React, { type FC } from 'react';
5
+ import React from 'react';
6
6
 
7
7
  import { Capabilities, useCapabilities, useCapability } from '@dxos/app-framework';
8
8
  import { type AssociatedArtifact } from '@dxos/artifact';
@@ -13,14 +13,16 @@ import { ThreadContainer } from './Thread';
13
13
  import { ASSISTANT_PLUGIN } from '../meta';
14
14
  import { type AssistantSettingsProps, type AIChatType } from '../types';
15
15
 
16
- export type ChatContainerProps = {
16
+ // TODO(burdon): Attention.
17
+ export const ChatContainer = ({
18
+ role,
19
+ chat,
20
+ associatedArtifact,
21
+ }: {
17
22
  role: string;
18
23
  chat: AIChatType;
19
24
  associatedArtifact?: AssociatedArtifact;
20
- };
21
-
22
- // TODO(burdon): Attention.
23
- export const ChatContainer: FC<ChatContainerProps> = ({ role, chat, associatedArtifact }) => {
25
+ }) => {
24
26
  const transcription = useCapabilities(TranscriptionCapabilities.Transcriber).length > 0;
25
27
  const settings = useCapability(Capabilities.SettingsStore).getStore<AssistantSettingsProps>(ASSISTANT_PLUGIN)?.value;
26
28
 
@@ -0,0 +1,49 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import '@dxos-theme';
6
+
7
+ import { type Meta, type StoryObj } from '@storybook/react';
8
+ import React from 'react';
9
+
10
+ import { useSpace } from '@dxos/react-client/echo';
11
+ import { withClientProvider } from '@dxos/react-client/testing';
12
+ import { withLayout, withTheme } from '@dxos/storybook-utils';
13
+
14
+ import { ServiceRegistry } from './ServiceRegistry';
15
+ import { ServiceType } from '../../types';
16
+
17
+ const meta: Meta<typeof ServiceRegistry> = {
18
+ title: 'plugins/plugin-automation/ServiceRegistry',
19
+ component: ServiceRegistry,
20
+ render: ({ space: _ignore, ...args }) => {
21
+ const space = useSpace();
22
+ if (!space) {
23
+ return <div />;
24
+ }
25
+
26
+ return (
27
+ <div className='h-full w-[300px] overflow-hidden'>
28
+ <ServiceRegistry space={space} {...args} />
29
+ </div>
30
+ );
31
+ },
32
+ decorators: [
33
+ withClientProvider({
34
+ createIdentity: true,
35
+ createSpace: true,
36
+ types: [ServiceType],
37
+ }),
38
+ withLayout({ fullscreen: true, tooltips: true, classNames: 'flex justify-center' }),
39
+ withTheme,
40
+ ],
41
+ };
42
+
43
+ export default meta;
44
+
45
+ type Story = StoryObj<typeof ServiceRegistry>;
46
+
47
+ export const Default: Story = {
48
+ args: {},
49
+ };
@@ -0,0 +1,76 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React, { useMemo } from 'react';
6
+
7
+ import { Filter, type Space } from '@dxos/client/echo';
8
+ import { useQuery } from '@dxos/react-client/echo';
9
+ import { Icon, Input, List, ListItem } from '@dxos/react-ui';
10
+
11
+ import { useServices } from '../../hooks';
12
+ import { categoryIcons, ServiceType } from '../../types';
13
+
14
+ // TODO(burdon): Option to show all/enabled/filter.
15
+ export const ServiceRegistry = ({ space }: { space: Space }) => {
16
+ const matchingServices = useServices(space);
17
+ const enabledServices = useQuery(space, Filter.schema(ServiceType));
18
+
19
+ // Join matching services with enabled services.
20
+ const services = useMemo(() => {
21
+ return matchingServices.map((service) => enabledServices.find((s) => s.serviceId === service.serviceId) ?? service);
22
+ }, [matchingServices, enabledServices]);
23
+
24
+ // TODO(burdon): Reaplce with SpacePlugin intent.
25
+ const handleSetEnabled = (service: ServiceType, enabled: boolean) => {
26
+ if (enabled) {
27
+ space.db.add(service);
28
+ } else {
29
+ // TODO(burdon): Remove or disable?
30
+ space.db.remove(service);
31
+ }
32
+ };
33
+
34
+ return (
35
+ <List classNames='h-full grid auto-rows-[5rem] gap-2 p-2 pis-2 pie-2 overflow-y-auto scrollbar-thin'>
36
+ {services.map((service) => (
37
+ <ServiceItem
38
+ key={service.serviceId}
39
+ service={service}
40
+ enabled={service.enabled}
41
+ setEnabled={(enabled) => handleSetEnabled(service, enabled)}
42
+ />
43
+ ))}
44
+ </List>
45
+ );
46
+ };
47
+
48
+ const ServiceItem = ({
49
+ service,
50
+ enabled,
51
+ setEnabled,
52
+ }: {
53
+ service: ServiceType;
54
+ enabled?: boolean;
55
+ setEnabled?: (enabled: boolean) => void;
56
+ }) => {
57
+ return (
58
+ <ListItem.Root classNames='flex flex-col gap-1 p-1 overflow-hidden rounded-md border border-separator'>
59
+ <div className='grid grid-cols-[40px_1fr_40px]'>
60
+ <div className='flex gow justify-center items-center'>
61
+ <Icon icon={categoryIcons[service.category ?? 'default'] ?? 'ph--placeholder--regular'} size={6} />
62
+ </div>
63
+ <div className='grow items-center truncate mie-2'>{service.name}</div>
64
+ <div className='flex gow justify-center items-center'>
65
+ <Input.Root>
66
+ <Input.Switch checked={enabled} onClick={() => setEnabled?.(!enabled)} />
67
+ </Input.Root>
68
+ </div>
69
+ </div>
70
+ <div className='grid grid-cols-[40px_1fr]'>
71
+ <div />
72
+ <div className='text-sm text-subdued line-clamp-2 mie-1'>{service.description}</div>
73
+ </div>
74
+ </ListItem.Root>
75
+ );
76
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './ServiceRegistry';
@@ -2,16 +2,92 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import React from 'react';
5
+ import { Match, type Schema as S } from 'effect';
6
+ import React, { type ChangeEvent, useCallback } from 'react';
6
7
 
8
+ import { debounce } from '@dxos/async';
9
+ import { Input, Select, Toolbar, useTranslation } from '@dxos/react-ui';
7
10
  import { StackItem } from '@dxos/react-ui-stack';
8
11
 
9
12
  import { TemplateEditor } from './TemplateEditor';
10
- import { type TemplateType } from '../types';
13
+ import { ASSISTANT_PLUGIN } from '../meta';
14
+ import { TemplateKinds, type TemplateKindSchema, type TemplateType } from '../types';
11
15
 
12
16
  export const TemplateContainer = ({ template, role }: { template: TemplateType; role: string }) => {
17
+ const { t } = useTranslation(ASSISTANT_PLUGIN);
18
+
19
+ const handleKindChange = useCallback(
20
+ (value: string) => {
21
+ const kind = Match.type<string>().pipe(
22
+ Match.withReturnType<S.Schema.Type<typeof TemplateKindSchema>>(),
23
+ Match.when('always', () => ({ include: 'always' })),
24
+ Match.when('schema-matching', () => ({ include: 'schema-matching', typename: '' })),
25
+ Match.when('automatically', () => ({ include: 'automatically', description: '' })),
26
+ Match.orElse(() => ({ include: 'manual' })),
27
+ )(value);
28
+
29
+ template.kind = kind;
30
+ },
31
+ [template],
32
+ );
33
+
34
+ const handleTypenameChange = useCallback(
35
+ debounce((event: ChangeEvent<HTMLInputElement>) => {
36
+ if (template.kind.include === 'schema-matching') {
37
+ template.kind.typename = event.target.value;
38
+ }
39
+ }, 300),
40
+ [template.kind.include],
41
+ );
42
+
43
+ const handleDescriptionChange = useCallback(
44
+ debounce((event: ChangeEvent<HTMLInputElement>) => {
45
+ if (template.kind.include === 'automatically') {
46
+ template.kind.description = event.target.value;
47
+ }
48
+ }, 300),
49
+ [template.kind.include],
50
+ );
51
+
13
52
  return (
14
- <StackItem.Content role={role} classNames='container-max-width'>
53
+ <StackItem.Content role={role} toolbar classNames='container-max-width'>
54
+ {/* TODO(wittjosiah): Move this toolbar into c11y sidebar. */}
55
+ <Toolbar.Root>
56
+ <Select.Root value={template.kind.include} onValueChange={handleKindChange}>
57
+ <Toolbar.Button asChild>
58
+ <Select.TriggerButton />
59
+ </Toolbar.Button>
60
+ <Select.Portal>
61
+ <Select.Content>
62
+ <Select.Viewport>
63
+ {TemplateKinds.map((kind) => (
64
+ <Select.Option key={kind} value={kind}>
65
+ {kind}
66
+ </Select.Option>
67
+ ))}
68
+ </Select.Viewport>
69
+ </Select.Content>
70
+ </Select.Portal>
71
+ </Select.Root>
72
+ {template.kind.include === 'schema-matching' && (
73
+ <Input.Root>
74
+ <Input.TextInput
75
+ placeholder={t('typename placeholder')}
76
+ defaultValue={template.kind.typename}
77
+ onChange={handleTypenameChange}
78
+ />
79
+ </Input.Root>
80
+ )}
81
+ {template.kind.include === 'automatically' && (
82
+ <Input.Root>
83
+ <Input.TextInput
84
+ placeholder={t('description placeholder')}
85
+ defaultValue={template.kind.description}
86
+ onChange={handleDescriptionChange}
87
+ />
88
+ </Input.Root>
89
+ )}
90
+ </Toolbar.Root>
15
91
  <TemplateEditor template={template} />
16
92
  </StackItem.Content>
17
93
  );
@@ -8,7 +8,7 @@ import { type Meta } from '@storybook/react';
8
8
  import React, { useState } from 'react';
9
9
 
10
10
  import { createSystemPrompt } from '@dxos/artifact';
11
- import { live } from '@dxos/live-object';
11
+ import { create } from '@dxos/live-object';
12
12
  import { useClient } from '@dxos/react-client';
13
13
  import { withClientProvider } from '@dxos/react-client/testing';
14
14
  import { withLayout, withTheme } from '@dxos/storybook-utils';
@@ -38,7 +38,7 @@ const DefaultStory = ({ text }: TemplateEditorProps & { text: string }) => {
38
38
  const client = useClient();
39
39
  const [template] = useState(() => {
40
40
  const space = client.spaces.default;
41
- return space.db.add(live(TemplateType, { source: text, kind: { include: 'manual' } }));
41
+ return space.db.add(create(TemplateType, { source: text, kind: { include: 'manual' } }));
42
42
  });
43
43
 
44
44
  return (
@@ -7,7 +7,7 @@ import '@dxos-theme';
7
7
  import { type Meta } from '@storybook/react';
8
8
  import React, { useState } from 'react';
9
9
 
10
- import { live } from '@dxos/live-object';
10
+ import { create } from '@dxos/live-object';
11
11
  import { useClient } from '@dxos/react-client';
12
12
  import { withClientProvider } from '@dxos/react-client/testing';
13
13
  import { withLayout, withTheme } from '@dxos/storybook-utils';
@@ -30,7 +30,7 @@ const DefaultStory = () => {
30
30
  const client = useClient();
31
31
  const [template] = useState(() => {
32
32
  const space = client.spaces.default;
33
- return space.db.add(live(TemplateType, { source: TEMPLATE, kind: { include: 'manual' } }));
33
+ return space.db.add(create(TemplateType, { source: TEMPLATE, kind: { include: 'manual' } }));
34
34
  });
35
35
 
36
36
  return (
@@ -20,9 +20,9 @@ import { withPluginManager } from '@dxos/app-framework/testing';
20
20
  import { Message, type Tool } from '@dxos/artifact';
21
21
  import { genericTools, localServiceEndpoints, type IsObject } from '@dxos/artifact-testing';
22
22
  import { AIServiceEdgeClient } from '@dxos/assistant';
23
- import { create, ObjectId } from '@dxos/echo-schema';
23
+ import { createStatic, ObjectId } from '@dxos/echo-schema';
24
24
  import { invariant } from '@dxos/invariant';
25
- import { DXN } from '@dxos/keys';
25
+ import { DXN, QueueSubspaceTags, SpaceId } from '@dxos/keys';
26
26
  import { ChessPlugin } from '@dxos/plugin-chess';
27
27
  import { ChessType } from '@dxos/plugin-chess/types';
28
28
  import { ClientPlugin } from '@dxos/plugin-client';
@@ -30,10 +30,11 @@ import { InboxPlugin } from '@dxos/plugin-inbox';
30
30
  import { MapPlugin } from '@dxos/plugin-map';
31
31
  import { SpacePlugin } from '@dxos/plugin-space';
32
32
  import { TablePlugin } from '@dxos/plugin-table';
33
- import { createQueueDxn, useQueue, useSpace } from '@dxos/react-client/echo';
33
+ import { useQueue, useSpace } from '@dxos/react-client/echo';
34
+ import { withClientProvider } from '@dxos/react-client/testing';
34
35
  import { IconButton, Input, Toolbar } from '@dxos/react-ui';
35
36
  import { mx } from '@dxos/react-ui-theme';
36
- import { withLayout, withTheme } from '@dxos/storybook-utils';
37
+ import { withLayout, withSignals, withTheme } from '@dxos/storybook-utils';
37
38
 
38
39
  import { Thread, type ThreadProps } from './Thread';
39
40
  import { ChatProcessor } from '../../hooks';
@@ -76,13 +77,13 @@ const DefaultStory = ({ items: _items, prompts = [], ...props }: RenderProps) =>
76
77
  }, [aiClient, tools, space, dispatch, artifactDefinitions]);
77
78
 
78
79
  // Queue.
79
- const [queueDxn, setQueueDxn] = useState<string>(() => createQueueDxn().toString());
80
+ const [queueDxn, setQueueDxn] = useState<string>(() => randomQueueDxn());
80
81
  const queue = useQueue<Message>(DXN.tryParse(queueDxn));
81
82
 
82
83
  useEffect(() => {
83
84
  if (queue?.items.length === 0 && !queue.isLoading && prompts.length > 0) {
84
85
  queue.append([
85
- create(Message, {
86
+ createStatic(Message, {
86
87
  role: 'assistant',
87
88
  content: prompts.map(
88
89
  (prompt) =>
@@ -159,7 +160,7 @@ const DefaultStory = ({ items: _items, prompts = [], ...props }: RenderProps) =>
159
160
  iconOnly
160
161
  label='Clear history'
161
162
  icon='ph--trash--regular'
162
- onClick={() => setQueueDxn(createQueueDxn().toString())}
163
+ onClick={() => setQueueDxn(randomQueueDxn())}
163
164
  />
164
165
  <IconButton iconOnly label='Stop' icon='ph--stop--regular' onClick={() => processor?.cancel()} />
165
166
  </Input.Root>
@@ -200,10 +201,18 @@ const DefaultStory = ({ items: _items, prompts = [], ...props }: RenderProps) =>
200
201
  );
201
202
  };
202
203
 
204
+ const randomQueueDxn = () =>
205
+ new DXN(DXN.kind.QUEUE, [QueueSubspaceTags.DATA, SpaceId.random(), ObjectId.random()]).toString();
206
+
203
207
  const meta: Meta<typeof DefaultStory> = {
204
208
  title: 'plugins/plugin-automation/ThreadContainer',
205
209
  render: DefaultStory,
206
210
  decorators: [
211
+ withSignals,
212
+ withClientProvider({
213
+ createIdentity: true,
214
+ createSpace: true,
215
+ }),
207
216
  withPluginManager({
208
217
  plugins: [
209
218
  ClientPlugin({
@@ -211,7 +220,7 @@ const meta: Meta<typeof DefaultStory> = {
211
220
  await client.halo.createIdentity();
212
221
  },
213
222
  }),
214
- SpacePlugin(),
223
+ SpacePlugin({ observability: false }),
215
224
  SettingsPlugin(),
216
225
  IntentPlugin(),
217
226
 
@@ -246,7 +255,7 @@ export const WithInitialItems: Story = {
246
255
  args: {
247
256
  debug: true,
248
257
  items: [
249
- create(ChessType, {
258
+ createStatic(ChessType, {
250
259
  fen: 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1',
251
260
  }),
252
261
  ],
@@ -2,13 +2,10 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import React, { useCallback, type FC, useEffect } from 'react';
5
+ import React, { useCallback, type FC } from 'react';
6
6
 
7
- import { CollaborationActions, createIntent, useIntentDispatcher } from '@dxos/app-framework';
8
7
  import { type AssociatedArtifact } from '@dxos/artifact';
9
8
  import { invariant } from '@dxos/invariant';
10
- import { DXN } from '@dxos/keys';
11
- import { makeRef, refFromDXN } from '@dxos/live-object';
12
9
  import { log } from '@dxos/log';
13
10
  import { getSpace } from '@dxos/react-client/echo';
14
11
  import { type ThemedClassName } from '@dxos/react-ui';
@@ -38,27 +35,8 @@ export const ThreadContainer: FC<ThemedClassName<ThreadContainerProps>> = ({
38
35
  const contextProvider = useContextProvider(space);
39
36
  const processor = useChatProcessor({ chat, space, settings, part, associatedArtifact });
40
37
  const messageQueue = useMessageQueue(chat);
41
- const { dispatchPromise: dispatch } = useIntentDispatcher();
42
- // TODO(thure): This will be referentially new on every render, is it causing overreactivity?
43
38
  const messages = [...(messageQueue?.items ?? []), ...processor.messages.value];
44
39
 
45
- // Post last message to document.
46
- useEffect(() => {
47
- if (!processor.streaming.value && messageQueue?.items) {
48
- const message = messageQueue.items[messageQueue.items.length - 1];
49
- if (space && chat && message && dispatch && associatedArtifact) {
50
- void dispatch(
51
- createIntent(CollaborationActions.InsertContent, {
52
- spaceId: space.id,
53
- target: makeRef(associatedArtifact),
54
- object: refFromDXN(new DXN(DXN.kind.QUEUE, [...chat.assistantChatQueue.dxn.parts, message.id])),
55
- label: 'View proposal',
56
- }),
57
- );
58
- }
59
- }
60
- }, [messageQueue, associatedArtifact, processor.streaming.value]);
61
-
62
40
  const handleSubmit = useCallback(
63
41
  (text: string) => {
64
42
  // Don't accept input if still processing.
@@ -96,11 +74,11 @@ export const ThreadContainer: FC<ThemedClassName<ThreadContainerProps>> = ({
96
74
  processing={processor.streaming.value}
97
75
  error={processor.error.value}
98
76
  tools={processor.tools}
99
- contextProvider={contextProvider}
100
77
  onSubmit={handleSubmit}
101
78
  onCancel={handleCancel}
102
79
  onPrompt={handleSubmit}
103
80
  onOpenChange={onOpenChange}
81
+ contextProvider={contextProvider}
104
82
  {...props}
105
83
  />
106
84
  );
@@ -105,7 +105,7 @@ const components: Record<string, BlockComponent> = {
105
105
  return (
106
106
  <ToggleContainer
107
107
  // open={open}
108
- defaultOpen={systemDispositions.includes(block.disposition ?? '') && block.pending}
108
+ defaultOpen={block.disposition === 'cot' && block.pending}
109
109
  title={title}
110
110
  icon={
111
111
  block.pending ? (
@@ -115,7 +115,7 @@ const components: Record<string, BlockComponent> = {
115
115
  >
116
116
  <MarkdownViewer
117
117
  content={block.text}
118
- classNames={['pbe-2', systemDispositions.includes(block.disposition ?? '') && 'text-sm text-subdued']}
118
+ classNames={['pbe-2', block.disposition === 'cot' && 'text-sm text-subdued']}
119
119
  />
120
120
  </ToggleContainer>
121
121
  );
@@ -193,7 +193,4 @@ const titles: Record<string, string> = {
193
193
  ['tool_use' as const]: 'Tool request',
194
194
  ['tool_result' as const]: 'Tool result',
195
195
  ['tool_list' as const]: 'Tools',
196
- ['artifact-update' as const]: 'Artifact(s) changed',
197
196
  };
198
-
199
- const systemDispositions: string[] = ['cot', 'artifact-update'];
@@ -44,7 +44,7 @@ const meta: Meta<typeof Toolbox> = {
44
44
  await client.halo.createIdentity();
45
45
  },
46
46
  }),
47
- SpacePlugin(),
47
+ SpacePlugin({ observability: false }),
48
48
  SettingsPlugin(),
49
49
  IntentPlugin(),
50
50
  ChessPlugin(),
@@ -5,7 +5,7 @@
5
5
  import { lazy } from 'react';
6
6
 
7
7
  export * from './AssistantSettings';
8
- export * from './PromptSettings';
8
+ export * from './ServiceRegistry';
9
9
  export * from './TemplateEditor';
10
10
  export * from './Thread';
11
11
  export * from './Toolbox';
@@ -9,7 +9,7 @@ import { type ArtifactDefinition, type Message, type MessageContentBlock, type T
9
9
  import { type AIServiceClient, AISession, DEFAULT_EDGE_MODEL, type GenerateRequest } from '@dxos/assistant';
10
10
  import { invariant } from '@dxos/invariant';
11
11
  import { log } from '@dxos/log';
12
- import { getVersion, type Space } from '@dxos/react-client/echo';
12
+ import { type Space } from '@dxos/react-client/echo';
13
13
 
14
14
  // TODO(burdon): Factor out.
15
15
  declare global {
@@ -99,7 +99,7 @@ export class ChatProcessor {
99
99
  * Make GPT request.
100
100
  */
101
101
  async request(message: string, options: RequestOptions = {}): Promise<Message[]> {
102
- this._session = new AISession({ operationModel: 'configured' });
102
+ this._session = new AISession({ operationModel: 'immediate' });
103
103
 
104
104
  // Message complete.
105
105
  this._session.message.on((message) => {
@@ -125,39 +125,17 @@ export class ChatProcessor {
125
125
  client: this._ai,
126
126
  history: options.history ?? [],
127
127
  artifacts: this._artifacts ?? [],
128
- requiredArtifactIds: this._artifacts?.map((artifact) => artifact.id) ?? [],
129
128
  tools: this._tools ?? [],
130
129
  prompt: message,
131
130
  systemPrompt: this._options.systemPrompt,
132
131
  extensions: this._extensions,
133
- artifactDiffResolver: async (artifacts) => {
134
- const space = this._extensions?.space;
135
- if (!space) {
136
- return new Map();
137
- }
138
- const versions = new Map();
139
- await Promise.all(
140
- artifacts.map(async (artifact) => {
141
- const {
142
- objects: [object],
143
- } = await space.db.query({ id: artifact.id }).run();
144
- if (!object) {
145
- return;
146
- }
147
- versions.set(artifact.id, {
148
- version: getVersion(object),
149
- diff: `Current state: ${JSON.stringify(object)}`,
150
- });
151
- }),
152
- );
153
- return versions;
154
- },
155
132
  generationOptions: {
156
133
  model: this._options.model,
157
134
  },
158
135
  });
159
136
 
160
- log('completed', { messages });
137
+ log.info('completed', { messages });
138
+
161
139
  options.onComplete?.(this._pending.value);
162
140
  } catch (err) {
163
141
  log.catch(err);