@notionhq/workers 0.5.0 → 0.7.0
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/alpha/ajv-formats.d.js +0 -0
- package/dist/alpha/builder.d.ts +149 -0
- package/dist/alpha/builder.d.ts.map +1 -0
- package/dist/alpha/builder.js +260 -0
- package/dist/alpha/builder.test.d.ts +2 -0
- package/dist/alpha/builder.test.d.ts.map +1 -0
- package/dist/alpha/cli/build.d.ts +13 -0
- package/dist/alpha/cli/build.d.ts.map +1 -0
- package/dist/alpha/cli/build.js +36 -0
- package/dist/alpha/cli/build.test.d.ts +2 -0
- package/dist/alpha/cli/build.test.d.ts.map +1 -0
- package/dist/alpha/cli/codegen.d.ts +10 -0
- package/dist/alpha/cli/codegen.d.ts.map +1 -0
- package/dist/alpha/cli/codegen.js +41 -0
- package/dist/alpha/cli/codegen.test.d.ts +2 -0
- package/dist/alpha/cli/codegen.test.d.ts.map +1 -0
- package/dist/alpha/cli/discover.d.ts +35 -0
- package/dist/alpha/cli/discover.d.ts.map +1 -0
- package/dist/alpha/cli/discover.js +39 -0
- package/dist/alpha/cli/discover.test.d.ts +2 -0
- package/dist/alpha/cli/discover.test.d.ts.map +1 -0
- package/dist/alpha/cli/emit-manifest.d.ts +33 -0
- package/dist/alpha/cli/emit-manifest.d.ts.map +1 -0
- package/dist/alpha/cli/emit-manifest.js +266 -0
- package/dist/alpha/cli/emit-manifest.test.d.ts +2 -0
- package/dist/alpha/cli/emit-manifest.test.d.ts.map +1 -0
- package/dist/alpha/cli/index.d.ts +3 -0
- package/dist/alpha/cli/index.d.ts.map +1 -0
- package/dist/alpha/cli/index.js +36 -0
- package/dist/alpha/context.d.ts +8 -0
- package/dist/alpha/context.d.ts.map +1 -0
- package/dist/alpha/context.js +33 -0
- package/dist/alpha/database.d.ts +90 -0
- package/dist/alpha/database.d.ts.map +1 -0
- package/dist/alpha/database.js +9 -0
- package/dist/alpha/error.d.ts +41 -0
- package/dist/alpha/error.d.ts.map +1 -0
- package/dist/alpha/error.js +25 -0
- package/dist/alpha/icon-names.d.ts +6 -0
- package/dist/alpha/icon-names.d.ts.map +1 -0
- package/dist/alpha/icon-names.js +0 -0
- package/dist/alpha/json-schema.d.ts +117 -0
- package/dist/alpha/json-schema.d.ts.map +1 -0
- package/dist/alpha/json-schema.js +0 -0
- package/dist/alpha/manifest.d.ts +44 -0
- package/dist/alpha/manifest.d.ts.map +1 -0
- package/dist/alpha/manifest.js +0 -0
- package/dist/alpha/output.d.ts +7 -0
- package/dist/alpha/output.d.ts.map +1 -0
- package/dist/alpha/output.js +8 -0
- package/dist/alpha/pacer.d.ts +74 -0
- package/dist/alpha/pacer.d.ts.map +1 -0
- package/dist/alpha/pacer.js +66 -0
- package/dist/alpha/pacer.test.d.ts +2 -0
- package/dist/alpha/pacer.test.d.ts.map +1 -0
- package/dist/alpha/schedule.d.ts +6 -0
- package/dist/alpha/schedule.d.ts.map +1 -0
- package/dist/alpha/schedule.js +43 -0
- package/dist/alpha/schedule.test.d.ts +2 -0
- package/dist/alpha/schedule.test.d.ts.map +1 -0
- package/dist/alpha/schema-builder.d.ts +79 -0
- package/dist/alpha/schema-builder.d.ts.map +1 -0
- package/dist/alpha/schema-builder.js +135 -0
- package/dist/alpha/schema.d.ts +185 -0
- package/dist/alpha/schema.d.ts.map +1 -0
- package/dist/alpha/schema.js +115 -0
- package/dist/alpha/sync.d.ts +233 -0
- package/dist/alpha/sync.d.ts.map +1 -0
- package/dist/alpha/sync.js +70 -0
- package/dist/alpha/sync.test.d.ts +2 -0
- package/dist/alpha/sync.test.d.ts.map +1 -0
- package/dist/alpha/tool.d.ts +132 -0
- package/dist/alpha/tool.d.ts.map +1 -0
- package/dist/alpha/tool.js +156 -0
- package/dist/alpha/tool.test.d.ts +2 -0
- package/dist/alpha/tool.test.d.ts.map +1 -0
- package/dist/alpha/triggers.d.ts +365 -0
- package/dist/alpha/triggers.d.ts.map +1 -0
- package/dist/alpha/triggers.generated.d.ts +246 -0
- package/dist/alpha/triggers.generated.d.ts.map +1 -0
- package/dist/alpha/triggers.generated.js +239 -0
- package/dist/alpha/triggers.js +0 -0
- package/dist/alpha/types.d.ts +228 -0
- package/dist/alpha/types.d.ts.map +1 -0
- package/dist/alpha/types.js +0 -0
- package/dist/alpha/workflow.d.ts +70 -0
- package/dist/alpha/workflow.d.ts.map +1 -0
- package/dist/alpha/workflow.js +39 -0
- package/dist/alpha/workflow.test.d.ts +2 -0
- package/dist/alpha/workflow.test.d.ts.map +1 -0
- package/dist/block.d.ts.map +1 -1
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +2 -6
- package/dist/capabilities/ai_connector.d.ts.map +1 -1
- package/dist/capabilities/automation.d.ts.map +1 -1
- package/dist/capabilities/context.d.ts.map +1 -1
- package/dist/capabilities/oauth.d.ts.map +1 -1
- package/dist/capabilities/output.d.ts.map +1 -1
- package/dist/capabilities/output.js +2 -4
- package/dist/capabilities/stateful-capability.d.ts.map +1 -1
- package/dist/capabilities/stateful-capability.js +2 -6
- package/dist/capabilities/sync.d.ts.map +1 -1
- package/dist/capabilities/sync.js +2 -8
- package/dist/capabilities/tool.d.ts.map +1 -1
- package/dist/capabilities/tool.js +6 -20
- package/dist/capabilities/webhook.d.ts.map +1 -1
- package/dist/capabilities/workflow.d.ts +2 -2
- package/dist/capabilities/workflow.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -7
- package/dist/json-schema.d.ts.map +1 -1
- package/dist/schema-builder.d.ts.map +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +1 -4
- package/package.json +74 -14
- package/src/alpha/ajv-formats.d.ts +7 -0
- package/src/alpha/builder.test.ts +197 -0
- package/src/alpha/builder.ts +338 -0
- package/src/alpha/cli/build.test.ts +240 -0
- package/src/alpha/cli/build.ts +57 -0
- package/src/alpha/cli/codegen.test.ts +31 -0
- package/src/alpha/cli/codegen.ts +51 -0
- package/src/alpha/cli/discover.test.ts +43 -0
- package/src/alpha/cli/discover.ts +81 -0
- package/src/alpha/cli/emit-manifest.test.ts +45 -0
- package/src/alpha/cli/emit-manifest.ts +409 -0
- package/src/alpha/cli/index.ts +41 -0
- package/src/alpha/context.ts +61 -0
- package/src/alpha/database.ts +102 -0
- package/src/alpha/error.ts +49 -0
- package/src/alpha/icon-names.ts +890 -0
- package/src/alpha/json-schema.ts +180 -0
- package/src/alpha/manifest.ts +47 -0
- package/src/alpha/output.ts +8 -0
- package/src/alpha/pacer.test.ts +81 -0
- package/src/alpha/pacer.ts +181 -0
- package/src/alpha/schedule.test.ts +31 -0
- package/src/alpha/schedule.ts +53 -0
- package/src/alpha/schema-builder.ts +193 -0
- package/src/alpha/schema.ts +222 -0
- package/src/alpha/sync.test.ts +191 -0
- package/src/alpha/sync.ts +340 -0
- package/src/alpha/tool.test.ts +116 -0
- package/src/alpha/tool.ts +319 -0
- package/src/alpha/triggers.generated.ts +489 -0
- package/src/alpha/triggers.ts +500 -0
- package/src/alpha/types.ts +284 -0
- package/src/alpha/workflow.test.ts +84 -0
- package/src/alpha/workflow.ts +131 -0
- package/src/block.ts +1 -5
- package/src/builder.test.ts +28 -60
- package/src/builder.ts +3 -10
- package/src/capabilities/ai_connector.test.ts +9 -32
- package/src/capabilities/ai_connector.ts +5 -17
- package/src/capabilities/automation.test.ts +3 -12
- package/src/capabilities/automation.ts +3 -11
- package/src/capabilities/context.ts +3 -6
- package/src/capabilities/oauth.test.ts +1 -0
- package/src/capabilities/oauth.ts +1 -3
- package/src/capabilities/output.ts +1 -3
- package/src/capabilities/stateful-capability.test.ts +1 -0
- package/src/capabilities/stateful-capability.ts +2 -6
- package/src/capabilities/sync.test.ts +15 -45
- package/src/capabilities/sync.ts +10 -40
- package/src/capabilities/tool.test.ts +106 -146
- package/src/capabilities/tool.ts +17 -39
- package/src/capabilities/webhook.ts +3 -10
- package/src/capabilities/workflow.test.ts +10 -31
- package/src/capabilities/workflow.ts +5 -12
- package/src/index.ts +2 -12
- package/src/json-schema.test.ts +2 -4
- package/src/json-schema.ts +7 -6
- package/src/pacer.test.ts +1 -3
- package/src/pacer_internal.ts +1 -5
- package/src/schema-builder.test.ts +10 -35
- package/src/schema-builder.ts +5 -16
- package/src/schema.ts +2 -10
- package/src/types.ts +1 -7
- package/src/worker.ts +8 -34
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
beforeEach,
|
|
4
|
-
describe,
|
|
5
|
-
expect,
|
|
6
|
-
it,
|
|
7
|
-
type Mock,
|
|
8
|
-
vi,
|
|
9
|
-
} from "vitest";
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, type Mock, vi } from "vitest";
|
|
2
|
+
|
|
10
3
|
import { j } from "../schema-builder.js";
|
|
11
4
|
import { createToolCapability } from "./tool.js";
|
|
12
5
|
|
|
@@ -14,9 +7,7 @@ describe("Worker.tool", () => {
|
|
|
14
7
|
let stdoutSpy: Mock<typeof process.stdout.write>;
|
|
15
8
|
|
|
16
9
|
beforeEach(() => {
|
|
17
|
-
stdoutSpy = vi
|
|
18
|
-
.spyOn(process.stdout, "write")
|
|
19
|
-
.mockImplementation(() => true);
|
|
10
|
+
stdoutSpy = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
|
|
20
11
|
});
|
|
21
12
|
|
|
22
13
|
afterEach(() => {
|
|
@@ -24,17 +15,14 @@ describe("Worker.tool", () => {
|
|
|
24
15
|
});
|
|
25
16
|
|
|
26
17
|
it("sync execution", async () => {
|
|
27
|
-
const capability = createToolCapability<{ name: string }, string>(
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
execute: (input: { name: string }) => {
|
|
34
|
-
return `Hello, ${input.name}!`;
|
|
35
|
-
},
|
|
18
|
+
const capability = createToolCapability<{ name: string }, string>("sayHello", {
|
|
19
|
+
title: "Say Hello",
|
|
20
|
+
description: "Greet a user",
|
|
21
|
+
schema: j.object({ name: j.string() }),
|
|
22
|
+
execute: (input: { name: string }) => {
|
|
23
|
+
return `Hello, ${input.name}!`;
|
|
36
24
|
},
|
|
37
|
-
);
|
|
25
|
+
});
|
|
38
26
|
|
|
39
27
|
const result = await capability.handler({ name: "Alice" });
|
|
40
28
|
|
|
@@ -46,19 +34,16 @@ describe("Worker.tool", () => {
|
|
|
46
34
|
});
|
|
47
35
|
|
|
48
36
|
it("async execution", async () => {
|
|
49
|
-
const capability = createToolCapability<{ id: number }, { data: string }>(
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
58
|
-
return { data: `Data for ID ${input.id}` };
|
|
59
|
-
},
|
|
37
|
+
const capability = createToolCapability<{ id: number }, { data: string }>("fetchData", {
|
|
38
|
+
title: "Fetch Data",
|
|
39
|
+
description: "Fetch data asynchronously",
|
|
40
|
+
schema: j.object({ id: j.number() }),
|
|
41
|
+
execute: async (input: { id: number }) => {
|
|
42
|
+
// Simulate async operation
|
|
43
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
44
|
+
return { data: `Data for ID ${input.id}` };
|
|
60
45
|
},
|
|
61
|
-
);
|
|
46
|
+
});
|
|
62
47
|
|
|
63
48
|
const result = await capability.handler({ id: 42 });
|
|
64
49
|
|
|
@@ -73,17 +58,14 @@ describe("Worker.tool", () => {
|
|
|
73
58
|
});
|
|
74
59
|
|
|
75
60
|
it("execution error", async () => {
|
|
76
|
-
const capability = createToolCapability<Record<string, never>, string>(
|
|
77
|
-
"
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
execute: () => {
|
|
83
|
-
throw new Error("Something went wrong");
|
|
84
|
-
},
|
|
61
|
+
const capability = createToolCapability<Record<string, never>, string>("throwError", {
|
|
62
|
+
title: "Throw Error",
|
|
63
|
+
description: "Throws an error",
|
|
64
|
+
schema: j.object({}),
|
|
65
|
+
execute: () => {
|
|
66
|
+
throw new Error("Something went wrong");
|
|
85
67
|
},
|
|
86
|
-
);
|
|
68
|
+
});
|
|
87
69
|
|
|
88
70
|
const result = (await capability.handler({})) as {
|
|
89
71
|
_tag: "error";
|
|
@@ -102,17 +84,14 @@ describe("Worker.tool", () => {
|
|
|
102
84
|
});
|
|
103
85
|
|
|
104
86
|
it("invalid input", async () => {
|
|
105
|
-
const capability = createToolCapability<{ name: string }, string>(
|
|
106
|
-
"
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
execute: (input: { name: string }) => {
|
|
112
|
-
return `Hello, ${input.name}!`;
|
|
113
|
-
},
|
|
87
|
+
const capability = createToolCapability<{ name: string }, string>("sayHelloStrict", {
|
|
88
|
+
title: "Say Hello",
|
|
89
|
+
description: "Requires a name property",
|
|
90
|
+
schema: j.object({ name: j.string() }),
|
|
91
|
+
execute: (input: { name: string }) => {
|
|
92
|
+
return `Hello, ${input.name}!`;
|
|
114
93
|
},
|
|
115
|
-
);
|
|
94
|
+
});
|
|
116
95
|
|
|
117
96
|
const result = (await capability.handler({ age: 25 })) as {
|
|
118
97
|
_tag: "error";
|
|
@@ -131,19 +110,19 @@ describe("Worker.tool", () => {
|
|
|
131
110
|
});
|
|
132
111
|
|
|
133
112
|
it("invalid output", async () => {
|
|
134
|
-
const capability = createToolCapability<
|
|
135
|
-
|
|
136
|
-
{
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
113
|
+
const capability = createToolCapability<Record<string, never>, { result: string }>(
|
|
114
|
+
"invalidOutput",
|
|
115
|
+
{
|
|
116
|
+
title: "Return Invalid Output",
|
|
117
|
+
description: "Returns output that doesn't match schema",
|
|
118
|
+
schema: j.object({}),
|
|
119
|
+
outputSchema: j.object({ result: j.string() }),
|
|
120
|
+
// @ts-expect-error Testing invalid output - intentionally returning number instead of string
|
|
121
|
+
execute: () => {
|
|
122
|
+
return { result: 123 };
|
|
123
|
+
},
|
|
145
124
|
},
|
|
146
|
-
|
|
125
|
+
);
|
|
147
126
|
|
|
148
127
|
const result = (await capability.handler({})) as {
|
|
149
128
|
_tag: "error";
|
|
@@ -155,42 +134,37 @@ describe("Worker.tool", () => {
|
|
|
155
134
|
expect(result.error.message).toContain("result");
|
|
156
135
|
|
|
157
136
|
expect(stdoutSpy).toHaveBeenCalledWith(
|
|
158
|
-
expect.stringContaining(
|
|
159
|
-
`"_tag":"error","error":{"name":"InvalidToolOutputError"`,
|
|
160
|
-
),
|
|
137
|
+
expect.stringContaining(`"_tag":"error","error":{"name":"InvalidToolOutputError"`),
|
|
161
138
|
);
|
|
162
139
|
});
|
|
163
140
|
|
|
164
141
|
it("accepts schema with format string types (date, datetime, etc.)", () => {
|
|
165
|
-
const capability = createToolCapability<
|
|
166
|
-
|
|
167
|
-
string
|
|
168
|
-
>("dateFormats", {
|
|
169
|
-
title: "Date Formats",
|
|
170
|
-
description: "Uses date and datetime format strings",
|
|
171
|
-
schema: j.object({
|
|
172
|
-
due: j.date(),
|
|
173
|
-
createdAt: j.datetime(),
|
|
174
|
-
}),
|
|
175
|
-
execute: ({ due, createdAt }) => `${due} ${createdAt}`,
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
expect(capability.config.schema).toBeDefined();
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
it("rejects invalid date-time format at runtime", async () => {
|
|
182
|
-
const capability = createToolCapability<{ ts: string }, string>(
|
|
183
|
-
"datetimeValidation",
|
|
142
|
+
const capability = createToolCapability<{ due: string; createdAt: string }, string>(
|
|
143
|
+
"dateFormats",
|
|
184
144
|
{
|
|
185
|
-
title: "
|
|
186
|
-
description: "
|
|
145
|
+
title: "Date Formats",
|
|
146
|
+
description: "Uses date and datetime format strings",
|
|
187
147
|
schema: j.object({
|
|
188
|
-
|
|
148
|
+
due: j.date(),
|
|
149
|
+
createdAt: j.datetime(),
|
|
189
150
|
}),
|
|
190
|
-
execute: ({
|
|
151
|
+
execute: ({ due, createdAt }) => `${due} ${createdAt}`,
|
|
191
152
|
},
|
|
192
153
|
);
|
|
193
154
|
|
|
155
|
+
expect(capability.config.schema).toBeDefined();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("rejects invalid date-time format at runtime", async () => {
|
|
159
|
+
const capability = createToolCapability<{ ts: string }, string>("datetimeValidation", {
|
|
160
|
+
title: "Datetime Validation",
|
|
161
|
+
description: "Validates datetime input",
|
|
162
|
+
schema: j.object({
|
|
163
|
+
ts: j.datetime(),
|
|
164
|
+
}),
|
|
165
|
+
execute: ({ ts }) => ts,
|
|
166
|
+
});
|
|
167
|
+
|
|
194
168
|
const valid = await capability.handler({ ts: "2024-01-01T00:00:00Z" });
|
|
195
169
|
expect(valid).toEqual({
|
|
196
170
|
_tag: "success",
|
|
@@ -206,78 +180,66 @@ describe("Worker.tool", () => {
|
|
|
206
180
|
});
|
|
207
181
|
|
|
208
182
|
it("accepts schema with nullable (string | null) properties", () => {
|
|
209
|
-
const capability = createToolCapability<
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
183
|
+
const capability = createToolCapability<{ name: string; nickname: string | null }, string>(
|
|
184
|
+
"nullable",
|
|
185
|
+
{
|
|
186
|
+
title: "Nullable",
|
|
187
|
+
description: "Has nullable properties",
|
|
188
|
+
schema: j.object({
|
|
189
|
+
name: j.string(),
|
|
190
|
+
nickname: j.string().nullable(),
|
|
191
|
+
}),
|
|
192
|
+
execute: ({ name, nickname }) => `${name} (${nickname ?? "no nickname"})`,
|
|
193
|
+
},
|
|
194
|
+
);
|
|
221
195
|
|
|
222
196
|
expect(capability.config.schema).toBeDefined();
|
|
223
197
|
});
|
|
224
198
|
|
|
225
199
|
describe("hints", () => {
|
|
226
200
|
it("omits hints from config when not specified (existing tools unchanged)", () => {
|
|
227
|
-
const capability = createToolCapability<{ name: string }, string>(
|
|
228
|
-
"
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
execute: ({ name }) => `Hello, ${name}`,
|
|
234
|
-
},
|
|
235
|
-
);
|
|
201
|
+
const capability = createToolCapability<{ name: string }, string>("noHints", {
|
|
202
|
+
title: "No Hints",
|
|
203
|
+
description: "A tool without hints",
|
|
204
|
+
schema: j.object({ name: j.string() }),
|
|
205
|
+
execute: ({ name }) => `Hello, ${name}`,
|
|
206
|
+
});
|
|
236
207
|
|
|
237
208
|
expect(capability.config.hints).toBeUndefined();
|
|
238
209
|
});
|
|
239
210
|
|
|
240
211
|
it("flows readOnlyHint=true through to config", () => {
|
|
241
|
-
const capability = createToolCapability<{ query: string }, string>(
|
|
242
|
-
"
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
execute: ({ query }) => query,
|
|
249
|
-
},
|
|
250
|
-
);
|
|
212
|
+
const capability = createToolCapability<{ query: string }, string>("readOnly", {
|
|
213
|
+
title: "Read Only",
|
|
214
|
+
description: "A read-only tool",
|
|
215
|
+
schema: j.object({ query: j.string() }),
|
|
216
|
+
hints: { readOnlyHint: true },
|
|
217
|
+
execute: ({ query }) => query,
|
|
218
|
+
});
|
|
251
219
|
|
|
252
220
|
expect(capability.config.hints).toEqual({ readOnlyHint: true });
|
|
253
221
|
});
|
|
254
222
|
|
|
255
223
|
it("flows readOnlyHint=false through to config", () => {
|
|
256
|
-
const capability = createToolCapability<{ pageId: string }, string>(
|
|
257
|
-
"
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
execute: ({ pageId }) => pageId,
|
|
264
|
-
},
|
|
265
|
-
);
|
|
224
|
+
const capability = createToolCapability<{ pageId: string }, string>("writeTool", {
|
|
225
|
+
title: "Write Tool",
|
|
226
|
+
description: "A write tool",
|
|
227
|
+
schema: j.object({ pageId: j.string() }),
|
|
228
|
+
hints: { readOnlyHint: false },
|
|
229
|
+
execute: ({ pageId }) => pageId,
|
|
230
|
+
});
|
|
266
231
|
|
|
267
232
|
expect(capability.config.hints).toEqual({ readOnlyHint: false });
|
|
268
233
|
});
|
|
269
234
|
|
|
270
235
|
it("does not affect execution behavior", async () => {
|
|
271
|
-
const capability = createToolCapability<{ x: number }, number>(
|
|
272
|
-
"
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
execute: ({ x }) => x * 2,
|
|
279
|
-
},
|
|
280
|
-
);
|
|
236
|
+
const capability = createToolCapability<{ x: number }, number>("doubleReadOnly", {
|
|
237
|
+
title: "Double",
|
|
238
|
+
description: "Doubles a number",
|
|
239
|
+
schema: j.object({ x: j.number() }),
|
|
240
|
+
hints: { readOnlyHint: true },
|
|
241
|
+
execute: ({ x }) => x * 2,
|
|
242
|
+
});
|
|
281
243
|
|
|
282
244
|
const result = await capability.handler({ x: 7 });
|
|
283
245
|
|
|
@@ -315,9 +277,7 @@ describe("Worker.tool", () => {
|
|
|
315
277
|
expect(result.error.message).toContain("message");
|
|
316
278
|
|
|
317
279
|
expect(stdoutSpy).toHaveBeenCalledWith(
|
|
318
|
-
expect.stringContaining(
|
|
319
|
-
`"_tag":"error","error":{"name":"InvalidToolOutputError"`,
|
|
320
|
-
),
|
|
280
|
+
expect.stringContaining(`"_tag":"error","error":{"name":"InvalidToolOutputError"`),
|
|
321
281
|
);
|
|
322
282
|
});
|
|
323
283
|
});
|
package/src/capabilities/tool.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Ajv } from "ajv";
|
|
2
2
|
import addFormats from "ajv-formats";
|
|
3
|
+
|
|
3
4
|
import type { AnyJSONSchema } from "../json-schema.js";
|
|
4
5
|
import type { SchemaBuilder } from "../schema-builder.js";
|
|
5
6
|
import { getSchema } from "../schema-builder.js";
|
|
@@ -15,10 +16,7 @@ import { writeOutput } from "./output.js";
|
|
|
15
16
|
* Throws a descriptive error at tool registration time (not request time)
|
|
16
17
|
* so the developer sees it immediately.
|
|
17
18
|
*/
|
|
18
|
-
function validateRequiredProperties(
|
|
19
|
-
schema: AnyJSONSchema,
|
|
20
|
-
path: string = "",
|
|
21
|
-
): void {
|
|
19
|
+
function validateRequiredProperties(schema: AnyJSONSchema, path: string = ""): void {
|
|
22
20
|
if ("type" in schema && schema.type === "object" && "properties" in schema) {
|
|
23
21
|
const propKeys = Object.keys(schema.properties).sort();
|
|
24
22
|
const required = [...(schema.required ?? [])].sort();
|
|
@@ -43,20 +41,14 @@ function validateRequiredProperties(
|
|
|
43
41
|
// Recurse into $defs
|
|
44
42
|
if ("$defs" in schema && schema.$defs) {
|
|
45
43
|
for (const [key, defSchema] of Object.entries(schema.$defs)) {
|
|
46
|
-
validateRequiredProperties(
|
|
47
|
-
defSchema,
|
|
48
|
-
path ? `${path}.$defs.${key}` : `$defs.${key}`,
|
|
49
|
-
);
|
|
44
|
+
validateRequiredProperties(defSchema, path ? `${path}.$defs.${key}` : `$defs.${key}`);
|
|
50
45
|
}
|
|
51
46
|
}
|
|
52
47
|
}
|
|
53
48
|
|
|
54
49
|
// Recurse into array items
|
|
55
50
|
if ("type" in schema && schema.type === "array" && "items" in schema) {
|
|
56
|
-
validateRequiredProperties(
|
|
57
|
-
schema.items as AnyJSONSchema,
|
|
58
|
-
path ? `${path}.items` : "items",
|
|
59
|
-
);
|
|
51
|
+
validateRequiredProperties(schema.items as AnyJSONSchema, path ? `${path}.items` : "items");
|
|
60
52
|
}
|
|
61
53
|
|
|
62
54
|
// Recurse into anyOf branches
|
|
@@ -90,10 +82,7 @@ export interface ToolHints {
|
|
|
90
82
|
readOnlyHint?: boolean;
|
|
91
83
|
}
|
|
92
84
|
|
|
93
|
-
export interface ToolConfiguration<
|
|
94
|
-
I extends JSONValue,
|
|
95
|
-
O extends JSONValue = JSONValue,
|
|
96
|
-
> {
|
|
85
|
+
export interface ToolConfiguration<I extends JSONValue, O extends JSONValue = JSONValue> {
|
|
97
86
|
title: string;
|
|
98
87
|
description: string;
|
|
99
88
|
schema: SchemaBuilder<I>;
|
|
@@ -156,10 +145,9 @@ export class ToolExecutionError extends Error {
|
|
|
156
145
|
}
|
|
157
146
|
}
|
|
158
147
|
|
|
159
|
-
export type ToolCapability<
|
|
160
|
-
I
|
|
161
|
-
|
|
162
|
-
> = ReturnType<typeof createToolCapability<I, O>>;
|
|
148
|
+
export type ToolCapability<I extends JSONValue, O extends JSONValue = JSONValue> = ReturnType<
|
|
149
|
+
typeof createToolCapability<I, O>
|
|
150
|
+
>;
|
|
163
151
|
|
|
164
152
|
/**
|
|
165
153
|
* Creates a capability definition for a tool to be used by an agent.
|
|
@@ -167,16 +155,14 @@ export type ToolCapability<
|
|
|
167
155
|
* @param config - The configuration for the tool.
|
|
168
156
|
* @returns A capability definition for the tool.
|
|
169
157
|
*/
|
|
170
|
-
export function createToolCapability<
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
158
|
+
export function createToolCapability<I extends JSONValue, O extends JSONValue = JSONValue>(
|
|
159
|
+
key: string,
|
|
160
|
+
config: ToolConfiguration<I, O>,
|
|
161
|
+
) {
|
|
174
162
|
const inputSchema = getSchema(config.schema);
|
|
175
163
|
validateRequiredProperties(inputSchema as AnyJSONSchema);
|
|
176
164
|
|
|
177
|
-
const outputSchema = config.outputSchema
|
|
178
|
-
? getSchema(config.outputSchema)
|
|
179
|
-
: undefined;
|
|
165
|
+
const outputSchema = config.outputSchema ? getSchema(config.outputSchema) : undefined;
|
|
180
166
|
|
|
181
167
|
if (outputSchema) {
|
|
182
168
|
validateRequiredProperties(outputSchema as AnyJSONSchema);
|
|
@@ -215,14 +201,10 @@ export function createToolCapability<
|
|
|
215
201
|
if (!validateInput(input)) {
|
|
216
202
|
// ajv resets the "errors" property on each validation call.
|
|
217
203
|
if (validateInput.errors == null) {
|
|
218
|
-
throw new Error(
|
|
219
|
-
"Unexpected: No validation errors after failed validation",
|
|
220
|
-
);
|
|
204
|
+
throw new Error("Unexpected: No validation errors after failed validation");
|
|
221
205
|
}
|
|
222
206
|
|
|
223
|
-
const error = new InvalidToolInputError(
|
|
224
|
-
JSON.stringify(validateInput.errors, null, 2),
|
|
225
|
-
);
|
|
207
|
+
const error = new InvalidToolInputError(JSON.stringify(validateInput.errors, null, 2));
|
|
226
208
|
|
|
227
209
|
if (options?.concreteOutput) {
|
|
228
210
|
throw error;
|
|
@@ -242,9 +224,7 @@ export function createToolCapability<
|
|
|
242
224
|
const capabilityContext = createCapabilityContext("tool");
|
|
243
225
|
const result = await config.execute(input, capabilityContext);
|
|
244
226
|
if (validateOutput && !validateOutput(result)) {
|
|
245
|
-
const error = new InvalidToolOutputError(
|
|
246
|
-
JSON.stringify(validateOutput.errors, null, 2),
|
|
247
|
-
);
|
|
227
|
+
const error = new InvalidToolOutputError(JSON.stringify(validateOutput.errors, null, 2));
|
|
248
228
|
|
|
249
229
|
if (options?.concreteOutput) {
|
|
250
230
|
throw error;
|
|
@@ -275,9 +255,7 @@ export function createToolCapability<
|
|
|
275
255
|
value: result,
|
|
276
256
|
};
|
|
277
257
|
} catch (err) {
|
|
278
|
-
const error = new ToolExecutionError(
|
|
279
|
-
err instanceof Error ? err.message : String(err),
|
|
280
|
-
);
|
|
258
|
+
const error = new ToolExecutionError(err instanceof Error ? err.message : String(err));
|
|
281
259
|
|
|
282
260
|
if (options?.concreteOutput) {
|
|
283
261
|
throw error;
|
|
@@ -94,18 +94,12 @@ export interface WebhookConfiguration {
|
|
|
94
94
|
* @param context - The capability execution context (Notion client, etc.)
|
|
95
95
|
* @returns A promise that resolves when the webhook processing completes
|
|
96
96
|
*/
|
|
97
|
-
execute: (
|
|
98
|
-
events: WebhookEvent[],
|
|
99
|
-
context: CapabilityContext,
|
|
100
|
-
) => Promise<void> | void;
|
|
97
|
+
execute: (events: WebhookEvent[], context: CapabilityContext) => Promise<void> | void;
|
|
101
98
|
}
|
|
102
99
|
|
|
103
100
|
export type WebhookCapability = ReturnType<typeof createWebhookCapability>;
|
|
104
101
|
|
|
105
|
-
export function createWebhookCapability(
|
|
106
|
-
key: string,
|
|
107
|
-
config: WebhookConfiguration,
|
|
108
|
-
) {
|
|
102
|
+
export function createWebhookCapability(key: string, config: WebhookConfiguration) {
|
|
109
103
|
return {
|
|
110
104
|
_tag: "webhook" as const,
|
|
111
105
|
key,
|
|
@@ -127,8 +121,7 @@ export function createWebhookCapability(
|
|
|
127
121
|
writeOutput({ _tag: "success", value: { status: "success" } });
|
|
128
122
|
}
|
|
129
123
|
} catch (err) {
|
|
130
|
-
const error =
|
|
131
|
-
err instanceof ExecutionError ? err : new ExecutionError(err);
|
|
124
|
+
const error = err instanceof ExecutionError ? err : new ExecutionError(err);
|
|
132
125
|
|
|
133
126
|
if (!options?.concreteOutput) {
|
|
134
127
|
writeOutput({
|
|
@@ -1,19 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
beforeEach,
|
|
4
|
-
describe,
|
|
5
|
-
expect,
|
|
6
|
-
expectTypeOf,
|
|
7
|
-
it,
|
|
8
|
-
type Mock,
|
|
9
|
-
vi,
|
|
10
|
-
} from "vitest";
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, expectTypeOf, it, type Mock, vi } from "vitest";
|
|
2
|
+
|
|
11
3
|
import { ExecutionError } from "../error.js";
|
|
12
|
-
import {
|
|
13
|
-
type CapabilityContext,
|
|
14
|
-
Worker,
|
|
15
|
-
type WorkflowConfiguration,
|
|
16
|
-
} from "../index.js";
|
|
4
|
+
import { type CapabilityContext, Worker, type WorkflowConfiguration } from "../index.js";
|
|
17
5
|
import {
|
|
18
6
|
type NotionPageCreatedEvent,
|
|
19
7
|
type NotionPageCreatedTrigger,
|
|
@@ -66,9 +54,7 @@ describe("createWorkflowCapability", () => {
|
|
|
66
54
|
let stdoutSpy: Mock<typeof process.stdout.write>;
|
|
67
55
|
|
|
68
56
|
beforeEach(() => {
|
|
69
|
-
stdoutSpy = vi
|
|
70
|
-
.spyOn(process.stdout, "write")
|
|
71
|
-
.mockImplementation(() => true);
|
|
57
|
+
stdoutSpy = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
|
|
72
58
|
});
|
|
73
59
|
|
|
74
60
|
afterEach(() => {
|
|
@@ -82,13 +68,8 @@ describe("createWorkflowCapability", () => {
|
|
|
82
68
|
});
|
|
83
69
|
|
|
84
70
|
it("requires trigger declarations in workflow configuration", () => {
|
|
85
|
-
type PageAddedConfiguration = WorkflowConfiguration<
|
|
86
|
-
|
|
87
|
-
>;
|
|
88
|
-
type ConfigurationWithoutTriggers = Omit<
|
|
89
|
-
PageAddedConfiguration,
|
|
90
|
-
"triggers"
|
|
91
|
-
>;
|
|
71
|
+
type PageAddedConfiguration = WorkflowConfiguration<readonly [NotionPageCreatedTrigger]>;
|
|
72
|
+
type ConfigurationWithoutTriggers = Omit<PageAddedConfiguration, "triggers">;
|
|
92
73
|
|
|
93
74
|
expectTypeOf<ConfigurationWithoutTriggers>().not.toMatchTypeOf<PageAddedConfiguration>();
|
|
94
75
|
});
|
|
@@ -137,9 +118,9 @@ describe("createWorkflowCapability", () => {
|
|
|
137
118
|
execute,
|
|
138
119
|
});
|
|
139
120
|
|
|
140
|
-
await expect(
|
|
141
|
-
|
|
142
|
-
|
|
121
|
+
await expect(capability.handler(pageCreatedEvent, { concreteOutput: true })).resolves.toEqual({
|
|
122
|
+
status: "success",
|
|
123
|
+
});
|
|
143
124
|
expect(execute).toHaveBeenCalledWith(
|
|
144
125
|
pageCreatedEvent,
|
|
145
126
|
expect.objectContaining({ notion: expect.any(Object) }),
|
|
@@ -172,9 +153,7 @@ describe("createWorkflowCapability", () => {
|
|
|
172
153
|
},
|
|
173
154
|
});
|
|
174
155
|
|
|
175
|
-
await expect(capability.handler(pageCreatedEvent)).rejects.toThrow(
|
|
176
|
-
ExecutionError,
|
|
177
|
-
);
|
|
156
|
+
await expect(capability.handler(pageCreatedEvent)).rejects.toThrow(ExecutionError);
|
|
178
157
|
expect(stdoutSpy).toHaveBeenCalledWith(
|
|
179
158
|
expect.stringContaining(
|
|
180
159
|
'"_tag":"error","error":{"name":"ExecutionError","message":"Error during worker execution: Error: Something went wrong"',
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { ExecutionError } from "../error.js";
|
|
2
|
-
import type {
|
|
3
|
-
WorkflowEventMap,
|
|
4
|
-
WorkflowTrigger,
|
|
5
|
-
} from "../triggers.generated.js";
|
|
2
|
+
import type { WorkflowEventMap, WorkflowTrigger } from "../triggers.generated.js";
|
|
6
3
|
import type { HandlerOptions } from "../types.js";
|
|
7
4
|
import type { CapabilityContext } from "./context.js";
|
|
8
5
|
import { createCapabilityContext } from "./context.js";
|
|
@@ -10,8 +7,7 @@ import { writeOutput } from "./output.js";
|
|
|
10
7
|
|
|
11
8
|
export type WorkflowEvent = WorkflowEventMap[keyof WorkflowEventMap];
|
|
12
9
|
|
|
13
|
-
export type WorkflowEventForTrigger<T extends WorkflowTrigger> =
|
|
14
|
-
WorkflowEventMap[T["type"]];
|
|
10
|
+
export type WorkflowEventForTrigger<T extends WorkflowTrigger> = WorkflowEventMap[T["type"]];
|
|
15
11
|
|
|
16
12
|
export type WorkflowEventForTriggers<T extends readonly WorkflowTrigger[]> =
|
|
17
13
|
WorkflowEventForTrigger<T[number]>;
|
|
@@ -46,10 +42,10 @@ export type WorkflowConfiguration<
|
|
|
46
42
|
};
|
|
47
43
|
|
|
48
44
|
export type WorkflowCapability<
|
|
49
|
-
TTriggers extends readonly [
|
|
45
|
+
TTriggers extends readonly [WorkflowTrigger, ...WorkflowTrigger[]] = readonly [
|
|
50
46
|
WorkflowTrigger,
|
|
51
47
|
...WorkflowTrigger[],
|
|
52
|
-
]
|
|
48
|
+
],
|
|
53
49
|
> = {
|
|
54
50
|
_tag: "workflow";
|
|
55
51
|
key: string;
|
|
@@ -73,10 +69,7 @@ export type WorkflowCapability<
|
|
|
73
69
|
*/
|
|
74
70
|
export function createWorkflowCapability<
|
|
75
71
|
const TTriggers extends readonly [WorkflowTrigger, ...WorkflowTrigger[]],
|
|
76
|
-
>(
|
|
77
|
-
key: string,
|
|
78
|
-
config: WorkflowConfiguration<TTriggers>,
|
|
79
|
-
): WorkflowCapability<TTriggers> {
|
|
72
|
+
>(key: string, config: WorkflowConfiguration<TTriggers>): WorkflowCapability<TTriggers> {
|
|
80
73
|
return {
|
|
81
74
|
_tag: "workflow",
|
|
82
75
|
key,
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
export {
|
|
2
|
-
emojiIcon,
|
|
3
|
-
imageCover,
|
|
4
|
-
imageIcon,
|
|
5
|
-
notionIcon,
|
|
6
|
-
place,
|
|
7
|
-
} from "./builder.js";
|
|
1
|
+
export { emojiIcon, imageCover, imageIcon, notionIcon, place } from "./builder.js";
|
|
8
2
|
export type {
|
|
9
3
|
AiConnectorArchetype,
|
|
10
4
|
AiConnectorCapability,
|
|
@@ -43,11 +37,7 @@ export type {
|
|
|
43
37
|
SyncExecutionResult,
|
|
44
38
|
SyncMode,
|
|
45
39
|
} from "./capabilities/sync.js";
|
|
46
|
-
export type {
|
|
47
|
-
ToolCapability,
|
|
48
|
-
ToolConfiguration,
|
|
49
|
-
ToolHints,
|
|
50
|
-
} from "./capabilities/tool.js";
|
|
40
|
+
export type { ToolCapability, ToolConfiguration, ToolHints } from "./capabilities/tool.js";
|
|
51
41
|
export type {
|
|
52
42
|
WebhookCapability,
|
|
53
43
|
WebhookConfiguration,
|
package/src/json-schema.test.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* This ensures tsc sees the error on the line immediately after the directive.
|
|
13
13
|
*/
|
|
14
14
|
import { describe, expect, it } from "vitest";
|
|
15
|
+
|
|
15
16
|
import type {
|
|
16
17
|
AnyJSONSchema,
|
|
17
18
|
JSONSchema,
|
|
@@ -671,10 +672,7 @@ describe("JSONSchema — complex schemas", () => {
|
|
|
671
672
|
|
|
672
673
|
describe("JSONSchema — structural type assertions", () => {
|
|
673
674
|
it("JSONSchemaObjectDef requires additionalProperties to be false", () => {
|
|
674
|
-
type _Proof = Assert<
|
|
675
|
-
JSONSchemaObjectDef<{ x: number }>["additionalProperties"],
|
|
676
|
-
false
|
|
677
|
-
>;
|
|
675
|
+
type _Proof = Assert<JSONSchemaObjectDef<{ x: number }>["additionalProperties"], false>;
|
|
678
676
|
});
|
|
679
677
|
|
|
680
678
|
it("JSONSchemaArrayDef minItems is restricted to 0 | 1", () => {
|