@botbotgo/runtime 1.0.0

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 (313) hide show
  1. package/.github/workflows/ci.yml +46 -0
  2. package/.github/workflows/release.yml +79 -0
  3. package/README.md +71 -0
  4. package/config/examples/memory.yaml +39 -0
  5. package/config/examples/model.yaml +21 -0
  6. package/config/examples/runtime.yaml +44 -0
  7. package/config/examples/skills.yaml +8 -0
  8. package/config/examples/tool.yaml +16 -0
  9. package/dist/config/index.d.ts +7 -0
  10. package/dist/config/index.d.ts.map +1 -0
  11. package/dist/config/index.js +4 -0
  12. package/dist/config/index.js.map +1 -0
  13. package/dist/config/loader.d.ts +41 -0
  14. package/dist/config/loader.d.ts.map +1 -0
  15. package/dist/config/loader.js +140 -0
  16. package/dist/config/loader.js.map +1 -0
  17. package/dist/config/resolveRuntimeConfig.d.ts +83 -0
  18. package/dist/config/resolveRuntimeConfig.d.ts.map +1 -0
  19. package/dist/config/resolveRuntimeConfig.js +85 -0
  20. package/dist/config/resolveRuntimeConfig.js.map +1 -0
  21. package/dist/config/resources.d.ts +112 -0
  22. package/dist/config/resources.d.ts.map +1 -0
  23. package/dist/config/resources.js +20 -0
  24. package/dist/config/resources.js.map +1 -0
  25. package/dist/config/runtimeConfigLoader.d.ts +28 -0
  26. package/dist/config/runtimeConfigLoader.d.ts.map +1 -0
  27. package/dist/config/runtimeConfigLoader.js +38 -0
  28. package/dist/config/runtimeConfigLoader.js.map +1 -0
  29. package/dist/index.d.ts +9 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +5 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/runtime/agentMiddleware.d.ts +3 -0
  34. package/dist/runtime/agentMiddleware.d.ts.map +1 -0
  35. package/dist/runtime/agentMiddleware.js +2 -0
  36. package/dist/runtime/agentMiddleware.js.map +1 -0
  37. package/dist/runtime/bootstrap/runtimeFactory.d.ts +7 -0
  38. package/dist/runtime/bootstrap/runtimeFactory.d.ts.map +1 -0
  39. package/dist/runtime/bootstrap/runtimeFactory.js +139 -0
  40. package/dist/runtime/bootstrap/runtimeFactory.js.map +1 -0
  41. package/dist/runtime/bootstrap/runtimeModuleInitializer.d.ts +5 -0
  42. package/dist/runtime/bootstrap/runtimeModuleInitializer.d.ts.map +1 -0
  43. package/dist/runtime/bootstrap/runtimeModuleInitializer.js +32 -0
  44. package/dist/runtime/bootstrap/runtimeModuleInitializer.js.map +1 -0
  45. package/dist/runtime/context/agentContext.d.ts +5 -0
  46. package/dist/runtime/context/agentContext.d.ts.map +1 -0
  47. package/dist/runtime/context/agentContext.js +19 -0
  48. package/dist/runtime/context/agentContext.js.map +1 -0
  49. package/dist/runtime/context/globalContext.d.ts +19 -0
  50. package/dist/runtime/context/globalContext.d.ts.map +1 -0
  51. package/dist/runtime/context/globalContext.js +47 -0
  52. package/dist/runtime/context/globalContext.js.map +1 -0
  53. package/dist/runtime/events/eventPublisher.d.ts +15 -0
  54. package/dist/runtime/events/eventPublisher.d.ts.map +1 -0
  55. package/dist/runtime/events/eventPublisher.js +23 -0
  56. package/dist/runtime/events/eventPublisher.js.map +1 -0
  57. package/dist/runtime/execution/agentRunExecutor.d.ts +38 -0
  58. package/dist/runtime/execution/agentRunExecutor.d.ts.map +1 -0
  59. package/dist/runtime/execution/agentRunExecutor.js +378 -0
  60. package/dist/runtime/execution/agentRunExecutor.js.map +1 -0
  61. package/dist/runtime/execution/agentRunExecutor.types.d.ts +37 -0
  62. package/dist/runtime/execution/agentRunExecutor.types.d.ts.map +1 -0
  63. package/dist/runtime/execution/agentRunExecutor.types.js +2 -0
  64. package/dist/runtime/execution/agentRunExecutor.types.js.map +1 -0
  65. package/dist/runtime/execution/agentRunProgress.d.ts +8 -0
  66. package/dist/runtime/execution/agentRunProgress.d.ts.map +1 -0
  67. package/dist/runtime/execution/agentRunProgress.js +46 -0
  68. package/dist/runtime/execution/agentRunProgress.js.map +1 -0
  69. package/dist/runtime/execution/agentRunState.d.ts +44 -0
  70. package/dist/runtime/execution/agentRunState.d.ts.map +1 -0
  71. package/dist/runtime/execution/agentRunState.js +17 -0
  72. package/dist/runtime/execution/agentRunState.js.map +1 -0
  73. package/dist/runtime/execution/policies/runCompletionPolicy.d.ts +5 -0
  74. package/dist/runtime/execution/policies/runCompletionPolicy.d.ts.map +1 -0
  75. package/dist/runtime/execution/policies/runCompletionPolicy.js +30 -0
  76. package/dist/runtime/execution/policies/runCompletionPolicy.js.map +1 -0
  77. package/dist/runtime/execution/policies/runErrorPolicy.d.ts +7 -0
  78. package/dist/runtime/execution/policies/runErrorPolicy.d.ts.map +1 -0
  79. package/dist/runtime/execution/policies/runErrorPolicy.js +40 -0
  80. package/dist/runtime/execution/policies/runErrorPolicy.js.map +1 -0
  81. package/dist/runtime/execution/policies/runPromptBuilder.d.ts +10 -0
  82. package/dist/runtime/execution/policies/runPromptBuilder.d.ts.map +1 -0
  83. package/dist/runtime/execution/policies/runPromptBuilder.js +34 -0
  84. package/dist/runtime/execution/policies/runPromptBuilder.js.map +1 -0
  85. package/dist/runtime/execution/policies/runSummaryFormatter.d.ts +6 -0
  86. package/dist/runtime/execution/policies/runSummaryFormatter.d.ts.map +1 -0
  87. package/dist/runtime/execution/policies/runSummaryFormatter.js +47 -0
  88. package/dist/runtime/execution/policies/runSummaryFormatter.js.map +1 -0
  89. package/dist/runtime/execution/policies/runtimeDelay.d.ts +4 -0
  90. package/dist/runtime/execution/policies/runtimeDelay.d.ts.map +1 -0
  91. package/dist/runtime/execution/policies/runtimeDelay.js +6 -0
  92. package/dist/runtime/execution/policies/runtimeDelay.js.map +1 -0
  93. package/dist/runtime/execution/policies/toolConfigReader.d.ts +8 -0
  94. package/dist/runtime/execution/policies/toolConfigReader.d.ts.map +1 -0
  95. package/dist/runtime/execution/policies/toolConfigReader.js +91 -0
  96. package/dist/runtime/execution/policies/toolConfigReader.js.map +1 -0
  97. package/dist/runtime/human-loop/consoleHumanLoop.d.ts +21 -0
  98. package/dist/runtime/human-loop/consoleHumanLoop.d.ts.map +1 -0
  99. package/dist/runtime/human-loop/consoleHumanLoop.js +102 -0
  100. package/dist/runtime/human-loop/consoleHumanLoop.js.map +1 -0
  101. package/dist/runtime/human-loop/humanLoop.d.ts +44 -0
  102. package/dist/runtime/human-loop/humanLoop.d.ts.map +1 -0
  103. package/dist/runtime/human-loop/humanLoop.js +36 -0
  104. package/dist/runtime/human-loop/humanLoop.js.map +1 -0
  105. package/dist/runtime/index.d.ts +10 -0
  106. package/dist/runtime/index.d.ts.map +1 -0
  107. package/dist/runtime/index.js +6 -0
  108. package/dist/runtime/index.js.map +1 -0
  109. package/dist/runtime/middleware/agentToolMiddleware.d.ts +30 -0
  110. package/dist/runtime/middleware/agentToolMiddleware.d.ts.map +1 -0
  111. package/dist/runtime/middleware/agentToolMiddleware.js +259 -0
  112. package/dist/runtime/middleware/agentToolMiddleware.js.map +1 -0
  113. package/dist/runtime/middleware/commandPolicy.d.ts +8 -0
  114. package/dist/runtime/middleware/commandPolicy.d.ts.map +1 -0
  115. package/dist/runtime/middleware/commandPolicy.js +55 -0
  116. package/dist/runtime/middleware/commandPolicy.js.map +1 -0
  117. package/dist/runtime/middleware/frameworkPrompt.d.ts +4 -0
  118. package/dist/runtime/middleware/frameworkPrompt.d.ts.map +1 -0
  119. package/dist/runtime/middleware/frameworkPrompt.js +44 -0
  120. package/dist/runtime/middleware/frameworkPrompt.js.map +1 -0
  121. package/dist/runtime/middleware/index.d.ts +4 -0
  122. package/dist/runtime/middleware/index.d.ts.map +1 -0
  123. package/dist/runtime/middleware/index.js +3 -0
  124. package/dist/runtime/middleware/index.js.map +1 -0
  125. package/dist/runtime/middleware/skillPathMap.d.ts +3 -0
  126. package/dist/runtime/middleware/skillPathMap.d.ts.map +1 -0
  127. package/dist/runtime/middleware/skillPathMap.js +44 -0
  128. package/dist/runtime/middleware/skillPathMap.js.map +1 -0
  129. package/dist/runtime/middleware/toolArgsNormalizer.d.ts +21 -0
  130. package/dist/runtime/middleware/toolArgsNormalizer.d.ts.map +1 -0
  131. package/dist/runtime/middleware/toolArgsNormalizer.js +227 -0
  132. package/dist/runtime/middleware/toolArgsNormalizer.js.map +1 -0
  133. package/dist/runtime/middleware/toolCallGuard.d.ts +8 -0
  134. package/dist/runtime/middleware/toolCallGuard.d.ts.map +1 -0
  135. package/dist/runtime/middleware/toolCallGuard.js +60 -0
  136. package/dist/runtime/middleware/toolCallGuard.js.map +1 -0
  137. package/dist/runtime/middleware/toolFsHandlers.d.ts +12 -0
  138. package/dist/runtime/middleware/toolFsHandlers.d.ts.map +1 -0
  139. package/dist/runtime/middleware/toolFsHandlers.js +79 -0
  140. package/dist/runtime/middleware/toolFsHandlers.js.map +1 -0
  141. package/dist/runtime/middleware/toolRequestParser.d.ts +14 -0
  142. package/dist/runtime/middleware/toolRequestParser.d.ts.map +1 -0
  143. package/dist/runtime/middleware/toolRequestParser.js +72 -0
  144. package/dist/runtime/middleware/toolRequestParser.js.map +1 -0
  145. package/dist/runtime/middleware/types.d.ts +87 -0
  146. package/dist/runtime/middleware/types.d.ts.map +1 -0
  147. package/dist/runtime/middleware/types.js +3 -0
  148. package/dist/runtime/middleware/types.js.map +1 -0
  149. package/dist/runtime/providers/backendResolver.d.ts +26 -0
  150. package/dist/runtime/providers/backendResolver.d.ts.map +1 -0
  151. package/dist/runtime/providers/backendResolver.js +73 -0
  152. package/dist/runtime/providers/backendResolver.js.map +1 -0
  153. package/dist/runtime/providers/index.d.ts +14 -0
  154. package/dist/runtime/providers/index.d.ts.map +1 -0
  155. package/dist/runtime/providers/index.js +10 -0
  156. package/dist/runtime/providers/index.js.map +1 -0
  157. package/dist/runtime/providers/langchainRuntime.d.ts +11 -0
  158. package/dist/runtime/providers/langchainRuntime.d.ts.map +1 -0
  159. package/dist/runtime/providers/langchainRuntime.js +45 -0
  160. package/dist/runtime/providers/langchainRuntime.js.map +1 -0
  161. package/dist/runtime/providers/localShellBackend.d.ts +10 -0
  162. package/dist/runtime/providers/localShellBackend.d.ts.map +1 -0
  163. package/dist/runtime/providers/localShellBackend.js +23 -0
  164. package/dist/runtime/providers/localShellBackend.js.map +1 -0
  165. package/dist/runtime/providers/openaiDeepAgent.d.ts +9 -0
  166. package/dist/runtime/providers/openaiDeepAgent.d.ts.map +1 -0
  167. package/dist/runtime/providers/openaiDeepAgent.js +7 -0
  168. package/dist/runtime/providers/openaiDeepAgent.js.map +1 -0
  169. package/dist/runtime/providers/openaiLocalAgent.d.ts +17 -0
  170. package/dist/runtime/providers/openaiLocalAgent.d.ts.map +1 -0
  171. package/dist/runtime/providers/openaiLocalAgent.js +26 -0
  172. package/dist/runtime/providers/openaiLocalAgent.js.map +1 -0
  173. package/dist/runtime/providers/openaiLocalAgentFactory.d.ts +36 -0
  174. package/dist/runtime/providers/openaiLocalAgentFactory.d.ts.map +1 -0
  175. package/dist/runtime/providers/openaiLocalAgentFactory.js +139 -0
  176. package/dist/runtime/providers/openaiLocalAgentFactory.js.map +1 -0
  177. package/dist/runtime/providers/shared/agentProbe.d.ts +4 -0
  178. package/dist/runtime/providers/shared/agentProbe.d.ts.map +1 -0
  179. package/dist/runtime/providers/shared/agentProbe.js +17 -0
  180. package/dist/runtime/providers/shared/agentProbe.js.map +1 -0
  181. package/dist/runtime/providers/shared/moduleFallback.d.ts +2 -0
  182. package/dist/runtime/providers/shared/moduleFallback.d.ts.map +1 -0
  183. package/dist/runtime/providers/shared/moduleFallback.js +34 -0
  184. package/dist/runtime/providers/shared/moduleFallback.js.map +1 -0
  185. package/dist/runtime/providers/shared/resourceCloser.d.ts +6 -0
  186. package/dist/runtime/providers/shared/resourceCloser.d.ts.map +1 -0
  187. package/dist/runtime/providers/shared/resourceCloser.js +30 -0
  188. package/dist/runtime/providers/shared/resourceCloser.js.map +1 -0
  189. package/dist/runtime/runtimeService.d.ts +109 -0
  190. package/dist/runtime/runtimeService.d.ts.map +1 -0
  191. package/dist/runtime/runtimeService.js +90 -0
  192. package/dist/runtime/runtimeService.js.map +1 -0
  193. package/dist/runtime/stream/agentMessages.d.ts +40 -0
  194. package/dist/runtime/stream/agentMessages.d.ts.map +1 -0
  195. package/dist/runtime/stream/agentMessages.js +44 -0
  196. package/dist/runtime/stream/agentMessages.js.map +1 -0
  197. package/dist/runtime/stream/agentStream.d.ts +31 -0
  198. package/dist/runtime/stream/agentStream.d.ts.map +1 -0
  199. package/dist/runtime/stream/agentStream.js +106 -0
  200. package/dist/runtime/stream/agentStream.js.map +1 -0
  201. package/dist/runtime/stream/messageSummary.d.ts +20 -0
  202. package/dist/runtime/stream/messageSummary.d.ts.map +1 -0
  203. package/dist/runtime/stream/messageSummary.js +150 -0
  204. package/dist/runtime/stream/messageSummary.js.map +1 -0
  205. package/dist/runtime/stream/runArtifacts.d.ts +9 -0
  206. package/dist/runtime/stream/runArtifacts.d.ts.map +1 -0
  207. package/dist/runtime/stream/runArtifacts.js +48 -0
  208. package/dist/runtime/stream/runArtifacts.js.map +1 -0
  209. package/dist/state/index.d.ts +7 -0
  210. package/dist/state/index.d.ts.map +1 -0
  211. package/dist/state/index.js +4 -0
  212. package/dist/state/index.js.map +1 -0
  213. package/dist/state/runState.d.ts +36 -0
  214. package/dist/state/runState.d.ts.map +1 -0
  215. package/dist/state/runState.js +51 -0
  216. package/dist/state/runState.js.map +1 -0
  217. package/dist/state/todos.d.ts +19 -0
  218. package/dist/state/todos.d.ts.map +1 -0
  219. package/dist/state/todos.js +45 -0
  220. package/dist/state/todos.js.map +1 -0
  221. package/dist/state/workspaceRunSession.d.ts +32 -0
  222. package/dist/state/workspaceRunSession.d.ts.map +1 -0
  223. package/dist/state/workspaceRunSession.js +67 -0
  224. package/dist/state/workspaceRunSession.js.map +1 -0
  225. package/dist/state/workspaceState.d.ts +94 -0
  226. package/dist/state/workspaceState.d.ts.map +1 -0
  227. package/dist/state/workspaceState.js +119 -0
  228. package/dist/state/workspaceState.js.map +1 -0
  229. package/dist/types.d.ts +2 -0
  230. package/dist/types.d.ts.map +1 -0
  231. package/dist/types.js +2 -0
  232. package/dist/types.js.map +1 -0
  233. package/example/.tsbuildinfo +1 -0
  234. package/example/build/.tsbuildinfo +1 -0
  235. package/example/config/memory.yaml +35 -0
  236. package/example/config/model.yaml +14 -0
  237. package/example/config/runtime.yaml +46 -0
  238. package/example/config/tool.yaml +24 -0
  239. package/example/index.ts +159 -0
  240. package/example/package-lock.json +1396 -0
  241. package/example/package.json +26 -0
  242. package/example/serve-output.mjs +52 -0
  243. package/example/tsconfig.json +19 -0
  244. package/package.json +73 -0
  245. package/scripts/resolve-deps.js +40 -0
  246. package/src/config/index.ts +29 -0
  247. package/src/config/loader.ts +174 -0
  248. package/src/config/resolveRuntimeConfig.ts +160 -0
  249. package/src/config/resources.ts +152 -0
  250. package/src/config/runtimeConfigLoader.ts +68 -0
  251. package/src/external-modules.d.ts +20 -0
  252. package/src/index.ts +36 -0
  253. package/src/runtime/agentMiddleware.ts +6 -0
  254. package/src/runtime/bootstrap/runtimeFactory.ts +212 -0
  255. package/src/runtime/bootstrap/runtimeModuleInitializer.ts +34 -0
  256. package/src/runtime/context/agentContext.ts +24 -0
  257. package/src/runtime/context/globalContext.ts +70 -0
  258. package/src/runtime/events/eventPublisher.ts +45 -0
  259. package/src/runtime/execution/agentRunExecutor.ts +499 -0
  260. package/src/runtime/execution/agentRunExecutor.types.ts +39 -0
  261. package/src/runtime/execution/agentRunProgress.ts +67 -0
  262. package/src/runtime/execution/agentRunState.ts +66 -0
  263. package/src/runtime/execution/policies/runCompletionPolicy.ts +30 -0
  264. package/src/runtime/execution/policies/runErrorPolicy.ts +50 -0
  265. package/src/runtime/execution/policies/runPromptBuilder.ts +39 -0
  266. package/src/runtime/execution/policies/runSummaryFormatter.ts +57 -0
  267. package/src/runtime/execution/policies/runtimeDelay.ts +5 -0
  268. package/src/runtime/execution/policies/toolConfigReader.ts +107 -0
  269. package/src/runtime/human-loop/consoleHumanLoop.ts +113 -0
  270. package/src/runtime/human-loop/humanLoop.ts +90 -0
  271. package/src/runtime/index.ts +36 -0
  272. package/src/runtime/middleware/agentToolMiddleware.ts +329 -0
  273. package/src/runtime/middleware/commandPolicy.ts +65 -0
  274. package/src/runtime/middleware/frameworkPrompt.ts +51 -0
  275. package/src/runtime/middleware/index.ts +7 -0
  276. package/src/runtime/middleware/skillPathMap.ts +49 -0
  277. package/src/runtime/middleware/toolArgsNormalizer.ts +277 -0
  278. package/src/runtime/middleware/toolCallGuard.ts +73 -0
  279. package/src/runtime/middleware/toolFsHandlers.ts +94 -0
  280. package/src/runtime/middleware/toolRequestParser.ts +84 -0
  281. package/src/runtime/middleware/types.ts +91 -0
  282. package/src/runtime/providers/backendResolver.ts +127 -0
  283. package/src/runtime/providers/index.ts +19 -0
  284. package/src/runtime/providers/langchainRuntime.ts +67 -0
  285. package/src/runtime/providers/localShellBackend.ts +54 -0
  286. package/src/runtime/providers/openaiDeepAgent.ts +17 -0
  287. package/src/runtime/providers/openaiLocalAgent.ts +35 -0
  288. package/src/runtime/providers/openaiLocalAgentFactory.ts +185 -0
  289. package/src/runtime/providers/shared/agentProbe.ts +24 -0
  290. package/src/runtime/providers/shared/moduleFallback.ts +41 -0
  291. package/src/runtime/providers/shared/resourceCloser.ts +30 -0
  292. package/src/runtime/runtimeService.ts +205 -0
  293. package/src/runtime/stream/agentMessages.ts +72 -0
  294. package/src/runtime/stream/agentStream.ts +168 -0
  295. package/src/runtime/stream/messageSummary.ts +164 -0
  296. package/src/runtime/stream/runArtifacts.ts +72 -0
  297. package/src/state/index.ts +19 -0
  298. package/src/state/runState.ts +84 -0
  299. package/src/state/todos.ts +59 -0
  300. package/src/state/workspaceRunSession.ts +96 -0
  301. package/src/state/workspaceState.ts +199 -0
  302. package/src/types/easynet-agent-common.d.ts +62 -0
  303. package/src/types.ts +1 -0
  304. package/test/integration/runtime-live.integration.test.ts +30 -0
  305. package/test/unit/config/loader.test.ts +429 -0
  306. package/test/unit/runtime/agentContext.test.ts +23 -0
  307. package/test/unit/runtime/agentRuntime.test.ts +99 -0
  308. package/test/unit/runtime/consoleHumanLoop.test.ts +52 -0
  309. package/test/unit/runtime/events.test.ts +11 -0
  310. package/test/unit/runtime/globalContext.test.ts +34 -0
  311. package/test/unit/runtime/humanLoop.test.ts +104 -0
  312. package/test/unit/runtime/toolArgsNormalizer.test.ts +136 -0
  313. package/tsconfig.json +18 -0
@@ -0,0 +1,499 @@
1
+ import { AgentStreamService, type DrainAgentStreamOptions, type DrainAgentStreamResult } from "../stream/agentStream.js";
2
+ import { AgentMessageService } from "../stream/agentMessages.js";
3
+ import { type AgentWorkspaceState } from "../../state/workspaceState.js";
4
+ import { RunArtifactService } from "../stream/runArtifacts.js";
5
+ import { type AgentRuntimeEventPublisher } from "../events/eventPublisher.js";
6
+ import { AgentRunProgress } from "./agentRunProgress.js";
7
+ import { AgentRunStateFactory, type ExecutionContext, type RetryState } from "./agentRunState.js";
8
+ import { RunCompletionPolicy } from "./policies/runCompletionPolicy.js";
9
+ import { RunErrorPolicy } from "./policies/runErrorPolicy.js";
10
+ import { RunPromptBuilder } from "./policies/runPromptBuilder.js";
11
+ import { RunSummaryFormatter } from "./policies/runSummaryFormatter.js";
12
+ import { RuntimeDelay } from "./policies/runtimeDelay.js";
13
+ import { type AgentRuntimeRunOptions, type ConstructorParams, type RunStreamFactory } from "./agentRunExecutor.types.js";
14
+ export type { AgentRuntimeRunOptions } from "./agentRunExecutor.types.js";
15
+
16
+ export class AgentRunExecutor {
17
+ private readonly rootDir: string;
18
+ private readonly workspace: AgentWorkspaceState;
19
+ private readonly eventsPublisher: AgentRuntimeEventPublisher;
20
+ private readonly runLogger: (message: string) => void;
21
+ private readonly defaultIncompleteRunMaxRetries?: number;
22
+ private readonly defaultEmptyRunMaxRetries?: number;
23
+ private readonly defaultMalformedToolCallMaxRetries?: number;
24
+ private readonly defaultIdleTimeoutMaxRetries?: number;
25
+ private readonly defaultHeartbeatIntervalMs?: number;
26
+ private readonly defaultIdleTimeoutMs?: number;
27
+ private readonly artifactValidator?: ConstructorParams["artifactValidator"];
28
+
29
+ public constructor(params: ConstructorParams) {
30
+ this.rootDir = params.rootDir;
31
+ this.workspace = params.workspace;
32
+ this.eventsPublisher = params.events;
33
+ this.runLogger = params.runLogger;
34
+ this.defaultIncompleteRunMaxRetries = params.defaultIncompleteRunMaxRetries;
35
+ this.defaultEmptyRunMaxRetries = params.defaultEmptyRunMaxRetries;
36
+ this.defaultMalformedToolCallMaxRetries = params.defaultMalformedToolCallMaxRetries;
37
+ this.defaultIdleTimeoutMaxRetries = params.defaultIdleTimeoutMaxRetries;
38
+ this.defaultHeartbeatIntervalMs = params.defaultHeartbeatIntervalMs;
39
+ this.defaultIdleTimeoutMs = params.defaultIdleTimeoutMs;
40
+ this.artifactValidator = params.artifactValidator;
41
+ }
42
+
43
+ public async runStream<TChunk>(
44
+ params: {
45
+ prompt: string;
46
+ createStream: RunStreamFactory<TChunk>;
47
+ } & AgentRuntimeRunOptions<TChunk>,
48
+ ): Promise<DrainAgentStreamResult<TChunk>> {
49
+ const context = await this.createRunContext(params);
50
+ const retryState = AgentRunStateFactory.createRetryState(
51
+ context.trackedArtifactFiles.length > 0,
52
+ params,
53
+ {
54
+ incompleteRunMaxRetries: this.defaultIncompleteRunMaxRetries,
55
+ emptyRunMaxRetries: this.defaultEmptyRunMaxRetries,
56
+ malformedToolCallMaxRetries: this.defaultMalformedToolCallMaxRetries,
57
+ idleTimeoutMaxRetries: this.defaultIdleTimeoutMaxRetries,
58
+ },
59
+ );
60
+
61
+ try {
62
+ const result = await this.executeLoop(context, params, retryState);
63
+ await this.finalizeSuccessfulRun(context, params, result);
64
+ return result;
65
+ } catch (error) {
66
+ await this.finalizeFailedRun(context, error);
67
+ throw error;
68
+ }
69
+ }
70
+
71
+ private async createRunContext<TChunk>(
72
+ params: {
73
+ prompt: string;
74
+ createStream: RunStreamFactory<TChunk>;
75
+ } & AgentRuntimeRunOptions<TChunk>,
76
+ ): Promise<ExecutionContext<TChunk>> {
77
+ const effectivePrompt = RunPromptBuilder.buildExecutionPrompt(params.prompt);
78
+ const trackedArtifactFiles = RunArtifactService.resolveTrackedArtifactFiles(
79
+ this.rootDir,
80
+ this.workspace.artifactFiles,
81
+ effectivePrompt,
82
+ );
83
+ const trackedPaths = RunArtifactService.buildTrackedPaths(
84
+ this.rootDir,
85
+ this.workspace.runStateFile,
86
+ this.workspace.todosFile,
87
+ trackedArtifactFiles,
88
+ );
89
+ const requiredArtifactPaths = this.toRelativeArtifactPaths(trackedArtifactFiles);
90
+ this.emitRunPrepare(effectivePrompt, trackedPaths, requiredArtifactPaths);
91
+
92
+ const run = await this.workspace.prepareRun({
93
+ prompt: effectivePrompt,
94
+ fallbackThreadId: params.fallbackThreadId,
95
+ resumeHint:
96
+ params.resumeHint ??
97
+ `A previous run was interrupted. Continue from the current workspace state, especially ${trackedPaths.join(", ")}, instead of restarting from scratch.`,
98
+ });
99
+ await RunArtifactService.resetTrackedArtifactsForFreshRun(run.previousState?.status, trackedArtifactFiles);
100
+ await run.start();
101
+ this.emitRunStart(effectivePrompt, run.threadId);
102
+
103
+ return {
104
+ run,
105
+ effectivePrompt,
106
+ trackedArtifactFiles,
107
+ trackedPaths,
108
+ requiredArtifactPaths,
109
+ runInput: run.input,
110
+ runConfig: run.config,
111
+ pendingToolCall: undefined,
112
+ lastLoggedSummary: "",
113
+ lastStepCount: 0,
114
+ lastSummary: "",
115
+ };
116
+ }
117
+
118
+ private emitRunPrepare(prompt: string, trackedPaths: string[], requiredArtifactPaths: string[]): void {
119
+ this.eventsPublisher.emit({
120
+ name: "agent.runtime2.run.prepare",
121
+ from: "agent-runtime2.runtime",
122
+ to: "agent-runtime2.workspace",
123
+ payload: { prompt, trackedPaths, requiredArtifactPaths },
124
+ });
125
+ }
126
+
127
+ private emitRunStart(prompt: string, threadId: string): void {
128
+ this.eventsPublisher.emit({
129
+ name: "agent.runtime2.run.start",
130
+ from: "user",
131
+ to: "agent-runtime2.runtime",
132
+ payload: { prompt, threadId },
133
+ });
134
+ }
135
+
136
+ private async executeLoop<TChunk>(
137
+ context: ExecutionContext<TChunk>,
138
+ params: {
139
+ createStream: RunStreamFactory<TChunk>;
140
+ } & AgentRuntimeRunOptions<TChunk>,
141
+ retryState: RetryState,
142
+ ): Promise<DrainAgentStreamResult<TChunk>> {
143
+ while (true) {
144
+ try {
145
+ const result = await this.drainStream(context, params);
146
+ if (await this.resolvePostDrainAction(context, result, params, retryState) === "complete") {
147
+ return result;
148
+ }
149
+ } catch (error) {
150
+ if (!(await this.handleExecutionError(context, error, retryState))) {
151
+ throw error;
152
+ }
153
+ }
154
+ }
155
+ }
156
+
157
+ private async drainStream<TChunk>(
158
+ context: ExecutionContext<TChunk>,
159
+ params: {
160
+ createStream: RunStreamFactory<TChunk>;
161
+ } & AgentRuntimeRunOptions<TChunk>,
162
+ ): Promise<DrainAgentStreamResult<TChunk>> {
163
+ return AgentStreamService.drain(await params.createStream({
164
+ input: context.runInput,
165
+ config: context.runConfig,
166
+ }), this.createDrainOptions(context, params));
167
+ }
168
+
169
+ private createDrainOptions<TChunk>(
170
+ context: ExecutionContext<TChunk>,
171
+ params: AgentRuntimeRunOptions<TChunk>,
172
+ ): DrainAgentStreamOptions<TChunk> {
173
+ const idleTimeoutMs = this.resolveIdleTimeoutMs(params.streamOptions?.idleTimeoutMs);
174
+ return {
175
+ ...params.streamOptions,
176
+ onChunk: async (chunk) => {
177
+ this.eventsPublisher.emit({
178
+ name: "agent.runtime2.stream.chunk",
179
+ from: "agent-runtime2.stream",
180
+ to: "agent-runtime2.runtime",
181
+ payload: { chunk },
182
+ });
183
+ await params.streamOptions?.onChunk?.(chunk);
184
+ },
185
+ heartbeatIntervalMs:
186
+ params.heartbeatIntervalMs ??
187
+ params.streamOptions?.heartbeatIntervalMs ??
188
+ this.defaultHeartbeatIntervalMs ??
189
+ 10_000,
190
+ idleTimeoutMs,
191
+ summarizeChunk: params.summarizeChunk ?? AgentMessageService.summarizeAgentChunk,
192
+ onHeartbeat: async (event) => {
193
+ this.eventsPublisher.emit({
194
+ name: "agent.runtime2.stream.heartbeat",
195
+ from: "agent-runtime2.stream",
196
+ to: "agent-runtime2.runtime",
197
+ payload: event,
198
+ });
199
+ this.runLogger(`... waiting for model output (${(event.elapsedMs / 1000).toFixed(1)}s)`);
200
+ },
201
+ shouldStopOnSummary: async (event) => {
202
+ if (await params.streamOptions?.shouldStopOnSummary?.(event)) {
203
+ return true;
204
+ }
205
+ return AgentRunProgress.shouldStopForSummary(
206
+ context,
207
+ event.summary,
208
+ event.chunk,
209
+ (trackedArtifactFiles) => this.areTrackedArtifactsReady(trackedArtifactFiles, context, params),
210
+ );
211
+ },
212
+ shouldStop: async (chunk) => {
213
+ if (await params.streamOptions?.shouldStop?.(chunk)) {
214
+ return true;
215
+ }
216
+ return AgentRunProgress.shouldStopForChunk(
217
+ context,
218
+ params,
219
+ chunk,
220
+ (trackedArtifactFiles) => this.areTrackedArtifactsReady(trackedArtifactFiles, context, params),
221
+ );
222
+ },
223
+ onSummary: async (event) => {
224
+ context.lastStepCount = event.stepIndex;
225
+ context.lastSummary = event.summary;
226
+ this.eventsPublisher.emit({
227
+ name: "agent.runtime2.stream.summary",
228
+ from: "agent-runtime2.stream",
229
+ to: "agent-runtime2.runtime",
230
+ payload: event,
231
+ });
232
+ if (params.onSummary) {
233
+ await params.onSummary(event);
234
+ } else {
235
+ AgentRunProgress.logRunSummary(context, event.summary, event.elapsedMs, this.runLogger);
236
+ }
237
+ await context.run.update(event.stepIndex, event.summary);
238
+ },
239
+ };
240
+ }
241
+
242
+ private resolveIdleTimeoutMs(requestedIdleTimeoutMs: number | undefined): number {
243
+ if (requestedIdleTimeoutMs != null) return requestedIdleTimeoutMs;
244
+ const configuredIdleTimeoutMs = Number(process.env.LLM_IDLE_TIMEOUT_MS);
245
+ return this.defaultIdleTimeoutMs ?? (Number.isFinite(configuredIdleTimeoutMs) && configuredIdleTimeoutMs > 0
246
+ ? configuredIdleTimeoutMs
247
+ : 300_000);
248
+ }
249
+
250
+ private async resolvePostDrainAction<TChunk>(
251
+ context: ExecutionContext<TChunk>,
252
+ result: DrainAgentStreamResult<TChunk>,
253
+ params: AgentRuntimeRunOptions<TChunk>,
254
+ retryState: RetryState,
255
+ ): Promise<"retry" | "complete"> {
256
+ if (await this.shouldRetryEmptyResult(context, result, params, retryState)) {
257
+ await RuntimeDelay.wait(Math.min(1000 * retryState.emptyRetryCount, 3000));
258
+ return "retry";
259
+ }
260
+ if (await this.shouldRetryIncompleteRun(context, result, params, retryState)) {
261
+ context.runInput = {
262
+ messages: [{
263
+ role: "user",
264
+ content: RunPromptBuilder.buildIncompleteRetryPrompt({
265
+ prompt: context.effectivePrompt,
266
+ trackedPaths: context.trackedPaths,
267
+ requiredArtifactPaths: context.requiredArtifactPaths,
268
+ lastSummary: result.lastSummary,
269
+ }),
270
+ }],
271
+ };
272
+ return "retry";
273
+ }
274
+ return "complete";
275
+ }
276
+
277
+ private shouldRetryEmptyResult<TChunk>(
278
+ context: ExecutionContext<TChunk>,
279
+ result: DrainAgentStreamResult<TChunk>,
280
+ params: AgentRuntimeRunOptions<TChunk>,
281
+ retryState: RetryState,
282
+ ): Promise<boolean> | boolean {
283
+ const noProgressPromise = this.areTrackedArtifactsReady(context.trackedArtifactFiles, context, params)
284
+ .then((artifactsReady) =>
285
+ !artifactsReady &&
286
+ result.stepCount === 0 &&
287
+ (!result.lastSummary || result.lastSummary.trim().length === 0));
288
+ return noProgressPromise.then((noProgress) => {
289
+ if (!noProgress || retryState.emptyRetryCount >= retryState.emptyRunMaxRetries) return false;
290
+
291
+ retryState.emptyRetryCount += 1;
292
+ this.eventsPublisher.emit({
293
+ name: "agent.runtime2.run.retry.empty",
294
+ from: "agent-runtime2.runtime",
295
+ to: "agent-runtime2.runtime",
296
+ payload: {
297
+ attempt: retryState.emptyRetryCount,
298
+ maxRetries: retryState.emptyRunMaxRetries,
299
+ },
300
+ });
301
+ this.runLogger(
302
+ `! Retrying after empty model response (attempt ${retryState.emptyRetryCount}/${retryState.emptyRunMaxRetries})`,
303
+ );
304
+ context.runConfig = {
305
+ configurable: { thread_id: `${context.run.threadId}-empty-${retryState.emptyRetryCount}-${Date.now()}` },
306
+ };
307
+ return true;
308
+ });
309
+ }
310
+
311
+ private async shouldRetryIncompleteRun<TChunk>(
312
+ context: ExecutionContext<TChunk>,
313
+ result: DrainAgentStreamResult<TChunk>,
314
+ params: AgentRuntimeRunOptions<TChunk>,
315
+ retryState: RetryState,
316
+ ): Promise<boolean> {
317
+ const artifactsReady = await this.areTrackedArtifactsReady(context.trackedArtifactFiles, context, params);
318
+ const appearsCompleted = context.trackedArtifactFiles.length > 0
319
+ ? artifactsReady
320
+ : RunCompletionPolicy.hasAssistantFinalMessage(result.lastChunk);
321
+ if ((artifactsReady && appearsCompleted) || retryState.incompleteRetryCount >= retryState.incompleteRunMaxRetries) {
322
+ return false;
323
+ }
324
+
325
+ retryState.incompleteRetryCount += 1;
326
+ this.eventsPublisher.emit({
327
+ name: "agent.runtime2.run.retry.incomplete",
328
+ from: "agent-runtime2.runtime",
329
+ to: "agent-runtime2.runtime",
330
+ payload: {
331
+ attempt: retryState.incompleteRetryCount,
332
+ maxRetries: retryState.incompleteRunMaxRetries,
333
+ lastSummary: result.lastSummary,
334
+ },
335
+ });
336
+ this.runLogger(
337
+ `! Retrying to finish incomplete run (attempt ${retryState.incompleteRetryCount}/${retryState.incompleteRunMaxRetries})`,
338
+ );
339
+ context.pendingToolCall = undefined;
340
+ context.lastLoggedSummary = "";
341
+ return true;
342
+ }
343
+
344
+ private async handleExecutionError<TChunk>(
345
+ context: ExecutionContext<TChunk>,
346
+ error: unknown,
347
+ retryState: RetryState,
348
+ ): Promise<boolean> {
349
+ if (RunErrorPolicy.isIdleTimeoutError(error) &&
350
+ retryState.idleTimeoutRetryCount < retryState.idleTimeoutMaxRetries) {
351
+ retryState.idleTimeoutRetryCount += 1;
352
+ this.eventsPublisher.emit({
353
+ name: "agent.runtime2.run.retry.idle_timeout",
354
+ from: "agent-runtime2.runtime",
355
+ to: "agent-runtime2.runtime",
356
+ payload: {
357
+ attempt: retryState.idleTimeoutRetryCount,
358
+ maxRetries: retryState.idleTimeoutMaxRetries,
359
+ },
360
+ });
361
+ this.runLogger(
362
+ `! Retrying after idle timeout (attempt ${retryState.idleTimeoutRetryCount}/${retryState.idleTimeoutMaxRetries})`,
363
+ );
364
+ return true;
365
+ }
366
+ if (RunErrorPolicy.isTransientModelError(error)) {
367
+ return this.handleTransientModelError(context, error, retryState);
368
+ }
369
+ if (!RunErrorPolicy.isRecoverableToolCallError(error) ||
370
+ retryState.malformedRetryCount >= retryState.malformedToolCallMaxRetries) {
371
+ return false;
372
+ }
373
+
374
+ retryState.malformedRetryCount += 1;
375
+ this.eventsPublisher.emit({
376
+ name: "agent.runtime2.run.retry.tool_call",
377
+ from: "agent-runtime2.runtime",
378
+ to: "agent-runtime2.runtime",
379
+ payload: {
380
+ attempt: retryState.malformedRetryCount,
381
+ maxRetries: retryState.malformedToolCallMaxRetries,
382
+ error: error instanceof Error ? error.message : String(error),
383
+ },
384
+ });
385
+ this.runLogger(
386
+ `! Retrying after recoverable tool-call error (attempt ${retryState.malformedRetryCount}/${retryState.malformedToolCallMaxRetries})`,
387
+ );
388
+ return true;
389
+ }
390
+
391
+ private async handleTransientModelError<TChunk>(
392
+ context: ExecutionContext<TChunk>,
393
+ error: unknown,
394
+ retryState: RetryState,
395
+ ): Promise<boolean> {
396
+ if (retryState.transientModelRetryCount >= retryState.transientModelMaxRetries) {
397
+ throw RunErrorPolicy.createTransientModelError(error);
398
+ }
399
+
400
+ retryState.transientModelRetryCount += 1;
401
+ this.eventsPublisher.emit({
402
+ name: "agent.runtime2.run.retry.transient_model",
403
+ from: "agent-runtime2.runtime",
404
+ to: "agent-runtime2.runtime",
405
+ payload: {
406
+ attempt: retryState.transientModelRetryCount,
407
+ maxRetries: retryState.transientModelMaxRetries,
408
+ },
409
+ });
410
+ this.runLogger(
411
+ `! Retrying after transient model error (${retryState.transientModelRetryCount}/${retryState.transientModelMaxRetries})`,
412
+ );
413
+ await RuntimeDelay.wait(Math.min(1000 * retryState.transientModelRetryCount, 3000));
414
+ context.runConfig = {
415
+ configurable: { thread_id: `${context.run.threadId}-transient-${retryState.transientModelRetryCount}-${Date.now()}` },
416
+ };
417
+ return true;
418
+ }
419
+
420
+ private async finalizeSuccessfulRun<TChunk>(
421
+ context: ExecutionContext<TChunk>,
422
+ params: AgentRuntimeRunOptions<TChunk>,
423
+ result: DrainAgentStreamResult<TChunk>,
424
+ ): Promise<void> {
425
+ if (!params.onSummary && context.pendingToolCall) {
426
+ this.runLogger(RunSummaryFormatter.formatRunStep(
427
+ context.pendingToolCall.summary,
428
+ context.pendingToolCall.elapsedMs,
429
+ ));
430
+ }
431
+ await context.run.finish(result.stepCount, result.lastSummary);
432
+
433
+ const artifactsReady = await this.areTrackedArtifactsReady(context.trackedArtifactFiles, context, params);
434
+ const appearsCompleted = context.trackedArtifactFiles.length > 0
435
+ ? artifactsReady
436
+ : RunCompletionPolicy.hasAssistantFinalMessage(result.lastChunk);
437
+ if (!artifactsReady || !appearsCompleted) {
438
+ throw new Error(
439
+ `Run ended before completion (summary="${result.lastSummary || "n/a"}", stepCount=${result.stepCount}, artifactsReady=${artifactsReady})`,
440
+ );
441
+ }
442
+ if (!params.onSummary && context.lastLoggedSummary !== "Run completed") {
443
+ this.runLogger(RunSummaryFormatter.formatRunStep("Run completed", result.durationMs));
444
+ }
445
+ this.eventsPublisher.emit({
446
+ name: "agent.runtime2.run.done",
447
+ from: "agent-runtime2.runtime",
448
+ to: "user",
449
+ payload: {
450
+ threadId: context.run.threadId,
451
+ stepCount: result.stepCount,
452
+ durationMs: result.durationMs,
453
+ lastSummary: result.lastSummary,
454
+ },
455
+ });
456
+ }
457
+
458
+ private async finalizeFailedRun<TChunk>(context: ExecutionContext<TChunk>, error: unknown): Promise<void> {
459
+ const summary = context.lastSummary || "Run failed";
460
+ await context.run.finish(context.lastStepCount, summary).catch(() => {});
461
+ this.eventsPublisher.emit({
462
+ name: "agent.runtime2.run.error",
463
+ from: "agent-runtime2.runtime",
464
+ to: "user",
465
+ payload: {
466
+ threadId: context.run.threadId,
467
+ stepCount: context.lastStepCount,
468
+ lastSummary: summary,
469
+ error: error instanceof Error ? error.message : String(error),
470
+ },
471
+ });
472
+ }
473
+
474
+ private async areTrackedArtifactsReady<TChunk>(
475
+ trackedArtifactFiles: string[],
476
+ context: Pick<ExecutionContext<TChunk>, "requiredArtifactPaths">,
477
+ params: Pick<AgentRuntimeRunOptions<TChunk>, "artifactValidator">,
478
+ ): Promise<boolean> {
479
+ if (!RunArtifactService.areArtifactsUsable(trackedArtifactFiles)) {
480
+ return false;
481
+ }
482
+ const validator = params.artifactValidator ?? this.artifactValidator;
483
+ if (!validator) {
484
+ return true;
485
+ }
486
+ return await validator({
487
+ rootDir: this.rootDir,
488
+ trackedArtifactFiles,
489
+ requiredArtifactPaths: context.requiredArtifactPaths,
490
+ });
491
+ }
492
+
493
+ private toRelativeArtifactPaths(trackedArtifactFiles: string[]): string[] {
494
+ const normalizedRoot = this.rootDir.replace(/\\/g, "/");
495
+ return trackedArtifactFiles
496
+ .map((file) => file.replace(/\\/g, "/"))
497
+ .map((file) => file.startsWith(`${normalizedRoot}/`) ? file.slice(normalizedRoot.length + 1) : file);
498
+ }
499
+ }
@@ -0,0 +1,39 @@
1
+ import type { DrainAgentStreamOptions } from "../stream/agentStream.js";
2
+ import type { AgentWorkspaceState } from "../../state/workspaceState.js";
3
+
4
+ export interface AgentRuntimeRunOptions<TChunk> {
5
+ resumeHint?: string;
6
+ fallbackThreadId?: string;
7
+ malformedToolCallMaxRetries?: number;
8
+ incompleteRunMaxRetries?: number;
9
+ emptyRunMaxRetries?: number;
10
+ idleTimeoutMaxRetries?: number;
11
+ streamOptions?: Omit<DrainAgentStreamOptions<TChunk>, "onSummary" | "summarizeChunk" | "onHeartbeat">;
12
+ onSummary?: DrainAgentStreamOptions<TChunk>["onSummary"];
13
+ summarizeChunk?: (chunk: TChunk) => string | null | undefined;
14
+ heartbeatIntervalMs?: number;
15
+ artifactValidator?: (context: {
16
+ rootDir: string;
17
+ trackedArtifactFiles: string[];
18
+ requiredArtifactPaths: string[];
19
+ }) => boolean | Promise<boolean>;
20
+ }
21
+
22
+ export interface ConstructorParams {
23
+ rootDir: string;
24
+ workspace: AgentWorkspaceState;
25
+ events: import("../events/eventPublisher.js").AgentRuntimeEventPublisher;
26
+ runLogger: (message: string) => void;
27
+ defaultIncompleteRunMaxRetries?: number;
28
+ defaultEmptyRunMaxRetries?: number;
29
+ defaultMalformedToolCallMaxRetries?: number;
30
+ defaultIdleTimeoutMaxRetries?: number;
31
+ defaultHeartbeatIntervalMs?: number;
32
+ defaultIdleTimeoutMs?: number;
33
+ artifactValidator?: AgentRuntimeRunOptions<unknown>["artifactValidator"];
34
+ }
35
+
36
+ export type RunStreamFactory<TChunk> = (context: {
37
+ input: Awaited<ReturnType<AgentWorkspaceState["prepareRun"]>>["input"];
38
+ config: Awaited<ReturnType<AgentWorkspaceState["prepareRun"]>>["config"];
39
+ }) => Promise<AsyncIterable<TChunk>> | AsyncIterable<TChunk>;
@@ -0,0 +1,67 @@
1
+ import { AgentMessageService } from "../stream/agentMessages.js";
2
+ import { RunCompletionPolicy } from "./policies/runCompletionPolicy.js";
3
+ import { RunSummaryFormatter } from "./policies/runSummaryFormatter.js";
4
+ import type { AgentRuntimeRunOptions } from "./agentRunExecutor.js";
5
+ import type { ExecutionContext } from "./agentRunState.js";
6
+
7
+ export class AgentRunProgress {
8
+ public static shouldStopForSummary<TChunk>(
9
+ context: ExecutionContext<TChunk>,
10
+ summary: string,
11
+ chunk: TChunk,
12
+ areTrackedArtifactsReady: (trackedArtifactFiles: string[]) => boolean | Promise<boolean>,
13
+ ): Promise<boolean> {
14
+ return Promise.resolve(areTrackedArtifactsReady(context.trackedArtifactFiles)).then((artifactsReady) => {
15
+ if (context.trackedArtifactFiles.length > 0) {
16
+ return artifactsReady && !RunCompletionPolicy.isToolCallSummary(summary);
17
+ }
18
+ return artifactsReady &&
19
+ !RunCompletionPolicy.isToolCallSummary(summary) &&
20
+ RunCompletionPolicy.hasAssistantFinalMessage(chunk);
21
+ });
22
+ }
23
+
24
+ public static shouldStopForChunk<TChunk>(
25
+ context: ExecutionContext<TChunk>,
26
+ params: AgentRuntimeRunOptions<TChunk>,
27
+ chunk: TChunk,
28
+ areTrackedArtifactsReady: (trackedArtifactFiles: string[]) => boolean | Promise<boolean>,
29
+ ): Promise<boolean> {
30
+ const summary = (params.summarizeChunk ?? AgentMessageService.summarizeAgentChunk)(chunk);
31
+ if (typeof summary !== "string") return Promise.resolve(false);
32
+ return Promise.resolve(areTrackedArtifactsReady(context.trackedArtifactFiles)).then((artifactsReady) => {
33
+ if (context.trackedArtifactFiles.length > 0) {
34
+ return artifactsReady && !RunCompletionPolicy.isToolCallSummary(summary);
35
+ }
36
+ return artifactsReady &&
37
+ !RunCompletionPolicy.isToolCallSummary(summary) &&
38
+ RunCompletionPolicy.hasAssistantFinalMessage(chunk);
39
+ });
40
+ }
41
+
42
+ public static logRunSummary<TChunk>(
43
+ context: ExecutionContext<TChunk>,
44
+ summary: string,
45
+ elapsedMs: number,
46
+ runLogger: (message: string) => void,
47
+ ): void {
48
+ if (summary.startsWith("Tool call:")) {
49
+ if (context.pendingToolCall) {
50
+ runLogger(RunSummaryFormatter.formatRunStep(
51
+ context.pendingToolCall.summary,
52
+ context.pendingToolCall.elapsedMs,
53
+ ));
54
+ }
55
+ context.pendingToolCall = { summary, elapsedMs };
56
+ return;
57
+ }
58
+ if (summary === context.lastLoggedSummary) return;
59
+
60
+ const formatted = context.pendingToolCall
61
+ ? RunSummaryFormatter.formatMergedRunStep(context.pendingToolCall.summary, summary, elapsedMs)
62
+ : RunSummaryFormatter.formatRunStep(summary, elapsedMs);
63
+ runLogger(formatted);
64
+ context.pendingToolCall = undefined;
65
+ context.lastLoggedSummary = summary;
66
+ }
67
+ }
@@ -0,0 +1,66 @@
1
+ import type { AgentWorkspaceState } from "../../state/workspaceState.js";
2
+ export interface PendingToolCall {
3
+ summary: string;
4
+ elapsedMs: number;
5
+ }
6
+
7
+ export interface RetryState {
8
+ malformedRetryCount: number;
9
+ incompleteRetryCount: number;
10
+ emptyRetryCount: number;
11
+ idleTimeoutRetryCount: number;
12
+ transientModelRetryCount: number;
13
+ malformedToolCallMaxRetries: number;
14
+ incompleteRunMaxRetries: number;
15
+ emptyRunMaxRetries: number;
16
+ idleTimeoutMaxRetries: number;
17
+ transientModelMaxRetries: number;
18
+ }
19
+
20
+ export interface ExecutionContext<TChunk> {
21
+ run: Awaited<ReturnType<AgentWorkspaceState["prepareRun"]>>;
22
+ effectivePrompt: string;
23
+ trackedArtifactFiles: string[];
24
+ trackedPaths: string[];
25
+ requiredArtifactPaths: string[];
26
+ runInput: Awaited<ReturnType<AgentWorkspaceState["prepareRun"]>>["input"];
27
+ runConfig: Awaited<ReturnType<AgentWorkspaceState["prepareRun"]>>["config"];
28
+ pendingToolCall: PendingToolCall | undefined;
29
+ lastLoggedSummary: string;
30
+ lastStepCount: number;
31
+ lastSummary: string;
32
+ }
33
+
34
+ export class AgentRunStateFactory {
35
+ public static createRetryState(
36
+ hasTrackedArtifacts: boolean,
37
+ params: {
38
+ malformedToolCallMaxRetries?: number;
39
+ incompleteRunMaxRetries?: number;
40
+ emptyRunMaxRetries?: number;
41
+ idleTimeoutMaxRetries?: number;
42
+ },
43
+ defaults: {
44
+ incompleteRunMaxRetries?: number;
45
+ emptyRunMaxRetries?: number;
46
+ malformedToolCallMaxRetries?: number;
47
+ idleTimeoutMaxRetries?: number;
48
+ },
49
+ ): RetryState {
50
+ return {
51
+ malformedRetryCount: 0,
52
+ incompleteRetryCount: 0,
53
+ emptyRetryCount: 0,
54
+ idleTimeoutRetryCount: 0,
55
+ transientModelRetryCount: 0,
56
+ malformedToolCallMaxRetries:
57
+ params.malformedToolCallMaxRetries ?? defaults.malformedToolCallMaxRetries ?? 2,
58
+ incompleteRunMaxRetries:
59
+ params.incompleteRunMaxRetries ?? defaults.incompleteRunMaxRetries ?? (hasTrackedArtifacts ? 2 : 0),
60
+ emptyRunMaxRetries: params.emptyRunMaxRetries ?? defaults.emptyRunMaxRetries ?? 2,
61
+ idleTimeoutMaxRetries: params.idleTimeoutMaxRetries ?? defaults.idleTimeoutMaxRetries ?? 1,
62
+ transientModelMaxRetries:
63
+ Number(process.env.LLM_TRANSIENT_RETRIES) >= 0 ? Number(process.env.LLM_TRANSIENT_RETRIES) : 0,
64
+ };
65
+ }
66
+ }