@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
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { asyncTimeout } from '@dxos/async';
|
|
6
|
+
import type { ReactiveEchoObject } from '@dxos/echo-db';
|
|
7
|
+
import { getTypename } from '@dxos/echo-schema';
|
|
8
|
+
import { log } from '@dxos/log';
|
|
9
|
+
import { Filter, getSpace, ResultFormat } from '@dxos/react-client/echo';
|
|
10
|
+
|
|
11
|
+
// TODO(burdon): Move into assistant-protocol.
|
|
12
|
+
export type ThreadContext = {
|
|
13
|
+
subject?: ReactiveEchoObject<any>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const createSystemInstructions = async (context: ThreadContext): Promise<string> => {
|
|
17
|
+
let instructions = `
|
|
18
|
+
<instructions>
|
|
19
|
+
Before replying always think step-by-step on how to proceed.
|
|
20
|
+
Print your thoughts inside <cot> tags.
|
|
21
|
+
|
|
22
|
+
<example>
|
|
23
|
+
<cot>To answer the question I need to ...</cot>
|
|
24
|
+
</example>
|
|
25
|
+
</instructions>
|
|
26
|
+
|
|
27
|
+
<current_time>${new Date().toLocaleString()}</current_time>
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
if (context.subject) {
|
|
31
|
+
instructions += `
|
|
32
|
+
<user_attention>
|
|
33
|
+
The user is currently interacting with an object in Composer application:
|
|
34
|
+
|
|
35
|
+
${await formatContextObject(context.subject)}
|
|
36
|
+
</user_attention>
|
|
37
|
+
`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return looseFormatXml(instructions);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const formatContextObject = async (object: ReactiveEchoObject<any>): Promise<string> => {
|
|
44
|
+
let data;
|
|
45
|
+
try {
|
|
46
|
+
data = await asyncTimeout(preprocessContextObject(object), CONTEXT_OBJECT_QUERY_TIMEOUT);
|
|
47
|
+
} catch (err: any) {
|
|
48
|
+
log.error('Failed to preprocess context object:', { err });
|
|
49
|
+
data = object;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (typeof data === 'string') {
|
|
53
|
+
return data;
|
|
54
|
+
} else {
|
|
55
|
+
return `
|
|
56
|
+
<object>
|
|
57
|
+
<type>${getTypename(object)}</type>
|
|
58
|
+
<id>${object.id}</id>
|
|
59
|
+
${formatObjectAsXMLTags(data)}
|
|
60
|
+
</object>
|
|
61
|
+
`;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const preprocessContextObject = async (object: ReactiveEchoObject<any>): Promise<Record<string, any> | string> => {
|
|
66
|
+
const space = getSpace(object);
|
|
67
|
+
if (!space) {
|
|
68
|
+
return { ...object };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// TODO(dmaretskyi): Serialize based on schema annotations.
|
|
72
|
+
switch (getTypename(object)) {
|
|
73
|
+
// TODO(dmaretskyi): Reference types somehow without plugin-automation depending on other plugins.
|
|
74
|
+
case 'dxos.org/type/Document': {
|
|
75
|
+
const data = space.db
|
|
76
|
+
.query({ id: object.id }, { format: ResultFormat.Plain, include: { content: true } })
|
|
77
|
+
.first() ?? { content: { content: '' } };
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
...data,
|
|
81
|
+
threads: undefined,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
case 'dxos.org/type/Table': {
|
|
86
|
+
// TODO(dmaretskyi): Load references.
|
|
87
|
+
const schema = object.view ? space?.db.schemaRegistry.getSchema(object.view.query.typename) : undefined;
|
|
88
|
+
const { objects: rows } =
|
|
89
|
+
(schema &&
|
|
90
|
+
(await space.db
|
|
91
|
+
.query(Filter.schema(schema), { format: ResultFormat.Plain, limit: TABLE_ROWS_LIMIT })
|
|
92
|
+
.run())) ??
|
|
93
|
+
{};
|
|
94
|
+
|
|
95
|
+
// TODO(dmaretskyi): Format table schema.
|
|
96
|
+
return `
|
|
97
|
+
<object>
|
|
98
|
+
<id>${object.id}</id>
|
|
99
|
+
<type>${getTypename(object)}</type>
|
|
100
|
+
${formatObjectAsXMLTags(object)}
|
|
101
|
+
|
|
102
|
+
<rows>
|
|
103
|
+
<!-- Limited to first ${TABLE_ROWS_LIMIT} rows. -->
|
|
104
|
+
${rows
|
|
105
|
+
?.map(
|
|
106
|
+
(row: any) => `<row>
|
|
107
|
+
${formatObjectAsXMLTags(row)}
|
|
108
|
+
</row>`,
|
|
109
|
+
)
|
|
110
|
+
.join('\n')}
|
|
111
|
+
</rows>
|
|
112
|
+
|
|
113
|
+
`;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
default:
|
|
117
|
+
return { ...object };
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const formatObjectAsXMLTags = (object: any, depth = 1): string => {
|
|
122
|
+
return Object.entries(object)
|
|
123
|
+
.filter(([key, value]) => ['string', 'number', 'boolean', 'object'].includes(typeof value))
|
|
124
|
+
.map(([key, value]) => {
|
|
125
|
+
if (typeof value === 'object' && value !== null) {
|
|
126
|
+
if (depth === 0) {
|
|
127
|
+
return '';
|
|
128
|
+
} else {
|
|
129
|
+
return `<${key}>
|
|
130
|
+
${formatObjectAsXMLTags(value, depth - 1)}
|
|
131
|
+
</${key}>`;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return `<${key}>${value}</${key}>`;
|
|
136
|
+
})
|
|
137
|
+
.join('\n');
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const CONTEXT_OBJECT_QUERY_TIMEOUT = 5_000;
|
|
141
|
+
|
|
142
|
+
const TABLE_ROWS_LIMIT = 10;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Formats XML indentation for instructions so they are easier to read during debugging.
|
|
146
|
+
*/
|
|
147
|
+
const looseFormatXml = (xml: string): string => {
|
|
148
|
+
let currentIndent = 0;
|
|
149
|
+
|
|
150
|
+
return xml
|
|
151
|
+
.split('\n')
|
|
152
|
+
.map((line) => {
|
|
153
|
+
if (line.match(RE_CLOSE_TAG_LINE)) {
|
|
154
|
+
currentIndent--;
|
|
155
|
+
}
|
|
156
|
+
const indent = currentIndent;
|
|
157
|
+
if (line.match(RE_OPEN_TAG_LINE)) {
|
|
158
|
+
currentIndent++;
|
|
159
|
+
}
|
|
160
|
+
return ' '.repeat(indent * 2) + line.trimStart();
|
|
161
|
+
})
|
|
162
|
+
.join('\n');
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const RE_OPEN_TAG_LINE = /^[ ]*<[a-zA-Z0-9\-_]+>[ ]*$/;
|
|
166
|
+
const RE_CLOSE_TAG_LINE = /^[ ]*<\/[a-zA-Z0-9\-_]+>[ ]*$/;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import '@dxos-theme';
|
|
6
|
+
|
|
7
|
+
import { type Meta } from '@storybook/react';
|
|
8
|
+
import React from 'react';
|
|
9
|
+
|
|
10
|
+
import { FunctionTrigger } from '@dxos/functions';
|
|
11
|
+
import { FunctionType } from '@dxos/plugin-script/types';
|
|
12
|
+
import { create, useSpaces } from '@dxos/react-client/echo';
|
|
13
|
+
import { withClientProvider } from '@dxos/react-client/testing';
|
|
14
|
+
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
15
|
+
|
|
16
|
+
import { AutomationPanel } from './AutomationPanel';
|
|
17
|
+
import { functions } from '../../testing';
|
|
18
|
+
import translations from '../../translations';
|
|
19
|
+
import { ChainPromptType } from '../../types';
|
|
20
|
+
|
|
21
|
+
const DefaultStory = () => {
|
|
22
|
+
const spaces = useSpaces();
|
|
23
|
+
const space = spaces[1];
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div role='none' className='flex w-[350px] border border-separator overflow-hidden'>
|
|
27
|
+
<AutomationPanel space={space} />
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const meta: Meta = {
|
|
33
|
+
title: 'plugins/plugin-automation/AutomationPanel',
|
|
34
|
+
component: AutomationPanel,
|
|
35
|
+
render: DefaultStory,
|
|
36
|
+
decorators: [
|
|
37
|
+
withClientProvider({
|
|
38
|
+
createIdentity: true,
|
|
39
|
+
createSpace: true,
|
|
40
|
+
types: [FunctionType, FunctionTrigger, ChainPromptType],
|
|
41
|
+
onSpaceCreated: ({ space }) => {
|
|
42
|
+
for (const fn of functions) {
|
|
43
|
+
space.db.add(create(FunctionType, fn));
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
}),
|
|
47
|
+
withLayout({ fullscreen: true, tooltips: true, classNames: 'flex justify-center m-2' }),
|
|
48
|
+
withTheme,
|
|
49
|
+
],
|
|
50
|
+
parameters: {
|
|
51
|
+
translations,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export default meta;
|
|
56
|
+
|
|
57
|
+
export const Default = {};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { useState } from 'react';
|
|
6
|
+
|
|
7
|
+
import { S } from '@dxos/echo-schema';
|
|
8
|
+
import { FunctionTriggerSchema, FunctionTrigger, type FunctionTriggerType } from '@dxos/functions';
|
|
9
|
+
import { FunctionType, ScriptType } from '@dxos/plugin-script';
|
|
10
|
+
import { type Client, useClient } from '@dxos/react-client';
|
|
11
|
+
import { create, Filter, useQuery, type Space, type ReactiveObject, getSpace } from '@dxos/react-client/echo';
|
|
12
|
+
import { IconButton, Input, useTranslation, Button } from '@dxos/react-ui';
|
|
13
|
+
import { List } from '@dxos/react-ui-list';
|
|
14
|
+
import { ghostHover, mx } from '@dxos/react-ui-theme';
|
|
15
|
+
|
|
16
|
+
import { AUTOMATION_PLUGIN } from '../../meta';
|
|
17
|
+
import { TriggerEditor, type TriggerEditorProps } from '../TriggerEditor';
|
|
18
|
+
|
|
19
|
+
const grid = 'grid grid-cols-[40px_1fr_32px] min-bs-[2.5rem]';
|
|
20
|
+
|
|
21
|
+
export type AutomationPanelProps = {
|
|
22
|
+
space: Space;
|
|
23
|
+
object?: ReactiveObject<any>;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// TODO(burdon): Factor out common layout with ViewEditor.
|
|
27
|
+
export const AutomationPanel = ({ space }: AutomationPanelProps) => {
|
|
28
|
+
const { t } = useTranslation(AUTOMATION_PLUGIN);
|
|
29
|
+
const client = useClient();
|
|
30
|
+
const triggers = useQuery(space, Filter.schema(FunctionTrigger));
|
|
31
|
+
const functions = useQuery(space, Filter.schema(FunctionType));
|
|
32
|
+
const scripts = useQuery(space, Filter.schema(ScriptType));
|
|
33
|
+
|
|
34
|
+
const [trigger, setTrigger] = useState<FunctionTriggerType>();
|
|
35
|
+
const [selected, setSelected] = useState<FunctionTrigger>();
|
|
36
|
+
|
|
37
|
+
const handleSelect = (trigger: FunctionTrigger) => {
|
|
38
|
+
const { id: _, ...values } = trigger;
|
|
39
|
+
setTrigger(values);
|
|
40
|
+
setSelected(trigger);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const handleAdd = () => {
|
|
44
|
+
setTrigger(create(FunctionTriggerSchema, {}));
|
|
45
|
+
setSelected(undefined);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const handleDelete = (trigger: FunctionTrigger) => {
|
|
49
|
+
space.db.remove(trigger);
|
|
50
|
+
setTrigger(undefined);
|
|
51
|
+
setSelected(undefined);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const handleSave: TriggerEditorProps['onSave'] = (trigger) => {
|
|
55
|
+
if (selected) {
|
|
56
|
+
Object.assign(selected, trigger);
|
|
57
|
+
} else {
|
|
58
|
+
space.db.add(create(FunctionTrigger, trigger));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
setTrigger(undefined);
|
|
62
|
+
setSelected(undefined);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const handleCancel: TriggerEditorProps['onCancel'] = () => {
|
|
66
|
+
setTrigger(undefined);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<div className='flex flex-col w-full divide-y divide-separator overflow-y-auto'>
|
|
71
|
+
<List.Root<FunctionTrigger> items={triggers} isItem={S.is(FunctionTrigger)} getId={(field) => field.id}>
|
|
72
|
+
{({ items: triggers }) => (
|
|
73
|
+
<div role='list' className='flex flex-col w-full'>
|
|
74
|
+
{triggers?.map((trigger) => (
|
|
75
|
+
<List.Item<FunctionTrigger>
|
|
76
|
+
key={trigger.id}
|
|
77
|
+
item={trigger}
|
|
78
|
+
classNames={mx(grid, ghostHover, 'items-center')}
|
|
79
|
+
>
|
|
80
|
+
<Input.Root>
|
|
81
|
+
<Input.Switch checked={trigger.enabled} onCheckedChange={(checked) => (trigger.enabled = checked)} />
|
|
82
|
+
</Input.Root>
|
|
83
|
+
|
|
84
|
+
<div className={'flex'}>
|
|
85
|
+
<List.ItemTitle classNames='px-2 cursor-pointer w-0 shrink' onClick={() => handleSelect(trigger)}>
|
|
86
|
+
{getFunctionName(scripts, functions, trigger)}
|
|
87
|
+
</List.ItemTitle>
|
|
88
|
+
|
|
89
|
+
{/* TODO: a better way to expose URL copy action */}
|
|
90
|
+
<Button onClick={() => navigator.clipboard.writeText(getWebhookUrl(client, trigger))}>
|
|
91
|
+
Copy URL
|
|
92
|
+
</Button>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<List.ItemDeleteButton onClick={() => handleDelete(trigger)} />
|
|
96
|
+
</List.Item>
|
|
97
|
+
))}
|
|
98
|
+
</div>
|
|
99
|
+
)}
|
|
100
|
+
</List.Root>
|
|
101
|
+
|
|
102
|
+
{trigger && (
|
|
103
|
+
<TriggerEditor
|
|
104
|
+
space={space}
|
|
105
|
+
storedTrigger={selected}
|
|
106
|
+
trigger={trigger}
|
|
107
|
+
onSave={handleSave}
|
|
108
|
+
onCancel={handleCancel}
|
|
109
|
+
/>
|
|
110
|
+
)}
|
|
111
|
+
|
|
112
|
+
{!trigger && (
|
|
113
|
+
<div className='flex p-2 justify-center'>
|
|
114
|
+
<IconButton icon='ph--plus--regular' label={t('new trigger')} onClick={handleAdd} />
|
|
115
|
+
</div>
|
|
116
|
+
)}
|
|
117
|
+
</div>
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const getWebhookUrl = (client: Client, trigger: FunctionTrigger) => {
|
|
122
|
+
const spaceId = getSpace(trigger)!.id;
|
|
123
|
+
const edgeUrl = new URL(client.config.values.runtime!.services!.edge!.url!);
|
|
124
|
+
const isSecure = edgeUrl.protocol.startsWith('https') || edgeUrl.protocol.startsWith('wss');
|
|
125
|
+
edgeUrl.protocol = isSecure ? 'https' : 'http';
|
|
126
|
+
return new URL(`/webhook/${spaceId}:${trigger.id}`, edgeUrl).toString();
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const getFunctionName = (scripts: ScriptType[], functions: FunctionType[], trigger: FunctionTriggerType) => {
|
|
130
|
+
const functionObject = functions.find((fn) => fn.name === trigger.function);
|
|
131
|
+
if (!functionObject) {
|
|
132
|
+
return trigger.function;
|
|
133
|
+
}
|
|
134
|
+
return scripts.find((s) => functionObject.source?.id === s.id)?.name ?? functionObject.name;
|
|
135
|
+
};
|
|
@@ -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 { create } from '@dxos/
|
|
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';
|
|
@@ -7,47 +7,18 @@ import '@dxos-theme';
|
|
|
7
7
|
import { type Meta } from '@storybook/react';
|
|
8
8
|
import React, { useEffect, useState } from 'react';
|
|
9
9
|
|
|
10
|
-
import { AST, S, create, toJsonSchema } from '@dxos/echo-schema';
|
|
11
10
|
import { FunctionTrigger, TriggerKind } from '@dxos/functions';
|
|
11
|
+
import { create } from '@dxos/live-object';
|
|
12
12
|
import { FunctionType } from '@dxos/plugin-script/types';
|
|
13
13
|
import { useSpaces } from '@dxos/react-client/echo';
|
|
14
14
|
import { withClientProvider } from '@dxos/react-client/testing';
|
|
15
15
|
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
16
16
|
|
|
17
17
|
import { TriggerEditor } from './TriggerEditor';
|
|
18
|
+
import { functions } from '../../testing';
|
|
18
19
|
import translations from '../../translations';
|
|
19
20
|
import { ChainPromptType } from '../../types';
|
|
20
21
|
|
|
21
|
-
// TODO(burdon): Extract type?
|
|
22
|
-
const functions = [
|
|
23
|
-
{
|
|
24
|
-
name: 'example.com/function/chess',
|
|
25
|
-
version: 1,
|
|
26
|
-
inputSchema: toJsonSchema(
|
|
27
|
-
S.Struct({
|
|
28
|
-
level: S.Number.annotations({
|
|
29
|
-
[AST.TitleAnnotationId]: 'Level',
|
|
30
|
-
}),
|
|
31
|
-
}),
|
|
32
|
-
),
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
name: 'example.com/function/forex',
|
|
36
|
-
version: 1,
|
|
37
|
-
binding: 'FOREX',
|
|
38
|
-
inputSchema: toJsonSchema(
|
|
39
|
-
S.Struct({
|
|
40
|
-
from: S.String.annotations({
|
|
41
|
-
[AST.TitleAnnotationId]: 'Currency from',
|
|
42
|
-
}),
|
|
43
|
-
to: S.String.annotations({
|
|
44
|
-
[AST.TitleAnnotationId]: 'Currency to',
|
|
45
|
-
}),
|
|
46
|
-
}),
|
|
47
|
-
),
|
|
48
|
-
},
|
|
49
|
-
];
|
|
50
|
-
|
|
51
22
|
const DefaultStory = () => {
|
|
52
23
|
const spaces = useSpaces();
|
|
53
24
|
const space = spaces[1];
|
|
@@ -82,7 +53,6 @@ const meta: Meta = {
|
|
|
82
53
|
createSpace: true,
|
|
83
54
|
types: [FunctionType, FunctionTrigger, ChainPromptType],
|
|
84
55
|
onSpaceCreated: ({ space }) => {
|
|
85
|
-
console.log(space.id);
|
|
86
56
|
for (const fn of functions) {
|
|
87
57
|
space.db.add(create(FunctionType, fn));
|
|
88
58
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
7
|
import { FunctionTriggerSchema, type FunctionTriggerType, type FunctionTrigger, TriggerKind } from '@dxos/functions';
|
|
8
|
-
import { FunctionType } from '@dxos/plugin-script/types';
|
|
8
|
+
import { FunctionType, ScriptType } from '@dxos/plugin-script/types';
|
|
9
9
|
import { Filter, useQuery, type Space } from '@dxos/react-client/echo';
|
|
10
10
|
import { useTranslation } from '@dxos/react-ui';
|
|
11
11
|
import { Form, SelectInput } from '@dxos/react-ui-form';
|
|
@@ -14,67 +14,35 @@ import { AUTOMATION_PLUGIN } from '../../meta';
|
|
|
14
14
|
|
|
15
15
|
export type TriggerEditorProps = {
|
|
16
16
|
space: Space;
|
|
17
|
-
trigger:
|
|
17
|
+
trigger: FunctionTriggerType;
|
|
18
|
+
storedTrigger?: FunctionTrigger;
|
|
19
|
+
onSave?: (trigger: Omit<FunctionTrigger, 'id'>) => void;
|
|
20
|
+
onCancel?: () => void;
|
|
18
21
|
};
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
// TODO(burdon): Function meta (remove meta from existing trigger def).
|
|
22
|
-
// TODO(burdon): Actual integration.
|
|
23
|
-
|
|
24
|
-
export const TriggerEditor = ({ space, trigger }: TriggerEditorProps) => {
|
|
23
|
+
export const TriggerEditor = ({ space, trigger, onSave, onCancel, storedTrigger }: TriggerEditorProps) => {
|
|
25
24
|
const { t } = useTranslation(AUTOMATION_PLUGIN);
|
|
26
25
|
const functions = useQuery(space, Filter.schema(FunctionType));
|
|
26
|
+
const scripts = useQuery(space, Filter.schema(ScriptType));
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
// useEffect(() => {
|
|
32
|
-
// void space.db.schemaRegistry
|
|
33
|
-
// .query()
|
|
34
|
-
// .then((schemas) => {
|
|
35
|
-
// // TODO(zan): We should solve double adding of stored schemas in the schema registry.
|
|
36
|
-
// state.schemas = distinctBy([...state.schemas, ...schemas], (schema) => schema.typename).sort((a, b) =>
|
|
37
|
-
// a.typename < b.typename ? -1 : 1,
|
|
38
|
-
// );
|
|
39
|
-
// })
|
|
40
|
-
// .catch(() => {});
|
|
41
|
-
// }, [space]);
|
|
42
|
-
|
|
43
|
-
// Keen an enriched version of the schema in memory so we can share it with prompt editor.
|
|
44
|
-
// useEffect(() => {
|
|
45
|
-
// const spec = trigger.spec;
|
|
46
|
-
// invariant(spec);
|
|
47
|
-
// if (spec.type === 'subscription') {
|
|
48
|
-
// if (spec.filter) {
|
|
49
|
-
// const type = spec.filter.type;
|
|
50
|
-
// const foundSchema = state.schemas.find((schema) => schema.typename === type);
|
|
51
|
-
// if (foundSchema) {
|
|
52
|
-
// state.selectedSchema[trigger.id] = foundSchema;
|
|
53
|
-
// }
|
|
54
|
-
// }
|
|
55
|
-
// }
|
|
56
|
-
// // TODO(burdon): API issue.
|
|
57
|
-
// }, [JSON.stringify(trigger.spec), state.schemas]);
|
|
58
|
-
|
|
59
|
-
// useEffect(() => {
|
|
60
|
-
// if (!trigger.meta) {
|
|
61
|
-
// const extension = getFunctionMetaExtension(trigger, script);
|
|
62
|
-
// trigger.meta = extension?.initialValue?.();
|
|
63
|
-
// }
|
|
64
|
-
// }, [trigger.function, trigger.meta]);
|
|
28
|
+
const handleSave = (values: FunctionTriggerType) => {
|
|
29
|
+
onSave?.(values);
|
|
30
|
+
};
|
|
65
31
|
|
|
66
32
|
return (
|
|
67
33
|
<Form<FunctionTriggerType>
|
|
68
34
|
schema={FunctionTriggerSchema}
|
|
69
35
|
values={trigger}
|
|
70
36
|
filter={(props) => props.filter((p) => p.name !== 'meta')}
|
|
37
|
+
onSave={handleSave}
|
|
38
|
+
onCancel={onCancel}
|
|
71
39
|
Custom={{
|
|
72
40
|
['function' satisfies keyof FunctionTriggerType]: (props) => (
|
|
73
41
|
<SelectInput<FunctionTriggerType>
|
|
74
42
|
{...props}
|
|
75
|
-
options={functions.map((
|
|
76
|
-
value: name,
|
|
77
|
-
label:
|
|
43
|
+
options={functions.map((fn) => ({
|
|
44
|
+
value: fn.name,
|
|
45
|
+
label: getFunctionName(scripts, fn),
|
|
78
46
|
}))}
|
|
79
47
|
/>
|
|
80
48
|
),
|
|
@@ -91,3 +59,7 @@ export const TriggerEditor = ({ space, trigger }: TriggerEditorProps) => {
|
|
|
91
59
|
/>
|
|
92
60
|
);
|
|
93
61
|
};
|
|
62
|
+
|
|
63
|
+
const getFunctionName = (scripts: ScriptType[], fn: FunctionType) => {
|
|
64
|
+
return scripts.find((s) => fn.source?.id === s.id)?.name ?? fn.name;
|
|
65
|
+
};
|
package/src/components/index.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export
|
|
5
|
+
import { lazy } from 'react';
|
|
6
|
+
|
|
7
|
+
export const AssistantPanel = lazy(() => import('./AssistantPanel'));
|
|
8
|
+
export const AutomationPanel = lazy(() => import('./AutomationPanel'));
|
package/src/hooks/email.ts
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { findObjectWithForeignKey } from '@dxos/echo-db';
|
|
6
|
-
import {
|
|
6
|
+
import { foreignKey } from '@dxos/echo-schema';
|
|
7
7
|
import { log } from '@dxos/log';
|
|
8
8
|
import { MailboxType } from '@dxos/plugin-inbox/types';
|
|
9
9
|
import { MessageType } from '@dxos/plugin-space/types';
|
|
10
|
-
import { type Space, Filter } from '@dxos/react-client/echo';
|
|
10
|
+
import { type Space, Filter, create } from '@dxos/react-client/echo';
|
|
11
11
|
|
|
12
12
|
export const SOURCE_ID = 'hub.dxos.network/api/mailbox';
|
|
13
13
|
|
package/src/meta.ts
CHANGED
|
@@ -10,7 +10,7 @@ export default {
|
|
|
10
10
|
id: AUTOMATION_PLUGIN,
|
|
11
11
|
name: 'Automation',
|
|
12
12
|
description: 'Automation workflows.',
|
|
13
|
-
icon: 'ph--
|
|
13
|
+
icon: 'ph--magic-wand--regular',
|
|
14
14
|
source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/experimental/plugin-automation',
|
|
15
15
|
tags: ['experimental'],
|
|
16
16
|
} satisfies PluginMeta;
|
package/src/presets.ts
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { AST, S, toJsonSchema } from '@dxos/echo-schema';
|
|
6
|
+
|
|
7
|
+
export const functions = [
|
|
8
|
+
{
|
|
9
|
+
name: 'example.com/function/chess',
|
|
10
|
+
version: '0.0.1',
|
|
11
|
+
inputSchema: toJsonSchema(
|
|
12
|
+
S.Struct({
|
|
13
|
+
level: S.Number.annotations({
|
|
14
|
+
[AST.TitleAnnotationId]: 'Level',
|
|
15
|
+
}),
|
|
16
|
+
}),
|
|
17
|
+
),
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'example.com/function/forex',
|
|
21
|
+
version: '0.0.1',
|
|
22
|
+
binding: 'FOREX',
|
|
23
|
+
inputSchema: toJsonSchema(
|
|
24
|
+
S.Struct({
|
|
25
|
+
from: S.String.annotations({
|
|
26
|
+
[AST.TitleAnnotationId]: 'Currency from',
|
|
27
|
+
}),
|
|
28
|
+
to: S.String.annotations({
|
|
29
|
+
[AST.TitleAnnotationId]: 'Currency to',
|
|
30
|
+
}),
|
|
31
|
+
}),
|
|
32
|
+
),
|
|
33
|
+
},
|
|
34
|
+
];
|
package/src/translations.ts
CHANGED
package/src/types/types.ts
CHANGED
|
@@ -9,16 +9,14 @@ import type {
|
|
|
9
9
|
SurfaceProvides,
|
|
10
10
|
TranslationsProvides,
|
|
11
11
|
} from '@dxos/app-framework';
|
|
12
|
-
import { type SchemaProvides } from '@dxos/plugin-client';
|
|
13
12
|
import { type PanelProvides } from '@dxos/plugin-deck/types';
|
|
13
|
+
import { type SchemaProvides } from '@dxos/plugin-space';
|
|
14
14
|
|
|
15
|
-
import { AUTOMATION_PLUGIN } from '../meta';
|
|
15
|
+
// import { AUTOMATION_PLUGIN } from '../meta';
|
|
16
16
|
|
|
17
|
-
const AUTOMATION_ACTION = `${AUTOMATION_PLUGIN}/action`;
|
|
17
|
+
// const AUTOMATION_ACTION = `${AUTOMATION_PLUGIN}/action`;
|
|
18
18
|
|
|
19
|
-
export enum AutomationAction {
|
|
20
|
-
CREATE = `${AUTOMATION_ACTION}/create`,
|
|
21
|
-
}
|
|
19
|
+
export enum AutomationAction {}
|
|
22
20
|
|
|
23
21
|
export type AutomationPluginProvides = SurfaceProvides &
|
|
24
22
|
IntentResolverProvides &
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AutomationPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/AutomationPanel.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,eAAO,MAAM,eAAe,yBAY3B,CAAC"}
|