@polka-codes/core 0.10.11 → 0.10.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/dist/Agent/backoff.d.ts +7 -0
  2. package/dist/Agent/backoff.js +21 -0
  3. package/dist/Agent/backoff.js.map +1 -0
  4. package/dist/Agent/index.d.ts +2 -0
  5. package/dist/Agent/index.js +3 -0
  6. package/dist/Agent/index.js.map +1 -0
  7. package/dist/Agent/parseJsonFromMarkdown.d.ts +8 -0
  8. package/dist/Agent/parseJsonFromMarkdown.js +34 -0
  9. package/dist/Agent/parseJsonFromMarkdown.js.map +1 -0
  10. package/dist/Agent/parseJsonFromMarkdown.test.d.ts +1 -0
  11. package/dist/Agent/parseJsonFromMarkdown.test.js +70 -0
  12. package/dist/Agent/parseJsonFromMarkdown.test.js.map +1 -0
  13. package/dist/Agent/prompts.d.ts +9 -0
  14. package/dist/Agent/prompts.js +107 -0
  15. package/dist/Agent/prompts.js.map +1 -0
  16. package/dist/UsageMeter.d.ts +101 -0
  17. package/dist/UsageMeter.js +299 -0
  18. package/dist/UsageMeter.js.map +1 -0
  19. package/dist/UsageMeter.test.d.ts +4 -0
  20. package/dist/UsageMeter.test.js +556 -0
  21. package/dist/UsageMeter.test.js.map +1 -0
  22. package/dist/config/base.d.ts +68 -0
  23. package/dist/config/base.js +56 -0
  24. package/dist/config/base.js.map +1 -0
  25. package/dist/config/memory.d.ts +24 -0
  26. package/dist/config/memory.js +36 -0
  27. package/dist/config/memory.js.map +1 -0
  28. package/dist/config.d.ts +236 -0
  29. package/dist/config.js +184 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/errors/base.d.ts +31 -0
  32. package/dist/errors/base.js +60 -0
  33. package/dist/errors/base.js.map +1 -0
  34. package/dist/errors/index.d.ts +1 -0
  35. package/dist/errors/index.js +3 -0
  36. package/dist/errors/index.js.map +1 -0
  37. package/dist/fs/index.d.ts +2 -0
  38. package/dist/fs/index.js +3 -0
  39. package/dist/fs/index.js.map +1 -0
  40. package/dist/fs/node-provider.d.ts +16 -0
  41. package/dist/fs/node-provider.js +47 -0
  42. package/dist/fs/node-provider.js.map +1 -0
  43. package/dist/fs/provider.d.ts +61 -0
  44. package/dist/fs/provider.js +3 -0
  45. package/dist/fs/provider.js.map +1 -0
  46. package/dist/index.d.ts +20 -191
  47. package/dist/index.js +21 -4123
  48. package/dist/index.js.map +1 -0
  49. package/dist/memory/index.d.ts +1 -0
  50. package/dist/memory/index.js +2 -0
  51. package/dist/memory/index.js.map +1 -0
  52. package/dist/memory/types.d.ts +136 -0
  53. package/dist/memory/types.js +2 -0
  54. package/dist/memory/types.js.map +1 -0
  55. package/dist/path.d.ts +9 -0
  56. package/dist/path.js +68 -0
  57. package/dist/path.js.map +1 -0
  58. package/dist/path.test.d.ts +1 -0
  59. package/dist/path.test.js +82 -0
  60. package/dist/path.test.js.map +1 -0
  61. package/dist/pricing/converter.d.ts +6 -0
  62. package/dist/pricing/converter.js +13 -0
  63. package/dist/pricing/converter.js.map +1 -0
  64. package/dist/pricing/converter.test.d.ts +1 -0
  65. package/dist/pricing/converter.test.js +54 -0
  66. package/dist/pricing/converter.test.js.map +1 -0
  67. package/dist/pricing/index.d.ts +2 -0
  68. package/dist/pricing/index.js +2 -0
  69. package/dist/pricing/index.js.map +1 -0
  70. package/dist/pricing/portkey-client.d.ts +2 -0
  71. package/dist/pricing/portkey-client.js +57 -0
  72. package/dist/pricing/portkey-client.js.map +1 -0
  73. package/dist/pricing/pricing-service.d.ts +6 -0
  74. package/dist/pricing/pricing-service.js +125 -0
  75. package/dist/pricing/pricing-service.js.map +1 -0
  76. package/dist/pricing/pricing-service.test.d.ts +1 -0
  77. package/dist/pricing/pricing-service.test.js +141 -0
  78. package/dist/pricing/pricing-service.test.js.map +1 -0
  79. package/dist/pricing/types.d.ts +24 -0
  80. package/dist/pricing/types.js +2 -0
  81. package/dist/pricing/types.js.map +1 -0
  82. package/dist/skills/__tests__/discovery.test.d.ts +1 -0
  83. package/dist/skills/__tests__/discovery.test.js +254 -0
  84. package/dist/skills/__tests__/discovery.test.js.map +1 -0
  85. package/dist/skills/__tests__/validation.test.d.ts +1 -0
  86. package/dist/skills/__tests__/validation.test.js +221 -0
  87. package/dist/skills/__tests__/validation.test.js.map +1 -0
  88. package/dist/skills/constants.d.ts +32 -0
  89. package/dist/skills/constants.js +50 -0
  90. package/dist/skills/constants.js.map +1 -0
  91. package/dist/skills/discovery.d.ts +56 -0
  92. package/dist/skills/discovery.js +392 -0
  93. package/dist/skills/discovery.js.map +1 -0
  94. package/dist/skills/index.d.ts +4 -0
  95. package/dist/skills/index.js +6 -0
  96. package/dist/skills/index.js.map +1 -0
  97. package/dist/skills/tools/index.d.ts +3 -0
  98. package/dist/skills/tools/index.js +5 -0
  99. package/dist/skills/tools/index.js.map +1 -0
  100. package/dist/skills/tools/listSkills.d.ts +54 -0
  101. package/dist/skills/tools/listSkills.js +52 -0
  102. package/dist/skills/tools/listSkills.js.map +1 -0
  103. package/dist/skills/tools/loadSkill.d.ts +52 -0
  104. package/dist/skills/tools/loadSkill.js +86 -0
  105. package/dist/skills/tools/loadSkill.js.map +1 -0
  106. package/dist/skills/tools/readSkillFile.d.ts +43 -0
  107. package/dist/skills/tools/readSkillFile.js +68 -0
  108. package/dist/skills/tools/readSkillFile.js.map +1 -0
  109. package/dist/skills/types.d.ts +83 -0
  110. package/dist/skills/types.js +42 -0
  111. package/dist/skills/types.js.map +1 -0
  112. package/dist/skills/validation.d.ts +30 -0
  113. package/dist/skills/validation.js +133 -0
  114. package/dist/skills/validation.js.map +1 -0
  115. package/dist/tool.d.ts +51 -0
  116. package/dist/tool.js +2 -0
  117. package/dist/tool.js.map +1 -0
  118. package/dist/tools/askFollowupQuestion.d.ts +35 -0
  119. package/dist/tools/askFollowupQuestion.js +105 -0
  120. package/dist/tools/askFollowupQuestion.js.map +1 -0
  121. package/dist/tools/askFollowupQuestion.test.d.ts +1 -0
  122. package/dist/tools/askFollowupQuestion.test.js +80 -0
  123. package/dist/tools/askFollowupQuestion.test.js.map +1 -0
  124. package/dist/tools/executeCommand.d.ts +29 -0
  125. package/dist/tools/executeCommand.js +82 -0
  126. package/dist/tools/executeCommand.js.map +1 -0
  127. package/dist/tools/executeCommand.test.d.ts +1 -0
  128. package/dist/tools/executeCommand.test.js +60 -0
  129. package/dist/tools/executeCommand.test.js.map +1 -0
  130. package/dist/tools/fetchUrl.d.ts +26 -0
  131. package/dist/tools/fetchUrl.js +85 -0
  132. package/dist/tools/fetchUrl.js.map +1 -0
  133. package/dist/tools/index.d.ts +15 -0
  134. package/dist/tools/index.js +17 -0
  135. package/dist/tools/index.js.map +1 -0
  136. package/dist/tools/listFiles.d.ts +35 -0
  137. package/dist/tools/listFiles.js +61 -0
  138. package/dist/tools/listFiles.js.map +1 -0
  139. package/dist/tools/listFiles.test.d.ts +1 -0
  140. package/dist/tools/listFiles.test.js +59 -0
  141. package/dist/tools/listFiles.test.js.map +1 -0
  142. package/dist/tools/provider.d.ts +76 -0
  143. package/dist/tools/provider.js +60 -0
  144. package/dist/tools/provider.js.map +1 -0
  145. package/dist/tools/readBinaryFile.d.ts +26 -0
  146. package/dist/tools/readBinaryFile.js +52 -0
  147. package/dist/tools/readBinaryFile.js.map +1 -0
  148. package/dist/tools/readFile.d.ts +35 -0
  149. package/dist/tools/readFile.js +128 -0
  150. package/dist/tools/readFile.js.map +1 -0
  151. package/dist/tools/readFile.test.d.ts +1 -0
  152. package/dist/tools/readFile.test.js +37 -0
  153. package/dist/tools/readFile.test.js.map +1 -0
  154. package/dist/tools/removeFile.d.ts +26 -0
  155. package/dist/tools/removeFile.js +49 -0
  156. package/dist/tools/removeFile.js.map +1 -0
  157. package/dist/tools/removeFile.test.d.ts +1 -0
  158. package/dist/tools/removeFile.test.js +32 -0
  159. package/dist/tools/removeFile.test.js.map +1 -0
  160. package/dist/tools/renameFile.d.ts +29 -0
  161. package/dist/tools/renameFile.js +48 -0
  162. package/dist/tools/renameFile.js.map +1 -0
  163. package/dist/tools/renameFile.test.d.ts +1 -0
  164. package/dist/tools/renameFile.test.js +53 -0
  165. package/dist/tools/renameFile.test.js.map +1 -0
  166. package/dist/tools/replaceInFile.d.ts +29 -0
  167. package/dist/tools/replaceInFile.js +233 -0
  168. package/dist/tools/replaceInFile.js.map +1 -0
  169. package/dist/tools/replaceInFile.test.d.ts +1 -0
  170. package/dist/tools/replaceInFile.test.js +79 -0
  171. package/dist/tools/replaceInFile.test.js.map +1 -0
  172. package/dist/tools/response-builders.d.ts +64 -0
  173. package/dist/tools/response-builders.js +88 -0
  174. package/dist/tools/response-builders.js.map +1 -0
  175. package/dist/tools/search.d.ts +26 -0
  176. package/dist/tools/search.js +56 -0
  177. package/dist/tools/search.js.map +1 -0
  178. package/dist/tools/search.test.d.ts +1 -0
  179. package/dist/tools/search.test.js +22 -0
  180. package/dist/tools/search.test.js.map +1 -0
  181. package/dist/tools/searchFiles.d.ts +32 -0
  182. package/dist/tools/searchFiles.js +86 -0
  183. package/dist/tools/searchFiles.js.map +1 -0
  184. package/dist/tools/todo.d.ts +37 -0
  185. package/dist/tools/todo.js +41 -0
  186. package/dist/tools/todo.js.map +1 -0
  187. package/dist/tools/utils/index.d.ts +1 -0
  188. package/dist/tools/utils/index.js +2 -0
  189. package/dist/tools/utils/index.js.map +1 -0
  190. package/dist/tools/utils/replaceInFile.d.ts +7 -0
  191. package/dist/tools/utils/replaceInFile.js +133 -0
  192. package/dist/tools/utils/replaceInFile.js.map +1 -0
  193. package/dist/tools/utils/replaceInFile.test.d.ts +1 -0
  194. package/dist/tools/utils/replaceInFile.test.js +308 -0
  195. package/dist/tools/utils/replaceInFile.test.js.map +1 -0
  196. package/dist/tools/utils.d.ts +10 -0
  197. package/dist/tools/utils.js +27 -0
  198. package/dist/tools/utils.js.map +1 -0
  199. package/dist/tools/writeToFile.d.ts +29 -0
  200. package/dist/tools/writeToFile.js +85 -0
  201. package/dist/tools/writeToFile.js.map +1 -0
  202. package/dist/tools/writeToFile.test.d.ts +1 -0
  203. package/dist/tools/writeToFile.test.js +46 -0
  204. package/dist/tools/writeToFile.test.js.map +1 -0
  205. package/dist/utils/index.d.ts +1 -0
  206. package/dist/utils/index.js +3 -0
  207. package/dist/utils/index.js.map +1 -0
  208. package/dist/utils/merge.d.ts +26 -0
  209. package/dist/utils/merge.js +45 -0
  210. package/dist/utils/merge.js.map +1 -0
  211. package/dist/workflow/agent.workflow.d.ts +39 -0
  212. package/dist/workflow/agent.workflow.js +166 -0
  213. package/dist/workflow/agent.workflow.js.map +1 -0
  214. package/dist/workflow/agent.workflow.test.d.ts +1 -0
  215. package/dist/workflow/agent.workflow.test.js +175 -0
  216. package/dist/workflow/agent.workflow.test.js.map +1 -0
  217. package/dist/workflow/control-flow.test.d.ts +1 -0
  218. package/dist/workflow/control-flow.test.js +323 -0
  219. package/dist/workflow/control-flow.test.js.map +1 -0
  220. package/dist/workflow/dynamic-edge-cases.test.d.ts +1 -0
  221. package/dist/workflow/dynamic-edge-cases.test.js +486 -0
  222. package/dist/workflow/dynamic-edge-cases.test.js.map +1 -0
  223. package/dist/workflow/dynamic-types.d.ts +124 -0
  224. package/dist/workflow/dynamic-types.js +105 -0
  225. package/dist/workflow/dynamic-types.js.map +1 -0
  226. package/dist/workflow/dynamic.d.ts +118 -0
  227. package/dist/workflow/dynamic.js +999 -0
  228. package/dist/workflow/dynamic.js.map +1 -0
  229. package/dist/workflow/index.d.ts +6 -0
  230. package/dist/workflow/index.js +8 -0
  231. package/dist/workflow/index.js.map +1 -0
  232. package/dist/workflow/json-ai-types.d.ts +122 -0
  233. package/dist/workflow/json-ai-types.js +144 -0
  234. package/dist/workflow/json-ai-types.js.map +1 -0
  235. package/dist/workflow/json-schema-conversion.test.d.ts +1 -0
  236. package/dist/workflow/json-schema-conversion.test.js +371 -0
  237. package/dist/workflow/json-schema-conversion.test.js.map +1 -0
  238. package/dist/workflow/try-catch.test.d.ts +1 -0
  239. package/dist/workflow/try-catch.test.js +443 -0
  240. package/dist/workflow/try-catch.test.js.map +1 -0
  241. package/dist/workflow/types.d.ts +103 -0
  242. package/dist/workflow/types.js +17 -0
  243. package/dist/workflow/types.js.map +1 -0
  244. package/dist/workflow/workflow.d.ts +29 -0
  245. package/dist/workflow/workflow.js +57 -0
  246. package/dist/workflow/workflow.js.map +1 -0
  247. package/dist/workflow/workflow.test.d.ts +1 -0
  248. package/dist/workflow/workflow.test.js +189 -0
  249. package/dist/workflow/workflow.test.js.map +1 -0
  250. package/package.json +9 -1
package/dist/index.js CHANGED
@@ -1,4123 +1,21 @@
1
- // src/Agent/parseJsonFromMarkdown.ts
2
- var parseJsonFromMarkdown = (markdown) => {
3
- const jsonRegex = /```(?:json)?\n([\s\S]*?)\n```/;
4
- const match = markdown.match(jsonRegex);
5
- const tryParse = (str) => {
6
- try {
7
- let parsed = JSON.parse(str);
8
- if (typeof parsed === "string") {
9
- try {
10
- parsed = JSON.parse(parsed);
11
- } catch {
12
- }
13
- }
14
- return { success: true, data: parsed };
15
- } catch (e) {
16
- const error = e instanceof Error ? e.message : String(e);
17
- return { success: false, error: `Failed to parse JSON: ${error}` };
18
- }
19
- };
20
- if (match?.[1]) {
21
- const content = match[1].trim();
22
- return tryParse(content);
23
- }
24
- const parseResult = tryParse(markdown);
25
- if (parseResult.success) {
26
- return parseResult;
27
- }
28
- return { success: false, error: "No JSON object found in the string." };
29
- };
30
-
31
- // src/Agent/prompts.ts
32
- var NO_REASON_PROVIDED = "No reason provided";
33
- var responsePrompts = {
34
- errorInvokeTool: (tool, error) => `An error occurred while invoking the tool "${tool}": ${error}`,
35
- requireUseTool: `Error: No tool use detected. You MUST use a tool before proceeding.
36
- e.g. <tool_tool_name>tool_name</tool_tool_name>
37
-
38
- Ensure the opening and closing tags are correctly nested and closed, and that you are using the correct tool name.
39
- Avoid unnecessary text or symbols before or after the tool use.
40
- Avoid unnecessary escape characters or special characters.
41
- `,
42
- requireUseToolNative: `Error: No tool use detected. You MUST use a tool before proceeding.
43
- `,
44
- toolResults: (tool, result) => {
45
- switch (result.type) {
46
- case "text":
47
- return [
48
- {
49
- type: "text",
50
- text: `<tool_response name=${tool}>${result.value}</tool_response>`
51
- }
52
- ];
53
- case "error-text":
54
- return [
55
- {
56
- type: "text",
57
- text: `<tool_response_error name=${tool}>${result.value}</tool_response_error>`
58
- }
59
- ];
60
- case "json":
61
- return [
62
- {
63
- type: "text",
64
- text: `<tool_response_json name=${tool}>${JSON.stringify(result.value)}</tool_response_json>`
65
- }
66
- ];
67
- case "error-json":
68
- return [
69
- {
70
- type: "text",
71
- text: `<tool_response_error_json name=${tool}>${JSON.stringify(result.value)}</tool_response_error_json>`
72
- }
73
- ];
74
- case "content":
75
- return [
76
- {
77
- type: "text",
78
- text: `<tool_response name=${tool}>`
79
- },
80
- ...result.value.map((part) => {
81
- if (part.type === "text") {
82
- return part;
83
- }
84
- if ("mediaType" in part && "data" in part && part.mediaType.startsWith("image/")) {
85
- return {
86
- type: "image",
87
- mediaType: part.mediaType,
88
- image: part.data
89
- };
90
- }
91
- if ("mediaType" in part && "data" in part) {
92
- return {
93
- type: "file",
94
- mediaType: part.mediaType,
95
- data: part.data
96
- };
97
- }
98
- return {
99
- type: "text",
100
- text: JSON.stringify(part)
101
- };
102
- }),
103
- {
104
- type: "text",
105
- text: "</tool_response>"
106
- }
107
- ];
108
- case "execution-denied":
109
- return [
110
- {
111
- type: "text",
112
- text: `<tool_response_error name=${tool}>Execution denied: ${result.reason ?? NO_REASON_PROVIDED}</tool_response_error>`
113
- }
114
- ];
115
- default: {
116
- return [
117
- {
118
- type: "text",
119
- text: `<tool_response_error name=${tool}>Unknown result type: ${JSON.stringify(result)}</tool_response_error>`
120
- }
121
- ];
122
- }
123
- }
124
- },
125
- commandResult: (command, exitCode, stdout, stderr) => `<command>${command}</command>
126
- <command_exit_code>${exitCode}</command_exit_code>
127
- <command_stdout>
128
- ${stdout}
129
- </command_stdout>
130
- <command_stderr>
131
- ${stderr}
132
- </command_stderr>`
133
- };
134
-
135
- // src/Agent/backoff.ts
136
- function computeRateLimitBackoffSeconds(count, baseSeconds = 2, capSeconds = 60) {
137
- if (!Number.isFinite(count) || count <= 0) {
138
- count = 1;
139
- }
140
- if (!Number.isFinite(baseSeconds) || baseSeconds <= 0) {
141
- baseSeconds = 2;
142
- }
143
- if (!Number.isFinite(capSeconds) || capSeconds <= 0) {
144
- capSeconds = 60;
145
- }
146
- const delay = baseSeconds * 2 ** (count - 1);
147
- return Math.min(delay, capSeconds);
148
- }
149
-
150
- // src/config.ts
151
- import { z as z3 } from "zod";
152
-
153
- // src/config/base.ts
154
- import { z } from "zod";
155
- var baseModelConfigSchema = z.object({
156
- provider: z.string().optional(),
157
- model: z.string().optional(),
158
- parameters: z.record(z.string(), z.unknown()).optional()
159
- });
160
- var baseApprovalConfigSchema = z.object({
161
- level: z.enum(["none", "destructive", "commits", "all"]).optional(),
162
- autoApprove: z.boolean().optional(),
163
- maxCost: z.number().positive().optional()
164
- });
165
- var providerConfigSchema = z.object({
166
- apiKey: z.string().optional(),
167
- defaultModel: z.string().optional(),
168
- defaultParameters: z.record(z.string(), z.unknown()).optional(),
169
- location: z.string().optional(),
170
- project: z.string().optional(),
171
- keyFile: z.string().optional(),
172
- baseUrl: z.string().optional(),
173
- name: z.string().optional()
174
- });
175
- var modelConfigSchema = baseModelConfigSchema.extend({
176
- budget: z.number().positive().optional(),
177
- rules: z.union([z.string(), z.array(z.string()).optional()]).optional()
178
- });
179
- var toolConfigSchema = z.union([
180
- z.boolean(),
181
- // Simple enable/disable
182
- baseModelConfigSchema
183
- // Model override for this tool
184
- ]);
185
-
186
- // src/config/memory.ts
187
- import { z as z2 } from "zod";
188
- var memoryConfigSchema = z2.object({
189
- enabled: z2.boolean().optional().default(true),
190
- type: z2.enum(["sqlite", "memory"]).optional().default("sqlite"),
191
- path: z2.string().optional().default("~/.config/polkacodes/memory/memory.sqlite")
192
- }).strict().optional();
193
- var DEFAULT_MEMORY_CONFIG = {
194
- enabled: true,
195
- type: "sqlite",
196
- path: "~/.config/polkacodes/memory/memory.sqlite"
197
- };
198
- function resolveHomePath(path) {
199
- if (path.startsWith("~")) {
200
- const home = process.env.HOME || process.env.USERPROFILE || ".";
201
- if (home === ".") {
202
- throw new Error("Cannot resolve home directory: HOME and USERPROFILE environment variables are not set");
203
- }
204
- return `${home}${path.slice(1)}`;
205
- }
206
- return path;
207
- }
208
-
209
- // src/config.ts
210
- var ruleSchema = z3.union([
211
- z3.string(),
212
- z3.object({ path: z3.string() }).strict(),
213
- z3.object({ url: z3.string() }).strict(),
214
- z3.object({
215
- repo: z3.string(),
216
- path: z3.string(),
217
- tag: z3.string().optional(),
218
- commit: z3.string().optional(),
219
- branch: z3.string().optional()
220
- }).strict()
221
- ]);
222
- var providerModelSchema = z3.object({
223
- provider: z3.string().optional(),
224
- model: z3.string().optional(),
225
- parameters: z3.record(z3.string(), z3.unknown()).optional(),
226
- budget: z3.number().positive().optional(),
227
- rules: z3.array(ruleSchema).optional().or(z3.string()).optional()
228
- });
229
- var scriptSchema = z3.union([
230
- // Type 1: Simple shell command (backward compatible)
231
- z3.string(),
232
- // Type 2: Object with command and description (backward compatible)
233
- z3.object({
234
- command: z3.string(),
235
- description: z3.string()
236
- }).strict(),
237
- // Type 3: Reference to dynamic workflow YAML
238
- z3.object({
239
- workflow: z3.string(),
240
- // Path to .yml workflow file
241
- description: z3.string().optional(),
242
- input: z3.record(z3.string(), z3.unknown()).optional()
243
- // Default workflow input
244
- }).strict(),
245
- // Type 4: TypeScript script file (NEW)
246
- z3.object({
247
- script: z3.string(),
248
- // Path to .ts file
249
- description: z3.string().optional(),
250
- permissions: z3.object({
251
- fs: z3.enum(["read", "write", "none"]).optional(),
252
- network: z3.boolean().optional(),
253
- subprocess: z3.boolean().optional()
254
- }).optional(),
255
- timeout: z3.number().int().positive().max(36e5).optional(),
256
- // Max 1 hour in milliseconds
257
- memory: z3.number().int().positive().min(64).max(8192).optional()
258
- // 64MB-8GB in MB
259
- }).strict()
260
- ]);
261
- var mcpServerConfigSchema = z3.object({
262
- command: z3.string(),
263
- args: z3.array(z3.string()).optional(),
264
- env: z3.record(z3.string(), z3.string()).optional(),
265
- tools: z3.record(
266
- z3.string(),
267
- z3.boolean().or(
268
- z3.object({
269
- provider: z3.string().optional(),
270
- model: z3.string().optional(),
271
- parameters: z3.record(z3.string(), z3.unknown()).optional()
272
- }).strict()
273
- )
274
- ).optional()
275
- }).strict();
276
- var agentContinuousImprovementSchema = z3.object({
277
- sleepTimeOnNoTasks: z3.number().int().optional(),
278
- sleepTimeBetweenTasks: z3.number().int().optional(),
279
- maxCycles: z3.number().int().optional()
280
- }).strict().optional();
281
- var agentDiscoverySchema = z3.object({
282
- enabledStrategies: z3.array(z3.string()).optional(),
283
- cacheTime: z3.number().int().optional(),
284
- checkChanges: z3.boolean().optional()
285
- }).strict().optional();
286
- var agentSafetySchema = z3.object({
287
- enabledChecks: z3.array(z3.string()).optional(),
288
- blockDestructive: z3.boolean().optional(),
289
- maxFileSize: z3.number().int().optional()
290
- }).strict().optional();
291
- var agentHealthCheckSchema = z3.object({
292
- enabled: z3.boolean().optional(),
293
- interval: z3.number().int().optional()
294
- }).strict().optional();
295
- var agentApprovalSchema = z3.object({
296
- level: z3.enum(["none", "destructive", "commits", "all"]).optional(),
297
- autoApproveSafeTasks: z3.boolean().optional(),
298
- maxAutoApprovalCost: z3.number().optional()
299
- }).strict().optional();
300
- var agentSchema = z3.object({
301
- preset: z3.string().optional(),
302
- strategy: z3.enum(["goal-directed", "continuous-improvement"]).optional(),
303
- continueOnCompletion: z3.boolean().optional(),
304
- maxIterations: z3.number().int().optional(),
305
- timeout: z3.number().int().optional(),
306
- requireApprovalFor: z3.enum(["none", "destructive", "commits", "all"]).optional(),
307
- autoApproveSafeTasks: z3.boolean().optional(),
308
- maxAutoApprovalCost: z3.number().optional(),
309
- pauseOnError: z3.boolean().optional(),
310
- workingBranch: z3.string().optional(),
311
- destructiveOperations: z3.array(z3.string()).optional(),
312
- maxConcurrency: z3.number().int().optional(),
313
- autoSaveInterval: z3.number().int().optional(),
314
- workingDir: z3.string().optional(),
315
- continuousImprovement: agentContinuousImprovementSchema,
316
- discovery: agentDiscoverySchema,
317
- safety: agentSafetySchema,
318
- healthCheck: agentHealthCheckSchema,
319
- approval: agentApprovalSchema
320
- }).strict().optional();
321
- var configSchema = z3.object({
322
- prices: z3.record(
323
- z3.string(),
324
- // provider
325
- z3.record(
326
- z3.string(),
327
- // model
328
- z3.object({
329
- inputPrice: z3.number().optional(),
330
- outputPrice: z3.number().optional(),
331
- cacheWritesPrice: z3.number().optional(),
332
- cacheReadsPrice: z3.number().optional()
333
- })
334
- )
335
- ).optional(),
336
- providers: z3.record(z3.string(), providerConfigSchema).optional(),
337
- defaultProvider: z3.string().optional(),
338
- defaultModel: z3.string().optional(),
339
- defaultParameters: z3.record(z3.string(), z3.unknown()).optional(),
340
- maxMessageCount: z3.number().int().positive().optional(),
341
- budget: z3.number().positive().optional(),
342
- retryCount: z3.number().int().min(0).optional(),
343
- requestTimeoutSeconds: z3.number().int().positive().optional(),
344
- summaryThreshold: z3.number().int().positive().optional(),
345
- scripts: z3.record(z3.string(), scriptSchema).optional(),
346
- commands: z3.record(z3.string(), providerModelSchema).optional(),
347
- tools: z3.object({
348
- search: providerModelSchema.or(z3.boolean()).optional()
349
- }).optional(),
350
- mcpServers: z3.record(z3.string(), mcpServerConfigSchema).optional(),
351
- rules: z3.array(ruleSchema).optional().or(z3.string()).optional(),
352
- excludeFiles: z3.array(z3.string()).optional(),
353
- agent: agentSchema,
354
- memory: memoryConfigSchema,
355
- loadRules: z3.record(z3.string(), z3.boolean()).optional()
356
- }).strict().nullish();
357
-
358
- // src/errors/base.ts
359
- var BaseError = class extends Error {
360
- constructor(name, message, cause) {
361
- super(message);
362
- this.name = name;
363
- this.cause = cause;
364
- this.name = name;
365
- if (cause) {
366
- this.cause = cause;
367
- }
368
- if (Error.captureStackTrace) {
369
- Error.captureStackTrace(this, this.constructor);
370
- }
371
- }
372
- };
373
- function createErrorClass(name, template) {
374
- class NamedError extends BaseError {
375
- constructor(...args) {
376
- const message = template(args);
377
- const lastArg = args[args.length - 1];
378
- const cause = lastArg instanceof Error ? lastArg : void 0;
379
- super(name, message, cause);
380
- }
381
- }
382
- Object.defineProperty(NamedError, "name", { value: name });
383
- return NamedError;
384
- }
385
-
386
- // src/fs/node-provider.ts
387
- import { existsSync } from "fs";
388
- import { readdir, readFile, stat } from "fs/promises";
389
- import { join, normalize } from "path";
390
- var NodeFileSystemProvider = class {
391
- constructor(_options = {}) {
392
- this._options = _options;
393
- }
394
- exists(path) {
395
- return existsSync(path);
396
- }
397
- async readdir(path) {
398
- const entries = await readdir(path, { withFileTypes: true });
399
- return entries.map((entry) => ({
400
- name: entry.name,
401
- isDirectory: entry.isDirectory(),
402
- isFile: entry.isFile()
403
- }));
404
- }
405
- async readFile(path) {
406
- return readFile(path, "utf-8");
407
- }
408
- async readFileAsBuffer(path) {
409
- const buffer = await readFile(path);
410
- return new Uint8Array(buffer);
411
- }
412
- async stat(path) {
413
- const stats = await stat(path);
414
- return {
415
- size: stats.size,
416
- isDirectory: stats.isDirectory(),
417
- isFile: stats.isFile()
418
- };
419
- }
420
- join(...paths) {
421
- return join(...paths);
422
- }
423
- normalize(path) {
424
- return normalize(path);
425
- }
426
- };
427
-
428
- // src/pricing/pricing-service.ts
429
- import { randomUUID } from "crypto";
430
- import { mkdir, readFile as readFile2, rename, writeFile } from "fs/promises";
431
- import { homedir } from "os";
432
- import { dirname, join as join2 } from "path";
433
-
434
- // src/pricing/converter.ts
435
- function convertPortkeyToModelInfo(portkey) {
436
- return {
437
- inputPrice: (portkey.request_token?.price ?? 0) * 10,
438
- outputPrice: (portkey.response_token?.price ?? 0) * 10,
439
- cacheWritesPrice: (portkey.cache_write_input_token?.price ?? 0) * 10,
440
- cacheReadsPrice: (portkey.cache_read_input_token?.price ?? 0) * 10
441
- };
442
- }
443
-
444
- // src/pricing/portkey-client.ts
445
- var PORTKEY_BASE_URL = "https://api.portkey.ai/model-configs/pricing";
446
- var TIMEOUT_MS = 5e3;
447
- var MAX_RETRIES = 2;
448
- async function fetchWithTimeout(url, timeoutMs) {
449
- const controller = new AbortController();
450
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
451
- try {
452
- const response = await fetch(url, { signal: controller.signal });
453
- return response;
454
- } finally {
455
- clearTimeout(timeout);
456
- }
457
- }
458
- async function sleep(ms) {
459
- return new Promise((resolve) => setTimeout(resolve, ms));
460
- }
461
- function shouldRetry(response, error) {
462
- if (error) return true;
463
- if (response.status >= 500) return true;
464
- return false;
465
- }
466
- async function fetchPricing(provider, model) {
467
- const url = `${PORTKEY_BASE_URL}/${provider}/${model}`;
468
- for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
469
- try {
470
- const response = await fetchWithTimeout(url, TIMEOUT_MS);
471
- if (!response.ok) {
472
- if (!shouldRetry(response, null)) {
473
- return null;
474
- }
475
- if (attempt < MAX_RETRIES) {
476
- await sleep(2 ** attempt * 1e3);
477
- continue;
478
- }
479
- return null;
480
- }
481
- const data = await response.json();
482
- return data;
483
- } catch (error) {
484
- if (attempt < MAX_RETRIES && shouldRetry(new Response(null, { status: 500 }), error)) {
485
- await sleep(2 ** attempt * 1e3);
486
- continue;
487
- }
488
- return null;
489
- }
490
- }
491
- return null;
492
- }
493
-
494
- // src/pricing/pricing-service.ts
495
- var CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
496
- var PricingService = class {
497
- #fallbackPrices;
498
- #cacheFile;
499
- #cache = null;
500
- #loadPromise = null;
501
- constructor(fallbackPrices = {}) {
502
- const normalized = {};
503
- for (const [provider, providerInfo] of Object.entries(fallbackPrices)) {
504
- const normalizedProvider = provider.split("-")[0];
505
- normalized[normalizedProvider] = {};
506
- for (const [model, modelInfo] of Object.entries(providerInfo)) {
507
- const normalizedModel = model.replace(/[.-]/g, "");
508
- normalized[normalizedProvider][normalizedModel] = {
509
- inputPrice: modelInfo.inputPrice ?? 0,
510
- outputPrice: modelInfo.outputPrice ?? 0,
511
- cacheWritesPrice: modelInfo.cacheWritesPrice ?? 0,
512
- cacheReadsPrice: modelInfo.cacheReadsPrice ?? 0
513
- };
514
- }
515
- }
516
- this.#fallbackPrices = normalized;
517
- this.#cacheFile = join2(homedir(), ".config", "polkacodes", "pricing-cache.json");
518
- }
519
- async #load() {
520
- if (this.#loadPromise) {
521
- return this.#loadPromise;
522
- }
523
- this.#loadPromise = (async () => {
524
- this.#cache = /* @__PURE__ */ new Map();
525
- try {
526
- const content = await readFile2(this.#cacheFile, "utf-8");
527
- const data = JSON.parse(content);
528
- for (const [key, value] of Object.entries(data)) {
529
- this.#cache.set(key, value);
530
- }
531
- } catch {
532
- }
533
- })();
534
- return this.#loadPromise;
535
- }
536
- async #get(provider, model) {
537
- await this.#load();
538
- const key = `${provider}:${model}`;
539
- const entry = this.#cache?.get(key);
540
- if (!entry) {
541
- return null;
542
- }
543
- if (Date.now() - entry.timestamp > CACHE_TTL_MS) {
544
- this.#cache?.delete(key);
545
- return null;
546
- }
547
- return entry.pricing;
548
- }
549
- async #set(provider, model, pricing) {
550
- await this.#load();
551
- const key = `${provider}:${model}`;
552
- this.#cache?.set(key, {
553
- pricing,
554
- timestamp: Date.now()
555
- });
556
- await this.#save();
557
- }
558
- async #save() {
559
- if (!this.#cache) {
560
- return;
561
- }
562
- try {
563
- const dir = dirname(this.#cacheFile);
564
- await mkdir(dir, { recursive: true });
565
- const data = {};
566
- for (const [key, value] of this.#cache.entries()) {
567
- data[key] = value;
568
- }
569
- const tempFile = `${this.#cacheFile}.${randomUUID()}.tmp`;
570
- await writeFile(tempFile, JSON.stringify(data, null, 2), "utf-8");
571
- await rename(tempFile, this.#cacheFile);
572
- } catch {
573
- }
574
- }
575
- async getPricing(provider, model) {
576
- const normalizedProvider = provider.split("-")[0];
577
- const normalizedModel = model.replace(/[.-]/g, "");
578
- const cached = await this.#get(normalizedProvider, normalizedModel);
579
- if (cached) {
580
- return cached;
581
- }
582
- const fallbackPrice = this.#fallbackPrices[normalizedProvider]?.[normalizedModel];
583
- if (fallbackPrice) {
584
- return fallbackPrice;
585
- }
586
- const portkeyPricing = await fetchPricing(normalizedProvider, model);
587
- if (portkeyPricing) {
588
- const modelInfo = convertPortkeyToModelInfo(portkeyPricing);
589
- await this.#set(normalizedProvider, normalizedModel, modelInfo);
590
- return modelInfo;
591
- }
592
- return {
593
- inputPrice: 0,
594
- outputPrice: 0,
595
- cacheWritesPrice: 0,
596
- cacheReadsPrice: 0
597
- };
598
- }
599
- };
600
-
601
- // src/skills/constants.ts
602
- var SKILL_LIMITS = {
603
- MAX_FILE_SIZE: 1024 * 1024,
604
- // 1MB per file
605
- MAX_SKILL_SIZE: 10 * 1024 * 1024,
606
- // 10MB total
607
- MAX_DEPTH: 10,
608
- // Maximum directory recursion depth
609
- MAX_FILES: 500,
610
- // Maximum files to load per skill
611
- MIN_DESCRIPTION_LENGTH: 20,
612
- // Minimum description length
613
- MAX_DESCRIPTION_LENGTH: 1024,
614
- // Maximum description length
615
- MAX_NAME_LENGTH: 64
616
- // Maximum skill name length
617
- };
618
- var IGNORED_DIRECTORIES = [
619
- ".git",
620
- "node_modules",
621
- ".next",
622
- ".turbo",
623
- "dist",
624
- "build",
625
- "coverage",
626
- ".cache",
627
- ".vscode",
628
- ".idea",
629
- "tmp",
630
- "temp",
631
- ".DS_Store"
632
- ];
633
- var SUSPICIOUS_PATTERNS = [
634
- /<script[^>]*>[\s\S]*?<\/script>/i,
635
- // Script tags (with dotAll for multiline)
636
- /javascript:/i,
637
- // JavaScript URLs
638
- /on\w+\s*=/i
639
- // Event handlers (onclick, onload, etc.)
640
- ];
641
- var SKILL_ERROR_MESSAGES = {
642
- MISSING_FRONTMATTER: "SKILL.md must begin with YAML frontmatter enclosed in ---",
643
- FRONTMATTER_INVALID: "Invalid frontmatter: {message}",
644
- SKILL_NOT_FOUND: "Skill not found",
645
- CONTEXT_NOT_INITIALIZED: "Skill context not initialized"
646
- };
647
- var SOURCE_ICONS = {
648
- project: "\u{1F4C1}",
649
- personal: "\u{1F3E0}",
650
- plugin: "\u{1F50C}"
651
- };
652
-
653
- // src/skills/discovery.ts
654
- import { homedir as homedir2 } from "os";
655
- import { parse } from "yaml";
656
- import { ZodError } from "zod";
657
-
658
- // src/skills/types.ts
659
- import { z as z4 } from "zod";
660
- var skillMetadataSchema = z4.object({
661
- name: z4.string().regex(/^[a-z0-9-]+$/, "Skill name must be lowercase letters, numbers, and hyphens").max(64, "Skill name must be at most 64 characters"),
662
- description: z4.string().max(1024, "Description must be at most 1024 characters"),
663
- allowedTools: z4.array(z4.string()).optional()
664
- });
665
- var SkillDiscoveryError = class extends Error {
666
- constructor(message, path) {
667
- super(message);
668
- this.path = path;
669
- this.name = "SkillDiscoveryError";
670
- }
671
- };
672
- var SkillValidationError = class extends Error {
673
- constructor(message, path) {
674
- super(message);
675
- this.path = path;
676
- this.name = "SkillValidationError";
677
- }
678
- };
679
-
680
- // src/skills/discovery.ts
681
- var BINARY_EXTENSIONS = [
682
- ".png",
683
- ".jpg",
684
- ".jpeg",
685
- ".gif",
686
- ".bmp",
687
- ".ico",
688
- ".webp",
689
- ".pdf",
690
- ".zip",
691
- ".tar",
692
- ".gz",
693
- ".exe",
694
- ".dll",
695
- ".so",
696
- ".dylib",
697
- ".bin",
698
- ".dat",
699
- ".db",
700
- ".sqlite",
701
- ".woff",
702
- ".woff2",
703
- ".ttf",
704
- ".eot"
705
- ];
706
- function isBinaryFile(filename) {
707
- const ext = filename.toLowerCase().slice(filename.lastIndexOf("."));
708
- return BINARY_EXTENSIONS.includes(ext);
709
- }
710
- function isBinaryContent(buffer) {
711
- const checkLength = Math.min(buffer.length, 8192);
712
- for (let i = 0; i < checkLength; i++) {
713
- if (buffer[i] === 0) {
714
- return true;
715
- }
716
- }
717
- return false;
718
- }
719
- async function tryReadTextFile(filePath, fs) {
720
- try {
721
- const buffer = await fs.readFileAsBuffer(filePath);
722
- if (isBinaryContent(buffer)) {
723
- return null;
724
- }
725
- try {
726
- return new TextDecoder("utf-8", { fatal: true }).decode(buffer);
727
- } catch (_decodeError) {
728
- return null;
729
- }
730
- } catch (error) {
731
- if (error && typeof error === "object" && "code" in error && (error.code === "EINVAL" || error.code === "EISDIR")) {
732
- return null;
733
- }
734
- throw error;
735
- }
736
- }
737
- var SkillDiscoveryService = class {
738
- fs;
739
- personalSkillsDir;
740
- projectSkillsDir;
741
- pluginSkillsDirs;
742
- constructor(options) {
743
- this.fs = options.fs ?? new NodeFileSystemProvider();
744
- this.personalSkillsDir = options.personalSkillsDir ?? this.fs.join(homedir2(), ".claude", "skills");
745
- this.projectSkillsDir = this.fs.join(options.cwd, ".claude", "skills");
746
- this.pluginSkillsDirs = options.pluginSkillsDirs ?? [];
747
- }
748
- /**
749
- * Discover all available skills from all sources
750
- * Removes duplicates (project skills take priority over personal/plugin)
751
- */
752
- async discoverAll() {
753
- const skills = [];
754
- const results = await Promise.allSettled([
755
- this.discoverInDirectory(this.projectSkillsDir, "project"),
756
- this.discoverInDirectory(this.personalSkillsDir, "personal"),
757
- this.discoverPlugins()
758
- ]);
759
- const projectSkills = results[0].status === "fulfilled" ? results[0].value : [];
760
- const personalSkills = results[1].status === "fulfilled" ? results[1].value : [];
761
- const pluginSkills = results[2].status === "fulfilled" ? results[2].value : [];
762
- if (results[0].status === "rejected") {
763
- console.warn(`Failed to load project skills: ${results[0].reason}`);
764
- }
765
- if (results[1].status === "rejected") {
766
- console.warn(`Failed to load personal skills: ${results[1].reason}`);
767
- }
768
- if (results[2].status === "rejected") {
769
- console.warn(`Failed to load plugin skills: ${results[2].reason}`);
770
- }
771
- const seenNames = /* @__PURE__ */ new Set();
772
- const allSkills = [...projectSkills, ...personalSkills, ...pluginSkills];
773
- for (const skill of allSkills) {
774
- if (!seenNames.has(skill.metadata.name)) {
775
- seenNames.add(skill.metadata.name);
776
- skills.push(skill);
777
- }
778
- }
779
- return skills;
780
- }
781
- /**
782
- * Discover skills in a specific directory
783
- */
784
- async discoverInDirectory(dir, source) {
785
- const exists = typeof this.fs.exists === "boolean" ? this.fs.exists(dir) : await this.fs.exists(dir);
786
- if (!exists) {
787
- return [];
788
- }
789
- const skills = [];
790
- const entries = await this.fs.readdir(dir);
791
- for (const entry of entries) {
792
- if (!entry.isDirectory) {
793
- continue;
794
- }
795
- const skillPath = this.fs.join(dir, entry.name);
796
- const skillMdPath = this.fs.join(skillPath, "SKILL.md");
797
- const skillMdExists = typeof this.fs.exists === "boolean" ? this.fs.exists(skillMdPath) : await this.fs.exists(skillMdPath);
798
- if (!skillMdExists) {
799
- continue;
800
- }
801
- try {
802
- const content = await this.fs.readFile(skillMdPath);
803
- const { metadata } = this.parseSkillMd(content);
804
- skills.push({
805
- metadata,
806
- path: skillPath,
807
- source
808
- });
809
- } catch (error) {
810
- let message = "Unknown error";
811
- let path = skillPath;
812
- if (error instanceof SkillDiscoveryError) {
813
- message = error.message;
814
- path = error.path;
815
- } else if (error instanceof ZodError) {
816
- message = error.issues[0]?.message ?? "Invalid skill metadata";
817
- } else if (error instanceof Error) {
818
- message = error.message;
819
- }
820
- console.warn(`Warning: Failed to load skill at ${path}: ${message}`);
821
- }
822
- }
823
- return skills;
824
- }
825
- /**
826
- * Discover skills from plugin directories (node_modules)
827
- */
828
- async discoverPlugins() {
829
- const skills = [];
830
- for (const pluginDir of this.pluginSkillsDirs) {
831
- const exists = typeof this.fs.exists === "boolean" ? this.fs.exists(pluginDir) : await this.fs.exists(pluginDir);
832
- if (!exists) {
833
- continue;
834
- }
835
- const pluginSkills = await this.discoverInDirectory(pluginDir, "plugin");
836
- skills.push(...pluginSkills);
837
- }
838
- return skills;
839
- }
840
- /**
841
- * Load a single skill from its directory
842
- */
843
- async loadSkill(skillPath, source) {
844
- const skillMdPath = this.fs.join(skillPath, "SKILL.md");
845
- const skillMdExists = typeof this.fs.exists === "boolean" ? this.fs.exists(skillMdPath) : await this.fs.exists(skillMdPath);
846
- if (!skillMdExists) {
847
- throw new SkillDiscoveryError("SKILL.md not found", skillPath);
848
- }
849
- const content = await this.fs.readFile(skillMdPath);
850
- const { metadata, content: instructions } = this.parseSkillMd(content);
851
- const files = /* @__PURE__ */ new Map();
852
- let totalSize = 0;
853
- const entries = await this.fs.readdir(skillPath);
854
- for (const entry of entries) {
855
- if (entry.name === "SKILL.md") {
856
- continue;
857
- }
858
- const filePath = this.fs.join(skillPath, entry.name);
859
- if (entry.isFile) {
860
- if (isBinaryFile(entry.name)) {
861
- continue;
862
- }
863
- const fileStats = await this.fs.stat(filePath);
864
- const fileSize = fileStats.size;
865
- if (fileSize > SKILL_LIMITS.MAX_FILE_SIZE) {
866
- throw new SkillDiscoveryError(`File size exceeds limit (${fileSize} > ${SKILL_LIMITS.MAX_FILE_SIZE}): ${entry.name}`, skillPath);
867
- }
868
- if (totalSize + fileSize > SKILL_LIMITS.MAX_SKILL_SIZE) {
869
- throw new SkillDiscoveryError(
870
- `Total skill size exceeds limit (${totalSize + fileSize} > ${SKILL_LIMITS.MAX_SKILL_SIZE}): ${skillPath}`,
871
- skillPath
872
- );
873
- }
874
- const fileContent = await tryReadTextFile(filePath, this.fs);
875
- if (fileContent === null) {
876
- continue;
877
- }
878
- totalSize += fileSize;
879
- files.set(entry.name, fileContent);
880
- } else if (entry.isDirectory) {
881
- totalSize = await this.loadDirectoryFiles(filePath, entry.name, files, 0, totalSize);
882
- }
883
- }
884
- return {
885
- metadata,
886
- content: instructions,
887
- files,
888
- path: skillPath,
889
- source
890
- };
891
- }
892
- /**
893
- * Parse SKILL.md content and extract frontmatter
894
- */
895
- parseSkillMd(content) {
896
- const frontmatterRegex = /^---\r?\n([\s\S]+?)\r?\n---\r?\n([\s\S]*)$/;
897
- const match = content.match(frontmatterRegex);
898
- if (!match || match.length < 3) {
899
- throw new SkillDiscoveryError(SKILL_ERROR_MESSAGES.MISSING_FRONTMATTER, "");
900
- }
901
- const frontmatter = match[1] ?? "";
902
- const instructions = match[2] ?? "";
903
- const metadata = this.parseMetadata(frontmatter);
904
- return { metadata, content: instructions };
905
- }
906
- /**
907
- * Parse and validate YAML frontmatter
908
- */
909
- parseMetadata(frontmatter) {
910
- const parsed = parse(frontmatter);
911
- return skillMetadataSchema.parse(parsed);
912
- }
913
- /**
914
- * Recursively load files from a directory into the files map
915
- * @returns The total size of all files loaded (in bytes)
916
- */
917
- async loadDirectoryFiles(dirPath, prefix, files, depth = 0, currentTotal = 0) {
918
- const { MAX_DEPTH, MAX_FILES } = SKILL_LIMITS;
919
- let totalSize = currentTotal;
920
- if (depth > MAX_DEPTH) {
921
- return totalSize;
922
- }
923
- if (files.size >= MAX_FILES) {
924
- return totalSize;
925
- }
926
- const currentDirName = prefix.split("/").pop() ?? prefix;
927
- if (IGNORED_DIRECTORIES.includes(currentDirName)) {
928
- return totalSize;
929
- }
930
- const entries = await this.fs.readdir(dirPath);
931
- for (const entry of entries) {
932
- if (files.size >= MAX_FILES) {
933
- break;
934
- }
935
- const filePath = this.fs.join(dirPath, entry.name);
936
- const key = `${prefix}/${entry.name}`.replace(/\/+/g, "/");
937
- if (entry.isFile) {
938
- if (isBinaryFile(entry.name)) {
939
- continue;
940
- }
941
- const fileStats = await this.fs.stat(filePath);
942
- const fileSize = fileStats.size;
943
- if (fileSize > SKILL_LIMITS.MAX_FILE_SIZE) {
944
- throw new SkillDiscoveryError(`File size exceeds limit (${fileSize} > ${SKILL_LIMITS.MAX_FILE_SIZE}): ${key}`, dirPath);
945
- }
946
- if (totalSize + fileSize > SKILL_LIMITS.MAX_SKILL_SIZE) {
947
- throw new SkillDiscoveryError(
948
- `Total skill size exceeds limit (${totalSize + fileSize} > ${SKILL_LIMITS.MAX_SKILL_SIZE}): ${dirPath}`,
949
- dirPath
950
- );
951
- }
952
- const content = await tryReadTextFile(filePath, this.fs);
953
- if (content === null) {
954
- continue;
955
- }
956
- totalSize += fileSize;
957
- files.set(key, content);
958
- } else if (entry.isDirectory) {
959
- if (IGNORED_DIRECTORIES.includes(entry.name)) {
960
- continue;
961
- }
962
- totalSize = await this.loadDirectoryFiles(filePath, key, files, depth + 1, totalSize);
963
- }
964
- }
965
- return totalSize;
966
- }
967
- /**
968
- * Create an initial skill context object
969
- */
970
- async createContext() {
971
- const availableSkills = await this.discoverAll();
972
- return {
973
- activeSkill: null,
974
- availableSkills,
975
- skillLoadingHistory: [],
976
- loadSkill: async (name) => {
977
- const ref = availableSkills.find((s) => s.metadata.name === name);
978
- if (!ref) return null;
979
- return this.loadSkill(ref.path, ref.source);
980
- }
981
- };
982
- }
983
- };
984
-
985
- // src/skills/validation.ts
986
- import { join as join3, normalize as normalize2 } from "path";
987
- function validateSkillSecurity(skill) {
988
- const { MAX_FILE_SIZE, MAX_SKILL_SIZE } = SKILL_LIMITS;
989
- let totalSize = 0;
990
- const contentSize = Buffer.byteLength(skill.content, "utf8");
991
- if (contentSize > MAX_FILE_SIZE) {
992
- throw new SkillValidationError(`SKILL.md content exceeds size limit (${contentSize} > ${MAX_FILE_SIZE})`, join3(skill.path, "SKILL.md"));
993
- }
994
- totalSize += contentSize;
995
- for (const [filename, content] of skill.files) {
996
- const fileSize = Buffer.byteLength(content, "utf8");
997
- if (fileSize > MAX_FILE_SIZE) {
998
- throw new SkillValidationError(`File ${filename} exceeds size limit (${fileSize} > ${MAX_FILE_SIZE})`, join3(skill.path, filename));
999
- }
1000
- totalSize += fileSize;
1001
- }
1002
- if (totalSize > MAX_SKILL_SIZE) {
1003
- throw new SkillValidationError(`Skill total size exceeds limit (${totalSize} > ${MAX_SKILL_SIZE})`, skill.path);
1004
- }
1005
- validateContentSecurity(skill.content, skill.path);
1006
- for (const [filename, content] of skill.files) {
1007
- validateContentSecurity(content, join3(skill.path, filename));
1008
- }
1009
- }
1010
- function validateContentSecurity(content, path) {
1011
- for (const pattern of SUSPICIOUS_PATTERNS) {
1012
- if (pattern.test(content)) {
1013
- throw new SkillValidationError("Suspicious content detected", path);
1014
- }
1015
- }
1016
- }
1017
- function validateSkillReferences(skill) {
1018
- const warnings = [];
1019
- const externalRefs = skill.content.match(/https?:\/\/[^\s\])]+/g) || [];
1020
- if (externalRefs.length > 0 && !skill.metadata.description.toLowerCase().includes("external")) {
1021
- warnings.push(
1022
- `Skill '${skill.metadata.name}' contains external references. Consider adding 'external' to description for transparency.`
1023
- );
1024
- }
1025
- const codeBlocks = skill.content.match(/```[\s\S]*?```/g) || [];
1026
- for (const block of codeBlocks) {
1027
- const pathsInCode = block.match(/\/[a-zA-Z][\w./-]*/g) || [];
1028
- for (const path of pathsInCode) {
1029
- if (!path.startsWith("/dev") && !path.startsWith("/proc") && !path.startsWith("/sys") && !path.startsWith("//")) {
1030
- warnings.push(`Skill '${skill.metadata.name}' contains possible absolute path '${path}'. Use relative paths instead.`);
1031
- }
1032
- }
1033
- }
1034
- const linkRegex = /\[[^\]]+\]\(([^)]+(?:\s+[^)]+)*)\)/g;
1035
- let match;
1036
- match = linkRegex.exec(skill.content);
1037
- while (match !== null) {
1038
- const filepath = match[1];
1039
- match = linkRegex.exec(skill.content);
1040
- if (filepath.startsWith("http://") || filepath.startsWith("https://") || filepath.startsWith("#")) {
1041
- continue;
1042
- }
1043
- const normalizedPath = normalize2(filepath).replace(/^\.?\//, "").replace(/\\/g, "/");
1044
- if (!skill.files.has(normalizedPath)) {
1045
- warnings.push(`Referenced file not found: ${filepath}`);
1046
- }
1047
- }
1048
- return warnings;
1049
- }
1050
- function validateSkillMetadata(skill) {
1051
- const errors = [];
1052
- if (skill.metadata.description.length < 20) {
1053
- errors.push(`Description too short: ${skill.metadata.description.length} < 20`);
1054
- }
1055
- return errors;
1056
- }
1057
- function getSkillStats(skill) {
1058
- let totalSize = Buffer.byteLength(skill.content, "utf8");
1059
- let largestFile = { name: "SKILL.md", size: totalSize };
1060
- let fileCount = 1;
1061
- for (const [name, content] of skill.files) {
1062
- const size = Buffer.byteLength(content, "utf8");
1063
- totalSize += size;
1064
- fileCount++;
1065
- if (size > largestFile.size) {
1066
- largestFile = { name, size };
1067
- }
1068
- }
1069
- return {
1070
- totalSize,
1071
- fileCount,
1072
- largestFile
1073
- };
1074
- }
1075
-
1076
- // src/skills/tools/listSkills.ts
1077
- import { z as z5 } from "zod";
1078
- var ListSkillsInputSchema = z5.object({
1079
- filter: z5.string().optional().describe("Optional filter string to match against skill names and descriptions")
1080
- });
1081
- var ListSkillsOutputSchema = z5.object({
1082
- skills: z5.array(
1083
- z5.object({
1084
- name: z5.string(),
1085
- description: z5.string(),
1086
- source: z5.enum(["personal", "project", "plugin"])
1087
- })
1088
- ),
1089
- total: z5.number()
1090
- });
1091
- async function listSkills(input, context) {
1092
- const { filter } = input;
1093
- let skills = context.availableSkills;
1094
- if (filter) {
1095
- const filterLower = filter.toLowerCase();
1096
- skills = skills.filter((s) => s.metadata.name.includes(filterLower) || s.metadata.description.toLowerCase().includes(filterLower));
1097
- }
1098
- return {
1099
- skills: skills.map((s) => ({
1100
- name: s.metadata.name,
1101
- description: s.metadata.description,
1102
- source: s.source
1103
- })),
1104
- total: skills.length
1105
- };
1106
- }
1107
- var listSkillsToolInfo = {
1108
- name: "listSkills",
1109
- description: "List all available skills with their descriptions. Use this to discover what specialized capabilities are available.",
1110
- parameters: ListSkillsInputSchema,
1111
- returns: ListSkillsOutputSchema
1112
- };
1113
-
1114
- // src/skills/tools/loadSkill.ts
1115
- import { z as z6 } from "zod";
1116
- var LoadSkillInputSchema = z6.object({
1117
- skillName: z6.string().describe("The name of the skill to load")
1118
- });
1119
- var LoadSkillOutputSchema = z6.object({
1120
- success: z6.boolean(),
1121
- skill: z6.object({
1122
- name: z6.string(),
1123
- description: z6.string(),
1124
- content: z6.string(),
1125
- availableFiles: z6.array(z6.string())
1126
- }).optional(),
1127
- error: z6.string().optional(),
1128
- warnings: z6.array(z6.string()).optional()
1129
- });
1130
- async function loadSkill(input, context) {
1131
- const { skillName } = input;
1132
- const skillRef = context.availableSkills.find((s) => s.metadata.name === skillName);
1133
- if (!skillRef) {
1134
- return {
1135
- success: false,
1136
- error: `Skill '${skillName}' not found`
1137
- };
1138
- }
1139
- try {
1140
- const skill = await context.loadSkill(skillName);
1141
- if (!skill) {
1142
- return {
1143
- success: false,
1144
- error: `Failed to load skill '${skillName}'`
1145
- };
1146
- }
1147
- validateSkillSecurity(skill);
1148
- const warnings = validateSkillReferences(skill);
1149
- context.activeSkill = skill;
1150
- context.skillLoadingHistory.push(skillName);
1151
- return {
1152
- success: true,
1153
- skill: {
1154
- name: skill.metadata.name,
1155
- description: skill.metadata.description,
1156
- content: skill.content,
1157
- availableFiles: Array.from(skill.files.keys())
1158
- },
1159
- warnings: warnings.length > 0 ? warnings : void 0
1160
- };
1161
- } catch (error) {
1162
- const message = error instanceof Error ? error.message : String(error);
1163
- return {
1164
- success: false,
1165
- error: `Failed to load skill '${skillName}': ${message}`
1166
- };
1167
- }
1168
- }
1169
- var loadSkillToolInfo = {
1170
- name: "loadSkill",
1171
- description: "Load a skill by name to access its instructions and resources. Use this when you need specialized knowledge or capabilities for a specific task.",
1172
- parameters: LoadSkillInputSchema,
1173
- returns: LoadSkillOutputSchema
1174
- };
1175
-
1176
- // src/skills/tools/readSkillFile.ts
1177
- import { z as z7 } from "zod";
1178
- var ReadSkillFileInputSchema = z7.object({
1179
- skillName: z7.string().describe("The name of the skill"),
1180
- filename: z7.string().describe('The name of the file to read (e.g., "reference.md", "scripts/helper.py")')
1181
- });
1182
- var ReadSkillFileOutputSchema = z7.object({
1183
- success: z7.boolean(),
1184
- content: z7.string().optional(),
1185
- error: z7.string().optional()
1186
- });
1187
- async function readSkillFile(input, context) {
1188
- const { skillName, filename } = input;
1189
- let skill = context.activeSkill && context.activeSkill.metadata.name === skillName ? context.activeSkill : null;
1190
- if (!skill) {
1191
- try {
1192
- skill = await context.loadSkill(skillName);
1193
- } catch (_error) {
1194
- }
1195
- }
1196
- if (!skill) {
1197
- return {
1198
- success: false,
1199
- error: `Skill '${skillName}' not found or could not be loaded. Use loadSkill first.`
1200
- };
1201
- }
1202
- if (!skill.files.has(filename)) {
1203
- const availableFiles = Array.from(skill.files.keys()).sort();
1204
- return {
1205
- success: false,
1206
- error: `File '${filename}' not found in skill '${skillName}'. Available files: ${availableFiles.join(", ") || "none"}`
1207
- };
1208
- }
1209
- const content = skill.files.get(filename);
1210
- return {
1211
- success: true,
1212
- content
1213
- };
1214
- }
1215
- var readSkillFileToolInfo = {
1216
- name: "readSkillFile",
1217
- description: "Read a supporting file from a skill. Use this to access reference documentation, examples, scripts, or templates bundled with a skill. First use loadSkill to see available files, then use this tool to read specific files.",
1218
- parameters: ReadSkillFileInputSchema,
1219
- returns: ReadSkillFileOutputSchema
1220
- };
1221
-
1222
- // src/tools/askFollowupQuestion.ts
1223
- import { z as z8 } from "zod";
1224
- var questionObject = z8.object({
1225
- prompt: z8.string().describe("The text of the question.").meta({ usageValue: "question text here" }),
1226
- options: z8.array(z8.string()).default([]).describe("Ordered list of suggested answers (omit if none).").meta({ usageValue: "suggested answer here" })
1227
- });
1228
- var toolInfo = {
1229
- name: "askFollowupQuestion",
1230
- description: "Call this when vital details are missing. Pose each follow-up as one direct, unambiguous question. If it speeds the reply, add up to five short, mutually-exclusive answer options. Group any related questions in the same call to avoid a back-and-forth chain.",
1231
- parameters: z8.object({
1232
- questions: z8.array(questionObject).describe("One or more follow-up questions you need answered before you can continue.").meta({ usageValue: "questions here" })
1233
- }).meta({
1234
- examples: [
1235
- {
1236
- description: "Single clarifying question (no options)",
1237
- input: {
1238
- questions: [{ prompt: "What is the target deployment environment?" }]
1239
- }
1240
- },
1241
- {
1242
- description: "Single question with multiple-choice options",
1243
- input: {
1244
- questions: [
1245
- {
1246
- prompt: "Which frontend framework are you using?",
1247
- options: ["React", "Angular", "Vue", "Svelte"]
1248
- }
1249
- ]
1250
- }
1251
- },
1252
- {
1253
- description: "Two related questions in one call",
1254
- input: {
1255
- questions: [
1256
- { prompt: "What type of application are you building?" },
1257
- {
1258
- prompt: "Preferred programming language?",
1259
- options: ["JavaScript", "TypeScript", "Python", "Java"]
1260
- }
1261
- ]
1262
- }
1263
- },
1264
- {
1265
- description: "Binary (yes/no) confirmation",
1266
- input: {
1267
- questions: [
1268
- {
1269
- prompt: "Is it acceptable to refactor existing tests to improve performance?",
1270
- options: ["Yes", "No"]
1271
- }
1272
- ]
1273
- }
1274
- }
1275
- ]
1276
- })
1277
- };
1278
- var handler = async (provider, args) => {
1279
- if (!provider.askFollowupQuestion) {
1280
- return {
1281
- success: false,
1282
- message: {
1283
- type: "error-text",
1284
- value: "Not possible to ask followup question."
1285
- }
1286
- };
1287
- }
1288
- const { questions } = toolInfo.parameters.parse(args);
1289
- if (questions.length === 0) {
1290
- return {
1291
- success: false,
1292
- message: {
1293
- type: "error-text",
1294
- value: "No questions provided"
1295
- }
1296
- };
1297
- }
1298
- const answers = [];
1299
- for (const question of questions) {
1300
- const { prompt, options } = question;
1301
- const answer = await provider.askFollowupQuestion(prompt, options);
1302
- answers.push(`<ask_followup_question_answer question="${prompt}">
1303
- ${answer}
1304
- </ask_followup_question_answer>`);
1305
- }
1306
- return {
1307
- success: true,
1308
- message: {
1309
- type: "text",
1310
- value: answers.join("\n")
1311
- }
1312
- };
1313
- };
1314
- var askFollowupQuestion_default = {
1315
- ...toolInfo,
1316
- handler
1317
- };
1318
-
1319
- // src/tools/executeCommand.ts
1320
- import { z as z9 } from "zod";
1321
-
1322
- // src/tools/response-builders.ts
1323
- function createSuccessResponse(value, type = "text") {
1324
- return {
1325
- success: true,
1326
- message: { type, value }
1327
- };
1328
- }
1329
- function createErrorResponse(message) {
1330
- return {
1331
- success: false,
1332
- message: { type: "error-text", value: message }
1333
- };
1334
- }
1335
- function createProviderErrorResponse(capability) {
1336
- return {
1337
- success: false,
1338
- message: {
1339
- type: "error-text",
1340
- value: `Not possible to ${capability}.`
1341
- }
1342
- };
1343
- }
1344
- function createValidationErrorResponse(errors) {
1345
- return {
1346
- success: false,
1347
- message: {
1348
- type: "error-text",
1349
- value: `Validation failed: ${errors.message}`
1350
- }
1351
- };
1352
- }
1353
-
1354
- // src/tools/utils.ts
1355
- function preprocessBoolean(val) {
1356
- return typeof val === "string" ? val.toLowerCase() === "true" : val;
1357
- }
1358
- function createFileElement(tagName, path, content, attrs) {
1359
- const allAttrs = { path, ...attrs };
1360
- const attrStr = Object.entries(allAttrs).map(([k, v]) => ` ${k}="${v}"`).join("");
1361
- if (content === void 0) {
1362
- return `<${tagName}${attrStr} />`;
1363
- }
1364
- const isEmpty = content.trim().length === 0;
1365
- if (isEmpty) {
1366
- return `<${tagName}${attrStr} is_empty="true" />`;
1367
- }
1368
- return `<${tagName}${attrStr}>${content}</${tagName}>`;
1369
- }
1370
-
1371
- // src/tools/executeCommand.ts
1372
- var toolInfo2 = {
1373
- name: "executeCommand",
1374
- description: "Run a single CLI command. The command is always executed in the project-root working directory (regardless of earlier commands). Prefer one-off shell commands over wrapper scripts for flexibility. **IMPORTANT**: After an `execute_command` call, you MUST stop and NOT allowed to make further tool calls in the same message.",
1375
- parameters: z9.object({
1376
- command: z9.string().describe("The exact command to run (valid for the current OS). It must be correctly formatted and free of harmful instructions.").meta({ usageValue: "your-command-here" }),
1377
- requiresApproval: z9.preprocess(preprocessBoolean, z9.boolean().optional().default(false)).describe(
1378
- "Set to `true` for commands that install/uninstall software, modify or delete files, change system settings, perform network operations, or have other side effects. Use `false` for safe, read-only, or purely local development actions (e.g., listing files, make a build, running tests)."
1379
- ).meta({ usageValue: "true | false" })
1380
- }).meta({
1381
- examples: [
1382
- {
1383
- description: "Make a build",
1384
- input: {
1385
- command: "npm run build",
1386
- requiresApproval: "false"
1387
- }
1388
- }
1389
- ]
1390
- })
1391
- };
1392
- var handler2 = async (provider, args) => {
1393
- if (!provider.executeCommand) {
1394
- return createProviderErrorResponse("execute command. Abort");
1395
- }
1396
- const { command, requiresApproval } = toolInfo2.parameters.parse(args);
1397
- try {
1398
- const result = await provider.executeCommand(command, requiresApproval);
1399
- let message = `<command>${command}</command>
1400
- <command_exit_code>${result.exitCode}</command_exit_code>
1401
- `;
1402
- if (result.summary) {
1403
- message += `<command_output_summary>
1404
- ${result.summary}
1405
- </command_output_summary>
1406
- `;
1407
- } else {
1408
- message += `<command_stdout>
1409
- ${result.stdout}
1410
- </command_stdout>
1411
- <command_stderr>
1412
- ${result.stderr}
1413
- </command_stderr>
1414
- `;
1415
- }
1416
- if (result.exitCode === 0) {
1417
- return {
1418
- success: true,
1419
- message: {
1420
- type: "text",
1421
- value: message
1422
- }
1423
- };
1424
- }
1425
- return {
1426
- success: false,
1427
- message: {
1428
- type: "error-text",
1429
- value: message
1430
- }
1431
- };
1432
- } catch (error) {
1433
- return {
1434
- success: false,
1435
- message: {
1436
- type: "error-text",
1437
- value: error instanceof Error ? error.message : String(error)
1438
- }
1439
- };
1440
- }
1441
- };
1442
- var executeCommand_default = {
1443
- ...toolInfo2,
1444
- handler: handler2
1445
- };
1446
-
1447
- // src/tools/fetchUrl.ts
1448
- import { z as z10 } from "zod";
1449
- var toolInfo3 = {
1450
- name: "fetchUrl",
1451
- description: "Fetch the content located at one or more HTTP(S) URLs and return it in Markdown format. This works for standard web pages as well as raw files (e.g. README.md, source code) hosted on platforms like GitHub.",
1452
- parameters: z10.object({
1453
- url: z10.preprocess((val) => {
1454
- if (!val) return [];
1455
- const values = Array.isArray(val) ? val : [val];
1456
- return values.flatMap((i) => typeof i === "string" ? i.split(",") : []).filter((s) => s.length > 0);
1457
- }, z10.array(z10.string())).describe("One or more URLs to fetch, separated by commas if multiple.").meta({ usageValue: "url" })
1458
- }).meta({
1459
- examples: [
1460
- {
1461
- description: "Fetch a single webpage",
1462
- input: {
1463
- url: "https://example.com"
1464
- }
1465
- },
1466
- {
1467
- description: "Fetch multiple webpages",
1468
- input: {
1469
- url: "https://example.com,https://developer.mozilla.org/en-US/docs/Web/HTTP"
1470
- }
1471
- },
1472
- {
1473
- description: "Fetch a raw file from GitHub",
1474
- input: {
1475
- url: "https://raw.githubusercontent.com/user/repo/main/README.md"
1476
- }
1477
- }
1478
- ]
1479
- })
1480
- };
1481
- var handler3 = async (provider, args) => {
1482
- if (!provider.fetchUrl) {
1483
- return {
1484
- success: false,
1485
- message: {
1486
- type: "error-text",
1487
- value: "Not possible to fetch url."
1488
- }
1489
- };
1490
- }
1491
- const { url: urls } = toolInfo3.parameters.parse(args);
1492
- if (urls.length === 0) {
1493
- return {
1494
- success: false,
1495
- message: {
1496
- type: "error-text",
1497
- value: "No URLs provided. Please provide at least one URL to fetch."
1498
- }
1499
- };
1500
- }
1501
- const results = [];
1502
- for (const url of urls) {
1503
- try {
1504
- const content = provider.fetchUrl(url).then((res) => `<fetch_url_content url="${url}">${res}</fetch_url_content>`);
1505
- results.push(content);
1506
- } catch (error) {
1507
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
1508
- results.push(Promise.resolve(`<fetch_url_error url="${url}">${errorMessage}</fetch_url_error>`));
1509
- }
1510
- }
1511
- const resolvedResults = await Promise.all(results);
1512
- return {
1513
- success: true,
1514
- message: {
1515
- type: "text",
1516
- value: resolvedResults.join("\n")
1517
- }
1518
- };
1519
- };
1520
- var fetchUrl_default = {
1521
- ...toolInfo3,
1522
- handler: handler3
1523
- };
1524
-
1525
- // src/tools/listFiles.ts
1526
- import { z as z11 } from "zod";
1527
- var toolInfo4 = {
1528
- name: "listFiles",
1529
- 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.",
1530
- parameters: z11.object({
1531
- path: z11.string().describe("The path of the directory to list contents for (relative to the current working directory)").meta({ usageValue: "Directory path here" }),
1532
- maxCount: z11.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)" }),
1533
- recursive: z11.preprocess(preprocessBoolean, z11.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)" }),
1534
- includeIgnored: z11.preprocess(preprocessBoolean, z11.boolean().optional().default(false)).describe("Whether to include ignored files. Use true to include files ignored by .gitignore.").meta({ usageValue: "true or false (optional)" })
1535
- }).meta({
1536
- examples: [
1537
- {
1538
- description: "Request to list files",
1539
- input: {
1540
- path: "src",
1541
- maxCount: "100"
1542
- }
1543
- }
1544
- ]
1545
- })
1546
- };
1547
- var handler4 = async (provider, args) => {
1548
- if (!provider.listFiles) {
1549
- return createProviderErrorResponse("list files");
1550
- }
1551
- const { path, maxCount, recursive, includeIgnored } = toolInfo4.parameters.parse(args);
1552
- const [files, limitReached] = await provider.listFiles(path, recursive, maxCount, includeIgnored);
1553
- return {
1554
- success: true,
1555
- message: {
1556
- type: "text",
1557
- value: `<list_files_path>${path}</list_files_path>
1558
- <list_files_files>
1559
- ${files.join("\n")}
1560
- </list_files_files>
1561
- <list_files_truncated>${limitReached}</list_files_truncated>`
1562
- }
1563
- };
1564
- };
1565
- var listFiles_default = {
1566
- ...toolInfo4,
1567
- handler: handler4
1568
- };
1569
-
1570
- // src/tools/provider.ts
1571
- var MockProvider = class {
1572
- async listTodoItems(id, _status) {
1573
- if (id) {
1574
- return [{ id: `${id}-1`, title: "mock sub item", status: "open", description: "" }];
1575
- }
1576
- return [{ id: "1", title: "mock item", status: "open", description: "" }];
1577
- }
1578
- async getTodoItem(id) {
1579
- return {
1580
- id,
1581
- title: "mock item",
1582
- description: "mock desc",
1583
- status: "open",
1584
- subItems: []
1585
- };
1586
- }
1587
- async updateTodoItem(input) {
1588
- if (input.operation === "add") {
1589
- return { id: "2" };
1590
- }
1591
- return { id: input.id };
1592
- }
1593
- async readFile(_path, _includeIgnored) {
1594
- return "mock content";
1595
- }
1596
- async writeFile(_path, _content) {
1597
- return;
1598
- }
1599
- async removeFile(_path) {
1600
- return;
1601
- }
1602
- async renameFile(_sourcePath, _targetPath) {
1603
- return;
1604
- }
1605
- async listFiles(_path, _recursive, _maxCount, _includeIgnored) {
1606
- return [["mock-file.txt"], false];
1607
- }
1608
- async searchFiles(_path, _regex, _filePattern) {
1609
- return ["mock-file.txt"];
1610
- }
1611
- async executeCommand(_command, _needApprove) {
1612
- return { stdout: "mock output", stderr: "", exitCode: 0 };
1613
- }
1614
- async askFollowupQuestion(_question, _options) {
1615
- return "mock answer";
1616
- }
1617
- async search(_query) {
1618
- return "mock search result";
1619
- }
1620
- async listMemoryTopics() {
1621
- return ["default"];
1622
- }
1623
- async readMemory(_topic) {
1624
- return "mock memory content";
1625
- }
1626
- async updateMemory(_operation, _topic, _content) {
1627
- return;
1628
- }
1629
- };
1630
-
1631
- // src/tools/readBinaryFile.ts
1632
- import { z as z12 } from "zod";
1633
- var toolInfo5 = {
1634
- name: "readBinaryFile",
1635
- 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.",
1636
- parameters: z12.object({
1637
- url: z12.string().describe("The URL or local path of the file to read.")
1638
- })
1639
- };
1640
- var handler5 = async (provider, args) => {
1641
- if (!provider.readBinaryFile) {
1642
- return {
1643
- success: false,
1644
- message: {
1645
- type: "error-text",
1646
- value: "Not possible to fetch files. Abort."
1647
- }
1648
- };
1649
- }
1650
- const { url } = toolInfo5.parameters.parse(args);
1651
- try {
1652
- const filePart = await provider.readBinaryFile(url);
1653
- return {
1654
- success: true,
1655
- message: {
1656
- type: "content",
1657
- value: [
1658
- {
1659
- type: "media",
1660
- url,
1661
- data: filePart.base64Data,
1662
- mediaType: filePart.mediaType
1663
- }
1664
- ]
1665
- }
1666
- };
1667
- } catch (error) {
1668
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
1669
- return {
1670
- success: false,
1671
- message: {
1672
- type: "error-text",
1673
- value: `Error fetching file from ${url}: ${errorMessage}`
1674
- }
1675
- };
1676
- }
1677
- };
1678
- var readBinaryFile_default = {
1679
- ...toolInfo5,
1680
- handler: handler5
1681
- };
1682
-
1683
- // src/tools/readFile.ts
1684
- import { z as z13 } from "zod";
1685
- var toolInfo6 = {
1686
- name: "readFile",
1687
- description: `Request to read the contents of one or multiple files at the specified paths.
1688
-
1689
- When to use:
1690
- - Examining file contents you don't know
1691
- - Analyzing code, reviewing text files, extracting configuration info
1692
- - Reading multiple files at once (use comma-separated paths)
1693
- - Understanding file structure before editing
1694
-
1695
- When NOT to use:
1696
- - For file existence checks: Use listFiles instead
1697
- - For searching within files: Use grep instead
1698
- - For file name searches: Use searchFiles instead
1699
- - Prefer this tool over executeCommand with cat/head/tail
1700
-
1701
- Features:
1702
- - Supports comma-separated paths for multiple files
1703
- - Line numbers included for easy reference
1704
- - Optional offset/limit for partial file reading
1705
- - Automatically handles different file types
1706
-
1707
- IMPORTANT:
1708
- - Line numbers are included for easy reference
1709
- - Use offset/limit for large files to read specific sections`,
1710
- parameters: z13.object({
1711
- path: z13.preprocess((val) => {
1712
- if (!val) return [];
1713
- if (Array.isArray(val)) {
1714
- return val.filter((s) => typeof s === "string" && s.length > 0);
1715
- }
1716
- return val.split(",").filter((s) => s.length > 0);
1717
- }, z13.array(z13.string())).describe("The path of the file to read").meta({ usageValue: "Comma separated paths here" }),
1718
- offset: z13.number().optional().describe("Skip first N lines (for partial file reading)").meta({ usageValue: "100" }),
1719
- limit: z13.number().optional().describe("Read at most N lines (for partial file reading)").meta({ usageValue: "50" }),
1720
- includeIgnored: z13.preprocess(preprocessBoolean, z13.boolean().nullish().default(false)).describe("Whether to include ignored files. Use true to include files ignored by .gitignore.").meta({ usageValue: "true or false (optional)" })
1721
- }).meta({
1722
- examples: [
1723
- {
1724
- description: "Request to read the contents of a file",
1725
- input: {
1726
- path: "src/main.js"
1727
- }
1728
- },
1729
- {
1730
- description: "Request to read multiple files",
1731
- input: {
1732
- path: "src/main.js,src/index.js"
1733
- }
1734
- },
1735
- {
1736
- description: "Read partial file (lines 100-150)",
1737
- input: {
1738
- path: "src/large-file.ts",
1739
- offset: 100,
1740
- limit: 50
1741
- }
1742
- }
1743
- ]
1744
- })
1745
- };
1746
- var handler6 = async (provider, args) => {
1747
- if (!provider.readFile) {
1748
- return createProviderErrorResponse("read file");
1749
- }
1750
- const parsed = toolInfo6.parameters.safeParse(args);
1751
- if (!parsed.success) {
1752
- return {
1753
- success: false,
1754
- message: {
1755
- type: "error-text",
1756
- value: `Invalid arguments for readFile: ${parsed.error.message}`
1757
- }
1758
- };
1759
- }
1760
- const { path: paths, offset, limit, includeIgnored } = parsed.data;
1761
- const resp = [];
1762
- for (const path of paths) {
1763
- const fileContent = await provider.readFile(path, includeIgnored ?? false);
1764
- if (!fileContent) {
1765
- resp.push(createFileElement("read_file_file_content", path, void 0, { file_not_found: "true" }));
1766
- continue;
1767
- }
1768
- let lines = fileContent.split("\n");
1769
- const start = offset ?? 0;
1770
- const end = limit ? start + limit : lines.length;
1771
- if (offset !== void 0 || limit !== void 0) {
1772
- lines = lines.slice(start, end);
1773
- }
1774
- const lineOffset = offset ?? 0;
1775
- const numberedContent = lines.map((line, i) => {
1776
- const lineNumber = lineOffset + i + 1;
1777
- const paddedNumber = String(lineNumber).padStart(6, " ");
1778
- return `${paddedNumber}\u2192${line}`;
1779
- }).join("\n");
1780
- resp.push(createFileElement("read_file_file_content", path, numberedContent));
1781
- }
1782
- return {
1783
- success: true,
1784
- message: {
1785
- type: "text",
1786
- value: resp.join("\n")
1787
- }
1788
- };
1789
- };
1790
- var readFile_default = {
1791
- ...toolInfo6,
1792
- handler: handler6
1793
- };
1794
-
1795
- // src/tools/removeFile.ts
1796
- import { z as z14 } from "zod";
1797
- var toolInfo7 = {
1798
- name: "removeFile",
1799
- description: "Request to remove a file at the specified path.",
1800
- parameters: z14.object({
1801
- path: z14.string().describe("The path of the file to remove").meta({ usageValue: "File path here" })
1802
- }).meta({
1803
- examples: [
1804
- {
1805
- description: "Request to remove a file",
1806
- input: {
1807
- path: "src/main.js"
1808
- }
1809
- }
1810
- ]
1811
- })
1812
- };
1813
- var handler7 = async (provider, args) => {
1814
- if (!provider.removeFile) {
1815
- return createProviderErrorResponse("remove file");
1816
- }
1817
- const parsed = toolInfo7.parameters.safeParse(args);
1818
- if (!parsed.success) {
1819
- return {
1820
- success: false,
1821
- message: {
1822
- type: "error-text",
1823
- value: `Invalid arguments for removeFile: ${parsed.error.message}`
1824
- }
1825
- };
1826
- }
1827
- const { path } = parsed.data;
1828
- await provider.removeFile(path);
1829
- return {
1830
- success: true,
1831
- message: {
1832
- type: "text",
1833
- value: `<remove_file_path>${path}</remove_file_path><status>Success</status>`
1834
- }
1835
- };
1836
- };
1837
- var removeFile_default = {
1838
- ...toolInfo7,
1839
- handler: handler7
1840
- };
1841
-
1842
- // src/tools/renameFile.ts
1843
- import { z as z15 } from "zod";
1844
- var toolInfo8 = {
1845
- name: "renameFile",
1846
- description: "Request to rename a file from source path to target path.",
1847
- parameters: z15.object({
1848
- source_path: z15.string().describe("The current path of the file").meta({ usageValue: "Source file path here" }),
1849
- target_path: z15.string().describe("The new path for the file").meta({ usageValue: "Target file path here" })
1850
- }).meta({
1851
- examples: [
1852
- {
1853
- description: "Request to rename a file",
1854
- input: {
1855
- source_path: "src/old-name.js",
1856
- target_path: "src/new-name.js"
1857
- }
1858
- }
1859
- ]
1860
- })
1861
- };
1862
- var handler8 = async (provider, args) => {
1863
- if (!provider.renameFile) {
1864
- return {
1865
- success: false,
1866
- message: {
1867
- type: "error-text",
1868
- value: "Not possible to rename file."
1869
- }
1870
- };
1871
- }
1872
- const { source_path, target_path } = toolInfo8.parameters.parse(args);
1873
- await provider.renameFile(source_path, target_path);
1874
- return {
1875
- success: true,
1876
- message: {
1877
- type: "text",
1878
- value: `<rename_file_path>${target_path}</rename_file_path><status>Success</status>`
1879
- }
1880
- };
1881
- };
1882
- var renameFile_default = {
1883
- ...toolInfo8,
1884
- handler: handler8
1885
- };
1886
-
1887
- // src/tools/replaceInFile.ts
1888
- import { z as z16 } from "zod";
1889
-
1890
- // src/tools/utils/replaceInFile.ts
1891
- var replaceInFile = (fileContent, diff) => {
1892
- const blockPattern = /^\s*<<<<<+\s*SEARCH>?\s*\r?\n([\s\S]*?)\r?\n=======[ \t]*\r?\n([\s\S]*?)\r?\n?>>>>>+\s*REPLACE\s*$/gm;
1893
- const blocks = [];
1894
- for (let match = blockPattern.exec(diff); match !== null; match = blockPattern.exec(diff)) {
1895
- blocks.push({ search: match[1], replace: match[2] });
1896
- }
1897
- if (blocks.length === 0) {
1898
- throw new Error("No valid diff blocks found.");
1899
- }
1900
- const findAndReplace = (content, search, replace) => {
1901
- let index = content.indexOf(search);
1902
- if (index !== -1) {
1903
- return content.slice(0, index) + replace + content.slice(index + search.length);
1904
- }
1905
- const trimmedSearch = search.trim();
1906
- const trimmedContent = content.trim();
1907
- const offset = content.indexOf(trimmedContent);
1908
- index = trimmedContent.indexOf(trimmedSearch);
1909
- if (index !== -1) {
1910
- const absoluteIndex = offset + index;
1911
- return content.slice(0, absoluteIndex) + replace + content.slice(absoluteIndex + trimmedSearch.length);
1912
- }
1913
- const normalizedSearch = trimmedSearch.replace(/\s+/g, " ");
1914
- const normalizedContent = trimmedContent.replace(/\s+/g, " ");
1915
- index = normalizedContent.indexOf(normalizedSearch);
1916
- if (index !== -1) {
1917
- let runningIndex = 0;
1918
- let actualPos = offset;
1919
- for (const segment of trimmedSearch.replace(/\s+/g, " ").split(" ")) {
1920
- const segIndex = content.indexOf(segment, actualPos);
1921
- if (segIndex === -1) {
1922
- break;
1923
- }
1924
- if (runningIndex === 0) {
1925
- actualPos = segIndex;
1926
- } else {
1927
- actualPos = segIndex + segment.length;
1928
- }
1929
- runningIndex++;
1930
- }
1931
- const searchWords = trimmedSearch.replace(/\s+/g, " ").split(" ").filter((w) => w.length > 0);
1932
- let matchStartPos = -1;
1933
- let matchEndPos = -1;
1934
- if (searchWords.length > 0) {
1935
- const firstWordPos = content.indexOf(searchWords[0], offset);
1936
- if (firstWordPos !== -1) {
1937
- matchStartPos = firstWordPos;
1938
- matchEndPos = firstWordPos + searchWords[0].length;
1939
- for (let i = 1; i < searchWords.length; i++) {
1940
- const nextWordPos = content.indexOf(searchWords[i], matchEndPos);
1941
- if (nextWordPos === -1 || nextWordPos > matchEndPos + 100) {
1942
- matchStartPos = -1;
1943
- break;
1944
- }
1945
- matchEndPos = nextWordPos + searchWords[i].length;
1946
- }
1947
- }
1948
- }
1949
- if (matchStartPos !== -1 && matchEndPos !== -1) {
1950
- return content.slice(0, matchStartPos) + replace + content.slice(matchEndPos);
1951
- }
1952
- }
1953
- return null;
1954
- };
1955
- let updatedFile = fileContent;
1956
- let appliedCount = 0;
1957
- const totalCount = blocks.length;
1958
- for (const { search, replace } of blocks) {
1959
- const result = findAndReplace(updatedFile, search, replace);
1960
- if (result !== null) {
1961
- updatedFile = result;
1962
- appliedCount++;
1963
- }
1964
- }
1965
- let status;
1966
- if (appliedCount === 0) {
1967
- status = "no_diff_applied";
1968
- } else if (appliedCount < totalCount) {
1969
- status = "some_diff_applied";
1970
- } else {
1971
- status = "all_diff_applied";
1972
- }
1973
- return {
1974
- content: updatedFile,
1975
- status,
1976
- appliedCount,
1977
- totalCount
1978
- };
1979
- };
1980
-
1981
- // src/tools/replaceInFile.ts
1982
- var toolInfo9 = {
1983
- name: "replaceInFile",
1984
- description: `Request to replace sections of content in an existing file using
1985
- SEARCH/REPLACE blocks.
1986
-
1987
- When to use:
1988
- - Making targeted changes to specific parts of a file
1989
- - Replacing variable names, function signatures, imports
1990
- - Fixing bugs in existing code
1991
- - When you know the exact content to replace
1992
-
1993
- When NOT to use:
1994
- - For creating new files: Use writeToFile instead
1995
- - For completely replacing file contents: Use writeToFile instead
1996
- - When you don't know the exact content: Read file first
1997
-
1998
- SEARCH/REPLACE FORMAT:
1999
- <<<<<<< SEARCH
2000
- [exact content to find]
2001
- =======
2002
- [new content to replace with]
2003
- >>>>>>> REPLACE
2004
-
2005
- Critical rules:
2006
- 1. SEARCH content must match EXACTLY (character-for-character including whitespace)
2007
- 2. Each block replaces only first occurrence
2008
- 3. Include just enough lines for uniqueness (not too many, not too few)
2009
- 4. Keep blocks concise (don't include long unchanged sections)
2010
- 5. List blocks in order they appear in file
2011
- 6. Use multiple blocks for multiple independent changes
2012
-
2013
- Special operations:
2014
- - Move code: Two blocks (delete from original + insert at new location)
2015
- - Delete code: Empty REPLACE section
2016
-
2017
- IMPORTANT CONSTRAINTS:
2018
- - SEARCH text must match file content exactly
2019
- - Each block is independent (doesn't affect other blocks)
2020
- - Cannot use for appending or inserting without SEARCH context`,
2021
- parameters: z16.object({
2022
- path: z16.string().describe("The path of the file to modify").meta({ usageValue: "File path here" }),
2023
- diff: z16.string().describe(
2024
- `One or more SEARCH/REPLACE blocks following this exact format:
2025
- \`\`\`
2026
- <<<<<<< SEARCH
2027
- [exact content to find]
2028
- =======
2029
- [new content to replace with]
2030
- >>>>>>> REPLACE
2031
- \`\`\`
2032
- Critical rules:
2033
- 1. SEARCH content must match the associated file section to find EXACTLY:
2034
- * Match character-for-character including whitespace, indentation, line endings
2035
- * Include all comments, docstrings, etc.
2036
- 2. SEARCH/REPLACE blocks will ONLY replace the first match occurrence.
2037
- * Including multiple unique SEARCH/REPLACE blocks if you need to make multiple changes.
2038
- * Include *just* enough lines in each SEARCH section to uniquely match each set of lines that need to change.
2039
- * When using multiple SEARCH/REPLACE blocks, list them in the order they appear in the file.
2040
- 3. Keep SEARCH/REPLACE blocks concise:
2041
- * Break large SEARCH/REPLACE blocks into a series of smaller blocks that each change a small portion of the file.
2042
- * Include just the changing lines, and a few surrounding lines if needed for uniqueness.
2043
- * Do not include long runs of unchanging lines in SEARCH/REPLACE blocks.
2044
- * Each line must be complete. Never truncate lines mid-way through as this can cause matching failures.
2045
- 4. Special operations:
2046
- * To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
2047
- * To delete code: Empty REPLACE section`
2048
- ).meta({ usageValue: "Search and replace blocks here" })
2049
- }).meta({
2050
- examples: [
2051
- {
2052
- description: "Request to replace sections of content in a file",
2053
- input: {
2054
- path: "src/main.js",
2055
- diff: `<<<<<<< SEARCH
2056
- import React from 'react';
2057
- =======
2058
- import React, { useState } from 'react';
2059
- >>>>>>> REPLACE
2060
-
2061
- <<<<<<< SEARCH
2062
- function handleSubmit() {
2063
- saveData();
2064
- setLoading(false);
2065
- }
2066
-
2067
- =======
2068
- >>>>>>> REPLACE
2069
-
2070
- <<<<<<< SEARCH
2071
- return (
2072
- <div>
2073
- =======
2074
- function handleSubmit() {
2075
- saveData();
2076
- setLoading(false);
2077
- }
2078
-
2079
- return (
2080
- <div>
2081
- >>>>>>> REPLACE`
2082
- }
2083
- },
2084
- {
2085
- description: "Request to perform a simple, single-line replacement",
2086
- input: {
2087
- path: "src/config.js",
2088
- diff: `<<<<<<< SEARCH
2089
- const API_URL = 'https://api.example.com';
2090
- =======
2091
- const API_URL = 'https://api.staging.example.com';
2092
- >>>>>>> REPLACE`
2093
- }
2094
- },
2095
- {
2096
- description: "Request to add a new function to a file",
2097
- input: {
2098
- path: "src/utils.js",
2099
- diff: `<<<<<<< SEARCH
2100
- function helperA() {
2101
- // ...
2102
- }
2103
- =======
2104
- function helperA() {
2105
- // ...
2106
- }
2107
-
2108
- function newHelper() {
2109
- // implementation
2110
- }
2111
- >>>>>>> REPLACE`
2112
- }
2113
- },
2114
- {
2115
- description: "Request to delete a block of code from a file",
2116
- input: {
2117
- path: "src/app.js",
2118
- diff: `<<<<<<< SEARCH
2119
- function oldFeature() {
2120
- // This is no longer needed
2121
- }
2122
-
2123
- =======
2124
- >>>>>>> REPLACE`
2125
- }
2126
- }
2127
- ]
2128
- })
2129
- };
2130
- var handler9 = async (provider, args) => {
2131
- if (!provider.readFile || !provider.writeFile) {
2132
- return {
2133
- success: false,
2134
- message: {
2135
- type: "error-text",
2136
- value: "Not possible to replace in file."
2137
- }
2138
- };
2139
- }
2140
- const parsed = toolInfo9.parameters.safeParse(args);
2141
- if (!parsed.success) {
2142
- return {
2143
- success: false,
2144
- message: {
2145
- type: "error-text",
2146
- value: `Invalid arguments for replaceInFile: ${parsed.error.message}`
2147
- }
2148
- };
2149
- }
2150
- const { path, diff } = parsed.data;
2151
- try {
2152
- const fileContent = await provider.readFile(path, false);
2153
- if (fileContent == null) {
2154
- return {
2155
- success: false,
2156
- message: {
2157
- type: "error-text",
2158
- value: `<replace_in_file_result path="${path}" status="failed" message="File not found" />`
2159
- }
2160
- };
2161
- }
2162
- const result = replaceInFile(fileContent, diff);
2163
- if (result.status === "no_diff_applied") {
2164
- return {
2165
- success: false,
2166
- message: {
2167
- type: "error-text",
2168
- value: `<replace_in_file_result path="${path}" status="failed" message="Unable to apply changes">
2169
- <file_content path="${path}">${fileContent}</file_content>
2170
- </replace_in_file_result>`
2171
- }
2172
- };
2173
- }
2174
- await provider.writeFile(path, result.content);
2175
- if (result.status === "some_diff_applied") {
2176
- return {
2177
- success: true,
2178
- message: {
2179
- type: "text",
2180
- value: `<replace_in_file_result path="${path}" status="some_diff_applied" applied_count="${result.appliedCount}" total_count="${result.totalCount}">
2181
- <file_content path="${path}">${result.content}</file_content>
2182
- </replace_in_file_result>`
2183
- }
2184
- };
2185
- }
2186
- return {
2187
- success: true,
2188
- message: {
2189
- type: "text",
2190
- value: `<replace_in_file_result path="${path}" status="all_diff_applied" />`
2191
- }
2192
- };
2193
- } catch (error) {
2194
- return {
2195
- success: false,
2196
- message: {
2197
- type: "error-text",
2198
- value: `Invalid arguments for replaceInFile: ${error}`
2199
- }
2200
- };
2201
- }
2202
- };
2203
- var replaceInFile_default = {
2204
- ...toolInfo9,
2205
- handler: handler9
2206
- };
2207
-
2208
- // src/tools/search.ts
2209
- import { z as z17 } from "zod";
2210
- var toolInfo10 = {
2211
- name: "search",
2212
- 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.",
2213
- parameters: z17.object({
2214
- query: z17.string().describe("The query to search for").meta({ usageValue: "Your search query here" })
2215
- }).meta({
2216
- examples: [
2217
- {
2218
- description: "Search for current events or news",
2219
- input: {
2220
- query: "latest developments in AI language models 2024"
2221
- }
2222
- },
2223
- {
2224
- description: "Look up technical documentation",
2225
- input: {
2226
- query: "TypeScript advanced type system features"
2227
- }
2228
- },
2229
- {
2230
- description: "Research specific information",
2231
- input: {
2232
- query: "Node.js performance optimization best practices"
2233
- }
2234
- }
2235
- ]
2236
- })
2237
- };
2238
- var handler10 = async (provider, args) => {
2239
- const { query } = toolInfo10.parameters.parse(args);
2240
- if (!provider.search) {
2241
- return {
2242
- success: false,
2243
- message: {
2244
- type: "text",
2245
- value: "This tool requires a web provider to be installed."
2246
- }
2247
- };
2248
- }
2249
- const result = await provider.search(query);
2250
- return {
2251
- success: true,
2252
- message: {
2253
- type: "text",
2254
- value: result
2255
- }
2256
- };
2257
- };
2258
- var search_default = {
2259
- ...toolInfo10,
2260
- handler: handler10
2261
- };
2262
-
2263
- // src/tools/searchFiles.ts
2264
- import { z as z18 } from "zod";
2265
- var toolInfo11 = {
2266
- name: "searchFiles",
2267
- 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.",
2268
- parameters: z18.object({
2269
- path: z18.string().describe(
2270
- "The path of the directory to search in (relative to the current working directory). This directory will be recursively searched."
2271
- ).meta({ usageValue: "Directory path here" }),
2272
- regex: z18.string().describe("The regular expression pattern to search for. Uses Rust regex syntax.").meta({
2273
- usageValue: "Your regex pattern here"
2274
- }),
2275
- filePattern: z18.string().optional().describe(
2276
- '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 (*).'
2277
- ).meta({
2278
- usageValue: "file pattern here (optional)"
2279
- })
2280
- }).meta({
2281
- examples: [
2282
- {
2283
- description: "Request to perform a regex search across files",
2284
- input: {
2285
- path: "src",
2286
- regex: "^components/",
2287
- filePattern: "*.ts,*.tsx"
2288
- }
2289
- }
2290
- ]
2291
- })
2292
- };
2293
- var handler11 = async (provider, args) => {
2294
- if (!provider.searchFiles) {
2295
- return {
2296
- success: false,
2297
- message: {
2298
- type: "error-text",
2299
- value: "Not possible to search files."
2300
- }
2301
- };
2302
- }
2303
- const parsed = toolInfo11.parameters.safeParse(args);
2304
- if (!parsed.success) {
2305
- return {
2306
- success: false,
2307
- message: {
2308
- type: "error-text",
2309
- value: `Invalid arguments for searchFiles: ${parsed.error.message}`
2310
- }
2311
- };
2312
- }
2313
- const { path, regex, filePattern } = parsed.data;
2314
- try {
2315
- const files = await provider.searchFiles(path, regex, filePattern ?? "*");
2316
- return {
2317
- success: true,
2318
- message: {
2319
- type: "text",
2320
- value: `<search_files_path>${path}</search_files_path>
2321
- <search_files_regex>${regex}</search_files_regex>
2322
- <search_files_file_pattern>${filePattern}</search_files_file_pattern>
2323
- <search_files_files>
2324
- ${files.join("\n")}
2325
- </search_files_files>
2326
- `
2327
- }
2328
- };
2329
- } catch (error) {
2330
- return {
2331
- success: false,
2332
- message: {
2333
- type: "error-text",
2334
- value: `Error searching files: ${error}`
2335
- }
2336
- };
2337
- }
2338
- };
2339
- var searchFiles_default = {
2340
- ...toolInfo11,
2341
- handler: handler11
2342
- };
2343
-
2344
- // src/tools/todo.ts
2345
- import { z as z19 } from "zod";
2346
- var TodoStatus = z19.enum(["open", "completed", "closed"]);
2347
- var TodoItemSchema = z19.object({
2348
- id: z19.string(),
2349
- title: z19.string(),
2350
- description: z19.string(),
2351
- status: TodoStatus
2352
- });
2353
- var UpdateTodoItemInputSchema = z19.object({
2354
- operation: z19.enum(["add", "update"]),
2355
- id: z19.string().nullish(),
2356
- parentId: z19.string().nullish(),
2357
- title: z19.string().nullish(),
2358
- description: z19.string().nullish(),
2359
- status: TodoStatus.nullish()
2360
- }).superRefine((data, ctx) => {
2361
- if (data.operation === "add") {
2362
- if (!data.title) {
2363
- ctx.addIssue({
2364
- code: "custom",
2365
- message: 'Title is required for "add" operation',
2366
- path: ["title"]
2367
- });
2368
- }
2369
- } else if (data.operation === "update") {
2370
- if (!data.id) {
2371
- ctx.addIssue({
2372
- code: "custom",
2373
- message: 'ID is required for "update" operation',
2374
- path: ["id"]
2375
- });
2376
- }
2377
- }
2378
- });
2379
- var UpdateTodoItemOutputSchema = z19.object({
2380
- id: z19.string()
2381
- });
2382
-
2383
- // src/tools/writeToFile.ts
2384
- import { z as z20 } from "zod";
2385
- var toolInfo12 = {
2386
- name: "writeToFile",
2387
- description: `Request to write content to a file at the specified path.
2388
-
2389
- When to use:
2390
- - Creating new files
2391
- - Completely replacing file contents
2392
- - When you have the complete intended content
2393
-
2394
- When NOT to use:
2395
- - For modifying existing files: Use replaceInFile instead
2396
- - For appending content: Use executeCommand with echo >> instead
2397
- - For targeted edits: Use replaceInFile instead
2398
-
2399
- Features:
2400
- - Automatically creates any directories needed
2401
- - Overwrites existing files completely
2402
- - Must provide complete file content (no truncation)
2403
-
2404
- IMPORTANT CONSTRAINT:
2405
- - Always provide COMPLETE intended content (no omissions)
2406
- - Ensure no incorrect escape sequences (&lt;, &gt;, &amp;)
2407
- - Ensure no unwanted CDATA tags in content`,
2408
- parameters: z20.object({
2409
- path: z20.string().describe("The path of the file to write to").meta({ usageValue: "File path here" }),
2410
- content: z20.string().describe(
2411
- "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."
2412
- ).meta({ usageValue: "Your file content here" })
2413
- }).meta({
2414
- examples: [
2415
- {
2416
- description: "Request to write content to a file",
2417
- input: {
2418
- path: "src/main.js",
2419
- content: `import React from 'react';
2420
-
2421
- function App() {
2422
- return (
2423
- <div>
2424
- <h1>Hello, World!</h1>
2425
- </div>
2426
- );
2427
- }
2428
-
2429
- export default App;
2430
- `
2431
- }
2432
- }
2433
- ]
2434
- })
2435
- };
2436
- var handler12 = async (provider, args) => {
2437
- if (!provider.writeFile) {
2438
- return createProviderErrorResponse("write file");
2439
- }
2440
- const parsed = toolInfo12.parameters.safeParse(args);
2441
- if (!parsed.success) {
2442
- return {
2443
- success: false,
2444
- message: {
2445
- type: "error-text",
2446
- value: `Invalid arguments for writeToFile: ${parsed.error.message}`
2447
- }
2448
- };
2449
- }
2450
- const { path, content } = parsed.data;
2451
- await provider.writeFile(path, content);
2452
- return {
2453
- success: true,
2454
- message: {
2455
- type: "text",
2456
- value: `<write_to_file_path>${path}</write_to_file_path><status>Success</status>`
2457
- }
2458
- };
2459
- };
2460
- var writeToFile_default = {
2461
- ...toolInfo12,
2462
- handler: handler12
2463
- };
2464
-
2465
- // src/UsageMeter.ts
2466
- var ZERO_PRICING = {
2467
- inputPrice: 0,
2468
- outputPrice: 0,
2469
- cacheWritesPrice: 0,
2470
- cacheReadsPrice: 0
2471
- };
2472
- var TOKENS_PER_UNIT = 1e6;
2473
- var MAX_METADATA_ENTRIES = 1e3;
2474
- var UsageMeter = class {
2475
- #totals = { input: 0, output: 0, cachedRead: 0, cost: 0, messageCount: 0 };
2476
- #providerMetadataEntries = [];
2477
- #pendingUpdates = /* @__PURE__ */ new Set();
2478
- #modelInfos;
2479
- #maxMessages;
2480
- #maxCost;
2481
- #pricingService;
2482
- constructor(modelInfos = {}, opts = {}) {
2483
- const infos = {};
2484
- for (const [provider, providerInfo] of Object.entries(modelInfos)) {
2485
- for (const [model, modelInfo] of Object.entries(providerInfo)) {
2486
- infos[`${provider.split("-")[0]}:${model.replace(/[.-]/g, "")}`] = {
2487
- inputPrice: modelInfo.inputPrice ?? 0,
2488
- outputPrice: modelInfo.outputPrice ?? 0,
2489
- cacheWritesPrice: modelInfo.cacheWritesPrice ?? 0,
2490
- cacheReadsPrice: modelInfo.cacheReadsPrice ?? 0
2491
- };
2492
- }
2493
- }
2494
- this.#modelInfos = infos;
2495
- this.#maxMessages = opts.maxMessages ?? 1e3;
2496
- this.#maxCost = opts.maxCost ?? 100;
2497
- this.#pricingService = opts.pricingService;
2498
- }
2499
- #calculateUsageV3(usage, providerMetadata, modelInfo) {
2500
- if (!usage?.inputTokens || !usage?.outputTokens) {
2501
- return { input: 0, output: 0, cachedRead: 0, cost: 0 };
2502
- }
2503
- const providerMetadataKey = Object.keys(providerMetadata ?? {})[0];
2504
- const metadata = providerMetadata?.[providerMetadataKey] ?? {};
2505
- const inputTokens = usage.inputTokens.noCache ?? usage.inputTokens.total ?? 0;
2506
- const cachedReadTokens = usage.inputTokens.cacheRead ?? 0;
2507
- const cachedWriteTokens = usage.inputTokens.cacheWrite ?? 0;
2508
- const outputTokens = usage.outputTokens.total ?? usage.outputTokens.text ?? 0;
2509
- return this.#calculateCost(inputTokens, outputTokens, cachedReadTokens, cachedWriteTokens, providerMetadataKey, metadata, modelInfo);
2510
- }
2511
- #calculateUsageAiPackage(usage, providerMetadata, modelInfo) {
2512
- if (!usage?.inputTokens || !usage?.outputTokens) {
2513
- return { input: 0, output: 0, cachedRead: 0, cost: 0 };
2514
- }
2515
- const providerMetadataKey = Object.keys(providerMetadata ?? {})[0];
2516
- const metadata = providerMetadata?.[providerMetadataKey] ?? {};
2517
- const details = usage.inputTokenDetails;
2518
- const outputDetails = usage.outputTokenDetails;
2519
- const inputTokens = details?.noCacheTokens ?? usage.inputTokens ?? 0;
2520
- const cachedReadTokens = details?.cacheReadTokens ?? 0;
2521
- const cachedWriteTokens = details?.cacheWriteTokens ?? 0;
2522
- const outputTokens = outputDetails?.textTokens ?? usage.outputTokens ?? 0;
2523
- return this.#calculateCost(inputTokens, outputTokens, cachedReadTokens, cachedWriteTokens, providerMetadataKey, metadata, modelInfo);
2524
- }
2525
- #calculateCost(inputTokens, outputTokens, cachedReadTokens, cachedWriteTokens, providerMetadataKey, metadata, modelInfo) {
2526
- const getNumber = (obj, key) => {
2527
- const value = obj[key];
2528
- return typeof value === "number" ? value : void 0;
2529
- };
2530
- switch (providerMetadataKey) {
2531
- case "openrouter": {
2532
- const usage = metadata.usage;
2533
- const cost = typeof usage === "object" && usage !== null && "cost" in usage && typeof usage.cost === "number" ? usage.cost : 0;
2534
- return {
2535
- input: inputTokens,
2536
- output: outputTokens,
2537
- cachedRead: cachedReadTokens,
2538
- cost
2539
- };
2540
- }
2541
- case "anthropic": {
2542
- const cacheWrite = getNumber(metadata, "promptCacheMissTokens") ?? cachedWriteTokens;
2543
- return {
2544
- input: inputTokens + cacheWrite + cachedReadTokens,
2545
- output: outputTokens,
2546
- cachedRead: cachedReadTokens,
2547
- cost: (inputTokens * modelInfo.inputPrice + outputTokens * modelInfo.outputPrice + cacheWrite * modelInfo.cacheWritesPrice + cachedReadTokens * modelInfo.cacheReadsPrice) / TOKENS_PER_UNIT
2548
- };
2549
- }
2550
- case "deepseek": {
2551
- const cacheWrite = getNumber(metadata, "promptCacheMissTokens") ?? cachedWriteTokens;
2552
- return {
2553
- input: inputTokens,
2554
- output: outputTokens,
2555
- cachedRead: cachedReadTokens,
2556
- cost: (outputTokens * modelInfo.outputPrice + cacheWrite * modelInfo.inputPrice + cachedReadTokens * modelInfo.cacheReadsPrice) / TOKENS_PER_UNIT
2557
- };
2558
- }
2559
- default: {
2560
- return {
2561
- input: inputTokens,
2562
- output: outputTokens,
2563
- cachedRead: cachedReadTokens,
2564
- cost: (inputTokens * modelInfo.inputPrice + outputTokens * modelInfo.outputPrice) / TOKENS_PER_UNIT
2565
- };
2566
- }
2567
- }
2568
- }
2569
- addUsage(llm, resp, options = {}) {
2570
- const provider = llm.provider.split(".")[0];
2571
- const normalizedModel = llm.modelId.replace(/[.-]/g, "");
2572
- const key = `${provider}:${normalizedModel}`;
2573
- let modelInfo = options.modelInfo ?? this.#modelInfos[key];
2574
- const updatePromise = (async () => {
2575
- try {
2576
- if (!modelInfo && this.#pricingService) {
2577
- modelInfo = await this.#pricingService.getPricing(provider, llm.modelId);
2578
- this.#modelInfos[key] = modelInfo;
2579
- }
2580
- } catch {
2581
- modelInfo = ZERO_PRICING;
2582
- }
2583
- modelInfo = modelInfo ?? ZERO_PRICING;
2584
- const usage = "totalUsage" in resp ? resp.totalUsage : resp.usage;
2585
- let result;
2586
- if ("inputTokenDetails" in usage || typeof usage.inputTokens === "number") {
2587
- result = this.#calculateUsageAiPackage(usage, resp.providerMetadata, modelInfo);
2588
- } else {
2589
- result = this.#calculateUsageV3(usage, resp.providerMetadata, modelInfo);
2590
- }
2591
- this.#totals.input += result.input;
2592
- this.#totals.output += result.output;
2593
- this.#totals.cachedRead += result.cachedRead;
2594
- this.#totals.cost += result.cost;
2595
- this.#totals.messageCount += 1;
2596
- if (resp.providerMetadata && Object.keys(resp.providerMetadata).length > 0) {
2597
- const providerKey = Object.keys(resp.providerMetadata)[0] || llm.provider;
2598
- const metadata = resp.providerMetadata[providerKey];
2599
- if (typeof metadata === "object" && metadata !== null && !Array.isArray(metadata)) {
2600
- this.#providerMetadataEntries.push({
2601
- provider: providerKey,
2602
- model: llm.modelId,
2603
- metadata,
2604
- timestamp: Date.now()
2605
- });
2606
- }
2607
- if (this.#providerMetadataEntries.length > MAX_METADATA_ENTRIES) {
2608
- this.#providerMetadataEntries.splice(0, this.#providerMetadataEntries.length - MAX_METADATA_ENTRIES);
2609
- }
2610
- }
2611
- })();
2612
- this.#pendingUpdates.add(updatePromise);
2613
- updatePromise.finally(() => {
2614
- this.#pendingUpdates.delete(updatePromise);
2615
- });
2616
- return updatePromise;
2617
- }
2618
- /** Override the running totals (e.g., restore from saved state). */
2619
- setUsage(newUsage, options = {}) {
2620
- if (newUsage.input != null) this.#totals.input = newUsage.input;
2621
- if (newUsage.output != null) this.#totals.output = newUsage.output;
2622
- if (newUsage.cachedRead != null) this.#totals.cachedRead = newUsage.cachedRead;
2623
- if (newUsage.cost != null) this.#totals.cost = newUsage.cost;
2624
- if (newUsage.messageCount != null) this.#totals.messageCount = newUsage.messageCount;
2625
- if (options.clearMetadata) {
2626
- this.#providerMetadataEntries = [];
2627
- }
2628
- }
2629
- /** Manually bump the message count (useful if you record some messages without token info). */
2630
- incrementMessageCount(n = 1) {
2631
- this.#totals.messageCount += n;
2632
- }
2633
- /** Reset the running totals. */
2634
- resetUsage() {
2635
- this.#totals = { input: 0, output: 0, cachedRead: 0, cost: 0, messageCount: 0 };
2636
- this.#providerMetadataEntries = [];
2637
- }
2638
- /** Return true once either messages or cost exceed the configured caps. */
2639
- isLimitExceeded() {
2640
- const messageCount = this.#maxMessages > 0 && this.#totals.messageCount >= this.#maxMessages;
2641
- const cost = this.#maxCost > 0 && this.#totals.cost >= this.#maxCost;
2642
- return {
2643
- messageCount,
2644
- maxMessages: this.#maxMessages,
2645
- cost,
2646
- maxCost: this.#maxCost,
2647
- result: messageCount || cost
2648
- };
2649
- }
2650
- /** Same as isLimitExceeded but throws an error if a limit is hit. */
2651
- checkLimit() {
2652
- const result = this.isLimitExceeded();
2653
- if (result.result) {
2654
- throw new Error(
2655
- `Usage limit exceeded. Message count: ${result.messageCount}/${result.maxMessages}, cost: ${result.cost}/${result.maxCost}`
2656
- );
2657
- }
2658
- }
2659
- /** Getter for the aggregated totals (immutable copy). */
2660
- get usage() {
2661
- return { ...this.#totals };
2662
- }
2663
- /** Getter for provider metadata entries (immutable copy). */
2664
- get providerMetadata() {
2665
- return [...this.#providerMetadataEntries];
2666
- }
2667
- /** Calculate cache statistics from stored metadata entries. */
2668
- get cacheStats() {
2669
- const entries = this.#providerMetadataEntries;
2670
- const totalRequests = entries.length;
2671
- let totalCachedTokens = 0;
2672
- let requestsWithCache = 0;
2673
- for (const entry of entries) {
2674
- const metadata = entry.metadata;
2675
- const getValueAsNumber = (key) => {
2676
- const value = metadata[key];
2677
- return typeof value === "number" ? value : void 0;
2678
- };
2679
- const cachedTokens = getValueAsNumber("cachedPromptTokens") ?? getValueAsNumber("cacheReadTokens") ?? getValueAsNumber("prompt_cache_hit_tokens") ?? 0;
2680
- if (cachedTokens > 0) {
2681
- totalCachedTokens += cachedTokens;
2682
- requestsWithCache++;
2683
- }
2684
- }
2685
- const cacheHitRate = totalRequests > 0 ? requestsWithCache / totalRequests : 0;
2686
- return {
2687
- totalCachedTokens,
2688
- totalRequests,
2689
- requestsWithCache,
2690
- cacheHitRate,
2691
- entries: [...this.#providerMetadataEntries]
2692
- };
2693
- }
2694
- /** Clear stored provider metadata entries. */
2695
- clearProviderMetadata() {
2696
- this.#providerMetadataEntries = [];
2697
- }
2698
- /** Merge another UsageMeter's totals into this one. */
2699
- merge(other) {
2700
- const otherUsage = other.usage;
2701
- this.#totals.input += otherUsage.input;
2702
- this.#totals.output += otherUsage.output;
2703
- this.#totals.cachedRead += otherUsage.cachedRead;
2704
- this.#totals.cost += otherUsage.cost;
2705
- this.#totals.messageCount += otherUsage.messageCount;
2706
- this.#providerMetadataEntries.push(...other.providerMetadata);
2707
- }
2708
- /** Wait for all pending usage updates to complete. */
2709
- async waitForPending() {
2710
- const pending = Array.from(this.#pendingUpdates);
2711
- await Promise.allSettled(pending);
2712
- }
2713
- getUsageText() {
2714
- const u = this.usage;
2715
- return `Usage - messages: ${u.messageCount}, input: ${u.input}, cached: ${u.cachedRead}, output: ${u.output}, cost: $${u.cost.toFixed(4)}`;
2716
- }
2717
- onFinishHandler(llm) {
2718
- return async (evt) => {
2719
- await this.addUsage(llm, evt);
2720
- };
2721
- }
2722
- };
2723
-
2724
- // src/utils/merge.ts
2725
- function deepMerge(base, override, deepPaths) {
2726
- const result = { ...base, ...override };
2727
- for (const path of deepPaths) {
2728
- const baseValue = base[path];
2729
- const overrideValue = override[path];
2730
- if (typeof baseValue === "object" && baseValue !== null && !Array.isArray(baseValue) && typeof overrideValue === "object" && overrideValue !== null && !Array.isArray(overrideValue)) {
2731
- result[path] = { ...baseValue, ...overrideValue };
2732
- }
2733
- }
2734
- return result;
2735
- }
2736
-
2737
- // src/workflow/agent.workflow.ts
2738
- import { jsonSchema } from "ai";
2739
- import { toJSONSchema, z as z21 } from "zod";
2740
-
2741
- // src/workflow/types.ts
2742
- var TaskEventKind = /* @__PURE__ */ ((TaskEventKind2) => {
2743
- TaskEventKind2["StartTask"] = "StartTask";
2744
- TaskEventKind2["StartRequest"] = "StartRequest";
2745
- TaskEventKind2["EndRequest"] = "EndRequest";
2746
- TaskEventKind2["Text"] = "Text";
2747
- TaskEventKind2["Reasoning"] = "Reasoning";
2748
- TaskEventKind2["ToolUse"] = "ToolUse";
2749
- TaskEventKind2["ToolReply"] = "ToolReply";
2750
- TaskEventKind2["ToolError"] = "ToolError";
2751
- TaskEventKind2["UsageExceeded"] = "UsageExceeded";
2752
- TaskEventKind2["EndTask"] = "EndTask";
2753
- return TaskEventKind2;
2754
- })(TaskEventKind || {});
2755
-
2756
- // src/workflow/agent.workflow.ts
2757
- function isValidToolResultOutput(value) {
2758
- return typeof value === "object" && value !== null && "type" in value && (value.type === "text" || value.type === "content" || value.type === "execution-denied");
2759
- }
2760
- var agentWorkflow = async (input, { step, tools, logger }) => {
2761
- const event = (name, event2) => step(name, () => tools.taskEvent(event2));
2762
- const { tools: toolInfo13, maxToolRoundTrips = 200 } = input;
2763
- const messages = "systemPrompt" in input ? [{ role: "system", content: input.systemPrompt }] : input.messages;
2764
- await event("start-task", { kind: "StartTask" /* StartTask */, systemPrompt: "systemPrompt" in input ? input.systemPrompt : "" });
2765
- const toolSet = {};
2766
- for (const tool of toolInfo13) {
2767
- toolSet[tool.name] = {
2768
- description: tool.description,
2769
- inputSchema: jsonSchema(toJSONSchema(tool.parameters))
2770
- };
2771
- }
2772
- let nextMessage = input.userMessage;
2773
- for (let i = 0; i < maxToolRoundTrips; i++) {
2774
- messages.push(...nextMessage);
2775
- await event(`start-round-${i}`, { kind: "StartRequest" /* StartRequest */, userMessage: nextMessage });
2776
- const assistantMessage = await step(`agent-round-${i}`, { retry: 2 }, async () => {
2777
- return await tools.generateText({
2778
- messages,
2779
- tools: toolSet,
2780
- model: input.model
2781
- });
2782
- });
2783
- messages.push(...assistantMessage);
2784
- const toolCalls = [];
2785
- for (const msg of assistantMessage) {
2786
- if (typeof msg.content === "string") {
2787
- continue;
2788
- }
2789
- if (msg.content) {
2790
- for (const part of msg.content) {
2791
- if (part.type === "tool-call") {
2792
- toolCalls.push(part);
2793
- }
2794
- }
2795
- }
2796
- }
2797
- const textContent = assistantMessage.flatMap((m) => {
2798
- if (typeof m.content === "string") {
2799
- return [m.content];
2800
- }
2801
- if (m.role === "assistant" && Array.isArray(m.content)) {
2802
- return m.content.map((part) => {
2803
- if (part.type === "text") {
2804
- return part.text;
2805
- }
2806
- return "";
2807
- });
2808
- }
2809
- return [];
2810
- }).join("\n");
2811
- await event(`end-round-${i}`, { kind: "EndRequest" /* EndRequest */, message: textContent });
2812
- if (toolCalls.length === 0) {
2813
- if (!input.outputSchema) {
2814
- const exitReason3 = { type: "Exit", message: textContent, messages };
2815
- await event("end-task", { kind: "EndTask" /* EndTask */, exitReason: exitReason3 });
2816
- return exitReason3;
2817
- }
2818
- const parsed = parseJsonFromMarkdown(textContent);
2819
- if (!parsed.success) {
2820
- const errorMessage = `Failed to parse JSON from markdown. Error: ${parsed.error}. Please correct the output. It MUST be in valid JSON format.`;
2821
- nextMessage = [{ role: "user", content: errorMessage }];
2822
- continue;
2823
- }
2824
- const validated = input.outputSchema.safeParse(parsed.data);
2825
- if (!validated.success) {
2826
- const errorMessage = `Output validation failed. Error: ${z21.prettifyError(validated.error)}. Please correct the output.`;
2827
- nextMessage = [{ role: "user", content: errorMessage }];
2828
- continue;
2829
- }
2830
- const exitReason2 = { type: "Exit", message: textContent, object: validated.data, messages };
2831
- await event("end-task", { kind: "EndTask" /* EndTask */, exitReason: exitReason2 });
2832
- return exitReason2;
2833
- }
2834
- const toolResults = [];
2835
- for (const toolCall of toolCalls) {
2836
- if (!toolSet[toolCall.toolName]) {
2837
- logger.warn("Tool not found.", toolCall);
2838
- await event(`event-tool-error-${toolCall.toolName}-${toolCall.toolCallId}`, {
2839
- kind: "ToolError" /* ToolError */,
2840
- tool: toolCall.toolName,
2841
- error: {
2842
- type: "error-text",
2843
- value: `Tool '${toolCall.toolName}' not found.`
2844
- }
2845
- });
2846
- toolResults.push({
2847
- toolCallId: toolCall.toolCallId,
2848
- toolName: toolCall.toolName,
2849
- output: {
2850
- type: "error-text",
2851
- value: `Error: Tool '${toolCall.toolName}' not found.`
2852
- }
2853
- });
2854
- continue;
2855
- }
2856
- await event(`event-tool-use-${toolCall.toolName}-${toolCall.toolCallId}`, {
2857
- kind: "ToolUse" /* ToolUse */,
2858
- tool: toolCall.toolName,
2859
- params: toolCall.input
2860
- });
2861
- const toolResponse = await step(`invoke-tool-${toolCall.toolName}-${toolCall.toolCallId}`, async () => {
2862
- return await tools.invokeTool({
2863
- toolName: toolCall.toolName,
2864
- input: toolCall.input
2865
- });
2866
- });
2867
- if (toolResponse.success) {
2868
- await event(`event-tool-reply-${toolCall.toolName}-${toolCall.toolCallId}`, {
2869
- kind: "ToolReply" /* ToolReply */,
2870
- tool: toolCall.toolName,
2871
- content: toolResponse.message
2872
- });
2873
- if (!isValidToolResultOutput(toolResponse.message)) {
2874
- throw new Error(`Invalid tool result format from ${toolCall.toolName}`);
2875
- }
2876
- toolResults.push({
2877
- toolCallId: toolCall.toolCallId,
2878
- toolName: toolCall.toolName,
2879
- output: toolResponse.message
2880
- });
2881
- } else {
2882
- await event(`event-tool-error-${toolCall.toolName}-${toolCall.toolCallId}`, {
2883
- kind: "ToolError" /* ToolError */,
2884
- tool: toolCall.toolName,
2885
- error: toolResponse.message ?? "Unknown error"
2886
- });
2887
- if (!isValidToolResultOutput(toolResponse.message)) {
2888
- throw new Error(`Invalid tool result format from ${toolCall.toolName}`);
2889
- }
2890
- toolResults.push({
2891
- toolCallId: toolCall.toolCallId,
2892
- toolName: toolCall.toolName,
2893
- output: toolResponse.message
2894
- });
2895
- }
2896
- }
2897
- nextMessage = [
2898
- {
2899
- role: "tool",
2900
- content: toolResults.map((r) => ({
2901
- type: "tool-result",
2902
- ...r
2903
- }))
2904
- }
2905
- ];
2906
- }
2907
- const exitReason = { type: "UsageExceeded", messages };
2908
- await event("end-task", { kind: "EndTask" /* EndTask */, exitReason });
2909
- return exitReason;
2910
- };
2911
-
2912
- // src/workflow/dynamic.ts
2913
- import { parse as parse2 } from "yaml";
2914
- import { z as z23 } from "zod";
2915
-
2916
- // src/workflow/dynamic-types.ts
2917
- import { z as z22 } from "zod";
2918
- var WorkflowInputDefinitionSchema = z22.object({
2919
- id: z22.string(),
2920
- description: z22.string().nullish(),
2921
- default: z22.unknown().nullish()
2922
- });
2923
- var WorkflowStepDefinitionSchema = z22.object({
2924
- id: z22.string(),
2925
- tools: z22.array(z22.string()).nullish(),
2926
- task: z22.string(),
2927
- output: z22.string().nullish(),
2928
- expected_outcome: z22.string().nullish(),
2929
- /**
2930
- * Optional JSON schema or other metadata for future structured outputs.
2931
- * Not interpreted by core today.
2932
- */
2933
- outputSchema: z22.unknown().nullish(),
2934
- /**
2935
- * Optional timeout in milliseconds. Step execution will be aborted if it exceeds this duration.
2936
- */
2937
- timeout: z22.number().positive().nullish()
2938
- });
2939
- var WhileLoopStepSchema = z22.object({
2940
- id: z22.string(),
2941
- while: z22.object({
2942
- condition: z22.string().describe("JavaScript expression that evaluates to true/false"),
2943
- steps: z22.array(z22.lazy(() => WorkflowControlFlowStepSchema))
2944
- }),
2945
- output: z22.string().nullish()
2946
- });
2947
- var IfElseStepSchema = z22.object({
2948
- id: z22.string(),
2949
- if: z22.object({
2950
- condition: z22.string().describe("JavaScript expression that evaluates to true/false"),
2951
- thenBranch: z22.array(z22.lazy(() => WorkflowControlFlowStepSchema)),
2952
- elseBranch: z22.array(z22.lazy(() => WorkflowControlFlowStepSchema)).optional()
2953
- }),
2954
- output: z22.string().nullish()
2955
- });
2956
- var BreakStepSchema = z22.object({
2957
- break: z22.literal(true)
2958
- });
2959
- var ContinueStepSchema = z22.object({
2960
- continue: z22.literal(true)
2961
- });
2962
- var TryCatchStepSchema = z22.object({
2963
- id: z22.string(),
2964
- try: z22.object({
2965
- trySteps: z22.array(z22.lazy(() => WorkflowControlFlowStepSchema)),
2966
- catchSteps: z22.array(z22.lazy(() => WorkflowControlFlowStepSchema))
2967
- }),
2968
- output: z22.string().nullish()
2969
- });
2970
- var WorkflowControlFlowStepSchema = z22.union([
2971
- WorkflowStepDefinitionSchema,
2972
- WhileLoopStepSchema,
2973
- IfElseStepSchema,
2974
- BreakStepSchema,
2975
- ContinueStepSchema,
2976
- TryCatchStepSchema
2977
- ]);
2978
- var WorkflowDefinitionSchema = z22.object({
2979
- task: z22.string(),
2980
- inputs: z22.array(WorkflowInputDefinitionSchema).nullish(),
2981
- steps: z22.array(WorkflowControlFlowStepSchema),
2982
- output: z22.string().nullish()
2983
- });
2984
- var WorkflowFileSchema = z22.object({
2985
- workflows: z22.record(z22.string(), WorkflowDefinitionSchema)
2986
- });
2987
-
2988
- // src/workflow/dynamic.ts
2989
- var MAX_WHILE_LOOP_ITERATIONS = 1e3;
2990
- function convertJsonSchemaToZod(schema) {
2991
- if (schema.enum) {
2992
- const enumValues = schema.enum;
2993
- if (enumValues.length === 0) {
2994
- return z23.never();
2995
- }
2996
- if (enumValues.every((v) => typeof v === "string")) {
2997
- return z23.enum(enumValues);
2998
- }
2999
- const literals = enumValues.map((v) => z23.literal(v));
3000
- if (literals.length === 1) {
3001
- return literals[0];
3002
- }
3003
- return z23.union([literals[0], literals[1], ...literals.slice(2)]);
3004
- }
3005
- if (Array.isArray(schema.type)) {
3006
- const types = schema.type;
3007
- if (types.includes("null") && types.length === 2) {
3008
- const nonNullType = types.find((t) => t !== "null");
3009
- if (nonNullType === "string") return z23.string().nullable();
3010
- if (nonNullType === "number") return z23.number().nullable();
3011
- if (nonNullType === "integer")
3012
- return z23.number().refine((val) => Number.isInteger(val)).nullable();
3013
- if (nonNullType === "boolean") return z23.boolean().nullable();
3014
- if (nonNullType === "object") {
3015
- const shape = {};
3016
- if (schema.properties) {
3017
- for (const [propName, propSchema] of Object.entries(schema.properties)) {
3018
- const propZod = convertJsonSchemaToZod(propSchema);
3019
- const isRequired = schema.required?.includes(propName);
3020
- shape[propName] = isRequired ? propZod : propZod.optional();
3021
- }
3022
- }
3023
- return z23.object(shape).nullable();
3024
- }
3025
- if (nonNullType === "array") return z23.array(z23.any()).nullable();
3026
- }
3027
- return z23.any();
3028
- }
3029
- const type = schema.type;
3030
- switch (type) {
3031
- case "string":
3032
- return z23.string();
3033
- case "number":
3034
- return z23.number();
3035
- case "integer":
3036
- return z23.number().refine((val) => Number.isInteger(val), { message: "Expected an integer" });
3037
- case "boolean":
3038
- return z23.boolean();
3039
- case "null":
3040
- return z23.null();
3041
- case "object": {
3042
- const shape = {};
3043
- if (schema.properties) {
3044
- for (const [propName, propSchema] of Object.entries(schema.properties)) {
3045
- const propZod = convertJsonSchemaToZod(propSchema);
3046
- const isRequired = schema.required?.includes(propName);
3047
- shape[propName] = isRequired ? propZod : propZod.optional();
3048
- }
3049
- }
3050
- if (schema.additionalProperties === true) {
3051
- return z23.object(shape).passthrough();
3052
- }
3053
- if (typeof schema.additionalProperties === "object") {
3054
- const additionalSchema = convertJsonSchemaToZod(schema.additionalProperties);
3055
- return z23.intersection(z23.object(shape), z23.record(z23.string(), additionalSchema));
3056
- }
3057
- return z23.object(shape);
3058
- }
3059
- case "array": {
3060
- if (!schema.items) {
3061
- return z23.array(z23.any());
3062
- }
3063
- const itemSchema = convertJsonSchemaToZod(schema.items);
3064
- return z23.array(itemSchema);
3065
- }
3066
- default:
3067
- return z23.any();
3068
- }
3069
- }
3070
- var TOOL_GROUPS = {
3071
- readonly: ["readFile", "readBinaryFile", "listFiles", "searchFiles"],
3072
- readwrite: ["readFile", "readBinaryFile", "listFiles", "searchFiles", "writeToFile", "replaceInFile", "removeFile", "renameFile"],
3073
- internet: ["fetchUrl", "search"]
3074
- };
3075
- function validateWorkflowFile(definition) {
3076
- const errors = [];
3077
- for (const [workflowId, workflow] of Object.entries(definition.workflows)) {
3078
- if (!workflow.steps || workflow.steps.length === 0) {
3079
- errors.push(`Workflow '${workflowId}' has no steps`);
3080
- continue;
3081
- }
3082
- const checkBreakOutsideLoop = (steps, inLoop, path) => {
3083
- for (const step of steps) {
3084
- if (isBreakStep(step) || isContinueStep(step)) {
3085
- if (!inLoop) {
3086
- errors.push(`${path} has break/continue outside of a loop`);
3087
- }
3088
- }
3089
- if (isWhileLoopStep(step)) {
3090
- checkBreakOutsideLoop(step.while.steps, true, `${path}/${step.id}`);
3091
- }
3092
- if (isIfElseStep(step)) {
3093
- if (step.if.thenBranch) {
3094
- checkBreakOutsideLoop(step.if.thenBranch, inLoop, `${path}/${step.id}/then`);
3095
- }
3096
- if (step.if.elseBranch) {
3097
- checkBreakOutsideLoop(step.if.elseBranch, inLoop, `${path}/${step.id}/else`);
3098
- }
3099
- }
3100
- if (isTryCatchStep(step)) {
3101
- checkBreakOutsideLoop(step.try.trySteps, inLoop, `${path}/${step.id}/try`);
3102
- checkBreakOutsideLoop(step.try.catchSteps, inLoop, `${path}/${step.id}/catch`);
3103
- }
3104
- }
3105
- };
3106
- checkBreakOutsideLoop(workflow.steps, false, workflowId);
3107
- const findRunWorkflowCalls = (steps, path) => {
3108
- for (const step of steps) {
3109
- if (isWhileLoopStep(step)) {
3110
- findRunWorkflowCalls(step.while.steps, `${path}/${step.id}`);
3111
- }
3112
- if (isIfElseStep(step)) {
3113
- if (step.if.thenBranch) {
3114
- findRunWorkflowCalls(step.if.thenBranch, `${path}/${step.id}/then`);
3115
- }
3116
- if (step.if.elseBranch) {
3117
- findRunWorkflowCalls(step.if.elseBranch, `${path}/${step.id}/else`);
3118
- }
3119
- }
3120
- if (isTryCatchStep(step)) {
3121
- findRunWorkflowCalls(step.try.trySteps, `${path}/${step.id}/try`);
3122
- findRunWorkflowCalls(step.try.catchSteps, `${path}/${step.id}/catch`);
3123
- }
3124
- }
3125
- };
3126
- findRunWorkflowCalls(workflow.steps, workflowId);
3127
- }
3128
- if (errors.length > 0) {
3129
- return { success: false, errors };
3130
- }
3131
- return { success: true };
3132
- }
3133
- function parseDynamicWorkflowDefinition(source) {
3134
- try {
3135
- const raw = parse2(source);
3136
- const validated = WorkflowFileSchema.safeParse(raw);
3137
- if (!validated.success) {
3138
- return { success: false, error: z23.prettifyError(validated.error) };
3139
- }
3140
- const validation = validateWorkflowFile(validated.data);
3141
- if (!validation.success) {
3142
- return { success: false, error: `Workflow validation failed:
3143
- ${validation.errors.map((e) => ` - ${e}`).join("\n")}` };
3144
- }
3145
- return { success: true, definition: validated.data };
3146
- } catch (error) {
3147
- return { success: false, error: error instanceof Error ? error.message : String(error) };
3148
- }
3149
- }
3150
- function validateAndApplyDefaults(workflowId, workflow, input) {
3151
- if (!workflow.inputs || workflow.inputs.length === 0) {
3152
- return input;
3153
- }
3154
- const validatedInput = { ...input };
3155
- const errors = [];
3156
- for (const inputDef of workflow.inputs) {
3157
- const providedValue = input[inputDef.id];
3158
- if (providedValue !== void 0 && providedValue !== null) {
3159
- validatedInput[inputDef.id] = providedValue;
3160
- } else if (inputDef.default !== void 0 && inputDef.default !== null) {
3161
- validatedInput[inputDef.id] = inputDef.default;
3162
- } else {
3163
- errors.push(`Missing required input '${inputDef.id}'${inputDef.description ? `: ${inputDef.description}` : ""}`);
3164
- }
3165
- }
3166
- if (errors.length > 0) {
3167
- throw new Error(`Workflow '${workflowId}' input validation failed:
3168
- ${errors.map((e) => ` - ${e}`).join("\n")}`);
3169
- }
3170
- return validatedInput;
3171
- }
3172
- function evaluateCondition(condition, input, state, allowUnsafeCodeExecution = false, logger) {
3173
- if (allowUnsafeCodeExecution) {
3174
- if (logger) {
3175
- logger.warn(
3176
- `[SECURITY] Executing unsafe code evaluation for condition: ${condition}. This allows arbitrary JavaScript execution and should only be used for trusted workflows.`
3177
- );
3178
- }
3179
- const functionBody = `
3180
- try {
3181
- return ${condition};
3182
- } catch (error) {
3183
- throw new Error('Condition evaluation failed: ' + (error instanceof Error ? error.message : String(error)));
3184
- }
3185
- `;
3186
- try {
3187
- const fn = new Function("input", "state", functionBody);
3188
- const result = fn(input, state);
3189
- return Boolean(result);
3190
- } catch (error) {
3191
- throw new Error(`Failed to evaluate condition: ${condition}. Error: ${error instanceof Error ? error.message : String(error)}`);
3192
- }
3193
- } else {
3194
- return evaluateConditionSafe(condition, input, state);
3195
- }
3196
- }
3197
- function evaluateConditionSafe(condition, input, state) {
3198
- condition = condition.trim();
3199
- if (condition === "true") return true;
3200
- if (condition === "false") return false;
3201
- const orIndex = findTopLevelOperator(condition, "||");
3202
- if (orIndex !== -1) {
3203
- const left = condition.slice(0, orIndex).trim();
3204
- const right = condition.slice(orIndex + 2).trim();
3205
- return evaluateConditionSafe(left, input, state) || evaluateConditionSafe(right, input, state);
3206
- }
3207
- const andIndex = findTopLevelOperator(condition, "&&");
3208
- if (andIndex !== -1) {
3209
- const left = condition.slice(0, andIndex).trim();
3210
- const right = condition.slice(andIndex + 2).trim();
3211
- return evaluateConditionSafe(left, input, state) && evaluateConditionSafe(right, input, state);
3212
- }
3213
- const comparisonOps = ["===", "!==", "==", "!=", ">=", "<=", ">", "<"];
3214
- for (const op of comparisonOps) {
3215
- const opIndex = findTopLevelOperator(condition, op);
3216
- if (opIndex !== -1) {
3217
- const left = evaluateValue(condition.slice(0, opIndex).trim(), input, state);
3218
- const right = evaluateValue(condition.slice(opIndex + op.length).trim(), input, state);
3219
- return compareValues(left, right, op);
3220
- }
3221
- }
3222
- if (condition.startsWith("!")) {
3223
- return !evaluateConditionSafe(condition.slice(1).trim(), input, state);
3224
- }
3225
- if (hasEnclosingParens(condition)) {
3226
- const inner = condition.slice(1, -1);
3227
- return evaluateConditionSafe(inner, input, state);
3228
- }
3229
- const value = evaluateValue(condition, input, state);
3230
- return Boolean(value);
3231
- }
3232
- function findTopLevelOperator(expr, op) {
3233
- let parenDepth = 0;
3234
- let inString = false;
3235
- let stringChar = "";
3236
- let escapeNext = false;
3237
- for (let i = 0; i <= expr.length - op.length; i++) {
3238
- const char = expr[i];
3239
- if (escapeNext) {
3240
- escapeNext = false;
3241
- continue;
3242
- }
3243
- if (char === "\\") {
3244
- escapeNext = true;
3245
- continue;
3246
- }
3247
- if (!inString && (char === '"' || char === "'")) {
3248
- inString = true;
3249
- stringChar = char;
3250
- continue;
3251
- }
3252
- if (inString && char === stringChar) {
3253
- inString = false;
3254
- stringChar = "";
3255
- continue;
3256
- }
3257
- if (inString) continue;
3258
- if (char === "(") parenDepth++;
3259
- if (char === ")") parenDepth--;
3260
- if (parenDepth === 0 && expr.slice(i, i + op.length) === op) {
3261
- return i;
3262
- }
3263
- }
3264
- return -1;
3265
- }
3266
- function hasEnclosingParens(expr) {
3267
- expr = expr.trim();
3268
- if (!expr.startsWith("(") || !expr.endsWith(")")) {
3269
- return false;
3270
- }
3271
- let depth = 0;
3272
- let inString = false;
3273
- let stringChar = "";
3274
- let escapeNext = false;
3275
- for (let i = 0; i < expr.length; i++) {
3276
- const char = expr[i];
3277
- if (escapeNext) {
3278
- escapeNext = false;
3279
- continue;
3280
- }
3281
- if (char === "\\") {
3282
- escapeNext = true;
3283
- continue;
3284
- }
3285
- if (!inString && (char === '"' || char === "'")) {
3286
- inString = true;
3287
- stringChar = char;
3288
- continue;
3289
- }
3290
- if (inString && char === stringChar) {
3291
- inString = false;
3292
- stringChar = "";
3293
- continue;
3294
- }
3295
- if (inString) continue;
3296
- if (char === "(") {
3297
- depth++;
3298
- if (i === 0) depth = 1;
3299
- }
3300
- if (char === ")") {
3301
- depth--;
3302
- if (depth === 0 && i === expr.length - 1) {
3303
- return true;
3304
- }
3305
- if (depth === 0 && i < expr.length - 1) {
3306
- return false;
3307
- }
3308
- }
3309
- }
3310
- return false;
3311
- }
3312
- function evaluateValue(expr, input, state) {
3313
- expr = expr.trim();
3314
- const stringMatch = expr.match(/^(["'])(?:(?=(\\?))\2.)*?\1$/);
3315
- if (stringMatch) {
3316
- const quote = stringMatch[1];
3317
- if (quote === '"') {
3318
- try {
3319
- return JSON.parse(expr);
3320
- } catch (error) {
3321
- throw new Error(`Invalid string literal: "${expr}". Error: ${error instanceof Error ? error.message : String(error)}`);
3322
- }
3323
- } else {
3324
- let inner = expr.slice(1, -1);
3325
- inner = inner.replace(/\\'/g, "'");
3326
- inner = inner.replace(/\\"/g, '"');
3327
- const converted = `"${inner.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
3328
- try {
3329
- return JSON.parse(converted);
3330
- } catch (error) {
3331
- throw new Error(`Invalid string literal: "${expr}". Error: ${error instanceof Error ? error.message : String(error)}`);
3332
- }
3333
- }
3334
- }
3335
- if (/^-?\d*\.?\d+(?:[eE][+-]?\d+)?$/.test(expr)) {
3336
- return Number.parseFloat(expr);
3337
- }
3338
- if (expr === "true") return true;
3339
- if (expr === "false") return false;
3340
- if (expr === "null") return null;
3341
- if (expr.startsWith("input.")) {
3342
- return getNestedProperty(input, expr.slice(6));
3343
- }
3344
- if (expr.startsWith("state.")) {
3345
- return getNestedProperty(state, expr.slice(6));
3346
- }
3347
- throw new Error(
3348
- `Unrecognized expression in condition: "${expr}". Valid expressions are: string literals, numbers, boolean literals, null, or property access like "input.foo" or "state.bar"`
3349
- );
3350
- }
3351
- function getNestedProperty(obj, path) {
3352
- const parts = path.split(".");
3353
- let current = obj;
3354
- for (const part of parts) {
3355
- if (current == null) return void 0;
3356
- if (typeof current !== "object") return void 0;
3357
- current = current[part];
3358
- }
3359
- return current;
3360
- }
3361
- function compareValues(left, right, op) {
3362
- switch (op) {
3363
- case "===":
3364
- return left === right;
3365
- case "!==":
3366
- return left !== right;
3367
- case "==":
3368
- return Object.is(left, right);
3369
- case "!=":
3370
- return !Object.is(left, right);
3371
- case ">=":
3372
- return left >= right;
3373
- case "<=":
3374
- return left <= right;
3375
- case ">":
3376
- return left > right;
3377
- case "<":
3378
- return left < right;
3379
- default:
3380
- throw new Error(`Unknown comparison operator: ${op}`);
3381
- }
3382
- }
3383
- function createRunWorkflowFn(args) {
3384
- return async (subWorkflowId, subInput) => {
3385
- const mergedInput = { ...args.input, ...args.state, ...subInput ?? {} };
3386
- return await args.runInternal(subWorkflowId, mergedInput, args.context, args.state);
3387
- };
3388
- }
3389
- async function executeStepWithAgent(stepDef, workflowId, input, state, context, options, runInternal) {
3390
- const tools = context.tools;
3391
- if (typeof tools.generateText !== "function" || typeof tools.invokeTool !== "function" || typeof tools.taskEvent !== "function") {
3392
- throw new Error(
3393
- `Step '${stepDef.id}' in workflow '${workflowId}' requires agent execution, but AgentToolRegistry tools are not available.`
3394
- );
3395
- }
3396
- if (!options.toolInfo) {
3397
- throw new Error(
3398
- `Step '${stepDef.id}' in workflow '${workflowId}' requires agent execution, but no toolInfo was provided to DynamicWorkflowRunner.`
3399
- );
3400
- }
3401
- const rawAllowedToolNames = stepDef.tools;
3402
- let toolsForAgent;
3403
- if (rawAllowedToolNames) {
3404
- const expandedToolNames = /* @__PURE__ */ new Set();
3405
- let includeAll = false;
3406
- for (const name of rawAllowedToolNames) {
3407
- if (name === "all") {
3408
- includeAll = true;
3409
- break;
3410
- }
3411
- if (Object.hasOwn(TOOL_GROUPS, name)) {
3412
- for (const tool of TOOL_GROUPS[name]) {
3413
- expandedToolNames.add(tool);
3414
- }
3415
- } else {
3416
- expandedToolNames.add(name);
3417
- }
3418
- }
3419
- if (includeAll) {
3420
- toolsForAgent = [...options.toolInfo];
3421
- } else {
3422
- toolsForAgent = options.toolInfo.filter((t) => expandedToolNames.has(t.name));
3423
- }
3424
- } else {
3425
- toolsForAgent = [...options.toolInfo];
3426
- }
3427
- if (!rawAllowedToolNames || rawAllowedToolNames.includes("all") || rawAllowedToolNames.includes("runWorkflow")) {
3428
- toolsForAgent.push({
3429
- name: "runWorkflow",
3430
- description: "Run a named sub-workflow defined in the current workflow file.",
3431
- parameters: z23.object({
3432
- workflowId: z23.string().describe("Sub-workflow id to run"),
3433
- input: z23.any().nullish().describe("Optional input object for the sub-workflow")
3434
- }),
3435
- handler: async () => {
3436
- return { success: false, message: { type: "error-text", value: "runWorkflow is virtual." } };
3437
- }
3438
- });
3439
- }
3440
- const allowedToolNameSet = new Set(toolsForAgent.map((t) => t.name));
3441
- context.logger.debug(`[Agent] Available tools for step '${stepDef.id}': ${toolsForAgent.map((t) => t.name).join(", ")}`);
3442
- const systemPrompt = options.stepSystemPrompt?.({ workflowId, step: stepDef, input, state }) ?? [
3443
- `You are an AI assistant executing a workflow step.`,
3444
- "",
3445
- "# Instructions",
3446
- "- Execute the task defined in the user message.",
3447
- "- Use the provided tools to accomplish the task.",
3448
- "- Return the step output as valid JSON in markdown.",
3449
- "- Do not ask for user input. If information is missing, make a reasonable assumption or fail."
3450
- ].filter(Boolean).join("\n");
3451
- const userContent = [
3452
- `Workflow: ${workflowId}`,
3453
- `Step: ${stepDef.id}`,
3454
- `Task: ${stepDef.task}`,
3455
- stepDef.expected_outcome ? `Expected outcome: ${stepDef.expected_outcome}` : "",
3456
- `Workflow Input: ${JSON.stringify(input)}`,
3457
- `Current State: ${JSON.stringify(state)}`
3458
- ].filter(Boolean).join("\n");
3459
- const runWorkflow = createRunWorkflowFn({ input, state, context, runInternal });
3460
- const agentTools = {
3461
- generateText: tools.generateText.bind(tools),
3462
- taskEvent: tools.taskEvent.bind(tools),
3463
- invokeTool: async ({ toolName, input: toolInput }) => {
3464
- if (!allowedToolNameSet.has(toolName)) {
3465
- return {
3466
- success: false,
3467
- message: { type: "error-text", value: `Tool '${toolName}' is not allowed in this step.` }
3468
- };
3469
- }
3470
- if (toolName === "runWorkflow") {
3471
- const runWorkflowInput = toolInput;
3472
- const subWorkflowId = runWorkflowInput?.workflowId;
3473
- const subInput = runWorkflowInput?.input;
3474
- if (typeof subWorkflowId !== "string") {
3475
- return {
3476
- success: false,
3477
- message: { type: "error-text", value: "runWorkflow.workflowId must be a string." }
3478
- };
3479
- }
3480
- try {
3481
- const output = await runWorkflow(subWorkflowId, subInput);
3482
- const jsonResult = { type: "json", value: output };
3483
- return { success: true, message: jsonResult };
3484
- } catch (error) {
3485
- return {
3486
- success: false,
3487
- message: { type: "error-text", value: error instanceof Error ? error.message : String(error) }
3488
- };
3489
- }
3490
- }
3491
- return await tools.invokeTool({ toolName, input: toolInput });
3492
- }
3493
- };
3494
- const result = await agentWorkflow(
3495
- {
3496
- tools: toolsForAgent,
3497
- systemPrompt,
3498
- userMessage: [{ role: "user", content: userContent }],
3499
- maxToolRoundTrips: options.maxToolRoundTrips,
3500
- model: options.model
3501
- },
3502
- { ...context, tools: agentTools }
3503
- );
3504
- if (result.type === "Exit") {
3505
- if (result.object !== void 0) {
3506
- return result.object;
3507
- }
3508
- const parsed = parseJsonFromMarkdown(result.message);
3509
- if (parsed.success) {
3510
- return parsed.data;
3511
- }
3512
- if (options.wrapAgentResultInObject) {
3513
- context.logger.warn(`[Agent] Step '${stepDef.id}' returned plain text instead of JSON. Wrapping in {result: ...}`);
3514
- return { result: result.message };
3515
- }
3516
- return result.message;
3517
- }
3518
- if (result.type === "Error") {
3519
- throw new Error(`Agent step '${stepDef.id}' in workflow '${workflowId}' failed: ${result.error?.message || "Unknown error"}`);
3520
- }
3521
- if (result.type === "UsageExceeded") {
3522
- throw new Error(`Agent step '${stepDef.id}' in workflow '${workflowId}' exceeded usage limits (tokens or rounds)`);
3523
- }
3524
- const _exhaustiveCheck = result;
3525
- throw new Error(`Agent step '${stepDef.id}' in workflow '${workflowId}' exited unexpectedly with unhandled type`);
3526
- }
3527
- async function executeStepWithTimeout(stepDef, workflowId, input, state, context, options, runInternal) {
3528
- const executeStepLogic = async () => {
3529
- context.logger.debug(`[Step] Executing step '${stepDef.id}' with agent`);
3530
- const result = await executeStepWithAgent(stepDef, workflowId, input, state, context, options, runInternal);
3531
- context.logger.debug(`[Step] Agent execution completed for step '${stepDef.id}'`);
3532
- return result;
3533
- };
3534
- if (stepDef.timeout && stepDef.timeout > 0) {
3535
- context.logger.debug(`[Step] Step '${stepDef.id}' has timeout of ${stepDef.timeout}ms`);
3536
- let timeoutId;
3537
- const timeoutPromise = new Promise((_, reject) => {
3538
- timeoutId = setTimeout(
3539
- () => reject(new Error(`Step '${stepDef.id}' in workflow '${workflowId}' timed out after ${stepDef.timeout}ms`)),
3540
- stepDef.timeout
3541
- );
3542
- });
3543
- try {
3544
- return await Promise.race([executeStepLogic(), timeoutPromise]);
3545
- } finally {
3546
- if (timeoutId) clearTimeout(timeoutId);
3547
- }
3548
- }
3549
- return await executeStepLogic();
3550
- }
3551
- async function executeStep(stepDef, workflowId, input, state, context, options, runInternal) {
3552
- const result = await executeStepWithTimeout(stepDef, workflowId, input, state, context, options, runInternal);
3553
- if (stepDef.outputSchema) {
3554
- try {
3555
- context.logger.debug(`[Step] Validating output for step '${stepDef.id}' against schema`);
3556
- const zodSchema = convertJsonSchemaToZod(stepDef.outputSchema);
3557
- const validationResult = zodSchema.safeParse(result);
3558
- if (!validationResult.success) {
3559
- const errorDetails = validationResult.error.issues.map((e) => ` - ${e.path.join(".") || "root"}: ${e.message}`).join("\n");
3560
- throw new Error(`Output does not match expected schema:
3561
- ${errorDetails}`);
3562
- }
3563
- context.logger.debug(`[Step] Output validation successful for step '${stepDef.id}'`);
3564
- } catch (error) {
3565
- throw new Error(
3566
- `Step '${stepDef.id}' in workflow '${workflowId}' output validation failed: ${error instanceof Error ? error.message : String(error)}`
3567
- );
3568
- }
3569
- }
3570
- return result;
3571
- }
3572
- function isBreakStep(step) {
3573
- return typeof step === "object" && step !== null && "break" in step && step.break === true;
3574
- }
3575
- function isContinueStep(step) {
3576
- return typeof step === "object" && step !== null && "continue" in step && step.continue === true;
3577
- }
3578
- function isWhileLoopStep(step) {
3579
- return typeof step === "object" && step !== null && "while" in step;
3580
- }
3581
- function isIfElseStep(step) {
3582
- return typeof step === "object" && step !== null && "if" in step;
3583
- }
3584
- function isTryCatchStep(step) {
3585
- return typeof step === "object" && step !== null && "try" in step;
3586
- }
3587
- function storeStepOutput(step, result, state) {
3588
- if ("id" in step && step.output) {
3589
- const outputKey = step.output;
3590
- state[outputKey] = result;
3591
- }
3592
- }
3593
- function getStepId(step) {
3594
- if ("id" in step && step.id) {
3595
- return step.id;
3596
- }
3597
- if (isWhileLoopStep(step)) {
3598
- return "while";
3599
- }
3600
- if (isIfElseStep(step)) {
3601
- return "if";
3602
- }
3603
- if (isTryCatchStep(step)) {
3604
- return "try";
3605
- }
3606
- return "control";
3607
- }
3608
- async function executeControlFlowStep(step, workflowId, input, state, context, options, runInternal, loopDepth, breakFlag, continueFlag) {
3609
- if (isBreakStep(step)) {
3610
- if (loopDepth === 0) {
3611
- throw new Error(`'break' statement found outside of a loop in workflow '${workflowId}'`);
3612
- }
3613
- context.logger.debug(`[ControlFlow] Executing break statement (loop depth: ${loopDepth})`);
3614
- return { result: void 0, shouldBreak: true, shouldContinue: false };
3615
- }
3616
- if (isContinueStep(step)) {
3617
- if (loopDepth === 0) {
3618
- throw new Error(`'continue' statement found outside of a loop in workflow '${workflowId}'`);
3619
- }
3620
- context.logger.debug(`[ControlFlow] Executing continue statement (loop depth: ${loopDepth})`);
3621
- return { result: void 0, shouldBreak: false, shouldContinue: true };
3622
- }
3623
- if (isWhileLoopStep(step)) {
3624
- context.logger.info(`[ControlFlow] Executing while loop '${step.id}'`);
3625
- context.logger.debug(`[ControlFlow] Condition: ${step.while.condition}`);
3626
- context.logger.debug(`[ControlFlow] Loop body has ${step.while.steps.length} step(s)`);
3627
- let iterationCount = 0;
3628
- let loopResult;
3629
- while (true) {
3630
- iterationCount++;
3631
- if (iterationCount > MAX_WHILE_LOOP_ITERATIONS) {
3632
- throw new Error(
3633
- `While loop '${step.id}' in workflow '${workflowId}' exceeded maximum iteration limit of ${MAX_WHILE_LOOP_ITERATIONS}`
3634
- );
3635
- }
3636
- const conditionResult = evaluateCondition(step.while.condition, input, state, options.allowUnsafeCodeExecution);
3637
- context.logger.debug(`[ControlFlow] While loop '${step.id}' iteration ${iterationCount}: condition = ${conditionResult}`);
3638
- if (!conditionResult) {
3639
- context.logger.info(`[ControlFlow] While loop '${step.id}' terminated after ${iterationCount - 1} iteration(s)`);
3640
- break;
3641
- }
3642
- for (const bodyStep of step.while.steps) {
3643
- const { result, shouldBreak, shouldContinue } = await executeControlFlowStep(
3644
- bodyStep,
3645
- workflowId,
3646
- input,
3647
- state,
3648
- context,
3649
- options,
3650
- runInternal,
3651
- loopDepth + 1,
3652
- breakFlag,
3653
- continueFlag
3654
- );
3655
- if (shouldBreak) {
3656
- context.logger.debug(`[ControlFlow] Breaking from while loop '${step.id}'`);
3657
- breakFlag.value = false;
3658
- return { result: loopResult, shouldBreak: false, shouldContinue: false };
3659
- }
3660
- if (shouldContinue) {
3661
- context.logger.debug(`[ControlFlow] Continuing to next iteration of while loop '${step.id}'`);
3662
- continueFlag.value = false;
3663
- break;
3664
- }
3665
- storeStepOutput(bodyStep, result, state);
3666
- loopResult = result;
3667
- }
3668
- }
3669
- const outputKey = step.output ?? step.id;
3670
- state[outputKey] = loopResult;
3671
- context.logger.debug(`[ControlFlow] While loop '${step.id}' stored output as '${outputKey}'`);
3672
- return { result: loopResult, shouldBreak: false, shouldContinue: false };
3673
- }
3674
- if (isIfElseStep(step)) {
3675
- const ifStep = step;
3676
- context.logger.info(`[ControlFlow] Executing if/else branch '${ifStep.id}'`);
3677
- context.logger.debug(`[ControlFlow] Condition: ${ifStep.if.condition}`);
3678
- context.logger.debug(`[ControlFlow] Then branch has ${ifStep.if.thenBranch.length} step(s)`);
3679
- if (ifStep.if.elseBranch) {
3680
- context.logger.debug(`[ControlFlow] Else branch has ${ifStep.if.elseBranch.length} step(s)`);
3681
- }
3682
- const conditionResult = evaluateCondition(ifStep.if.condition, input, state, options.allowUnsafeCodeExecution);
3683
- context.logger.debug(`[ControlFlow] If/else '${ifStep.id}' condition = ${conditionResult}`);
3684
- const branchSteps = conditionResult ? ifStep.if.thenBranch : ifStep.if.elseBranch ?? [];
3685
- const branchName = conditionResult ? "then" : ifStep.if.elseBranch ? "else" : "else (empty)";
3686
- context.logger.info(`[ControlFlow] Taking '${branchName}' branch of '${ifStep.id}'`);
3687
- let branchResult;
3688
- for (const branchStep of branchSteps) {
3689
- const { result, shouldBreak, shouldContinue } = await executeControlFlowStep(
3690
- branchStep,
3691
- workflowId,
3692
- input,
3693
- state,
3694
- context,
3695
- options,
3696
- runInternal,
3697
- loopDepth,
3698
- breakFlag,
3699
- continueFlag
3700
- );
3701
- if (shouldBreak || shouldContinue) {
3702
- return { result, shouldBreak, shouldContinue };
3703
- }
3704
- storeStepOutput(branchStep, result, state);
3705
- branchResult = result;
3706
- }
3707
- const outputKey = ifStep.output ?? ifStep.id;
3708
- state[outputKey] = branchResult;
3709
- context.logger.debug(`[ControlFlow] If/else '${ifStep.id}' stored output as '${outputKey}'`);
3710
- return { result: branchResult, shouldBreak: false, shouldContinue: false };
3711
- }
3712
- if (isTryCatchStep(step)) {
3713
- const tryStep = step;
3714
- context.logger.info(`[ControlFlow] Executing try/catch block '${tryStep.id}'`);
3715
- context.logger.debug(`[ControlFlow] Try block has ${tryStep.try.trySteps.length} step(s)`);
3716
- context.logger.debug(`[ControlFlow] Catch block has ${tryStep.try.catchSteps.length} step(s)`);
3717
- let tryResult;
3718
- let caughtError;
3719
- try {
3720
- for (const tryStepItem of tryStep.try.trySteps) {
3721
- const { result } = await executeControlFlowStep(
3722
- tryStepItem,
3723
- workflowId,
3724
- input,
3725
- state,
3726
- context,
3727
- options,
3728
- runInternal,
3729
- loopDepth,
3730
- breakFlag,
3731
- continueFlag
3732
- );
3733
- storeStepOutput(tryStepItem, result, state);
3734
- tryResult = result;
3735
- }
3736
- const outputKey = tryStep.output ?? tryStep.id;
3737
- state[outputKey] = tryResult;
3738
- context.logger.debug(`[ControlFlow] Try/catch '${tryStep.id}' completed successfully`);
3739
- return { result: tryResult, shouldBreak: false, shouldContinue: false };
3740
- } catch (error) {
3741
- caughtError = error instanceof Error ? error : new Error(String(error));
3742
- context.logger.warn(`[ControlFlow] Try/catch '${tryStep.id}' caught error: ${caughtError.message}`);
3743
- let catchResult;
3744
- for (const catchStepItem of tryStep.try.catchSteps) {
3745
- const { result } = await executeControlFlowStep(
3746
- catchStepItem,
3747
- workflowId,
3748
- input,
3749
- state,
3750
- context,
3751
- options,
3752
- runInternal,
3753
- loopDepth,
3754
- breakFlag,
3755
- continueFlag
3756
- );
3757
- storeStepOutput(catchStepItem, result, state);
3758
- catchResult = result;
3759
- }
3760
- const outputKey = tryStep.output ?? tryStep.id;
3761
- state[outputKey] = catchResult;
3762
- context.logger.debug(`[ControlFlow] Try/catch '${tryStep.id}' caught error and executed catch block`);
3763
- return { result: catchResult, shouldBreak: false, shouldContinue: false };
3764
- }
3765
- }
3766
- const stepDef = step;
3767
- const stepResult = await executeStep(stepDef, workflowId, input, state, context, options, runInternal);
3768
- return { result: stepResult, shouldBreak: false, shouldContinue: false };
3769
- }
3770
- function createDynamicWorkflow(definition, options = {}) {
3771
- if (typeof definition === "string") {
3772
- const res = parseDynamicWorkflowDefinition(definition);
3773
- if (!res.success) {
3774
- throw new Error(res.error);
3775
- }
3776
- definition = res.definition;
3777
- }
3778
- const runInternal = async (workflowId, input, context, inheritedState) => {
3779
- const workflow = definition.workflows[workflowId];
3780
- if (!workflow) {
3781
- const builtIn = options.builtInWorkflows?.[workflowId];
3782
- if (builtIn) {
3783
- context.logger.info(`[Workflow] Delegating to built-in workflow '${workflowId}'`);
3784
- return await builtIn(input, context);
3785
- }
3786
- throw new Error(`Workflow '${workflowId}' not found`);
3787
- }
3788
- const validatedInput = validateAndApplyDefaults(workflowId, workflow, input);
3789
- context.logger.info(`[Workflow] Starting workflow '${workflowId}'`);
3790
- context.logger.debug(`[Workflow] Input: ${JSON.stringify(validatedInput)}`);
3791
- context.logger.debug(`[Workflow] Inherited state: ${JSON.stringify(inheritedState)}`);
3792
- context.logger.debug(`[Workflow] Steps: ${workflow.steps.map((s) => "id" in s ? s.id : "<control flow>").join(", ")}`);
3793
- const state = { ...inheritedState };
3794
- let lastOutput;
3795
- const breakFlag = { value: false };
3796
- const continueFlag = { value: false };
3797
- for (let i = 0; i < workflow.steps.length; i++) {
3798
- const stepDef = workflow.steps[i];
3799
- const stepId = getStepId(stepDef);
3800
- context.logger.info(`[Workflow] Step ${i + 1}/${workflow.steps.length}: ${stepId}`);
3801
- const { result } = await executeControlFlowStep(
3802
- stepDef,
3803
- workflowId,
3804
- validatedInput,
3805
- state,
3806
- context,
3807
- options,
3808
- runInternal,
3809
- 0,
3810
- // loop depth
3811
- breakFlag,
3812
- continueFlag
3813
- );
3814
- lastOutput = result;
3815
- storeStepOutput(stepDef, result, state);
3816
- if ("id" in stepDef && stepDef.output) {
3817
- context.logger.debug(
3818
- `[Workflow] Step output stored as '${stepDef.output}': ${typeof lastOutput === "object" ? JSON.stringify(lastOutput).substring(0, 200) : lastOutput}`
3819
- );
3820
- }
3821
- }
3822
- context.logger.info(`[Workflow] Completed workflow '${workflowId}'`);
3823
- if (workflow.output) {
3824
- context.logger.debug(`[Workflow] Returning output field: ${workflow.output}`);
3825
- return state[workflow.output];
3826
- }
3827
- context.logger.debug(`[Workflow] Returning full state with keys: ${Object.keys(state).join(", ")}`);
3828
- return state;
3829
- };
3830
- return async (workflowId, input, context) => {
3831
- return await runInternal(workflowId, input, context, {});
3832
- };
3833
- }
3834
-
3835
- // src/workflow/json-ai-types.ts
3836
- var toJsonDataContent = (data) => {
3837
- if (data instanceof URL) {
3838
- return {
3839
- type: "url",
3840
- value: data.toString()
3841
- };
3842
- }
3843
- if (typeof data === "string") {
3844
- return {
3845
- type: "base64",
3846
- value: data
3847
- };
3848
- }
3849
- let buffer;
3850
- if (data instanceof Uint8Array) {
3851
- buffer = Buffer.from(data);
3852
- } else if (data instanceof Buffer) {
3853
- buffer = data;
3854
- } else {
3855
- buffer = Buffer.from(data);
3856
- }
3857
- return {
3858
- type: "base64",
3859
- value: buffer.toString("base64")
3860
- };
3861
- };
3862
- var toJsonUserContent = (content) => {
3863
- if (typeof content === "string") {
3864
- return content;
3865
- }
3866
- return content.map((part) => {
3867
- switch (part.type) {
3868
- case "image":
3869
- return {
3870
- ...part,
3871
- image: toJsonDataContent(part.image)
3872
- };
3873
- case "file":
3874
- return {
3875
- ...part,
3876
- data: toJsonDataContent(part.data)
3877
- };
3878
- }
3879
- return part;
3880
- });
3881
- };
3882
- var toJsonAssistantContent = (content) => {
3883
- if (typeof content === "string") {
3884
- return content;
3885
- }
3886
- return content.map((part) => {
3887
- switch (part.type) {
3888
- case "file":
3889
- return {
3890
- ...part,
3891
- data: toJsonDataContent(part.data)
3892
- };
3893
- case "tool-call":
3894
- return {
3895
- ...part,
3896
- input: part.input
3897
- };
3898
- }
3899
- return part;
3900
- });
3901
- };
3902
- var toJsonModelMessage = (msg) => {
3903
- switch (msg.role) {
3904
- case "user":
3905
- return {
3906
- ...msg,
3907
- content: toJsonUserContent(msg.content)
3908
- };
3909
- case "assistant":
3910
- return {
3911
- ...msg,
3912
- content: toJsonAssistantContent(msg.content)
3913
- };
3914
- }
3915
- return msg;
3916
- };
3917
- var fromJsonDataContent = (data) => {
3918
- if (data.type === "url") {
3919
- return new URL(data.value);
3920
- }
3921
- return Buffer.from(data.value, "base64");
3922
- };
3923
- var fromJsonUserContent = (content) => {
3924
- if (typeof content === "string") {
3925
- return content;
3926
- }
3927
- return content.map((part) => {
3928
- switch (part.type) {
3929
- case "image":
3930
- return {
3931
- ...part,
3932
- image: fromJsonDataContent(part.image)
3933
- };
3934
- case "file":
3935
- return {
3936
- ...part,
3937
- data: fromJsonDataContent(part.data)
3938
- };
3939
- }
3940
- return part;
3941
- });
3942
- };
3943
- var fromJsonAssistantContent = (content) => {
3944
- if (typeof content === "string") {
3945
- return content;
3946
- }
3947
- return content.map((part) => {
3948
- switch (part.type) {
3949
- case "file":
3950
- return {
3951
- ...part,
3952
- data: fromJsonDataContent(part.data)
3953
- };
3954
- }
3955
- return part;
3956
- });
3957
- };
3958
- var fromJsonModelMessage = (msg) => {
3959
- switch (msg.role) {
3960
- case "system":
3961
- return msg;
3962
- case "user":
3963
- return {
3964
- ...msg,
3965
- content: fromJsonUserContent(msg.content)
3966
- };
3967
- case "assistant":
3968
- return {
3969
- ...msg,
3970
- content: fromJsonAssistantContent(msg.content)
3971
- };
3972
- }
3973
- return msg;
3974
- };
3975
-
3976
- // src/workflow/workflow.ts
3977
- var silentLogger = {
3978
- debug: () => {
3979
- },
3980
- info: () => {
3981
- },
3982
- warn: () => {
3983
- },
3984
- error: () => {
3985
- }
3986
- };
3987
- function createContext(tools, stepFn, logger = silentLogger) {
3988
- if (!stepFn) {
3989
- stepFn = async (_name, arg2, arg3) => {
3990
- const fn = typeof arg2 === "function" ? arg2 : arg3;
3991
- return fn();
3992
- };
3993
- }
3994
- return { step: stepFn, logger, tools };
3995
- }
3996
- var makeStepFn = () => {
3997
- const results = /* @__PURE__ */ new Map();
3998
- const callStack = [];
3999
- return async (name, arg2, arg3) => {
4000
- let fn;
4001
- let options;
4002
- if (typeof arg2 === "function") {
4003
- fn = arg2;
4004
- options = arg3;
4005
- } else {
4006
- options = arg2;
4007
- fn = arg3;
4008
- }
4009
- callStack.push(name);
4010
- const key = callStack.join(">");
4011
- try {
4012
- if (results.has(key)) {
4013
- return results.get(key);
4014
- }
4015
- const maxRetryCount = options?.retry ?? 0;
4016
- let lastError;
4017
- for (let retryCount = 0; retryCount <= maxRetryCount; retryCount++) {
4018
- try {
4019
- const result = await fn();
4020
- results.set(key, result);
4021
- return result;
4022
- } catch (error) {
4023
- lastError = error;
4024
- }
4025
- }
4026
- throw lastError;
4027
- } finally {
4028
- callStack.pop();
4029
- }
4030
- };
4031
- };
4032
- export {
4033
- BaseError,
4034
- BreakStepSchema,
4035
- ContinueStepSchema,
4036
- DEFAULT_MEMORY_CONFIG,
4037
- IGNORED_DIRECTORIES,
4038
- IfElseStepSchema,
4039
- ListSkillsInputSchema,
4040
- ListSkillsOutputSchema,
4041
- LoadSkillInputSchema,
4042
- LoadSkillOutputSchema,
4043
- MockProvider,
4044
- NodeFileSystemProvider,
4045
- PricingService,
4046
- ReadSkillFileInputSchema,
4047
- ReadSkillFileOutputSchema,
4048
- SKILL_ERROR_MESSAGES,
4049
- SKILL_LIMITS,
4050
- SOURCE_ICONS,
4051
- SUSPICIOUS_PATTERNS,
4052
- SkillDiscoveryError,
4053
- SkillDiscoveryService,
4054
- SkillValidationError,
4055
- TOOL_GROUPS,
4056
- TaskEventKind,
4057
- TodoItemSchema,
4058
- TodoStatus,
4059
- TryCatchStepSchema,
4060
- UpdateTodoItemInputSchema,
4061
- UpdateTodoItemOutputSchema,
4062
- UsageMeter,
4063
- WhileLoopStepSchema,
4064
- WorkflowControlFlowStepSchema,
4065
- WorkflowDefinitionSchema,
4066
- WorkflowFileSchema,
4067
- WorkflowInputDefinitionSchema,
4068
- WorkflowStepDefinitionSchema,
4069
- agentWorkflow,
4070
- askFollowupQuestion_default as askFollowupQuestion,
4071
- baseApprovalConfigSchema,
4072
- baseModelConfigSchema,
4073
- computeRateLimitBackoffSeconds,
4074
- configSchema,
4075
- convertJsonSchemaToZod,
4076
- createContext,
4077
- createDynamicWorkflow,
4078
- createErrorClass,
4079
- createErrorResponse,
4080
- createProviderErrorResponse,
4081
- createSuccessResponse,
4082
- createValidationErrorResponse,
4083
- deepMerge,
4084
- executeCommand_default as executeCommand,
4085
- fetchUrl_default as fetchUrl,
4086
- fromJsonModelMessage,
4087
- getSkillStats,
4088
- listFiles_default as listFiles,
4089
- listSkills,
4090
- listSkillsToolInfo,
4091
- loadSkill,
4092
- loadSkillToolInfo,
4093
- makeStepFn,
4094
- mcpServerConfigSchema,
4095
- memoryConfigSchema,
4096
- modelConfigSchema,
4097
- parseDynamicWorkflowDefinition,
4098
- parseJsonFromMarkdown,
4099
- providerConfigSchema,
4100
- providerModelSchema,
4101
- readBinaryFile_default as readBinaryFile,
4102
- readFile_default as readFile,
4103
- readSkillFile,
4104
- readSkillFileToolInfo,
4105
- removeFile_default as removeFile,
4106
- renameFile_default as renameFile,
4107
- replaceInFile_default as replaceInFile,
4108
- replaceInFile as replaceInFileHelper,
4109
- resolveHomePath,
4110
- responsePrompts,
4111
- ruleSchema,
4112
- scriptSchema,
4113
- search_default as search,
4114
- searchFiles_default as searchFiles,
4115
- skillMetadataSchema,
4116
- toJsonModelMessage,
4117
- toolConfigSchema,
4118
- validateSkillMetadata,
4119
- validateSkillReferences,
4120
- validateSkillSecurity,
4121
- validateWorkflowFile,
4122
- writeToFile_default as writeToFile
4123
- };
1
+ export * from './Agent';
2
+ export * from './Agent/backoff';
3
+ export * from './config';
4
+ export * from './errors';
5
+ export * from './fs';
6
+ export * from './memory';
7
+ export * from './pricing';
8
+ export * from './skills';
9
+ export * from './skills/tools';
10
+ export * from './tool';
11
+ export * from './tools';
12
+ export { replaceInFile as replaceInFileHelper } from './tools/utils/replaceInFile';
13
+ export * from './UsageMeter';
14
+ export * from './utils';
15
+ export * from './workflow/agent.workflow';
16
+ export * from './workflow/dynamic';
17
+ export * from './workflow/dynamic-types';
18
+ export * from './workflow/json-ai-types';
19
+ export * from './workflow/types';
20
+ export * from './workflow/workflow';
21
+ //# sourceMappingURL=index.js.map