@slates/provider 1.0.0-rc.17 → 1.0.0-rc.19
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 +569 -55
- package/dist/index.d.cts +218 -48
- package/dist/index.d.ts +218 -48
- package/dist/index.module.js +554 -55
- package/package.json +3 -2
- package/src/action/action.ts +19 -1
- package/src/action/attachment.ts +55 -9
- package/src/action/builder.test.ts +136 -0
- package/src/action/builder.ts +68 -11
- package/src/action/directUpload.ts +59 -0
- package/src/action/getFileUrlTool.ts +41 -0
- package/src/action/index.ts +3 -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/auth/index.ts +1 -0
- package/src/auth/redact.test.ts +103 -0
- package/src/auth/redact.ts +111 -0
- package/src/auth/types.ts +0 -1
- package/src/axios/trace.ts +72 -38
- package/src/context/context.ts +222 -17
- package/src/context/hook.ts +5 -10
- package/src/index.ts +2 -0
- package/src/specification/slate.ts +38 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slates/provider",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.19",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"@lowerdeck/error": "^1.1.0",
|
|
35
35
|
"@toon-format/toon": "^2.1.0",
|
|
36
36
|
"axios": "^1.13.2",
|
|
37
|
+
"p-queue": "^6.6.2",
|
|
37
38
|
"zod": "^4.2.1"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
@@ -42,4 +43,4 @@
|
|
|
42
43
|
"typescript": "5.8.2",
|
|
43
44
|
"vitest": "^3.1.2"
|
|
44
45
|
}
|
|
45
|
-
}
|
|
46
|
+
}
|
package/src/action/action.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { z } from 'zod';
|
|
2
|
-
import type { SlateContext } from '../context';
|
|
2
|
+
import type { SlateContext, SlatePublicContext } from '../context';
|
|
3
3
|
import type { SlateActionDocsReference } from '../docs';
|
|
4
4
|
import type { SlateSpecification } from '../specification/specification';
|
|
5
5
|
import type { SlateAttachment } from './attachment';
|
|
@@ -29,6 +29,8 @@ export interface SlateActionParameters {
|
|
|
29
29
|
scopes?: SlateActionScopes;
|
|
30
30
|
authMethods?: string[];
|
|
31
31
|
docs?: SlateActionDocsReference[];
|
|
32
|
+
adapter?: string | null;
|
|
33
|
+
isPublic?: boolean;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
export type SlateToolInvocationHandler<
|
|
@@ -42,6 +44,14 @@ export type SlateToolInvocationHandler<
|
|
|
42
44
|
attachments?: SlateAttachment[];
|
|
43
45
|
}>;
|
|
44
46
|
|
|
47
|
+
export type SlatePublicToolInvocationHandler<InputType extends {}, OutputType extends {}> = (
|
|
48
|
+
context: SlatePublicContext<InputType>
|
|
49
|
+
) => Promise<{
|
|
50
|
+
output: OutputType;
|
|
51
|
+
message: string;
|
|
52
|
+
attachments?: SlateAttachment[];
|
|
53
|
+
}>;
|
|
54
|
+
|
|
45
55
|
export type SlateTriggerMappingHandler<
|
|
46
56
|
ConfigType extends {},
|
|
47
57
|
AuthType extends {},
|
|
@@ -258,4 +268,12 @@ export abstract class SlateAction<
|
|
|
258
268
|
get docs() {
|
|
259
269
|
return this._params.docs;
|
|
260
270
|
}
|
|
271
|
+
|
|
272
|
+
get adapter() {
|
|
273
|
+
return this._params.adapter ?? null;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
get isPublic() {
|
|
277
|
+
return this._params.isPublic === true;
|
|
278
|
+
}
|
|
261
279
|
}
|
package/src/action/attachment.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export interface SlateAttachmentUrlContent {
|
|
2
2
|
type: 'url';
|
|
3
3
|
url: string;
|
|
4
|
+
headers?: Record<string, string>;
|
|
5
|
+
query?: Record<string, string>;
|
|
6
|
+
refreshReference?: unknown;
|
|
7
|
+
refreshAt?: string;
|
|
4
8
|
}
|
|
5
9
|
|
|
6
10
|
export interface SlateAttachmentInlineContent {
|
|
@@ -9,21 +13,58 @@ export interface SlateAttachmentInlineContent {
|
|
|
9
13
|
content: string;
|
|
10
14
|
}
|
|
11
15
|
|
|
16
|
+
export interface SlateAttachmentUploadReferenceContent {
|
|
17
|
+
type: 'upload_reference';
|
|
18
|
+
referenceId: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
12
21
|
export interface SlateAttachment {
|
|
13
22
|
mimeType?: string;
|
|
14
|
-
|
|
23
|
+
attachmentHash?: string;
|
|
24
|
+
content:
|
|
25
|
+
| SlateAttachmentUrlContent
|
|
26
|
+
| SlateAttachmentInlineContent
|
|
27
|
+
| SlateAttachmentUploadReferenceContent;
|
|
15
28
|
}
|
|
16
29
|
|
|
17
|
-
export let createUrlAttachment = (
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
30
|
+
export let createUrlAttachment = (
|
|
31
|
+
url: string,
|
|
32
|
+
opts: {
|
|
33
|
+
mimeType?: string;
|
|
34
|
+
attachmentHash?: string;
|
|
35
|
+
headers?: Record<string, string>;
|
|
36
|
+
query?: Record<string, string>;
|
|
37
|
+
refreshReference?: unknown;
|
|
38
|
+
refreshAt?: string;
|
|
39
|
+
} = {}
|
|
40
|
+
): SlateAttachment => {
|
|
41
|
+
if (opts.refreshReference !== undefined && !opts.refreshAt) {
|
|
42
|
+
throw new Error('createUrlAttachment: refreshAt is required when refreshReference is set');
|
|
22
43
|
}
|
|
23
|
-
});
|
|
24
44
|
|
|
25
|
-
|
|
45
|
+
return {
|
|
46
|
+
mimeType: opts.mimeType,
|
|
47
|
+
attachmentHash: opts.attachmentHash,
|
|
48
|
+
content: {
|
|
49
|
+
type: 'url',
|
|
50
|
+
url,
|
|
51
|
+
...(opts.headers ? { headers: opts.headers } : {}),
|
|
52
|
+
...(opts.query ? { query: opts.query } : {}),
|
|
53
|
+
...(opts.refreshReference !== undefined
|
|
54
|
+
? { refreshReference: opts.refreshReference }
|
|
55
|
+
: {}),
|
|
56
|
+
...(opts.refreshAt ? { refreshAt: opts.refreshAt } : {})
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export let createBase64Attachment = (
|
|
62
|
+
content: string,
|
|
63
|
+
mimeType?: string,
|
|
64
|
+
attachmentHash?: string
|
|
65
|
+
): SlateAttachment => ({
|
|
26
66
|
mimeType,
|
|
67
|
+
attachmentHash,
|
|
27
68
|
content: {
|
|
28
69
|
type: 'content',
|
|
29
70
|
encoding: 'base64',
|
|
@@ -31,8 +72,13 @@ export let createBase64Attachment = (content: string, mimeType?: string): SlateA
|
|
|
31
72
|
}
|
|
32
73
|
});
|
|
33
74
|
|
|
34
|
-
export let createTextAttachment = (
|
|
75
|
+
export let createTextAttachment = (
|
|
76
|
+
content: string,
|
|
77
|
+
mimeType?: string,
|
|
78
|
+
attachmentHash?: string
|
|
79
|
+
): SlateAttachment => ({
|
|
35
80
|
mimeType,
|
|
81
|
+
attachmentHash,
|
|
36
82
|
content: {
|
|
37
83
|
type: 'content',
|
|
38
84
|
encoding: 'utf-8',
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { SlateAuth } from '../auth';
|
|
4
|
+
import { SlateConfig } from '../config';
|
|
5
|
+
import { SlatePublicContext } from '../context';
|
|
6
|
+
import { SlateSpecification } from '../specification/specification';
|
|
7
|
+
import { SlatePublicTool } from './publicTool';
|
|
8
|
+
import { SlateTool } from './tool';
|
|
9
|
+
|
|
10
|
+
let createTestSpec = () => {
|
|
11
|
+
let config = SlateConfig.create(
|
|
12
|
+
z.object({
|
|
13
|
+
prefix: z.string()
|
|
14
|
+
})
|
|
15
|
+
);
|
|
16
|
+
let auth = SlateAuth.create<{ token: string }>().output(
|
|
17
|
+
z.object({
|
|
18
|
+
token: z.string()
|
|
19
|
+
})
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
return SlateSpecification.create({
|
|
23
|
+
key: 'demo',
|
|
24
|
+
name: 'Demo',
|
|
25
|
+
config,
|
|
26
|
+
auth
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
describe('SlateActionBuilder.lockInterface', () => {
|
|
31
|
+
it('prevents changing input and output schemas after the interface is locked', () => {
|
|
32
|
+
let spec = createTestSpec();
|
|
33
|
+
let builder = SlateTool.create(spec, {
|
|
34
|
+
key: 'send',
|
|
35
|
+
name: 'Send'
|
|
36
|
+
})
|
|
37
|
+
.input(z.object({ to: z.string() }))
|
|
38
|
+
.output(z.object({ id: z.string() }))
|
|
39
|
+
.lockInterface();
|
|
40
|
+
|
|
41
|
+
expect(() => builder.input(z.object({}))).toThrow(
|
|
42
|
+
'Adapter contract input schema cannot be changed'
|
|
43
|
+
);
|
|
44
|
+
expect(() => builder.output(z.object({}))).toThrow(
|
|
45
|
+
'Adapter contract output schema cannot be changed'
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('SlatePublicTool', () => {
|
|
51
|
+
it('builds a public tool that omits config and auth from the handler context', async () => {
|
|
52
|
+
let spec = createTestSpec();
|
|
53
|
+
let tool = SlatePublicTool.create(spec, {
|
|
54
|
+
key: 'setup',
|
|
55
|
+
name: 'Setup'
|
|
56
|
+
})
|
|
57
|
+
.input(
|
|
58
|
+
z.object({
|
|
59
|
+
name: z.string()
|
|
60
|
+
})
|
|
61
|
+
)
|
|
62
|
+
.output(
|
|
63
|
+
z.object({
|
|
64
|
+
greeting: z.string()
|
|
65
|
+
})
|
|
66
|
+
)
|
|
67
|
+
.handleInvocation(async ctx => {
|
|
68
|
+
expect(ctx).not.toHaveProperty('config');
|
|
69
|
+
expect(ctx).not.toHaveProperty('auth');
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
output: { greeting: `Hello ${ctx.input.name}` },
|
|
73
|
+
message: 'ok'
|
|
74
|
+
};
|
|
75
|
+
})
|
|
76
|
+
.build();
|
|
77
|
+
|
|
78
|
+
expect(tool.isPublic).toBe(true);
|
|
79
|
+
expect(tool.key).toBe('setup');
|
|
80
|
+
|
|
81
|
+
let result = await tool.handleInvocation(
|
|
82
|
+
new SlatePublicContext({ name: 'Ada' }, spec, {
|
|
83
|
+
debug: () => {},
|
|
84
|
+
error: () => {},
|
|
85
|
+
info: () => {},
|
|
86
|
+
progress: () => {},
|
|
87
|
+
warn: () => {}
|
|
88
|
+
} as any) as any
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
expect(result.output).toEqual({ greeting: 'Hello Ada' });
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('keeps regular tools private by default', () => {
|
|
95
|
+
let spec = createTestSpec();
|
|
96
|
+
let tool = SlateTool.create(spec, {
|
|
97
|
+
key: 'send',
|
|
98
|
+
name: 'Send'
|
|
99
|
+
})
|
|
100
|
+
.input(z.object({}))
|
|
101
|
+
.output(z.object({}))
|
|
102
|
+
.handleInvocation(async () => ({
|
|
103
|
+
output: {},
|
|
104
|
+
message: 'ok'
|
|
105
|
+
}))
|
|
106
|
+
.build();
|
|
107
|
+
|
|
108
|
+
expect(tool.isPublic).toBe(false);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('rejects authentication methods on public tools', () => {
|
|
112
|
+
let spec = createTestSpec();
|
|
113
|
+
|
|
114
|
+
expect(() =>
|
|
115
|
+
SlatePublicTool.create(spec, {
|
|
116
|
+
key: 'setup',
|
|
117
|
+
name: 'Setup'
|
|
118
|
+
}).authMethods(['token_auth'])
|
|
119
|
+
).toThrow('Public tools cannot require authentication methods');
|
|
120
|
+
|
|
121
|
+
expect(() =>
|
|
122
|
+
SlatePublicTool.create(spec, {
|
|
123
|
+
key: 'setup',
|
|
124
|
+
name: 'Setup',
|
|
125
|
+
authMethods: ['token_auth']
|
|
126
|
+
})
|
|
127
|
+
.input(z.object({}))
|
|
128
|
+
.output(z.object({}))
|
|
129
|
+
.handleInvocation(async () => ({
|
|
130
|
+
output: {},
|
|
131
|
+
message: 'ok'
|
|
132
|
+
}))
|
|
133
|
+
.build()
|
|
134
|
+
).toThrow('Public tools cannot require authentication methods');
|
|
135
|
+
});
|
|
136
|
+
});
|
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,
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { SlateAttachment } from './attachment';
|
|
2
|
+
|
|
3
|
+
export interface SlateLiveInvocationInfo {
|
|
4
|
+
token: string;
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
maxAttachmentSizeBytes: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface SlateDirectUploadInput {
|
|
10
|
+
live: SlateLiveInvocationInfo;
|
|
11
|
+
mimeType?: string;
|
|
12
|
+
filename?: string;
|
|
13
|
+
body: ReadableStream<Uint8Array> | Uint8Array;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export let uploadAttachmentDirect = async (
|
|
17
|
+
d: SlateDirectUploadInput
|
|
18
|
+
): Promise<SlateAttachment> => {
|
|
19
|
+
let baseUrl = d.live.baseUrl.replace(/\/$/, '');
|
|
20
|
+
|
|
21
|
+
let registerRes = await fetch(`${baseUrl}/slates-hub/live-invocation/attachments`, {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
headers: {
|
|
24
|
+
'content-type': 'application/json',
|
|
25
|
+
authorization: `Bearer ${d.live.token}`
|
|
26
|
+
},
|
|
27
|
+
body: JSON.stringify({
|
|
28
|
+
attachments: [{ mimeType: d.mimeType, filename: d.filename }]
|
|
29
|
+
})
|
|
30
|
+
});
|
|
31
|
+
if (!registerRes.ok) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
`Failed to register attachment for direct upload (status ${registerRes.status})`
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let { attachments } = (await registerRes.json()) as {
|
|
38
|
+
attachments: { referenceId: string; uploadUrl: string }[];
|
|
39
|
+
};
|
|
40
|
+
let registration = attachments[0];
|
|
41
|
+
if (!registration) {
|
|
42
|
+
throw new Error('Live invocation API returned no attachment registrations');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let putRes = await fetch(registration.uploadUrl, {
|
|
46
|
+
method: 'PUT',
|
|
47
|
+
...(d.body instanceof Uint8Array ? {} : ({ duplex: 'half' } as any)),
|
|
48
|
+
headers: d.mimeType ? { 'content-type': d.mimeType } : undefined,
|
|
49
|
+
body: d.body
|
|
50
|
+
});
|
|
51
|
+
if (!putRes.ok) {
|
|
52
|
+
throw new Error(`Failed to upload attachment content (status ${putRes.status})`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
mimeType: d.mimeType,
|
|
57
|
+
content: { type: 'upload_reference', referenceId: registration.referenceId }
|
|
58
|
+
};
|
|
59
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { SlateContext } from '../context/context';
|
|
3
|
+
import type { SlateSpecification } from '../specification/specification';
|
|
4
|
+
import { tool } from './tool';
|
|
5
|
+
|
|
6
|
+
export let GET_FILE_URL_TOOL_ID = 'metorial$getFileUrl';
|
|
7
|
+
|
|
8
|
+
export let getFileUrlToolInputSchema = z.object({
|
|
9
|
+
url: z.string(),
|
|
10
|
+
reference: z.any().nullable()
|
|
11
|
+
});
|
|
12
|
+
export type GetFileUrlToolInput = z.infer<typeof getFileUrlToolInputSchema>;
|
|
13
|
+
|
|
14
|
+
export let getFileUrlToolOutputSchema = z.object({
|
|
15
|
+
url: z.string(),
|
|
16
|
+
expiresAt: z.string(),
|
|
17
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
18
|
+
query: z.record(z.string(), z.string()).optional()
|
|
19
|
+
});
|
|
20
|
+
export type GetFileUrlToolOutput = z.infer<typeof getFileUrlToolOutputSchema>;
|
|
21
|
+
|
|
22
|
+
export type GetFileUrlHandler<ConfigType extends {}, AuthType extends {}> = (
|
|
23
|
+
context: SlateContext<ConfigType, AuthType, GetFileUrlToolInput>
|
|
24
|
+
) => Promise<GetFileUrlToolOutput>;
|
|
25
|
+
|
|
26
|
+
export let getFileUrlTool = <ConfigType extends {}, AuthType extends {}>(
|
|
27
|
+
spec: SlateSpecification<ConfigType, AuthType>,
|
|
28
|
+
handleGetFileUrl: GetFileUrlHandler<ConfigType, AuthType>
|
|
29
|
+
) =>
|
|
30
|
+
tool(spec, {
|
|
31
|
+
key: GET_FILE_URL_TOOL_ID,
|
|
32
|
+
name: 'Get File URL',
|
|
33
|
+
description: 'Reserved: refreshes an expiring attachment download URL. Hub-internal only.'
|
|
34
|
+
})
|
|
35
|
+
.input(getFileUrlToolInputSchema)
|
|
36
|
+
.output(getFileUrlToolOutputSchema)
|
|
37
|
+
.handleInvocation(async ctx => ({
|
|
38
|
+
output: await handleGetFileUrl(ctx),
|
|
39
|
+
message: 'ok'
|
|
40
|
+
}))
|
|
41
|
+
.build();
|
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
|
+
}
|