@vedangiitb/qwintly-core 1.0.2

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 (226) hide show
  1. package/README.md +8 -0
  2. package/dist/ai/ai.d.ts +2 -0
  3. package/dist/ai/ai.d.ts.map +1 -0
  4. package/dist/ai/ai.js +2 -0
  5. package/dist/ai/ai.js.map +1 -0
  6. package/dist/ai/generate/gemini.client.d.ts +15 -0
  7. package/dist/ai/generate/gemini.client.d.ts.map +1 -0
  8. package/dist/ai/generate/gemini.client.js +39 -0
  9. package/dist/ai/generate/gemini.client.js.map +1 -0
  10. package/dist/ai/generate/generateClient.d.ts +3 -0
  11. package/dist/ai/generate/generateClient.d.ts.map +1 -0
  12. package/dist/ai/generate/generateClient.js +8 -0
  13. package/dist/ai/generate/generateClient.js.map +1 -0
  14. package/dist/ai/toolLoop/toolLoopContext.d.ts +33 -0
  15. package/dist/ai/toolLoop/toolLoopContext.d.ts.map +1 -0
  16. package/dist/ai/toolLoop/toolLoopContext.js +112 -0
  17. package/dist/ai/toolLoop/toolLoopContext.js.map +1 -0
  18. package/dist/ai/toolLoop/toolLoopRunner.d.ts +43 -0
  19. package/dist/ai/toolLoop/toolLoopRunner.d.ts.map +1 -0
  20. package/dist/ai/toolLoop/toolLoopRunner.js +227 -0
  21. package/dist/ai/toolLoop/toolLoopRunner.js.map +1 -0
  22. package/dist/ai/toolLoop/toolLoopRunnerUtils.d.ts +51 -0
  23. package/dist/ai/toolLoop/toolLoopRunnerUtils.d.ts.map +1 -0
  24. package/dist/ai/toolLoop/toolLoopRunnerUtils.js +164 -0
  25. package/dist/ai/toolLoop/toolLoopRunnerUtils.js.map +1 -0
  26. package/dist/ai/tools/helpers/applyPatch.helpers.d.ts +36 -0
  27. package/dist/ai/tools/helpers/applyPatch.helpers.d.ts.map +1 -0
  28. package/dist/ai/tools/helpers/applyPatch.helpers.js +307 -0
  29. package/dist/ai/tools/helpers/applyPatch.helpers.js.map +1 -0
  30. package/dist/ai/tools/helpers/applyPatch.helpers.test.d.ts +2 -0
  31. package/dist/ai/tools/helpers/applyPatch.helpers.test.d.ts.map +1 -0
  32. package/dist/ai/tools/helpers/applyPatch.helpers.test.js +50 -0
  33. package/dist/ai/tools/helpers/applyPatch.helpers.test.js.map +1 -0
  34. package/dist/ai/tools/helpers/fileSystem.helpers.d.ts +2 -0
  35. package/dist/ai/tools/helpers/fileSystem.helpers.d.ts.map +1 -0
  36. package/dist/ai/tools/helpers/fileSystem.helpers.js +45 -0
  37. package/dist/ai/tools/helpers/fileSystem.helpers.js.map +1 -0
  38. package/dist/ai/tools/helpers/fileSystem.helpers.test.d.ts +2 -0
  39. package/dist/ai/tools/helpers/fileSystem.helpers.test.d.ts.map +1 -0
  40. package/dist/ai/tools/helpers/fileSystem.helpers.test.js +15 -0
  41. package/dist/ai/tools/helpers/fileSystem.helpers.test.js.map +1 -0
  42. package/dist/ai/tools/helpers/format.helpers.d.ts +2 -0
  43. package/dist/ai/tools/helpers/format.helpers.d.ts.map +1 -0
  44. package/dist/ai/tools/helpers/format.helpers.js +14 -0
  45. package/dist/ai/tools/helpers/format.helpers.js.map +1 -0
  46. package/dist/ai/tools/helpers/nextRouteFilePolicy.d.ts +8 -0
  47. package/dist/ai/tools/helpers/nextRouteFilePolicy.d.ts.map +1 -0
  48. package/dist/ai/tools/helpers/nextRouteFilePolicy.js +26 -0
  49. package/dist/ai/tools/helpers/nextRouteFilePolicy.js.map +1 -0
  50. package/dist/ai/tools/implementations/applyPatch.impl.d.ts +53 -0
  51. package/dist/ai/tools/implementations/applyPatch.impl.d.ts.map +1 -0
  52. package/dist/ai/tools/implementations/applyPatch.impl.js +242 -0
  53. package/dist/ai/tools/implementations/applyPatch.impl.js.map +1 -0
  54. package/dist/ai/tools/implementations/applyPatch.impl.test.d.ts +2 -0
  55. package/dist/ai/tools/implementations/applyPatch.impl.test.d.ts.map +1 -0
  56. package/dist/ai/tools/implementations/applyPatch.impl.test.js +72 -0
  57. package/dist/ai/tools/implementations/applyPatch.impl.test.js.map +1 -0
  58. package/dist/ai/tools/implementations/factories.d.ts +90 -0
  59. package/dist/ai/tools/implementations/factories.d.ts.map +1 -0
  60. package/dist/ai/tools/implementations/factories.js +26 -0
  61. package/dist/ai/tools/implementations/factories.js.map +1 -0
  62. package/dist/ai/tools/implementations/listDir.impl.d.ts +3 -0
  63. package/dist/ai/tools/implementations/listDir.impl.d.ts.map +1 -0
  64. package/dist/ai/tools/implementations/listDir.impl.js +47 -0
  65. package/dist/ai/tools/implementations/listDir.impl.js.map +1 -0
  66. package/dist/ai/tools/implementations/readFile.impl.d.ts +3 -0
  67. package/dist/ai/tools/implementations/readFile.impl.d.ts.map +1 -0
  68. package/dist/ai/tools/implementations/readFile.impl.js +23 -0
  69. package/dist/ai/tools/implementations/readFile.impl.js.map +1 -0
  70. package/dist/ai/tools/implementations/search.impl.d.ts +18 -0
  71. package/dist/ai/tools/implementations/search.impl.d.ts.map +1 -0
  72. package/dist/ai/tools/implementations/search.impl.js +74 -0
  73. package/dist/ai/tools/implementations/search.impl.js.map +1 -0
  74. package/dist/ai/tools/implementations/workspaceDeps.d.ts +22 -0
  75. package/dist/ai/tools/implementations/workspaceDeps.d.ts.map +1 -0
  76. package/dist/ai/tools/implementations/workspaceDeps.js +2 -0
  77. package/dist/ai/tools/implementations/workspaceDeps.js.map +1 -0
  78. package/dist/ai/tools/implementations/writeFile.impl.d.ts +27 -0
  79. package/dist/ai/tools/implementations/writeFile.impl.d.ts.map +1 -0
  80. package/dist/ai/tools/implementations/writeFile.impl.js +62 -0
  81. package/dist/ai/tools/implementations/writeFile.impl.js.map +1 -0
  82. package/dist/ai/tools/schemas/applyPatch.schema.d.ts +16 -0
  83. package/dist/ai/tools/schemas/applyPatch.schema.d.ts.map +1 -0
  84. package/dist/ai/tools/schemas/applyPatch.schema.js +17 -0
  85. package/dist/ai/tools/schemas/applyPatch.schema.js.map +1 -0
  86. package/dist/ai/tools/schemas/listDir.schema.d.ts +22 -0
  87. package/dist/ai/tools/schemas/listDir.schema.d.ts.map +1 -0
  88. package/dist/ai/tools/schemas/listDir.schema.js +22 -0
  89. package/dist/ai/tools/schemas/listDir.schema.js.map +1 -0
  90. package/dist/ai/tools/schemas/readFile.schema.d.ts +26 -0
  91. package/dist/ai/tools/schemas/readFile.schema.d.ts.map +1 -0
  92. package/dist/ai/tools/schemas/readFile.schema.js +26 -0
  93. package/dist/ai/tools/schemas/readFile.schema.js.map +1 -0
  94. package/dist/ai/tools/schemas/search.schema.d.ts +16 -0
  95. package/dist/ai/tools/schemas/search.schema.d.ts.map +1 -0
  96. package/dist/ai/tools/schemas/search.schema.js +16 -0
  97. package/dist/ai/tools/schemas/search.schema.js.map +1 -0
  98. package/dist/ai/tools/schemas/submitCodegenDone.schema.d.ts +16 -0
  99. package/dist/ai/tools/schemas/submitCodegenDone.schema.d.ts.map +1 -0
  100. package/dist/ai/tools/schemas/submitCodegenDone.schema.js +16 -0
  101. package/dist/ai/tools/schemas/submitCodegenDone.schema.js.map +1 -0
  102. package/dist/ai/tools/schemas/submitPlannerTasks.schema.d.ts +33 -0
  103. package/dist/ai/tools/schemas/submitPlannerTasks.schema.d.ts.map +1 -0
  104. package/dist/ai/tools/schemas/submitPlannerTasks.schema.js +31 -0
  105. package/dist/ai/tools/schemas/submitPlannerTasks.schema.js.map +1 -0
  106. package/dist/ai/tools/schemas/writeFile.schema.d.ts +20 -0
  107. package/dist/ai/tools/schemas/writeFile.schema.d.ts.map +1 -0
  108. package/dist/ai/tools/schemas/writeFile.schema.js +23 -0
  109. package/dist/ai/tools/schemas/writeFile.schema.js.map +1 -0
  110. package/dist/ai/tools/toolsets/codegenTools.d.ts +3 -0
  111. package/dist/ai/tools/toolsets/codegenTools.d.ts.map +1 -0
  112. package/dist/ai/tools/toolsets/codegenTools.js +17 -0
  113. package/dist/ai/tools/toolsets/codegenTools.js.map +1 -0
  114. package/dist/ai/tools/toolsets/plannerTools.d.ts +3 -0
  115. package/dist/ai/tools/toolsets/plannerTools.d.ts.map +1 -0
  116. package/dist/ai/tools/toolsets/plannerTools.js +17 -0
  117. package/dist/ai/tools/toolsets/plannerTools.js.map +1 -0
  118. package/dist/core.d.ts +44 -0
  119. package/dist/core.d.ts.map +1 -0
  120. package/dist/core.js +80 -0
  121. package/dist/core.js.map +1 -0
  122. package/dist/index.d.ts +2 -0
  123. package/dist/index.d.ts.map +1 -0
  124. package/dist/index.js +3 -0
  125. package/dist/index.js.map +1 -0
  126. package/dist/indexer/codegenIndex.d.ts +3 -0
  127. package/dist/indexer/codegenIndex.d.ts.map +1 -0
  128. package/dist/indexer/codegenIndex.js +17 -0
  129. package/dist/indexer/codegenIndex.js.map +1 -0
  130. package/dist/indexer/data/configs.constants.d.ts +85 -0
  131. package/dist/indexer/data/configs.constants.d.ts.map +1 -0
  132. package/dist/indexer/data/configs.constants.js +136 -0
  133. package/dist/indexer/data/configs.constants.js.map +1 -0
  134. package/dist/indexer/helpers/buildFolderTree.d.ts +2 -0
  135. package/dist/indexer/helpers/buildFolderTree.d.ts.map +1 -0
  136. package/dist/indexer/helpers/buildFolderTree.js +40 -0
  137. package/dist/indexer/helpers/buildFolderTree.js.map +1 -0
  138. package/dist/indexer/plannerIndex.d.ts +3 -0
  139. package/dist/indexer/plannerIndex.d.ts.map +1 -0
  140. package/dist/indexer/plannerIndex.js +20 -0
  141. package/dist/indexer/plannerIndex.js.map +1 -0
  142. package/dist/indexer/projectInfoIndex.d.ts +3 -0
  143. package/dist/indexer/projectInfoIndex.d.ts.map +1 -0
  144. package/dist/indexer/projectInfoIndex.js +257 -0
  145. package/dist/indexer/projectInfoIndex.js.map +1 -0
  146. package/dist/indexer/validatorIndex.d.ts +3 -0
  147. package/dist/indexer/validatorIndex.d.ts.map +1 -0
  148. package/dist/indexer/validatorIndex.js +14 -0
  149. package/dist/indexer/validatorIndex.js.map +1 -0
  150. package/dist/lib/redis.d.ts +3 -0
  151. package/dist/lib/redis.d.ts.map +1 -0
  152. package/dist/lib/redis.js +7 -0
  153. package/dist/lib/redis.js.map +1 -0
  154. package/dist/lib/supabase.d.ts +2 -0
  155. package/dist/lib/supabase.d.ts.map +1 -0
  156. package/dist/lib/supabase.js +4 -0
  157. package/dist/lib/supabase.js.map +1 -0
  158. package/dist/logging/genStatus.service.d.ts +14 -0
  159. package/dist/logging/genStatus.service.d.ts.map +1 -0
  160. package/dist/logging/genStatus.service.js +36 -0
  161. package/dist/logging/genStatus.service.js.map +1 -0
  162. package/dist/logging/logging.utils.d.ts +12 -0
  163. package/dist/logging/logging.utils.d.ts.map +1 -0
  164. package/dist/logging/logging.utils.js +15 -0
  165. package/dist/logging/logging.utils.js.map +1 -0
  166. package/dist/logging/redis.service.d.ts +11 -0
  167. package/dist/logging/redis.service.d.ts.map +1 -0
  168. package/dist/logging/redis.service.js +26 -0
  169. package/dist/logging/redis.service.js.map +1 -0
  170. package/dist/repository/context.repository.d.ts +8 -0
  171. package/dist/repository/context.repository.d.ts.map +1 -0
  172. package/dist/repository/context.repository.js +59 -0
  173. package/dist/repository/context.repository.js.map +1 -0
  174. package/dist/repository/genStatus.repository.d.ts +13 -0
  175. package/dist/repository/genStatus.repository.d.ts.map +1 -0
  176. package/dist/repository/genStatus.repository.js +18 -0
  177. package/dist/repository/genStatus.repository.js.map +1 -0
  178. package/dist/repository/planTasks.repository.d.ts +9 -0
  179. package/dist/repository/planTasks.repository.d.ts.map +1 -0
  180. package/dist/repository/planTasks.repository.js +24 -0
  181. package/dist/repository/planTasks.repository.js.map +1 -0
  182. package/dist/repository/repository.d.ts +5 -0
  183. package/dist/repository/repository.d.ts.map +1 -0
  184. package/dist/repository/repository.js +7 -0
  185. package/dist/repository/repository.js.map +1 -0
  186. package/dist/types/context.types.d.ts +64 -0
  187. package/dist/types/context.types.d.ts.map +1 -0
  188. package/dist/types/context.types.js +55 -0
  189. package/dist/types/context.types.js.map +1 -0
  190. package/dist/types/events.d.ts +16 -0
  191. package/dist/types/events.d.ts.map +1 -0
  192. package/dist/types/events.js +14 -0
  193. package/dist/types/events.js.map +1 -0
  194. package/dist/types/index/configs.types.d.ts +28 -0
  195. package/dist/types/index/configs.types.d.ts.map +1 -0
  196. package/dist/types/index/configs.types.js +2 -0
  197. package/dist/types/index/configs.types.js.map +1 -0
  198. package/dist/types/index/conventions.types.d.ts +40 -0
  199. package/dist/types/index/conventions.types.d.ts.map +1 -0
  200. package/dist/types/index/conventions.types.js +2 -0
  201. package/dist/types/index/conventions.types.js.map +1 -0
  202. package/dist/types/index/index.types.d.ts +16 -0
  203. package/dist/types/index/index.types.d.ts.map +1 -0
  204. package/dist/types/index/index.types.js +2 -0
  205. package/dist/types/index/index.types.js.map +1 -0
  206. package/dist/types/index/indexing.types.d.ts +9 -0
  207. package/dist/types/index/indexing.types.d.ts.map +1 -0
  208. package/dist/types/index/indexing.types.js +2 -0
  209. package/dist/types/index/indexing.types.js.map +1 -0
  210. package/dist/types/projectInfo.types.d.ts +16 -0
  211. package/dist/types/projectInfo.types.d.ts.map +1 -0
  212. package/dist/types/projectInfo.types.js +2 -0
  213. package/dist/types/projectInfo.types.js.map +1 -0
  214. package/dist/types/updatePlan.types.d.ts +34 -0
  215. package/dist/types/updatePlan.types.d.ts.map +1 -0
  216. package/dist/types/updatePlan.types.js +18 -0
  217. package/dist/types/updatePlan.types.js.map +1 -0
  218. package/dist/utils/utils.d.ts +2 -0
  219. package/dist/utils/utils.d.ts.map +1 -0
  220. package/dist/utils/utils.js +6 -0
  221. package/dist/utils/utils.js.map +1 -0
  222. package/dist/utils/workspace.d.ts +13 -0
  223. package/dist/utils/workspace.d.ts.map +1 -0
  224. package/dist/utils/workspace.js +92 -0
  225. package/dist/utils/workspace.js.map +1 -0
  226. package/package.json +58 -0
package/README.md ADDED
@@ -0,0 +1,8 @@
1
+ # qwintly-core
2
+
3
+ A shared package consisting of
4
+ 1. Shared AI tools
5
+ 2. Project indexer
6
+ 3. Status logging
7
+
8
+ These components are used in qwintly website generator project
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/ai/ai.ts"],"names":[],"mappings":""}
package/dist/ai/ai.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.js","sourceRoot":"","sources":["../../src/ai/ai.ts"],"names":[],"mappings":"","sourcesContent":[""]}
@@ -0,0 +1,15 @@
1
+ import { FunctionCallingConfigMode, GoogleGenAI, Tool } from "@google/genai";
2
+ import type { ZodSchema } from "zod";
3
+ type AIResponseOptions = {
4
+ tools?: Tool[];
5
+ schema?: ZodSchema;
6
+ toolCallingMode?: FunctionCallingConfigMode;
7
+ };
8
+ export declare class GenerateGeminiReponse {
9
+ gemini: GoogleGenAI;
10
+ model: string;
11
+ constructor(geminiApiKey: string, model?: string);
12
+ aiResponse(request: unknown, options?: AIResponseOptions): Promise<import("@google/genai").GenerateContentResponse>;
13
+ }
14
+ export {};
15
+ //# sourceMappingURL=gemini.client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.client.d.ts","sourceRoot":"","sources":["../../../src/ai/generate/gemini.client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EAEzB,WAAW,EACX,IAAI,EACL,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAKrC,KAAK,iBAAiB,GAAG;IACvB,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,eAAe,CAAC,EAAE,yBAAyB,CAAC;CAC7C,CAAC;AAEF,qBAAa,qBAAqB;IACzB,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,MAAM,CAAiB;gBAEzB,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAOnC,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,GAAE,iBAAsB;CAmC1E"}
@@ -0,0 +1,39 @@
1
+ import { FunctionCallingConfigMode, GoogleGenAI, } from "@google/genai";
2
+ import { zodToJsonSchema } from "zod-to-json-schema";
3
+ const DEFAULT_MODEL = "gemini-2.5-flash-lite";
4
+ export class GenerateGeminiReponse {
5
+ constructor(geminiApiKey, model) {
6
+ this.model = DEFAULT_MODEL;
7
+ this.gemini = new GoogleGenAI({ apiKey: geminiApiKey });
8
+ if (model) {
9
+ this.model = model;
10
+ }
11
+ }
12
+ async aiResponse(request, options = {}) {
13
+ const { tools, schema, toolCallingMode = FunctionCallingConfigMode.AUTO, } = options;
14
+ const config = {};
15
+ if (tools && tools.length > 0) {
16
+ config.tools = tools;
17
+ config.toolConfig = {
18
+ functionCallingConfig: {
19
+ mode: toolCallingMode,
20
+ },
21
+ };
22
+ }
23
+ if (schema) {
24
+ config.responseMimeType = "application/json";
25
+ config.responseJsonSchema = zodToJsonSchema(schema);
26
+ }
27
+ try {
28
+ return await this.gemini.models.generateContent({
29
+ model: this.model,
30
+ contents: request,
31
+ ...(Object.keys(config).length > 0 && { config }),
32
+ });
33
+ }
34
+ catch (err) {
35
+ throw new Error(`AI generation failed: ${err?.message || "Unknown error"}`);
36
+ }
37
+ }
38
+ }
39
+ //# sourceMappingURL=gemini.client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.client.js","sourceRoot":"","sources":["../../../src/ai/generate/gemini.client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EAEzB,WAAW,GAEZ,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,aAAa,GAAG,uBAAuB,CAAC;AAQ9C,MAAM,OAAO,qBAAqB;IAIhC,YAAY,YAAoB,EAAE,KAAc;QAFzC,UAAK,GAAW,aAAa,CAAC;QAGnC,IAAI,CAAC,MAAM,GAAG,IAAI,WAAW,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;QACxD,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACrB,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,UAAU,CAAC,OAAgB,EAAE,UAA6B,EAAE;QACvE,MAAM,EACJ,KAAK,EACL,MAAM,EACN,eAAe,GAAG,yBAAyB,CAAC,IAAI,GACjD,GAAG,OAAO,CAAC;QAEZ,MAAM,MAAM,GAA0B,EAAE,CAAC;QAEzC,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;YACrB,MAAM,CAAC,UAAU,GAAG;gBAClB,qBAAqB,EAAE;oBACrB,IAAI,EAAE,eAAe;iBACtB;aACF,CAAC;QACJ,CAAC;QAED,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,gBAAgB,GAAG,kBAAkB,CAAC;YAC7C,MAAM,CAAC,kBAAkB,GAAG,eAAe,CAAC,MAAa,CAAC,CAAC;QAC7D,CAAC;QAED,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC;gBAC9C,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,QAAQ,EAAE,OAAc;gBACxB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;aAClD,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CACb,yBAAyB,GAAG,EAAE,OAAO,IAAI,eAAe,EAAE,CAC3D,CAAC;QACJ,CAAC;IACH,CAAC;CACF","sourcesContent":["import {\n FunctionCallingConfigMode,\n GenerateContentConfig,\n GoogleGenAI,\n Tool,\n} from \"@google/genai\";\nimport type { ZodSchema } from \"zod\";\nimport { zodToJsonSchema } from \"zod-to-json-schema\";\n\nconst DEFAULT_MODEL = \"gemini-2.5-flash-lite\";\n\ntype AIResponseOptions = {\n tools?: Tool[];\n schema?: ZodSchema;\n toolCallingMode?: FunctionCallingConfigMode;\n};\n\nexport class GenerateGeminiReponse {\n public gemini: GoogleGenAI;\n public model: string = DEFAULT_MODEL;\n\n constructor(geminiApiKey: string, model?: string) {\n this.gemini = new GoogleGenAI({ apiKey: geminiApiKey });\n if (model) {\n this.model = model;\n }\n }\n\n public async aiResponse(request: unknown, options: AIResponseOptions = {}) {\n const {\n tools,\n schema,\n toolCallingMode = FunctionCallingConfigMode.AUTO,\n } = options;\n\n const config: GenerateContentConfig = {};\n\n if (tools && tools.length > 0) {\n config.tools = tools;\n config.toolConfig = {\n functionCallingConfig: {\n mode: toolCallingMode,\n },\n };\n }\n\n if (schema) {\n config.responseMimeType = \"application/json\";\n config.responseJsonSchema = zodToJsonSchema(schema as any);\n }\n\n try {\n return await this.gemini.models.generateContent({\n model: this.model,\n contents: request as any,\n ...(Object.keys(config).length > 0 && { config }),\n });\n } catch (err: any) {\n throw new Error(\n `AI generation failed: ${err?.message || \"Unknown error\"}`,\n );\n }\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import { GenerateGeminiReponse } from "./gemini.client.js";
2
+ export declare const getClient: (provider: string, apiKey: string, model?: string) => GenerateGeminiReponse;
3
+ //# sourceMappingURL=generateClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateClient.d.ts","sourceRoot":"","sources":["../../../src/ai/generate/generateClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,eAAO,MAAM,SAAS,GACpB,UAAU,MAAM,EAChB,QAAQ,MAAM,EACd,QAAQ,MAAM,0BAMf,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { GenerateGeminiReponse } from "./gemini.client.js";
2
+ export const getClient = (provider, apiKey, model) => {
3
+ if (provider === "gemini") {
4
+ return new GenerateGeminiReponse(apiKey, model);
5
+ }
6
+ throw new Error(`Unknown provider: ${provider}`);
7
+ };
8
+ //# sourceMappingURL=generateClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateClient.js","sourceRoot":"","sources":["../../../src/ai/generate/generateClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,QAAgB,EAChB,MAAc,EACd,KAAc,EACd,EAAE;IACF,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO,IAAI,qBAAqB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAClD,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,EAAE,CAAC,CAAC;AACnD,CAAC,CAAC","sourcesContent":["import { GenerateGeminiReponse } from \"./gemini.client.js\";\r\n\r\nexport const getClient = (\r\n provider: string,\r\n apiKey: string,\r\n model?: string,\r\n) => {\r\n if (provider === \"gemini\") {\r\n return new GenerateGeminiReponse(apiKey, model);\r\n }\r\n throw new Error(`Unknown provider: ${provider}`);\r\n};\r\n"]}
@@ -0,0 +1,33 @@
1
+ export type ToolEvent = {
2
+ name: string;
3
+ summary: string;
4
+ };
5
+ export type ToolLoopContextPolicy = {
6
+ readFileDefaultMaxLines?: number;
7
+ tailMessages?: number;
8
+ maxModelChars?: number;
9
+ logApproxModelChars?: boolean;
10
+ };
11
+ export declare const DEFAULT_CONTEXT_POLICY: Required<ToolLoopContextPolicy>;
12
+ export declare const redactFunctionCallArgs: (name: string, args: Record<string, unknown>) => Record<string, unknown>;
13
+ export declare const compactForModel: (input: {
14
+ initialCount: number;
15
+ modelContents: any[];
16
+ toolEvents: ToolEvent[];
17
+ policy: Required<ToolLoopContextPolicy>;
18
+ }) => any[];
19
+ export declare const normalizeReadFileArgs: (args: Record<string, unknown>, maxLines: number) => {
20
+ effectiveArgs: {
21
+ start_line: number;
22
+ end_line: number;
23
+ };
24
+ start: number;
25
+ end: number;
26
+ wasCapped: boolean;
27
+ };
28
+ export declare const getApplyPatchEventMeta: (args: Record<string, unknown>) => {
29
+ chars: number;
30
+ sha256: string;
31
+ files: string[];
32
+ };
33
+ //# sourceMappingURL=toolLoopContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolLoopContext.d.ts","sourceRoot":"","sources":["../../../src/ai/toolLoop/toolLoopContext.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,qBAAqB,CAKlE,CAAC;AAuBF,eAAO,MAAM,sBAAsB,GACjC,MAAM,MAAM,EACZ,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,4BAqB9B,CAAC;AAiBF,eAAO,MAAM,eAAe,GAAI,OAAO;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,GAAG,EAAE,CAAC;IACrB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,CAAC;CACzC,UA8BA,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,UAAU,MAAM;;;;;;;;CAmCjB,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;CAOnE,CAAC"}
@@ -0,0 +1,112 @@
1
+ import crypto from "node:crypto";
2
+ export const DEFAULT_CONTEXT_POLICY = {
3
+ readFileDefaultMaxLines: 200,
4
+ tailMessages: 12,
5
+ maxModelChars: 120000,
6
+ logApproxModelChars: false,
7
+ };
8
+ const sha256Hex = (value) => crypto.createHash("sha256").update(value, "utf8").digest("hex");
9
+ const extractPatchFiles = (patchString) => {
10
+ const lines = patchString.replace(/\r\n/g, "\n").split("\n");
11
+ const files = new Set();
12
+ for (const line of lines) {
13
+ const match = /^\*\*\* (Update File|Add File|Delete File):\s+(.+)$/.exec(line) ??
14
+ /^\*\*\* Move to:\s+(.+)$/.exec(line);
15
+ if (!match)
16
+ continue;
17
+ const filePath = (match[2] ?? match[1] ?? "").trim();
18
+ if (filePath)
19
+ files.add(filePath);
20
+ }
21
+ return [...files];
22
+ };
23
+ export const redactFunctionCallArgs = (name, args) => {
24
+ if (name !== "apply_patch")
25
+ return args;
26
+ const patch = typeof args.patch_string === "string" ? args.patch_string : "";
27
+ if (!patch) {
28
+ return {
29
+ ...args,
30
+ patch_string: { omitted: true, chars: 0, sha256: sha256Hex(""), files: [] },
31
+ };
32
+ }
33
+ return {
34
+ ...args,
35
+ patch_string: {
36
+ omitted: true,
37
+ chars: patch.length,
38
+ sha256: sha256Hex(patch),
39
+ files: extractPatchFiles(patch),
40
+ },
41
+ };
42
+ };
43
+ const isMemoryMessage = (item) => {
44
+ const text = item?.parts?.[0]?.text;
45
+ return (item?.role === "model" &&
46
+ typeof text === "string" &&
47
+ text.startsWith("MEMORY (tool trace summary):"));
48
+ };
49
+ const buildMemoryText = (events) => {
50
+ if (events.length === 0)
51
+ return "";
52
+ const lines = events.map((e) => `- ${e.summary}`);
53
+ return `MEMORY (tool trace summary):\n${lines.join("\n")}`;
54
+ };
55
+ export const compactForModel = (input) => {
56
+ const { initialCount, modelContents, toolEvents, policy } = input;
57
+ const withoutOldMemory = modelContents.filter((c) => !isMemoryMessage(c));
58
+ const tailStart = Math.max(initialCount, withoutOldMemory.length - policy.tailMessages);
59
+ const initial = withoutOldMemory.slice(0, initialCount);
60
+ const tail = withoutOldMemory.slice(tailStart);
61
+ const memoryText = buildMemoryText(toolEvents);
62
+ const memory = memoryText
63
+ ? [{ role: "model", parts: [{ text: memoryText }] }]
64
+ : [];
65
+ let compacted = [...initial, ...memory, ...tail];
66
+ const maxChars = Math.max(10000, policy.maxModelChars);
67
+ while (JSON.stringify(compacted).length > maxChars) {
68
+ const minLen = initial.length + memory.length + 1;
69
+ if (compacted.length <= minLen)
70
+ break;
71
+ compacted = [
72
+ ...initial,
73
+ ...memory,
74
+ ...compacted.slice(initial.length + memory.length + 1),
75
+ ];
76
+ }
77
+ return compacted;
78
+ };
79
+ export const normalizeReadFileArgs = (args, maxLines) => {
80
+ const requestedStart = args.start_line === undefined || args.start_line === null
81
+ ? 1
82
+ : Number(args.start_line);
83
+ const requestedEnd = args.end_line === undefined || args.end_line === null
84
+ ? undefined
85
+ : Number(args.end_line);
86
+ const start = Number.isFinite(requestedStart) && requestedStart > 0 ? requestedStart : 1;
87
+ const cap = Math.max(1, Math.floor(maxLines));
88
+ const desiredEnd = requestedEnd === undefined ||
89
+ !Number.isFinite(requestedEnd) ||
90
+ requestedEnd < start
91
+ ? start + cap - 1
92
+ : requestedEnd;
93
+ const cappedEnd = Math.min(desiredEnd, start + cap - 1);
94
+ const wasCapped = requestedEnd === undefined ||
95
+ desiredEnd !== requestedEnd ||
96
+ cappedEnd !== desiredEnd;
97
+ return {
98
+ effectiveArgs: { ...args, start_line: start, end_line: cappedEnd },
99
+ start,
100
+ end: cappedEnd,
101
+ wasCapped,
102
+ };
103
+ };
104
+ export const getApplyPatchEventMeta = (args) => {
105
+ const patch = typeof args.patch_string === "string" ? args.patch_string : "";
106
+ return {
107
+ chars: patch.length,
108
+ sha256: sha256Hex(patch),
109
+ files: extractPatchFiles(patch),
110
+ };
111
+ };
112
+ //# sourceMappingURL=toolLoopContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolLoopContext.js","sourceRoot":"","sources":["../../../src/ai/toolLoop/toolLoopContext.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from \"node:crypto\";\n\nexport type ToolEvent = {\n name: string;\n summary: string;\n};\n\nexport type ToolLoopContextPolicy = {\n readFileDefaultMaxLines?: number;\n tailMessages?: number;\n maxModelChars?: number;\n logApproxModelChars?: boolean;\n};\n\nexport const DEFAULT_CONTEXT_POLICY: Required<ToolLoopContextPolicy> = {\n readFileDefaultMaxLines: 200,\n tailMessages: 12,\n maxModelChars: 120_000,\n logApproxModelChars: false,\n};\n\nconst sha256Hex = (value: string) =>\n crypto.createHash(\"sha256\").update(value, \"utf8\").digest(\"hex\");\n\nconst extractPatchFiles = (patchString: string): string[] => {\n const lines = patchString.replace(/\\r\\n/g, \"\\n\").split(\"\\n\");\n const files = new Set<string>();\n\n for (const line of lines) {\n const match =\n /^\\*\\*\\* (Update File|Add File|Delete File):\\s+(.+)$/.exec(line) ??\n /^\\*\\*\\* Move to:\\s+(.+)$/.exec(line);\n\n if (!match) continue;\n\n const filePath = (match[2] ?? match[1] ?? \"\").trim();\n if (filePath) files.add(filePath);\n }\n\n return [...files];\n};\n\nexport const redactFunctionCallArgs = (\n name: string,\n args: Record<string, unknown>,\n) => {\n if (name !== \"apply_patch\") return args;\n\n const patch = typeof args.patch_string === \"string\" ? args.patch_string : \"\";\n if (!patch) {\n return {\n ...args,\n patch_string: { omitted: true, chars: 0, sha256: sha256Hex(\"\"), files: [] },\n };\n }\n\n return {\n ...args,\n patch_string: {\n omitted: true,\n chars: patch.length,\n sha256: sha256Hex(patch),\n files: extractPatchFiles(patch),\n },\n };\n};\n\nconst isMemoryMessage = (item: any) => {\n const text = item?.parts?.[0]?.text;\n return (\n item?.role === \"model\" &&\n typeof text === \"string\" &&\n text.startsWith(\"MEMORY (tool trace summary):\")\n );\n};\n\nconst buildMemoryText = (events: ToolEvent[]) => {\n if (events.length === 0) return \"\";\n const lines = events.map((e) => `- ${e.summary}`);\n return `MEMORY (tool trace summary):\\n${lines.join(\"\\n\")}`;\n};\n\nexport const compactForModel = (input: {\n initialCount: number;\n modelContents: any[];\n toolEvents: ToolEvent[];\n policy: Required<ToolLoopContextPolicy>;\n}) => {\n const { initialCount, modelContents, toolEvents, policy } = input;\n\n const withoutOldMemory = modelContents.filter((c) => !isMemoryMessage(c));\n const tailStart = Math.max(\n initialCount,\n withoutOldMemory.length - policy.tailMessages,\n );\n\n const initial = withoutOldMemory.slice(0, initialCount);\n const tail = withoutOldMemory.slice(tailStart);\n const memoryText = buildMemoryText(toolEvents);\n const memory = memoryText\n ? [{ role: \"model\", parts: [{ text: memoryText }] }]\n : [];\n\n let compacted = [...initial, ...memory, ...tail];\n\n const maxChars = Math.max(10_000, policy.maxModelChars);\n while (JSON.stringify(compacted).length > maxChars) {\n const minLen = initial.length + memory.length + 1;\n if (compacted.length <= minLen) break;\n compacted = [\n ...initial,\n ...memory,\n ...compacted.slice(initial.length + memory.length + 1),\n ];\n }\n\n return compacted;\n};\n\nexport const normalizeReadFileArgs = (\n args: Record<string, unknown>,\n maxLines: number,\n) => {\n const requestedStart =\n args.start_line === undefined || args.start_line === null\n ? 1\n : Number(args.start_line);\n\n const requestedEnd =\n args.end_line === undefined || args.end_line === null\n ? undefined\n : Number(args.end_line);\n\n const start =\n Number.isFinite(requestedStart) && requestedStart > 0 ? requestedStart : 1;\n const cap = Math.max(1, Math.floor(maxLines));\n\n const desiredEnd =\n requestedEnd === undefined ||\n !Number.isFinite(requestedEnd) ||\n requestedEnd < start\n ? start + cap - 1\n : requestedEnd;\n\n const cappedEnd = Math.min(desiredEnd, start + cap - 1);\n const wasCapped =\n requestedEnd === undefined ||\n desiredEnd !== requestedEnd ||\n cappedEnd !== desiredEnd;\n\n return {\n effectiveArgs: { ...args, start_line: start, end_line: cappedEnd },\n start,\n end: cappedEnd,\n wasCapped,\n };\n};\n\nexport const getApplyPatchEventMeta = (args: Record<string, unknown>) => {\n const patch = typeof args.patch_string === \"string\" ? args.patch_string : \"\";\n return {\n chars: patch.length,\n sha256: sha256Hex(patch),\n files: extractPatchFiles(patch),\n };\n};\n\n"]}
@@ -0,0 +1,43 @@
1
+ import { FunctionCallingConfigMode, Tool } from "@google/genai";
2
+ import { EventType } from "../../types/events.js";
3
+ import { ToolLoopContextPolicy } from "./toolLoopContext.js";
4
+ export type ToolHandler = (args: Record<string, unknown>) => Promise<unknown>;
5
+ export type ToolLoopResult = {
6
+ contents: any[];
7
+ modelContents: any[];
8
+ finalText: string;
9
+ steps: number;
10
+ terminalCall?: {
11
+ name: string;
12
+ args: Record<string, unknown>;
13
+ response: unknown;
14
+ };
15
+ };
16
+ export type Logger = (message: string, eventType: EventType) => Promise<void>;
17
+ export type AiCallResponse = {
18
+ functionCalls?: any[];
19
+ text?: string;
20
+ };
21
+ export type AiCallFn = (request: unknown, options: {
22
+ tools?: Tool[];
23
+ model?: string;
24
+ toolCallingMode?: FunctionCallingConfigMode;
25
+ }) => Promise<AiCallResponse>;
26
+ export type RunToolLoopOptions = {
27
+ initialContents: any[];
28
+ tools: Tool[];
29
+ handlers: Record<string, ToolHandler>;
30
+ maxSteps?: number;
31
+ toolCallingMode?: FunctionCallingConfigMode;
32
+ terminalToolNames?: string[];
33
+ keepFullTrace?: boolean;
34
+ contextPolicy?: ToolLoopContextPolicy;
35
+ aiCall: AiCallFn;
36
+ logger: Logger;
37
+ applyPatchAutoRetryMax?: number;
38
+ aiCallAutoRetryMax?: number;
39
+ aiCallAutoRetryBaseMs?: number;
40
+ aiCallAutoRetryMaxMs?: number;
41
+ };
42
+ export declare function runToolLoop(options: RunToolLoopOptions): Promise<ToolLoopResult>;
43
+ //# sourceMappingURL=toolLoopRunner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolLoopRunner.d.ts","sourceRoot":"","sources":["../../../src/ai/toolLoop/toolLoopRunner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAe,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAML,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAQ9B,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE9E,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,GAAG,EAAE,CAAC;IAChB,aAAa,EAAE,GAAG,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC9B,QAAQ,EAAE,OAAO,CAAC;KACnB,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9E,MAAM,MAAM,cAAc,GAAG;IAC3B,aAAa,CAAC,EAAE,GAAG,EAAE,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,CACrB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE;IACP,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,yBAAyB,CAAC;CAC7C,KACE,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,eAAe,EAAE,GAAG,EAAE,CAAC;IACvB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,yBAAyB,CAAC;IAC5C,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,qBAAqB,CAAC;IACtC,MAAM,EAAE,QAAQ,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF,wBAAsB,WAAW,CAC/B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,cAAc,CAAC,CA2RzB"}
@@ -0,0 +1,227 @@
1
+ import { FunctionCallingConfigMode } from "@google/genai";
2
+ import { EVENT_TYPES } from "../../types/events.js";
3
+ import { compactForModel, DEFAULT_CONTEXT_POLICY, normalizeReadFileArgs, redactFunctionCallArgs, } from "./toolLoopContext.js";
4
+ import { aiCallWithRetry, buildToolStatusMessage, recordToolEvent, serializeError, } from "./toolLoopRunnerUtils.js";
5
+ export async function runToolLoop(options) {
6
+ const { initialContents, tools, handlers, maxSteps = 30, toolCallingMode = FunctionCallingConfigMode.ANY, terminalToolNames = [], keepFullTrace = true, contextPolicy, aiCall, logger, applyPatchAutoRetryMax = 2, aiCallAutoRetryMax = 3, // must have it to try 3 times as gemini errors a lot due to high demand sometimes
7
+ aiCallAutoRetryBaseMs = 400, aiCallAutoRetryMaxMs = 10000, } = options;
8
+ if (typeof aiCall !== "function") {
9
+ throw new Error("Tool loop: aiCall is required.");
10
+ }
11
+ const policy = {
12
+ ...DEFAULT_CONTEXT_POLICY,
13
+ ...(contextPolicy ?? {}),
14
+ };
15
+ const toolEvents = [];
16
+ let applyPatchRetryCount = 0;
17
+ const fullTraceContents = keepFullTrace ? [...initialContents] : [];
18
+ let modelContents = [...initialContents];
19
+ const pushBoth = (fullItem, modelItem) => {
20
+ if (keepFullTrace)
21
+ fullTraceContents.push(fullItem);
22
+ modelContents.push(modelItem);
23
+ };
24
+ const pushModelOnly = (modelItem) => {
25
+ modelContents.push(modelItem);
26
+ };
27
+ for (let step = 0; step < maxSteps; step++) {
28
+ modelContents = compactForModel({
29
+ initialCount: initialContents.length,
30
+ modelContents,
31
+ toolEvents,
32
+ policy,
33
+ });
34
+ if (policy.logApproxModelChars) {
35
+ const approxChars = JSON.stringify(modelContents).length;
36
+ console.log("Tool loop: approx model chars", {
37
+ approxChars,
38
+ step: step + 1,
39
+ });
40
+ }
41
+ let response;
42
+ response = await aiCallWithRetry({
43
+ aiCall,
44
+ request: modelContents,
45
+ options: { tools, toolCallingMode },
46
+ retryMax: aiCallAutoRetryMax,
47
+ retryBaseMs: aiCallAutoRetryBaseMs,
48
+ retryMaxMs: aiCallAutoRetryMaxMs,
49
+ step: step + 1,
50
+ logger,
51
+ });
52
+ const functionCalls = response.functionCalls ?? [];
53
+ if (functionCalls.length === 0) {
54
+ return {
55
+ contents: keepFullTrace ? fullTraceContents : modelContents,
56
+ modelContents,
57
+ finalText: (response.text ?? "").trim(),
58
+ steps: step + 1,
59
+ };
60
+ }
61
+ for (const call of functionCalls) {
62
+ const name = call.name?.toString() ?? "";
63
+ const args = (call.args ?? {});
64
+ if (!name) {
65
+ throw new Error("Tool loop: function call missing name.");
66
+ }
67
+ const handler = handlers[name];
68
+ const handlerMissingResult = !handler
69
+ ? {
70
+ success: false,
71
+ error: `No handler registered for "${name}".`,
72
+ error_detail: {
73
+ name: "MissingToolHandlerError",
74
+ message: `No handler registered for "${name}".`,
75
+ },
76
+ }
77
+ : null;
78
+ let effectiveArgs = args;
79
+ let readFileMeta = null;
80
+ if (name === "read_file") {
81
+ const normalized = normalizeReadFileArgs(effectiveArgs, policy.readFileDefaultMaxLines);
82
+ effectiveArgs = normalized.effectiveArgs;
83
+ readFileMeta = {
84
+ start: normalized.start,
85
+ end: normalized.end,
86
+ wasCapped: normalized.wasCapped,
87
+ };
88
+ }
89
+ logger(buildToolStatusMessage(name, effectiveArgs, readFileMeta), EVENT_TYPES.STEP_STARTED);
90
+ const modelArgs = redactFunctionCallArgs(name, effectiveArgs);
91
+ const assistantFull = {
92
+ role: "model",
93
+ parts: [
94
+ {
95
+ functionCall: {
96
+ name,
97
+ args: effectiveArgs,
98
+ },
99
+ },
100
+ ],
101
+ };
102
+ const assistantModel = {
103
+ role: "model",
104
+ parts: [
105
+ {
106
+ functionCall: {
107
+ name,
108
+ args: modelArgs,
109
+ },
110
+ },
111
+ ],
112
+ };
113
+ if (keepFullTrace) {
114
+ pushBoth(assistantFull, assistantModel);
115
+ }
116
+ else {
117
+ pushModelOnly(assistantModel);
118
+ }
119
+ let toolResultRaw;
120
+ if (handlerMissingResult) {
121
+ toolResultRaw = handlerMissingResult;
122
+ }
123
+ else {
124
+ try {
125
+ toolResultRaw = await handler(effectiveArgs);
126
+ }
127
+ catch (err) {
128
+ logger(`AI tool: ${name} failed`, EVENT_TYPES.STEP_ERROR);
129
+ console.error("Tool loop: handler threw", err, {
130
+ tool: name,
131
+ step: step + 1,
132
+ });
133
+ toolResultRaw = {
134
+ success: false,
135
+ error: err instanceof Error ? err.message : String(err),
136
+ error_detail: serializeError(err),
137
+ note: "Tool handler threw. Inspect error_detail and retry with corrected args or a different approach.",
138
+ };
139
+ }
140
+ }
141
+ let toolResult = toolResultRaw;
142
+ if (name === "read_file" && readFileMeta) {
143
+ const path = String(effectiveArgs.path ?? "");
144
+ const rawContent = typeof toolResultRaw?.content === "string"
145
+ ? String(toolResultRaw.content)
146
+ : typeof toolResultRaw === "string"
147
+ ? toolResultRaw
148
+ : JSON.stringify(toolResultRaw ?? null);
149
+ toolResult = {
150
+ path,
151
+ start_line: readFileMeta.start,
152
+ end_line: readFileMeta.end,
153
+ truncated: readFileMeta.wasCapped,
154
+ content: rawContent,
155
+ note: readFileMeta.wasCapped
156
+ ? `Capped to ${policy.readFileDefaultMaxLines} lines. Request more with start_line/end_line.`
157
+ : undefined,
158
+ };
159
+ }
160
+ const responseFull = {
161
+ role: "user",
162
+ parts: [
163
+ {
164
+ functionResponse: {
165
+ name,
166
+ response: toolResult,
167
+ },
168
+ },
169
+ ],
170
+ };
171
+ if (keepFullTrace) {
172
+ fullTraceContents.push(responseFull);
173
+ }
174
+ modelContents.push(responseFull);
175
+ if (name === "apply_patch" &&
176
+ toolResult?.success === false &&
177
+ applyPatchAutoRetryMax > 0 &&
178
+ applyPatchRetryCount < applyPatchAutoRetryMax) {
179
+ applyPatchRetryCount += 1;
180
+ const error = String(toolResult?.error ?? "unknown error");
181
+ const debugFiles = Array.isArray(toolResult?.debug?.files)
182
+ ? toolResult.debug.files
183
+ : [];
184
+ const debugText = debugFiles.length > 0
185
+ ? `\n\nFILE SNAPSHOTS (for regenerating the patch):\n${debugFiles
186
+ .slice(0, 3)
187
+ .map((f) => `--- ${String(f.path ?? "")} ---\n${String(f.head ?? "")}\n--- end ---`)
188
+ .join("\n\n")}`
189
+ : "";
190
+ const retryInstruction = {
191
+ role: "user",
192
+ parts: [
193
+ {
194
+ text: `apply_patch failed (attempt ${applyPatchRetryCount}/${applyPatchAutoRetryMax}): ${error}\n` +
195
+ `Regenerate a patch that matches the current file contents. ` +
196
+ `For large rewrites, prefer write_file(path, content) or Delete+Add instead of Update.` +
197
+ debugText,
198
+ },
199
+ ],
200
+ };
201
+ if (keepFullTrace)
202
+ fullTraceContents.push(retryInstruction);
203
+ modelContents.push(retryInstruction);
204
+ }
205
+ recordToolEvent({
206
+ toolEvents,
207
+ name,
208
+ effectiveArgs,
209
+ modelArgs,
210
+ readFileMeta,
211
+ toolResult,
212
+ toolResultRaw,
213
+ });
214
+ if (terminalToolNames.includes(name)) {
215
+ return {
216
+ contents: keepFullTrace ? fullTraceContents : modelContents,
217
+ modelContents,
218
+ finalText: "",
219
+ steps: step + 1,
220
+ terminalCall: { name, args: effectiveArgs, response: toolResultRaw },
221
+ };
222
+ }
223
+ }
224
+ }
225
+ throw new Error(`Tool loop: max steps reached (${maxSteps}).`);
226
+ }
227
+ //# sourceMappingURL=toolLoopRunner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolLoopRunner.js","sourceRoot":"","sources":["../../../src/ai/toolLoop/toolLoopRunner.ts"],"names":[],"mappings":"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","sourcesContent":["import { FunctionCallingConfigMode, Tool } from \"@google/genai\";\nimport { EVENT_TYPES, EventType } from \"../../types/events.js\";\nimport {\n compactForModel,\n DEFAULT_CONTEXT_POLICY,\n normalizeReadFileArgs,\n redactFunctionCallArgs,\n ToolEvent,\n ToolLoopContextPolicy,\n} from \"./toolLoopContext.js\";\nimport {\n aiCallWithRetry,\n buildToolStatusMessage,\n recordToolEvent,\n serializeError,\n} from \"./toolLoopRunnerUtils.js\";\n\nexport type ToolHandler = (args: Record<string, unknown>) => Promise<unknown>;\n\nexport type ToolLoopResult = {\n contents: any[];\n modelContents: any[];\n finalText: string;\n steps: number;\n terminalCall?: {\n name: string;\n args: Record<string, unknown>;\n response: unknown;\n };\n};\n\nexport type Logger = (message: string, eventType: EventType) => Promise<void>;\n\nexport type AiCallResponse = {\n functionCalls?: any[];\n text?: string;\n};\n\nexport type AiCallFn = (\n request: unknown,\n options: {\n tools?: Tool[];\n model?: string;\n toolCallingMode?: FunctionCallingConfigMode;\n },\n) => Promise<AiCallResponse>;\n\nexport type RunToolLoopOptions = {\n initialContents: any[];\n tools: Tool[];\n handlers: Record<string, ToolHandler>;\n maxSteps?: number;\n toolCallingMode?: FunctionCallingConfigMode;\n terminalToolNames?: string[];\n keepFullTrace?: boolean;\n contextPolicy?: ToolLoopContextPolicy;\n aiCall: AiCallFn;\n logger: Logger;\n applyPatchAutoRetryMax?: number;\n aiCallAutoRetryMax?: number;\n aiCallAutoRetryBaseMs?: number;\n aiCallAutoRetryMaxMs?: number;\n};\n\nexport async function runToolLoop(\n options: RunToolLoopOptions,\n): Promise<ToolLoopResult> {\n const {\n initialContents,\n tools,\n handlers,\n maxSteps = 30,\n toolCallingMode = FunctionCallingConfigMode.ANY,\n terminalToolNames = [],\n keepFullTrace = true,\n contextPolicy,\n aiCall,\n logger,\n applyPatchAutoRetryMax = 2,\n aiCallAutoRetryMax = 3, // must have it to try 3 times as gemini errors a lot due to high demand sometimes\n aiCallAutoRetryBaseMs = 400,\n aiCallAutoRetryMaxMs = 10_000,\n } = options;\n\n if (typeof aiCall !== \"function\") {\n throw new Error(\"Tool loop: aiCall is required.\");\n }\n\n const policy: Required<ToolLoopContextPolicy> = {\n ...DEFAULT_CONTEXT_POLICY,\n ...(contextPolicy ?? {}),\n };\n\n const toolEvents: ToolEvent[] = [];\n let applyPatchRetryCount = 0;\n\n const fullTraceContents: any[] = keepFullTrace ? [...initialContents] : [];\n let modelContents: any[] = [...initialContents];\n const pushBoth = (fullItem: any, modelItem: any) => {\n if (keepFullTrace) fullTraceContents.push(fullItem);\n modelContents.push(modelItem);\n };\n const pushModelOnly = (modelItem: any) => {\n modelContents.push(modelItem);\n };\n\n for (let step = 0; step < maxSteps; step++) {\n modelContents = compactForModel({\n initialCount: initialContents.length,\n modelContents,\n toolEvents,\n policy,\n });\n\n if (policy.logApproxModelChars) {\n const approxChars = JSON.stringify(modelContents).length;\n console.log(\"Tool loop: approx model chars\", {\n approxChars,\n step: step + 1,\n });\n }\n\n let response: Awaited<ReturnType<AiCallFn>>;\n response = await aiCallWithRetry({\n aiCall,\n request: modelContents,\n options: { tools, toolCallingMode },\n retryMax: aiCallAutoRetryMax,\n retryBaseMs: aiCallAutoRetryBaseMs,\n retryMaxMs: aiCallAutoRetryMaxMs,\n step: step + 1,\n logger,\n });\n\n const functionCalls = response.functionCalls ?? [];\n if (functionCalls.length === 0) {\n return {\n contents: keepFullTrace ? fullTraceContents : modelContents,\n modelContents,\n finalText: (response.text ?? \"\").trim(),\n steps: step + 1,\n };\n }\n\n for (const call of functionCalls) {\n const name = call.name?.toString() ?? \"\";\n const args = (call.args ?? {}) as Record<string, unknown>;\n\n if (!name) {\n throw new Error(\"Tool loop: function call missing name.\");\n }\n\n const handler = handlers[name];\n const handlerMissingResult = !handler\n ? {\n success: false,\n error: `No handler registered for \"${name}\".`,\n error_detail: {\n name: \"MissingToolHandlerError\",\n message: `No handler registered for \"${name}\".`,\n },\n }\n : null;\n\n let effectiveArgs: Record<string, unknown> = args;\n let readFileMeta: {\n start: number;\n end: number;\n wasCapped: boolean;\n } | null = null;\n if (name === \"read_file\") {\n const normalized = normalizeReadFileArgs(\n effectiveArgs,\n policy.readFileDefaultMaxLines,\n );\n effectiveArgs = normalized.effectiveArgs;\n readFileMeta = {\n start: normalized.start,\n end: normalized.end,\n wasCapped: normalized.wasCapped,\n };\n }\n\n logger(\n buildToolStatusMessage(name, effectiveArgs, readFileMeta),\n EVENT_TYPES.STEP_STARTED,\n );\n\n const modelArgs = redactFunctionCallArgs(name, effectiveArgs);\n\n const assistantFull = {\n role: \"model\",\n parts: [\n {\n functionCall: {\n name,\n args: effectiveArgs,\n },\n },\n ],\n };\n\n const assistantModel = {\n role: \"model\",\n parts: [\n {\n functionCall: {\n name,\n args: modelArgs,\n },\n },\n ],\n };\n\n if (keepFullTrace) {\n pushBoth(assistantFull, assistantModel);\n } else {\n pushModelOnly(assistantModel);\n }\n\n let toolResultRaw: unknown;\n if (handlerMissingResult) {\n toolResultRaw = handlerMissingResult;\n } else {\n try {\n toolResultRaw = await handler(effectiveArgs);\n } catch (err) {\n logger(`AI tool: ${name} failed`, EVENT_TYPES.STEP_ERROR);\n console.error(\"Tool loop: handler threw\", err, {\n tool: name,\n step: step + 1,\n });\n toolResultRaw = {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n error_detail: serializeError(err),\n note: \"Tool handler threw. Inspect error_detail and retry with corrected args or a different approach.\",\n };\n }\n }\n let toolResult: unknown = toolResultRaw;\n\n if (name === \"read_file\" && readFileMeta) {\n const path = String(effectiveArgs.path ?? \"\");\n const rawContent =\n typeof (toolResultRaw as any)?.content === \"string\"\n ? String((toolResultRaw as any).content)\n : typeof toolResultRaw === \"string\"\n ? toolResultRaw\n : JSON.stringify(toolResultRaw ?? null);\n\n toolResult = {\n path,\n start_line: readFileMeta.start,\n end_line: readFileMeta.end,\n truncated: readFileMeta.wasCapped,\n content: rawContent,\n note: readFileMeta.wasCapped\n ? `Capped to ${policy.readFileDefaultMaxLines} lines. Request more with start_line/end_line.`\n : undefined,\n };\n }\n\n const responseFull = {\n role: \"user\",\n parts: [\n {\n functionResponse: {\n name,\n response: toolResult,\n },\n },\n ],\n };\n\n if (keepFullTrace) {\n fullTraceContents.push(responseFull);\n }\n modelContents.push(responseFull);\n\n if (\n name === \"apply_patch\" &&\n (toolResult as any)?.success === false &&\n applyPatchAutoRetryMax > 0 &&\n applyPatchRetryCount < applyPatchAutoRetryMax\n ) {\n applyPatchRetryCount += 1;\n\n const error = String((toolResult as any)?.error ?? \"unknown error\");\n const debugFiles = Array.isArray((toolResult as any)?.debug?.files)\n ? ((toolResult as any).debug.files as Array<{\n path?: string;\n head?: string;\n }>)\n : [];\n\n const debugText =\n debugFiles.length > 0\n ? `\\n\\nFILE SNAPSHOTS (for regenerating the patch):\\n${debugFiles\n .slice(0, 3)\n .map(\n (f) =>\n `--- ${String(f.path ?? \"\")} ---\\n${String(\n f.head ?? \"\",\n )}\\n--- end ---`,\n )\n .join(\"\\n\\n\")}`\n : \"\";\n\n const retryInstruction = {\n role: \"user\",\n parts: [\n {\n text:\n `apply_patch failed (attempt ${applyPatchRetryCount}/${applyPatchAutoRetryMax}): ${error}\\n` +\n `Regenerate a patch that matches the current file contents. ` +\n `For large rewrites, prefer write_file(path, content) or Delete+Add instead of Update.` +\n debugText,\n },\n ],\n };\n\n if (keepFullTrace) fullTraceContents.push(retryInstruction);\n modelContents.push(retryInstruction);\n }\n\n recordToolEvent({\n toolEvents,\n name,\n effectiveArgs,\n modelArgs,\n readFileMeta,\n toolResult,\n toolResultRaw,\n });\n\n if (terminalToolNames.includes(name)) {\n return {\n contents: keepFullTrace ? fullTraceContents : modelContents,\n modelContents,\n finalText: \"\",\n steps: step + 1,\n terminalCall: { name, args: effectiveArgs, response: toolResultRaw },\n };\n }\n }\n }\n\n throw new Error(`Tool loop: max steps reached (${maxSteps}).`);\n}\n"]}