@dxos/plugin-automation 0.7.2 → 0.7.3-main.2dd075e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/AssistantPanel-622FK3DP.mjs +341 -0
- package/dist/lib/browser/AssistantPanel-622FK3DP.mjs.map +7 -0
- package/dist/lib/browser/AutomationPanel-AQMN2CQR.mjs +153 -0
- package/dist/lib/browser/AutomationPanel-AQMN2CQR.mjs.map +7 -0
- package/dist/lib/browser/{chunk-B3Z4NQC2.mjs → chunk-7KB4UMXO.mjs} +2 -8
- package/dist/lib/browser/{chunk-B3Z4NQC2.mjs.map → chunk-7KB4UMXO.mjs.map} +3 -3
- package/dist/lib/browser/{chunk-PQLGYMNY.mjs → chunk-X5KMOH3I.mjs} +2 -2
- package/dist/lib/browser/{chunk-PQLGYMNY.mjs.map → chunk-X5KMOH3I.mjs.map} +1 -1
- package/dist/lib/browser/index.mjs +111 -288
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/meta.mjs +1 -1
- package/dist/lib/browser/types/index.mjs +1 -2
- package/dist/lib/node/AssistantPanel-HRJRVOZD.cjs +361 -0
- package/dist/lib/node/AssistantPanel-HRJRVOZD.cjs.map +7 -0
- package/dist/lib/node/AutomationPanel-HZS5WKI5.cjs +173 -0
- package/dist/lib/node/AutomationPanel-HZS5WKI5.cjs.map +7 -0
- package/dist/lib/node/{chunk-SUMUWFZA.cjs → chunk-CUCUWUAF.cjs} +5 -8
- package/dist/lib/node/{chunk-SUMUWFZA.cjs.map → chunk-CUCUWUAF.cjs.map} +3 -3
- package/dist/lib/node/{chunk-JSZ6PAYL.cjs → chunk-DTJ7XVO2.cjs} +5 -5
- package/dist/lib/node/{chunk-JSZ6PAYL.cjs.map → chunk-DTJ7XVO2.cjs.map} +1 -1
- package/dist/lib/node/index.cjs +145 -315
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.cjs +3 -3
- package/dist/lib/node/meta.cjs.map +1 -1
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/types/index.cjs +6 -7
- package/dist/lib/node/types/index.cjs.map +2 -2
- package/dist/lib/node-esm/AssistantPanel-QIIX7S4V.mjs +342 -0
- package/dist/lib/node-esm/AssistantPanel-QIIX7S4V.mjs.map +7 -0
- package/dist/lib/node-esm/AutomationPanel-JUHOWQWW.mjs +154 -0
- package/dist/lib/node-esm/AutomationPanel-JUHOWQWW.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-PYT2WY4B.mjs → chunk-23LY7DYS.mjs} +2 -7
- package/dist/lib/node-esm/{chunk-PYT2WY4B.mjs.map → chunk-23LY7DYS.mjs.map} +3 -3
- package/dist/lib/node-esm/{chunk-B35UD3D7.mjs → chunk-HNOBZHWK.mjs} +2 -2
- package/dist/lib/node-esm/{chunk-B35UD3D7.mjs.map → chunk-HNOBZHWK.mjs.map} +1 -1
- package/dist/lib/node-esm/index.mjs +111 -288
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/meta.mjs +1 -1
- package/dist/lib/node-esm/types/index.mjs +1 -2
- package/dist/types/src/AutomationPlugin.d.ts.map +1 -1
- package/dist/types/src/components/AssistantPanel/AssistantPanel.d.ts +8 -0
- package/dist/types/src/components/AssistantPanel/AssistantPanel.d.ts.map +1 -0
- package/dist/types/src/components/AssistantPanel/index.d.ts +3 -0
- package/dist/types/src/components/AssistantPanel/index.d.ts.map +1 -0
- package/dist/types/src/components/AssistantPanel/system-instructions.d.ts +6 -0
- package/dist/types/src/components/AssistantPanel/system-instructions.d.ts.map +1 -0
- package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts +8 -0
- package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts.map +1 -0
- package/dist/types/src/components/AutomationPanel/AutomationPanel.stories.d.ts +6 -0
- package/dist/types/src/components/AutomationPanel/AutomationPanel.stories.d.ts.map +1 -0
- package/dist/types/src/components/AutomationPanel/index.d.ts +3 -0
- package/dist/types/src/components/AutomationPanel/index.d.ts.map +1 -0
- package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts +6 -3
- package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts.map +1 -1
- package/dist/types/src/components/TriggerEditor/TriggerEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +2 -3
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/hooks/email.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +2 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/testing.d.ts +12 -0
- package/dist/types/src/testing/testing.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +2 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/schema.d.ts +3 -3
- package/dist/types/src/types/types.d.ts +1 -2
- package/dist/types/src/types/types.d.ts.map +1 -1
- package/package.json +38 -34
- package/src/AutomationPlugin.tsx +89 -36
- package/src/components/AssistantPanel/AssistantPanel.tsx +230 -0
- package/src/components/AssistantPanel/index.ts +7 -0
- package/src/components/AssistantPanel/system-instructions.ts +166 -0
- package/src/components/AutomationPanel/AutomationPanel.stories.tsx +57 -0
- package/src/components/AutomationPanel/AutomationPanel.tsx +135 -0
- package/src/components/AutomationPanel/index.ts +7 -0
- package/src/components/PromptEditor/PromptEditor.stories.tsx +1 -1
- package/src/components/TriggerEditor/TriggerEditor.stories.tsx +2 -32
- package/src/components/TriggerEditor/TriggerEditor.tsx +19 -47
- package/src/components/index.ts +4 -3
- package/src/hooks/email.ts +2 -2
- package/src/meta.ts +1 -1
- package/src/presets.ts +1 -1
- package/src/testing/index.ts +5 -0
- package/src/testing/testing.ts +34 -0
- package/src/translations.ts +3 -0
- package/src/types/types.ts +4 -6
- package/dist/types/src/components/AutomationPanel.d.ts +0 -3
- package/dist/types/src/components/AutomationPanel.d.ts.map +0 -1
- package/src/components/AutomationPanel.tsx +0 -23
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/plugin-automation",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3-main.2dd075e",
|
|
4
4
|
"description": "Prompt chain plugin",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -47,32 +47,36 @@
|
|
|
47
47
|
"@effect/schema": "^0.75.5",
|
|
48
48
|
"@preact/signals-core": "^1.6.0",
|
|
49
49
|
"lodash.get": "^4.4.2",
|
|
50
|
-
"@dxos/app-framework": "0.7.
|
|
51
|
-
"@dxos/
|
|
52
|
-
"@dxos/
|
|
53
|
-
"@dxos/
|
|
54
|
-
"@dxos/echo-db": "0.7.
|
|
55
|
-
"@dxos/
|
|
56
|
-
"@dxos/
|
|
57
|
-
"@dxos/
|
|
58
|
-
"@dxos/
|
|
59
|
-
"@dxos/
|
|
60
|
-
"@dxos/
|
|
61
|
-
"@dxos/
|
|
62
|
-
"@dxos/
|
|
63
|
-
"@dxos/plugin-
|
|
64
|
-
"@dxos/plugin-
|
|
65
|
-
"@dxos/plugin-inbox": "0.7.
|
|
66
|
-
"@dxos/plugin-
|
|
67
|
-
"@dxos/plugin-
|
|
68
|
-
"@dxos/plugin-
|
|
69
|
-
"@dxos/plugin-space": "0.7.
|
|
70
|
-
"@dxos/plugin-
|
|
71
|
-
"@dxos/
|
|
72
|
-
"@dxos/
|
|
73
|
-
"@dxos/react-ui-
|
|
74
|
-
"@dxos/
|
|
75
|
-
"@dxos/
|
|
50
|
+
"@dxos/app-framework": "0.7.3-main.2dd075e",
|
|
51
|
+
"@dxos/assistant": "0.7.3-main.2dd075e",
|
|
52
|
+
"@dxos/context": "0.7.3-main.2dd075e",
|
|
53
|
+
"@dxos/chain": "0.7.3-main.2dd075e",
|
|
54
|
+
"@dxos/echo-db": "0.7.3-main.2dd075e",
|
|
55
|
+
"@dxos/async": "0.7.3-main.2dd075e",
|
|
56
|
+
"@dxos/echo-schema": "0.7.3-main.2dd075e",
|
|
57
|
+
"@dxos/invariant": "0.7.3-main.2dd075e",
|
|
58
|
+
"@dxos/live-object": "0.7.3-main.2dd075e",
|
|
59
|
+
"@dxos/functions": "0.7.3-main.2dd075e",
|
|
60
|
+
"@dxos/log": "0.7.3-main.2dd075e",
|
|
61
|
+
"@dxos/plugin-chess": "0.7.3-main.2dd075e",
|
|
62
|
+
"@dxos/keys": "0.7.3-main.2dd075e",
|
|
63
|
+
"@dxos/plugin-client": "0.7.3-main.2dd075e",
|
|
64
|
+
"@dxos/plugin-deck": "0.7.3-main.2dd075e",
|
|
65
|
+
"@dxos/plugin-inbox": "0.7.3-main.2dd075e",
|
|
66
|
+
"@dxos/plugin-ipfs": "0.7.3-main.2dd075e",
|
|
67
|
+
"@dxos/plugin-graph": "0.7.3-main.2dd075e",
|
|
68
|
+
"@dxos/plugin-markdown": "0.7.3-main.2dd075e",
|
|
69
|
+
"@dxos/plugin-space": "0.7.3-main.2dd075e",
|
|
70
|
+
"@dxos/plugin-script": "0.7.3-main.2dd075e",
|
|
71
|
+
"@dxos/plugin-sketch": "0.7.3-main.2dd075e",
|
|
72
|
+
"@dxos/plugin-stack": "0.7.3-main.2dd075e",
|
|
73
|
+
"@dxos/react-ui-form": "0.7.3-main.2dd075e",
|
|
74
|
+
"@dxos/react-client": "0.7.3-main.2dd075e",
|
|
75
|
+
"@dxos/react-ui-list": "0.7.3-main.2dd075e",
|
|
76
|
+
"@dxos/react-ui-editor": "0.7.3-main.2dd075e",
|
|
77
|
+
"@dxos/react-ui-syntax-highlighter": "0.7.3-main.2dd075e",
|
|
78
|
+
"@dxos/schema": "0.7.3-main.2dd075e",
|
|
79
|
+
"@dxos/util": "0.7.3-main.2dd075e"
|
|
76
80
|
},
|
|
77
81
|
"devDependencies": {
|
|
78
82
|
"@phosphor-icons/react": "^2.1.5",
|
|
@@ -82,18 +86,18 @@
|
|
|
82
86
|
"react": "~18.2.0",
|
|
83
87
|
"react-dom": "~18.2.0",
|
|
84
88
|
"vite": "5.4.7",
|
|
85
|
-
"@dxos/
|
|
86
|
-
"@dxos/
|
|
87
|
-
"@dxos/
|
|
88
|
-
"@dxos/react-ui-theme": "0.7.
|
|
89
|
-
"@dxos/
|
|
89
|
+
"@dxos/react-ui": "0.7.3-main.2dd075e",
|
|
90
|
+
"@dxos/random": "0.7.3-main.2dd075e",
|
|
91
|
+
"@dxos/storybook-utils": "0.7.3-main.2dd075e",
|
|
92
|
+
"@dxos/react-ui-theme": "0.7.3-main.2dd075e",
|
|
93
|
+
"@dxos/echo-db": "0.7.3-main.2dd075e"
|
|
90
94
|
},
|
|
91
95
|
"peerDependencies": {
|
|
92
96
|
"@phosphor-icons/react": "^2.1.5",
|
|
93
97
|
"react": "~18.2.0",
|
|
94
98
|
"react-dom": "~18.2.0",
|
|
95
|
-
"@dxos/react-ui": "0.7.
|
|
96
|
-
"@dxos/react-ui-theme": "0.7.
|
|
99
|
+
"@dxos/react-ui": "0.7.3-main.2dd075e",
|
|
100
|
+
"@dxos/react-ui-theme": "0.7.3-main.2dd075e"
|
|
97
101
|
},
|
|
98
102
|
"publishConfig": {
|
|
99
103
|
"access": "public"
|
package/src/AutomationPlugin.tsx
CHANGED
|
@@ -4,17 +4,26 @@
|
|
|
4
4
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
|
-
import { type PluginDefinition,
|
|
7
|
+
import { parseMetadataResolverPlugin, type PluginDefinition, resolvePlugin } from '@dxos/app-framework';
|
|
8
8
|
import { FunctionTrigger } from '@dxos/functions';
|
|
9
9
|
import { invariant } from '@dxos/invariant';
|
|
10
10
|
import { parseClientPlugin } from '@dxos/plugin-client';
|
|
11
11
|
import { createExtension, toSignal } from '@dxos/plugin-graph';
|
|
12
|
-
import {
|
|
12
|
+
import { memoizeQuery } from '@dxos/plugin-space';
|
|
13
|
+
import {
|
|
14
|
+
getSpace,
|
|
15
|
+
getTypename,
|
|
16
|
+
isEchoObject,
|
|
17
|
+
loadObjectReferences,
|
|
18
|
+
parseId,
|
|
19
|
+
SpaceState,
|
|
20
|
+
} from '@dxos/react-client/echo';
|
|
21
|
+
import { translations as formTranslations } from '@dxos/react-ui-form';
|
|
13
22
|
|
|
14
|
-
import { AutomationPanel } from './components';
|
|
23
|
+
import { AssistantPanel, AutomationPanel } from './components';
|
|
15
24
|
import meta, { AUTOMATION_PLUGIN } from './meta';
|
|
16
25
|
import translations from './translations';
|
|
17
|
-
import {
|
|
26
|
+
import { type AutomationPluginProvides, ChainPromptType, ChainType } from './types';
|
|
18
27
|
|
|
19
28
|
export const AutomationPlugin = (): PluginDefinition<AutomationPluginProvides> => {
|
|
20
29
|
return {
|
|
@@ -30,16 +39,21 @@ export const AutomationPlugin = (): PluginDefinition<AutomationPluginProvides> =
|
|
|
30
39
|
},
|
|
31
40
|
},
|
|
32
41
|
},
|
|
33
|
-
translations,
|
|
42
|
+
translations: [...translations, ...formTranslations],
|
|
34
43
|
echo: {
|
|
35
|
-
|
|
44
|
+
system: [ChainType, ChainPromptType, FunctionTrigger],
|
|
36
45
|
},
|
|
37
46
|
complementary: {
|
|
38
47
|
panels: [
|
|
39
48
|
{
|
|
40
49
|
id: 'automation',
|
|
41
50
|
label: ['open automation panel label', { ns: AUTOMATION_PLUGIN }],
|
|
42
|
-
icon: 'ph--
|
|
51
|
+
icon: 'ph--magic-wand--regular',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'assistant',
|
|
55
|
+
label: ['open assistant panel label', { ns: AUTOMATION_PLUGIN }],
|
|
56
|
+
icon: 'ph--atom--regular',
|
|
43
57
|
},
|
|
44
58
|
],
|
|
45
59
|
},
|
|
@@ -62,11 +76,17 @@ export const AutomationPlugin = (): PluginDefinition<AutomationPluginProvides> =
|
|
|
62
76
|
}
|
|
63
77
|
|
|
64
78
|
const type = 'orphan-settings-for-subject';
|
|
65
|
-
const icon = 'ph--
|
|
79
|
+
const icon = 'ph--magic-wand--regular';
|
|
66
80
|
|
|
67
81
|
const [subjectId] = id.split('~');
|
|
68
82
|
const { spaceId, objectId } = parseId(subjectId);
|
|
69
|
-
const
|
|
83
|
+
const spaces = toSignal(
|
|
84
|
+
(onChange) => client.spaces.subscribe(() => onChange()).unsubscribe,
|
|
85
|
+
() => client.spaces.get(),
|
|
86
|
+
);
|
|
87
|
+
const space = spaces?.find(
|
|
88
|
+
(space) => space.id === spaceId && space.state.get() === SpaceState.SPACE_READY,
|
|
89
|
+
);
|
|
70
90
|
if (!objectId) {
|
|
71
91
|
// TODO(burdon): Ref SPACE_PLUGIN ns.
|
|
72
92
|
const label = space
|
|
@@ -89,18 +109,7 @@ export const AutomationPlugin = (): PluginDefinition<AutomationPluginProvides> =
|
|
|
89
109
|
};
|
|
90
110
|
}
|
|
91
111
|
|
|
92
|
-
const object =
|
|
93
|
-
(onChange) => {
|
|
94
|
-
const timeout = setTimeout(async () => {
|
|
95
|
-
await space?.db.query({ id: objectId }).first();
|
|
96
|
-
onChange();
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
return () => clearTimeout(timeout);
|
|
100
|
-
},
|
|
101
|
-
() => space?.db.getObjectById(objectId),
|
|
102
|
-
subjectId,
|
|
103
|
-
);
|
|
112
|
+
const [object] = memoizeQuery(space, { id: objectId });
|
|
104
113
|
if (!object || !subjectId) {
|
|
105
114
|
return;
|
|
106
115
|
}
|
|
@@ -122,33 +131,77 @@ export const AutomationPlugin = (): PluginDefinition<AutomationPluginProvides> =
|
|
|
122
131
|
};
|
|
123
132
|
},
|
|
124
133
|
}),
|
|
134
|
+
createExtension({
|
|
135
|
+
id: `${AUTOMATION_PLUGIN}/assistant-for-subject`,
|
|
136
|
+
resolver: ({ id }) => {
|
|
137
|
+
// TODO(Zan): Find util (or make one). Effect schema!!
|
|
138
|
+
if (!id.endsWith('~assistant')) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const [subjectId] = id.split('~');
|
|
143
|
+
const { spaceId, objectId } = parseId(subjectId);
|
|
144
|
+
const spaces = toSignal(
|
|
145
|
+
(onChange) => client.spaces.subscribe(() => onChange()).unsubscribe,
|
|
146
|
+
() => client.spaces.get(),
|
|
147
|
+
);
|
|
148
|
+
const space = spaces?.find(
|
|
149
|
+
(space) => space.id === spaceId && space.state.get() === SpaceState.SPACE_READY,
|
|
150
|
+
);
|
|
151
|
+
if (!objectId) {
|
|
152
|
+
// TODO(wittjosiah): Support assistant for arbitrary subjects.
|
|
153
|
+
// This is to ensure that the assistant panel is not stuck on an old object.
|
|
154
|
+
return {
|
|
155
|
+
id,
|
|
156
|
+
type: 'orphan-automation-for-subject',
|
|
157
|
+
data: null,
|
|
158
|
+
properties: {
|
|
159
|
+
icon: 'ph--atom--regular',
|
|
160
|
+
label: ['assistant panel label', { ns: AUTOMATION_PLUGIN }],
|
|
161
|
+
object: null,
|
|
162
|
+
space,
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const [object] = memoizeQuery(space, { id: objectId });
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
id,
|
|
171
|
+
type: 'orphan-automation-for-subject',
|
|
172
|
+
data: null,
|
|
173
|
+
properties: {
|
|
174
|
+
icon: 'ph--atom--regular',
|
|
175
|
+
label: ['assistant panel label', { ns: AUTOMATION_PLUGIN }],
|
|
176
|
+
object,
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
},
|
|
180
|
+
}),
|
|
125
181
|
];
|
|
126
182
|
},
|
|
127
183
|
},
|
|
128
184
|
surface: {
|
|
129
185
|
component: ({ data, role }) => {
|
|
130
186
|
switch (role) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
187
|
+
case 'complementary--assistant':
|
|
188
|
+
return <AssistantPanel subject={data.subject as any} />;
|
|
189
|
+
case 'complementary--automation': {
|
|
190
|
+
const object = data.subject;
|
|
191
|
+
const space = isEchoObject(object) ? getSpace(object) : undefined;
|
|
192
|
+
if (space) {
|
|
193
|
+
invariant(isEchoObject(object));
|
|
194
|
+
return <AutomationPanel space={space} object={object} />;
|
|
195
|
+
}
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
136
198
|
}
|
|
137
199
|
|
|
138
200
|
return null;
|
|
139
201
|
},
|
|
140
202
|
},
|
|
141
203
|
intent: {
|
|
142
|
-
resolver: (intent) => {
|
|
143
|
-
switch (intent.action) {
|
|
144
|
-
case AutomationAction.CREATE: {
|
|
145
|
-
return {
|
|
146
|
-
// data: create(ChainType, { prompts: [] }),
|
|
147
|
-
// data: create(FunctionTrigger, { function: '', spec: { type: 'timer', cron: '' } }),
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
},
|
|
204
|
+
resolver: (intent) => {},
|
|
152
205
|
},
|
|
153
206
|
},
|
|
154
207
|
};
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
/* eslint-disable no-console */
|
|
6
|
+
|
|
7
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
8
|
+
|
|
9
|
+
import { type AIServiceClient, AIServiceClientImpl, ObjectId, type Message } from '@dxos/assistant';
|
|
10
|
+
import type { ReactiveEchoObject } from '@dxos/echo-db';
|
|
11
|
+
import { SpaceId } from '@dxos/keys';
|
|
12
|
+
import { useClient, useConfig } from '@dxos/react-client';
|
|
13
|
+
import { ContextMenu, type ThemedClassName } from '@dxos/react-ui';
|
|
14
|
+
import { Icon, Input, Toolbar, useTranslation } from '@dxos/react-ui';
|
|
15
|
+
import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
|
|
16
|
+
import { mx } from '@dxos/react-ui-theme';
|
|
17
|
+
|
|
18
|
+
import { createSystemInstructions } from './system-instructions';
|
|
19
|
+
import { AUTOMATION_PLUGIN } from '../../meta';
|
|
20
|
+
|
|
21
|
+
const PROPERTIES_ASSISTANT_KEY = 'dxos.assistant.beta.properties';
|
|
22
|
+
|
|
23
|
+
export type AssistantPanelProps = ThemedClassName<{
|
|
24
|
+
subject?: ReactiveEchoObject<any>;
|
|
25
|
+
}>;
|
|
26
|
+
|
|
27
|
+
export const AssistantPanel = ({ subject, classNames }: AssistantPanelProps) => {
|
|
28
|
+
const { t } = useTranslation(AUTOMATION_PLUGIN);
|
|
29
|
+
const config = useConfig();
|
|
30
|
+
const client = useClient();
|
|
31
|
+
const aiClient = useRef<AIServiceClient>();
|
|
32
|
+
const [contextSpaceId, setContextSpaceId] = useState<SpaceId | undefined>();
|
|
33
|
+
const [threadId, setThreadId] = useState<ObjectId | undefined>();
|
|
34
|
+
const [history, setHistory] = useState<Message[]>([]);
|
|
35
|
+
const [input, setInput] = useState('');
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (!aiClient.current) {
|
|
39
|
+
const endpoint = config.values.runtime?.services?.ai?.server;
|
|
40
|
+
if (!endpoint) {
|
|
41
|
+
throw new Error('AI service endpoint is not configured');
|
|
42
|
+
}
|
|
43
|
+
aiClient.current = new AIServiceClientImpl({
|
|
44
|
+
endpoint,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
queueMicrotask(async () => {
|
|
49
|
+
const properties = client.spaces.default.properties;
|
|
50
|
+
|
|
51
|
+
properties[PROPERTIES_ASSISTANT_KEY] ??= {};
|
|
52
|
+
properties[PROPERTIES_ASSISTANT_KEY].contextSpaceId ??= SpaceId.random();
|
|
53
|
+
properties[PROPERTIES_ASSISTANT_KEY].threadId ??= ObjectId.random();
|
|
54
|
+
|
|
55
|
+
const contextSpaceId = properties[PROPERTIES_ASSISTANT_KEY].contextSpaceId;
|
|
56
|
+
const threadId = properties[PROPERTIES_ASSISTANT_KEY].threadId;
|
|
57
|
+
|
|
58
|
+
setContextSpaceId(contextSpaceId);
|
|
59
|
+
setThreadId(threadId);
|
|
60
|
+
|
|
61
|
+
const messages = await aiClient.current!.getMessagesInThread(contextSpaceId, threadId);
|
|
62
|
+
setHistory(messages);
|
|
63
|
+
});
|
|
64
|
+
}, []);
|
|
65
|
+
|
|
66
|
+
const handleRequest = async (input: string) => {
|
|
67
|
+
if (input === '') {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
setInput('');
|
|
72
|
+
|
|
73
|
+
// TODO(dmaretskyi): Can we call `create(Message, { ... })` here?
|
|
74
|
+
const userMessage: Message = {
|
|
75
|
+
id: ObjectId.random(),
|
|
76
|
+
spaceId: contextSpaceId!,
|
|
77
|
+
threadId: threadId!,
|
|
78
|
+
role: 'user',
|
|
79
|
+
content: [{ type: 'text', text: input }],
|
|
80
|
+
};
|
|
81
|
+
await aiClient.current!.insertMessages([userMessage]);
|
|
82
|
+
setHistory([...history, userMessage]);
|
|
83
|
+
|
|
84
|
+
const generationStream = await aiClient.current!.generate({
|
|
85
|
+
model: '@anthropic/claude-3-5-sonnet-20241022',
|
|
86
|
+
spaceId: contextSpaceId!,
|
|
87
|
+
threadId: threadId!,
|
|
88
|
+
tools: [],
|
|
89
|
+
systemPrompt: await getSystemPrompt(),
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const historyBefore = [...history, userMessage];
|
|
93
|
+
for await (const _event of generationStream) {
|
|
94
|
+
setHistory([...historyBefore, ...generationStream.accumulatedMessages]);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
await aiClient.current!.insertMessages(await generationStream.complete());
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const getSystemPrompt = async () => {
|
|
101
|
+
return createSystemInstructions({ subject });
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const clearThread = async () => {
|
|
105
|
+
const properties = client.spaces.default.properties;
|
|
106
|
+
|
|
107
|
+
properties[PROPERTIES_ASSISTANT_KEY] ??= {};
|
|
108
|
+
// properties[PROPERTIES_ASSISTANT_KEY].contextSpaceId ??= SpaceId.random();
|
|
109
|
+
properties[PROPERTIES_ASSISTANT_KEY].threadId = ObjectId.random();
|
|
110
|
+
|
|
111
|
+
// const contextSpaceId = properties[PROPERTIES_ASSISTANT_KEY].contextSpaceId;
|
|
112
|
+
const threadId = properties[PROPERTIES_ASSISTANT_KEY].threadId;
|
|
113
|
+
|
|
114
|
+
// setContextSpaceId(contextSpaceId);
|
|
115
|
+
setThreadId(threadId);
|
|
116
|
+
|
|
117
|
+
const messages = await aiClient.current!.getMessagesInThread(contextSpaceId!, threadId);
|
|
118
|
+
setHistory(messages);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// TODO(burdon): Factor out with script plugin.
|
|
122
|
+
return (
|
|
123
|
+
<div className={mx('flex flex-col h-full overflow-hidden', classNames)}>
|
|
124
|
+
{history.length > 0 && (
|
|
125
|
+
<div className='flex flex-col gap-6 h-full p-2 overflow-x-hidden overflow-y-auto'>
|
|
126
|
+
{history.map((message) => (
|
|
127
|
+
<MessageItem key={message.id} message={message} />
|
|
128
|
+
))}
|
|
129
|
+
</div>
|
|
130
|
+
)}
|
|
131
|
+
|
|
132
|
+
<Toolbar.Root classNames='p-1'>
|
|
133
|
+
<Input.Root>
|
|
134
|
+
<Input.TextInput
|
|
135
|
+
autoFocus
|
|
136
|
+
placeholder={t('ask me anything')}
|
|
137
|
+
value={input}
|
|
138
|
+
onChange={(ev) => setInput(ev.target.value)}
|
|
139
|
+
onKeyDown={(ev) => ev.key === 'Enter' && handleRequest(input)}
|
|
140
|
+
/>
|
|
141
|
+
</Input.Root>
|
|
142
|
+
<ContextMenu.Root>
|
|
143
|
+
<ContextMenu.Trigger asChild>
|
|
144
|
+
<Toolbar.Button onClick={() => handleRequest(input)}>
|
|
145
|
+
<Icon icon='ph--play--regular' size={4} />
|
|
146
|
+
</Toolbar.Button>
|
|
147
|
+
</ContextMenu.Trigger>
|
|
148
|
+
<ContextMenu.Portal>
|
|
149
|
+
<ContextMenu.Content classNames='z-[31]'>
|
|
150
|
+
<ContextMenu.Viewport>
|
|
151
|
+
<ContextMenu.Item onClick={clearThread}>Clear thread</ContextMenu.Item>
|
|
152
|
+
<ContextMenu.Item onClick={async () => console.log(await getSystemPrompt())}>
|
|
153
|
+
Print instructions to console
|
|
154
|
+
</ContextMenu.Item>
|
|
155
|
+
</ContextMenu.Viewport>
|
|
156
|
+
</ContextMenu.Content>
|
|
157
|
+
</ContextMenu.Portal>
|
|
158
|
+
</ContextMenu.Root>
|
|
159
|
+
|
|
160
|
+
{/* <Toolbar.Button onClick={() => (state ? handleStop() : handleClear())}>
|
|
161
|
+
<Icon icon={state ? 'ph--stop--regular' : 'ph--trash--regular'} size={4} />
|
|
162
|
+
</Toolbar.Button> */}
|
|
163
|
+
</Toolbar.Root>
|
|
164
|
+
</div>
|
|
165
|
+
);
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const MessageItem = ({ classNames, message }: ThemedClassName<{ message: Message }>) => {
|
|
169
|
+
const { id: _, role, content } = message;
|
|
170
|
+
const styleContainer = 'flex flex-col overflow-x-hidden overflow-y-auto rounded-md gap-2 divide-y divide-separator';
|
|
171
|
+
|
|
172
|
+
return (
|
|
173
|
+
<div className={mx('flex', role === 'user' ? 'ml-[1rem] justify-end' : 'mr-[1rem]', classNames)}>
|
|
174
|
+
{content.map((content, i) => {
|
|
175
|
+
switch (content.type) {
|
|
176
|
+
case 'text': {
|
|
177
|
+
const { cot, message } = parseMessage(content.text);
|
|
178
|
+
return (
|
|
179
|
+
<div
|
|
180
|
+
key={i}
|
|
181
|
+
role='none'
|
|
182
|
+
className={mx(
|
|
183
|
+
styleContainer,
|
|
184
|
+
role === 'user' ? 'bg-primary-400 dark:bg-primary-600' : 'bg-hoverSurface',
|
|
185
|
+
)}
|
|
186
|
+
>
|
|
187
|
+
{cot && <div className='p-2 whitespace-pre-wrap text-xs text-subdued'>{cot}</div>}
|
|
188
|
+
<div className='p-2 whitespace-pre-wrap'>{message}</div>
|
|
189
|
+
</div>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
case 'tool_use': {
|
|
194
|
+
return (
|
|
195
|
+
<div key={i} className={mx(styleContainer, 'text-xs')}>
|
|
196
|
+
<div>
|
|
197
|
+
<span className='p-2 text-primary'>Tool use</span>: {content.name} {content.id}
|
|
198
|
+
</div>
|
|
199
|
+
<SyntaxHighlighter language='json'>{content.inputJson}</SyntaxHighlighter>
|
|
200
|
+
</div>
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
case 'tool_result': {
|
|
205
|
+
return (
|
|
206
|
+
<div key={i} className={mx(styleContainer, 'text-xs', content.isError && 'text-error')}>
|
|
207
|
+
<div>
|
|
208
|
+
<span className='p-2 text-primary'>Tool result</span>: {content.toolUseId}
|
|
209
|
+
</div>
|
|
210
|
+
<SyntaxHighlighter language='json'>{content.content}</SyntaxHighlighter>
|
|
211
|
+
</div>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return null;
|
|
217
|
+
})}
|
|
218
|
+
</div>
|
|
219
|
+
);
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// TODO(burdon): Move to server-side parsing.
|
|
223
|
+
const parseMessage = (text: string): { cot?: string; message: string } => {
|
|
224
|
+
const regex = /<cot>([\s\S]*?)<\/cot>\s*([\s\S]*)/;
|
|
225
|
+
const match = text.match(regex);
|
|
226
|
+
return {
|
|
227
|
+
cot: match?.[1].trim(),
|
|
228
|
+
message: match?.[2] ?? text ?? '\u00D8',
|
|
229
|
+
};
|
|
230
|
+
};
|