@polka-codes/cli 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.
Files changed (2) hide show
  1. package/dist/index.js +1020 -868
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -37660,7 +37660,7 @@ var {
37660
37660
  Help
37661
37661
  } = import__.default;
37662
37662
  // package.json
37663
- var version = "0.9.80";
37663
+ var version = "0.9.81";
37664
37664
 
37665
37665
  // src/commands/code.ts
37666
37666
  import { readFile as readFile4 } from "node:fs/promises";
@@ -50382,12 +50382,6 @@ function date4(params) {
50382
50382
  // ../../node_modules/zod/v4/classic/external.js
50383
50383
  config(en_default());
50384
50384
  // ../core/src/config.ts
50385
- var providerModelSchema = exports_external.object({
50386
- provider: exports_external.string().optional(),
50387
- model: exports_external.string().optional(),
50388
- parameters: exports_external.record(exports_external.string(), exports_external.any()).optional(),
50389
- budget: exports_external.number().positive().optional()
50390
- });
50391
50385
  var ruleSchema = exports_external.union([
50392
50386
  exports_external.string(),
50393
50387
  exports_external.object({ path: exports_external.string() }).strict(),
@@ -50400,6 +50394,13 @@ var ruleSchema = exports_external.union([
50400
50394
  branch: exports_external.string().optional()
50401
50395
  }).strict()
50402
50396
  ]);
50397
+ var providerModelSchema = exports_external.object({
50398
+ provider: exports_external.string().optional(),
50399
+ model: exports_external.string().optional(),
50400
+ parameters: exports_external.record(exports_external.string(), exports_external.any()).optional(),
50401
+ budget: exports_external.number().positive().optional(),
50402
+ rules: exports_external.array(ruleSchema).optional().or(exports_external.string()).optional()
50403
+ });
50403
50404
  var configSchema = exports_external.object({
50404
50405
  prices: exports_external.record(exports_external.string(), exports_external.record(exports_external.string(), exports_external.object({
50405
50406
  inputPrice: exports_external.number().optional(),
@@ -50492,7 +50493,7 @@ var toolInfo = {
50492
50493
  var handler = async (provider, args) => {
50493
50494
  if (!provider.askFollowupQuestion) {
50494
50495
  return {
50495
- type: "Error" /* Error */,
50496
+ success: false,
50496
50497
  message: {
50497
50498
  type: "error-text",
50498
50499
  value: "Not possible to ask followup question."
@@ -50502,7 +50503,7 @@ var handler = async (provider, args) => {
50502
50503
  const { questions } = toolInfo.parameters.parse(args);
50503
50504
  if (questions.length === 0) {
50504
50505
  return {
50505
- type: "Error" /* Error */,
50506
+ success: false,
50506
50507
  message: {
50507
50508
  type: "error-text",
50508
50509
  value: "No questions provided"
@@ -50518,7 +50519,7 @@ ${answer}
50518
50519
  </ask_followup_question_answer>`);
50519
50520
  }
50520
50521
  return {
50521
- type: "Reply" /* Reply */,
50522
+ success: true,
50522
50523
  message: {
50523
50524
  type: "text",
50524
50525
  value: answers.join(`
@@ -50561,7 +50562,7 @@ var toolInfo2 = {
50561
50562
  var handler2 = async (provider, args) => {
50562
50563
  if (!provider.executeCommand) {
50563
50564
  return {
50564
- type: "Error" /* Error */,
50565
+ success: false,
50565
50566
  message: {
50566
50567
  type: "error-text",
50567
50568
  value: "Not possible to execute command. Abort."
@@ -50590,7 +50591,7 @@ ${result.stderr}
50590
50591
  }
50591
50592
  if (result.exitCode === 0) {
50592
50593
  return {
50593
- type: "Reply" /* Reply */,
50594
+ success: true,
50594
50595
  message: {
50595
50596
  type: "text",
50596
50597
  value: message
@@ -50598,7 +50599,7 @@ ${result.stderr}
50598
50599
  };
50599
50600
  }
50600
50601
  return {
50601
- type: "Error" /* Error */,
50602
+ success: false,
50602
50603
  message: {
50603
50604
  type: "error-text",
50604
50605
  value: message
@@ -50606,7 +50607,7 @@ ${result.stderr}
50606
50607
  };
50607
50608
  } catch (error46) {
50608
50609
  return {
50609
- type: "Error" /* Error */,
50610
+ success: false,
50610
50611
  message: {
50611
50612
  type: "error-text",
50612
50613
  value: error46 instanceof Error ? error46.message : String(error46)
@@ -50655,7 +50656,7 @@ var toolInfo3 = {
50655
50656
  var handler3 = async (provider, args) => {
50656
50657
  if (!provider.fetchUrl) {
50657
50658
  return {
50658
- type: "Error" /* Error */,
50659
+ success: false,
50659
50660
  message: {
50660
50661
  type: "error-text",
50661
50662
  value: "Not possible to fetch url."
@@ -50665,7 +50666,7 @@ var handler3 = async (provider, args) => {
50665
50666
  const { url: urls } = toolInfo3.parameters.parse(args);
50666
50667
  if (urls.length === 0) {
50667
50668
  return {
50668
- type: "Error" /* Error */,
50669
+ success: false,
50669
50670
  message: {
50670
50671
  type: "error-text",
50671
50672
  value: "No URLs provided. Please provide at least one URL to fetch."
@@ -50684,7 +50685,7 @@ var handler3 = async (provider, args) => {
50684
50685
  }
50685
50686
  const resolvedResults = await Promise.all(results);
50686
50687
  return {
50687
- type: "Reply" /* Reply */,
50688
+ success: true,
50688
50689
  message: {
50689
50690
  type: "text",
50690
50691
  value: resolvedResults.join(`
@@ -50696,40 +50697,8 @@ var fetchUrl_default = {
50696
50697
  ...toolInfo3,
50697
50698
  handler: handler3
50698
50699
  };
50699
- // ../core/src/tools/getTodoItem.ts
50700
- var toolInfo4 = {
50701
- name: "getTodoItem",
50702
- description: "Get a to-do item by its ID.",
50703
- parameters: exports_external.object({
50704
- id: exports_external.string().describe("The ID of the to-do item.")
50705
- })
50706
- };
50707
- var handler4 = async (provider, args) => {
50708
- if (!provider.getTodoItem) {
50709
- return {
50710
- type: "Error" /* Error */,
50711
- message: {
50712
- type: "error-text",
50713
- value: "Not possible to get a to-do item."
50714
- }
50715
- };
50716
- }
50717
- const { id } = toolInfo4.parameters.parse(args);
50718
- const item = await provider.getTodoItem(id);
50719
- return {
50720
- type: "Reply" /* Reply */,
50721
- message: {
50722
- type: "json",
50723
- value: item ?? null
50724
- }
50725
- };
50726
- };
50727
- var getTodoItem_default = {
50728
- ...toolInfo4,
50729
- handler: handler4
50730
- };
50731
50700
  // ../core/src/tools/listFiles.ts
50732
- var toolInfo5 = {
50701
+ var toolInfo4 = {
50733
50702
  name: "listFiles",
50734
50703
  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.",
50735
50704
  parameters: exports_external.object({
@@ -50767,20 +50736,20 @@ var toolInfo5 = {
50767
50736
  ]
50768
50737
  })
50769
50738
  };
50770
- var handler5 = async (provider, args) => {
50739
+ var handler4 = async (provider, args) => {
50771
50740
  if (!provider.listFiles) {
50772
50741
  return {
50773
- type: "Error" /* Error */,
50742
+ success: false,
50774
50743
  message: {
50775
50744
  type: "error-text",
50776
50745
  value: "Not possible to list files."
50777
50746
  }
50778
50747
  };
50779
50748
  }
50780
- const { path, maxCount, recursive, includeIgnored } = toolInfo5.parameters.parse(args);
50749
+ const { path, maxCount, recursive, includeIgnored } = toolInfo4.parameters.parse(args);
50781
50750
  const [files, limitReached] = await provider.listFiles(path, recursive, maxCount, includeIgnored);
50782
50751
  return {
50783
- type: "Reply" /* Reply */,
50752
+ success: true,
50784
50753
  message: {
50785
50754
  type: "text",
50786
50755
  value: `<list_files_path>${path}</list_files_path>
@@ -50793,128 +50762,32 @@ ${files.join(`
50793
50762
  };
50794
50763
  };
50795
50764
  var listFiles_default = {
50796
- ...toolInfo5,
50797
- handler: handler5
50798
- };
50799
- // ../core/src/tools/listMemoryTopics.ts
50800
- var toolInfo6 = {
50801
- name: "listMemoryTopics",
50802
- description: "Lists all topics in memory. Use this to see what information has been stored and which topics are available to read from.",
50803
- parameters: exports_external.object({})
50804
- };
50805
- var handler6 = async (provider, _args) => {
50806
- const topics = await provider.listMemoryTopics();
50807
- if (!topics.length) {
50808
- return { type: "Reply" /* Reply */, message: { type: "text", value: "No topics found." } };
50809
- }
50810
- return {
50811
- type: "Reply" /* Reply */,
50812
- message: {
50813
- type: "text",
50814
- value: `Memory topics:
50815
- ${topics.join(`
50816
- `)}`
50817
- }
50818
- };
50819
- };
50820
- var listMemoryTopics_default = {
50821
- ...toolInfo6,
50822
- handler: handler6
50823
- };
50824
- // ../core/src/tools/todo.ts
50825
- var TodoStatus = exports_external.enum(["open", "completed", "closed"]);
50826
- var TodoItemSchema = exports_external.object({
50827
- id: exports_external.string(),
50828
- title: exports_external.string(),
50829
- description: exports_external.string(),
50830
- status: TodoStatus
50831
- });
50832
- var UpdateTodoItemInputSchema = exports_external.object({
50833
- operation: exports_external.enum(["add", "update"]),
50834
- id: exports_external.string().nullish(),
50835
- parentId: exports_external.string().nullish(),
50836
- title: exports_external.string().nullish(),
50837
- description: exports_external.string().nullish(),
50838
- status: TodoStatus.nullish()
50839
- }).superRefine((data, ctx) => {
50840
- if (data.operation === "add") {
50841
- if (!data.title) {
50842
- ctx.addIssue({
50843
- code: "custom",
50844
- message: 'Title is required for "add" operation',
50845
- path: ["title"]
50846
- });
50847
- }
50848
- } else if (data.operation === "update") {
50849
- if (!data.id) {
50850
- ctx.addIssue({
50851
- code: "custom",
50852
- message: 'ID is required for "update" operation',
50853
- path: ["id"]
50854
- });
50855
- }
50856
- }
50857
- });
50858
- var UpdateTodoItemOutputSchema = exports_external.object({
50859
- id: exports_external.string()
50860
- });
50861
-
50862
- // ../core/src/tools/listTodoItems.ts
50863
- var toolInfo7 = {
50864
- name: "listTodoItems",
50865
- 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.",
50866
- parameters: exports_external.object({
50867
- id: exports_external.string().nullish(),
50868
- status: TodoStatus.nullish()
50869
- })
50870
- };
50871
- var handler7 = async (provider, args) => {
50872
- if (!provider.listTodoItems) {
50873
- return {
50874
- type: "Error" /* Error */,
50875
- message: {
50876
- type: "error-text",
50877
- value: "Not possible to list to-do items."
50878
- }
50879
- };
50880
- }
50881
- const { id, status } = toolInfo7.parameters.parse(args);
50882
- const items = await provider.listTodoItems(id, status);
50883
- return {
50884
- type: "Reply" /* Reply */,
50885
- message: {
50886
- type: "json",
50887
- value: items
50888
- }
50889
- };
50890
- };
50891
- var listTodoItems_default = {
50892
- ...toolInfo7,
50893
- handler: handler7
50765
+ ...toolInfo4,
50766
+ handler: handler4
50894
50767
  };
50895
50768
  // ../core/src/tools/readBinaryFile.ts
50896
- var toolInfo8 = {
50769
+ var toolInfo5 = {
50897
50770
  name: "readBinaryFile",
50898
50771
  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.",
50899
50772
  parameters: exports_external.object({
50900
50773
  url: exports_external.string().describe("The URL or local path of the file to read.")
50901
50774
  })
50902
50775
  };
50903
- var handler8 = async (provider, args) => {
50776
+ var handler5 = async (provider, args) => {
50904
50777
  if (!provider.readBinaryFile) {
50905
50778
  return {
50906
- type: "Error" /* Error */,
50779
+ success: false,
50907
50780
  message: {
50908
50781
  type: "error-text",
50909
50782
  value: "Not possible to fetch files. Abort."
50910
50783
  }
50911
50784
  };
50912
50785
  }
50913
- const { url: url2 } = toolInfo8.parameters.parse(args);
50786
+ const { url: url2 } = toolInfo5.parameters.parse(args);
50914
50787
  try {
50915
50788
  const filePart = await provider.readBinaryFile(url2);
50916
50789
  return {
50917
- type: "Reply" /* Reply */,
50790
+ success: true,
50918
50791
  message: {
50919
50792
  type: "content",
50920
50793
  value: [
@@ -50930,7 +50803,7 @@ var handler8 = async (provider, args) => {
50930
50803
  } catch (error46) {
50931
50804
  const errorMessage = error46 instanceof Error ? error46.message : "Unknown error";
50932
50805
  return {
50933
- type: "Error" /* Error */,
50806
+ success: false,
50934
50807
  message: {
50935
50808
  type: "error-text",
50936
50809
  value: `Error fetching file from ${url2}: ${errorMessage}`
@@ -50939,11 +50812,11 @@ var handler8 = async (provider, args) => {
50939
50812
  }
50940
50813
  };
50941
50814
  var readBinaryFile_default = {
50942
- ...toolInfo8,
50943
- handler: handler8
50815
+ ...toolInfo5,
50816
+ handler: handler5
50944
50817
  };
50945
50818
  // ../core/src/tools/readFile.ts
50946
- var toolInfo9 = {
50819
+ var toolInfo6 = {
50947
50820
  name: "readFile",
50948
50821
  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.",
50949
50822
  parameters: exports_external.object({
@@ -50980,17 +50853,17 @@ var toolInfo9 = {
50980
50853
  ]
50981
50854
  })
50982
50855
  };
50983
- var handler9 = async (provider, args) => {
50856
+ var handler6 = async (provider, args) => {
50984
50857
  if (!provider.readFile) {
50985
50858
  return {
50986
- type: "Error" /* Error */,
50859
+ success: false,
50987
50860
  message: {
50988
50861
  type: "error-text",
50989
50862
  value: "Not possible to read file."
50990
50863
  }
50991
50864
  };
50992
50865
  }
50993
- const { path: paths, includeIgnored } = toolInfo9.parameters.parse(args);
50866
+ const { path: paths, includeIgnored } = toolInfo6.parameters.parse(args);
50994
50867
  const resp = [];
50995
50868
  for (const path of paths) {
50996
50869
  const fileContent = await provider.readFile(path, includeIgnored ?? false);
@@ -51006,7 +50879,7 @@ var handler9 = async (provider, args) => {
51006
50879
  }
51007
50880
  }
51008
50881
  return {
51009
- type: "Reply" /* Reply */,
50882
+ success: true,
51010
50883
  message: {
51011
50884
  type: "text",
51012
50885
  value: resp.join(`
@@ -51015,45 +50888,11 @@ var handler9 = async (provider, args) => {
51015
50888
  };
51016
50889
  };
51017
50890
  var readFile_default = {
51018
- ...toolInfo9,
51019
- handler: handler9
51020
- };
51021
- // ../core/src/tools/readMemory.ts
51022
- var toolInfo10 = {
51023
- name: "readMemory",
51024
- 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.",
51025
- parameters: exports_external.object({
51026
- topic: exports_external.string().nullish().describe('The topic to read from memory. Defaults to ":default:".')
51027
- })
51028
- };
51029
- var handler10 = async (provider, args) => {
51030
- const { topic } = toolInfo10.parameters.parse(args);
51031
- const content = await provider.readMemory(topic ?? undefined);
51032
- if (content) {
51033
- return {
51034
- type: "Reply" /* Reply */,
51035
- message: {
51036
- type: "text",
51037
- value: `<memory${topic ? ` topic="${topic}"` : ""}>
51038
- ${content}
51039
- </memory>`
51040
- }
51041
- };
51042
- }
51043
- return {
51044
- type: "Reply" /* Reply */,
51045
- message: {
51046
- type: "text",
51047
- value: `<memory ${topic ? `topic="${topic}"` : ""} isEmpty="true" />`
51048
- }
51049
- };
51050
- };
51051
- var readMemory_default = {
51052
- ...toolInfo10,
51053
- handler: handler10
50891
+ ...toolInfo6,
50892
+ handler: handler6
51054
50893
  };
51055
50894
  // ../core/src/tools/removeFile.ts
51056
- var toolInfo11 = {
50895
+ var toolInfo7 = {
51057
50896
  name: "removeFile",
51058
50897
  description: "Request to remove a file at the specified path.",
51059
50898
  parameters: exports_external.object({
@@ -51069,20 +50908,20 @@ var toolInfo11 = {
51069
50908
  ]
51070
50909
  })
51071
50910
  };
51072
- var handler11 = async (provider, args) => {
50911
+ var handler7 = async (provider, args) => {
51073
50912
  if (!provider.removeFile) {
51074
50913
  return {
51075
- type: "Error" /* Error */,
50914
+ success: false,
51076
50915
  message: {
51077
50916
  type: "error-text",
51078
50917
  value: "Not possible to remove file."
51079
50918
  }
51080
50919
  };
51081
50920
  }
51082
- const parsed = toolInfo11.parameters.safeParse(args);
50921
+ const parsed = toolInfo7.parameters.safeParse(args);
51083
50922
  if (!parsed.success) {
51084
50923
  return {
51085
- type: "Error" /* Error */,
50924
+ success: false,
51086
50925
  message: {
51087
50926
  type: "error-text",
51088
50927
  value: `Invalid arguments for removeFile: ${parsed.error.message}`
@@ -51092,7 +50931,7 @@ var handler11 = async (provider, args) => {
51092
50931
  const { path } = parsed.data;
51093
50932
  await provider.removeFile(path);
51094
50933
  return {
51095
- type: "Reply" /* Reply */,
50934
+ success: true,
51096
50935
  message: {
51097
50936
  type: "text",
51098
50937
  value: `<remove_file_path>${path}</remove_file_path><status>Success</status>`
@@ -51100,11 +50939,11 @@ var handler11 = async (provider, args) => {
51100
50939
  };
51101
50940
  };
51102
50941
  var removeFile_default = {
51103
- ...toolInfo11,
51104
- handler: handler11
50942
+ ...toolInfo7,
50943
+ handler: handler7
51105
50944
  };
51106
50945
  // ../core/src/tools/renameFile.ts
51107
- var toolInfo12 = {
50946
+ var toolInfo8 = {
51108
50947
  name: "renameFile",
51109
50948
  description: "Request to rename a file from source path to target path.",
51110
50949
  parameters: exports_external.object({
@@ -51122,20 +50961,20 @@ var toolInfo12 = {
51122
50961
  ]
51123
50962
  })
51124
50963
  };
51125
- var handler12 = async (provider, args) => {
50964
+ var handler8 = async (provider, args) => {
51126
50965
  if (!provider.renameFile) {
51127
50966
  return {
51128
- type: "Error" /* Error */,
50967
+ success: false,
51129
50968
  message: {
51130
50969
  type: "error-text",
51131
50970
  value: "Not possible to rename file."
51132
50971
  }
51133
50972
  };
51134
50973
  }
51135
- const { source_path, target_path } = toolInfo12.parameters.parse(args);
50974
+ const { source_path, target_path } = toolInfo8.parameters.parse(args);
51136
50975
  await provider.renameFile(source_path, target_path);
51137
50976
  return {
51138
- type: "Reply" /* Reply */,
50977
+ success: true,
51139
50978
  message: {
51140
50979
  type: "text",
51141
50980
  value: `<rename_file_path>${target_path}</rename_file_path><status>Success</status>`
@@ -51143,8 +50982,8 @@ var handler12 = async (provider, args) => {
51143
50982
  };
51144
50983
  };
51145
50984
  var renameFile_default = {
51146
- ...toolInfo12,
51147
- handler: handler12
50985
+ ...toolInfo8,
50986
+ handler: handler8
51148
50987
  };
51149
50988
  // ../core/src/tools/utils/replaceInFile.ts
51150
50989
  var replaceInFile = (fileContent, diff) => {
@@ -51221,7 +51060,7 @@ var replaceInFile = (fileContent, diff) => {
51221
51060
  };
51222
51061
 
51223
51062
  // ../core/src/tools/replaceInFile.ts
51224
- var toolInfo13 = {
51063
+ var toolInfo9 = {
51225
51064
  name: "replaceInFile",
51226
51065
  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.",
51227
51066
  parameters: exports_external.object({
@@ -51331,20 +51170,20 @@ function oldFeature() {
51331
51170
  ]
51332
51171
  })
51333
51172
  };
51334
- var handler13 = async (provider, args) => {
51173
+ var handler9 = async (provider, args) => {
51335
51174
  if (!provider.readFile || !provider.writeFile) {
51336
51175
  return {
51337
- type: "Error" /* Error */,
51176
+ success: false,
51338
51177
  message: {
51339
51178
  type: "error-text",
51340
51179
  value: "Not possible to replace in file."
51341
51180
  }
51342
51181
  };
51343
51182
  }
51344
- const parsed = toolInfo13.parameters.safeParse(args);
51183
+ const parsed = toolInfo9.parameters.safeParse(args);
51345
51184
  if (!parsed.success) {
51346
51185
  return {
51347
- type: "Error" /* Error */,
51186
+ success: false,
51348
51187
  message: {
51349
51188
  type: "error-text",
51350
51189
  value: `Invalid arguments for replaceInFile: ${parsed.error.message}`
@@ -51356,7 +51195,7 @@ var handler13 = async (provider, args) => {
51356
51195
  const fileContent = await provider.readFile(path, false);
51357
51196
  if (fileContent == null) {
51358
51197
  return {
51359
- type: "Error" /* Error */,
51198
+ success: false,
51360
51199
  message: {
51361
51200
  type: "error-text",
51362
51201
  value: `<replace_in_file_result path="${path}" status="failed" message="File not found" />`
@@ -51366,7 +51205,7 @@ var handler13 = async (provider, args) => {
51366
51205
  const result = replaceInFile(fileContent, diff);
51367
51206
  if (result.status === "no_diff_applied") {
51368
51207
  return {
51369
- type: "Error" /* Error */,
51208
+ success: false,
51370
51209
  message: {
51371
51210
  type: "error-text",
51372
51211
  value: `<replace_in_file_result path="${path}" status="failed" message="Unable to apply changes">
@@ -51378,7 +51217,7 @@ var handler13 = async (provider, args) => {
51378
51217
  await provider.writeFile(path, result.content);
51379
51218
  if (result.status === "some_diff_applied") {
51380
51219
  return {
51381
- type: "Reply" /* Reply */,
51220
+ success: true,
51382
51221
  message: {
51383
51222
  type: "text",
51384
51223
  value: `<replace_in_file_result path="${path}" status="some_diff_applied" applied_count="${result.appliedCount}" total_count="${result.totalCount}">
@@ -51388,7 +51227,7 @@ var handler13 = async (provider, args) => {
51388
51227
  };
51389
51228
  }
51390
51229
  return {
51391
- type: "Reply" /* Reply */,
51230
+ success: true,
51392
51231
  message: {
51393
51232
  type: "text",
51394
51233
  value: `<replace_in_file_result path="${path}" status="all_diff_applied" />`
@@ -51396,7 +51235,7 @@ var handler13 = async (provider, args) => {
51396
51235
  };
51397
51236
  } catch (error46) {
51398
51237
  return {
51399
- type: "Error" /* Error */,
51238
+ success: false,
51400
51239
  message: {
51401
51240
  type: "error-text",
51402
51241
  value: `Invalid arguments for replaceInFile: ${error46}`
@@ -51405,11 +51244,11 @@ var handler13 = async (provider, args) => {
51405
51244
  }
51406
51245
  };
51407
51246
  var replaceInFile_default = {
51408
- ...toolInfo13,
51409
- handler: handler13
51247
+ ...toolInfo9,
51248
+ handler: handler9
51410
51249
  };
51411
51250
  // ../core/src/tools/search.ts
51412
- var toolInfo14 = {
51251
+ var toolInfo10 = {
51413
51252
  name: "search",
51414
51253
  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.",
51415
51254
  parameters: exports_external.object({
@@ -51437,11 +51276,11 @@ var toolInfo14 = {
51437
51276
  ]
51438
51277
  })
51439
51278
  };
51440
- var handler14 = async (provider, args) => {
51441
- const { query } = toolInfo14.parameters.parse(args);
51279
+ var handler10 = async (provider, args) => {
51280
+ const { query } = toolInfo10.parameters.parse(args);
51442
51281
  if (!provider.search) {
51443
51282
  return {
51444
- type: "Error" /* Error */,
51283
+ success: false,
51445
51284
  message: {
51446
51285
  type: "text",
51447
51286
  value: "This tool requires a web provider to be installed."
@@ -51450,7 +51289,7 @@ var handler14 = async (provider, args) => {
51450
51289
  }
51451
51290
  const result = await provider.search(query);
51452
51291
  return {
51453
- type: "Reply" /* Reply */,
51292
+ success: true,
51454
51293
  message: {
51455
51294
  type: "text",
51456
51295
  value: result
@@ -51458,11 +51297,11 @@ var handler14 = async (provider, args) => {
51458
51297
  };
51459
51298
  };
51460
51299
  var search_default = {
51461
- ...toolInfo14,
51462
- handler: handler14
51300
+ ...toolInfo10,
51301
+ handler: handler10
51463
51302
  };
51464
51303
  // ../core/src/tools/searchFiles.ts
51465
- var toolInfo15 = {
51304
+ var toolInfo11 = {
51466
51305
  name: "searchFiles",
51467
51306
  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.",
51468
51307
  parameters: exports_external.object({
@@ -51486,20 +51325,20 @@ var toolInfo15 = {
51486
51325
  ]
51487
51326
  })
51488
51327
  };
51489
- var handler15 = async (provider, args) => {
51328
+ var handler11 = async (provider, args) => {
51490
51329
  if (!provider.searchFiles) {
51491
51330
  return {
51492
- type: "Error" /* Error */,
51331
+ success: false,
51493
51332
  message: {
51494
51333
  type: "error-text",
51495
51334
  value: "Not possible to search files."
51496
51335
  }
51497
51336
  };
51498
51337
  }
51499
- const parsed = toolInfo15.parameters.safeParse(args);
51338
+ const parsed = toolInfo11.parameters.safeParse(args);
51500
51339
  if (!parsed.success) {
51501
51340
  return {
51502
- type: "Error" /* Error */,
51341
+ success: false,
51503
51342
  message: {
51504
51343
  type: "error-text",
51505
51344
  value: `Invalid arguments for searchFiles: ${parsed.error.message}`
@@ -51510,7 +51349,7 @@ var handler15 = async (provider, args) => {
51510
51349
  try {
51511
51350
  const files = await provider.searchFiles(path, regex, filePattern ?? "*");
51512
51351
  return {
51513
- type: "Reply" /* Reply */,
51352
+ success: true,
51514
51353
  message: {
51515
51354
  type: "text",
51516
51355
  value: `<search_files_path>${path}</search_files_path>
@@ -51525,7 +51364,7 @@ ${files.join(`
51525
51364
  };
51526
51365
  } catch (error46) {
51527
51366
  return {
51528
- type: "Error" /* Error */,
51367
+ success: false,
51529
51368
  message: {
51530
51369
  type: "error-text",
51531
51370
  value: `Error searching files: ${error46}`
@@ -51534,112 +51373,48 @@ ${files.join(`
51534
51373
  }
51535
51374
  };
51536
51375
  var searchFiles_default = {
51537
- ...toolInfo15,
51538
- handler: handler15
51376
+ ...toolInfo11,
51377
+ handler: handler11
51539
51378
  };
51540
- // ../core/src/tools/updateMemory.ts
51541
- var toolInfo16 = {
51542
- name: "updateMemory",
51543
- 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.',
51544
- parameters: exports_external.object({
51545
- operation: exports_external.enum(["append", "replace", "remove"]).describe("The operation to perform."),
51546
- topic: exports_external.string().nullish().describe('The topic to update in memory. Defaults to ":default:".'),
51547
- content: exports_external.string().nullish().describe("The content for append or replace operations. Must be omitted for remove operation.")
51548
- }).superRefine((data, ctx) => {
51549
- if (data.operation === "append" || data.operation === "replace") {
51550
- if (data.content === undefined) {
51551
- ctx.addIssue({
51552
- code: "custom",
51553
- message: 'Content is required for "append" and "replace" operations.',
51554
- path: ["content"]
51555
- });
51556
- }
51557
- } else if (data.operation === "remove") {
51558
- if (data.content !== undefined) {
51559
- ctx.addIssue({
51560
- code: "custom",
51561
- message: 'Content must not be provided for "remove" operation.',
51562
- path: ["content"]
51563
- });
51564
- }
51379
+ // ../core/src/tools/todo.ts
51380
+ var TodoStatus = exports_external.enum(["open", "completed", "closed"]);
51381
+ var TodoItemSchema = exports_external.object({
51382
+ id: exports_external.string(),
51383
+ title: exports_external.string(),
51384
+ description: exports_external.string(),
51385
+ status: TodoStatus
51386
+ });
51387
+ var UpdateTodoItemInputSchema = exports_external.object({
51388
+ operation: exports_external.enum(["add", "update"]),
51389
+ id: exports_external.string().nullish(),
51390
+ parentId: exports_external.string().nullish(),
51391
+ title: exports_external.string().nullish(),
51392
+ description: exports_external.string().nullish(),
51393
+ status: TodoStatus.nullish()
51394
+ }).superRefine((data, ctx) => {
51395
+ if (data.operation === "add") {
51396
+ if (!data.title) {
51397
+ ctx.addIssue({
51398
+ code: "custom",
51399
+ message: 'Title is required for "add" operation',
51400
+ path: ["title"]
51401
+ });
51565
51402
  }
51566
- })
51567
- };
51568
- var handler16 = async (provider, args) => {
51569
- if (!provider.updateMemory) {
51570
- return {
51571
- type: "Error" /* Error */,
51572
- message: {
51573
- type: "error-text",
51574
- value: "Memory operations are not supported by the current provider."
51575
- }
51576
- };
51577
- }
51578
- const params = toolInfo16.parameters.parse(args);
51579
- await provider.updateMemory(params.operation, params.topic ?? undefined, params.content ?? undefined);
51580
- switch (params.operation) {
51581
- case "append":
51582
- return {
51583
- type: "Reply" /* Reply */,
51584
- message: {
51585
- type: "text",
51586
- value: `Content appended to memory topic '${params.topic || ":default:"}'.`
51587
- }
51588
- };
51589
- case "replace":
51590
- return {
51591
- type: "Reply" /* Reply */,
51592
- message: {
51593
- type: "text",
51594
- value: `Memory topic '${params.topic || ":default:"}' replaced.`
51595
- }
51596
- };
51597
- case "remove":
51598
- return {
51599
- type: "Reply" /* Reply */,
51600
- message: {
51601
- type: "text",
51602
- value: `Memory topic '${params.topic || ":default:"}' removed.`
51603
- }
51604
- };
51605
- }
51606
- };
51607
- var updateMemory_default = {
51608
- ...toolInfo16,
51609
- handler: handler16
51610
- };
51611
- // ../core/src/tools/updateTodoItem.ts
51612
- var toolInfo17 = {
51613
- name: "updateTodoItem",
51614
- description: "Add or update a to-do item.",
51615
- parameters: UpdateTodoItemInputSchema
51616
- };
51617
- var handler17 = async (provider, args) => {
51618
- if (!provider.updateTodoItem) {
51619
- return {
51620
- type: "Error" /* Error */,
51621
- message: {
51622
- type: "error-text",
51623
- value: "Not possible to update a to-do item."
51624
- }
51625
- };
51626
- }
51627
- const input = toolInfo17.parameters.parse(args);
51628
- const result = await provider.updateTodoItem(input);
51629
- return {
51630
- type: "Reply" /* Reply */,
51631
- message: {
51632
- type: "json",
51633
- value: result
51403
+ } else if (data.operation === "update") {
51404
+ if (!data.id) {
51405
+ ctx.addIssue({
51406
+ code: "custom",
51407
+ message: 'ID is required for "update" operation',
51408
+ path: ["id"]
51409
+ });
51634
51410
  }
51635
- };
51636
- };
51637
- var updateTodoItem_default = {
51638
- ...toolInfo17,
51639
- handler: handler17
51640
- };
51411
+ }
51412
+ });
51413
+ var UpdateTodoItemOutputSchema = exports_external.object({
51414
+ id: exports_external.string()
51415
+ });
51641
51416
  // ../core/src/tools/writeToFile.ts
51642
- var toolInfo18 = {
51417
+ var toolInfo12 = {
51643
51418
  name: "writeToFile",
51644
51419
  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.",
51645
51420
  parameters: exports_external.object({
@@ -51668,20 +51443,20 @@ export default App;
51668
51443
  ]
51669
51444
  })
51670
51445
  };
51671
- var handler18 = async (provider, args) => {
51446
+ var handler12 = async (provider, args) => {
51672
51447
  if (!provider.writeFile) {
51673
51448
  return {
51674
- type: "Error" /* Error */,
51449
+ success: false,
51675
51450
  message: {
51676
51451
  type: "error-text",
51677
51452
  value: "Not possible to write file."
51678
51453
  }
51679
51454
  };
51680
51455
  }
51681
- const parsed = toolInfo18.parameters.safeParse(args);
51456
+ const parsed = toolInfo12.parameters.safeParse(args);
51682
51457
  if (!parsed.success) {
51683
51458
  return {
51684
- type: "Error" /* Error */,
51459
+ success: false,
51685
51460
  message: {
51686
51461
  type: "error-text",
51687
51462
  value: `Invalid arguments for writeToFile: ${parsed.error.message}`
@@ -51694,7 +51469,7 @@ var handler18 = async (provider, args) => {
51694
51469
  content = trimmedContent.slice(9, -3);
51695
51470
  await provider.writeFile(path, content);
51696
51471
  return {
51697
- type: "Reply" /* Reply */,
51472
+ success: true,
51698
51473
  message: {
51699
51474
  type: "text",
51700
51475
  value: `<write_to_file_path>${path}</write_to_file_path><status>Success</status>`
@@ -51702,8 +51477,8 @@ var handler18 = async (provider, args) => {
51702
51477
  };
51703
51478
  };
51704
51479
  var writeToFile_default = {
51705
- ...toolInfo18,
51706
- handler: handler18
51480
+ ...toolInfo12,
51481
+ handler: handler12
51707
51482
  };
51708
51483
  // ../core/src/UsageMeter.ts
51709
51484
  class UsageMeter {
@@ -63981,11 +63756,11 @@ var uiMessagesSchema = lazyValidator(() => zodSchema(exports_external.array(expo
63981
63756
  // ../core/src/workflow/agent.workflow.ts
63982
63757
  var agentWorkflow = async (input, { step, tools, logger }) => {
63983
63758
  const event = (name17, event2) => step(name17, () => tools.taskEvent(event2));
63984
- const { tools: toolInfo19, maxToolRoundTrips = 200 } = input;
63759
+ const { tools: toolInfo13, maxToolRoundTrips = 200 } = input;
63985
63760
  const messages = "systemPrompt" in input ? [{ role: "system", content: input.systemPrompt }] : input.messages;
63986
63761
  await event("start-task", { kind: "StartTask" /* StartTask */, systemPrompt: "systemPrompt" in input ? input.systemPrompt : "" });
63987
63762
  const toolSet = {};
63988
- for (const tool2 of toolInfo19) {
63763
+ for (const tool2 of toolInfo13) {
63989
63764
  toolSet[tool2.name] = {
63990
63765
  description: tool2.description,
63991
63766
  inputSchema: jsonSchema(toJSONSchema(tool2.parameters))
@@ -64087,50 +63862,28 @@ var agentWorkflow = async (input, { step, tools, logger }) => {
64087
63862
  input: toolCall.input
64088
63863
  });
64089
63864
  });
64090
- switch (toolResponse.type) {
64091
- case "Reply" /* Reply */:
64092
- await event(`event-tool-reply-${toolCall.toolName}-${toolCall.toolCallId}`, {
64093
- kind: "ToolReply" /* ToolReply */,
64094
- tool: toolCall.toolName,
64095
- content: toolResponse.message
64096
- });
64097
- toolResults.push({
64098
- toolCallId: toolCall.toolCallId,
64099
- toolName: toolCall.toolName,
64100
- output: toolResponse.message
64101
- });
64102
- break;
64103
- case "Error" /* Error */:
64104
- await event(`event-tool-error-${toolCall.toolName}-${toolCall.toolCallId}`, {
64105
- kind: "ToolError" /* ToolError */,
64106
- tool: toolCall.toolName,
64107
- error: toolResponse.message ?? "Unknown error"
64108
- });
64109
- toolResults.push({
64110
- toolCallId: toolCall.toolCallId,
64111
- toolName: toolCall.toolName,
64112
- output: toolResponse.message
64113
- });
64114
- break;
64115
- case "Exit": {
64116
- if (toolCalls.length > 1) {
64117
- toolResults.push({
64118
- toolCallId: toolCall.toolCallId,
64119
- toolName: toolCall.toolName,
64120
- output: {
64121
- type: "error-text",
64122
- value: `Error: The tool '${toolCall.toolName}' must be called alone, but it was called with other tools.`
64123
- }
64124
- });
64125
- break;
64126
- }
64127
- if (toolResults.length > 0) {
64128
- break;
64129
- }
64130
- const exitReason = { ...toolResponse, messages };
64131
- await event("end-task", { kind: "EndTask" /* EndTask */, exitReason });
64132
- return exitReason;
64133
- }
63865
+ if (toolResponse.success) {
63866
+ await event(`event-tool-reply-${toolCall.toolName}-${toolCall.toolCallId}`, {
63867
+ kind: "ToolReply" /* ToolReply */,
63868
+ tool: toolCall.toolName,
63869
+ content: toolResponse.message
63870
+ });
63871
+ toolResults.push({
63872
+ toolCallId: toolCall.toolCallId,
63873
+ toolName: toolCall.toolName,
63874
+ output: toolResponse.message
63875
+ });
63876
+ } else {
63877
+ await event(`event-tool-error-${toolCall.toolName}-${toolCall.toolCallId}`, {
63878
+ kind: "ToolError" /* ToolError */,
63879
+ tool: toolCall.toolName,
63880
+ error: toolResponse.message ?? "Unknown error"
63881
+ });
63882
+ toolResults.push({
63883
+ toolCallId: toolCall.toolCallId,
63884
+ toolName: toolCall.toolName,
63885
+ output: toolResponse.message
63886
+ });
64134
63887
  }
64135
63888
  }
64136
63889
  nextMessage = [
@@ -64219,6 +63972,11 @@ var WorkflowFileSchema = exports_external.object({
64219
63972
  });
64220
63973
 
64221
63974
  // ../core/src/workflow/dynamic.ts
63975
+ var TOOL_GROUPS = {
63976
+ readonly: ["readFile", "readBinaryFile", "listFiles", "searchFiles"],
63977
+ readwrite: ["readFile", "readBinaryFile", "listFiles", "searchFiles", "writeToFile", "replaceInFile", "removeFile", "renameFile"],
63978
+ internet: ["fetchUrl", "search"]
63979
+ };
64222
63980
  function parseDynamicWorkflowDefinition(source) {
64223
63981
  try {
64224
63982
  const raw = $parse(source);
@@ -64293,9 +64051,33 @@ async function executeStepWithAgent(stepDef, workflowId, input, state, context,
64293
64051
  if (!options.toolInfo) {
64294
64052
  throw new Error(`Step '${stepDef.id}' in workflow '${workflowId}' requires agent execution, but no toolInfo was provided to DynamicWorkflowRunner.`);
64295
64053
  }
64296
- const allowedToolNames = stepDef.tools;
64297
- const toolsForAgent = allowedToolNames ? options.toolInfo.filter((t) => allowedToolNames.includes(t.name)) : [...options.toolInfo];
64298
- if (!allowedToolNames || allowedToolNames.includes("runWorkflow")) {
64054
+ const rawAllowedToolNames = stepDef.tools;
64055
+ let toolsForAgent;
64056
+ if (rawAllowedToolNames) {
64057
+ const expandedToolNames = new Set;
64058
+ let includeAll = false;
64059
+ for (const name17 of rawAllowedToolNames) {
64060
+ if (name17 === "all") {
64061
+ includeAll = true;
64062
+ break;
64063
+ }
64064
+ if (Object.hasOwn(TOOL_GROUPS, name17)) {
64065
+ for (const tool2 of TOOL_GROUPS[name17]) {
64066
+ expandedToolNames.add(tool2);
64067
+ }
64068
+ } else {
64069
+ expandedToolNames.add(name17);
64070
+ }
64071
+ }
64072
+ if (includeAll) {
64073
+ toolsForAgent = [...options.toolInfo];
64074
+ } else {
64075
+ toolsForAgent = options.toolInfo.filter((t) => expandedToolNames.has(t.name));
64076
+ }
64077
+ } else {
64078
+ toolsForAgent = [...options.toolInfo];
64079
+ }
64080
+ if (!rawAllowedToolNames || rawAllowedToolNames.includes("all") || rawAllowedToolNames.includes("runWorkflow")) {
64299
64081
  toolsForAgent.push({
64300
64082
  name: "runWorkflow",
64301
64083
  description: "Run a named sub-workflow defined in the current workflow file.",
@@ -64304,7 +64086,7 @@ async function executeStepWithAgent(stepDef, workflowId, input, state, context,
64304
64086
  input: exports_external.any().nullish().describe("Optional input object for the sub-workflow")
64305
64087
  }),
64306
64088
  handler: async () => {
64307
- return { type: "Error" /* Error */, message: { type: "error-text", value: "runWorkflow is virtual." } };
64089
+ return { success: false, message: { type: "error-text", value: "runWorkflow is virtual." } };
64308
64090
  }
64309
64091
  });
64310
64092
  }
@@ -64336,7 +64118,7 @@ async function executeStepWithAgent(stepDef, workflowId, input, state, context,
64336
64118
  invokeTool: async ({ toolName, input: toolInput }) => {
64337
64119
  if (!allowedToolNameSet.has(toolName)) {
64338
64120
  return {
64339
- type: "Error" /* Error */,
64121
+ success: false,
64340
64122
  message: { type: "error-text", value: `Tool '${toolName}' is not allowed in this step.` }
64341
64123
  };
64342
64124
  }
@@ -64345,17 +64127,17 @@ async function executeStepWithAgent(stepDef, workflowId, input, state, context,
64345
64127
  const subInput = toolInput?.input;
64346
64128
  if (typeof subWorkflowId !== "string") {
64347
64129
  return {
64348
- type: "Error" /* Error */,
64130
+ success: false,
64349
64131
  message: { type: "error-text", value: "runWorkflow.workflowId must be a string." }
64350
64132
  };
64351
64133
  }
64352
64134
  try {
64353
64135
  const output = await runWorkflow(subWorkflowId, subInput);
64354
64136
  const jsonResult = { type: "json", value: output };
64355
- return { type: "Reply" /* Reply */, message: jsonResult };
64137
+ return { success: true, message: jsonResult };
64356
64138
  } catch (error46) {
64357
64139
  return {
64358
- type: "Error" /* Error */,
64140
+ success: false,
64359
64141
  message: { type: "error-text", value: error46 instanceof Error ? error46.message : String(error46) }
64360
64142
  };
64361
64143
  }
@@ -64398,6 +64180,14 @@ async function executeStepWithTimeout(stepDef, workflowId, input, state, context
64398
64180
  context.logger.debug(`[Step] Executing step '${stepDef.id}' with compiled code`);
64399
64181
  const fn = compileStep(stepDef, workflowId, compiledSteps);
64400
64182
  const runWorkflow = createRunWorkflowFn({ input, state, context, runInternal });
64183
+ const agentTools = {};
64184
+ if (options.toolInfo) {
64185
+ for (const tool2 of options.toolInfo) {
64186
+ if (typeof context.tools[tool2.name] === "function") {
64187
+ agentTools[tool2.name] = context.tools[tool2.name];
64188
+ }
64189
+ }
64190
+ }
64401
64191
  const runtimeCtx = {
64402
64192
  workflowId,
64403
64193
  stepId: stepDef.id,
@@ -64407,7 +64197,8 @@ async function executeStepWithTimeout(stepDef, workflowId, input, state, context
64407
64197
  logger: context.logger,
64408
64198
  step: context.step,
64409
64199
  runWorkflow,
64410
- toolInfo: options.toolInfo
64200
+ toolInfo: options.toolInfo,
64201
+ agentTools
64411
64202
  };
64412
64203
  const result2 = await fn(runtimeCtx);
64413
64204
  context.logger.debug(`[Step] Compiled code execution completed for step '${stepDef.id}'`);
@@ -64504,17 +64295,358 @@ function createDynamicWorkflow(definition, options = {}) {
64504
64295
  return await runInternal(workflowId, input, context, {});
64505
64296
  };
64506
64297
  }
64298
+ // ../core/src/workflow/prompts/dynamic-generator-prompts.ts
64299
+ var RUNTIME_CONTEXT_TYPES = `## Runtime context (ctx)
64300
+ \`\`\`ts
64301
+ // Runtime types (for reference)
64302
+ type Logger = {
64303
+ debug: (...args: any[]) => void
64304
+ info: (...args: any[]) => void
64305
+ warn: (...args: any[]) => void
64306
+ error: (...args: any[]) => void
64307
+ }
64308
+
64309
+ type StepFn = {
64310
+ <T>(name: string, fn: () => Promise<T>): Promise<T>
64311
+ <T>(name: string, options: { retry?: number }, fn: () => Promise<T>): Promise<T>
64312
+ }
64313
+
64314
+ type JsonModelMessage = { role: 'system' | 'user' | 'assistant' | 'tool'; content: any }
64315
+ type JsonResponseMessage = { role: 'assistant' | 'tool'; content: any }
64316
+ type ToolSet = Record<string, any>
64317
+
64318
+ type ToolResponseResult =
64319
+ | { type: 'text'; value: string }
64320
+ | { type: 'json'; value: any }
64321
+ | { type: 'error-text'; value: string }
64322
+ | { type: 'error-json'; value: any }
64323
+ | { type: 'content'; value: any[] }
64324
+
64325
+ type ToolResponse =
64326
+ | { type: 'Reply'; message: ToolResponseResult }
64327
+ | { type: 'Exit'; message: string; object?: any }
64328
+ | { type: 'Error'; message: ToolResponseResult }
64329
+
64330
+ type ExitReason =
64331
+ | { type: 'UsageExceeded' }
64332
+ | { type: 'Exit'; message: string; object?: any }
64333
+ | { type: 'Error'; error: { message: string; stack?: string } }
64334
+
64335
+ type FullToolInfo = { name: string; description: string; parameters: any; handler: any }
64336
+
64337
+ type AgentTools = {
64338
+ readFile: (input: { path: string }) => Promise<string | null>
64339
+ writeToFile: (input: { path: string; content: string }) => Promise<void>
64340
+ executeCommand: (input: { command: string; pipe?: boolean; requiresApproval?: boolean } & ({ args: string[]; shell?: false } | { shell: true })) => Promise<{
64341
+ exitCode: number
64342
+ stdout: string
64343
+ stderr: string
64344
+ }>
64345
+ searchFiles: (input: { path: string; regex: string; filePattern?: string }) => Promise<string>
64346
+ listFiles: (input: { path: string; recursive?: boolean; maxCount?: number; includeIgnored?: boolean }) => Promise<string>
64347
+ fetchUrl: (input: { url: string[] }) => Promise<string>
64348
+ askFollowupQuestion: (input: { questions: { prompt: string; options?: string[] }[] }) => Promise<any>
64349
+ // ... and other tools available in the environment
64350
+ }
64351
+
64352
+ // Tools available on ctx.tools in dynamic steps
64353
+ type DynamicWorkflowTools = {
64354
+ // LLM + agent helpers
64355
+ runAgent: (input: {
64356
+ tools: Readonly<FullToolInfo[]>
64357
+ maxToolRoundTrips?: number
64358
+ userMessage: readonly JsonModelMessage[]
64359
+ } & ({ messages: JsonModelMessage[] } | { systemPrompt: string })) => Promise<ExitReason>
64360
+
64361
+ // CLI UX helpers
64362
+ confirm: (input: { message: string }) => Promise<boolean>
64363
+ input: (input: { message: string; default?: string }) => Promise<string>
64364
+ select: (input: { message: string; choices: { name: string; value: string }[] }) => Promise<string>
64365
+ }
64366
+
64367
+ type DynamicStepRuntimeContext = {
64368
+ workflowId: string
64369
+ stepId: string
64370
+ input: Record<string, any>
64371
+ state: Record<string, any>
64372
+ tools: DynamicWorkflowTools
64373
+ agentTools: AgentTools
64374
+ logger: Logger
64375
+ step: StepFn
64376
+ runWorkflow: (workflowId: string, input?: Record<string, any>) => Promise<any>
64377
+ toolInfo?: ReadonlyArray<FullToolInfo>
64378
+ }
64379
+ \`\`\`
64380
+
64381
+ - \`ctx.input\`: workflow inputs (read-only).
64382
+ - \`ctx.state\`: shared state between steps (previous step outputs are stored here).
64383
+ - \`ctx.agentTools\`: standard tools (readFile, executeCommand, etc.). Call as \`await ctx.agentTools.someTool({ ... })\`.
64384
+ - \`ctx.tools\`: workflow helpers (runAgent, confirm, input, select).
64385
+ - \`ctx.runWorkflow\`: run a sub-workflow by id.`;
64386
+ var CONTEXT_USAGE_GUIDELINES = `## Guidelines
64387
+ - Use \`await\` for all async operations.
64388
+ - Return the output value for the step (this becomes the step output).
64389
+ - Access inputs via \`ctx.input.<inputId>\`.
64390
+ - Access previous step outputs via \`ctx.state.<stepOutputKey>\` (defaults to the step \`output\` or \`id\`).`;
64391
+ var QUALITY_GUIDELINES = `## Quality Guidelines for Code Implementation
64392
+
64393
+ ### Error Handling
64394
+ - ALWAYS validate inputs at the start of steps
64395
+ - Use try-catch for operations that might fail (file I/O, parsing, API calls)
64396
+ - Preserve stack traces: re-throw original errors rather than creating new ones
64397
+ - Use error type guards: \`const err = error instanceof Error ? error : new Error(String(error))\`
64398
+ - Check for null/undefined before using values
64399
+ - Handle edge cases (empty arrays, missing files, invalid data)
64400
+
64401
+ ### Logging
64402
+ - Use \`ctx.logger.info()\` for important progress updates
64403
+ - Use \`ctx.logger.debug()\` for detailed information
64404
+ - Use \`ctx.logger.warn()\` for recoverable issues
64405
+ - Use \`ctx.logger.error()\` before throwing errors
64406
+ - Log when starting and completing significant operations
64407
+ - Use template literals for readability: \`ctx.logger.info(\\\`Processing \${items.length} items...\\\`)\`
64408
+
64409
+ ### User Experience
64410
+ - Provide progress feedback for long operations
64411
+ - Return structured data (objects/arrays), not strings when possible
64412
+ - Include helpful metadata in results (counts, timestamps, status)
64413
+ - For batch operations, report progress: \`Processed 5/10 items\`
64414
+
64415
+ ### Data Validation
64416
+ - Validate required fields exist before accessing
64417
+ - Check data types match expectations
64418
+ - Validate array lengths before iteration
64419
+ - Example: \`if (!data?.users || !Array.isArray(data.users)) throw new Error('Invalid data format')\`
64420
+
64421
+ ### Best Practices
64422
+ - Use meaningful variable names
64423
+ - Avoid nested callbacks - use async/await
64424
+ - Clean up resources (close files, clear timeouts)
64425
+ - Return consistent data structures across similar steps
64426
+ - For iteration, consider batching or rate limiting
64427
+
64428
+ ### When to Simplify
64429
+ - Simple transformation steps (e.g., formatting strings) need only basic error handling
64430
+ - Internal sub-workflow steps with validated inputs from parent can skip redundant validation
64431
+ - Minimal logging is fine for fast steps (<100ms) that don't perform I/O or external calls
64432
+ - Use judgment: match error handling complexity to the step's failure risk and impact`;
64433
+ var TOOL_CALLING_EXAMPLES = `## Tool calling examples
64434
+
64435
+ ### Standard tools (ctx.agentTools)
64436
+ \`\`\`ts
64437
+ // readFile
64438
+ const readme = await ctx.agentTools.readFile({ path: 'README.md' })
64439
+ if (readme == null) throw new Error('README.md not found')
64440
+
64441
+ // writeToFile
64442
+ await ctx.agentTools.writeToFile({ path: 'notes.txt', content: 'hello\\n' })
64443
+
64444
+ // executeCommand (args form)
64445
+ const rg = await ctx.agentTools.executeCommand({ command: 'rg', args: ['-n', 'TODO', '.'] })
64446
+ if (rg.exitCode !== 0) throw new Error(rg.stderr)
64447
+
64448
+ // executeCommand (shell form)
64449
+ await ctx.agentTools.executeCommand({ command: 'ls -la', shell: true, pipe: true })
64450
+ \`\`\`
64451
+
64452
+ ### Workflow helpers (ctx.tools)
64453
+ \`\`\`ts
64454
+ // runAgent (nested agent; use ctx.toolInfo as the tool list)
64455
+ const agentRes = await ctx.tools.runAgent({
64456
+ systemPrompt: 'You are a helpful assistant.',
64457
+ userMessage: [{ role: 'user', content: 'Summarize README.md in 3 bullets.' }],
64458
+ tools: (ctx.toolInfo ?? []) as any,
64459
+ })
64460
+ if (agentRes.type !== 'Exit') throw new Error('runAgent failed')
64461
+
64462
+ // confirm / input / select (interactive)
64463
+ const ok = await ctx.tools.confirm({ message: 'Proceed?' })
64464
+ const name = await ctx.tools.input({ message: 'Name?', default: 'main' })
64465
+ const flavor = await ctx.tools.select({
64466
+ message: 'Pick one',
64467
+ choices: [
64468
+ { name: 'A', value: 'a' },
64469
+ { name: 'B', value: 'b' },
64470
+ ],
64471
+ })
64472
+ \`\`\`
64473
+
64474
+ ### Sub-workflow example (ctx.runWorkflow)
64475
+ \`\`\`ts
64476
+ const results: any[] = []
64477
+ for (const pr of ctx.state.prs ?? []) {
64478
+ results.push(await ctx.runWorkflow('reviewPR', { prId: pr.id }))
64479
+ }
64480
+ return results
64481
+ \`\`\``;
64482
+ var COMPLETE_STEP_EXAMPLE = `## Complete Example: High-Quality Step Implementation
64483
+
64484
+ This example demonstrates all quality guidelines in a single step:
64485
+
64486
+ \`\`\`ts
64487
+ // Step: processUserData
64488
+ // Task: Read, validate, and process user data from a file
64489
+
64490
+ // Input validation
64491
+ if (!ctx.input.dataFile) {
64492
+ throw new Error('Missing required input: dataFile')
64493
+ }
64494
+
64495
+ ctx.logger.info(\`Starting user data processing for: \${ctx.input.dataFile}\`)
64496
+
64497
+ // Read file with error handling
64498
+ let rawData
64499
+ try {
64500
+ ctx.logger.debug(\`Reading file: \${ctx.input.dataFile}\`)
64501
+ rawData = await ctx.agentTools.readFile({ path: ctx.input.dataFile })
64502
+
64503
+ if (!rawData) {
64504
+ throw new Error(\`File not found or empty: \${ctx.input.dataFile}\`)
64505
+ }
64506
+ } catch (error) {
64507
+ const err = error instanceof Error ? error : new Error(String(error))
64508
+ ctx.logger.error(\`Failed to read file: \${err.message}\`)
64509
+ throw err // Preserve original stack trace
64510
+ }
64511
+
64512
+ // Parse and validate data
64513
+ let users
64514
+ try {
64515
+ ctx.logger.debug('Parsing JSON data')
64516
+ const parsed = JSON.parse(rawData)
64517
+
64518
+ if (!parsed?.users || !Array.isArray(parsed.users)) {
64519
+ throw new Error('Invalid data format: expected {users: [...]}')
64520
+ }
64521
+
64522
+ users = parsed.users
64523
+ ctx.logger.info(\`Found \${users.length} users to process\`)
64524
+ } catch (error) {
64525
+ const err = error instanceof Error ? error : new Error(String(error))
64526
+ ctx.logger.error(\`Data parsing failed: \${err.message}\`)
64527
+ throw err // Preserve original stack trace
64528
+ }
64529
+
64530
+ // Process each user with progress reporting
64531
+ const results = []
64532
+ for (let i = 0; i < users.length; i++) {
64533
+ const user = users[i]
64534
+
64535
+ // Validate each user object
64536
+ if (!user?.id || !user?.email) {
64537
+ ctx.logger.warn(\`Skipping invalid user at index \${i}: missing id or email\`)
64538
+ continue
64539
+ }
64540
+
64541
+ // Process user
64542
+ const processed = {
64543
+ id: user.id,
64544
+ email: user.email.toLowerCase().trim(),
64545
+ name: user.name?.trim() || 'Unknown',
64546
+ processedAt: new Date().toISOString(),
64547
+ status: 'active'
64548
+ }
64549
+
64550
+ results.push(processed)
64551
+
64552
+ // Progress feedback every 10 items
64553
+ if ((i + 1) % 10 === 0) {
64554
+ ctx.logger.info(\`Processed \${i + 1}/\${users.length} users\`)
64555
+ }
64556
+ }
64557
+
64558
+ ctx.logger.info(\`Successfully processed \${results.length}/\${users.length} users\`)
64559
+
64560
+ // Return structured result with metadata
64561
+ return {
64562
+ users: results,
64563
+ metadata: {
64564
+ totalInput: users.length,
64565
+ totalProcessed: results.length,
64566
+ skipped: users.length - results.length,
64567
+ processedAt: new Date().toISOString()
64568
+ }
64569
+ }
64570
+ \`\`\`
64571
+
64572
+ Key features demonstrated:
64573
+ - Input validation at start
64574
+ - Comprehensive error handling with try-catch that preserves stack traces
64575
+ - Logging at info, debug, warn, and error levels
64576
+ - Progress reporting for long operations (every 10 items)
64577
+ - Data validation throughout (null checks, type checks, array validation)
64578
+ - Structured return value with metadata for observability
64579
+ - Descriptive error messages with context
64580
+ - Meaningful variable names (rawData, users, processed)
64581
+ - Clean async/await usage
64582
+ - Template literals for readable string interpolation
64583
+ - Proper error type guards (error instanceof Error)`;
64584
+ var CODE_FIELD_CONSTRAINTS = `REMEMBER: The "code" field must be ONLY the function body statements.
64585
+ - DO NOT wrap code in arrow functions: \`(ctx) => { ... }\`
64586
+ - DO NOT wrap code in async functions: \`async (ctx) => { ... }\`
64587
+ - DO NOT include outer curly braces
64588
+ - DO include a return statement if the step should produce output
64589
+ - Each "code" field should be a string containing multiple statements separated by newlines`;
64590
+ function composeImplementationGuidelines() {
64591
+ return [
64592
+ RUNTIME_CONTEXT_TYPES,
64593
+ "",
64594
+ CONTEXT_USAGE_GUIDELINES,
64595
+ "",
64596
+ QUALITY_GUIDELINES,
64597
+ "",
64598
+ TOOL_CALLING_EXAMPLES,
64599
+ "",
64600
+ COMPLETE_STEP_EXAMPLE
64601
+ ].join(`
64602
+ `);
64603
+ }
64604
+
64507
64605
  // ../core/src/workflow/dynamic-generator.workflow.ts
64508
64606
  var GenerateWorkflowDefinitionInputSchema = exports_external.object({
64509
64607
  prompt: exports_external.string(),
64510
64608
  availableTools: exports_external.array(exports_external.object({
64511
64609
  name: exports_external.string(),
64512
64610
  description: exports_external.string()
64513
- })).optional()
64611
+ })).nullish()
64514
64612
  });
64515
64613
  var GenerateWorkflowCodeInputSchema = exports_external.object({
64516
- workflow: WorkflowFileSchema
64614
+ workflow: WorkflowFileSchema,
64615
+ skipReview: exports_external.boolean().nullish()
64517
64616
  });
64617
+ var AsyncFunction2 = Object.getPrototypeOf(async () => {}).constructor;
64618
+ function validateWorkflowDefinition(workflow) {
64619
+ const errors4 = [];
64620
+ if (!workflow.workflows.main) {
64621
+ errors4.push("Missing required 'main' workflow");
64622
+ }
64623
+ for (const [wfId, wf] of Object.entries(workflow.workflows)) {
64624
+ const stepIds = new Set;
64625
+ for (const step of wf.steps) {
64626
+ if (stepIds.has(step.id)) {
64627
+ errors4.push(`Duplicate step ID '${step.id}' in workflow '${wfId}'`);
64628
+ }
64629
+ stepIds.add(step.id);
64630
+ }
64631
+ }
64632
+ return { valid: errors4.length === 0, errors: errors4 };
64633
+ }
64634
+ function validateWorkflowCodeSyntax(workflow) {
64635
+ const errors4 = [];
64636
+ for (const [wfId, wf] of Object.entries(workflow.workflows)) {
64637
+ for (const step of wf.steps) {
64638
+ if (step.code) {
64639
+ try {
64640
+ new AsyncFunction2("ctx", step.code);
64641
+ } catch (e) {
64642
+ const errorMsg = e instanceof Error ? e.message : String(e);
64643
+ errors4.push(`Syntax error in ${wfId}.${step.id}: ${errorMsg}`);
64644
+ }
64645
+ }
64646
+ }
64647
+ }
64648
+ return { valid: errors4.length === 0, errors: errors4 };
64649
+ }
64518
64650
  var WORKFLOW_DEFINITION_SYSTEM_PROMPT = `You are an expert workflow architect.
64519
64651
  Your task is to create a JSON workflow definition based on the user's request.
64520
64652
 
@@ -64530,10 +64662,10 @@ The workflow definition must follow this structure:
64530
64662
  {
64531
64663
  "id": "stepId",
64532
64664
  "task": "Description of the step",
64533
- "tools": ["toolName1", "toolName2"], // Optional: restrict which tools can be used
64665
+ "tools": ["toolName1", "toolName2"], // Optional: restrict which tools can be used. Can use groups: "readonly", "readwrite", "internet", "all".
64534
64666
  "output": "outputVariableName", // Optional: defaults to step id
64535
64667
  "timeout": 30000, // Optional: timeout in milliseconds
64536
- "expected_outcome": "What this step produces", // Optional: documentation
64668
+ "expected_outcome": "What this step produces", // Optional: documentation for expected results
64537
64669
  "outputSchema": { "type": "object" } // Optional: validation schema
64538
64670
  }
64539
64671
  ],
@@ -64550,14 +64682,22 @@ Constraints:
64550
64682
 
64551
64683
  Quality Guidelines:
64552
64684
  - Add "timeout" field (in milliseconds) for steps that might take long (file I/O, API calls, searches)
64553
- - Use "expected_outcome" field to document what each step should produce
64685
+ - Use "expected_outcome" field to document what each step should produce and its format
64554
64686
  - Use descriptive step IDs (e.g., "validateInput", "fetchUserData", not "step1", "step2")
64555
64687
  - Design steps to be focused - one responsibility per step
64556
64688
  - For steps that process multiple items, consider creating a sub-workflow
64557
64689
  - Add "outputSchema" with type information for validation-critical steps
64558
64690
  - Order steps logically with clear data flow
64559
64691
 
64560
- Example 1:
64692
+ ### Using expected_outcome Effectively
64693
+
64694
+ The "expected_outcome" field helps document what each step produces. Best practices:
64695
+ - Describe the data structure: "Returns an array of { id, name, status } objects"
64696
+ - Mention important constraints: "Returns at most 10 results, sorted by date"
64697
+ - Note failure modes: "Returns null if file not found"
64698
+ - Document side effects: "Creates output directory if it doesn't exist"
64699
+
64700
+ Example 1 - Research workflow:
64561
64701
  User: "Research a topic and summarize it."
64562
64702
  Output:
64563
64703
  \`\`\`json
@@ -64573,13 +64713,16 @@ Output:
64573
64713
  "id": "search",
64574
64714
  "task": "Search for information about the topic",
64575
64715
  "tools": ["search"],
64576
- "output": "searchResults"
64716
+ "output": "searchResults",
64717
+ "timeout": 30000,
64718
+ "expected_outcome": "Returns search results with titles, URLs, and snippets related to the topic"
64577
64719
  },
64578
64720
  {
64579
64721
  "id": "summarize",
64580
64722
  "task": "Summarize the search results",
64581
- "tools": ["generateText"],
64582
- "output": "summary"
64723
+ "tools": ["runAgent"],
64724
+ "output": "summary",
64725
+ "expected_outcome": "Returns a concise summary string (2-3 paragraphs) of the key findings"
64583
64726
  }
64584
64727
  ],
64585
64728
  "output": "summary"
@@ -64588,7 +64731,7 @@ Output:
64588
64731
  }
64589
64732
  \`\`\`
64590
64733
 
64591
- Example 2:
64734
+ Example 2 - PR review workflow with sub-workflow:
64592
64735
  User: "Review urgent PRs. For each PR, run the review workflow."
64593
64736
  Output:
64594
64737
  \`\`\`json
@@ -64602,13 +64745,16 @@ Output:
64602
64745
  "id": "fetchPRs",
64603
64746
  "task": "Fetch list of urgent PRs",
64604
64747
  "tools": ["github_list_prs"],
64605
- "output": "prs"
64748
+ "output": "prs",
64749
+ "timeout": 15000,
64750
+ "expected_outcome": "Returns array of PR objects with { id, title, author, url }"
64606
64751
  },
64607
64752
  {
64608
64753
  "id": "reviewEachPR",
64609
64754
  "task": "Run review workflow for each PR",
64610
64755
  "tools": [],
64611
- "output": "reviews"
64756
+ "output": "reviews",
64757
+ "expected_outcome": "Returns array of review results, one per PR"
64612
64758
  }
64613
64759
  ],
64614
64760
  "output": "reviews"
@@ -64623,13 +64769,16 @@ Output:
64623
64769
  "id": "getDiff",
64624
64770
  "task": "Get PR diff",
64625
64771
  "tools": ["github_get_diff"],
64626
- "output": "diff"
64772
+ "output": "diff",
64773
+ "timeout": 10000,
64774
+ "expected_outcome": "Returns the unified diff string for the PR"
64627
64775
  },
64628
64776
  {
64629
64777
  "id": "analyze",
64630
- "task": "Analyze the diff",
64631
- "tools": ["generateText"],
64632
- "output": "analysis"
64778
+ "task": "Analyze the diff and provide feedback",
64779
+ "tools": ["runAgent"],
64780
+ "output": "analysis",
64781
+ "expected_outcome": "Returns { summary, issues, suggestions } object with review feedback"
64633
64782
  }
64634
64783
  ],
64635
64784
  "output": "analysis"
@@ -64637,7 +64786,73 @@ Output:
64637
64786
  }
64638
64787
  }
64639
64788
  \`\`\`
64789
+
64790
+ Example 3 - File processing with conditional logic:
64791
+ User: "Process all JSON files in a directory, validate them, and generate a report."
64792
+ Output:
64793
+ \`\`\`json
64794
+ {
64795
+ "workflows": {
64796
+ "main": {
64797
+ "task": "Process and validate JSON files, then generate a report",
64798
+ "inputs": [
64799
+ { "id": "directory", "description": "Directory containing JSON files", "default": "data" }
64800
+ ],
64801
+ "steps": [
64802
+ {
64803
+ "id": "listJsonFiles",
64804
+ "task": "List all JSON files in the directory",
64805
+ "tools": ["listFiles"],
64806
+ "output": "jsonFiles",
64807
+ "timeout": 5000,
64808
+ "expected_outcome": "Returns array of file paths ending in .json"
64809
+ },
64810
+ {
64811
+ "id": "processFiles",
64812
+ "task": "Process each JSON file using the processFile sub-workflow",
64813
+ "tools": [],
64814
+ "output": "processedResults",
64815
+ "expected_outcome": "Returns array of { file, valid, errors?, data? } for each file"
64816
+ },
64817
+ {
64818
+ "id": "generateReport",
64819
+ "task": "Generate a summary report of all processed files",
64820
+ "tools": ["writeToFile"],
64821
+ "output": "reportPath",
64822
+ "expected_outcome": "Writes report to 'report.md' and returns the file path"
64823
+ }
64824
+ ],
64825
+ "output": "reportPath"
64826
+ },
64827
+ "processFile": {
64828
+ "task": "Process and validate a single JSON file",
64829
+ "inputs": [
64830
+ { "id": "filePath", "description": "Path to the JSON file" }
64831
+ ],
64832
+ "steps": [
64833
+ {
64834
+ "id": "readFile",
64835
+ "task": "Read the JSON file content",
64836
+ "tools": ["readFile"],
64837
+ "output": "content",
64838
+ "timeout": 3000,
64839
+ "expected_outcome": "Returns file content as string, or null if not found"
64840
+ },
64841
+ {
64842
+ "id": "validateJson",
64843
+ "task": "Parse and validate the JSON structure",
64844
+ "tools": [],
64845
+ "output": "validationResult",
64846
+ "expected_outcome": "Returns { valid: boolean, data?: object, errors?: string[] }"
64847
+ }
64848
+ ],
64849
+ "output": "validationResult"
64850
+ }
64851
+ }
64852
+ }
64853
+ \`\`\`
64640
64854
  `;
64855
+ var WORKFLOW_IMPLEMENTATION_GUIDELINES = composeImplementationGuidelines();
64641
64856
  var WORKFLOW_CODE_SYSTEM_PROMPT = `You are an expert TypeScript developer.
64642
64857
  Your task is to implement the TypeScript code for the steps in the provided workflow definition.
64643
64858
 
@@ -64647,404 +64862,54 @@ You must fill in the "code" field for each step with valid TypeScript code.
64647
64862
  CRITICAL: Each step "code" field must contain ONLY the function body statements (the code inside the curly braces).
64648
64863
  DO NOT include function declaration, arrow function syntax, async keyword, parameter list, or outer curly braces.
64649
64864
 
64865
+ 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\`).
64866
+
64650
64867
  The code will be wrapped automatically in: \`async (ctx) => { YOUR_CODE_HERE }\`
64651
64868
 
64652
64869
  Example of CORRECT code field:
64653
- \`\`\`ts
64654
- const result = await ctx.tools.readFile({ path: 'README.md' })
64655
- if (!result) throw new Error('File not found')
64656
- return result
64657
- \`\`\`
64870
+ \`\`\`ts
64871
+ const result = await ctx.agentTools.readFile({ path: 'README.md' })
64872
+ if (!result) throw new Error('File not found')
64873
+ return result
64874
+ \`\`\`
64658
64875
 
64659
64876
  Example of INCORRECT code field (DO NOT DO THIS):
64660
- \`\`\`ts
64661
- async (ctx) => {
64662
- const result = await ctx.tools.readFile({ path: 'README.md' })
64663
- return result
64664
- }
64665
- \`\`\`
64877
+ \`\`\`ts
64878
+ async (ctx) => {
64879
+ const result = await ctx.agentTools.readFile({ path: 'README.md' })
64880
+ return result
64881
+ }
64882
+ \`\`\`
64666
64883
 
64667
- Example of INCORRECT code field (DO NOT DO THIS):
64668
- \`\`\`ts
64669
- (ctx) => {
64670
- return 'hello'
64671
- }
64672
- \`\`\`
64673
-
64674
- ## Runtime context (ctx)
64675
- \`\`\`ts
64676
- // Runtime types (for reference)
64677
- type Logger = {
64678
- debug: (...args: any[]) => void
64679
- info: (...args: any[]) => void
64680
- warn: (...args: any[]) => void
64681
- error: (...args: any[]) => void
64682
- }
64683
-
64684
- type StepFn = {
64685
- <T>(name: string, fn: () => Promise<T>): Promise<T>
64686
- <T>(name: string, options: { retry?: number }, fn: () => Promise<T>): Promise<T>
64687
- }
64688
-
64689
- type JsonModelMessage = { role: 'system' | 'user' | 'assistant' | 'tool'; content: any }
64690
- type JsonResponseMessage = { role: 'assistant' | 'tool'; content: any }
64691
- type ToolSet = Record<string, any>
64692
-
64693
- type ToolResponseResult =
64694
- | { type: 'text'; value: string }
64695
- | { type: 'json'; value: any }
64696
- | { type: 'error-text'; value: string }
64697
- | { type: 'error-json'; value: any }
64698
- | { type: 'content'; value: any[] }
64699
-
64700
- type AgentToolResponse =
64701
- | { type: 'Reply'; message: ToolResponseResult }
64702
- | { type: 'Exit'; message: string; object?: any }
64703
- | { type: 'Error'; message: ToolResponseResult }
64704
-
64705
- type ExitReason =
64706
- | { type: 'UsageExceeded' }
64707
- | { type: 'Exit'; message: string; object?: any }
64708
- | { type: 'Error'; error: { message: string; stack?: string } }
64709
-
64710
- type FullAgentToolInfo = { name: string; description: string; parameters: any; handler: any }
64711
-
64712
- // Tools available on ctx.tools in dynamic steps
64713
- type DynamicWorkflowTools = {
64714
- // LLM + agent helpers
64715
- generateText: (input: { messages: JsonModelMessage[]; tools: ToolSet }) => Promise<JsonResponseMessage[]>
64716
- runAgent: (input: {
64717
- tools: Readonly<FullAgentToolInfo[]>
64718
- maxToolRoundTrips?: number
64719
- userMessage: readonly JsonModelMessage[]
64720
- } & ({ messages: JsonModelMessage[] } | { systemPrompt: string })) => Promise<ExitReason>
64721
-
64722
- // Generic bridge to "agent tools" by name
64723
- invokeTool: (input: { toolName: string; input: any }) => Promise<AgentToolResponse>
64724
-
64725
- // File + command helpers (direct)
64726
- readFile: (input: { path: string }) => Promise<string | null>
64727
- writeToFile: (input: { path: string; content: string }) => Promise<void>
64728
- executeCommand: (input: { command: string; pipe?: boolean } & ({ args: string[]; shell?: false } | { shell: true })) => Promise<{
64729
- exitCode: number
64730
- stdout: string
64731
- stderr: string
64732
- }>
64733
-
64734
- // CLI UX helpers
64735
- confirm: (input: { message: string }) => Promise<boolean>
64736
- input: (input: { message: string; default?: string }) => Promise<string>
64737
- select: (input: { message: string; choices: { name: string; value: string }[] }) => Promise<string>
64738
- }
64739
-
64740
- type DynamicStepRuntimeContext = {
64741
- workflowId: string
64742
- stepId: string
64743
- input: Record<string, any>
64744
- state: Record<string, any>
64745
- tools: DynamicWorkflowTools
64746
- logger: Logger
64747
- step: StepFn
64748
- runWorkflow: (workflowId: string, input?: Record<string, any>) => Promise<any>
64749
- toolInfo?: ReadonlyArray<FullAgentToolInfo>
64750
- }
64751
- \`\`\`
64884
+ ${WORKFLOW_IMPLEMENTATION_GUIDELINES}
64752
64885
 
64753
- - \`ctx.input\`: workflow inputs (read-only).
64754
- - \`ctx.state\`: shared state between steps (previous step outputs are stored here).
64755
- - \`ctx.tools\`: async tool functions. Call tools as \`await ctx.tools.someTool({ ... })\`.
64756
- - \`ctx.runWorkflow\`: run a sub-workflow by id.
64757
-
64758
- ## Guidelines
64759
- - Use \`await\` for all async operations.
64760
- - Return the output value for the step (this becomes the step output).
64761
- - Access inputs via \`ctx.input.<inputId>\`.
64762
- - Access previous step outputs via \`ctx.state.<stepOutputKey>\` (defaults to the step \`output\` or \`id\`).
64763
-
64764
- ## Quality Guidelines for Code Implementation
64765
-
64766
- ### Error Handling
64767
- - ALWAYS validate inputs at the start of steps
64768
- - Use try-catch for operations that might fail (file I/O, parsing, API calls)
64769
- - Preserve stack traces: re-throw original errors rather than creating new ones
64770
- - Use error type guards: \`const err = error instanceof Error ? error : new Error(String(error))\`
64771
- - Check for null/undefined before using values
64772
- - Handle edge cases (empty arrays, missing files, invalid data)
64773
-
64774
- ### Logging
64775
- - Use \`ctx.logger.info()\` for important progress updates
64776
- - Use \`ctx.logger.debug()\` for detailed information
64777
- - Use \`ctx.logger.warn()\` for recoverable issues
64778
- - Use \`ctx.logger.error()\` before throwing errors
64779
- - Log when starting and completing significant operations
64780
- - Use template literals for readability: \`ctx.logger.info(\\\`Processing \${items.length} items...\\\`)\`
64781
-
64782
- ### User Experience
64783
- - Provide progress feedback for long operations
64784
- - Return structured data (objects/arrays), not strings when possible
64785
- - Include helpful metadata in results (counts, timestamps, status)
64786
- - For batch operations, report progress: \`Processed 5/10 items\`
64787
-
64788
- ### Data Validation
64789
- - Validate required fields exist before accessing
64790
- - Check data types match expectations
64791
- - Validate array lengths before iteration
64792
- - Example: \`if (!data?.users || !Array.isArray(data.users)) throw new Error('Invalid data format')\`
64793
-
64794
- ### Best Practices
64795
- - Use meaningful variable names
64796
- - Avoid nested callbacks - use async/await
64797
- - Clean up resources (close files, clear timeouts)
64798
- - Return consistent data structures across similar steps
64799
- - For iteration, consider batching or rate limiting
64800
-
64801
- ### When to Simplify
64802
- - Simple transformation steps (e.g., formatting strings) need only basic error handling
64803
- - Internal sub-workflow steps with validated inputs from parent can skip redundant validation
64804
- - Minimal logging is fine for fast steps (<100ms) that don't perform I/O or external calls
64805
- - Use judgment: match error handling complexity to the step's failure risk and impact
64806
-
64807
- ## Tool calling examples (every tool)
64808
-
64809
- ### Direct ctx.tools methods
64810
- \`\`\`ts
64811
- // readFile
64812
- const readme = await ctx.tools.readFile({ path: 'README.md' })
64813
- if (readme == null) throw new Error('README.md not found')
64814
-
64815
- // writeToFile
64816
- await ctx.tools.writeToFile({ path: 'notes.txt', content: 'hello\\n' })
64817
-
64818
- // executeCommand (args form)
64819
- const rg = await ctx.tools.executeCommand({ command: 'rg', args: ['-n', 'TODO', '.'] })
64820
- if (rg.exitCode !== 0) throw new Error(rg.stderr)
64821
-
64822
- // executeCommand (shell form)
64823
- await ctx.tools.executeCommand({ command: 'ls -la', shell: true, pipe: true })
64824
-
64825
- // generateText (LLM call; pass tools: {})
64826
- const msgs = await ctx.tools.generateText({
64827
- messages: [
64828
- { role: 'system', content: 'Summarize the following text.' },
64829
- { role: 'user', content: readme },
64830
- ],
64831
- tools: {},
64832
- })
64833
- const last = msgs[msgs.length - 1]
64834
- const lastText = typeof last?.content === 'string' ? last.content : JSON.stringify(last?.content)
64835
-
64836
- // runAgent (nested agent; use ctx.toolInfo as the tool list)
64837
- const agentRes = await ctx.tools.runAgent({
64838
- systemPrompt: 'You are a helpful assistant.',
64839
- userMessage: [{ role: 'user', content: 'Summarize README.md in 3 bullets.' }],
64840
- tools: (ctx.toolInfo ?? []) as any,
64841
- })
64842
- if (agentRes.type !== 'Exit') throw new Error('runAgent failed')
64843
-
64844
- // confirm / input / select (interactive)
64845
- const ok = await ctx.tools.confirm({ message: 'Proceed?' })
64846
- const name = await ctx.tools.input({ message: 'Name?', default: 'main' })
64847
- const flavor = await ctx.tools.select({
64848
- message: 'Pick one',
64849
- choices: [
64850
- { name: 'A', value: 'a' },
64851
- { name: 'B', value: 'b' },
64852
- ],
64853
- })
64854
-
64855
- \`\`\`
64856
-
64857
- ### Agent tools via ctx.tools.invokeTool (toolName examples)
64858
- \`\`\`ts
64859
- // Helper to unwrap a successful tool reply
64860
- function unwrapToolValue(resp: any) {
64861
- if (!resp || resp.type !== 'Reply') {
64862
- const msg = resp?.message?.value
64863
- throw new Error(typeof msg === 'string' ? msg : JSON.stringify(resp))
64864
- }
64865
- return resp.message.value
64866
- }
64867
-
64868
- // askFollowupQuestion
64869
- const answersText = unwrapToolValue(
64870
- await ctx.tools.invokeTool({
64871
- toolName: 'askFollowupQuestion',
64872
- input: { questions: [{ prompt: 'Which directory?', options: ['src', 'packages'] }] },
64873
- }),
64874
- )
64875
-
64876
- // listFiles
64877
- const filesText = unwrapToolValue(
64878
- await ctx.tools.invokeTool({
64879
- toolName: 'listFiles',
64880
- input: { path: 'src', recursive: true, maxCount: 2000, includeIgnored: false },
64881
- }),
64882
- )
64883
-
64884
- // searchFiles
64885
- const hitsText = unwrapToolValue(
64886
- await ctx.tools.invokeTool({
64887
- toolName: 'searchFiles',
64888
- input: { path: '.', regex: 'generateWorkflowCodeWorkflow', filePattern: '*.ts' },
64889
- }),
64890
- )
64891
-
64892
- // fetchUrl
64893
- const pageText = unwrapToolValue(await ctx.tools.invokeTool({ toolName: 'fetchUrl', input: { url: 'https://example.com' } }))
64894
-
64895
- // search (web search)
64896
- const webResults = unwrapToolValue(
64897
- await ctx.tools.invokeTool({ toolName: 'search', input: { query: 'TypeScript zod schema examples' } }),
64898
- )
64899
-
64900
- // executeCommand (provider-backed; may require approval in some environments)
64901
- const cmdText = unwrapToolValue(
64902
- await ctx.tools.invokeTool({ toolName: 'executeCommand', input: { command: 'bun test', requiresApproval: false } }),
64903
- )
64904
-
64905
- // readFile / writeToFile (provider-backed)
64906
- const fileText = unwrapToolValue(
64907
- await ctx.tools.invokeTool({ toolName: 'readFile', input: { path: 'README.md', includeIgnored: false } }),
64908
- )
64909
- const writeText = unwrapToolValue(await ctx.tools.invokeTool({ toolName: 'writeToFile', input: { path: 'out.txt', content: 'hi' } }))
64910
-
64911
- // replaceInFile
64912
- const diff = ['<<<<<<< SEARCH', 'old', '=======', 'new', '>>>>>>> REPLACE'].join('\\n')
64913
- const replaceText = unwrapToolValue(await ctx.tools.invokeTool({ toolName: 'replaceInFile', input: { path: 'out.txt', diff } }))
64914
-
64915
- // removeFile / renameFile
64916
- const rmText = unwrapToolValue(await ctx.tools.invokeTool({ toolName: 'removeFile', input: { path: 'out.txt' } }))
64917
- const mvText = unwrapToolValue(
64918
- await ctx.tools.invokeTool({ toolName: 'renameFile', input: { source_path: 'a.txt', target_path: 'b.txt' } }),
64919
- )
64920
-
64921
- // readBinaryFile (returns { type: 'content', value: [...] } in resp.message)
64922
- const binResp = await ctx.tools.invokeTool({ toolName: 'readBinaryFile', input: { url: 'file://path/to/image.png' } })
64923
- \`\`\`
64924
-
64925
- ### Sub-workflow example (ctx.runWorkflow)
64926
- \`\`\`ts
64927
- const results: any[] = []
64928
- for (const pr of ctx.state.prs ?? []) {
64929
- results.push(await ctx.runWorkflow('reviewPR', { prId: pr.id }))
64930
- }
64931
- return results
64932
- \`\`\`
64933
-
64934
- ## Complete Example: High-Quality Step Implementation
64935
-
64936
- This example demonstrates all quality guidelines in a single step:
64937
-
64938
- \`\`\`ts
64939
- // Step: processUserData
64940
- // Task: Read, validate, and process user data from a file
64941
-
64942
- // Input validation
64943
- if (!ctx.input.dataFile) {
64944
- throw new Error('Missing required input: dataFile')
64945
- }
64946
-
64947
- ctx.logger.info(\`Starting user data processing for: \${ctx.input.dataFile}\`)
64948
-
64949
- // Read file with error handling
64950
- let rawData
64951
- try {
64952
- ctx.logger.debug(\`Reading file: \${ctx.input.dataFile}\`)
64953
- rawData = await ctx.tools.readFile({ path: ctx.input.dataFile })
64954
-
64955
- if (!rawData) {
64956
- throw new Error(\`File not found or empty: \${ctx.input.dataFile}\`)
64957
- }
64958
- } catch (error) {
64959
- const err = error instanceof Error ? error : new Error(String(error))
64960
- ctx.logger.error(\`Failed to read file: \${err.message}\`)
64961
- throw err // Preserve original stack trace
64962
- }
64963
-
64964
- // Parse and validate data
64965
- let users
64966
- try {
64967
- ctx.logger.debug('Parsing JSON data')
64968
- const parsed = JSON.parse(rawData)
64969
-
64970
- if (!parsed?.users || !Array.isArray(parsed.users)) {
64971
- throw new Error('Invalid data format: expected {users: [...]}')
64972
- }
64973
-
64974
- users = parsed.users
64975
- ctx.logger.info(\`Found \${users.length} users to process\`)
64976
- } catch (error) {
64977
- const err = error instanceof Error ? error : new Error(String(error))
64978
- ctx.logger.error(\`Data parsing failed: \${err.message}\`)
64979
- throw err // Preserve original stack trace
64980
- }
64981
-
64982
- // Process each user with progress reporting
64983
- const results = []
64984
- for (let i = 0; i < users.length; i++) {
64985
- const user = users[i]
64986
-
64987
- // Validate each user object
64988
- if (!user?.id || !user?.email) {
64989
- ctx.logger.warn(\`Skipping invalid user at index \${i}: missing id or email\`)
64990
- continue
64991
- }
64992
-
64993
- // Process user
64994
- const processed = {
64995
- id: user.id,
64996
- email: user.email.toLowerCase().trim(),
64997
- name: user.name?.trim() || 'Unknown',
64998
- processedAt: new Date().toISOString(),
64999
- status: 'active'
65000
- }
65001
-
65002
- results.push(processed)
65003
-
65004
- // Progress feedback every 10 items
65005
- if ((i + 1) % 10 === 0) {
65006
- ctx.logger.info(\`Processed \${i + 1}/\${users.length} users\`)
65007
- }
65008
- }
65009
-
65010
- ctx.logger.info(\`Successfully processed \${results.length}/\${users.length} users\`)
65011
-
65012
- // Return structured result with metadata
65013
- return {
65014
- users: results,
65015
- metadata: {
65016
- totalInput: users.length,
65017
- totalProcessed: results.length,
65018
- skipped: users.length - results.length,
65019
- processedAt: new Date().toISOString()
65020
- }
65021
- }
65022
- \`\`\`
65023
-
65024
- Key features demonstrated:
65025
- - Input validation at start
65026
- - Comprehensive error handling with try-catch that preserves stack traces
65027
- - Logging at info, debug, warn, and error levels
65028
- - Progress reporting for long operations (every 10 items)
65029
- - Data validation throughout (null checks, type checks, array validation)
65030
- - Structured return value with metadata for observability
65031
- - Descriptive error messages with context
65032
- - Meaningful variable names (rawData, users, processed)
65033
- - Clean async/await usage
65034
- - Template literals for readable string interpolation
65035
- - Proper error type guards (error instanceof Error)
65036
-
65037
- ## Final Instructions
65038
-
65039
- REMEMBER: The "code" field must be ONLY the function body statements.
65040
- - DO NOT wrap code in arrow functions: \`(ctx) => { ... }\`
65041
- - DO NOT wrap code in async functions: \`async (ctx) => { ... }\`
65042
- - DO NOT include outer curly braces
65043
- - DO include a return statement if the step should produce output
65044
- - Each "code" field should be a string containing multiple statements separated by newlines
65045
-
65046
- Return the complete workflow JSON with the "code" fields populated.
65047
- `;
64886
+ ## Final Instructions
64887
+
64888
+ ${CODE_FIELD_CONSTRAINTS}
64889
+
64890
+ Return the complete workflow JSON with the "code" fields populated.
64891
+ `;
64892
+ var WORKFLOW_REVIEW_SYSTEM_PROMPT = `You are an expert TypeScript Code Reviewer.
64893
+ Your task is to review the provided workflow definition and its implemented code, and improve it to meet the highest quality standards.
64894
+
64895
+ You will receive a JSON workflow definition where the "code" fields are already populated.
64896
+ You must review each step's code and improve it if necessary.
64897
+
64898
+ Check for:
64899
+ - Correct usage of \`ctx.agentTools\` (for standard tools) and \`ctx.tools\` (for workflow helpers).
64900
+ - Proper error handling (try-catch, input validation).
64901
+ - Meaningful logging.
64902
+ - Adherence to the Quality Guidelines.
64903
+ - Correct syntax (no outer function wrappers).
64904
+
64905
+ ${QUALITY_GUIDELINES}
64906
+
64907
+ ## Final Instructions
64908
+
64909
+ Return the complete workflow JSON with the "code" fields improved where necessary.
64910
+ Ensure the "code" field still contains ONLY the function body statements.
64911
+ `;
64912
+ var MAX_GENERATION_ATTEMPTS = 3;
65048
64913
  var generateWorkflowDefinitionWorkflow = async (input, ctx) => {
65049
64914
  let systemPrompt = WORKFLOW_DEFINITION_SYSTEM_PROMPT;
65050
64915
  if (input.availableTools && input.availableTools.length > 0) {
@@ -65065,24 +64930,75 @@ Use these tools when appropriate.`;
65065
64930
  outputSchema: WorkflowFileSchema
65066
64931
  }, ctx);
65067
64932
  });
65068
- if (result.type === "Exit" && result.object) {
65069
- return result.object;
64933
+ if (result.type !== "Exit" || !result.object) {
64934
+ throw new Error("Failed to generate workflow definition");
65070
64935
  }
65071
- throw new Error("Failed to generate workflow definition");
64936
+ const workflow = result.object;
64937
+ await ctx.step("validate-workflow-definition", async () => {
64938
+ const validation = validateWorkflowDefinition(workflow);
64939
+ if (!validation.valid) {
64940
+ ctx.logger.warn(`Workflow definition validation warnings: ${validation.errors.join("; ")}`);
64941
+ }
64942
+ return validation;
64943
+ });
64944
+ return workflow;
65072
64945
  };
65073
64946
  var generateWorkflowCodeWorkflow = async (input, ctx) => {
65074
- const result = await ctx.step("generate-workflow-code", async () => {
65075
- return agentWorkflow({
65076
- systemPrompt: WORKFLOW_CODE_SYSTEM_PROMPT,
65077
- userMessage: [{ role: "user", content: JSON.stringify(input.workflow, null, 2) }],
65078
- tools: [],
65079
- outputSchema: WorkflowFileSchema
65080
- }, ctx);
65081
- });
65082
- if (result.type === "Exit" && result.object) {
65083
- return result.object;
64947
+ let lastError = null;
64948
+ let currentWorkflow = input.workflow;
64949
+ for (let attempt = 0;attempt < MAX_GENERATION_ATTEMPTS; attempt++) {
64950
+ const stepName = attempt === 0 ? "generate-workflow-code" : `retry-workflow-code-${attempt}`;
64951
+ const userMessage = lastError ? `Previous attempt had issues: ${lastError}
64952
+
64953
+ Please fix the problems in this workflow:
64954
+ ${JSON.stringify(currentWorkflow, null, 2)}` : JSON.stringify(currentWorkflow, null, 2);
64955
+ const generated = await ctx.step(stepName, async () => {
64956
+ return agentWorkflow({
64957
+ systemPrompt: WORKFLOW_CODE_SYSTEM_PROMPT,
64958
+ userMessage: [{ role: "user", content: userMessage }],
64959
+ tools: [],
64960
+ outputSchema: WorkflowFileSchema
64961
+ }, ctx);
64962
+ });
64963
+ if (generated.type !== "Exit" || !generated.object) {
64964
+ lastError = "Failed to generate workflow code";
64965
+ continue;
64966
+ }
64967
+ const generatedWorkflow = generated.object;
64968
+ const syntaxValidation = await ctx.step(`validate-code-syntax-${attempt}`, async () => {
64969
+ return validateWorkflowCodeSyntax(generatedWorkflow);
64970
+ });
64971
+ if (!syntaxValidation.valid) {
64972
+ lastError = syntaxValidation.errors.join("; ");
64973
+ currentWorkflow = generatedWorkflow;
64974
+ ctx.logger.warn(`Code syntax validation failed (attempt ${attempt + 1}): ${lastError}`);
64975
+ continue;
64976
+ }
64977
+ if (input.skipReview) {
64978
+ return generatedWorkflow;
64979
+ }
64980
+ const reviewed = await ctx.step("review-workflow-code", async () => {
64981
+ return agentWorkflow({
64982
+ systemPrompt: WORKFLOW_REVIEW_SYSTEM_PROMPT,
64983
+ userMessage: [{ role: "user", content: JSON.stringify(generatedWorkflow, null, 2) }],
64984
+ tools: [],
64985
+ outputSchema: WorkflowFileSchema
64986
+ }, ctx);
64987
+ });
64988
+ if (reviewed.type !== "Exit" || !reviewed.object) {
64989
+ throw new Error("Failed to review workflow code");
64990
+ }
64991
+ const reviewedWorkflow = reviewed.object;
64992
+ const reviewSyntaxValidation = await ctx.step("validate-reviewed-code-syntax", async () => {
64993
+ return validateWorkflowCodeSyntax(reviewedWorkflow);
64994
+ });
64995
+ if (!reviewSyntaxValidation.valid) {
64996
+ ctx.logger.warn(`Reviewed code has syntax issues: ${reviewSyntaxValidation.errors.join("; ")}`);
64997
+ return generatedWorkflow;
64998
+ }
64999
+ return reviewedWorkflow;
65084
65000
  }
65085
- throw new Error("Failed to generate workflow code");
65001
+ throw new Error(`Failed to generate valid workflow code after ${MAX_GENERATION_ATTEMPTS} attempts: ${lastError}`);
65086
65002
  };
65087
65003
  // ../core/src/workflow/json-ai-types.ts
65088
65004
  var toJsonDataContent = (data) => {
@@ -68681,15 +68597,15 @@ function useKeypress(userHandler) {
68681
68597
  signal.current = userHandler;
68682
68598
  useEffect((rl) => {
68683
68599
  let ignore = false;
68684
- const handler19 = withUpdates((_input, event) => {
68600
+ const handler13 = withUpdates((_input, event) => {
68685
68601
  if (ignore)
68686
68602
  return;
68687
68603
  signal.current(event, rl);
68688
68604
  });
68689
- rl.input.on("keypress", handler19);
68605
+ rl.input.on("keypress", handler13);
68690
68606
  return () => {
68691
68607
  ignore = true;
68692
- rl.input.removeListener("keypress", handler19);
68608
+ rl.input.removeListener("keypress", handler13);
68693
68609
  };
68694
68610
  }, []);
68695
68611
  }
@@ -69280,16 +69196,16 @@ class Emitter {
69280
69196
 
69281
69197
  class SignalExitBase {
69282
69198
  }
69283
- var signalExitWrap = (handler19) => {
69199
+ var signalExitWrap = (handler13) => {
69284
69200
  return {
69285
69201
  onExit(cb, opts) {
69286
- return handler19.onExit(cb, opts);
69202
+ return handler13.onExit(cb, opts);
69287
69203
  },
69288
69204
  load() {
69289
- return handler19.load();
69205
+ return handler13.load();
69290
69206
  },
69291
69207
  unload() {
69292
- return handler19.unload();
69208
+ return handler13.unload();
69293
69209
  }
69294
69210
  };
69295
69211
  };
@@ -71335,11 +71251,6 @@ Tool error:`, event.tool));
71335
71251
  }
71336
71252
  break;
71337
71253
  }
71338
- case "Exit" /* Exit */:
71339
- if (verbose > 0) {
71340
- customConsole.log("Exit Message:", event.exitReason.message);
71341
- }
71342
- break;
71343
71254
  }
71344
71255
  for (const [tool3, taskStats] of taskToolCallStats.entries()) {
71345
71256
  const globalStats = globalToolCallStats.get(tool3) ?? { calls: 0, success: 0, errors: 0 };
@@ -84835,7 +84746,7 @@ class ApiProviderConfig {
84835
84746
  return this.resolveModelConfig(mergedConfig);
84836
84747
  }
84837
84748
  resolveModelConfig(config4) {
84838
- const { provider: provider3, model, parameters, budget } = config4;
84749
+ const { provider: provider3, model, parameters, budget, rules } = config4;
84839
84750
  const finalProvider = provider3 ?? this.defaultProvider;
84840
84751
  if (!finalProvider) {
84841
84752
  return;
@@ -84856,7 +84767,8 @@ class ApiProviderConfig {
84856
84767
  keyFile,
84857
84768
  baseUrl,
84858
84769
  parameters: finalParameters,
84859
- budget
84770
+ budget,
84771
+ rules
84860
84772
  };
84861
84773
  }
84862
84774
  }
@@ -85038,6 +84950,38 @@ import { spawn as spawn3, spawnSync as spawnSync2 } from "node:child_process";
85038
84950
  import fs4, { mkdir as mkdir2 } from "node:fs/promises";
85039
84951
  import { dirname as dirname2 } from "node:path";
85040
84952
 
84953
+ // src/tools/getTodoItem.ts
84954
+ var toolInfo13 = {
84955
+ name: "getTodoItem",
84956
+ description: "Get a to-do item by its ID.",
84957
+ parameters: exports_external.object({
84958
+ id: exports_external.string().describe("The ID of the to-do item.")
84959
+ })
84960
+ };
84961
+ var handler13 = async (provider3, args) => {
84962
+ if (!provider3.getTodoItem) {
84963
+ return {
84964
+ success: false,
84965
+ message: {
84966
+ type: "error-text",
84967
+ value: "Not possible to get a to-do item."
84968
+ }
84969
+ };
84970
+ }
84971
+ const { id } = toolInfo13.parameters.parse(args);
84972
+ const item = await provider3.getTodoItem(id);
84973
+ return {
84974
+ success: true,
84975
+ message: {
84976
+ type: "json",
84977
+ value: item ?? null
84978
+ }
84979
+ };
84980
+ };
84981
+ var getTodoItem_default = {
84982
+ ...toolInfo13,
84983
+ handler: handler13
84984
+ };
85041
84985
  // src/tools/utils/diffLineNumbers.ts
85042
84986
  function parseHunkHeader(header) {
85043
84987
  const match = header.match(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
@@ -85097,7 +85041,7 @@ function annotateDiffWithLineNumbers(diff) {
85097
85041
  }
85098
85042
 
85099
85043
  // src/tools/gitDiff.ts
85100
- var toolInfo19 = {
85044
+ var toolInfo14 = {
85101
85045
  name: "git_diff",
85102
85046
  description: "Get the git diff for the current repository. Can be used to get staged changes, unstaged changes, or changes between commits. By default, it returns unstaged changes.",
85103
85047
  parameters: exports_external.object({
@@ -85126,17 +85070,17 @@ var toolInfo19 = {
85126
85070
  }, exports_external.boolean().optional().default(true)).describe("Annotate the diff with line numbers for additions and deletions.")
85127
85071
  })
85128
85072
  };
85129
- var handler19 = async (provider3, args) => {
85073
+ var handler14 = async (provider3, args) => {
85130
85074
  if (!provider3.executeCommand) {
85131
85075
  return {
85132
- type: "Error" /* Error */,
85076
+ success: false,
85133
85077
  message: {
85134
85078
  type: "error-text",
85135
85079
  value: "Not possible to execute command. Abort."
85136
85080
  }
85137
85081
  };
85138
85082
  }
85139
- const { staged, file: file2, commitRange, contextLines, includeLineNumbers } = toolInfo19.parameters.parse(args);
85083
+ const { staged, file: file2, commitRange, contextLines, includeLineNumbers } = toolInfo14.parameters.parse(args);
85140
85084
  const commandParts = ["git", "diff", "--no-color", `-U${contextLines}`];
85141
85085
  if (staged) {
85142
85086
  commandParts.push("--staged");
@@ -85153,7 +85097,7 @@ var handler19 = async (provider3, args) => {
85153
85097
  if (result.exitCode === 0) {
85154
85098
  if (!result.stdout.trim()) {
85155
85099
  return {
85156
- type: "Reply" /* Reply */,
85100
+ success: true,
85157
85101
  message: {
85158
85102
  type: "text",
85159
85103
  value: "No diff found."
@@ -85165,7 +85109,7 @@ var handler19 = async (provider3, args) => {
85165
85109
  diffOutput = annotateDiffWithLineNumbers(diffOutput);
85166
85110
  }
85167
85111
  return {
85168
- type: "Reply" /* Reply */,
85112
+ success: true,
85169
85113
  message: {
85170
85114
  type: "text",
85171
85115
  value: `<diff file="${file2 ?? "all"}">
@@ -85175,7 +85119,7 @@ ${diffOutput}
85175
85119
  };
85176
85120
  }
85177
85121
  return {
85178
- type: "Error" /* Error */,
85122
+ success: false,
85179
85123
  message: {
85180
85124
  type: "error-text",
85181
85125
  value: `\`${command}\` exited with code ${result.exitCode}:
@@ -85184,7 +85128,7 @@ ${result.stderr}`
85184
85128
  };
85185
85129
  } catch (error46) {
85186
85130
  return {
85187
- type: "Error" /* Error */,
85131
+ success: false,
85188
85132
  message: {
85189
85133
  type: "error-text",
85190
85134
  value: error46 instanceof Error ? error46.message : String(error46)
@@ -85193,6 +85137,199 @@ ${result.stderr}`
85193
85137
  }
85194
85138
  };
85195
85139
  var gitDiff_default = {
85140
+ ...toolInfo14,
85141
+ handler: handler14
85142
+ };
85143
+ // src/tools/listMemoryTopics.ts
85144
+ var toolInfo15 = {
85145
+ name: "listMemoryTopics",
85146
+ description: "Lists all topics in memory. Use this to see what information has been stored and which topics are available to read from.",
85147
+ parameters: exports_external.object({})
85148
+ };
85149
+ var handler15 = async (provider3, _args) => {
85150
+ const topics = await provider3.listMemoryTopics();
85151
+ if (!topics.length) {
85152
+ return { success: true, message: { type: "text", value: "No topics found." } };
85153
+ }
85154
+ return {
85155
+ success: true,
85156
+ message: {
85157
+ type: "text",
85158
+ value: `Memory topics:
85159
+ ${topics.join(`
85160
+ `)}`
85161
+ }
85162
+ };
85163
+ };
85164
+ var listMemoryTopics_default = {
85165
+ ...toolInfo15,
85166
+ handler: handler15
85167
+ };
85168
+ // src/tools/listTodoItems.ts
85169
+ var toolInfo16 = {
85170
+ name: "listTodoItems",
85171
+ 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.",
85172
+ parameters: exports_external.object({
85173
+ id: exports_external.string().nullish(),
85174
+ status: TodoStatus.nullish()
85175
+ })
85176
+ };
85177
+ var handler16 = async (provider3, args) => {
85178
+ if (!provider3.listTodoItems) {
85179
+ return {
85180
+ success: false,
85181
+ message: {
85182
+ type: "error-text",
85183
+ value: "Not possible to list to-do items."
85184
+ }
85185
+ };
85186
+ }
85187
+ const { id, status } = toolInfo16.parameters.parse(args);
85188
+ const items = await provider3.listTodoItems(id, status);
85189
+ return {
85190
+ success: true,
85191
+ message: {
85192
+ type: "json",
85193
+ value: items
85194
+ }
85195
+ };
85196
+ };
85197
+ var listTodoItems_default = {
85198
+ ...toolInfo16,
85199
+ handler: handler16
85200
+ };
85201
+ // src/tools/readMemory.ts
85202
+ var toolInfo17 = {
85203
+ name: "readMemory",
85204
+ 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.",
85205
+ parameters: exports_external.object({
85206
+ topic: exports_external.string().nullish().describe('The topic to read from memory. Defaults to ":default:".')
85207
+ })
85208
+ };
85209
+ var handler17 = async (provider3, args) => {
85210
+ const { topic } = toolInfo17.parameters.parse(args);
85211
+ const content = await provider3.readMemory(topic ?? undefined);
85212
+ if (content) {
85213
+ return {
85214
+ success: true,
85215
+ message: {
85216
+ type: "text",
85217
+ value: `<memory${topic ? ` topic="${topic}"` : ""}>
85218
+ ${content}
85219
+ </memory>`
85220
+ }
85221
+ };
85222
+ }
85223
+ return {
85224
+ success: true,
85225
+ message: {
85226
+ type: "text",
85227
+ value: `<memory ${topic ? `topic="${topic}"` : ""} isEmpty="true" />`
85228
+ }
85229
+ };
85230
+ };
85231
+ var readMemory_default = {
85232
+ ...toolInfo17,
85233
+ handler: handler17
85234
+ };
85235
+ // src/tools/updateMemory.ts
85236
+ var toolInfo18 = {
85237
+ name: "updateMemory",
85238
+ 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.',
85239
+ parameters: exports_external.object({
85240
+ operation: exports_external.enum(["append", "replace", "remove"]).describe("The operation to perform."),
85241
+ topic: exports_external.string().nullish().describe('The topic to update in memory. Defaults to ":default:".'),
85242
+ content: exports_external.string().nullish().describe("The content for append or replace operations. Must be omitted for remove operation.")
85243
+ }).superRefine((data, ctx) => {
85244
+ if (data.operation === "append" || data.operation === "replace") {
85245
+ if (data.content === undefined) {
85246
+ ctx.addIssue({
85247
+ code: "custom",
85248
+ message: 'Content is required for "append" and "replace" operations.',
85249
+ path: ["content"]
85250
+ });
85251
+ }
85252
+ } else if (data.operation === "remove") {
85253
+ if (data.content !== undefined) {
85254
+ ctx.addIssue({
85255
+ code: "custom",
85256
+ message: 'Content must not be provided for "remove" operation.',
85257
+ path: ["content"]
85258
+ });
85259
+ }
85260
+ }
85261
+ })
85262
+ };
85263
+ var handler18 = async (provider3, args) => {
85264
+ if (!provider3.updateMemory) {
85265
+ return {
85266
+ success: false,
85267
+ message: {
85268
+ type: "error-text",
85269
+ value: "Memory operations are not supported by the current provider."
85270
+ }
85271
+ };
85272
+ }
85273
+ const params = toolInfo18.parameters.parse(args);
85274
+ await provider3.updateMemory(params.operation, params.topic ?? undefined, params.content ?? undefined);
85275
+ switch (params.operation) {
85276
+ case "append":
85277
+ return {
85278
+ success: true,
85279
+ message: {
85280
+ type: "text",
85281
+ value: `Content appended to memory topic '${params.topic || ":default:"}'.`
85282
+ }
85283
+ };
85284
+ case "replace":
85285
+ return {
85286
+ success: true,
85287
+ message: {
85288
+ type: "text",
85289
+ value: `Memory topic '${params.topic || ":default:"}' replaced.`
85290
+ }
85291
+ };
85292
+ case "remove":
85293
+ return {
85294
+ success: true,
85295
+ message: {
85296
+ type: "text",
85297
+ value: `Memory topic '${params.topic || ":default:"}' removed.`
85298
+ }
85299
+ };
85300
+ }
85301
+ };
85302
+ var updateMemory_default = {
85303
+ ...toolInfo18,
85304
+ handler: handler18
85305
+ };
85306
+ // src/tools/updateTodoItem.ts
85307
+ var toolInfo19 = {
85308
+ name: "updateTodoItem",
85309
+ description: "Add or update a to-do item.",
85310
+ parameters: UpdateTodoItemInputSchema
85311
+ };
85312
+ var handler19 = async (provider3, args) => {
85313
+ if (!provider3.updateTodoItem) {
85314
+ return {
85315
+ success: false,
85316
+ message: {
85317
+ type: "error-text",
85318
+ value: "Not possible to update a to-do item."
85319
+ }
85320
+ };
85321
+ }
85322
+ const input = toolInfo19.parameters.parse(args);
85323
+ const result = await provider3.updateTodoItem(input);
85324
+ return {
85325
+ success: true,
85326
+ message: {
85327
+ type: "json",
85328
+ value: result
85329
+ }
85330
+ };
85331
+ };
85332
+ var updateTodoItem_default = {
85196
85333
  ...toolInfo19,
85197
85334
  handler: handler19
85198
85335
  };
@@ -85522,17 +85659,19 @@ function formatElapsedTime(ms) {
85522
85659
  const remainingMinutes = minutes % 60;
85523
85660
  return remainingMinutes > 0 ? `${hours}h ${remainingMinutes}m` : `${hours}h`;
85524
85661
  }
85525
- async function getDefaultContext() {
85662
+ async function getDefaultContext(commandName) {
85526
85663
  const config4 = await loadConfig();
85527
85664
  const cwd = process.cwd();
85528
85665
  const [files, truncated] = await listFiles(cwd, true, 2000, cwd, config4?.excludeFiles ?? []);
85529
85666
  const fileList = files.join(`
85530
85667
  `);
85668
+ const now2 = new Date;
85669
+ const formattedDate = `${now2.getUTCFullYear()}-${String(now2.getUTCMonth() + 1).padStart(2, "0")}-${String(now2.getUTCDate()).padStart(2, "0")}`;
85531
85670
  const contextParts = [
85532
85671
  `<file_list truncated="${truncated}">
85533
85672
  ${fileList}
85534
85673
  </file_list>`,
85535
- `<now_date>${new Date().toISOString()}</now_date>`
85674
+ `<now_date>${formattedDate}</now_date>`
85536
85675
  ];
85537
85676
  try {
85538
85677
  const agentsMdContent = await fs3.readFile(path.join(cwd, "AGENTS.md"), "utf-8");
@@ -85540,9 +85679,22 @@ ${fileList}
85540
85679
  ${agentsMdContent}
85541
85680
  </agents_instructions>`);
85542
85681
  } catch {}
85543
- if (config4?.rules) {
85682
+ let rules = await resolveRules(config4?.rules);
85683
+ if (commandName && config4) {
85684
+ const apiConfig = new ApiProviderConfig(config4);
85685
+ const commandConfig = apiConfig.getConfigForCommand(commandName);
85686
+ if (commandConfig?.rules) {
85687
+ const commandRules = await resolveRules(commandConfig.rules);
85688
+ if (commandRules) {
85689
+ rules = rules ? `${rules}
85690
+
85691
+ ${commandRules}` : commandRules;
85692
+ }
85693
+ }
85694
+ }
85695
+ if (rules) {
85544
85696
  contextParts.push(`<rules>
85545
- ${config4.rules}
85697
+ ${rules}
85546
85698
  </rules>`);
85547
85699
  }
85548
85700
  if (config4?.scripts) {
@@ -85826,7 +85978,7 @@ async function invokeTool(input2, context) {
85826
85978
  const tool3 = toolHandlers.get(input2.toolName);
85827
85979
  if (!tool3) {
85828
85980
  return {
85829
- type: "Error" /* Error */,
85981
+ success: false,
85830
85982
  message: {
85831
85983
  type: "error-text",
85832
85984
  value: `Tool not found: ${input2.toolName}`
@@ -85838,7 +85990,7 @@ async function invokeTool(input2, context) {
85838
85990
  return result;
85839
85991
  } catch (error46) {
85840
85992
  return {
85841
- type: "Error" /* Error */,
85993
+ success: false,
85842
85994
  message: {
85843
85995
  type: "error-text",
85844
85996
  value: error46?.message ?? `${error46}`
@@ -87053,7 +87205,7 @@ var fixWorkflow = async (input2, context) => {
87053
87205
  }
87054
87206
  logger.info(`Command failed with exit code ${exitCode}. Asking agent to fix it...`);
87055
87207
  const result = await step(`fix-${i2}`, async () => {
87056
- const defaultContext = await getDefaultContext();
87208
+ const defaultContext = await getDefaultContext("fix");
87057
87209
  const memoryContext = await tools2.getMemoryContext();
87058
87210
  const userPrompt = getFixUserPrompt(command, exitCode, stdout, stderr, task, prompt);
87059
87211
  const agentTools = [
@@ -87119,7 +87271,7 @@ async function createPlan(input2, context) {
87119
87271
  userMessage: [{ role: "user", content: userFeedback ?? task }]
87120
87272
  };
87121
87273
  } else {
87122
- const defaultContext = await getDefaultContext();
87274
+ const defaultContext = await getDefaultContext("plan");
87123
87275
  const memoryContext = await tools2.getMemoryContext();
87124
87276
  const prompt = `${memoryContext}
87125
87277
  ${getPlanPrompt(task, inputPlan)}
@@ -87410,7 +87562,7 @@ ${fileContentString}`;
87410
87562
  agentTools.push(additionalTools.search);
87411
87563
  }
87412
87564
  const res = await step("implement", async () => {
87413
- const defaultContext = await getDefaultContext();
87565
+ const defaultContext = await getDefaultContext("code");
87414
87566
  const memoryContext = await tools2.getMemoryContext();
87415
87567
  const textContent = userContent.find((c) => c.type === "text");
87416
87568
  if (textContent && textContent.type === "text") {
@@ -87730,7 +87882,7 @@ async function createPlan2(input2, context) {
87730
87882
  outputSchema: EpicPlanSchema
87731
87883
  }, context);
87732
87884
  }
87733
- const defaultContext = await getDefaultContext();
87885
+ const defaultContext = await getDefaultContext("epic");
87734
87886
  const memoryContext = await tools2.getMemoryContext();
87735
87887
  const prompt = `${memoryContext}
87736
87888
  ${getPlanPrompt(task, plan2)}
@@ -87775,7 +87927,7 @@ async function createAndApprovePlan(task, context, saveUsageSnapshot, interactiv
87775
87927
  const planAgentResult = await step(`plan-${planAttempt}`, () => createPlan2({ task, feedback, messages, additionalTools }, context));
87776
87928
  messages = planAgentResult.messages;
87777
87929
  planAttempt++;
87778
- if (planAgentResult.type !== "Exit" /* Exit */) {
87930
+ if (planAgentResult.type !== "Exit") {
87779
87931
  logger.error(`Plan creation failed. Agent exited with status: ${planAgentResult.type}`);
87780
87932
  return null;
87781
87933
  }
@@ -87953,7 +88105,7 @@ Review iteration ${i2 + 1}/${MAX_REVIEW_RETRIES}`);
87953
88105
  changedFiles
87954
88106
  };
87955
88107
  const reviewAgentResult = await step(`review-${iterationCount}-${i2}`, { retry: 1 }, async () => {
87956
- const defaultContext = await getDefaultContext();
88108
+ const defaultContext = await getDefaultContext("review");
87957
88109
  const memoryContext = await tools2.getMemoryContext();
87958
88110
  const userMessage = `${defaultContext}
87959
88111
  ${memoryContext}
@@ -87966,7 +88118,7 @@ ${formatReviewToolInput(changeInfo)}`;
87966
88118
  outputSchema: reviewOutputSchema
87967
88119
  }, context);
87968
88120
  });
87969
- if (reviewAgentResult.type !== "Exit" /* Exit */) {
88121
+ if (reviewAgentResult.type !== "Exit") {
87970
88122
  logger.error(`Review agent failed with status: ${reviewAgentResult.type}.`);
87971
88123
  break;
87972
88124
  }
@@ -88162,7 +88314,7 @@ Final review iteration ${i2 + 1}/${MAX_REVIEW_RETRIES}`);
88162
88314
  changedFiles
88163
88315
  };
88164
88316
  const reviewAgentResult = await step(`final-review-${i2}`, async () => {
88165
- const defaultContext = await getDefaultContext();
88317
+ const defaultContext = await getDefaultContext("review");
88166
88318
  const memoryContext = await tools2.getMemoryContext();
88167
88319
  const userMessage = `${defaultContext}
88168
88320
  ${memoryContext}
@@ -88175,7 +88327,7 @@ ${formatReviewToolInput(changeInfo)}`;
88175
88327
  outputSchema: reviewOutputSchema
88176
88328
  }, context);
88177
88329
  });
88178
- if (reviewAgentResult.type !== "Exit" /* Exit */) {
88330
+ if (reviewAgentResult.type !== "Exit") {
88179
88331
  logger.error(`Review agent failed with status: ${reviewAgentResult.type}.`);
88180
88332
  break;
88181
88333
  }
@@ -88373,7 +88525,7 @@ Running generic agent...
88373
88525
  agentTools.push(additionalTools.search);
88374
88526
  }
88375
88527
  await step("agent", async () => {
88376
- const defaultContext = await getDefaultContext();
88528
+ const defaultContext = await getDefaultContext("task");
88377
88529
  const userMessage = `${task}
88378
88530
 
88379
88531
  ${defaultContext}`;
@@ -88414,7 +88566,7 @@ Deciding which workflow to use for task...
88414
88566
  tools: [],
88415
88567
  outputSchema: DecisionSchema
88416
88568
  }, context);
88417
- if (result.type !== "Exit" /* Exit */ || !result.object) {
88569
+ if (result.type !== "Exit" || !result.object) {
88418
88570
  throw new Error(`Could not decide which workflow to run. Agent exited with reason: ${result.type}`);
88419
88571
  }
88420
88572
  const decision = result.object;
@@ -88484,7 +88636,7 @@ var prWorkflow = async (input2, context) => {
88484
88636
  tools: [],
88485
88637
  outputSchema: prDetailsSchema
88486
88638
  }, context);
88487
- if (agentResult.type !== "Exit" /* Exit */) {
88639
+ if (agentResult.type !== "Exit") {
88488
88640
  throw new Error(`Workflow exited unexpectedly with type: ${agentResult.type}`);
88489
88641
  }
88490
88642
  const prDetails = agentResult.object;
@@ -88646,7 +88798,7 @@ var reviewWorkflow = async (input2, context) => {
88646
88798
  return { overview: "No changes to review.", specificReviews: [] };
88647
88799
  }
88648
88800
  const result = await step("review", async () => {
88649
- const defaultContext = await getDefaultContext();
88801
+ const defaultContext = await getDefaultContext("review");
88650
88802
  const memoryContext = await tools2.getMemoryContext();
88651
88803
  const reviewInput = formatReviewToolInput(changeInfo);
88652
88804
  const fullContent = `${reviewInput}