zeitlich 0.2.0 → 0.2.2

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/workflow.js CHANGED
@@ -1,5 +1,5 @@
1
- import { defineQuery, proxyActivities, setHandler, workflowInfo, uuid4, executeChild } from '@temporalio/workflow';
2
- import z4, { z } from 'zod';
1
+ import { defineQuery, proxyActivities, setHandler, uuid4, workflowInfo, executeChild } from '@temporalio/workflow';
2
+ import z5, { z } from 'zod';
3
3
 
4
4
  // src/lib/session.ts
5
5
  var TASK_TOOL = "Task";
@@ -34,10 +34,10 @@ function createTaskTool(subagents) {
34
34
  return {
35
35
  name: TASK_TOOL,
36
36
  description: buildTaskDescription(subagents),
37
- schema: z4.object({
38
- subagent: z4.enum(names).describe("The type of subagent to launch"),
39
- description: z4.string().describe("A short (3-5 word) description of the task"),
40
- prompt: z4.string().describe("The task for the agent to perform")
37
+ schema: z5.object({
38
+ subagent: z5.enum(names).describe("The type of subagent to launch"),
39
+ description: z5.string().describe("A short (3-5 word) description of the task"),
40
+ prompt: z5.string().describe("The task for the agent to perform")
41
41
  })
42
42
  };
43
43
  }
@@ -51,16 +51,21 @@ function createTaskHandler(subagents) {
51
51
  );
52
52
  }
53
53
  const childWorkflowId = `${parentWorkflowId}-${args.subagent}-${uuid4()}`;
54
- const childResult = await executeChild(config.workflowType, {
54
+ const input = {
55
+ prompt: args.prompt,
56
+ ...config.context && { context: config.context }
57
+ };
58
+ const childOpts = {
55
59
  workflowId: childWorkflowId,
56
- args: [{ prompt: args.prompt }],
60
+ args: [input],
57
61
  taskQueue: config.taskQueue ?? parentTaskQueue
58
- });
62
+ };
63
+ const childResult = typeof config.workflow === "string" ? await executeChild(config.workflow, childOpts) : await executeChild(config.workflow, childOpts);
59
64
  const validated = config.resultSchema ? config.resultSchema.parse(childResult) : childResult;
60
- const content = typeof validated === "string" ? validated : JSON.stringify(validated, null, 2);
65
+ const toolResponse = typeof validated === "string" ? validated : JSON.stringify(validated, null, 2);
61
66
  return {
62
- content,
63
- result: {
67
+ toolResponse,
68
+ data: {
64
69
  result: validated,
65
70
  childWorkflowId
66
71
  }
@@ -69,12 +74,28 @@ function createTaskHandler(subagents) {
69
74
  }
70
75
  var createBashToolDescription = ({
71
76
  fileTree
72
- }) => `tool to execute bash commands, the file tree is: ${fileTree}`;
77
+ }) => `Execute shell commands in a bash environment.
78
+
79
+ Use this tool to:
80
+ - Run shell commands (ls, cat, grep, find, etc.)
81
+ - Execute scripts and chain commands with pipes (|) or logical operators (&&, ||)
82
+ - Inspect files and directories
83
+
84
+ Current file tree:
85
+ ${fileTree}`;
73
86
  var bashTool = {
74
87
  name: "Bash",
75
- description: "tool to execute bash commands",
76
- schema: z4.object({
77
- command: z4.string().describe("stringified command to be executed inside the Bash")
88
+ description: `Execute shell commands in a sandboxed bash environment.
89
+
90
+ Use this tool to:
91
+ - Run shell commands (ls, cat, grep, find, etc.)
92
+ - Execute scripts and chain commands with pipes (|) or logical operators (&&, ||)
93
+ - Inspect files and directories
94
+ `,
95
+ schema: z5.object({
96
+ command: z5.string().describe(
97
+ "The bash command to execute. Can include pipes (|), redirects (>, >>), logical operators (&&, ||), and shell features like command substitution $(...)."
98
+ )
78
99
  }),
79
100
  strict: true
80
101
  };
@@ -119,17 +140,17 @@ var taskCreateTool = {
119
140
  - Include enough detail in the description for another agent to understand and complete the task
120
141
  - After creating tasks, use TaskUpdate to set up dependencies (blocks/blockedBy) if needed
121
142
  - Check TaskList first to avoid creating duplicate tasks`,
122
- schema: z4.object({
123
- subject: z4.string().describe(
143
+ schema: z5.object({
144
+ subject: z5.string().describe(
124
145
  'A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")'
125
146
  ),
126
- description: z4.string().describe(
147
+ description: z5.string().describe(
127
148
  "Detailed description of what needs to be done, including context and acceptance criteria"
128
149
  ),
129
- activeForm: z4.string().describe(
150
+ activeForm: z5.string().describe(
130
151
  'Present continuous form shown in spinner when task is in_progress (e.g., "Fixing authentication bug"). This is displayed to the user while you work on the task.'
131
152
  ),
132
- metadata: z4.record(z4.string(), z4.string()).describe("Arbitrary key-value pairs for tracking")
153
+ metadata: z5.record(z5.string(), z5.string()).describe("Arbitrary key-value pairs for tracking")
133
154
  })
134
155
  };
135
156
 
@@ -153,9 +174,30 @@ function createToolRouter(options) {
153
174
  toolMap.set(tool.name, tool);
154
175
  }
155
176
  if (options.subagents) {
177
+ const subagentHooksMap = /* @__PURE__ */ new Map();
178
+ for (const s of options.subagents) {
179
+ if (s.hooks) subagentHooksMap.set(s.name, s.hooks);
180
+ }
181
+ const resolveSubagentName = (args) => args.subagent;
156
182
  toolMap.set("Task", {
157
183
  ...createTaskTool(options.subagents),
158
- handler: createTaskHandler(options.subagents)
184
+ handler: createTaskHandler(options.subagents),
185
+ ...subagentHooksMap.size > 0 && {
186
+ hooks: {
187
+ onPreToolUse: async (ctx) => {
188
+ const hooks = subagentHooksMap.get(resolveSubagentName(ctx.args));
189
+ return hooks?.onPreExecution?.(ctx) ?? {};
190
+ },
191
+ onPostToolUse: async (ctx) => {
192
+ const hooks = subagentHooksMap.get(resolveSubagentName(ctx.args));
193
+ await hooks?.onPostExecution?.(ctx);
194
+ },
195
+ onPostToolUseFailure: async (ctx) => {
196
+ const hooks = subagentHooksMap.get(resolveSubagentName(ctx.args));
197
+ return hooks?.onExecutionFailure?.(ctx) ?? {};
198
+ }
199
+ }
200
+ }
159
201
  });
160
202
  }
161
203
  if (options.buildInTools) {
@@ -178,6 +220,8 @@ function createToolRouter(options) {
178
220
  }
179
221
  async function processToolCall(toolCall, turn, handlerContext) {
180
222
  const startTime = Date.now();
223
+ const tool = toolMap.get(toolCall.name);
224
+ const toolHooks = tool?.hooks;
181
225
  let effectiveArgs = toolCall.args;
182
226
  if (options.hooks?.onPreToolUse) {
183
227
  const preResult = await options.hooks.onPreToolUse({
@@ -200,7 +244,27 @@ function createToolRouter(options) {
200
244
  effectiveArgs = preResult.modifiedArgs;
201
245
  }
202
246
  }
203
- const tool = toolMap.get(toolCall.name);
247
+ if (toolHooks?.onPreToolUse) {
248
+ const preResult = await toolHooks.onPreToolUse({
249
+ args: effectiveArgs,
250
+ threadId: options.threadId,
251
+ turn
252
+ });
253
+ if (preResult?.skip) {
254
+ await appendToolResult({
255
+ threadId: options.threadId,
256
+ toolCallId: toolCall.id,
257
+ content: JSON.stringify({
258
+ skipped: true,
259
+ reason: "Skipped by tool PreToolUse hook"
260
+ })
261
+ });
262
+ return null;
263
+ }
264
+ if (preResult?.modifiedArgs !== void 0) {
265
+ effectiveArgs = preResult.modifiedArgs;
266
+ }
267
+ }
204
268
  let result;
205
269
  let content;
206
270
  try {
@@ -209,30 +273,50 @@ function createToolRouter(options) {
209
273
  effectiveArgs,
210
274
  handlerContext ?? {}
211
275
  );
212
- result = response.result;
213
- content = response.content;
276
+ result = response.data;
277
+ content = response.toolResponse;
214
278
  } else {
215
279
  result = { error: `Unknown tool: ${toolCall.name}` };
216
280
  content = JSON.stringify(result, null, 2);
217
281
  }
218
282
  } catch (error) {
219
- if (options.hooks?.onPostToolUseFailure) {
283
+ const err = error instanceof Error ? error : new Error(String(error));
284
+ let recovered = false;
285
+ if (toolHooks?.onPostToolUseFailure) {
286
+ const failureResult = await toolHooks.onPostToolUseFailure({
287
+ args: effectiveArgs,
288
+ error: err,
289
+ threadId: options.threadId,
290
+ turn
291
+ });
292
+ if (failureResult?.fallbackContent !== void 0) {
293
+ content = failureResult.fallbackContent;
294
+ result = { error: String(error), recovered: true };
295
+ recovered = true;
296
+ } else if (failureResult?.suppress) {
297
+ content = JSON.stringify({ error: String(error), suppressed: true });
298
+ result = { error: String(error), suppressed: true };
299
+ recovered = true;
300
+ }
301
+ }
302
+ if (!recovered && options.hooks?.onPostToolUseFailure) {
220
303
  const failureResult = await options.hooks.onPostToolUseFailure({
221
304
  toolCall,
222
- error: error instanceof Error ? error : new Error(String(error)),
305
+ error: err,
223
306
  threadId: options.threadId,
224
307
  turn
225
308
  });
226
309
  if (failureResult?.fallbackContent !== void 0) {
227
310
  content = failureResult.fallbackContent;
228
311
  result = { error: String(error), recovered: true };
312
+ recovered = true;
229
313
  } else if (failureResult?.suppress) {
230
314
  content = JSON.stringify({ error: String(error), suppressed: true });
231
315
  result = { error: String(error), suppressed: true };
232
- } else {
233
- throw error;
316
+ recovered = true;
234
317
  }
235
- } else {
318
+ }
319
+ if (!recovered) {
236
320
  throw error;
237
321
  }
238
322
  }
@@ -244,10 +328,19 @@ function createToolRouter(options) {
244
328
  const toolResult = {
245
329
  toolCallId: toolCall.id,
246
330
  name: toolCall.name,
247
- result
331
+ data: result
248
332
  };
333
+ const durationMs = Date.now() - startTime;
334
+ if (toolHooks?.onPostToolUse) {
335
+ await toolHooks.onPostToolUse({
336
+ args: effectiveArgs,
337
+ result,
338
+ threadId: options.threadId,
339
+ turn,
340
+ durationMs
341
+ });
342
+ }
249
343
  if (options.hooks?.onPostToolUse) {
250
- const durationMs = Date.now() - startTime;
251
344
  await options.hooks.onPostToolUse({
252
345
  toolCall,
253
346
  result: toolResult,
@@ -328,12 +421,12 @@ function createToolRouter(options) {
328
421
  await appendToolResult({
329
422
  threadId: options.threadId,
330
423
  toolCallId: toolCall.id,
331
- content: response.content
424
+ content: response.toolResponse
332
425
  });
333
426
  return {
334
427
  toolCallId: toolCall.id,
335
428
  name: toolCall.name,
336
- result: response.result
429
+ data: response.data ?? null
337
430
  };
338
431
  };
339
432
  if (options.parallel) {
@@ -359,6 +452,12 @@ function createToolRouter(options) {
359
452
  }
360
453
  };
361
454
  }
455
+ function defineTool(tool) {
456
+ return tool;
457
+ }
458
+ function defineSubagent(config) {
459
+ return config;
460
+ }
362
461
  function hasNoOtherToolCalls(toolCalls, excludeName) {
363
462
  return toolCalls.filter((tc) => tc.name !== excludeName).length === 0;
364
463
  }
@@ -463,17 +562,47 @@ var createSession = async ({
463
562
  return message;
464
563
  }
465
564
  const rawToolCalls = await parseToolCalls(message);
466
- const parsedToolCalls = rawToolCalls.filter((tc) => tc.name !== "Task").map((tc) => toolRouter.parseToolCall(tc));
467
- const taskToolCalls = subagents && subagents.length > 0 ? rawToolCalls.filter((tc) => tc.name === "Task").map((tc) => {
468
- const parsedArgs = createTaskTool(subagents).schema.parse(
469
- tc.args
470
- );
471
- return {
472
- id: tc.id ?? "",
473
- name: tc.name,
474
- args: parsedArgs
475
- };
476
- }) : [];
565
+ const parsedToolCalls = [];
566
+ for (const tc of rawToolCalls.filter(
567
+ (tc2) => tc2.name !== "Task"
568
+ )) {
569
+ try {
570
+ parsedToolCalls.push(toolRouter.parseToolCall(tc));
571
+ } catch (error) {
572
+ await appendToolResult({
573
+ threadId,
574
+ toolCallId: tc.id ?? "",
575
+ content: JSON.stringify({
576
+ error: `Invalid tool call for "${tc.name}": ${error instanceof Error ? error.message : String(error)}`
577
+ })
578
+ });
579
+ }
580
+ }
581
+ const taskToolCalls = [];
582
+ if (subagents && subagents.length > 0) {
583
+ for (const tc of rawToolCalls.filter(
584
+ (tc2) => tc2.name === "Task"
585
+ )) {
586
+ try {
587
+ const parsedArgs = createTaskTool(subagents).schema.parse(
588
+ tc.args
589
+ );
590
+ taskToolCalls.push({
591
+ id: tc.id ?? "",
592
+ name: tc.name,
593
+ args: parsedArgs
594
+ });
595
+ } catch (error) {
596
+ await appendToolResult({
597
+ threadId,
598
+ toolCallId: tc.id ?? "",
599
+ content: JSON.stringify({
600
+ error: `Invalid tool call for "Task": ${error instanceof Error ? error.message : String(error)}`
601
+ })
602
+ });
603
+ }
604
+ }
605
+ }
477
606
  await toolRouter.processToolCalls(
478
607
  [...parsedToolCalls, ...taskToolCalls],
479
608
  {
@@ -503,8 +632,6 @@ var createSession = async ({
503
632
  function isTerminalStatus(status) {
504
633
  return status === "COMPLETED" || status === "FAILED" || status === "CANCELLED";
505
634
  }
506
-
507
- // src/lib/state-manager.ts
508
635
  var getStateQuery = defineQuery("getState");
509
636
  function createAgentStateManager(initialState) {
510
637
  let status = initialState?.status ?? "RUNNING";
@@ -599,7 +726,13 @@ function createAgentStateManager(initialState) {
599
726
  version++;
600
727
  },
601
728
  setTools(newTools) {
602
- tools = newTools;
729
+ tools = newTools.map((tool) => ({
730
+ name: tool.name,
731
+ description: tool.description,
732
+ schema: z.toJSONSchema(tool.schema),
733
+ strict: tool.strict,
734
+ max_uses: tool.max_uses
735
+ }));
603
736
  },
604
737
  deleteTask(id) {
605
738
  const deleted = tasks.delete(id);
@@ -630,18 +763,18 @@ Usage notes:
630
763
  * Use multiSelect: true to allow multiple answers to be selected for a question
631
764
  * If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end of the label
632
765
  `,
633
- schema: z4.object({
634
- questions: z4.array(
635
- z4.object({
636
- question: z4.string().describe("The full question text to display"),
637
- header: z4.string().describe("Short label for the question (max 12 characters)"),
638
- options: z4.array(
639
- z4.object({
640
- label: z4.string(),
641
- description: z4.string()
766
+ schema: z5.object({
767
+ questions: z5.array(
768
+ z5.object({
769
+ question: z5.string().describe("The full question text to display"),
770
+ header: z5.string().describe("Short label for the question (max 12 characters)"),
771
+ options: z5.array(
772
+ z5.object({
773
+ label: z5.string(),
774
+ description: z5.string()
642
775
  })
643
776
  ).min(0).max(4).describe("Array of 0-4 choices, each with label and description"),
644
- multiSelect: z4.boolean().describe("If true, users can select multiple options")
777
+ multiSelect: z5.boolean().describe("If true, users can select multiple options")
645
778
  })
646
779
  )
647
780
  }),
@@ -762,15 +895,10 @@ IMPORTANT:
762
895
  }),
763
896
  strict: true
764
897
  };
765
-
766
- // src/tools/task-create/handler.ts
767
- function createTaskCreateHandler({
768
- stateManager,
769
- idGenerator
770
- }) {
898
+ function createTaskCreateHandler(stateManager) {
771
899
  return (args) => {
772
900
  const task = {
773
- id: idGenerator(),
901
+ id: uuid4(),
774
902
  subject: args.subject,
775
903
  description: args.description,
776
904
  activeForm: args.activeForm,
@@ -781,16 +909,16 @@ function createTaskCreateHandler({
781
909
  };
782
910
  stateManager.setTask(task);
783
911
  return {
784
- content: JSON.stringify(task, null, 2),
785
- result: task
912
+ toolResponse: JSON.stringify(task, null, 2),
913
+ data: task
786
914
  };
787
915
  };
788
916
  }
789
917
  var taskGetTool = {
790
918
  name: "TaskGet",
791
919
  description: `Retrieve full task details including dependencies.`,
792
- schema: z4.object({
793
- taskId: z4.string().describe("The ID of the task to get")
920
+ schema: z5.object({
921
+ taskId: z5.string().describe("The ID of the task to get")
794
922
  })
795
923
  };
796
924
 
@@ -800,20 +928,20 @@ function createTaskGetHandler(stateManager) {
800
928
  const task = stateManager.getTask(args.taskId) ?? null;
801
929
  if (!task) {
802
930
  return {
803
- content: JSON.stringify({ error: `Task not found: ${args.taskId}` }),
804
- result: null
931
+ toolResponse: JSON.stringify({ error: `Task not found: ${args.taskId}` }),
932
+ data: null
805
933
  };
806
934
  }
807
935
  return {
808
- content: JSON.stringify(task, null, 2),
809
- result: task
936
+ toolResponse: JSON.stringify(task, null, 2),
937
+ data: task
810
938
  };
811
939
  };
812
940
  }
813
941
  var taskListTool = {
814
942
  name: "TaskList",
815
943
  description: `List all tasks with current state.`,
816
- schema: z4.object({})
944
+ schema: z5.object({})
817
945
  };
818
946
 
819
947
  // src/tools/task-list/handler.ts
@@ -821,19 +949,19 @@ function createTaskListHandler(stateManager) {
821
949
  return (_args) => {
822
950
  const taskList = stateManager.getTasks();
823
951
  return {
824
- content: JSON.stringify(taskList, null, 2),
825
- result: taskList
952
+ toolResponse: JSON.stringify(taskList, null, 2),
953
+ data: taskList
826
954
  };
827
955
  };
828
956
  }
829
957
  var taskUpdateTool = {
830
958
  name: "TaskUpdate",
831
959
  description: `Update status, add blockers, modify details.`,
832
- schema: z4.object({
833
- taskId: z4.string().describe("The ID of the task to get"),
834
- status: z4.enum(["pending", "in_progress", "completed"]).describe("The status of the task"),
835
- addBlockedBy: z4.array(z4.string()).describe("The IDs of the tasks that are blocking this task"),
836
- addBlocks: z4.array(z4.string()).describe("The IDs of the tasks that this task is blocking")
960
+ schema: z5.object({
961
+ taskId: z5.string().describe("The ID of the task to get"),
962
+ status: z5.enum(["pending", "in_progress", "completed"]).describe("The status of the task"),
963
+ addBlockedBy: z5.array(z5.string()).describe("The IDs of the tasks that are blocking this task"),
964
+ addBlocks: z5.array(z5.string()).describe("The IDs of the tasks that this task is blocking")
837
965
  })
838
966
  };
839
967
 
@@ -843,8 +971,8 @@ function createTaskUpdateHandler(stateManager) {
843
971
  const task = stateManager.getTask(args.taskId);
844
972
  if (!task) {
845
973
  return {
846
- content: JSON.stringify({ error: `Task not found: ${args.taskId}` }),
847
- result: null
974
+ toolResponse: JSON.stringify({ error: `Task not found: ${args.taskId}` }),
975
+ data: null
848
976
  };
849
977
  }
850
978
  if (args.status) {
@@ -876,12 +1004,12 @@ function createTaskUpdateHandler(stateManager) {
876
1004
  }
877
1005
  stateManager.setTask(task);
878
1006
  return {
879
- content: JSON.stringify(task, null, 2),
880
- result: task
1007
+ toolResponse: JSON.stringify(task, null, 2),
1008
+ data: task
881
1009
  };
882
1010
  };
883
1011
  }
884
1012
 
885
- export { AGENT_HANDLER_NAMES, askUserQuestionTool, bashTool, createAgentStateManager, createSession, createTaskCreateHandler, createTaskGetHandler, createTaskListHandler, createTaskTool, createTaskUpdateHandler, createToolRouter, editTool, globTool, grepTool, hasNoOtherToolCalls, isTerminalStatus, readTool, taskCreateTool, taskGetTool, taskListTool, taskUpdateTool, writeTool };
1013
+ export { AGENT_HANDLER_NAMES, askUserQuestionTool, bashTool, createAgentStateManager, createSession, createTaskCreateHandler, createTaskGetHandler, createTaskListHandler, createTaskTool, createTaskUpdateHandler, createToolRouter, defineSubagent, defineTool, editTool, globTool, grepTool, hasNoOtherToolCalls, isTerminalStatus, readTool, taskCreateTool, taskGetTool, taskListTool, taskUpdateTool, writeTool };
886
1014
  //# sourceMappingURL=workflow.js.map
887
1015
  //# sourceMappingURL=workflow.js.map