@polka-codes/core 0.9.80 → 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,53 +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(),
1934
1668
  /**
1935
1669
  * Optional timeout in milliseconds. Step execution will be aborted if it exceeds this duration.
1936
1670
  */
1937
- timeout: z21.number().positive().nullish()
1671
+ timeout: z16.number().positive().nullish()
1938
1672
  });
1939
- var WorkflowDefinitionSchema = z21.object({
1940
- task: z21.string(),
1941
- inputs: z21.array(WorkflowInputDefinitionSchema).nullish(),
1942
- steps: z21.array(WorkflowStepDefinitionSchema),
1943
- 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()
1944
1678
  });
1945
- var WorkflowFileSchema = z21.object({
1946
- workflows: z21.record(z21.string(), WorkflowDefinitionSchema)
1679
+ var WorkflowFileSchema = z16.object({
1680
+ workflows: z16.record(z16.string(), WorkflowDefinitionSchema)
1947
1681
  });
1948
1682
 
1949
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
+ };
1950
1689
  function parseDynamicWorkflowDefinition(source) {
1951
1690
  try {
1952
1691
  const raw = parse(source);
1953
1692
  const validated = WorkflowFileSchema.safeParse(raw);
1954
1693
  if (!validated.success) {
1955
- return { success: false, error: z22.prettifyError(validated.error) };
1694
+ return { success: false, error: z17.prettifyError(validated.error) };
1956
1695
  }
1957
1696
  return { success: true, definition: validated.data };
1958
1697
  } catch (error) {
@@ -2025,18 +1764,42 @@ async function executeStepWithAgent(stepDef, workflowId, input, state, context,
2025
1764
  `Step '${stepDef.id}' in workflow '${workflowId}' requires agent execution, but no toolInfo was provided to DynamicWorkflowRunner.`
2026
1765
  );
2027
1766
  }
2028
- const allowedToolNames = stepDef.tools;
2029
- const toolsForAgent = allowedToolNames ? options.toolInfo.filter((t) => allowedToolNames.includes(t.name)) : [...options.toolInfo];
2030
- 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")) {
2031
1794
  toolsForAgent.push({
2032
1795
  name: "runWorkflow",
2033
1796
  description: "Run a named sub-workflow defined in the current workflow file.",
2034
- parameters: z22.object({
2035
- workflowId: z22.string().describe("Sub-workflow id to run"),
2036
- 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")
2037
1800
  }),
2038
1801
  handler: async () => {
2039
- return { type: "Error" /* Error */, message: { type: "error-text", value: "runWorkflow is virtual." } };
1802
+ return { success: false, message: { type: "error-text", value: "runWorkflow is virtual." } };
2040
1803
  }
2041
1804
  });
2042
1805
  }
@@ -2066,7 +1829,7 @@ async function executeStepWithAgent(stepDef, workflowId, input, state, context,
2066
1829
  invokeTool: async ({ toolName, input: toolInput }) => {
2067
1830
  if (!allowedToolNameSet.has(toolName)) {
2068
1831
  return {
2069
- type: "Error" /* Error */,
1832
+ success: false,
2070
1833
  message: { type: "error-text", value: `Tool '${toolName}' is not allowed in this step.` }
2071
1834
  };
2072
1835
  }
@@ -2075,17 +1838,17 @@ async function executeStepWithAgent(stepDef, workflowId, input, state, context,
2075
1838
  const subInput = toolInput?.input;
2076
1839
  if (typeof subWorkflowId !== "string") {
2077
1840
  return {
2078
- type: "Error" /* Error */,
1841
+ success: false,
2079
1842
  message: { type: "error-text", value: "runWorkflow.workflowId must be a string." }
2080
1843
  };
2081
1844
  }
2082
1845
  try {
2083
1846
  const output = await runWorkflow(subWorkflowId, subInput);
2084
1847
  const jsonResult = { type: "json", value: output };
2085
- return { type: "Reply" /* Reply */, message: jsonResult };
1848
+ return { success: true, message: jsonResult };
2086
1849
  } catch (error) {
2087
1850
  return {
2088
- type: "Error" /* Error */,
1851
+ success: false,
2089
1852
  message: { type: "error-text", value: error instanceof Error ? error.message : String(error) }
2090
1853
  };
2091
1854
  }
@@ -2131,6 +1894,14 @@ async function executeStepWithTimeout(stepDef, workflowId, input, state, context
2131
1894
  context.logger.debug(`[Step] Executing step '${stepDef.id}' with compiled code`);
2132
1895
  const fn = compileStep(stepDef, workflowId, compiledSteps);
2133
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
+ }
2134
1905
  const runtimeCtx = {
2135
1906
  workflowId,
2136
1907
  stepId: stepDef.id,
@@ -2140,7 +1911,8 @@ async function executeStepWithTimeout(stepDef, workflowId, input, state, context
2140
1911
  logger: context.logger,
2141
1912
  step: context.step,
2142
1913
  runWorkflow,
2143
- toolInfo: options.toolInfo
1914
+ toolInfo: options.toolInfo,
1915
+ agentTools
2144
1916
  };
2145
1917
  const result2 = await fn(runtimeCtx);
2146
1918
  context.logger.debug(`[Step] Compiled code execution completed for step '${stepDef.id}'`);
@@ -2172,7 +1944,7 @@ async function executeStep(stepDef, workflowId, input, state, context, options,
2172
1944
  const result = await executeStepWithTimeout(stepDef, workflowId, input, state, context, options, compiledSteps, runInternal);
2173
1945
  if (stepDef.outputSchema) {
2174
1946
  try {
2175
- const _schema = z22.any();
1947
+ const _schema = z17.any();
2176
1948
  if (typeof stepDef.outputSchema === "object") {
2177
1949
  context.logger.debug(`[Step] Validating output for step '${stepDef.id}' against schema`);
2178
1950
  if (stepDef.outputSchema.type === "object") {
@@ -2245,19 +2017,362 @@ function createDynamicWorkflow(definition, options = {}) {
2245
2017
  }
2246
2018
 
2247
2019
  // src/workflow/dynamic-generator.workflow.ts
2248
- import { z as z23 } from "zod";
2249
- var GenerateWorkflowDefinitionInputSchema = z23.object({
2250
- prompt: z23.string(),
2251
- availableTools: z23.array(
2252
- z23.object({
2253
- name: z23.string(),
2254
- 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()
2255
2335
  })
2256
- ).optional()
2336
+ ).nullish()
2257
2337
  });
2258
- var GenerateWorkflowCodeInputSchema = z23.object({
2259
- workflow: WorkflowFileSchema
2338
+ var GenerateWorkflowCodeInputSchema = z18.object({
2339
+ workflow: WorkflowFileSchema,
2340
+ skipReview: z18.boolean().nullish()
2260
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
+ }
2261
2376
  var WORKFLOW_DEFINITION_SYSTEM_PROMPT = `You are an expert workflow architect.
2262
2377
  Your task is to create a JSON workflow definition based on the user's request.
2263
2378
 
@@ -2273,10 +2388,10 @@ The workflow definition must follow this structure:
2273
2388
  {
2274
2389
  "id": "stepId",
2275
2390
  "task": "Description of the step",
2276
- "tools": ["toolName1", "toolName2"], // Optional: restrict which tools can be used
2391
+ "tools": ["toolName1", "toolName2"], // Optional: restrict which tools can be used. Can use groups: "readonly", "readwrite", "internet", "all".
2277
2392
  "output": "outputVariableName", // Optional: defaults to step id
2278
2393
  "timeout": 30000, // Optional: timeout in milliseconds
2279
- "expected_outcome": "What this step produces", // Optional: documentation
2394
+ "expected_outcome": "What this step produces", // Optional: documentation for expected results
2280
2395
  "outputSchema": { "type": "object" } // Optional: validation schema
2281
2396
  }
2282
2397
  ],
@@ -2293,14 +2408,22 @@ Constraints:
2293
2408
 
2294
2409
  Quality Guidelines:
2295
2410
  - Add "timeout" field (in milliseconds) for steps that might take long (file I/O, API calls, searches)
2296
- - Use "expected_outcome" field to document what each step should produce
2411
+ - Use "expected_outcome" field to document what each step should produce and its format
2297
2412
  - Use descriptive step IDs (e.g., "validateInput", "fetchUserData", not "step1", "step2")
2298
2413
  - Design steps to be focused - one responsibility per step
2299
2414
  - For steps that process multiple items, consider creating a sub-workflow
2300
2415
  - Add "outputSchema" with type information for validation-critical steps
2301
2416
  - Order steps logically with clear data flow
2302
2417
 
2303
- Example 1:
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:
2304
2427
  User: "Research a topic and summarize it."
2305
2428
  Output:
2306
2429
  \`\`\`json
@@ -2316,13 +2439,16 @@ Output:
2316
2439
  "id": "search",
2317
2440
  "task": "Search for information about the topic",
2318
2441
  "tools": ["search"],
2319
- "output": "searchResults"
2442
+ "output": "searchResults",
2443
+ "timeout": 30000,
2444
+ "expected_outcome": "Returns search results with titles, URLs, and snippets related to the topic"
2320
2445
  },
2321
2446
  {
2322
2447
  "id": "summarize",
2323
2448
  "task": "Summarize the search results",
2324
- "tools": ["generateText"],
2325
- "output": "summary"
2449
+ "tools": ["runAgent"],
2450
+ "output": "summary",
2451
+ "expected_outcome": "Returns a concise summary string (2-3 paragraphs) of the key findings"
2326
2452
  }
2327
2453
  ],
2328
2454
  "output": "summary"
@@ -2331,7 +2457,7 @@ Output:
2331
2457
  }
2332
2458
  \`\`\`
2333
2459
 
2334
- Example 2:
2460
+ Example 2 - PR review workflow with sub-workflow:
2335
2461
  User: "Review urgent PRs. For each PR, run the review workflow."
2336
2462
  Output:
2337
2463
  \`\`\`json
@@ -2345,13 +2471,16 @@ Output:
2345
2471
  "id": "fetchPRs",
2346
2472
  "task": "Fetch list of urgent PRs",
2347
2473
  "tools": ["github_list_prs"],
2348
- "output": "prs"
2474
+ "output": "prs",
2475
+ "timeout": 15000,
2476
+ "expected_outcome": "Returns array of PR objects with { id, title, author, url }"
2349
2477
  },
2350
2478
  {
2351
2479
  "id": "reviewEachPR",
2352
2480
  "task": "Run review workflow for each PR",
2353
2481
  "tools": [],
2354
- "output": "reviews"
2482
+ "output": "reviews",
2483
+ "expected_outcome": "Returns array of review results, one per PR"
2355
2484
  }
2356
2485
  ],
2357
2486
  "output": "reviews"
@@ -2366,13 +2495,16 @@ Output:
2366
2495
  "id": "getDiff",
2367
2496
  "task": "Get PR diff",
2368
2497
  "tools": ["github_get_diff"],
2369
- "output": "diff"
2498
+ "output": "diff",
2499
+ "timeout": 10000,
2500
+ "expected_outcome": "Returns the unified diff string for the PR"
2370
2501
  },
2371
2502
  {
2372
2503
  "id": "analyze",
2373
- "task": "Analyze the diff",
2374
- "tools": ["generateText"],
2375
- "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"
2376
2508
  }
2377
2509
  ],
2378
2510
  "output": "analysis"
@@ -2380,7 +2512,73 @@ Output:
2380
2512
  }
2381
2513
  }
2382
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
+ \`\`\`
2383
2580
  `;
2581
+ var WORKFLOW_IMPLEMENTATION_GUIDELINES = composeImplementationGuidelines();
2384
2582
  var WORKFLOW_CODE_SYSTEM_PROMPT = `You are an expert TypeScript developer.
2385
2583
  Your task is to implement the TypeScript code for the steps in the provided workflow definition.
2386
2584
 
@@ -2390,404 +2588,54 @@ You must fill in the "code" field for each step with valid TypeScript code.
2390
2588
  CRITICAL: Each step "code" field must contain ONLY the function body statements (the code inside the curly braces).
2391
2589
  DO NOT include function declaration, arrow function syntax, async keyword, parameter list, or outer curly braces.
2392
2590
 
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\`).
2592
+
2393
2593
  The code will be wrapped automatically in: \`async (ctx) => { YOUR_CODE_HERE }\`
2394
2594
 
2395
2595
  Example of CORRECT code field:
2396
- \`\`\`ts
2397
- const result = await ctx.tools.readFile({ path: 'README.md' })
2398
- if (!result) throw new Error('File not found')
2399
- return result
2400
- \`\`\`
2596
+ \`\`\`ts
2597
+ const result = await ctx.agentTools.readFile({ path: 'README.md' })
2598
+ if (!result) throw new Error('File not found')
2599
+ return result
2600
+ \`\`\`
2401
2601
 
2402
2602
  Example of INCORRECT code field (DO NOT DO THIS):
2403
- \`\`\`ts
2404
- async (ctx) => {
2405
- const result = await ctx.tools.readFile({ path: 'README.md' })
2406
- return result
2407
- }
2408
- \`\`\`
2603
+ \`\`\`ts
2604
+ async (ctx) => {
2605
+ const result = await ctx.agentTools.readFile({ path: 'README.md' })
2606
+ return result
2607
+ }
2608
+ \`\`\`
2409
2609
 
2410
- Example of INCORRECT code field (DO NOT DO THIS):
2411
- \`\`\`ts
2412
- (ctx) => {
2413
- return 'hello'
2414
- }
2415
- \`\`\`
2416
-
2417
- ## Runtime context (ctx)
2418
- \`\`\`ts
2419
- // Runtime types (for reference)
2420
- type Logger = {
2421
- debug: (...args: any[]) => void
2422
- info: (...args: any[]) => void
2423
- warn: (...args: any[]) => void
2424
- error: (...args: any[]) => void
2425
- }
2426
-
2427
- type StepFn = {
2428
- <T>(name: string, fn: () => Promise<T>): Promise<T>
2429
- <T>(name: string, options: { retry?: number }, fn: () => Promise<T>): Promise<T>
2430
- }
2431
-
2432
- type JsonModelMessage = { role: 'system' | 'user' | 'assistant' | 'tool'; content: any }
2433
- type JsonResponseMessage = { role: 'assistant' | 'tool'; content: any }
2434
- type ToolSet = Record<string, any>
2435
-
2436
- type ToolResponseResult =
2437
- | { type: 'text'; value: string }
2438
- | { type: 'json'; value: any }
2439
- | { type: 'error-text'; value: string }
2440
- | { type: 'error-json'; value: any }
2441
- | { type: 'content'; value: any[] }
2442
-
2443
- type AgentToolResponse =
2444
- | { type: 'Reply'; message: ToolResponseResult }
2445
- | { type: 'Exit'; message: string; object?: any }
2446
- | { type: 'Error'; message: ToolResponseResult }
2447
-
2448
- type ExitReason =
2449
- | { type: 'UsageExceeded' }
2450
- | { type: 'Exit'; message: string; object?: any }
2451
- | { type: 'Error'; error: { message: string; stack?: string } }
2452
-
2453
- type FullAgentToolInfo = { name: string; description: string; parameters: any; handler: any }
2454
-
2455
- // Tools available on ctx.tools in dynamic steps
2456
- type DynamicWorkflowTools = {
2457
- // LLM + agent helpers
2458
- generateText: (input: { messages: JsonModelMessage[]; tools: ToolSet }) => Promise<JsonResponseMessage[]>
2459
- runAgent: (input: {
2460
- tools: Readonly<FullAgentToolInfo[]>
2461
- maxToolRoundTrips?: number
2462
- userMessage: readonly JsonModelMessage[]
2463
- } & ({ messages: JsonModelMessage[] } | { systemPrompt: string })) => Promise<ExitReason>
2464
-
2465
- // Generic bridge to "agent tools" by name
2466
- invokeTool: (input: { toolName: string; input: any }) => Promise<AgentToolResponse>
2467
-
2468
- // File + command helpers (direct)
2469
- readFile: (input: { path: string }) => Promise<string | null>
2470
- writeToFile: (input: { path: string; content: string }) => Promise<void>
2471
- executeCommand: (input: { command: string; pipe?: boolean } & ({ args: string[]; shell?: false } | { shell: true })) => Promise<{
2472
- exitCode: number
2473
- stdout: string
2474
- stderr: string
2475
- }>
2476
-
2477
- // CLI UX helpers
2478
- confirm: (input: { message: string }) => Promise<boolean>
2479
- input: (input: { message: string; default?: string }) => Promise<string>
2480
- select: (input: { message: string; choices: { name: string; value: string }[] }) => Promise<string>
2481
- }
2482
-
2483
- type DynamicStepRuntimeContext = {
2484
- workflowId: string
2485
- stepId: string
2486
- input: Record<string, any>
2487
- state: Record<string, any>
2488
- tools: DynamicWorkflowTools
2489
- logger: Logger
2490
- step: StepFn
2491
- runWorkflow: (workflowId: string, input?: Record<string, any>) => Promise<any>
2492
- toolInfo?: ReadonlyArray<FullAgentToolInfo>
2493
- }
2494
- \`\`\`
2610
+ ${WORKFLOW_IMPLEMENTATION_GUIDELINES}
2495
2611
 
2496
- - \`ctx.input\`: workflow inputs (read-only).
2497
- - \`ctx.state\`: shared state between steps (previous step outputs are stored here).
2498
- - \`ctx.tools\`: async tool functions. Call tools as \`await ctx.tools.someTool({ ... })\`.
2499
- - \`ctx.runWorkflow\`: run a sub-workflow by id.
2500
-
2501
- ## Guidelines
2502
- - Use \`await\` for all async operations.
2503
- - Return the output value for the step (this becomes the step output).
2504
- - Access inputs via \`ctx.input.<inputId>\`.
2505
- - Access previous step outputs via \`ctx.state.<stepOutputKey>\` (defaults to the step \`output\` or \`id\`).
2506
-
2507
- ## Quality Guidelines for Code Implementation
2508
-
2509
- ### Error Handling
2510
- - ALWAYS validate inputs at the start of steps
2511
- - Use try-catch for operations that might fail (file I/O, parsing, API calls)
2512
- - Preserve stack traces: re-throw original errors rather than creating new ones
2513
- - Use error type guards: \`const err = error instanceof Error ? error : new Error(String(error))\`
2514
- - Check for null/undefined before using values
2515
- - Handle edge cases (empty arrays, missing files, invalid data)
2516
-
2517
- ### Logging
2518
- - Use \`ctx.logger.info()\` for important progress updates
2519
- - Use \`ctx.logger.debug()\` for detailed information
2520
- - Use \`ctx.logger.warn()\` for recoverable issues
2521
- - Use \`ctx.logger.error()\` before throwing errors
2522
- - Log when starting and completing significant operations
2523
- - Use template literals for readability: \`ctx.logger.info(\\\`Processing \${items.length} items...\\\`)\`
2524
-
2525
- ### User Experience
2526
- - Provide progress feedback for long operations
2527
- - Return structured data (objects/arrays), not strings when possible
2528
- - Include helpful metadata in results (counts, timestamps, status)
2529
- - For batch operations, report progress: \`Processed 5/10 items\`
2530
-
2531
- ### Data Validation
2532
- - Validate required fields exist before accessing
2533
- - Check data types match expectations
2534
- - Validate array lengths before iteration
2535
- - Example: \`if (!data?.users || !Array.isArray(data.users)) throw new Error('Invalid data format')\`
2536
-
2537
- ### Best Practices
2538
- - Use meaningful variable names
2539
- - Avoid nested callbacks - use async/await
2540
- - Clean up resources (close files, clear timeouts)
2541
- - Return consistent data structures across similar steps
2542
- - For iteration, consider batching or rate limiting
2543
-
2544
- ### When to Simplify
2545
- - Simple transformation steps (e.g., formatting strings) need only basic error handling
2546
- - Internal sub-workflow steps with validated inputs from parent can skip redundant validation
2547
- - Minimal logging is fine for fast steps (<100ms) that don't perform I/O or external calls
2548
- - Use judgment: match error handling complexity to the step's failure risk and impact
2549
-
2550
- ## Tool calling examples (every tool)
2551
-
2552
- ### Direct ctx.tools methods
2553
- \`\`\`ts
2554
- // readFile
2555
- const readme = await ctx.tools.readFile({ path: 'README.md' })
2556
- if (readme == null) throw new Error('README.md not found')
2557
-
2558
- // writeToFile
2559
- await ctx.tools.writeToFile({ path: 'notes.txt', content: 'hello\\n' })
2560
-
2561
- // executeCommand (args form)
2562
- const rg = await ctx.tools.executeCommand({ command: 'rg', args: ['-n', 'TODO', '.'] })
2563
- if (rg.exitCode !== 0) throw new Error(rg.stderr)
2564
-
2565
- // executeCommand (shell form)
2566
- await ctx.tools.executeCommand({ command: 'ls -la', shell: true, pipe: true })
2567
-
2568
- // generateText (LLM call; pass tools: {})
2569
- const msgs = await ctx.tools.generateText({
2570
- messages: [
2571
- { role: 'system', content: 'Summarize the following text.' },
2572
- { role: 'user', content: readme },
2573
- ],
2574
- tools: {},
2575
- })
2576
- const last = msgs[msgs.length - 1]
2577
- const lastText = typeof last?.content === 'string' ? last.content : JSON.stringify(last?.content)
2578
-
2579
- // runAgent (nested agent; use ctx.toolInfo as the tool list)
2580
- const agentRes = await ctx.tools.runAgent({
2581
- systemPrompt: 'You are a helpful assistant.',
2582
- userMessage: [{ role: 'user', content: 'Summarize README.md in 3 bullets.' }],
2583
- tools: (ctx.toolInfo ?? []) as any,
2584
- })
2585
- if (agentRes.type !== 'Exit') throw new Error('runAgent failed')
2586
-
2587
- // confirm / input / select (interactive)
2588
- const ok = await ctx.tools.confirm({ message: 'Proceed?' })
2589
- const name = await ctx.tools.input({ message: 'Name?', default: 'main' })
2590
- const flavor = await ctx.tools.select({
2591
- message: 'Pick one',
2592
- choices: [
2593
- { name: 'A', value: 'a' },
2594
- { name: 'B', value: 'b' },
2595
- ],
2596
- })
2597
-
2598
- \`\`\`
2599
-
2600
- ### Agent tools via ctx.tools.invokeTool (toolName examples)
2601
- \`\`\`ts
2602
- // Helper to unwrap a successful tool reply
2603
- function unwrapToolValue(resp: any) {
2604
- if (!resp || resp.type !== 'Reply') {
2605
- const msg = resp?.message?.value
2606
- throw new Error(typeof msg === 'string' ? msg : JSON.stringify(resp))
2607
- }
2608
- return resp.message.value
2609
- }
2610
-
2611
- // askFollowupQuestion
2612
- const answersText = unwrapToolValue(
2613
- await ctx.tools.invokeTool({
2614
- toolName: 'askFollowupQuestion',
2615
- input: { questions: [{ prompt: 'Which directory?', options: ['src', 'packages'] }] },
2616
- }),
2617
- )
2618
-
2619
- // listFiles
2620
- const filesText = unwrapToolValue(
2621
- await ctx.tools.invokeTool({
2622
- toolName: 'listFiles',
2623
- input: { path: 'src', recursive: true, maxCount: 2000, includeIgnored: false },
2624
- }),
2625
- )
2626
-
2627
- // searchFiles
2628
- const hitsText = unwrapToolValue(
2629
- await ctx.tools.invokeTool({
2630
- toolName: 'searchFiles',
2631
- input: { path: '.', regex: 'generateWorkflowCodeWorkflow', filePattern: '*.ts' },
2632
- }),
2633
- )
2634
-
2635
- // fetchUrl
2636
- const pageText = unwrapToolValue(await ctx.tools.invokeTool({ toolName: 'fetchUrl', input: { url: 'https://example.com' } }))
2637
-
2638
- // search (web search)
2639
- const webResults = unwrapToolValue(
2640
- await ctx.tools.invokeTool({ toolName: 'search', input: { query: 'TypeScript zod schema examples' } }),
2641
- )
2642
-
2643
- // executeCommand (provider-backed; may require approval in some environments)
2644
- const cmdText = unwrapToolValue(
2645
- await ctx.tools.invokeTool({ toolName: 'executeCommand', input: { command: 'bun test', requiresApproval: false } }),
2646
- )
2647
-
2648
- // readFile / writeToFile (provider-backed)
2649
- const fileText = unwrapToolValue(
2650
- await ctx.tools.invokeTool({ toolName: 'readFile', input: { path: 'README.md', includeIgnored: false } }),
2651
- )
2652
- const writeText = unwrapToolValue(await ctx.tools.invokeTool({ toolName: 'writeToFile', input: { path: 'out.txt', content: 'hi' } }))
2653
-
2654
- // replaceInFile
2655
- const diff = ['<<<<<<< SEARCH', 'old', '=======', 'new', '>>>>>>> REPLACE'].join('\\n')
2656
- const replaceText = unwrapToolValue(await ctx.tools.invokeTool({ toolName: 'replaceInFile', input: { path: 'out.txt', diff } }))
2657
-
2658
- // removeFile / renameFile
2659
- const rmText = unwrapToolValue(await ctx.tools.invokeTool({ toolName: 'removeFile', input: { path: 'out.txt' } }))
2660
- const mvText = unwrapToolValue(
2661
- await ctx.tools.invokeTool({ toolName: 'renameFile', input: { source_path: 'a.txt', target_path: 'b.txt' } }),
2662
- )
2663
-
2664
- // readBinaryFile (returns { type: 'content', value: [...] } in resp.message)
2665
- const binResp = await ctx.tools.invokeTool({ toolName: 'readBinaryFile', input: { url: 'file://path/to/image.png' } })
2666
- \`\`\`
2667
-
2668
- ### Sub-workflow example (ctx.runWorkflow)
2669
- \`\`\`ts
2670
- const results: any[] = []
2671
- for (const pr of ctx.state.prs ?? []) {
2672
- results.push(await ctx.runWorkflow('reviewPR', { prId: pr.id }))
2673
- }
2674
- return results
2675
- \`\`\`
2676
-
2677
- ## Complete Example: High-Quality Step Implementation
2678
-
2679
- This example demonstrates all quality guidelines in a single step:
2680
-
2681
- \`\`\`ts
2682
- // Step: processUserData
2683
- // Task: Read, validate, and process user data from a file
2684
-
2685
- // Input validation
2686
- if (!ctx.input.dataFile) {
2687
- throw new Error('Missing required input: dataFile')
2688
- }
2689
-
2690
- ctx.logger.info(\`Starting user data processing for: \${ctx.input.dataFile}\`)
2691
-
2692
- // Read file with error handling
2693
- let rawData
2694
- try {
2695
- ctx.logger.debug(\`Reading file: \${ctx.input.dataFile}\`)
2696
- rawData = await ctx.tools.readFile({ path: ctx.input.dataFile })
2697
-
2698
- if (!rawData) {
2699
- throw new Error(\`File not found or empty: \${ctx.input.dataFile}\`)
2700
- }
2701
- } catch (error) {
2702
- const err = error instanceof Error ? error : new Error(String(error))
2703
- ctx.logger.error(\`Failed to read file: \${err.message}\`)
2704
- throw err // Preserve original stack trace
2705
- }
2706
-
2707
- // Parse and validate data
2708
- let users
2709
- try {
2710
- ctx.logger.debug('Parsing JSON data')
2711
- const parsed = JSON.parse(rawData)
2712
-
2713
- if (!parsed?.users || !Array.isArray(parsed.users)) {
2714
- throw new Error('Invalid data format: expected {users: [...]}')
2715
- }
2716
-
2717
- users = parsed.users
2718
- ctx.logger.info(\`Found \${users.length} users to process\`)
2719
- } catch (error) {
2720
- const err = error instanceof Error ? error : new Error(String(error))
2721
- ctx.logger.error(\`Data parsing failed: \${err.message}\`)
2722
- throw err // Preserve original stack trace
2723
- }
2724
-
2725
- // Process each user with progress reporting
2726
- const results = []
2727
- for (let i = 0; i < users.length; i++) {
2728
- const user = users[i]
2729
-
2730
- // Validate each user object
2731
- if (!user?.id || !user?.email) {
2732
- ctx.logger.warn(\`Skipping invalid user at index \${i}: missing id or email\`)
2733
- continue
2734
- }
2735
-
2736
- // Process user
2737
- const processed = {
2738
- id: user.id,
2739
- email: user.email.toLowerCase().trim(),
2740
- name: user.name?.trim() || 'Unknown',
2741
- processedAt: new Date().toISOString(),
2742
- status: 'active'
2743
- }
2744
-
2745
- results.push(processed)
2746
-
2747
- // Progress feedback every 10 items
2748
- if ((i + 1) % 10 === 0) {
2749
- ctx.logger.info(\`Processed \${i + 1}/\${users.length} users\`)
2750
- }
2751
- }
2752
-
2753
- ctx.logger.info(\`Successfully processed \${results.length}/\${users.length} users\`)
2754
-
2755
- // Return structured result with metadata
2756
- return {
2757
- users: results,
2758
- metadata: {
2759
- totalInput: users.length,
2760
- totalProcessed: results.length,
2761
- skipped: users.length - results.length,
2762
- processedAt: new Date().toISOString()
2763
- }
2764
- }
2765
- \`\`\`
2766
-
2767
- Key features demonstrated:
2768
- - Input validation at start
2769
- - Comprehensive error handling with try-catch that preserves stack traces
2770
- - Logging at info, debug, warn, and error levels
2771
- - Progress reporting for long operations (every 10 items)
2772
- - Data validation throughout (null checks, type checks, array validation)
2773
- - Structured return value with metadata for observability
2774
- - Descriptive error messages with context
2775
- - Meaningful variable names (rawData, users, processed)
2776
- - Clean async/await usage
2777
- - Template literals for readable string interpolation
2778
- - Proper error type guards (error instanceof Error)
2779
-
2780
- ## Final Instructions
2781
-
2782
- REMEMBER: The "code" field must be ONLY the function body statements.
2783
- - DO NOT wrap code in arrow functions: \`(ctx) => { ... }\`
2784
- - DO NOT wrap code in async functions: \`async (ctx) => { ... }\`
2785
- - DO NOT include outer curly braces
2786
- - DO include a return statement if the step should produce output
2787
- - Each "code" field should be a string containing multiple statements separated by newlines
2788
-
2789
- Return the complete workflow JSON with the "code" fields populated.
2790
- `;
2612
+ ## Final Instructions
2613
+
2614
+ ${CODE_FIELD_CONSTRAINTS}
2615
+
2616
+ Return the complete workflow JSON with the "code" fields populated.
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;
2791
2639
  var generateWorkflowDefinitionWorkflow = async (input, ctx) => {
2792
2640
  let systemPrompt = WORKFLOW_DEFINITION_SYSTEM_PROMPT;
2793
2641
  if (input.availableTools && input.availableTools.length > 0) {
@@ -2810,27 +2658,81 @@ Use these tools when appropriate.`;
2810
2658
  ctx
2811
2659
  );
2812
2660
  });
2813
- if (result.type === "Exit" && result.object) {
2814
- return result.object;
2815
- }
2816
- 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;
2817
2673
  };
2818
2674
  var generateWorkflowCodeWorkflow = async (input, ctx) => {
2819
- const result = await ctx.step("generate-workflow-code", async () => {
2820
- return agentWorkflow(
2821
- {
2822
- systemPrompt: WORKFLOW_CODE_SYSTEM_PROMPT,
2823
- userMessage: [{ role: "user", content: JSON.stringify(input.workflow, null, 2) }],
2824
- tools: [],
2825
- outputSchema: WorkflowFileSchema
2826
- },
2827
- ctx
2828
- );
2829
- });
2830
- if (result.type === "Exit" && result.object) {
2831
- 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;
2832
2734
  }
2833
- throw new Error("Failed to generate workflow code");
2735
+ throw new Error(`Failed to generate valid workflow code after ${MAX_GENERATION_ATTEMPTS} attempts: ${lastError}`);
2834
2736
  };
2835
2737
 
2836
2738
  // src/workflow/json-ai-types.ts
@@ -3034,10 +2936,10 @@ export {
3034
2936
  GenerateWorkflowCodeInputSchema,
3035
2937
  GenerateWorkflowDefinitionInputSchema,
3036
2938
  MockProvider,
2939
+ TOOL_GROUPS,
3037
2940
  TaskEventKind,
3038
2941
  TodoItemSchema,
3039
2942
  TodoStatus,
3040
- ToolResponseType,
3041
2943
  UpdateTodoItemInputSchema,
3042
2944
  UpdateTodoItemOutputSchema,
3043
2945
  UsageMeter,
@@ -3056,17 +2958,13 @@ export {
3056
2958
  fromJsonModelMessage,
3057
2959
  generateWorkflowCodeWorkflow,
3058
2960
  generateWorkflowDefinitionWorkflow,
3059
- getTodoItem_default as getTodoItem,
3060
2961
  listFiles_default as listFiles,
3061
- listMemoryTopics_default as listMemoryTopics,
3062
- listTodoItems_default as listTodoItems,
3063
2962
  makeStepFn,
3064
2963
  parseDynamicWorkflowDefinition,
3065
2964
  parseJsonFromMarkdown,
3066
2965
  providerModelSchema,
3067
2966
  readBinaryFile_default as readBinaryFile,
3068
2967
  readFile_default as readFile,
3069
- readMemory_default as readMemory,
3070
2968
  removeFile_default as removeFile,
3071
2969
  renameFile_default as renameFile,
3072
2970
  replaceInFile_default as replaceInFile,
@@ -3076,7 +2974,7 @@ export {
3076
2974
  search_default as search,
3077
2975
  searchFiles_default as searchFiles,
3078
2976
  toJsonModelMessage,
3079
- updateMemory_default as updateMemory,
3080
- updateTodoItem_default as updateTodoItem,
2977
+ validateWorkflowCodeSyntax,
2978
+ validateWorkflowDefinition,
3081
2979
  writeToFile_default as writeToFile
3082
2980
  };