@slates/provider 1.0.0-rc.17 → 1.0.0-rc.18
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/index.cjs +244 -17
- package/dist/index.d.cts +108 -29
- package/dist/index.d.ts +108 -29
- package/dist/index.module.js +237 -17
- package/package.json +2 -2
- package/src/action/action.ts +19 -1
- package/src/action/builder.test.ts +136 -0
- package/src/action/builder.ts +68 -11
- package/src/action/index.ts +2 -1
- package/src/action/publicTool.ts +36 -0
- package/src/action/tool.ts +15 -3
- package/src/adapter/adapter.ts +38 -0
- package/src/adapter/index.test.ts +322 -0
- package/src/adapter/index.ts +2 -0
- package/src/adapter/spec.ts +154 -0
- package/src/axios/trace.ts +3 -3
- package/src/context/context.ts +31 -16
- package/src/context/hook.ts +5 -10
- package/src/index.ts +1 -0
- package/src/specification/slate.ts +38 -2
package/src/action/builder.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
SlateActionScopes,
|
|
11
11
|
SlateActionType,
|
|
12
12
|
SlatePollingOptions,
|
|
13
|
+
SlatePublicToolInvocationHandler,
|
|
13
14
|
SlateToolInvocationHandler,
|
|
14
15
|
SlateTriggerMappingHandler,
|
|
15
16
|
SlateTriggerPollingHandler,
|
|
@@ -26,7 +27,8 @@ export class SlateActionBuilder<
|
|
|
26
27
|
AuthType extends {},
|
|
27
28
|
InputType extends {},
|
|
28
29
|
OutputType extends {},
|
|
29
|
-
Result extends SlateAction<Type, ConfigType, AuthType, any, any
|
|
30
|
+
Result extends SlateAction<Type, ConfigType, AuthType, any, any>,
|
|
31
|
+
IsPublic extends boolean = false
|
|
30
32
|
> {
|
|
31
33
|
#configSchema: z.ZodType<ConfigType>;
|
|
32
34
|
#authSchema: z.ZodType<AuthType>;
|
|
@@ -43,6 +45,7 @@ export class SlateActionBuilder<
|
|
|
43
45
|
InputType,
|
|
44
46
|
OutputType
|
|
45
47
|
> | null = null;
|
|
48
|
+
#interfaceLocked = false;
|
|
46
49
|
|
|
47
50
|
constructor(
|
|
48
51
|
private readonly type: Type,
|
|
@@ -50,7 +53,8 @@ export class SlateActionBuilder<
|
|
|
50
53
|
private readonly params: SlateActionParameters,
|
|
51
54
|
private readonly factory: (
|
|
52
55
|
params: SlateActionCreateParameters<any, any, any, any>
|
|
53
|
-
) => Result
|
|
56
|
+
) => Result,
|
|
57
|
+
private readonly isPublicTool: IsPublic = false as IsPublic
|
|
54
58
|
) {
|
|
55
59
|
this.#configSchema = spec.configSchema;
|
|
56
60
|
this.#authSchema = spec.authSchema;
|
|
@@ -58,21 +62,58 @@ export class SlateActionBuilder<
|
|
|
58
62
|
|
|
59
63
|
input<NewInputType extends {}>(
|
|
60
64
|
schema: z.ZodType<NewInputType>
|
|
61
|
-
): SlateActionBuilder<
|
|
65
|
+
): SlateActionBuilder<
|
|
66
|
+
Type,
|
|
67
|
+
ConfigType,
|
|
68
|
+
AuthType,
|
|
69
|
+
NewInputType,
|
|
70
|
+
OutputType,
|
|
71
|
+
Result,
|
|
72
|
+
IsPublic
|
|
73
|
+
> {
|
|
74
|
+
if (this.#interfaceLocked) {
|
|
75
|
+
throw new SlateDeclarationError('Adapter contract input schema cannot be changed');
|
|
76
|
+
}
|
|
77
|
+
|
|
62
78
|
this.#inputSchema = schema as any;
|
|
63
79
|
return this as any;
|
|
64
80
|
}
|
|
65
81
|
|
|
66
82
|
output<NewOutputType extends {}>(
|
|
67
83
|
schema: z.ZodType<NewOutputType>
|
|
68
|
-
): SlateActionBuilder<
|
|
84
|
+
): SlateActionBuilder<
|
|
85
|
+
Type,
|
|
86
|
+
ConfigType,
|
|
87
|
+
AuthType,
|
|
88
|
+
InputType,
|
|
89
|
+
NewOutputType,
|
|
90
|
+
Result,
|
|
91
|
+
IsPublic
|
|
92
|
+
> {
|
|
93
|
+
if (this.#interfaceLocked) {
|
|
94
|
+
throw new SlateDeclarationError('Adapter contract output schema cannot be changed');
|
|
95
|
+
}
|
|
96
|
+
|
|
69
97
|
this.#outputSchema = schema as any;
|
|
70
98
|
return this as any;
|
|
71
99
|
}
|
|
72
100
|
|
|
101
|
+
lockInterface(): SlateActionBuilder<
|
|
102
|
+
Type,
|
|
103
|
+
ConfigType,
|
|
104
|
+
AuthType,
|
|
105
|
+
InputType,
|
|
106
|
+
OutputType,
|
|
107
|
+
Result,
|
|
108
|
+
IsPublic
|
|
109
|
+
> {
|
|
110
|
+
this.#interfaceLocked = true;
|
|
111
|
+
return this;
|
|
112
|
+
}
|
|
113
|
+
|
|
73
114
|
scopes(
|
|
74
115
|
scopes: SlateActionScopes
|
|
75
|
-
): SlateActionBuilder<Type, ConfigType, AuthType, InputType, OutputType, Result> {
|
|
116
|
+
): SlateActionBuilder<Type, ConfigType, AuthType, InputType, OutputType, Result, IsPublic> {
|
|
76
117
|
validateScopes(scopes);
|
|
77
118
|
this.#scopes = scopes;
|
|
78
119
|
return this;
|
|
@@ -80,7 +121,11 @@ export class SlateActionBuilder<
|
|
|
80
121
|
|
|
81
122
|
authMethods(
|
|
82
123
|
authMethods: string[]
|
|
83
|
-
): SlateActionBuilder<Type, ConfigType, AuthType, InputType, OutputType, Result> {
|
|
124
|
+
): SlateActionBuilder<Type, ConfigType, AuthType, InputType, OutputType, Result, IsPublic> {
|
|
125
|
+
if (this.isPublicTool) {
|
|
126
|
+
throw new SlateDeclarationError('Public tools cannot require authentication methods');
|
|
127
|
+
}
|
|
128
|
+
|
|
84
129
|
this.#authMethods = this.validateAuthMethods(authMethods);
|
|
85
130
|
return this;
|
|
86
131
|
}
|
|
@@ -97,15 +142,22 @@ export class SlateActionBuilder<
|
|
|
97
142
|
}
|
|
98
143
|
|
|
99
144
|
handleInvocation(
|
|
100
|
-
handler:
|
|
101
|
-
|
|
145
|
+
handler: IsPublic extends true
|
|
146
|
+
? SlatePublicToolInvocationHandler<InputType, OutputType>
|
|
147
|
+
: SlateToolInvocationHandler<ConfigType, AuthType, InputType, OutputType>
|
|
148
|
+
): SlateActionBuilder<Type, ConfigType, AuthType, InputType, OutputType, Result, IsPublic> {
|
|
102
149
|
if (this.type !== 'tool') {
|
|
103
150
|
throw new SlateDeclarationError('handleInvocation can only be set for tool actions');
|
|
104
151
|
}
|
|
105
152
|
|
|
106
153
|
this.#toolParams = {
|
|
107
154
|
type: 'tool',
|
|
108
|
-
handleInvocation: handler
|
|
155
|
+
handleInvocation: handler as SlateToolInvocationHandler<
|
|
156
|
+
ConfigType,
|
|
157
|
+
AuthType,
|
|
158
|
+
InputType,
|
|
159
|
+
OutputType
|
|
160
|
+
>
|
|
109
161
|
};
|
|
110
162
|
|
|
111
163
|
return this;
|
|
@@ -117,7 +169,7 @@ export class SlateActionBuilder<
|
|
|
117
169
|
autoRegisterWebhook?: SlateTriggerWebhookAutoRegistrationHandler<ConfigType, AuthType>;
|
|
118
170
|
autoUnregisterWebhook?: SlateTriggerWebhookAutoUnregistrationHandler<ConfigType, AuthType>;
|
|
119
171
|
http?: SlateWebhookHttpOptions;
|
|
120
|
-
}): SlateActionBuilder<Type, ConfigType, AuthType, InputType, OutputType, Result> {
|
|
172
|
+
}): SlateActionBuilder<Type, ConfigType, AuthType, InputType, OutputType, Result, IsPublic> {
|
|
121
173
|
if (this.type !== 'trigger') {
|
|
122
174
|
throw new SlateDeclarationError('handleEvent can only be set for trigger actions');
|
|
123
175
|
}
|
|
@@ -139,7 +191,7 @@ export class SlateActionBuilder<
|
|
|
139
191
|
options?: SlatePollingOptions;
|
|
140
192
|
pollEvents?: SlateTriggerPollingHandler<ConfigType, AuthType, InputType>;
|
|
141
193
|
handleEvent: SlateTriggerMappingHandler<ConfigType, AuthType, InputType, OutputType>;
|
|
142
|
-
}): SlateActionBuilder<Type, ConfigType, AuthType, InputType, OutputType, Result> {
|
|
194
|
+
}): SlateActionBuilder<Type, ConfigType, AuthType, InputType, OutputType, Result, IsPublic> {
|
|
143
195
|
if (this.type !== 'trigger') {
|
|
144
196
|
throw new SlateDeclarationError('handleEvent can only be set for trigger actions');
|
|
145
197
|
}
|
|
@@ -162,6 +214,10 @@ export class SlateActionBuilder<
|
|
|
162
214
|
}
|
|
163
215
|
let authMethods = this.validateAuthMethods(this.#authMethods ?? this.params.authMethods);
|
|
164
216
|
|
|
217
|
+
if (this.isPublicTool && authMethods) {
|
|
218
|
+
throw new SlateDeclarationError('Public tools cannot require authentication methods');
|
|
219
|
+
}
|
|
220
|
+
|
|
165
221
|
if (!this.#inputSchema) {
|
|
166
222
|
throw new SlateDeclarationError('Input schema is not defined');
|
|
167
223
|
}
|
|
@@ -179,6 +235,7 @@ export class SlateActionBuilder<
|
|
|
179
235
|
...this.params,
|
|
180
236
|
scopes,
|
|
181
237
|
authMethods,
|
|
238
|
+
isPublic: this.isPublicTool === true,
|
|
182
239
|
configSchema: this.#configSchema,
|
|
183
240
|
authSchema: this.#authSchema,
|
|
184
241
|
inputSchema: this.#inputSchema,
|
package/src/action/index.ts
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { SlateSpecification } from '../specification/specification';
|
|
2
|
+
import type { SlateActionParameters, SlatePublicToolInvocationHandler } from './action';
|
|
3
|
+
import { SlateActionBuilder } from './builder';
|
|
4
|
+
import { SlateTool } from './tool';
|
|
5
|
+
|
|
6
|
+
export interface SlatePublicToolParameters<InputType extends {}, OutputType extends {}>
|
|
7
|
+
extends SlateActionParameters {
|
|
8
|
+
handleInvocation: SlatePublicToolInvocationHandler<InputType, OutputType>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class SlatePublicTool {
|
|
12
|
+
private constructor() {}
|
|
13
|
+
|
|
14
|
+
static create<ConfigType extends {}, AuthType extends {}>(
|
|
15
|
+
spec: SlateSpecification<ConfigType, AuthType>,
|
|
16
|
+
params: SlateActionParameters
|
|
17
|
+
) {
|
|
18
|
+
return new SlateActionBuilder(
|
|
19
|
+
'tool',
|
|
20
|
+
spec,
|
|
21
|
+
params,
|
|
22
|
+
params => {
|
|
23
|
+
return SlateTool.fromCreateParameters(spec, {
|
|
24
|
+
...params,
|
|
25
|
+
isPublic: true
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
true
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export let publicTool = <ConfigType extends {}, AuthType extends {}>(
|
|
34
|
+
spec: SlateSpecification<ConfigType, AuthType>,
|
|
35
|
+
params: SlateActionParameters
|
|
36
|
+
) => SlatePublicTool.create(spec, params);
|
package/src/action/tool.ts
CHANGED
|
@@ -24,7 +24,7 @@ export class SlateTool<
|
|
|
24
24
|
> extends SlateAction<'tool', ConfigType, AuthType, InputType, OutputType> {
|
|
25
25
|
#handleInvocation: SlateToolInvocationHandler<ConfigType, AuthType, InputType, OutputType>;
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
protected constructor(
|
|
28
28
|
spec: SlateSpecification<ConfigType, AuthType>,
|
|
29
29
|
inputSchema: z.ZodType<InputType>,
|
|
30
30
|
outputSchema: z.ZodType<OutputType>,
|
|
@@ -40,11 +40,23 @@ export class SlateTool<
|
|
|
40
40
|
params: SlateActionParameters
|
|
41
41
|
) {
|
|
42
42
|
return new SlateActionBuilder('tool', spec, params, params => {
|
|
43
|
-
|
|
44
|
-
return new SlateTool(spec, params.inputSchema, params.outputSchema, params);
|
|
43
|
+
return SlateTool.fromCreateParameters(spec, params);
|
|
45
44
|
});
|
|
46
45
|
}
|
|
47
46
|
|
|
47
|
+
static fromCreateParameters<ConfigType extends {}, AuthType extends {}>(
|
|
48
|
+
spec: SlateSpecification<ConfigType, AuthType>,
|
|
49
|
+
params: {
|
|
50
|
+
type: string;
|
|
51
|
+
inputSchema: z.ZodType<any>;
|
|
52
|
+
outputSchema: z.ZodType<any>;
|
|
53
|
+
handleInvocation?: SlateToolInvocationHandler<ConfigType, AuthType, any, any>;
|
|
54
|
+
} & SlateActionParameters
|
|
55
|
+
) {
|
|
56
|
+
if (params.type !== 'tool') throw new Error('Invalid action type for tool');
|
|
57
|
+
return new SlateTool(spec, params.inputSchema, params.outputSchema, params as any);
|
|
58
|
+
}
|
|
59
|
+
|
|
48
60
|
get handleInvocation() {
|
|
49
61
|
return this.#handleInvocation;
|
|
50
62
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { SlateTool, SlateTrigger } from '../action';
|
|
2
|
+
import type { SlateAdapterSpec } from './spec';
|
|
3
|
+
|
|
4
|
+
export class SlateAdapter<ConfigType extends {}, AuthType extends {}> {
|
|
5
|
+
constructor(
|
|
6
|
+
private readonly _spec: SlateAdapterSpec,
|
|
7
|
+
private readonly _tools: SlateTool<ConfigType, AuthType, any, any>[],
|
|
8
|
+
private readonly _triggers: SlateTrigger<ConfigType, AuthType, any, any>[]
|
|
9
|
+
) {}
|
|
10
|
+
|
|
11
|
+
get spec() {
|
|
12
|
+
return this._spec;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
get id() {
|
|
16
|
+
return this._spec.id;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get name() {
|
|
20
|
+
return this._spec.name;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get capabilities() {
|
|
24
|
+
return this._spec.capabilities;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get tools() {
|
|
28
|
+
return this._tools;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get triggers() {
|
|
32
|
+
return this._triggers;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get actions() {
|
|
36
|
+
return [...this._triggers, ...this._tools];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { SlateTool } from '../action/tool';
|
|
4
|
+
import { SlateAuth } from '../auth';
|
|
5
|
+
import { SlateConfig } from '../config';
|
|
6
|
+
import { Slate } from '../specification/slate';
|
|
7
|
+
import { SlateSpecification } from '../specification/specification';
|
|
8
|
+
import { SlateAdapterSpec } from './spec';
|
|
9
|
+
|
|
10
|
+
let createTestSpec = () => {
|
|
11
|
+
let config = SlateConfig.create(z.object({}));
|
|
12
|
+
let auth = SlateAuth.create<{}>().output(z.object({}));
|
|
13
|
+
|
|
14
|
+
return SlateSpecification.create({
|
|
15
|
+
key: 'demo',
|
|
16
|
+
name: 'Demo',
|
|
17
|
+
config,
|
|
18
|
+
auth
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
describe('SlateAdapterSpec', () => {
|
|
23
|
+
it('creates adapter tools and triggers linked to the adapter, then registers them', () => {
|
|
24
|
+
let spec = createTestSpec();
|
|
25
|
+
let gmailAdapterSpec = SlateAdapterSpec.create({
|
|
26
|
+
id: 'gmail',
|
|
27
|
+
name: 'Gmail',
|
|
28
|
+
capabilities: [{ id: 'send_email', value: true }]
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
let sendEmailTool = gmailAdapterSpec
|
|
32
|
+
.tool(spec, {
|
|
33
|
+
key: 'send_email',
|
|
34
|
+
name: 'Send Email'
|
|
35
|
+
})
|
|
36
|
+
.input(z.object({ to: z.string() }))
|
|
37
|
+
.output(z.object({ id: z.string() }))
|
|
38
|
+
.handleInvocation(async () => ({
|
|
39
|
+
output: { id: 'msg_1' },
|
|
40
|
+
message: 'sent'
|
|
41
|
+
}))
|
|
42
|
+
.build();
|
|
43
|
+
|
|
44
|
+
let emailReceivedTrigger = gmailAdapterSpec
|
|
45
|
+
.trigger(spec, {
|
|
46
|
+
key: 'email_received',
|
|
47
|
+
name: 'Email Received'
|
|
48
|
+
})
|
|
49
|
+
.input(z.object({ messageId: z.string() }))
|
|
50
|
+
.output(z.object({ type: z.literal('email.received') }))
|
|
51
|
+
.polling({
|
|
52
|
+
handleEvent: async ctx => ({
|
|
53
|
+
type: 'email.received',
|
|
54
|
+
id: ctx.input.messageId,
|
|
55
|
+
output: { type: 'email.received' as const }
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
.build();
|
|
59
|
+
|
|
60
|
+
expect(sendEmailTool.adapter).toBe('gmail');
|
|
61
|
+
expect(emailReceivedTrigger.adapter).toBe('gmail');
|
|
62
|
+
|
|
63
|
+
let gmailAdapter = gmailAdapterSpec.register({
|
|
64
|
+
tools: [sendEmailTool],
|
|
65
|
+
triggers: [emailReceivedTrigger]
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
expect(gmailAdapter.id).toBe('gmail');
|
|
69
|
+
expect(gmailAdapter.name).toBe('Gmail');
|
|
70
|
+
expect(gmailAdapter.capabilities).toEqual([{ id: 'send_email', value: true }]);
|
|
71
|
+
expect(gmailAdapter.tools).toEqual([sendEmailTool]);
|
|
72
|
+
expect(gmailAdapter.triggers).toEqual([emailReceivedTrigger]);
|
|
73
|
+
|
|
74
|
+
let providerTool = SlateTool.create(spec, {
|
|
75
|
+
key: 'list_labels',
|
|
76
|
+
name: 'List Labels'
|
|
77
|
+
})
|
|
78
|
+
.input(z.object({}))
|
|
79
|
+
.output(z.object({ labels: z.array(z.string()) }))
|
|
80
|
+
.handleInvocation(async () => ({
|
|
81
|
+
output: { labels: [] },
|
|
82
|
+
message: 'ok'
|
|
83
|
+
}))
|
|
84
|
+
.build();
|
|
85
|
+
|
|
86
|
+
let slate = Slate.create({
|
|
87
|
+
spec,
|
|
88
|
+
tools: [providerTool, sendEmailTool],
|
|
89
|
+
triggers: [emailReceivedTrigger],
|
|
90
|
+
adapters: [gmailAdapter]
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
expect(slate.actions.map(action => action.key)).toEqual([
|
|
94
|
+
'email_received',
|
|
95
|
+
'list_labels',
|
|
96
|
+
'send_email'
|
|
97
|
+
]);
|
|
98
|
+
expect(slate.adapters).toEqual([gmailAdapter]);
|
|
99
|
+
expect(slate.actions.filter(action => !action.adapter).map(action => action.key)).toEqual([
|
|
100
|
+
'list_labels'
|
|
101
|
+
]);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('includes adapter actions in the slate even when they are only passed via the adapter', () => {
|
|
105
|
+
let spec = createTestSpec();
|
|
106
|
+
let gmailAdapterSpec = SlateAdapterSpec.create({
|
|
107
|
+
id: 'gmail',
|
|
108
|
+
name: 'Gmail'
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
let sendEmailTool = gmailAdapterSpec
|
|
112
|
+
.tool(spec, {
|
|
113
|
+
key: 'send_email',
|
|
114
|
+
name: 'Send Email'
|
|
115
|
+
})
|
|
116
|
+
.input(z.object({}))
|
|
117
|
+
.output(z.object({}))
|
|
118
|
+
.handleInvocation(async () => ({
|
|
119
|
+
output: {},
|
|
120
|
+
message: 'ok'
|
|
121
|
+
}))
|
|
122
|
+
.build();
|
|
123
|
+
|
|
124
|
+
let gmailAdapter = gmailAdapterSpec.register({
|
|
125
|
+
tools: [sendEmailTool],
|
|
126
|
+
triggers: []
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
let slate = Slate.create({
|
|
130
|
+
spec,
|
|
131
|
+
tools: [],
|
|
132
|
+
triggers: [],
|
|
133
|
+
adapters: [gmailAdapter]
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
expect(slate.actions).toEqual([sendEmailTool]);
|
|
137
|
+
expect(slate.actions[0]!.adapter).toBe('gmail');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('rejects tools created for a different adapter', () => {
|
|
141
|
+
let spec = createTestSpec();
|
|
142
|
+
let gmailAdapterSpec = SlateAdapterSpec.create({
|
|
143
|
+
id: 'gmail',
|
|
144
|
+
name: 'Gmail'
|
|
145
|
+
});
|
|
146
|
+
let outlookAdapterSpec = SlateAdapterSpec.create({
|
|
147
|
+
id: 'outlook',
|
|
148
|
+
name: 'Outlook'
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
let outlookTool = outlookAdapterSpec
|
|
152
|
+
.tool(spec, {
|
|
153
|
+
key: 'send_email',
|
|
154
|
+
name: 'Send Email'
|
|
155
|
+
})
|
|
156
|
+
.input(z.object({}))
|
|
157
|
+
.output(z.object({}))
|
|
158
|
+
.handleInvocation(async () => ({
|
|
159
|
+
output: {},
|
|
160
|
+
message: 'ok'
|
|
161
|
+
}))
|
|
162
|
+
.build();
|
|
163
|
+
|
|
164
|
+
expect(() =>
|
|
165
|
+
gmailAdapterSpec.register({
|
|
166
|
+
tools: [outlookTool],
|
|
167
|
+
triggers: []
|
|
168
|
+
})
|
|
169
|
+
).toThrow('Action "send_email" is linked to adapter "outlook", not "gmail"');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('rejects provider tools that were not created through the adapter helpers', () => {
|
|
173
|
+
let spec = createTestSpec();
|
|
174
|
+
let gmailAdapterSpec = SlateAdapterSpec.create({
|
|
175
|
+
id: 'gmail',
|
|
176
|
+
name: 'Gmail'
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
let providerTool = SlateTool.create(spec, {
|
|
180
|
+
key: 'send_email',
|
|
181
|
+
name: 'Send Email'
|
|
182
|
+
})
|
|
183
|
+
.input(z.object({}))
|
|
184
|
+
.output(z.object({}))
|
|
185
|
+
.handleInvocation(async () => ({
|
|
186
|
+
output: {},
|
|
187
|
+
message: 'ok'
|
|
188
|
+
}))
|
|
189
|
+
.build();
|
|
190
|
+
|
|
191
|
+
expect(() =>
|
|
192
|
+
gmailAdapterSpec.register({
|
|
193
|
+
tools: [providerTool],
|
|
194
|
+
triggers: []
|
|
195
|
+
})
|
|
196
|
+
).toThrow(
|
|
197
|
+
'Action "send_email" must be created with this adapter\'s tool(), publicTool(), or trigger() helpers'
|
|
198
|
+
);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('rejects duplicate adapter action keys and duplicate adapter ids', () => {
|
|
202
|
+
let spec = createTestSpec();
|
|
203
|
+
let gmailAdapterSpec = SlateAdapterSpec.create({
|
|
204
|
+
id: 'gmail',
|
|
205
|
+
name: 'Gmail'
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
let sendEmailTool = gmailAdapterSpec
|
|
209
|
+
.tool(spec, {
|
|
210
|
+
key: 'send_email',
|
|
211
|
+
name: 'Send Email'
|
|
212
|
+
})
|
|
213
|
+
.input(z.object({}))
|
|
214
|
+
.output(z.object({}))
|
|
215
|
+
.handleInvocation(async () => ({
|
|
216
|
+
output: {},
|
|
217
|
+
message: 'ok'
|
|
218
|
+
}))
|
|
219
|
+
.build();
|
|
220
|
+
|
|
221
|
+
let sendEmailTrigger = gmailAdapterSpec
|
|
222
|
+
.trigger(spec, {
|
|
223
|
+
key: 'send_email',
|
|
224
|
+
name: 'Send Email Trigger'
|
|
225
|
+
})
|
|
226
|
+
.input(z.object({}))
|
|
227
|
+
.output(z.object({ type: z.string() }))
|
|
228
|
+
.polling({
|
|
229
|
+
handleEvent: async () => ({
|
|
230
|
+
type: 'email.sent',
|
|
231
|
+
id: '1',
|
|
232
|
+
output: { type: 'email.sent' }
|
|
233
|
+
})
|
|
234
|
+
})
|
|
235
|
+
.build();
|
|
236
|
+
|
|
237
|
+
expect(() =>
|
|
238
|
+
gmailAdapterSpec.register({
|
|
239
|
+
tools: [sendEmailTool],
|
|
240
|
+
triggers: [sendEmailTrigger]
|
|
241
|
+
})
|
|
242
|
+
).toThrow('Adapter "gmail" already has an action with key "send_email"');
|
|
243
|
+
|
|
244
|
+
let adapter = gmailAdapterSpec.register({
|
|
245
|
+
tools: [sendEmailTool],
|
|
246
|
+
triggers: []
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
expect(() =>
|
|
250
|
+
Slate.create({
|
|
251
|
+
spec,
|
|
252
|
+
tools: [],
|
|
253
|
+
triggers: [],
|
|
254
|
+
adapters: [adapter, adapter]
|
|
255
|
+
})
|
|
256
|
+
).toThrow('Adapter "gmail" is registered more than once');
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('rejects empty adapter ids and duplicate capability ids', () => {
|
|
260
|
+
expect(() =>
|
|
261
|
+
SlateAdapterSpec.create({
|
|
262
|
+
id: ' ',
|
|
263
|
+
name: 'Gmail'
|
|
264
|
+
})
|
|
265
|
+
).toThrow('Adapter id must be a non-empty string');
|
|
266
|
+
|
|
267
|
+
expect(() =>
|
|
268
|
+
SlateAdapterSpec.create({
|
|
269
|
+
id: 'gmail',
|
|
270
|
+
name: 'Gmail',
|
|
271
|
+
capabilities: [
|
|
272
|
+
{ id: 'send_email', value: true },
|
|
273
|
+
{ id: 'send_email', value: false }
|
|
274
|
+
]
|
|
275
|
+
})
|
|
276
|
+
).toThrow('Adapter capability "send_email" is defined more than once');
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('creates public adapter tools that remain linked and public', () => {
|
|
280
|
+
let spec = createTestSpec();
|
|
281
|
+
let gmailAdapterSpec = SlateAdapterSpec.create({
|
|
282
|
+
id: 'gmail',
|
|
283
|
+
name: 'Gmail'
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
let setupTool = gmailAdapterSpec
|
|
287
|
+
.publicTool(spec, {
|
|
288
|
+
key: 'setup',
|
|
289
|
+
name: 'Setup'
|
|
290
|
+
})
|
|
291
|
+
.input(z.object({}))
|
|
292
|
+
.output(z.object({ ok: z.boolean() }))
|
|
293
|
+
.handleInvocation(async ctx => {
|
|
294
|
+
expect(ctx).not.toHaveProperty('config');
|
|
295
|
+
expect(ctx).not.toHaveProperty('auth');
|
|
296
|
+
return {
|
|
297
|
+
output: { ok: true },
|
|
298
|
+
message: 'ok'
|
|
299
|
+
};
|
|
300
|
+
})
|
|
301
|
+
.build();
|
|
302
|
+
|
|
303
|
+
expect(setupTool.adapter).toBe('gmail');
|
|
304
|
+
expect(setupTool.isPublic).toBe(true);
|
|
305
|
+
|
|
306
|
+
let gmailAdapter = gmailAdapterSpec.register({
|
|
307
|
+
tools: [setupTool],
|
|
308
|
+
triggers: []
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
let slate = Slate.create({
|
|
312
|
+
spec,
|
|
313
|
+
tools: [setupTool],
|
|
314
|
+
triggers: [],
|
|
315
|
+
adapters: [gmailAdapter]
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
expect(slate.actions.map(action => action.key)).toEqual(['setup']);
|
|
319
|
+
expect(slate.actions[0]!.isPublic).toBe(true);
|
|
320
|
+
expect(slate.actions[0]!.adapter).toBe('gmail');
|
|
321
|
+
});
|
|
322
|
+
});
|