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