@plotday/twister 0.47.0 → 0.49.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.
Files changed (123) hide show
  1. package/bin/commands/generate.js +5 -5
  2. package/bin/commands/generate.js.map +1 -1
  3. package/bin/templates/AGENTS.template.md +8 -2
  4. package/bin/utils/bundle.js +14 -0
  5. package/bin/utils/bundle.js.map +1 -1
  6. package/cli/templates/AGENTS.template.md +8 -2
  7. package/dist/connector.d.ts +67 -7
  8. package/dist/connector.d.ts.map +1 -1
  9. package/dist/connector.js +15 -5
  10. package/dist/connector.js.map +1 -1
  11. package/dist/docs/assets/hierarchy.js +1 -1
  12. package/dist/docs/assets/navigation.js +1 -1
  13. package/dist/docs/assets/search.js +1 -1
  14. package/dist/docs/classes/index.Connector.html +58 -49
  15. package/dist/docs/classes/index.Imap.html +1 -1
  16. package/dist/docs/classes/index.Options.html +1 -1
  17. package/dist/docs/classes/index.Smtp.html +1 -1
  18. package/dist/docs/classes/tools_ai.AI.html +1 -1
  19. package/dist/docs/classes/tools_callbacks.Callbacks.html +1 -1
  20. package/dist/docs/classes/tools_integrations.Integrations.html +21 -5
  21. package/dist/docs/classes/tools_network.Network.html +1 -1
  22. package/dist/docs/classes/tools_plot.Plot.html +1 -1
  23. package/dist/docs/classes/tools_store.Store.html +1 -1
  24. package/dist/docs/classes/tools_tasks.Tasks.html +1 -1
  25. package/dist/docs/classes/tools_twists.Twists.html +1 -1
  26. package/dist/docs/classes/twist.Twist.html +28 -28
  27. package/dist/docs/documents/Building_Connectors.html +8 -1
  28. package/dist/docs/documents/CLI_Reference.html +6 -4
  29. package/dist/docs/enums/tag.Tag.html +11 -1
  30. package/dist/docs/enums/tools_integrations.AuthProvider.html +14 -12
  31. package/dist/docs/hierarchy.html +1 -1
  32. package/dist/docs/media/AGENTS.md +298 -775
  33. package/dist/docs/media/MULTI_USER_AUTH.md +6 -4
  34. package/dist/docs/media/SYNC_STRATEGIES.md +20 -14
  35. package/dist/docs/modules/index.html +1 -1
  36. package/dist/docs/types/index.CreateLinkDraft.html +7 -12
  37. package/dist/docs/types/index.NoteWriteBackResult.html +38 -0
  38. package/dist/docs/types/tools_integrations.ArchiveLinkFilter.html +5 -5
  39. package/dist/docs/types/tools_integrations.AuthToken.html +4 -4
  40. package/dist/docs/types/tools_integrations.Authorization.html +4 -4
  41. package/dist/llm-docs/connector.d.ts +1 -1
  42. package/dist/llm-docs/connector.d.ts.map +1 -1
  43. package/dist/llm-docs/connector.js +1 -1
  44. package/dist/llm-docs/connector.js.map +1 -1
  45. package/dist/llm-docs/tag.d.ts +1 -1
  46. package/dist/llm-docs/tag.d.ts.map +1 -1
  47. package/dist/llm-docs/tag.js +1 -1
  48. package/dist/llm-docs/tag.js.map +1 -1
  49. package/dist/llm-docs/tools/integrations.d.ts +1 -1
  50. package/dist/llm-docs/tools/integrations.d.ts.map +1 -1
  51. package/dist/llm-docs/tools/integrations.js +1 -1
  52. package/dist/llm-docs/tools/integrations.js.map +1 -1
  53. package/dist/llm-docs/twist-guide-template.d.ts +1 -1
  54. package/dist/llm-docs/twist-guide-template.d.ts.map +1 -1
  55. package/dist/llm-docs/twist-guide-template.js +1 -1
  56. package/dist/llm-docs/twist-guide-template.js.map +1 -1
  57. package/dist/llm-docs/twist.d.ts +1 -1
  58. package/dist/llm-docs/twist.d.ts.map +1 -1
  59. package/dist/llm-docs/twist.js +1 -1
  60. package/dist/llm-docs/twist.js.map +1 -1
  61. package/dist/tag.d.ts +11 -1
  62. package/dist/tag.d.ts.map +1 -1
  63. package/dist/tag.js +10 -0
  64. package/dist/tag.js.map +1 -1
  65. package/dist/tools/integrations.d.ts +25 -1
  66. package/dist/tools/integrations.d.ts.map +1 -1
  67. package/dist/tools/integrations.js +2 -0
  68. package/dist/tools/integrations.js.map +1 -1
  69. package/dist/twist-guide.d.ts +1 -1
  70. package/dist/twist-guide.d.ts.map +1 -1
  71. package/dist/twist.d.ts +2 -1
  72. package/dist/twist.d.ts.map +1 -1
  73. package/dist/twist.js.map +1 -1
  74. package/dist/utils/markdown.d.ts +27 -0
  75. package/dist/utils/markdown.d.ts.map +1 -0
  76. package/dist/utils/markdown.js +82 -0
  77. package/dist/utils/markdown.js.map +1 -0
  78. package/package.json +7 -1
  79. package/src/connector.ts +427 -0
  80. package/src/creator-docs.ts +29 -0
  81. package/src/index.ts +10 -0
  82. package/src/llm-docs/connector.ts +8 -0
  83. package/src/llm-docs/index.ts +48 -0
  84. package/src/llm-docs/options.ts +8 -0
  85. package/src/llm-docs/plot.ts +8 -0
  86. package/src/llm-docs/schedule.ts +8 -0
  87. package/src/llm-docs/tag.ts +8 -0
  88. package/src/llm-docs/tool.ts +8 -0
  89. package/src/llm-docs/tools/ai.ts +8 -0
  90. package/src/llm-docs/tools/callbacks.ts +8 -0
  91. package/src/llm-docs/tools/imap.ts +8 -0
  92. package/src/llm-docs/tools/integrations.ts +8 -0
  93. package/src/llm-docs/tools/network.ts +8 -0
  94. package/src/llm-docs/tools/plot.ts +8 -0
  95. package/src/llm-docs/tools/smtp.ts +8 -0
  96. package/src/llm-docs/tools/store.ts +8 -0
  97. package/src/llm-docs/tools/tasks.ts +8 -0
  98. package/src/llm-docs/tools/twists.ts +8 -0
  99. package/src/llm-docs/twist-guide-template.ts +8 -0
  100. package/src/llm-docs/twist.ts +8 -0
  101. package/src/options.ts +115 -0
  102. package/src/plot.ts +1068 -0
  103. package/src/schedule.ts +203 -0
  104. package/src/tag.ts +54 -0
  105. package/src/tool.ts +377 -0
  106. package/src/tools/ai.ts +845 -0
  107. package/src/tools/callbacks.ts +134 -0
  108. package/src/tools/imap.ts +266 -0
  109. package/src/tools/index.ts +10 -0
  110. package/src/tools/integrations.ts +352 -0
  111. package/src/tools/network.ts +240 -0
  112. package/src/tools/plot.ts +692 -0
  113. package/src/tools/smtp.ts +166 -0
  114. package/src/tools/store.ts +149 -0
  115. package/src/tools/tasks.ts +137 -0
  116. package/src/tools/twists.ts +228 -0
  117. package/src/twist-guide.ts +9 -0
  118. package/src/twist.ts +436 -0
  119. package/src/utils/hash.ts +8 -0
  120. package/src/utils/markdown.ts +94 -0
  121. package/src/utils/serializable.ts +54 -0
  122. package/src/utils/types.ts +130 -0
  123. package/src/utils/uuid.ts +9 -0
@@ -0,0 +1,203 @@
1
+ import { type Tag } from "./tag";
2
+ import {
3
+ type Actor,
4
+ type ActorId,
5
+ type NewActor,
6
+ type NewTags,
7
+ type Tags,
8
+ } from "./plot";
9
+ import { Uuid } from "./utils/uuid";
10
+
11
+ export { Uuid } from "./utils/uuid";
12
+
13
+ /**
14
+ * Represents a schedule entry for a thread.
15
+ *
16
+ * Schedules define when a thread occurs in time. A thread may have zero or more schedules:
17
+ * - Shared schedules (userId is null): visible to all members of the thread's priority
18
+ * - Per-user schedules (userId set): private ordering/scheduling for a specific user
19
+ *
20
+ * For recurring events in the SDK, start/end represent the first occurrence's
21
+ * time. In the database, the `at`/`on` range is expanded to span from the first
22
+ * occurrence start to the last occurrence end (or open-ended if no fixed end).
23
+ * The `duration` column stores the per-occurrence duration, enabling range overlap
24
+ * queries to correctly find all recurring events with occurrences in a given window.
25
+ */
26
+ export type Schedule = {
27
+ /** When this schedule was created */
28
+ created: Date;
29
+ /** Whether this schedule has been archived */
30
+ archived: boolean;
31
+ /** If set, this is a per-user schedule visible only to this user */
32
+ userId: ActorId | null;
33
+ /** Per-user ordering within a day (only set for per-user schedules) */
34
+ order: number | null;
35
+ /**
36
+ * Start time of the schedule.
37
+ * Date object for timed events, date string in "YYYY-MM-DD" format for all-day events.
38
+ */
39
+ start: Date | string | null;
40
+ /**
41
+ * End time of the schedule.
42
+ * Date object for timed events, date string in "YYYY-MM-DD" format for all-day events.
43
+ */
44
+ end: Date | string | null;
45
+ /** Recurrence rule in RFC 5545 RRULE format (e.g., "FREQ=WEEKLY;BYDAY=MO,WE,FR") */
46
+ recurrenceRule: string | null;
47
+ /** Duration of each occurrence in milliseconds (required for recurring schedules) */
48
+ duration: number | null;
49
+ /** Array of dates to exclude from the recurrence pattern */
50
+ recurrenceExdates: Date[] | null;
51
+ /**
52
+ * For occurrence exceptions: the original date/time of this occurrence in the series.
53
+ * Format: Date object or "YYYY-MM-DD" for all-day events.
54
+ */
55
+ occurrence: Date | string | null;
56
+ /** Contacts invited to this schedule (attendees/participants) */
57
+ contacts: ScheduleContact[];
58
+ };
59
+
60
+ export type ScheduleContactStatus = "attend" | "skip";
61
+ export type ScheduleContactRole = "organizer" | "required" | "optional";
62
+
63
+ export type ScheduleContact = {
64
+ contact: Actor;
65
+ status: ScheduleContactStatus | null;
66
+ role: ScheduleContactRole;
67
+ archived: boolean;
68
+ };
69
+
70
+ export type NewScheduleContact = {
71
+ contact: NewActor;
72
+ status?: ScheduleContactStatus | null;
73
+ role?: ScheduleContactRole | null;
74
+ archived?: boolean;
75
+ };
76
+
77
+ /**
78
+ * Type for creating new schedules.
79
+ *
80
+ * Requires `threadId` and `start`. All other fields are optional.
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * // Simple timed event
85
+ * const schedule: NewSchedule = {
86
+ * threadId: threadId,
87
+ * start: new Date("2025-03-15T10:00:00Z"),
88
+ * end: new Date("2025-03-15T11:00:00Z")
89
+ * };
90
+ *
91
+ * // All-day event
92
+ * const allDay: NewSchedule = {
93
+ * threadId: threadId,
94
+ * start: "2025-03-15",
95
+ * end: "2025-03-16"
96
+ * };
97
+ *
98
+ * // Recurring weekly event
99
+ * const recurring: NewSchedule = {
100
+ * threadId: threadId,
101
+ * start: new Date("2025-01-20T14:00:00Z"),
102
+ * end: new Date("2025-01-20T15:00:00Z"),
103
+ * recurrenceRule: "FREQ=WEEKLY;BYDAY=MO",
104
+ * recurrenceUntil: new Date("2025-06-30")
105
+ * };
106
+ * ```
107
+ */
108
+ export type NewSchedule = {
109
+ /** The thread this schedule belongs to */
110
+ threadId: Uuid;
111
+ /**
112
+ * Start time. Date for timed events, "YYYY-MM-DD" for all-day.
113
+ * Determines whether the schedule uses `at` (timed) or `on` (all-day) storage.
114
+ */
115
+ start: Date | string;
116
+ /** End time. Date for timed events, "YYYY-MM-DD" for all-day. */
117
+ end?: Date | string | null;
118
+ /** Recurrence rule in RFC 5545 RRULE format */
119
+ recurrenceRule?: string | null;
120
+ /**
121
+ * For recurring schedules, the last occurrence date (inclusive).
122
+ * When both recurrenceCount and recurrenceUntil are provided, recurrenceCount takes precedence.
123
+ */
124
+ recurrenceUntil?: Date | string | null;
125
+ /**
126
+ * For recurring schedules, the number of occurrences to generate.
127
+ * Takes precedence over recurrenceUntil if both are provided.
128
+ */
129
+ recurrenceCount?: number | null;
130
+ /** Array of dates to exclude from the recurrence pattern */
131
+ recurrenceExdates?: Date[] | null;
132
+ /**
133
+ * For occurrence exceptions: the original date/time of this occurrence.
134
+ */
135
+ occurrence?: Date | string | null;
136
+ /** If set, this is a per-user schedule for the specified user */
137
+ userId?: ActorId | null;
138
+ /** Per-user ordering (only valid with userId) */
139
+ order?: number | null;
140
+ /** Whether to archive this schedule */
141
+ archived?: boolean;
142
+ /** Contacts to upsert on this schedule. Upserted by contact identity. */
143
+ contacts?: NewScheduleContact[];
144
+ };
145
+
146
+ /**
147
+ * Represents a specific instance of a recurring schedule.
148
+ * All field values are computed by merging the recurring schedule's
149
+ * defaults with any occurrence-specific overrides.
150
+ */
151
+ export type ScheduleOccurrence = {
152
+ /**
153
+ * Original date/datetime of this occurrence.
154
+ * Use start for the occurrence's current start time.
155
+ */
156
+ occurrence: Date | string;
157
+
158
+ /** The recurring schedule of which this is an occurrence */
159
+ schedule: Schedule;
160
+
161
+ /** Effective start for this occurrence (series default + override) */
162
+ start: Date | string;
163
+ /** Effective end for this occurrence */
164
+ end: Date | string | null;
165
+
166
+ /** Tags for this occurrence */
167
+ tags: Tags;
168
+
169
+ /** True if the occurrence is archived */
170
+ archived: boolean;
171
+ };
172
+
173
+ /**
174
+ * Type for creating or updating schedule occurrences.
175
+ */
176
+ export type NewScheduleOccurrence = Pick<
177
+ ScheduleOccurrence,
178
+ "occurrence" | "start"
179
+ > &
180
+ Partial<
181
+ Omit<ScheduleOccurrence, "occurrence" | "start" | "schedule" | "tags">
182
+ > & {
183
+ /** Tags for this occurrence */
184
+ tags?: NewTags;
185
+
186
+ /** Add or remove the twist's tags on this occurrence */
187
+ twistTags?: Partial<Record<Tag, boolean>>;
188
+
189
+ /** Whether this occurrence should be marked as unread */
190
+ unread?: boolean;
191
+
192
+ /** Contacts to upsert on this occurrence's schedule */
193
+ contacts?: NewScheduleContact[];
194
+ };
195
+
196
+ /**
197
+ * Type for updating schedule occurrences inline.
198
+ */
199
+ export type ScheduleOccurrenceUpdate = Pick<
200
+ NewScheduleOccurrence,
201
+ "occurrence"
202
+ > &
203
+ Partial<Omit<NewScheduleOccurrence, "occurrence" | "schedule">>;
package/src/tag.ts ADDED
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Thread tags. Three types:
3
+ * 1. Special tags, which trigger other behaviors
4
+ * 2. Toggle tags, which anyone can toggle a shared value on or off
5
+ * 3. Count tags, where everyone can add or remove their own
6
+ */
7
+ export enum Tag {
8
+ // Special tags
9
+ Todo = 1,
10
+ Done = 3,
11
+
12
+ // Toggle tags
13
+ Pinned = 100,
14
+ Urgent = 101,
15
+ Goal = 103,
16
+ Decision = 104,
17
+ Waiting = 105,
18
+ Blocked = 106,
19
+ Warning = 107,
20
+ Question = 108,
21
+ Twist = 109,
22
+ Star = 110,
23
+ Idea = 111,
24
+
25
+ // Count tags
26
+ Yes = 1000,
27
+ No = 1001,
28
+ Volunteer = 1002,
29
+ Tada = 1003,
30
+ Fire = 1004,
31
+ Totally = 1005,
32
+ Looking = 1006,
33
+ Love = 1007,
34
+ Rocket = 1008,
35
+ Sparkles = 1009,
36
+ Thanks = 1010,
37
+ Smile = 1011,
38
+ Wave = 1012,
39
+ Praise = 1015,
40
+ Applause = 1016,
41
+ Cool = 1017,
42
+ Sad = 1018,
43
+ Reply = 1019,
44
+ Thinking = 1013,
45
+ Remember = 1014,
46
+ Agreed = 1020,
47
+ Relieved = 1021,
48
+ Send = 1022,
49
+ Noted = 1023,
50
+ Laugh = 1024,
51
+ Surprised = 1025,
52
+ Confused = 1026,
53
+ Dismayed = 1027,
54
+ }
package/src/tool.ts ADDED
@@ -0,0 +1,377 @@
1
+ import {
2
+ type Actor,
3
+ } from "./plot";
4
+ import type { Callback } from "./tools/callbacks";
5
+ import type {
6
+ InferOptions,
7
+ InferTools,
8
+ Serializable,
9
+ ToolBuilder,
10
+ ToolShed,
11
+ } from "./utils/types";
12
+
13
+ export type { ToolBuilder };
14
+
15
+ /**
16
+ * Abstrtact parent for both built-in tools and regular Tools.
17
+ * Regular tools extend Tool.
18
+ */
19
+ export abstract class ITool {}
20
+
21
+ /**
22
+ * Base class for regular tools.
23
+ *
24
+ * Regular tools run in isolation and can only access other tools declared
25
+ * in their build method. They are ideal for external API integrations
26
+ * and reusable functionality that doesn't require Plot's internal infrastructure.
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * class GoogleCalendarTool extends Tool<GoogleCalendarTool> {
31
+ * constructor(id: string, options: { clientId: string }) {
32
+ * super(id, options);
33
+ * }
34
+ *
35
+ * build(tools: ToolBuilder) {
36
+ * return {
37
+ * auth: tools.build(Integrations),
38
+ * network: tools.build(Network),
39
+ * };
40
+ * }
41
+ *
42
+ * async getCalendars() {
43
+ * const token = await this.tools.auth.get(...);
44
+ * // Implementation
45
+ * }
46
+ * }
47
+ * ```
48
+ */
49
+ export abstract class Tool<TSelf> implements ITool {
50
+ constructor(
51
+ protected id: string,
52
+ protected options: InferOptions<TSelf>,
53
+ private toolShed: ToolShed
54
+ ) {}
55
+
56
+ /**
57
+ * Gets the initialized tools for this tool.
58
+ * @throws Error if called before initialization is complete
59
+ */
60
+ protected get tools() {
61
+ return this.toolShed.getTools<InferTools<TSelf>>();
62
+ }
63
+
64
+ /**
65
+ * Declares tool dependencies for this tool.
66
+ * Return an object mapping tool names to build() promises.
67
+ * Default implementation returns empty object (no custom tools).
68
+ *
69
+ * @param build - The build function to use for declaring dependencies
70
+ * @returns Object mapping tool names to tool promises
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * build(build: ToolBuilder) {
75
+ * return {
76
+ * network: build(Network, { urls: ["https://api.example.com/*"] }),
77
+ * };
78
+ * }
79
+ * ```
80
+ */
81
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
82
+ build(build: ToolBuilder): Record<string, Promise<ITool>> {
83
+ return {};
84
+ }
85
+
86
+ /**
87
+ * Creates a persistent callback to a method on this tool.
88
+ *
89
+ * ExtraArgs are strongly typed to match the method's signature.
90
+ *
91
+ * @param fn - The method to callback
92
+ * @param extraArgs - Additional arguments to pass (type-checked, must be serializable)
93
+ * @returns Promise resolving to a persistent callback token
94
+ *
95
+ * @example
96
+ * ```typescript
97
+ * const callback = await this.callback(this.onWebhook, "calendar", 123);
98
+ * ```
99
+ */
100
+ protected async callback<
101
+ TArgs extends Serializable[],
102
+ Fn extends (...args: TArgs) => any
103
+ >(fn: Fn, ...extraArgs: TArgs): Promise<Callback> {
104
+ return this.tools.callbacks.create(fn, ...extraArgs);
105
+ }
106
+
107
+ /**
108
+ * Deletes a specific callback by its token.
109
+ *
110
+ * @param token - The callback token to delete
111
+ * @returns Promise that resolves when the callback is deleted
112
+ */
113
+ protected async deleteCallback(token: Callback): Promise<void> {
114
+ return this.tools.callbacks.delete(token);
115
+ }
116
+
117
+ /**
118
+ * Deletes all callbacks for this tool.
119
+ *
120
+ * @returns Promise that resolves when all callbacks are deleted
121
+ */
122
+ protected async deleteAllCallbacks(): Promise<void> {
123
+ return this.tools.callbacks.deleteAll();
124
+ }
125
+
126
+ /**
127
+ * Executes a callback by its token inline in the current execution.
128
+ *
129
+ * **Use `this.runTask()` instead for batch continuations and long-running work.**
130
+ * `this.run()` executes inline, sharing the current request count (~1000 limit)
131
+ * and blocking the HTTP response. This causes timeouts when used in lifecycle
132
+ * methods like `onChannelEnabled` or `syncBatch` continuations.
133
+ *
134
+ * `this.run()` is appropriate when you need the callback's **return value** —
135
+ * e.g., running a parent callback token that returns data. For fire-and-forget
136
+ * work, always prefer `this.runTask()`.
137
+ *
138
+ * @param token - The callback token to execute
139
+ * @param args - Optional arguments to pass to the callback
140
+ * @returns Promise resolving to the callback result
141
+ */
142
+ protected async run(token: Callback, ...args: any[]): Promise<any> {
143
+ return this.tools.callbacks.run(token, ...args);
144
+ }
145
+
146
+ /**
147
+ * Retrieves a value from persistent storage by key.
148
+ *
149
+ * Values are automatically deserialized using SuperJSON, which
150
+ * properly restores Date objects, Maps, Sets, and other complex types.
151
+ *
152
+ * @template T - The expected type of the stored value (must be Serializable)
153
+ * @param key - The storage key to retrieve
154
+ * @returns Promise resolving to the stored value or null
155
+ */
156
+ protected async get<T extends Serializable>(key: string): Promise<T | null> {
157
+ return this.tools.store.get(key);
158
+ }
159
+
160
+ /**
161
+ * Stores a value in persistent storage.
162
+ *
163
+ * The value will be serialized using SuperJSON and stored persistently.
164
+ * SuperJSON automatically handles Date objects, Maps, Sets, undefined values,
165
+ * and other complex types that standard JSON doesn't support.
166
+ *
167
+ * **Important**: Functions and Symbols cannot be stored.
168
+ * **For function references**: Use callbacks instead of storing functions directly.
169
+ *
170
+ * @example
171
+ * ```typescript
172
+ * // ✅ Date objects are preserved
173
+ * await this.set("sync_state", {
174
+ * lastSync: new Date(),
175
+ * minDate: new Date(2024, 0, 1)
176
+ * });
177
+ *
178
+ * // ✅ undefined is now supported
179
+ * await this.set("data", { name: "test", optional: undefined });
180
+ *
181
+ * // ✅ Arrays with undefined are supported
182
+ * await this.set("items", [1, undefined, 3]);
183
+ * await this.set("items", [1, null, 3]); // Also works
184
+ *
185
+ * // ✅ Maps and Sets are supported
186
+ * await this.set("mapping", new Map([["key", "value"]]));
187
+ * await this.set("tags", new Set(["tag1", "tag2"]));
188
+ *
189
+ * // ❌ WRONG: Cannot store functions directly
190
+ * await this.set("handler", this.myHandler);
191
+ *
192
+ * // ✅ CORRECT: Create a callback token first
193
+ * const token = await this.callback(this.myHandler, "arg1", "arg2");
194
+ * await this.set("handler_token", token);
195
+ *
196
+ * // Later, execute the callback
197
+ * const token = await this.get<string>("handler_token");
198
+ * await this.run(token, args);
199
+ * ```
200
+ *
201
+ * @template T - The type of value being stored (must be Serializable)
202
+ * @param key - The storage key to use
203
+ * @param value - The value to store (must be SuperJSON-serializable)
204
+ * @returns Promise that resolves when the value is stored
205
+ */
206
+ protected async set<T extends Serializable>(
207
+ key: string,
208
+ value: T
209
+ ): Promise<void> {
210
+ return this.tools.store.set(key, value);
211
+ }
212
+
213
+ /**
214
+ * Lists all storage keys matching a prefix.
215
+ *
216
+ * @param prefix - The prefix to match keys against
217
+ * @returns Promise resolving to an array of matching key strings
218
+ */
219
+ protected async list(prefix: string): Promise<string[]> {
220
+ return this.tools.store.list(prefix);
221
+ }
222
+
223
+ /**
224
+ * Removes a specific key from persistent storage.
225
+ *
226
+ * @param key - The storage key to remove
227
+ * @returns Promise that resolves when the key is removed
228
+ */
229
+ protected async clear(key: string): Promise<void> {
230
+ return this.tools.store.clear(key);
231
+ }
232
+
233
+ /**
234
+ * Removes all keys from this tool's storage.
235
+ *
236
+ * @returns Promise that resolves when all keys are removed
237
+ */
238
+ protected async clearAll(): Promise<void> {
239
+ return this.tools.store.clearAll();
240
+ }
241
+
242
+ /**
243
+ * Queues a callback to execute in a separate worker context with a fresh request limit.
244
+ *
245
+ * **Creates a NEW execution** with its own request limit of ~1000 requests (HTTP requests,
246
+ * tool calls, database operations). This is the primary way to stay under request limits
247
+ * when processing large datasets or making many API calls.
248
+ *
249
+ * Use this to break long loops into chunks that each stay under the ~1000 request limit.
250
+ * Each task runs in an isolated execution environment with ~1000 requests and ~60 seconds CPU time.
251
+ *
252
+ * @param callback - The callback token created with `this.callback()`
253
+ * @param options - Optional configuration for the execution
254
+ * @param options.runAt - If provided, schedules execution at this time; otherwise runs immediately
255
+ * @returns Promise resolving to a cancellation token (only for scheduled executions)
256
+ *
257
+ * @example
258
+ * ```typescript
259
+ * // Break large loop into batches
260
+ * const callback = await this.callback("processBatch", { page: 1 });
261
+ * await this.runTask(callback); // New execution with fresh request limit
262
+ * ```
263
+ */
264
+ protected async runTask(
265
+ callback: Callback,
266
+ options?: { runAt?: Date }
267
+ ): Promise<string | void> {
268
+ return this.tools.tasks.runTask(callback, options);
269
+ }
270
+
271
+ /**
272
+ * Cancels a previously scheduled execution.
273
+ *
274
+ * @param token - The cancellation token returned by runTask() with runAt option
275
+ * @returns Promise that resolves when the cancellation is processed
276
+ */
277
+ protected async cancelTask(token: string): Promise<void> {
278
+ return this.tools.tasks.cancelTask(token);
279
+ }
280
+
281
+ /**
282
+ * Cancels all scheduled executions for this tool.
283
+ *
284
+ * @returns Promise that resolves when all cancellations are processed
285
+ */
286
+ protected async cancelAllTasks(): Promise<void> {
287
+ return this.tools.tasks.cancelAllTasks();
288
+ }
289
+
290
+ /**
291
+ * Called before the twist's activate method, starting from the deepest tool dependencies.
292
+ *
293
+ * This method is called in a depth-first manner, with the deepest dependencies
294
+ * being called first, bubbling up to the top-level tools before the twist's
295
+ * activate method is called.
296
+ *
297
+ * @param context - Optional context containing the actor who triggered activation
298
+ * @returns Promise that resolves when pre-activation is complete
299
+ */
300
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
301
+ preActivate(context?: { actor: Actor }): Promise<void> {
302
+ return Promise.resolve();
303
+ }
304
+
305
+ /**
306
+ * Called after the twist's activate method, starting from the top-level tools.
307
+ *
308
+ * This method is called in reverse order, with top-level tools being called
309
+ * first, then cascading down to the deepest dependencies.
310
+ *
311
+ * @param context - Optional context containing the actor who triggered activation
312
+ * @returns Promise that resolves when post-activation is complete
313
+ */
314
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
315
+ postActivate(context?: { actor: Actor }): Promise<void> {
316
+ return Promise.resolve();
317
+ }
318
+
319
+ /**
320
+ * Called before the twist's upgrade method, starting from the deepest tool dependencies.
321
+ *
322
+ * This method is called in a depth-first manner, with the deepest dependencies
323
+ * being called first, bubbling up to the top-level tools before the twist's
324
+ * upgrade method is called.
325
+ *
326
+ * @returns Promise that resolves when pre-upgrade is complete
327
+ */
328
+ preUpgrade(): Promise<void> {
329
+ return Promise.resolve();
330
+ }
331
+
332
+ /**
333
+ * Called after the twist's upgrade method, starting from the top-level tools.
334
+ *
335
+ * This method is called in reverse order, with top-level tools being called
336
+ * first, then cascading down to the deepest dependencies.
337
+ *
338
+ * @returns Promise that resolves when post-upgrade is complete
339
+ */
340
+ postUpgrade(): Promise<void> {
341
+ return Promise.resolve();
342
+ }
343
+
344
+ /**
345
+ * Called before the twist's deactivate method, starting from the deepest tool dependencies.
346
+ *
347
+ * This method is called in a depth-first manner, with the deepest dependencies
348
+ * being called first, bubbling up to the top-level tools before the twist's
349
+ * deactivate method is called.
350
+ *
351
+ * @returns Promise that resolves when pre-deactivation is complete
352
+ */
353
+ preDeactivate(): Promise<void> {
354
+ return Promise.resolve();
355
+ }
356
+
357
+ /**
358
+ * Called after the twist's deactivate method, starting from the top-level tools.
359
+ *
360
+ * This method is called in reverse order, with top-level tools being called
361
+ * first, then cascading down to the deepest dependencies.
362
+ *
363
+ * @returns Promise that resolves when post-deactivation is complete
364
+ */
365
+ postDeactivate(): Promise<void> {
366
+ return Promise.resolve();
367
+ }
368
+
369
+ /**
370
+ * Waits for tool initialization to complete.
371
+ * Called automatically by the entrypoint before lifecycle methods.
372
+ * @internal
373
+ */
374
+ async waitForReady(): Promise<void> {
375
+ await this.toolShed.waitForReady();
376
+ }
377
+ }