@polka-codes/core 0.9.79 → 0.9.81

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -127,12 +127,6 @@ function computeRateLimitBackoffSeconds(count, baseSeconds = 2, capSeconds = 60)
127
127
 
128
128
  // src/config.ts
129
129
  import { z } from "zod";
130
- var providerModelSchema = z.object({
131
- provider: z.string().optional(),
132
- model: z.string().optional(),
133
- parameters: z.record(z.string(), z.any()).optional(),
134
- budget: z.number().positive().optional()
135
- });
136
130
  var ruleSchema = z.union([
137
131
  z.string(),
138
132
  z.object({ path: z.string() }).strict(),
@@ -145,6 +139,13 @@ var ruleSchema = z.union([
145
139
  branch: z.string().optional()
146
140
  }).strict()
147
141
  ]);
142
+ var providerModelSchema = z.object({
143
+ provider: z.string().optional(),
144
+ model: z.string().optional(),
145
+ parameters: z.record(z.string(), z.any()).optional(),
146
+ budget: z.number().positive().optional(),
147
+ rules: z.array(ruleSchema).optional().or(z.string()).optional()
148
+ });
148
149
  var configSchema = z.object({
149
150
  prices: z.record(
150
151
  z.string(),
@@ -196,14 +197,6 @@ var configSchema = z.object({
196
197
  excludeFiles: z.array(z.string()).optional()
197
198
  }).strict().nullish();
198
199
 
199
- // src/tool.ts
200
- var ToolResponseType = /* @__PURE__ */ ((ToolResponseType2) => {
201
- ToolResponseType2["Reply"] = "Reply";
202
- ToolResponseType2["Exit"] = "Exit";
203
- ToolResponseType2["Error"] = "Error";
204
- return ToolResponseType2;
205
- })(ToolResponseType || {});
206
-
207
200
  // src/tools/askFollowupQuestion.ts
208
201
  import { z as z2 } from "zod";
209
202
  var questionObject = z2.object({
@@ -263,7 +256,7 @@ var toolInfo = {
263
256
  var handler = async (provider, args) => {
264
257
  if (!provider.askFollowupQuestion) {
265
258
  return {
266
- type: "Error" /* Error */,
259
+ success: false,
267
260
  message: {
268
261
  type: "error-text",
269
262
  value: "Not possible to ask followup question."
@@ -273,7 +266,7 @@ var handler = async (provider, args) => {
273
266
  const { questions } = toolInfo.parameters.parse(args);
274
267
  if (questions.length === 0) {
275
268
  return {
276
- type: "Error" /* Error */,
269
+ success: false,
277
270
  message: {
278
271
  type: "error-text",
279
272
  value: "No questions provided"
@@ -289,7 +282,7 @@ ${answer}
289
282
  </ask_followup_question_answer>`);
290
283
  }
291
284
  return {
292
- type: "Reply" /* Reply */,
285
+ success: true,
293
286
  message: {
294
287
  type: "text",
295
288
  value: answers.join("\n")
@@ -333,7 +326,7 @@ var toolInfo2 = {
333
326
  var handler2 = async (provider, args) => {
334
327
  if (!provider.executeCommand) {
335
328
  return {
336
- type: "Error" /* Error */,
329
+ success: false,
337
330
  message: {
338
331
  type: "error-text",
339
332
  value: "Not possible to execute command. Abort."
@@ -362,7 +355,7 @@ ${result.stderr}
362
355
  }
363
356
  if (result.exitCode === 0) {
364
357
  return {
365
- type: "Reply" /* Reply */,
358
+ success: true,
366
359
  message: {
367
360
  type: "text",
368
361
  value: message
@@ -370,7 +363,7 @@ ${result.stderr}
370
363
  };
371
364
  }
372
365
  return {
373
- type: "Error" /* Error */,
366
+ success: false,
374
367
  message: {
375
368
  type: "error-text",
376
369
  value: message
@@ -378,7 +371,7 @@ ${result.stderr}
378
371
  };
379
372
  } catch (error) {
380
373
  return {
381
- type: "Error" /* Error */,
374
+ success: false,
382
375
  message: {
383
376
  type: "error-text",
384
377
  value: error instanceof Error ? error.message : String(error)
@@ -428,7 +421,7 @@ var toolInfo3 = {
428
421
  var handler3 = async (provider, args) => {
429
422
  if (!provider.fetchUrl) {
430
423
  return {
431
- type: "Error" /* Error */,
424
+ success: false,
432
425
  message: {
433
426
  type: "error-text",
434
427
  value: "Not possible to fetch url."
@@ -438,7 +431,7 @@ var handler3 = async (provider, args) => {
438
431
  const { url: urls } = toolInfo3.parameters.parse(args);
439
432
  if (urls.length === 0) {
440
433
  return {
441
- type: "Error" /* Error */,
434
+ success: false,
442
435
  message: {
443
436
  type: "error-text",
444
437
  value: "No URLs provided. Please provide at least one URL to fetch."
@@ -457,7 +450,7 @@ var handler3 = async (provider, args) => {
457
450
  }
458
451
  const resolvedResults = await Promise.all(results);
459
452
  return {
460
- type: "Reply" /* Reply */,
453
+ success: true,
461
454
  message: {
462
455
  type: "text",
463
456
  value: resolvedResults.join("\n")
@@ -469,64 +462,30 @@ var fetchUrl_default = {
469
462
  handler: handler3
470
463
  };
471
464
 
472
- // src/tools/getTodoItem.ts
465
+ // src/tools/listFiles.ts
473
466
  import { z as z5 } from "zod";
474
467
  var toolInfo4 = {
475
- name: "getTodoItem",
476
- description: "Get a to-do item by its ID.",
477
- parameters: z5.object({
478
- id: z5.string().describe("The ID of the to-do item.")
479
- })
480
- };
481
- var handler4 = async (provider, args) => {
482
- if (!provider.getTodoItem) {
483
- return {
484
- type: "Error" /* Error */,
485
- message: {
486
- type: "error-text",
487
- value: "Not possible to get a to-do item."
488
- }
489
- };
490
- }
491
- const { id } = toolInfo4.parameters.parse(args);
492
- const item = await provider.getTodoItem(id);
493
- return {
494
- type: "Reply" /* Reply */,
495
- message: {
496
- type: "json",
497
- value: item ?? null
498
- }
499
- };
500
- };
501
- var getTodoItem_default = {
502
- ...toolInfo4,
503
- handler: handler4
504
- };
505
-
506
- // src/tools/listFiles.ts
507
- import { z as z6 } from "zod";
508
- var toolInfo5 = {
509
468
  name: "listFiles",
510
469
  description: "Request to list files and directories within the specified directory. If recursive is true, it will list all files and directories recursively. If recursive is false or not provided, it will only list the top-level contents. Do not use this tool to confirm the existence of files you may have created, as the user will let you know if the files were created successfully or not.",
511
- parameters: z6.object({
512
- path: z6.string().describe("The path of the directory to list contents for (relative to the current working directory)").meta({ usageValue: "Directory path here" }),
513
- maxCount: z6.coerce.number().optional().default(2e3).describe("The maximum number of files to list. Default to 2000").meta({ usageValue: "Maximum number of files to list (optional)" }),
514
- recursive: z6.preprocess((val) => {
470
+ parameters: z5.object({
471
+ path: z5.string().describe("The path of the directory to list contents for (relative to the current working directory)").meta({ usageValue: "Directory path here" }),
472
+ maxCount: z5.coerce.number().optional().default(2e3).describe("The maximum number of files to list. Default to 2000").meta({ usageValue: "Maximum number of files to list (optional)" }),
473
+ recursive: z5.preprocess((val) => {
515
474
  if (typeof val === "string") {
516
475
  const lower = val.toLowerCase();
517
476
  if (lower === "false") return false;
518
477
  if (lower === "true") return true;
519
478
  }
520
479
  return val;
521
- }, z6.boolean().optional().default(true)).describe("Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.").meta({ usageValue: "true or false (optional)" }),
522
- includeIgnored: z6.preprocess((val) => {
480
+ }, z5.boolean().optional().default(true)).describe("Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.").meta({ usageValue: "true or false (optional)" }),
481
+ includeIgnored: z5.preprocess((val) => {
523
482
  if (typeof val === "string") {
524
483
  const lower = val.toLowerCase();
525
484
  if (lower === "false") return false;
526
485
  if (lower === "true") return true;
527
486
  }
528
487
  return val;
529
- }, z6.boolean().optional().default(false)).describe("Whether to include ignored files. Use true to include files ignored by .gitignore.").meta({ usageValue: "true or false (optional)" })
488
+ }, z5.boolean().optional().default(false)).describe("Whether to include ignored files. Use true to include files ignored by .gitignore.").meta({ usageValue: "true or false (optional)" })
530
489
  }).meta({
531
490
  examples: [
532
491
  {
@@ -539,20 +498,20 @@ var toolInfo5 = {
539
498
  ]
540
499
  })
541
500
  };
542
- var handler5 = async (provider, args) => {
501
+ var handler4 = async (provider, args) => {
543
502
  if (!provider.listFiles) {
544
503
  return {
545
- type: "Error" /* Error */,
504
+ success: false,
546
505
  message: {
547
506
  type: "error-text",
548
507
  value: "Not possible to list files."
549
508
  }
550
509
  };
551
510
  }
552
- const { path, maxCount, recursive, includeIgnored } = toolInfo5.parameters.parse(args);
511
+ const { path, maxCount, recursive, includeIgnored } = toolInfo4.parameters.parse(args);
553
512
  const [files, limitReached] = await provider.listFiles(path, recursive, maxCount, includeIgnored);
554
513
  return {
555
- type: "Reply" /* Reply */,
514
+ success: true,
556
515
  message: {
557
516
  type: "text",
558
517
  value: `<list_files_path>${path}</list_files_path>
@@ -564,110 +523,8 @@ ${files.join("\n")}
564
523
  };
565
524
  };
566
525
  var listFiles_default = {
567
- ...toolInfo5,
568
- handler: handler5
569
- };
570
-
571
- // src/tools/listMemoryTopics.ts
572
- import { z as z7 } from "zod";
573
- var toolInfo6 = {
574
- name: "listMemoryTopics",
575
- description: "Lists all topics in memory. Use this to see what information has been stored and which topics are available to read from.",
576
- parameters: z7.object({})
577
- };
578
- var handler6 = async (provider, _args) => {
579
- const topics = await provider.listMemoryTopics();
580
- if (!topics.length) {
581
- return { type: "Reply" /* Reply */, message: { type: "text", value: "No topics found." } };
582
- }
583
- return {
584
- type: "Reply" /* Reply */,
585
- message: {
586
- type: "text",
587
- value: `Memory topics:
588
- ${topics.join("\n")}`
589
- }
590
- };
591
- };
592
- var listMemoryTopics_default = {
593
- ...toolInfo6,
594
- handler: handler6
595
- };
596
-
597
- // src/tools/listTodoItems.ts
598
- import { z as z9 } from "zod";
599
-
600
- // src/tools/todo.ts
601
- import { z as z8 } from "zod";
602
- var TodoStatus = z8.enum(["open", "completed", "closed"]);
603
- var TodoItemSchema = z8.object({
604
- id: z8.string(),
605
- title: z8.string(),
606
- description: z8.string(),
607
- status: TodoStatus
608
- });
609
- var UpdateTodoItemInputSchema = z8.object({
610
- operation: z8.enum(["add", "update"]),
611
- id: z8.string().nullish(),
612
- parentId: z8.string().nullish(),
613
- title: z8.string().nullish(),
614
- description: z8.string().nullish(),
615
- status: TodoStatus.nullish()
616
- }).superRefine((data, ctx) => {
617
- if (data.operation === "add") {
618
- if (!data.title) {
619
- ctx.addIssue({
620
- code: "custom",
621
- message: 'Title is required for "add" operation',
622
- path: ["title"]
623
- });
624
- }
625
- } else if (data.operation === "update") {
626
- if (!data.id) {
627
- ctx.addIssue({
628
- code: "custom",
629
- message: 'ID is required for "update" operation',
630
- path: ["id"]
631
- });
632
- }
633
- }
634
- });
635
- var UpdateTodoItemOutputSchema = z8.object({
636
- id: z8.string()
637
- });
638
-
639
- // src/tools/listTodoItems.ts
640
- var toolInfo7 = {
641
- name: "listTodoItems",
642
- description: "List all to-do items, sorted by id. If an id is provided, it lists all sub-items for that id. Can be filtered by status.",
643
- parameters: z9.object({
644
- id: z9.string().nullish(),
645
- status: TodoStatus.nullish()
646
- })
647
- };
648
- var handler7 = async (provider, args) => {
649
- if (!provider.listTodoItems) {
650
- return {
651
- type: "Error" /* Error */,
652
- message: {
653
- type: "error-text",
654
- value: "Not possible to list to-do items."
655
- }
656
- };
657
- }
658
- const { id, status } = toolInfo7.parameters.parse(args);
659
- const items = await provider.listTodoItems(id, status);
660
- return {
661
- type: "Reply" /* Reply */,
662
- message: {
663
- type: "json",
664
- value: items
665
- }
666
- };
667
- };
668
- var listTodoItems_default = {
669
- ...toolInfo7,
670
- handler: handler7
526
+ ...toolInfo4,
527
+ handler: handler4
671
528
  };
672
529
 
673
530
  // src/tools/provider.ts
@@ -732,29 +589,29 @@ var MockProvider = class {
732
589
  };
733
590
 
734
591
  // src/tools/readBinaryFile.ts
735
- import { z as z10 } from "zod";
736
- var toolInfo8 = {
592
+ import { z as z6 } from "zod";
593
+ var toolInfo5 = {
737
594
  name: "readBinaryFile",
738
595
  description: "Read a binary file from a URL or local path. Use file:// prefix to access local files. This can be used to access non-text files such as PDFs or images.",
739
- parameters: z10.object({
740
- url: z10.string().describe("The URL or local path of the file to read.")
596
+ parameters: z6.object({
597
+ url: z6.string().describe("The URL or local path of the file to read.")
741
598
  })
742
599
  };
743
- var handler8 = async (provider, args) => {
600
+ var handler5 = async (provider, args) => {
744
601
  if (!provider.readBinaryFile) {
745
602
  return {
746
- type: "Error" /* Error */,
603
+ success: false,
747
604
  message: {
748
605
  type: "error-text",
749
606
  value: "Not possible to fetch files. Abort."
750
607
  }
751
608
  };
752
609
  }
753
- const { url } = toolInfo8.parameters.parse(args);
610
+ const { url } = toolInfo5.parameters.parse(args);
754
611
  try {
755
612
  const filePart = await provider.readBinaryFile(url);
756
613
  return {
757
- type: "Reply" /* Reply */,
614
+ success: true,
758
615
  message: {
759
616
  type: "content",
760
617
  value: [
@@ -770,7 +627,7 @@ var handler8 = async (provider, args) => {
770
627
  } catch (error) {
771
628
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
772
629
  return {
773
- type: "Error" /* Error */,
630
+ success: false,
774
631
  message: {
775
632
  type: "error-text",
776
633
  value: `Error fetching file from ${url}: ${errorMessage}`
@@ -779,29 +636,29 @@ var handler8 = async (provider, args) => {
779
636
  }
780
637
  };
781
638
  var readBinaryFile_default = {
782
- ...toolInfo8,
783
- handler: handler8
639
+ ...toolInfo5,
640
+ handler: handler5
784
641
  };
785
642
 
786
643
  // src/tools/readFile.ts
787
- import { z as z11 } from "zod";
788
- var toolInfo9 = {
644
+ import { z as z7 } from "zod";
645
+ var toolInfo6 = {
789
646
  name: "readFile",
790
647
  description: "Request to read the contents of one or multiple files at the specified paths. Use comma separated paths to read multiple files. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. May not be suitable for other types of binary files, as it returns the raw content as a string. Try to list all the potential files are relevent to the task, and then use this tool to read all the relevant files.",
791
- parameters: z11.object({
792
- path: z11.preprocess((val) => {
648
+ parameters: z7.object({
649
+ path: z7.preprocess((val) => {
793
650
  if (!val) return [];
794
651
  const values = Array.isArray(val) ? val : [val];
795
652
  return values.flatMap((i) => typeof i === "string" ? i.split(",") : []).filter((s) => s.length > 0);
796
- }, z11.array(z11.string())).describe("The path of the file to read").meta({ usageValue: "Comma separated paths here" }),
797
- includeIgnored: z11.preprocess((val) => {
653
+ }, z7.array(z7.string())).describe("The path of the file to read").meta({ usageValue: "Comma separated paths here" }),
654
+ includeIgnored: z7.preprocess((val) => {
798
655
  if (typeof val === "string") {
799
656
  const lower = val.toLowerCase();
800
657
  if (lower === "false") return false;
801
658
  if (lower === "true") return true;
802
659
  }
803
660
  return val;
804
- }, z11.boolean().nullish().default(false)).describe("Whether to include ignored files. Use true to include files ignored by .gitignore.").meta({ usageValue: "true or false (optional)" })
661
+ }, z7.boolean().nullish().default(false)).describe("Whether to include ignored files. Use true to include files ignored by .gitignore.").meta({ usageValue: "true or false (optional)" })
805
662
  }).meta({
806
663
  examples: [
807
664
  {
@@ -819,17 +676,17 @@ var toolInfo9 = {
819
676
  ]
820
677
  })
821
678
  };
822
- var handler9 = async (provider, args) => {
679
+ var handler6 = async (provider, args) => {
823
680
  if (!provider.readFile) {
824
681
  return {
825
- type: "Error" /* Error */,
682
+ success: false,
826
683
  message: {
827
684
  type: "error-text",
828
685
  value: "Not possible to read file."
829
686
  }
830
687
  };
831
688
  }
832
- const { path: paths, includeIgnored } = toolInfo9.parameters.parse(args);
689
+ const { path: paths, includeIgnored } = toolInfo6.parameters.parse(args);
833
690
  const resp = [];
834
691
  for (const path of paths) {
835
692
  const fileContent = await provider.readFile(path, includeIgnored ?? false);
@@ -845,7 +702,7 @@ var handler9 = async (provider, args) => {
845
702
  }
846
703
  }
847
704
  return {
848
- type: "Reply" /* Reply */,
705
+ success: true,
849
706
  message: {
850
707
  type: "text",
851
708
  value: resp.join("\n")
@@ -853,53 +710,17 @@ var handler9 = async (provider, args) => {
853
710
  };
854
711
  };
855
712
  var readFile_default = {
856
- ...toolInfo9,
857
- handler: handler9
858
- };
859
-
860
- // src/tools/readMemory.ts
861
- import { z as z12 } from "zod";
862
- var toolInfo10 = {
863
- name: "readMemory",
864
- description: "Reads content from a memory topic. Use this to retrieve information stored in previous steps. If no topic is specified, reads from the default topic.",
865
- parameters: z12.object({
866
- topic: z12.string().nullish().describe('The topic to read from memory. Defaults to ":default:".')
867
- })
868
- };
869
- var handler10 = async (provider, args) => {
870
- const { topic } = toolInfo10.parameters.parse(args);
871
- const content = await provider.readMemory(topic ?? void 0);
872
- if (content) {
873
- return {
874
- type: "Reply" /* Reply */,
875
- message: {
876
- type: "text",
877
- value: `<memory${topic ? ` topic="${topic}"` : ""}>
878
- ${content}
879
- </memory>`
880
- }
881
- };
882
- }
883
- return {
884
- type: "Reply" /* Reply */,
885
- message: {
886
- type: "text",
887
- value: `<memory ${topic ? `topic="${topic}"` : ""} isEmpty="true" />`
888
- }
889
- };
890
- };
891
- var readMemory_default = {
892
- ...toolInfo10,
893
- handler: handler10
713
+ ...toolInfo6,
714
+ handler: handler6
894
715
  };
895
716
 
896
717
  // src/tools/removeFile.ts
897
- import { z as z13 } from "zod";
898
- var toolInfo11 = {
718
+ import { z as z8 } from "zod";
719
+ var toolInfo7 = {
899
720
  name: "removeFile",
900
721
  description: "Request to remove a file at the specified path.",
901
- parameters: z13.object({
902
- path: z13.string().describe("The path of the file to remove").meta({ usageValue: "File path here" })
722
+ parameters: z8.object({
723
+ path: z8.string().describe("The path of the file to remove").meta({ usageValue: "File path here" })
903
724
  }).meta({
904
725
  examples: [
905
726
  {
@@ -911,20 +732,20 @@ var toolInfo11 = {
911
732
  ]
912
733
  })
913
734
  };
914
- var handler11 = async (provider, args) => {
735
+ var handler7 = async (provider, args) => {
915
736
  if (!provider.removeFile) {
916
737
  return {
917
- type: "Error" /* Error */,
738
+ success: false,
918
739
  message: {
919
740
  type: "error-text",
920
741
  value: "Not possible to remove file."
921
742
  }
922
743
  };
923
744
  }
924
- const parsed = toolInfo11.parameters.safeParse(args);
745
+ const parsed = toolInfo7.parameters.safeParse(args);
925
746
  if (!parsed.success) {
926
747
  return {
927
- type: "Error" /* Error */,
748
+ success: false,
928
749
  message: {
929
750
  type: "error-text",
930
751
  value: `Invalid arguments for removeFile: ${parsed.error.message}`
@@ -934,7 +755,7 @@ var handler11 = async (provider, args) => {
934
755
  const { path } = parsed.data;
935
756
  await provider.removeFile(path);
936
757
  return {
937
- type: "Reply" /* Reply */,
758
+ success: true,
938
759
  message: {
939
760
  type: "text",
940
761
  value: `<remove_file_path>${path}</remove_file_path><status>Success</status>`
@@ -942,18 +763,18 @@ var handler11 = async (provider, args) => {
942
763
  };
943
764
  };
944
765
  var removeFile_default = {
945
- ...toolInfo11,
946
- handler: handler11
766
+ ...toolInfo7,
767
+ handler: handler7
947
768
  };
948
769
 
949
770
  // src/tools/renameFile.ts
950
- import { z as z14 } from "zod";
951
- var toolInfo12 = {
771
+ import { z as z9 } from "zod";
772
+ var toolInfo8 = {
952
773
  name: "renameFile",
953
774
  description: "Request to rename a file from source path to target path.",
954
- parameters: z14.object({
955
- source_path: z14.string().describe("The current path of the file").meta({ usageValue: "Source file path here" }),
956
- target_path: z14.string().describe("The new path for the file").meta({ usageValue: "Target file path here" })
775
+ parameters: z9.object({
776
+ source_path: z9.string().describe("The current path of the file").meta({ usageValue: "Source file path here" }),
777
+ target_path: z9.string().describe("The new path for the file").meta({ usageValue: "Target file path here" })
957
778
  }).meta({
958
779
  examples: [
959
780
  {
@@ -966,20 +787,20 @@ var toolInfo12 = {
966
787
  ]
967
788
  })
968
789
  };
969
- var handler12 = async (provider, args) => {
790
+ var handler8 = async (provider, args) => {
970
791
  if (!provider.renameFile) {
971
792
  return {
972
- type: "Error" /* Error */,
793
+ success: false,
973
794
  message: {
974
795
  type: "error-text",
975
796
  value: "Not possible to rename file."
976
797
  }
977
798
  };
978
799
  }
979
- const { source_path, target_path } = toolInfo12.parameters.parse(args);
800
+ const { source_path, target_path } = toolInfo8.parameters.parse(args);
980
801
  await provider.renameFile(source_path, target_path);
981
802
  return {
982
- type: "Reply" /* Reply */,
803
+ success: true,
983
804
  message: {
984
805
  type: "text",
985
806
  value: `<rename_file_path>${target_path}</rename_file_path><status>Success</status>`
@@ -987,12 +808,12 @@ var handler12 = async (provider, args) => {
987
808
  };
988
809
  };
989
810
  var renameFile_default = {
990
- ...toolInfo12,
991
- handler: handler12
811
+ ...toolInfo8,
812
+ handler: handler8
992
813
  };
993
814
 
994
815
  // src/tools/replaceInFile.ts
995
- import { z as z15 } from "zod";
816
+ import { z as z10 } from "zod";
996
817
 
997
818
  // src/tools/utils/replaceInFile.ts
998
819
  var replaceInFile = (fileContent, diff) => {
@@ -1069,12 +890,12 @@ var replaceInFile = (fileContent, diff) => {
1069
890
  };
1070
891
 
1071
892
  // src/tools/replaceInFile.ts
1072
- var toolInfo13 = {
893
+ var toolInfo9 = {
1073
894
  name: "replaceInFile",
1074
895
  description: "Request to replace sections of content in an existing file using SEARCH/REPLACE blocks that define exact changes to specific parts of the file. This tool should be used when you need to make targeted changes to specific parts of a file.",
1075
- parameters: z15.object({
1076
- path: z15.string().describe("The path of the file to modify").meta({ usageValue: "File path here" }),
1077
- diff: z15.string().describe(
896
+ parameters: z10.object({
897
+ path: z10.string().describe("The path of the file to modify").meta({ usageValue: "File path here" }),
898
+ diff: z10.string().describe(
1078
899
  `One or more SEARCH/REPLACE blocks following this exact format:
1079
900
  \`\`\`
1080
901
  <<<<<<< SEARCH
@@ -1181,20 +1002,20 @@ function oldFeature() {
1181
1002
  ]
1182
1003
  })
1183
1004
  };
1184
- var handler13 = async (provider, args) => {
1005
+ var handler9 = async (provider, args) => {
1185
1006
  if (!provider.readFile || !provider.writeFile) {
1186
1007
  return {
1187
- type: "Error" /* Error */,
1008
+ success: false,
1188
1009
  message: {
1189
1010
  type: "error-text",
1190
1011
  value: "Not possible to replace in file."
1191
1012
  }
1192
1013
  };
1193
1014
  }
1194
- const parsed = toolInfo13.parameters.safeParse(args);
1015
+ const parsed = toolInfo9.parameters.safeParse(args);
1195
1016
  if (!parsed.success) {
1196
1017
  return {
1197
- type: "Error" /* Error */,
1018
+ success: false,
1198
1019
  message: {
1199
1020
  type: "error-text",
1200
1021
  value: `Invalid arguments for replaceInFile: ${parsed.error.message}`
@@ -1206,7 +1027,7 @@ var handler13 = async (provider, args) => {
1206
1027
  const fileContent = await provider.readFile(path, false);
1207
1028
  if (fileContent == null) {
1208
1029
  return {
1209
- type: "Error" /* Error */,
1030
+ success: false,
1210
1031
  message: {
1211
1032
  type: "error-text",
1212
1033
  value: `<replace_in_file_result path="${path}" status="failed" message="File not found" />`
@@ -1216,7 +1037,7 @@ var handler13 = async (provider, args) => {
1216
1037
  const result = replaceInFile(fileContent, diff);
1217
1038
  if (result.status === "no_diff_applied") {
1218
1039
  return {
1219
- type: "Error" /* Error */,
1040
+ success: false,
1220
1041
  message: {
1221
1042
  type: "error-text",
1222
1043
  value: `<replace_in_file_result path="${path}" status="failed" message="Unable to apply changes">
@@ -1228,7 +1049,7 @@ var handler13 = async (provider, args) => {
1228
1049
  await provider.writeFile(path, result.content);
1229
1050
  if (result.status === "some_diff_applied") {
1230
1051
  return {
1231
- type: "Reply" /* Reply */,
1052
+ success: true,
1232
1053
  message: {
1233
1054
  type: "text",
1234
1055
  value: `<replace_in_file_result path="${path}" status="some_diff_applied" applied_count="${result.appliedCount}" total_count="${result.totalCount}">
@@ -1238,7 +1059,7 @@ var handler13 = async (provider, args) => {
1238
1059
  };
1239
1060
  }
1240
1061
  return {
1241
- type: "Reply" /* Reply */,
1062
+ success: true,
1242
1063
  message: {
1243
1064
  type: "text",
1244
1065
  value: `<replace_in_file_result path="${path}" status="all_diff_applied" />`
@@ -1246,7 +1067,7 @@ var handler13 = async (provider, args) => {
1246
1067
  };
1247
1068
  } catch (error) {
1248
1069
  return {
1249
- type: "Error" /* Error */,
1070
+ success: false,
1250
1071
  message: {
1251
1072
  type: "error-text",
1252
1073
  value: `Invalid arguments for replaceInFile: ${error}`
@@ -1255,17 +1076,17 @@ var handler13 = async (provider, args) => {
1255
1076
  }
1256
1077
  };
1257
1078
  var replaceInFile_default = {
1258
- ...toolInfo13,
1259
- handler: handler13
1079
+ ...toolInfo9,
1080
+ handler: handler9
1260
1081
  };
1261
1082
 
1262
1083
  // src/tools/search.ts
1263
- import { z as z16 } from "zod";
1264
- var toolInfo14 = {
1084
+ import { z as z11 } from "zod";
1085
+ var toolInfo10 = {
1265
1086
  name: "search",
1266
1087
  description: "Search the web for information using Google Search. Use this tool to find current information, facts, news, documentation, or research that is not available in your training data. Returns comprehensive search results with relevant content extracted from the web.",
1267
- parameters: z16.object({
1268
- query: z16.string().describe("The query to search for").meta({ usageValue: "Your search query here" })
1088
+ parameters: z11.object({
1089
+ query: z11.string().describe("The query to search for").meta({ usageValue: "Your search query here" })
1269
1090
  }).meta({
1270
1091
  examples: [
1271
1092
  {
@@ -1289,11 +1110,11 @@ var toolInfo14 = {
1289
1110
  ]
1290
1111
  })
1291
1112
  };
1292
- var handler14 = async (provider, args) => {
1293
- const { query } = toolInfo14.parameters.parse(args);
1113
+ var handler10 = async (provider, args) => {
1114
+ const { query } = toolInfo10.parameters.parse(args);
1294
1115
  if (!provider.search) {
1295
1116
  return {
1296
- type: "Error" /* Error */,
1117
+ success: false,
1297
1118
  message: {
1298
1119
  type: "text",
1299
1120
  value: "This tool requires a web provider to be installed."
@@ -1302,7 +1123,7 @@ var handler14 = async (provider, args) => {
1302
1123
  }
1303
1124
  const result = await provider.search(query);
1304
1125
  return {
1305
- type: "Reply" /* Reply */,
1126
+ success: true,
1306
1127
  message: {
1307
1128
  type: "text",
1308
1129
  value: result
@@ -1310,23 +1131,23 @@ var handler14 = async (provider, args) => {
1310
1131
  };
1311
1132
  };
1312
1133
  var search_default = {
1313
- ...toolInfo14,
1314
- handler: handler14
1134
+ ...toolInfo10,
1135
+ handler: handler10
1315
1136
  };
1316
1137
 
1317
1138
  // src/tools/searchFiles.ts
1318
- import { z as z17 } from "zod";
1319
- var toolInfo15 = {
1139
+ import { z as z12 } from "zod";
1140
+ var toolInfo11 = {
1320
1141
  name: "searchFiles",
1321
1142
  description: "Request to perform a regex search across files in a specified directory, outputting context-rich results that include surrounding lines. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context.",
1322
- parameters: z17.object({
1323
- path: z17.string().describe(
1143
+ parameters: z12.object({
1144
+ path: z12.string().describe(
1324
1145
  "The path of the directory to search in (relative to the current working directory). This directory will be recursively searched."
1325
1146
  ).meta({ usageValue: "Directory path here" }),
1326
- regex: z17.string().describe("The regular expression pattern to search for. Uses Rust regex syntax.").meta({
1147
+ regex: z12.string().describe("The regular expression pattern to search for. Uses Rust regex syntax.").meta({
1327
1148
  usageValue: "Your regex pattern here"
1328
1149
  }),
1329
- filePattern: z17.string().optional().describe(
1150
+ filePattern: z12.string().optional().describe(
1330
1151
  'Comma-separated glob pattern to filter files (e.g., "*.ts" for TypeScript files or "*.ts,*.js" for both TypeScript and JavaScript files). If not provided, it will search all files (*).'
1331
1152
  ).meta({
1332
1153
  usageValue: "file pattern here (optional)"
@@ -1344,20 +1165,20 @@ var toolInfo15 = {
1344
1165
  ]
1345
1166
  })
1346
1167
  };
1347
- var handler15 = async (provider, args) => {
1168
+ var handler11 = async (provider, args) => {
1348
1169
  if (!provider.searchFiles) {
1349
1170
  return {
1350
- type: "Error" /* Error */,
1171
+ success: false,
1351
1172
  message: {
1352
1173
  type: "error-text",
1353
1174
  value: "Not possible to search files."
1354
1175
  }
1355
1176
  };
1356
1177
  }
1357
- const parsed = toolInfo15.parameters.safeParse(args);
1178
+ const parsed = toolInfo11.parameters.safeParse(args);
1358
1179
  if (!parsed.success) {
1359
1180
  return {
1360
- type: "Error" /* Error */,
1181
+ success: false,
1361
1182
  message: {
1362
1183
  type: "error-text",
1363
1184
  value: `Invalid arguments for searchFiles: ${parsed.error.message}`
@@ -1368,7 +1189,7 @@ var handler15 = async (provider, args) => {
1368
1189
  try {
1369
1190
  const files = await provider.searchFiles(path, regex, filePattern ?? "*");
1370
1191
  return {
1371
- type: "Reply" /* Reply */,
1192
+ success: true,
1372
1193
  message: {
1373
1194
  type: "text",
1374
1195
  value: `<search_files_path>${path}</search_files_path>
@@ -1382,7 +1203,7 @@ ${files.join("\n")}
1382
1203
  };
1383
1204
  } catch (error) {
1384
1205
  return {
1385
- type: "Error" /* Error */,
1206
+ success: false,
1386
1207
  message: {
1387
1208
  type: "error-text",
1388
1209
  value: `Error searching files: ${error}`
@@ -1391,122 +1212,57 @@ ${files.join("\n")}
1391
1212
  }
1392
1213
  };
1393
1214
  var searchFiles_default = {
1394
- ...toolInfo15,
1395
- handler: handler15
1215
+ ...toolInfo11,
1216
+ handler: handler11
1396
1217
  };
1397
1218
 
1398
- // src/tools/updateMemory.ts
1399
- import { z as z18 } from "zod";
1400
- var toolInfo16 = {
1401
- name: "updateMemory",
1402
- description: 'Appends, replaces, or removes content from a memory topic. Use "append" to add to existing content, "replace" to overwrite entirely, or "remove" to delete a topic. Memory persists across tool calls within a workflow.',
1403
- parameters: z18.object({
1404
- operation: z18.enum(["append", "replace", "remove"]).describe("The operation to perform."),
1405
- topic: z18.string().nullish().describe('The topic to update in memory. Defaults to ":default:".'),
1406
- content: z18.string().nullish().describe("The content for append or replace operations. Must be omitted for remove operation.")
1407
- }).superRefine((data, ctx) => {
1408
- if (data.operation === "append" || data.operation === "replace") {
1409
- if (data.content === void 0) {
1410
- ctx.addIssue({
1411
- code: "custom",
1412
- message: 'Content is required for "append" and "replace" operations.',
1413
- path: ["content"]
1414
- });
1415
- }
1416
- } else if (data.operation === "remove") {
1417
- if (data.content !== void 0) {
1418
- ctx.addIssue({
1419
- code: "custom",
1420
- message: 'Content must not be provided for "remove" operation.',
1421
- path: ["content"]
1422
- });
1423
- }
1219
+ // src/tools/todo.ts
1220
+ import { z as z13 } from "zod";
1221
+ var TodoStatus = z13.enum(["open", "completed", "closed"]);
1222
+ var TodoItemSchema = z13.object({
1223
+ id: z13.string(),
1224
+ title: z13.string(),
1225
+ description: z13.string(),
1226
+ status: TodoStatus
1227
+ });
1228
+ var UpdateTodoItemInputSchema = z13.object({
1229
+ operation: z13.enum(["add", "update"]),
1230
+ id: z13.string().nullish(),
1231
+ parentId: z13.string().nullish(),
1232
+ title: z13.string().nullish(),
1233
+ description: z13.string().nullish(),
1234
+ status: TodoStatus.nullish()
1235
+ }).superRefine((data, ctx) => {
1236
+ if (data.operation === "add") {
1237
+ if (!data.title) {
1238
+ ctx.addIssue({
1239
+ code: "custom",
1240
+ message: 'Title is required for "add" operation',
1241
+ path: ["title"]
1242
+ });
1424
1243
  }
1425
- })
1426
- };
1427
- var handler16 = async (provider, args) => {
1428
- if (!provider.updateMemory) {
1429
- return {
1430
- type: "Error" /* Error */,
1431
- message: {
1432
- type: "error-text",
1433
- value: "Memory operations are not supported by the current provider."
1434
- }
1435
- };
1436
- }
1437
- const params = toolInfo16.parameters.parse(args);
1438
- await provider.updateMemory(params.operation, params.topic ?? void 0, params.content ?? void 0);
1439
- switch (params.operation) {
1440
- case "append":
1441
- return {
1442
- type: "Reply" /* Reply */,
1443
- message: {
1444
- type: "text",
1445
- value: `Content appended to memory topic '${params.topic || ":default:"}'.`
1446
- }
1447
- };
1448
- case "replace":
1449
- return {
1450
- type: "Reply" /* Reply */,
1451
- message: {
1452
- type: "text",
1453
- value: `Memory topic '${params.topic || ":default:"}' replaced.`
1454
- }
1455
- };
1456
- case "remove":
1457
- return {
1458
- type: "Reply" /* Reply */,
1459
- message: {
1460
- type: "text",
1461
- value: `Memory topic '${params.topic || ":default:"}' removed.`
1462
- }
1463
- };
1464
- }
1465
- };
1466
- var updateMemory_default = {
1467
- ...toolInfo16,
1468
- handler: handler16
1469
- };
1470
-
1471
- // src/tools/updateTodoItem.ts
1472
- var toolInfo17 = {
1473
- name: "updateTodoItem",
1474
- description: "Add or update a to-do item.",
1475
- parameters: UpdateTodoItemInputSchema
1476
- };
1477
- var handler17 = async (provider, args) => {
1478
- if (!provider.updateTodoItem) {
1479
- return {
1480
- type: "Error" /* Error */,
1481
- message: {
1482
- type: "error-text",
1483
- value: "Not possible to update a to-do item."
1484
- }
1485
- };
1486
- }
1487
- const input = toolInfo17.parameters.parse(args);
1488
- const result = await provider.updateTodoItem(input);
1489
- return {
1490
- type: "Reply" /* Reply */,
1491
- message: {
1492
- type: "json",
1493
- value: result
1244
+ } else if (data.operation === "update") {
1245
+ if (!data.id) {
1246
+ ctx.addIssue({
1247
+ code: "custom",
1248
+ message: 'ID is required for "update" operation',
1249
+ path: ["id"]
1250
+ });
1494
1251
  }
1495
- };
1496
- };
1497
- var updateTodoItem_default = {
1498
- ...toolInfo17,
1499
- handler: handler17
1500
- };
1252
+ }
1253
+ });
1254
+ var UpdateTodoItemOutputSchema = z13.object({
1255
+ id: z13.string()
1256
+ });
1501
1257
 
1502
1258
  // src/tools/writeToFile.ts
1503
- import { z as z19 } from "zod";
1504
- var toolInfo18 = {
1259
+ import { z as z14 } from "zod";
1260
+ var toolInfo12 = {
1505
1261
  name: "writeToFile",
1506
1262
  description: "Request to write content to a file at the specified path. If the file exists, it will be overwritten with the provided content. If the file doesn't exist, it will be created. This tool will automatically create any directories needed to write the file. Ensure that the output content does not include incorrect escaped character patterns such as `&lt;`, `&gt;`, or `&amp;`. Also ensure there is no unwanted CDATA tags in the content.",
1507
- parameters: z19.object({
1508
- path: z19.string().describe("The path of the file to write to").meta({ usageValue: "File path here" }),
1509
- content: z19.string().describe(
1263
+ parameters: z14.object({
1264
+ path: z14.string().describe("The path of the file to write to").meta({ usageValue: "File path here" }),
1265
+ content: z14.string().describe(
1510
1266
  "The content to write to the file. ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified."
1511
1267
  ).meta({ usageValue: "Your file content here" })
1512
1268
  }).meta({
@@ -1532,20 +1288,20 @@ export default App;
1532
1288
  ]
1533
1289
  })
1534
1290
  };
1535
- var handler18 = async (provider, args) => {
1291
+ var handler12 = async (provider, args) => {
1536
1292
  if (!provider.writeFile) {
1537
1293
  return {
1538
- type: "Error" /* Error */,
1294
+ success: false,
1539
1295
  message: {
1540
1296
  type: "error-text",
1541
1297
  value: "Not possible to write file."
1542
1298
  }
1543
1299
  };
1544
1300
  }
1545
- const parsed = toolInfo18.parameters.safeParse(args);
1301
+ const parsed = toolInfo12.parameters.safeParse(args);
1546
1302
  if (!parsed.success) {
1547
1303
  return {
1548
- type: "Error" /* Error */,
1304
+ success: false,
1549
1305
  message: {
1550
1306
  type: "error-text",
1551
1307
  value: `Invalid arguments for writeToFile: ${parsed.error.message}`
@@ -1557,7 +1313,7 @@ var handler18 = async (provider, args) => {
1557
1313
  if (trimmedContent.startsWith("<![CDATA[") && content.endsWith("]]>")) content = trimmedContent.slice(9, -3);
1558
1314
  await provider.writeFile(path, content);
1559
1315
  return {
1560
- type: "Reply" /* Reply */,
1316
+ success: true,
1561
1317
  message: {
1562
1318
  type: "text",
1563
1319
  value: `<write_to_file_path>${path}</write_to_file_path><status>Success</status>`
@@ -1565,8 +1321,8 @@ var handler18 = async (provider, args) => {
1565
1321
  };
1566
1322
  };
1567
1323
  var writeToFile_default = {
1568
- ...toolInfo18,
1569
- handler: handler18
1324
+ ...toolInfo12,
1325
+ handler: handler12
1570
1326
  };
1571
1327
 
1572
1328
  // src/UsageMeter.ts
@@ -1719,7 +1475,7 @@ var UsageMeter = class {
1719
1475
 
1720
1476
  // src/workflow/agent.workflow.ts
1721
1477
  import { jsonSchema } from "ai";
1722
- import { toJSONSchema, z as z20 } from "zod";
1478
+ import { toJSONSchema, z as z15 } from "zod";
1723
1479
 
1724
1480
  // src/workflow/types.ts
1725
1481
  var TaskEventKind = /* @__PURE__ */ ((TaskEventKind2) => {
@@ -1739,11 +1495,11 @@ var TaskEventKind = /* @__PURE__ */ ((TaskEventKind2) => {
1739
1495
  // src/workflow/agent.workflow.ts
1740
1496
  var agentWorkflow = async (input, { step, tools, logger }) => {
1741
1497
  const event = (name, event2) => step(name, () => tools.taskEvent(event2));
1742
- const { tools: toolInfo19, maxToolRoundTrips = 200 } = input;
1498
+ const { tools: toolInfo13, maxToolRoundTrips = 200 } = input;
1743
1499
  const messages = "systemPrompt" in input ? [{ role: "system", content: input.systemPrompt }] : input.messages;
1744
1500
  await event("start-task", { kind: "StartTask" /* StartTask */, systemPrompt: "systemPrompt" in input ? input.systemPrompt : "" });
1745
1501
  const toolSet = {};
1746
- for (const tool of toolInfo19) {
1502
+ for (const tool of toolInfo13) {
1747
1503
  toolSet[tool.name] = {
1748
1504
  description: tool.description,
1749
1505
  inputSchema: jsonSchema(toJSONSchema(tool.parameters))
@@ -1803,7 +1559,7 @@ var agentWorkflow = async (input, { step, tools, logger }) => {
1803
1559
  }
1804
1560
  const validated = input.outputSchema.safeParse(parsed.data);
1805
1561
  if (!validated.success) {
1806
- const errorMessage = `Output validation failed. Error: ${z20.prettifyError(validated.error)}. Please correct the output.`;
1562
+ const errorMessage = `Output validation failed. Error: ${z15.prettifyError(validated.error)}. Please correct the output.`;
1807
1563
  nextMessage = [{ role: "user", content: errorMessage }];
1808
1564
  continue;
1809
1565
  }
@@ -1844,50 +1600,28 @@ var agentWorkflow = async (input, { step, tools, logger }) => {
1844
1600
  input: toolCall.input
1845
1601
  });
1846
1602
  });
1847
- switch (toolResponse.type) {
1848
- case "Reply" /* Reply */:
1849
- await event(`event-tool-reply-${toolCall.toolName}-${toolCall.toolCallId}`, {
1850
- kind: "ToolReply" /* ToolReply */,
1851
- tool: toolCall.toolName,
1852
- content: toolResponse.message
1853
- });
1854
- toolResults.push({
1855
- toolCallId: toolCall.toolCallId,
1856
- toolName: toolCall.toolName,
1857
- output: toolResponse.message
1858
- });
1859
- break;
1860
- case "Error" /* Error */:
1861
- await event(`event-tool-error-${toolCall.toolName}-${toolCall.toolCallId}`, {
1862
- kind: "ToolError" /* ToolError */,
1863
- tool: toolCall.toolName,
1864
- error: toolResponse.message ?? "Unknown error"
1865
- });
1866
- toolResults.push({
1867
- toolCallId: toolCall.toolCallId,
1868
- toolName: toolCall.toolName,
1869
- output: toolResponse.message
1870
- });
1871
- break;
1872
- case "Exit": {
1873
- if (toolCalls.length > 1) {
1874
- toolResults.push({
1875
- toolCallId: toolCall.toolCallId,
1876
- toolName: toolCall.toolName,
1877
- output: {
1878
- type: "error-text",
1879
- value: `Error: The tool '${toolCall.toolName}' must be called alone, but it was called with other tools.`
1880
- }
1881
- });
1882
- break;
1883
- }
1884
- if (toolResults.length > 0) {
1885
- break;
1886
- }
1887
- const exitReason = { ...toolResponse, messages };
1888
- await event("end-task", { kind: "EndTask" /* EndTask */, exitReason });
1889
- return exitReason;
1890
- }
1603
+ if (toolResponse.success) {
1604
+ await event(`event-tool-reply-${toolCall.toolName}-${toolCall.toolCallId}`, {
1605
+ kind: "ToolReply" /* ToolReply */,
1606
+ tool: toolCall.toolName,
1607
+ content: toolResponse.message
1608
+ });
1609
+ toolResults.push({
1610
+ toolCallId: toolCall.toolCallId,
1611
+ toolName: toolCall.toolName,
1612
+ output: toolResponse.message
1613
+ });
1614
+ } else {
1615
+ await event(`event-tool-error-${toolCall.toolName}-${toolCall.toolCallId}`, {
1616
+ kind: "ToolError" /* ToolError */,
1617
+ tool: toolCall.toolName,
1618
+ error: toolResponse.message ?? "Unknown error"
1619
+ });
1620
+ toolResults.push({
1621
+ toolCallId: toolCall.toolCallId,
1622
+ toolName: toolCall.toolName,
1623
+ output: toolResponse.message
1624
+ });
1891
1625
  }
1892
1626
  }
1893
1627
  nextMessage = [
@@ -1906,49 +1640,58 @@ var agentWorkflow = async (input, { step, tools, logger }) => {
1906
1640
 
1907
1641
  // src/workflow/dynamic.ts
1908
1642
  import { parse } from "yaml";
1909
- import { z as z22 } from "zod";
1643
+ import { z as z17 } from "zod";
1910
1644
 
1911
1645
  // src/workflow/dynamic-types.ts
1912
- import { z as z21 } from "zod";
1913
- var WorkflowInputDefinitionSchema = z21.object({
1914
- id: z21.string(),
1915
- description: z21.string().nullish(),
1916
- default: z21.any().nullish()
1646
+ import { z as z16 } from "zod";
1647
+ var WorkflowInputDefinitionSchema = z16.object({
1648
+ id: z16.string(),
1649
+ description: z16.string().nullish(),
1650
+ default: z16.any().nullish()
1917
1651
  });
1918
- var WorkflowStepDefinitionSchema = z21.object({
1919
- id: z21.string(),
1920
- tools: z21.array(z21.string()).nullish(),
1921
- task: z21.string(),
1922
- output: z21.string().nullish(),
1923
- expected_outcome: z21.string().nullish(),
1652
+ var WorkflowStepDefinitionSchema = z16.object({
1653
+ id: z16.string(),
1654
+ tools: z16.array(z16.string()).nullish(),
1655
+ task: z16.string(),
1656
+ output: z16.string().nullish(),
1657
+ expected_outcome: z16.string().nullish(),
1924
1658
  /**
1925
1659
  * Persisted JavaScript/TypeScript (JS-compatible) async function body.
1926
1660
  * The code is wrapped as: `async (ctx) => { <code> }`.
1927
1661
  */
1928
- code: z21.string().nullish(),
1662
+ code: z16.string().nullish(),
1929
1663
  /**
1930
1664
  * Optional JSON schema or other metadata for future structured outputs.
1931
1665
  * Not interpreted by core today.
1932
1666
  */
1933
- outputSchema: z21.any().nullish()
1667
+ outputSchema: z16.any().nullish(),
1668
+ /**
1669
+ * Optional timeout in milliseconds. Step execution will be aborted if it exceeds this duration.
1670
+ */
1671
+ timeout: z16.number().positive().nullish()
1934
1672
  });
1935
- var WorkflowDefinitionSchema = z21.object({
1936
- task: z21.string(),
1937
- inputs: z21.array(WorkflowInputDefinitionSchema).nullish(),
1938
- steps: z21.array(WorkflowStepDefinitionSchema),
1939
- output: z21.string().nullish()
1673
+ var WorkflowDefinitionSchema = z16.object({
1674
+ task: z16.string(),
1675
+ inputs: z16.array(WorkflowInputDefinitionSchema).nullish(),
1676
+ steps: z16.array(WorkflowStepDefinitionSchema),
1677
+ output: z16.string().nullish()
1940
1678
  });
1941
- var WorkflowFileSchema = z21.object({
1942
- workflows: z21.record(z21.string(), WorkflowDefinitionSchema)
1679
+ var WorkflowFileSchema = z16.object({
1680
+ workflows: z16.record(z16.string(), WorkflowDefinitionSchema)
1943
1681
  });
1944
1682
 
1945
1683
  // src/workflow/dynamic.ts
1684
+ var TOOL_GROUPS = {
1685
+ readonly: ["readFile", "readBinaryFile", "listFiles", "searchFiles"],
1686
+ readwrite: ["readFile", "readBinaryFile", "listFiles", "searchFiles", "writeToFile", "replaceInFile", "removeFile", "renameFile"],
1687
+ internet: ["fetchUrl", "search"]
1688
+ };
1946
1689
  function parseDynamicWorkflowDefinition(source) {
1947
1690
  try {
1948
1691
  const raw = parse(source);
1949
1692
  const validated = WorkflowFileSchema.safeParse(raw);
1950
1693
  if (!validated.success) {
1951
- return { success: false, error: z22.prettifyError(validated.error) };
1694
+ return { success: false, error: z17.prettifyError(validated.error) };
1952
1695
  }
1953
1696
  return { success: true, definition: validated.data };
1954
1697
  } catch (error) {
@@ -1957,6 +1700,28 @@ function parseDynamicWorkflowDefinition(source) {
1957
1700
  }
1958
1701
  var AsyncFunction = Object.getPrototypeOf(async () => {
1959
1702
  }).constructor;
1703
+ function validateAndApplyDefaults(workflowId, workflow, input) {
1704
+ if (!workflow.inputs || workflow.inputs.length === 0) {
1705
+ return input;
1706
+ }
1707
+ const validatedInput = {};
1708
+ const errors = [];
1709
+ for (const inputDef of workflow.inputs) {
1710
+ const providedValue = input[inputDef.id];
1711
+ if (providedValue !== void 0 && providedValue !== null) {
1712
+ validatedInput[inputDef.id] = providedValue;
1713
+ } else if (inputDef.default !== void 0 && inputDef.default !== null) {
1714
+ validatedInput[inputDef.id] = inputDef.default;
1715
+ } else {
1716
+ errors.push(`Missing required input '${inputDef.id}'${inputDef.description ? `: ${inputDef.description}` : ""}`);
1717
+ }
1718
+ }
1719
+ if (errors.length > 0) {
1720
+ throw new Error(`Workflow '${workflowId}' input validation failed:
1721
+ ${errors.map((e) => ` - ${e}`).join("\n")}`);
1722
+ }
1723
+ return validatedInput;
1724
+ }
1960
1725
  function createRunWorkflowFn(args) {
1961
1726
  return async (subWorkflowId, subInput) => {
1962
1727
  const mergedInput = { ...args.input, ...args.state, ...subInput ?? {} };
@@ -1977,8 +1742,13 @@ function compileStep(stepDef, workflowId, compiledSteps) {
1977
1742
  compiledSteps.set(key, fn);
1978
1743
  return fn;
1979
1744
  } catch (error) {
1745
+ const errorMsg = error instanceof Error ? error.message : String(error);
1746
+ const codePreview = stepDef.code.length > 200 ? `${stepDef.code.substring(0, 200)}...` : stepDef.code;
1980
1747
  throw new Error(
1981
- `Failed to compile code for step '${stepDef.id}' in workflow '${workflowId}': ${error instanceof Error ? error.message : String(error)}`
1748
+ `Failed to compile code for step '${stepDef.id}' in workflow '${workflowId}':
1749
+ Error: ${errorMsg}
1750
+ Code:
1751
+ ${codePreview.split("\n").map((line) => ` ${line}`).join("\n")}`
1982
1752
  );
1983
1753
  }
1984
1754
  }
@@ -1994,22 +1764,47 @@ async function executeStepWithAgent(stepDef, workflowId, input, state, context,
1994
1764
  `Step '${stepDef.id}' in workflow '${workflowId}' requires agent execution, but no toolInfo was provided to DynamicWorkflowRunner.`
1995
1765
  );
1996
1766
  }
1997
- const allowedToolNames = stepDef.tools;
1998
- const toolsForAgent = allowedToolNames ? options.toolInfo.filter((t) => allowedToolNames.includes(t.name)) : [...options.toolInfo];
1999
- if (!allowedToolNames || allowedToolNames.includes("runWorkflow")) {
1767
+ const rawAllowedToolNames = stepDef.tools;
1768
+ let toolsForAgent;
1769
+ if (rawAllowedToolNames) {
1770
+ const expandedToolNames = /* @__PURE__ */ new Set();
1771
+ let includeAll = false;
1772
+ for (const name of rawAllowedToolNames) {
1773
+ if (name === "all") {
1774
+ includeAll = true;
1775
+ break;
1776
+ }
1777
+ if (Object.hasOwn(TOOL_GROUPS, name)) {
1778
+ for (const tool of TOOL_GROUPS[name]) {
1779
+ expandedToolNames.add(tool);
1780
+ }
1781
+ } else {
1782
+ expandedToolNames.add(name);
1783
+ }
1784
+ }
1785
+ if (includeAll) {
1786
+ toolsForAgent = [...options.toolInfo];
1787
+ } else {
1788
+ toolsForAgent = options.toolInfo.filter((t) => expandedToolNames.has(t.name));
1789
+ }
1790
+ } else {
1791
+ toolsForAgent = [...options.toolInfo];
1792
+ }
1793
+ if (!rawAllowedToolNames || rawAllowedToolNames.includes("all") || rawAllowedToolNames.includes("runWorkflow")) {
2000
1794
  toolsForAgent.push({
2001
1795
  name: "runWorkflow",
2002
1796
  description: "Run a named sub-workflow defined in the current workflow file.",
2003
- parameters: z22.object({
2004
- workflowId: z22.string().describe("Sub-workflow id to run"),
2005
- input: z22.any().nullish().describe("Optional input object for the sub-workflow")
1797
+ parameters: z17.object({
1798
+ workflowId: z17.string().describe("Sub-workflow id to run"),
1799
+ input: z17.any().nullish().describe("Optional input object for the sub-workflow")
2006
1800
  }),
2007
1801
  handler: async () => {
2008
- return { type: "Error" /* Error */, message: { type: "error-text", value: "runWorkflow is virtual." } };
1802
+ return { success: false, message: { type: "error-text", value: "runWorkflow is virtual." } };
2009
1803
  }
2010
1804
  });
2011
1805
  }
2012
1806
  const allowedToolNameSet = new Set(toolsForAgent.map((t) => t.name));
1807
+ context.logger.debug(`[Agent] Available tools for step '${stepDef.id}': ${toolsForAgent.map((t) => t.name).join(", ")}`);
2013
1808
  const systemPrompt = options.stepSystemPrompt?.({ workflowId, step: stepDef, input, state }) ?? [
2014
1809
  `You are an AI assistant executing a workflow step.`,
2015
1810
  "",
@@ -2034,7 +1829,7 @@ async function executeStepWithAgent(stepDef, workflowId, input, state, context,
2034
1829
  invokeTool: async ({ toolName, input: toolInput }) => {
2035
1830
  if (!allowedToolNameSet.has(toolName)) {
2036
1831
  return {
2037
- type: "Error" /* Error */,
1832
+ success: false,
2038
1833
  message: { type: "error-text", value: `Tool '${toolName}' is not allowed in this step.` }
2039
1834
  };
2040
1835
  }
@@ -2043,17 +1838,17 @@ async function executeStepWithAgent(stepDef, workflowId, input, state, context,
2043
1838
  const subInput = toolInput?.input;
2044
1839
  if (typeof subWorkflowId !== "string") {
2045
1840
  return {
2046
- type: "Error" /* Error */,
1841
+ success: false,
2047
1842
  message: { type: "error-text", value: "runWorkflow.workflowId must be a string." }
2048
1843
  };
2049
1844
  }
2050
1845
  try {
2051
1846
  const output = await runWorkflow(subWorkflowId, subInput);
2052
1847
  const jsonResult = { type: "json", value: output };
2053
- return { type: "Reply" /* Reply */, message: jsonResult };
1848
+ return { success: true, message: jsonResult };
2054
1849
  } catch (error) {
2055
1850
  return {
2056
- type: "Error" /* Error */,
1851
+ success: false,
2057
1852
  message: { type: "error-text", value: error instanceof Error ? error.message : String(error) }
2058
1853
  };
2059
1854
  }
@@ -2079,28 +1874,95 @@ async function executeStepWithAgent(stepDef, workflowId, input, state, context,
2079
1874
  if (parsed.success) {
2080
1875
  return parsed.data;
2081
1876
  }
1877
+ if (options.wrapAgentResultInObject) {
1878
+ context.logger.warn(`[Agent] Step '${stepDef.id}' returned plain text instead of JSON. Wrapping in {result: ...}`);
1879
+ return { result: result.message };
1880
+ }
2082
1881
  return result.message;
2083
1882
  }
2084
- throw new Error(`Agent execution for step '${stepDef.id}' in workflow '${workflowId}' did not exit cleanly.`);
1883
+ if (result.type === "Error") {
1884
+ throw new Error(`Agent step '${stepDef.id}' in workflow '${workflowId}' failed: ${result.error?.message || "Unknown error"}`);
1885
+ }
1886
+ if (result.type === "UsageExceeded") {
1887
+ throw new Error(`Agent step '${stepDef.id}' in workflow '${workflowId}' exceeded usage limits (tokens or rounds)`);
1888
+ }
1889
+ throw new Error(`Agent step '${stepDef.id}' in workflow '${workflowId}' exited unexpectedly with type: ${result.type}`);
1890
+ }
1891
+ async function executeStepWithTimeout(stepDef, workflowId, input, state, context, options, compiledSteps, runInternal) {
1892
+ const executeStepLogic = async () => {
1893
+ if (stepDef.code && options.allowUnsafeCodeExecution) {
1894
+ context.logger.debug(`[Step] Executing step '${stepDef.id}' with compiled code`);
1895
+ const fn = compileStep(stepDef, workflowId, compiledSteps);
1896
+ const runWorkflow = createRunWorkflowFn({ input, state, context, runInternal });
1897
+ const agentTools = {};
1898
+ if (options.toolInfo) {
1899
+ for (const tool of options.toolInfo) {
1900
+ if (typeof context.tools[tool.name] === "function") {
1901
+ agentTools[tool.name] = context.tools[tool.name];
1902
+ }
1903
+ }
1904
+ }
1905
+ const runtimeCtx = {
1906
+ workflowId,
1907
+ stepId: stepDef.id,
1908
+ input,
1909
+ state,
1910
+ tools: context.tools,
1911
+ logger: context.logger,
1912
+ step: context.step,
1913
+ runWorkflow,
1914
+ toolInfo: options.toolInfo,
1915
+ agentTools
1916
+ };
1917
+ const result2 = await fn(runtimeCtx);
1918
+ context.logger.debug(`[Step] Compiled code execution completed for step '${stepDef.id}'`);
1919
+ return result2;
1920
+ }
1921
+ context.logger.debug(`[Step] Executing step '${stepDef.id}' with agent`);
1922
+ const result = await executeStepWithAgent(stepDef, workflowId, input, state, context, options, runInternal);
1923
+ context.logger.debug(`[Step] Agent execution completed for step '${stepDef.id}'`);
1924
+ return result;
1925
+ };
1926
+ if (stepDef.timeout && stepDef.timeout > 0) {
1927
+ context.logger.debug(`[Step] Step '${stepDef.id}' has timeout of ${stepDef.timeout}ms`);
1928
+ let timeoutId;
1929
+ const timeoutPromise = new Promise((_, reject) => {
1930
+ timeoutId = setTimeout(
1931
+ () => reject(new Error(`Step '${stepDef.id}' in workflow '${workflowId}' timed out after ${stepDef.timeout}ms`)),
1932
+ stepDef.timeout
1933
+ );
1934
+ });
1935
+ try {
1936
+ return await Promise.race([executeStepLogic(), timeoutPromise]);
1937
+ } finally {
1938
+ if (timeoutId) clearTimeout(timeoutId);
1939
+ }
1940
+ }
1941
+ return await executeStepLogic();
2085
1942
  }
2086
1943
  async function executeStep(stepDef, workflowId, input, state, context, options, compiledSteps, runInternal) {
2087
- if (stepDef.code && options.allowUnsafeCodeExecution) {
2088
- const fn = compileStep(stepDef, workflowId, compiledSteps);
2089
- const runWorkflow = createRunWorkflowFn({ input, state, context, runInternal });
2090
- const runtimeCtx = {
2091
- workflowId,
2092
- stepId: stepDef.id,
2093
- input,
2094
- state,
2095
- tools: context.tools,
2096
- logger: context.logger,
2097
- step: context.step,
2098
- runWorkflow,
2099
- toolInfo: options.toolInfo
2100
- };
2101
- return await fn(runtimeCtx);
1944
+ const result = await executeStepWithTimeout(stepDef, workflowId, input, state, context, options, compiledSteps, runInternal);
1945
+ if (stepDef.outputSchema) {
1946
+ try {
1947
+ const _schema = z17.any();
1948
+ if (typeof stepDef.outputSchema === "object") {
1949
+ context.logger.debug(`[Step] Validating output for step '${stepDef.id}' against schema`);
1950
+ if (stepDef.outputSchema.type === "object") {
1951
+ if (typeof result !== "object" || result === null || Array.isArray(result)) {
1952
+ throw new Error(`Expected object output, got ${Array.isArray(result) ? "array" : result === null ? "null" : typeof result}`);
1953
+ }
1954
+ }
1955
+ if (stepDef.outputSchema.type === "array" && !Array.isArray(result)) {
1956
+ throw new Error(`Expected array output, got ${typeof result}`);
1957
+ }
1958
+ }
1959
+ } catch (error) {
1960
+ throw new Error(
1961
+ `Step '${stepDef.id}' in workflow '${workflowId}' output validation failed: ${error instanceof Error ? error.message : String(error)}`
1962
+ );
1963
+ }
2102
1964
  }
2103
- return await executeStepWithAgent(stepDef, workflowId, input, state, context, options, runInternal);
1965
+ return result;
2104
1966
  }
2105
1967
  function createDynamicWorkflow(definition, options = {}) {
2106
1968
  if (typeof definition === "string") {
@@ -2116,19 +1978,37 @@ function createDynamicWorkflow(definition, options = {}) {
2116
1978
  if (!workflow) {
2117
1979
  throw new Error(`Workflow '${workflowId}' not found`);
2118
1980
  }
1981
+ const validatedInput = validateAndApplyDefaults(workflowId, workflow, input);
1982
+ context.logger.info(`[Workflow] Starting workflow '${workflowId}'`);
1983
+ context.logger.debug(`[Workflow] Input: ${JSON.stringify(validatedInput)}`);
1984
+ context.logger.debug(`[Workflow] Inherited state: ${JSON.stringify(inheritedState)}`);
1985
+ context.logger.debug(`[Workflow] Steps: ${workflow.steps.map((s) => s.id).join(", ")}`);
2119
1986
  const state = { ...inheritedState };
2120
1987
  let lastOutput;
2121
- for (const stepDef of workflow.steps) {
1988
+ for (let i = 0; i < workflow.steps.length; i++) {
1989
+ const stepDef = workflow.steps[i];
2122
1990
  const stepName = `${workflowId}.${stepDef.id}`;
1991
+ context.logger.info(`[Workflow] Step ${i + 1}/${workflow.steps.length}: ${stepDef.id}`);
1992
+ context.logger.debug(`[Workflow] Step task: ${stepDef.task}`);
1993
+ if (stepDef.expected_outcome) {
1994
+ context.logger.debug(`[Workflow] Expected outcome: ${stepDef.expected_outcome}`);
1995
+ }
1996
+ context.logger.debug(`[Workflow] Current state keys: ${Object.keys(state).join(", ")}`);
2123
1997
  lastOutput = await context.step(stepName, async () => {
2124
- return await executeStep(stepDef, workflowId, input, state, context, options, compiledSteps, runInternal);
1998
+ return await executeStep(stepDef, workflowId, validatedInput, state, context, options, compiledSteps, runInternal);
2125
1999
  });
2126
2000
  const outputKey = stepDef.output ?? stepDef.id;
2127
2001
  state[outputKey] = lastOutput;
2002
+ context.logger.debug(
2003
+ `[Workflow] Step output stored as '${outputKey}': ${typeof lastOutput === "object" ? JSON.stringify(lastOutput).substring(0, 200) : lastOutput}`
2004
+ );
2128
2005
  }
2006
+ context.logger.info(`[Workflow] Completed workflow '${workflowId}'`);
2129
2007
  if (workflow.output) {
2008
+ context.logger.debug(`[Workflow] Returning output field: ${workflow.output}`);
2130
2009
  return state[workflow.output];
2131
2010
  }
2011
+ context.logger.debug(`[Workflow] Returning full state with keys: ${Object.keys(state).join(", ")}`);
2132
2012
  return state;
2133
2013
  };
2134
2014
  return async (workflowId, input, context) => {
@@ -2137,19 +2017,362 @@ function createDynamicWorkflow(definition, options = {}) {
2137
2017
  }
2138
2018
 
2139
2019
  // src/workflow/dynamic-generator.workflow.ts
2140
- import { z as z23 } from "zod";
2141
- var GenerateWorkflowDefinitionInputSchema = z23.object({
2142
- prompt: z23.string(),
2143
- availableTools: z23.array(
2144
- z23.object({
2145
- name: z23.string(),
2146
- description: z23.string()
2020
+ import { z as z18 } from "zod";
2021
+
2022
+ // src/workflow/prompts/dynamic-generator-prompts.ts
2023
+ var RUNTIME_CONTEXT_TYPES = `## Runtime context (ctx)
2024
+ \`\`\`ts
2025
+ // Runtime types (for reference)
2026
+ type Logger = {
2027
+ debug: (...args: any[]) => void
2028
+ info: (...args: any[]) => void
2029
+ warn: (...args: any[]) => void
2030
+ error: (...args: any[]) => void
2031
+ }
2032
+
2033
+ type StepFn = {
2034
+ <T>(name: string, fn: () => Promise<T>): Promise<T>
2035
+ <T>(name: string, options: { retry?: number }, fn: () => Promise<T>): Promise<T>
2036
+ }
2037
+
2038
+ type JsonModelMessage = { role: 'system' | 'user' | 'assistant' | 'tool'; content: any }
2039
+ type JsonResponseMessage = { role: 'assistant' | 'tool'; content: any }
2040
+ type ToolSet = Record<string, any>
2041
+
2042
+ type ToolResponseResult =
2043
+ | { type: 'text'; value: string }
2044
+ | { type: 'json'; value: any }
2045
+ | { type: 'error-text'; value: string }
2046
+ | { type: 'error-json'; value: any }
2047
+ | { type: 'content'; value: any[] }
2048
+
2049
+ type ToolResponse =
2050
+ | { type: 'Reply'; message: ToolResponseResult }
2051
+ | { type: 'Exit'; message: string; object?: any }
2052
+ | { type: 'Error'; message: ToolResponseResult }
2053
+
2054
+ type ExitReason =
2055
+ | { type: 'UsageExceeded' }
2056
+ | { type: 'Exit'; message: string; object?: any }
2057
+ | { type: 'Error'; error: { message: string; stack?: string } }
2058
+
2059
+ type FullToolInfo = { name: string; description: string; parameters: any; handler: any }
2060
+
2061
+ type AgentTools = {
2062
+ readFile: (input: { path: string }) => Promise<string | null>
2063
+ writeToFile: (input: { path: string; content: string }) => Promise<void>
2064
+ executeCommand: (input: { command: string; pipe?: boolean; requiresApproval?: boolean } & ({ args: string[]; shell?: false } | { shell: true })) => Promise<{
2065
+ exitCode: number
2066
+ stdout: string
2067
+ stderr: string
2068
+ }>
2069
+ searchFiles: (input: { path: string; regex: string; filePattern?: string }) => Promise<string>
2070
+ listFiles: (input: { path: string; recursive?: boolean; maxCount?: number; includeIgnored?: boolean }) => Promise<string>
2071
+ fetchUrl: (input: { url: string[] }) => Promise<string>
2072
+ askFollowupQuestion: (input: { questions: { prompt: string; options?: string[] }[] }) => Promise<any>
2073
+ // ... and other tools available in the environment
2074
+ }
2075
+
2076
+ // Tools available on ctx.tools in dynamic steps
2077
+ type DynamicWorkflowTools = {
2078
+ // LLM + agent helpers
2079
+ runAgent: (input: {
2080
+ tools: Readonly<FullToolInfo[]>
2081
+ maxToolRoundTrips?: number
2082
+ userMessage: readonly JsonModelMessage[]
2083
+ } & ({ messages: JsonModelMessage[] } | { systemPrompt: string })) => Promise<ExitReason>
2084
+
2085
+ // CLI UX helpers
2086
+ confirm: (input: { message: string }) => Promise<boolean>
2087
+ input: (input: { message: string; default?: string }) => Promise<string>
2088
+ select: (input: { message: string; choices: { name: string; value: string }[] }) => Promise<string>
2089
+ }
2090
+
2091
+ type DynamicStepRuntimeContext = {
2092
+ workflowId: string
2093
+ stepId: string
2094
+ input: Record<string, any>
2095
+ state: Record<string, any>
2096
+ tools: DynamicWorkflowTools
2097
+ agentTools: AgentTools
2098
+ logger: Logger
2099
+ step: StepFn
2100
+ runWorkflow: (workflowId: string, input?: Record<string, any>) => Promise<any>
2101
+ toolInfo?: ReadonlyArray<FullToolInfo>
2102
+ }
2103
+ \`\`\`
2104
+
2105
+ - \`ctx.input\`: workflow inputs (read-only).
2106
+ - \`ctx.state\`: shared state between steps (previous step outputs are stored here).
2107
+ - \`ctx.agentTools\`: standard tools (readFile, executeCommand, etc.). Call as \`await ctx.agentTools.someTool({ ... })\`.
2108
+ - \`ctx.tools\`: workflow helpers (runAgent, confirm, input, select).
2109
+ - \`ctx.runWorkflow\`: run a sub-workflow by id.`;
2110
+ var CONTEXT_USAGE_GUIDELINES = `## Guidelines
2111
+ - Use \`await\` for all async operations.
2112
+ - Return the output value for the step (this becomes the step output).
2113
+ - Access inputs via \`ctx.input.<inputId>\`.
2114
+ - Access previous step outputs via \`ctx.state.<stepOutputKey>\` (defaults to the step \`output\` or \`id\`).`;
2115
+ var QUALITY_GUIDELINES = `## Quality Guidelines for Code Implementation
2116
+
2117
+ ### Error Handling
2118
+ - ALWAYS validate inputs at the start of steps
2119
+ - Use try-catch for operations that might fail (file I/O, parsing, API calls)
2120
+ - Preserve stack traces: re-throw original errors rather than creating new ones
2121
+ - Use error type guards: \`const err = error instanceof Error ? error : new Error(String(error))\`
2122
+ - Check for null/undefined before using values
2123
+ - Handle edge cases (empty arrays, missing files, invalid data)
2124
+
2125
+ ### Logging
2126
+ - Use \`ctx.logger.info()\` for important progress updates
2127
+ - Use \`ctx.logger.debug()\` for detailed information
2128
+ - Use \`ctx.logger.warn()\` for recoverable issues
2129
+ - Use \`ctx.logger.error()\` before throwing errors
2130
+ - Log when starting and completing significant operations
2131
+ - Use template literals for readability: \`ctx.logger.info(\\\`Processing \${items.length} items...\\\`)\`
2132
+
2133
+ ### User Experience
2134
+ - Provide progress feedback for long operations
2135
+ - Return structured data (objects/arrays), not strings when possible
2136
+ - Include helpful metadata in results (counts, timestamps, status)
2137
+ - For batch operations, report progress: \`Processed 5/10 items\`
2138
+
2139
+ ### Data Validation
2140
+ - Validate required fields exist before accessing
2141
+ - Check data types match expectations
2142
+ - Validate array lengths before iteration
2143
+ - Example: \`if (!data?.users || !Array.isArray(data.users)) throw new Error('Invalid data format')\`
2144
+
2145
+ ### Best Practices
2146
+ - Use meaningful variable names
2147
+ - Avoid nested callbacks - use async/await
2148
+ - Clean up resources (close files, clear timeouts)
2149
+ - Return consistent data structures across similar steps
2150
+ - For iteration, consider batching or rate limiting
2151
+
2152
+ ### When to Simplify
2153
+ - Simple transformation steps (e.g., formatting strings) need only basic error handling
2154
+ - Internal sub-workflow steps with validated inputs from parent can skip redundant validation
2155
+ - Minimal logging is fine for fast steps (<100ms) that don't perform I/O or external calls
2156
+ - Use judgment: match error handling complexity to the step's failure risk and impact`;
2157
+ var TOOL_CALLING_EXAMPLES = `## Tool calling examples
2158
+
2159
+ ### Standard tools (ctx.agentTools)
2160
+ \`\`\`ts
2161
+ // readFile
2162
+ const readme = await ctx.agentTools.readFile({ path: 'README.md' })
2163
+ if (readme == null) throw new Error('README.md not found')
2164
+
2165
+ // writeToFile
2166
+ await ctx.agentTools.writeToFile({ path: 'notes.txt', content: 'hello\\n' })
2167
+
2168
+ // executeCommand (args form)
2169
+ const rg = await ctx.agentTools.executeCommand({ command: 'rg', args: ['-n', 'TODO', '.'] })
2170
+ if (rg.exitCode !== 0) throw new Error(rg.stderr)
2171
+
2172
+ // executeCommand (shell form)
2173
+ await ctx.agentTools.executeCommand({ command: 'ls -la', shell: true, pipe: true })
2174
+ \`\`\`
2175
+
2176
+ ### Workflow helpers (ctx.tools)
2177
+ \`\`\`ts
2178
+ // runAgent (nested agent; use ctx.toolInfo as the tool list)
2179
+ const agentRes = await ctx.tools.runAgent({
2180
+ systemPrompt: 'You are a helpful assistant.',
2181
+ userMessage: [{ role: 'user', content: 'Summarize README.md in 3 bullets.' }],
2182
+ tools: (ctx.toolInfo ?? []) as any,
2183
+ })
2184
+ if (agentRes.type !== 'Exit') throw new Error('runAgent failed')
2185
+
2186
+ // confirm / input / select (interactive)
2187
+ const ok = await ctx.tools.confirm({ message: 'Proceed?' })
2188
+ const name = await ctx.tools.input({ message: 'Name?', default: 'main' })
2189
+ const flavor = await ctx.tools.select({
2190
+ message: 'Pick one',
2191
+ choices: [
2192
+ { name: 'A', value: 'a' },
2193
+ { name: 'B', value: 'b' },
2194
+ ],
2195
+ })
2196
+ \`\`\`
2197
+
2198
+ ### Sub-workflow example (ctx.runWorkflow)
2199
+ \`\`\`ts
2200
+ const results: any[] = []
2201
+ for (const pr of ctx.state.prs ?? []) {
2202
+ results.push(await ctx.runWorkflow('reviewPR', { prId: pr.id }))
2203
+ }
2204
+ return results
2205
+ \`\`\``;
2206
+ var COMPLETE_STEP_EXAMPLE = `## Complete Example: High-Quality Step Implementation
2207
+
2208
+ This example demonstrates all quality guidelines in a single step:
2209
+
2210
+ \`\`\`ts
2211
+ // Step: processUserData
2212
+ // Task: Read, validate, and process user data from a file
2213
+
2214
+ // Input validation
2215
+ if (!ctx.input.dataFile) {
2216
+ throw new Error('Missing required input: dataFile')
2217
+ }
2218
+
2219
+ ctx.logger.info(\`Starting user data processing for: \${ctx.input.dataFile}\`)
2220
+
2221
+ // Read file with error handling
2222
+ let rawData
2223
+ try {
2224
+ ctx.logger.debug(\`Reading file: \${ctx.input.dataFile}\`)
2225
+ rawData = await ctx.agentTools.readFile({ path: ctx.input.dataFile })
2226
+
2227
+ if (!rawData) {
2228
+ throw new Error(\`File not found or empty: \${ctx.input.dataFile}\`)
2229
+ }
2230
+ } catch (error) {
2231
+ const err = error instanceof Error ? error : new Error(String(error))
2232
+ ctx.logger.error(\`Failed to read file: \${err.message}\`)
2233
+ throw err // Preserve original stack trace
2234
+ }
2235
+
2236
+ // Parse and validate data
2237
+ let users
2238
+ try {
2239
+ ctx.logger.debug('Parsing JSON data')
2240
+ const parsed = JSON.parse(rawData)
2241
+
2242
+ if (!parsed?.users || !Array.isArray(parsed.users)) {
2243
+ throw new Error('Invalid data format: expected {users: [...]}')
2244
+ }
2245
+
2246
+ users = parsed.users
2247
+ ctx.logger.info(\`Found \${users.length} users to process\`)
2248
+ } catch (error) {
2249
+ const err = error instanceof Error ? error : new Error(String(error))
2250
+ ctx.logger.error(\`Data parsing failed: \${err.message}\`)
2251
+ throw err // Preserve original stack trace
2252
+ }
2253
+
2254
+ // Process each user with progress reporting
2255
+ const results = []
2256
+ for (let i = 0; i < users.length; i++) {
2257
+ const user = users[i]
2258
+
2259
+ // Validate each user object
2260
+ if (!user?.id || !user?.email) {
2261
+ ctx.logger.warn(\`Skipping invalid user at index \${i}: missing id or email\`)
2262
+ continue
2263
+ }
2264
+
2265
+ // Process user
2266
+ const processed = {
2267
+ id: user.id,
2268
+ email: user.email.toLowerCase().trim(),
2269
+ name: user.name?.trim() || 'Unknown',
2270
+ processedAt: new Date().toISOString(),
2271
+ status: 'active'
2272
+ }
2273
+
2274
+ results.push(processed)
2275
+
2276
+ // Progress feedback every 10 items
2277
+ if ((i + 1) % 10 === 0) {
2278
+ ctx.logger.info(\`Processed \${i + 1}/\${users.length} users\`)
2279
+ }
2280
+ }
2281
+
2282
+ ctx.logger.info(\`Successfully processed \${results.length}/\${users.length} users\`)
2283
+
2284
+ // Return structured result with metadata
2285
+ return {
2286
+ users: results,
2287
+ metadata: {
2288
+ totalInput: users.length,
2289
+ totalProcessed: results.length,
2290
+ skipped: users.length - results.length,
2291
+ processedAt: new Date().toISOString()
2292
+ }
2293
+ }
2294
+ \`\`\`
2295
+
2296
+ Key features demonstrated:
2297
+ - Input validation at start
2298
+ - Comprehensive error handling with try-catch that preserves stack traces
2299
+ - Logging at info, debug, warn, and error levels
2300
+ - Progress reporting for long operations (every 10 items)
2301
+ - Data validation throughout (null checks, type checks, array validation)
2302
+ - Structured return value with metadata for observability
2303
+ - Descriptive error messages with context
2304
+ - Meaningful variable names (rawData, users, processed)
2305
+ - Clean async/await usage
2306
+ - Template literals for readable string interpolation
2307
+ - Proper error type guards (error instanceof Error)`;
2308
+ var CODE_FIELD_CONSTRAINTS = `REMEMBER: The "code" field must be ONLY the function body statements.
2309
+ - DO NOT wrap code in arrow functions: \`(ctx) => { ... }\`
2310
+ - DO NOT wrap code in async functions: \`async (ctx) => { ... }\`
2311
+ - DO NOT include outer curly braces
2312
+ - DO include a return statement if the step should produce output
2313
+ - Each "code" field should be a string containing multiple statements separated by newlines`;
2314
+ function composeImplementationGuidelines() {
2315
+ return [
2316
+ RUNTIME_CONTEXT_TYPES,
2317
+ "",
2318
+ CONTEXT_USAGE_GUIDELINES,
2319
+ "",
2320
+ QUALITY_GUIDELINES,
2321
+ "",
2322
+ TOOL_CALLING_EXAMPLES,
2323
+ "",
2324
+ COMPLETE_STEP_EXAMPLE
2325
+ ].join("\n");
2326
+ }
2327
+
2328
+ // src/workflow/dynamic-generator.workflow.ts
2329
+ var GenerateWorkflowDefinitionInputSchema = z18.object({
2330
+ prompt: z18.string(),
2331
+ availableTools: z18.array(
2332
+ z18.object({
2333
+ name: z18.string(),
2334
+ description: z18.string()
2147
2335
  })
2148
- ).optional()
2336
+ ).nullish()
2149
2337
  });
2150
- var GenerateWorkflowCodeInputSchema = z23.object({
2151
- workflow: WorkflowFileSchema
2338
+ var GenerateWorkflowCodeInputSchema = z18.object({
2339
+ workflow: WorkflowFileSchema,
2340
+ skipReview: z18.boolean().nullish()
2152
2341
  });
2342
+ var AsyncFunction2 = Object.getPrototypeOf(async () => {
2343
+ }).constructor;
2344
+ function validateWorkflowDefinition(workflow) {
2345
+ const errors = [];
2346
+ if (!workflow.workflows.main) {
2347
+ errors.push("Missing required 'main' workflow");
2348
+ }
2349
+ for (const [wfId, wf] of Object.entries(workflow.workflows)) {
2350
+ const stepIds = /* @__PURE__ */ new Set();
2351
+ for (const step of wf.steps) {
2352
+ if (stepIds.has(step.id)) {
2353
+ errors.push(`Duplicate step ID '${step.id}' in workflow '${wfId}'`);
2354
+ }
2355
+ stepIds.add(step.id);
2356
+ }
2357
+ }
2358
+ return { valid: errors.length === 0, errors };
2359
+ }
2360
+ function validateWorkflowCodeSyntax(workflow) {
2361
+ const errors = [];
2362
+ for (const [wfId, wf] of Object.entries(workflow.workflows)) {
2363
+ for (const step of wf.steps) {
2364
+ if (step.code) {
2365
+ try {
2366
+ new AsyncFunction2("ctx", step.code);
2367
+ } catch (e) {
2368
+ const errorMsg = e instanceof Error ? e.message : String(e);
2369
+ errors.push(`Syntax error in ${wfId}.${step.id}: ${errorMsg}`);
2370
+ }
2371
+ }
2372
+ }
2373
+ }
2374
+ return { valid: errors.length === 0, errors };
2375
+ }
2153
2376
  var WORKFLOW_DEFINITION_SYSTEM_PROMPT = `You are an expert workflow architect.
2154
2377
  Your task is to create a JSON workflow definition based on the user's request.
2155
2378
 
@@ -2165,8 +2388,11 @@ The workflow definition must follow this structure:
2165
2388
  {
2166
2389
  "id": "stepId",
2167
2390
  "task": "Description of the step",
2168
- "tools": ["toolName1", "toolName2"], // Optional list of tools needed
2169
- "output": "outputVariableName", // Optional
2391
+ "tools": ["toolName1", "toolName2"], // Optional: restrict which tools can be used. Can use groups: "readonly", "readwrite", "internet", "all".
2392
+ "output": "outputVariableName", // Optional: defaults to step id
2393
+ "timeout": 30000, // Optional: timeout in milliseconds
2394
+ "expected_outcome": "What this step produces", // Optional: documentation for expected results
2395
+ "outputSchema": { "type": "object" } // Optional: validation schema
2170
2396
  }
2171
2397
  ],
2172
2398
  "output": "outputVariableName" // Optional
@@ -2180,7 +2406,24 @@ Constraints:
2180
2406
  - Break down complex tasks into logical steps.
2181
2407
  - Define clear inputs and outputs.
2182
2408
 
2183
- Example 1:
2409
+ Quality Guidelines:
2410
+ - Add "timeout" field (in milliseconds) for steps that might take long (file I/O, API calls, searches)
2411
+ - Use "expected_outcome" field to document what each step should produce and its format
2412
+ - Use descriptive step IDs (e.g., "validateInput", "fetchUserData", not "step1", "step2")
2413
+ - Design steps to be focused - one responsibility per step
2414
+ - For steps that process multiple items, consider creating a sub-workflow
2415
+ - Add "outputSchema" with type information for validation-critical steps
2416
+ - Order steps logically with clear data flow
2417
+
2418
+ ### Using expected_outcome Effectively
2419
+
2420
+ The "expected_outcome" field helps document what each step produces. Best practices:
2421
+ - Describe the data structure: "Returns an array of { id, name, status } objects"
2422
+ - Mention important constraints: "Returns at most 10 results, sorted by date"
2423
+ - Note failure modes: "Returns null if file not found"
2424
+ - Document side effects: "Creates output directory if it doesn't exist"
2425
+
2426
+ Example 1 - Research workflow:
2184
2427
  User: "Research a topic and summarize it."
2185
2428
  Output:
2186
2429
  \`\`\`json
@@ -2196,13 +2439,16 @@ Output:
2196
2439
  "id": "search",
2197
2440
  "task": "Search for information about the topic",
2198
2441
  "tools": ["search"],
2199
- "output": "searchResults"
2442
+ "output": "searchResults",
2443
+ "timeout": 30000,
2444
+ "expected_outcome": "Returns search results with titles, URLs, and snippets related to the topic"
2200
2445
  },
2201
2446
  {
2202
2447
  "id": "summarize",
2203
2448
  "task": "Summarize the search results",
2204
- "tools": ["generateText"],
2205
- "output": "summary"
2449
+ "tools": ["runAgent"],
2450
+ "output": "summary",
2451
+ "expected_outcome": "Returns a concise summary string (2-3 paragraphs) of the key findings"
2206
2452
  }
2207
2453
  ],
2208
2454
  "output": "summary"
@@ -2211,7 +2457,7 @@ Output:
2211
2457
  }
2212
2458
  \`\`\`
2213
2459
 
2214
- Example 2:
2460
+ Example 2 - PR review workflow with sub-workflow:
2215
2461
  User: "Review urgent PRs. For each PR, run the review workflow."
2216
2462
  Output:
2217
2463
  \`\`\`json
@@ -2225,13 +2471,16 @@ Output:
2225
2471
  "id": "fetchPRs",
2226
2472
  "task": "Fetch list of urgent PRs",
2227
2473
  "tools": ["github_list_prs"],
2228
- "output": "prs"
2474
+ "output": "prs",
2475
+ "timeout": 15000,
2476
+ "expected_outcome": "Returns array of PR objects with { id, title, author, url }"
2229
2477
  },
2230
2478
  {
2231
2479
  "id": "reviewEachPR",
2232
2480
  "task": "Run review workflow for each PR",
2233
2481
  "tools": [],
2234
- "output": "reviews"
2482
+ "output": "reviews",
2483
+ "expected_outcome": "Returns array of review results, one per PR"
2235
2484
  }
2236
2485
  ],
2237
2486
  "output": "reviews"
@@ -2246,13 +2495,16 @@ Output:
2246
2495
  "id": "getDiff",
2247
2496
  "task": "Get PR diff",
2248
2497
  "tools": ["github_get_diff"],
2249
- "output": "diff"
2498
+ "output": "diff",
2499
+ "timeout": 10000,
2500
+ "expected_outcome": "Returns the unified diff string for the PR"
2250
2501
  },
2251
2502
  {
2252
2503
  "id": "analyze",
2253
- "task": "Analyze the diff",
2254
- "tools": ["generateText"],
2255
- "output": "analysis"
2504
+ "task": "Analyze the diff and provide feedback",
2505
+ "tools": ["runAgent"],
2506
+ "output": "analysis",
2507
+ "expected_outcome": "Returns { summary, issues, suggestions } object with review feedback"
2256
2508
  }
2257
2509
  ],
2258
2510
  "output": "analysis"
@@ -2260,77 +2512,130 @@ Output:
2260
2512
  }
2261
2513
  }
2262
2514
  \`\`\`
2515
+
2516
+ Example 3 - File processing with conditional logic:
2517
+ User: "Process all JSON files in a directory, validate them, and generate a report."
2518
+ Output:
2519
+ \`\`\`json
2520
+ {
2521
+ "workflows": {
2522
+ "main": {
2523
+ "task": "Process and validate JSON files, then generate a report",
2524
+ "inputs": [
2525
+ { "id": "directory", "description": "Directory containing JSON files", "default": "data" }
2526
+ ],
2527
+ "steps": [
2528
+ {
2529
+ "id": "listJsonFiles",
2530
+ "task": "List all JSON files in the directory",
2531
+ "tools": ["listFiles"],
2532
+ "output": "jsonFiles",
2533
+ "timeout": 5000,
2534
+ "expected_outcome": "Returns array of file paths ending in .json"
2535
+ },
2536
+ {
2537
+ "id": "processFiles",
2538
+ "task": "Process each JSON file using the processFile sub-workflow",
2539
+ "tools": [],
2540
+ "output": "processedResults",
2541
+ "expected_outcome": "Returns array of { file, valid, errors?, data? } for each file"
2542
+ },
2543
+ {
2544
+ "id": "generateReport",
2545
+ "task": "Generate a summary report of all processed files",
2546
+ "tools": ["writeToFile"],
2547
+ "output": "reportPath",
2548
+ "expected_outcome": "Writes report to 'report.md' and returns the file path"
2549
+ }
2550
+ ],
2551
+ "output": "reportPath"
2552
+ },
2553
+ "processFile": {
2554
+ "task": "Process and validate a single JSON file",
2555
+ "inputs": [
2556
+ { "id": "filePath", "description": "Path to the JSON file" }
2557
+ ],
2558
+ "steps": [
2559
+ {
2560
+ "id": "readFile",
2561
+ "task": "Read the JSON file content",
2562
+ "tools": ["readFile"],
2563
+ "output": "content",
2564
+ "timeout": 3000,
2565
+ "expected_outcome": "Returns file content as string, or null if not found"
2566
+ },
2567
+ {
2568
+ "id": "validateJson",
2569
+ "task": "Parse and validate the JSON structure",
2570
+ "tools": [],
2571
+ "output": "validationResult",
2572
+ "expected_outcome": "Returns { valid: boolean, data?: object, errors?: string[] }"
2573
+ }
2574
+ ],
2575
+ "output": "validationResult"
2576
+ }
2577
+ }
2578
+ }
2579
+ \`\`\`
2263
2580
  `;
2581
+ var WORKFLOW_IMPLEMENTATION_GUIDELINES = composeImplementationGuidelines();
2264
2582
  var WORKFLOW_CODE_SYSTEM_PROMPT = `You are an expert TypeScript developer.
2265
2583
  Your task is to implement the TypeScript code for the steps in the provided workflow definition.
2266
2584
 
2267
2585
  You will receive a JSON workflow definition where the "code" field is null.
2268
2586
  You must fill in the "code" field for each step with valid TypeScript code.
2269
2587
 
2270
- The code will be executed in an async function with the following signature:
2271
- async (ctx) => {
2272
- // Your code here
2273
- }
2588
+ CRITICAL: Each step "code" field must contain ONLY the function body statements (the code inside the curly braces).
2589
+ DO NOT include function declaration, arrow function syntax, async keyword, parameter list, or outer curly braces.
2274
2590
 
2275
- The \`ctx\` object provides access to:
2276
- - \`ctx.input\`: The workflow inputs.
2277
- - \`ctx.state\`: A shared state object for passing data between steps.
2278
- - \`ctx.tools\`: An object containing available tools.
2279
- - \`ctx.runWorkflow\`: (workflowId: string, input?: any) => Promise<any>. Use this to run other workflows.
2280
-
2281
- Guidelines:
2282
- - Use \`await\` for asynchronous operations.
2283
- - Return the output value of the step.
2284
- - Access inputs via \`ctx.input.inputName\`.
2285
- - Access previous step outputs via \`ctx.state.stepOutputName\`.
2286
- - Use \`ctx.tools.invokeTool({ toolName: 'name', input: { ... } })\` to call tools.
2287
- - Use \`ctx.tools.generateText({ messages: [...] })\` for LLM calls.
2288
- - Use \`ctx.tools.invokeTool({ toolName: 'runAgent', input: { prompt: '...' } })\` for complex sub-tasks that require multiple steps or tools. Prefer this over \`generateText\` for advanced tasks.
2289
-
2290
- Example Code for a step:
2291
- \`\`\`typescript
2292
- const searchResults = await ctx.tools.invokeTool({
2293
- toolName: 'search',
2294
- input: { query: ctx.input.topic }
2295
- });
2296
- return searchResults;
2297
- \`\`\`
2591
+ Prefer using \`ctx.tools.runAgent\` for complex tasks or when multiple steps/tools are needed. Use \`ctx.agentTools\` for direct tool usage (e.g. \`ctx.agentTools.readFile\`).
2298
2592
 
2299
- Example Code for LLM step:
2300
- \`\`\`typescript
2301
- const summary = await ctx.tools.generateText({
2302
- messages: [
2303
- { role: 'system', content: 'Summarize the following text.' },
2304
- { role: 'user', content: ctx.state.searchResults }
2305
- ]
2306
- });
2307
- return summary;
2308
- \`\`\`
2593
+ The code will be wrapped automatically in: \`async (ctx) => { YOUR_CODE_HERE }\`
2309
2594
 
2310
- Example Code for runAgent:
2311
- \`\`\`typescript
2312
- const result = await ctx.tools.invokeTool({
2313
- toolName: 'runAgent',
2314
- input: {
2315
- prompt: 'Research the history of the internet and write a summary.',
2316
- tools: ['search', 'generateText']
2317
- }
2318
- });
2319
- return result;
2595
+ Example of CORRECT code field:
2596
+ \`\`\`ts
2597
+ const result = await ctx.agentTools.readFile({ path: 'README.md' })
2598
+ if (!result) throw new Error('File not found')
2599
+ return result
2320
2600
  \`\`\`
2321
2601
 
2322
- Example Code for invoking a sub-workflow:
2323
- \`\`\`typescript
2324
- const results = [];
2325
- for (const pr of ctx.state.prs) {
2326
- const review = await ctx.runWorkflow('reviewPR', { prId: pr.id });
2327
- results.push(review);
2602
+ Example of INCORRECT code field (DO NOT DO THIS):
2603
+ \`\`\`ts
2604
+ async (ctx) => {
2605
+ const result = await ctx.agentTools.readFile({ path: 'README.md' })
2606
+ return result
2328
2607
  }
2329
- return results;
2330
2608
  \`\`\`
2331
2609
 
2610
+ ${WORKFLOW_IMPLEMENTATION_GUIDELINES}
2611
+
2612
+ ## Final Instructions
2613
+
2614
+ ${CODE_FIELD_CONSTRAINTS}
2615
+
2332
2616
  Return the complete workflow JSON with the "code" fields populated.
2333
2617
  `;
2618
+ var WORKFLOW_REVIEW_SYSTEM_PROMPT = `You are an expert TypeScript Code Reviewer.
2619
+ Your task is to review the provided workflow definition and its implemented code, and improve it to meet the highest quality standards.
2620
+
2621
+ You will receive a JSON workflow definition where the "code" fields are already populated.
2622
+ You must review each step's code and improve it if necessary.
2623
+
2624
+ Check for:
2625
+ - Correct usage of \`ctx.agentTools\` (for standard tools) and \`ctx.tools\` (for workflow helpers).
2626
+ - Proper error handling (try-catch, input validation).
2627
+ - Meaningful logging.
2628
+ - Adherence to the Quality Guidelines.
2629
+ - Correct syntax (no outer function wrappers).
2630
+
2631
+ ${QUALITY_GUIDELINES}
2632
+
2633
+ ## Final Instructions
2634
+
2635
+ Return the complete workflow JSON with the "code" fields improved where necessary.
2636
+ Ensure the "code" field still contains ONLY the function body statements.
2637
+ `;
2638
+ var MAX_GENERATION_ATTEMPTS = 3;
2334
2639
  var generateWorkflowDefinitionWorkflow = async (input, ctx) => {
2335
2640
  let systemPrompt = WORKFLOW_DEFINITION_SYSTEM_PROMPT;
2336
2641
  if (input.availableTools && input.availableTools.length > 0) {
@@ -2353,27 +2658,81 @@ Use these tools when appropriate.`;
2353
2658
  ctx
2354
2659
  );
2355
2660
  });
2356
- if (result.type === "Exit" && result.object) {
2357
- return result.object;
2358
- }
2359
- throw new Error("Failed to generate workflow definition");
2661
+ if (result.type !== "Exit" || !result.object) {
2662
+ throw new Error("Failed to generate workflow definition");
2663
+ }
2664
+ const workflow = result.object;
2665
+ await ctx.step("validate-workflow-definition", async () => {
2666
+ const validation = validateWorkflowDefinition(workflow);
2667
+ if (!validation.valid) {
2668
+ ctx.logger.warn(`Workflow definition validation warnings: ${validation.errors.join("; ")}`);
2669
+ }
2670
+ return validation;
2671
+ });
2672
+ return workflow;
2360
2673
  };
2361
2674
  var generateWorkflowCodeWorkflow = async (input, ctx) => {
2362
- const result = await ctx.step("generate-workflow-code", async () => {
2363
- return agentWorkflow(
2364
- {
2365
- systemPrompt: WORKFLOW_CODE_SYSTEM_PROMPT,
2366
- userMessage: [{ role: "user", content: JSON.stringify(input.workflow, null, 2) }],
2367
- tools: [],
2368
- outputSchema: WorkflowFileSchema
2369
- },
2370
- ctx
2371
- );
2372
- });
2373
- if (result.type === "Exit" && result.object) {
2374
- return result.object;
2675
+ let lastError = null;
2676
+ let currentWorkflow = input.workflow;
2677
+ for (let attempt = 0; attempt < MAX_GENERATION_ATTEMPTS; attempt++) {
2678
+ const stepName = attempt === 0 ? "generate-workflow-code" : `retry-workflow-code-${attempt}`;
2679
+ const userMessage = lastError ? `Previous attempt had issues: ${lastError}
2680
+
2681
+ Please fix the problems in this workflow:
2682
+ ${JSON.stringify(currentWorkflow, null, 2)}` : JSON.stringify(currentWorkflow, null, 2);
2683
+ const generated = await ctx.step(stepName, async () => {
2684
+ return agentWorkflow(
2685
+ {
2686
+ systemPrompt: WORKFLOW_CODE_SYSTEM_PROMPT,
2687
+ userMessage: [{ role: "user", content: userMessage }],
2688
+ tools: [],
2689
+ outputSchema: WorkflowFileSchema
2690
+ },
2691
+ ctx
2692
+ );
2693
+ });
2694
+ if (generated.type !== "Exit" || !generated.object) {
2695
+ lastError = "Failed to generate workflow code";
2696
+ continue;
2697
+ }
2698
+ const generatedWorkflow = generated.object;
2699
+ const syntaxValidation = await ctx.step(`validate-code-syntax-${attempt}`, async () => {
2700
+ return validateWorkflowCodeSyntax(generatedWorkflow);
2701
+ });
2702
+ if (!syntaxValidation.valid) {
2703
+ lastError = syntaxValidation.errors.join("; ");
2704
+ currentWorkflow = generatedWorkflow;
2705
+ ctx.logger.warn(`Code syntax validation failed (attempt ${attempt + 1}): ${lastError}`);
2706
+ continue;
2707
+ }
2708
+ if (input.skipReview) {
2709
+ return generatedWorkflow;
2710
+ }
2711
+ const reviewed = await ctx.step("review-workflow-code", async () => {
2712
+ return agentWorkflow(
2713
+ {
2714
+ systemPrompt: WORKFLOW_REVIEW_SYSTEM_PROMPT,
2715
+ userMessage: [{ role: "user", content: JSON.stringify(generatedWorkflow, null, 2) }],
2716
+ tools: [],
2717
+ outputSchema: WorkflowFileSchema
2718
+ },
2719
+ ctx
2720
+ );
2721
+ });
2722
+ if (reviewed.type !== "Exit" || !reviewed.object) {
2723
+ throw new Error("Failed to review workflow code");
2724
+ }
2725
+ const reviewedWorkflow = reviewed.object;
2726
+ const reviewSyntaxValidation = await ctx.step("validate-reviewed-code-syntax", async () => {
2727
+ return validateWorkflowCodeSyntax(reviewedWorkflow);
2728
+ });
2729
+ if (!reviewSyntaxValidation.valid) {
2730
+ ctx.logger.warn(`Reviewed code has syntax issues: ${reviewSyntaxValidation.errors.join("; ")}`);
2731
+ return generatedWorkflow;
2732
+ }
2733
+ return reviewedWorkflow;
2375
2734
  }
2376
- throw new Error("Failed to generate workflow code");
2735
+ throw new Error(`Failed to generate valid workflow code after ${MAX_GENERATION_ATTEMPTS} attempts: ${lastError}`);
2377
2736
  };
2378
2737
 
2379
2738
  // src/workflow/json-ai-types.ts
@@ -2577,10 +2936,10 @@ export {
2577
2936
  GenerateWorkflowCodeInputSchema,
2578
2937
  GenerateWorkflowDefinitionInputSchema,
2579
2938
  MockProvider,
2939
+ TOOL_GROUPS,
2580
2940
  TaskEventKind,
2581
2941
  TodoItemSchema,
2582
2942
  TodoStatus,
2583
- ToolResponseType,
2584
2943
  UpdateTodoItemInputSchema,
2585
2944
  UpdateTodoItemOutputSchema,
2586
2945
  UsageMeter,
@@ -2599,17 +2958,13 @@ export {
2599
2958
  fromJsonModelMessage,
2600
2959
  generateWorkflowCodeWorkflow,
2601
2960
  generateWorkflowDefinitionWorkflow,
2602
- getTodoItem_default as getTodoItem,
2603
2961
  listFiles_default as listFiles,
2604
- listMemoryTopics_default as listMemoryTopics,
2605
- listTodoItems_default as listTodoItems,
2606
2962
  makeStepFn,
2607
2963
  parseDynamicWorkflowDefinition,
2608
2964
  parseJsonFromMarkdown,
2609
2965
  providerModelSchema,
2610
2966
  readBinaryFile_default as readBinaryFile,
2611
2967
  readFile_default as readFile,
2612
- readMemory_default as readMemory,
2613
2968
  removeFile_default as removeFile,
2614
2969
  renameFile_default as renameFile,
2615
2970
  replaceInFile_default as replaceInFile,
@@ -2619,7 +2974,7 @@ export {
2619
2974
  search_default as search,
2620
2975
  searchFiles_default as searchFiles,
2621
2976
  toJsonModelMessage,
2622
- updateMemory_default as updateMemory,
2623
- updateTodoItem_default as updateTodoItem,
2977
+ validateWorkflowCodeSyntax,
2978
+ validateWorkflowDefinition,
2624
2979
  writeToFile_default as writeToFile
2625
2980
  };