@notionhq/workers 0.5.0 → 0.6.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/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/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/custom-block.d.ts +124 -0
- package/dist/capabilities/custom-block.d.ts.map +1 -0
- package/dist/capabilities/custom-block.js +22 -0
- 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 +3 -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 +41 -1
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +51 -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/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/custom-block.ts +181 -0
- 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 +9 -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.test.ts +147 -0
- package/src/worker.ts +67 -35
- package/dist/block.d.ts +0 -321
- package/dist/block.d.ts.map +0 -1
- package/src/block.ts +0 -529
- /package/dist/{block.js → alpha/ajv-formats.d.js} +0 -0
package/src/capabilities/sync.ts
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
import { ExecutionError, RateLimitError } from "../error.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
initPacerState,
|
|
5
|
-
type PacerDeclaration,
|
|
6
|
-
} from "../pacer_internal.js";
|
|
7
|
-
import type {
|
|
8
|
-
PropertyConfiguration,
|
|
9
|
-
PropertySchema,
|
|
10
|
-
Schema,
|
|
11
|
-
} from "../schema.js";
|
|
2
|
+
import { getPacerState, initPacerState, type PacerDeclaration } from "../pacer_internal.js";
|
|
3
|
+
import type { PropertyConfiguration, PropertySchema, Schema } from "../schema.js";
|
|
12
4
|
import type {
|
|
13
5
|
Cover,
|
|
14
6
|
HandlerOptions,
|
|
@@ -62,10 +54,7 @@ export type SyncMode = StatefulCapabilityMode;
|
|
|
62
54
|
/**
|
|
63
55
|
* A change representing a record to be created or updated.
|
|
64
56
|
*/
|
|
65
|
-
export type SyncChangeUpsert<
|
|
66
|
-
PK extends string,
|
|
67
|
-
S extends PropertySchema<PK>,
|
|
68
|
-
> = {
|
|
57
|
+
export type SyncChangeUpsert<PK extends string, S extends PropertySchema<PK>> = {
|
|
69
58
|
/**
|
|
70
59
|
* The type of change. Use `"upsert"` to create or update a record.
|
|
71
60
|
*/
|
|
@@ -168,11 +157,7 @@ export type SyncExecutionResult<PK extends string, State = unknown> = {
|
|
|
168
157
|
/**
|
|
169
158
|
* Configuration for a sync capability that syncs data to a database.
|
|
170
159
|
*/
|
|
171
|
-
export type SyncConfiguration<
|
|
172
|
-
PK extends string,
|
|
173
|
-
S extends Schema<PK>,
|
|
174
|
-
State = unknown,
|
|
175
|
-
> = {
|
|
160
|
+
export type SyncConfiguration<PK extends string, S extends Schema<PK>, State = unknown> = {
|
|
176
161
|
/**
|
|
177
162
|
* The database to sync data into.
|
|
178
163
|
*/
|
|
@@ -233,11 +218,7 @@ export type SyncCapability = ReturnType<typeof createSyncCapability>;
|
|
|
233
218
|
* @returns A handler function that executes the sync function, and passes data
|
|
234
219
|
* needed to complete the sync back to the platform.
|
|
235
220
|
*/
|
|
236
|
-
export function createSyncCapability<
|
|
237
|
-
PK extends string,
|
|
238
|
-
S extends Schema<PK>,
|
|
239
|
-
Context = unknown,
|
|
240
|
-
>(
|
|
221
|
+
export function createSyncCapability<PK extends string, S extends Schema<PK>, Context = unknown>(
|
|
241
222
|
key: string,
|
|
242
223
|
syncConfiguration: SyncConfiguration<PK, S, Context>,
|
|
243
224
|
pacerDeclarations?: readonly PacerDeclaration[],
|
|
@@ -249,14 +230,9 @@ export function createSyncCapability<
|
|
|
249
230
|
databaseKey: syncConfiguration.database.key,
|
|
250
231
|
primaryKeyProperty: syncConfiguration.database.config.primaryKeyProperty,
|
|
251
232
|
mode: syncConfiguration.mode,
|
|
252
|
-
schedule: syncConfiguration.schedule
|
|
253
|
-
? parseSchedule(syncConfiguration.schedule)
|
|
254
|
-
: undefined,
|
|
233
|
+
schedule: syncConfiguration.schedule ? parseSchedule(syncConfiguration.schedule) : undefined,
|
|
255
234
|
},
|
|
256
|
-
async handler(
|
|
257
|
-
runtimeContext?: StatefulRuntimeContext<Context>,
|
|
258
|
-
options?: HandlerOptions,
|
|
259
|
-
) {
|
|
235
|
+
async handler(runtimeContext?: StatefulRuntimeContext<Context>, options?: HandlerOptions) {
|
|
260
236
|
const capabilityContext = createCapabilityContext("sync");
|
|
261
237
|
const state = runtimeContext?.state ?? runtimeContext?.userContext;
|
|
262
238
|
|
|
@@ -264,10 +240,7 @@ export function createSyncCapability<
|
|
|
264
240
|
|
|
265
241
|
let executionResult: SyncExecutionResult<PK, Context>;
|
|
266
242
|
try {
|
|
267
|
-
executionResult = await syncConfiguration.execute(
|
|
268
|
-
state,
|
|
269
|
-
capabilityContext,
|
|
270
|
-
);
|
|
243
|
+
executionResult = await syncConfiguration.execute(state, capabilityContext);
|
|
271
244
|
} catch (err) {
|
|
272
245
|
if (err instanceof RateLimitError) {
|
|
273
246
|
if (!options?.concreteOutput) {
|
|
@@ -277,9 +250,7 @@ export function createSyncCapability<
|
|
|
277
250
|
_tag: "rate_limit",
|
|
278
251
|
name: err.name,
|
|
279
252
|
message: err.message,
|
|
280
|
-
...(err.retryAfter !== undefined
|
|
281
|
-
? { retryAfter: err.retryAfter }
|
|
282
|
-
: {}),
|
|
253
|
+
...(err.retryAfter !== undefined ? { retryAfter: err.retryAfter } : {}),
|
|
283
254
|
},
|
|
284
255
|
};
|
|
285
256
|
writeOutput(envelope);
|
|
@@ -304,8 +275,7 @@ export function createSyncCapability<
|
|
|
304
275
|
|
|
305
276
|
const changes = executionResult.changes.map((change) => ({
|
|
306
277
|
...change,
|
|
307
|
-
targetDatabaseKey:
|
|
308
|
-
change.targetDatabaseKey ?? syncConfiguration.database.key,
|
|
278
|
+
targetDatabaseKey: change.targetDatabaseKey ?? syncConfiguration.database.key,
|
|
309
279
|
}));
|
|
310
280
|
|
|
311
281
|
const result = {
|
|
@@ -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({
|