@caupulican/pi-adaptative 0.81.40 → 0.81.41

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 (406) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -1
  3. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +1 -0
  4. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -1
  5. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +1 -0
  6. package/dist/cli/args.d.ts +2 -0
  7. package/dist/cli/args.d.ts.map +1 -1
  8. package/dist/cli/args.js +22 -1
  9. package/dist/cli/args.js.map +1 -1
  10. package/dist/core/agent-paths.d.ts +6 -0
  11. package/dist/core/agent-paths.d.ts.map +1 -1
  12. package/dist/core/agent-paths.js +12 -0
  13. package/dist/core/agent-paths.js.map +1 -1
  14. package/dist/core/agent-session-contracts.d.ts +293 -0
  15. package/dist/core/agent-session-contracts.d.ts.map +1 -0
  16. package/dist/core/agent-session-contracts.js +26 -0
  17. package/dist/core/agent-session-contracts.js.map +1 -0
  18. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  19. package/dist/core/agent-session-runtime.js +3 -0
  20. package/dist/core/agent-session-runtime.js.map +1 -1
  21. package/dist/core/agent-session.d.ts +26 -405
  22. package/dist/core/agent-session.d.ts.map +1 -1
  23. package/dist/core/agent-session.js +86 -307
  24. package/dist/core/agent-session.js.map +1 -1
  25. package/dist/core/auth-storage.d.ts.map +1 -1
  26. package/dist/core/auth-storage.js +3 -1
  27. package/dist/core/auth-storage.js.map +1 -1
  28. package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
  29. package/dist/core/autonomy/lane-tool-surface.js +2 -1
  30. package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
  31. package/dist/core/background-lane-controller.d.ts +3 -1
  32. package/dist/core/background-lane-controller.d.ts.map +1 -1
  33. package/dist/core/background-lane-controller.js +1 -0
  34. package/dist/core/background-lane-controller.js.map +1 -1
  35. package/dist/core/bedrock-sso-login.d.ts +16 -0
  36. package/dist/core/bedrock-sso-login.d.ts.map +1 -0
  37. package/dist/core/bedrock-sso-login.js +98 -0
  38. package/dist/core/bedrock-sso-login.js.map +1 -0
  39. package/dist/core/compaction-controller.d.ts.map +1 -1
  40. package/dist/core/compaction-controller.js +1 -1
  41. package/dist/core/compaction-controller.js.map +1 -1
  42. package/dist/core/compaction-support.d.ts +3 -8
  43. package/dist/core/compaction-support.d.ts.map +1 -1
  44. package/dist/core/compaction-support.js +3 -3
  45. package/dist/core/compaction-support.js.map +1 -1
  46. package/dist/core/context-pipeline.d.ts +1 -1
  47. package/dist/core/context-pipeline.d.ts.map +1 -1
  48. package/dist/core/context-pipeline.js +7 -33
  49. package/dist/core/context-pipeline.js.map +1 -1
  50. package/dist/core/cost/cost-summary.d.ts.map +1 -1
  51. package/dist/core/cost/cost-summary.js +5 -3
  52. package/dist/core/cost/cost-summary.js.map +1 -1
  53. package/dist/core/cost/daily-usage.d.ts.map +1 -1
  54. package/dist/core/cost/daily-usage.js +4 -5
  55. package/dist/core/cost/daily-usage.js.map +1 -1
  56. package/dist/core/default-tool-surface.d.ts.map +1 -1
  57. package/dist/core/default-tool-surface.js +1 -0
  58. package/dist/core/default-tool-surface.js.map +1 -1
  59. package/dist/core/extension-import-authority.d.ts +6 -0
  60. package/dist/core/extension-import-authority.d.ts.map +1 -0
  61. package/dist/core/extension-import-authority.js +10 -0
  62. package/dist/core/extension-import-authority.js.map +1 -0
  63. package/dist/core/extensions/loader.d.ts.map +1 -1
  64. package/dist/core/extensions/loader.js +2 -3
  65. package/dist/core/extensions/loader.js.map +1 -1
  66. package/dist/core/extensions/runner.d.ts +3 -0
  67. package/dist/core/extensions/runner.d.ts.map +1 -1
  68. package/dist/core/extensions/runner.js +14 -5
  69. package/dist/core/extensions/runner.js.map +1 -1
  70. package/dist/core/extensions/stale-context.d.ts +2 -0
  71. package/dist/core/extensions/stale-context.d.ts.map +1 -0
  72. package/dist/core/extensions/stale-context.js +2 -0
  73. package/dist/core/extensions/stale-context.js.map +1 -0
  74. package/dist/core/extensions/types.d.ts +8 -0
  75. package/dist/core/extensions/types.d.ts.map +1 -1
  76. package/dist/core/extensions/types.js.map +1 -1
  77. package/dist/core/foreground-recovery-controller.d.ts +1 -0
  78. package/dist/core/foreground-recovery-controller.d.ts.map +1 -1
  79. package/dist/core/foreground-recovery-controller.js +13 -13
  80. package/dist/core/foreground-recovery-controller.js.map +1 -1
  81. package/dist/core/goal-loop-controller.d.ts +14 -9
  82. package/dist/core/goal-loop-controller.d.ts.map +1 -1
  83. package/dist/core/goal-loop-controller.js +47 -75
  84. package/dist/core/goal-loop-controller.js.map +1 -1
  85. package/dist/core/goals/compact-goal-context.d.ts +11 -0
  86. package/dist/core/goals/compact-goal-context.d.ts.map +1 -0
  87. package/dist/core/goals/compact-goal-context.js +59 -0
  88. package/dist/core/goals/compact-goal-context.js.map +1 -0
  89. package/dist/core/goals/goal-acceptance.d.ts.map +1 -1
  90. package/dist/core/goals/goal-acceptance.js +2 -0
  91. package/dist/core/goals/goal-acceptance.js.map +1 -1
  92. package/dist/core/goals/goal-auto-continue-controller.d.ts +2 -1
  93. package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -1
  94. package/dist/core/goals/goal-auto-continue-controller.js +5 -8
  95. package/dist/core/goals/goal-auto-continue-controller.js.map +1 -1
  96. package/dist/core/goals/goal-continuation-controller.d.ts +2 -2
  97. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
  98. package/dist/core/goals/goal-continuation-controller.js +42 -11
  99. package/dist/core/goals/goal-continuation-controller.js.map +1 -1
  100. package/dist/core/goals/goal-continuation-defaults.d.ts +4 -29
  101. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
  102. package/dist/core/goals/goal-continuation-defaults.js +4 -32
  103. package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
  104. package/dist/core/goals/goal-continuation-prompt.d.ts +8 -18
  105. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
  106. package/dist/core/goals/goal-continuation-prompt.js +9 -179
  107. package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
  108. package/dist/core/goals/goal-lifecycle.d.ts +35 -12
  109. package/dist/core/goals/goal-lifecycle.d.ts.map +1 -1
  110. package/dist/core/goals/goal-lifecycle.js +98 -13
  111. package/dist/core/goals/goal-lifecycle.js.map +1 -1
  112. package/dist/core/goals/goal-record.d.ts +17 -0
  113. package/dist/core/goals/goal-record.d.ts.map +1 -0
  114. package/dist/core/goals/goal-record.js +31 -0
  115. package/dist/core/goals/goal-record.js.map +1 -0
  116. package/dist/core/goals/goal-session-controller.d.ts +42 -0
  117. package/dist/core/goals/goal-session-controller.d.ts.map +1 -0
  118. package/dist/core/goals/goal-session-controller.js +128 -0
  119. package/dist/core/goals/goal-session-controller.js.map +1 -0
  120. package/dist/core/goals/goal-state.d.ts +45 -25
  121. package/dist/core/goals/goal-state.d.ts.map +1 -1
  122. package/dist/core/goals/goal-state.js +85 -15
  123. package/dist/core/goals/goal-state.js.map +1 -1
  124. package/dist/core/goals/goal-tool-core.d.ts +1 -4
  125. package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
  126. package/dist/core/goals/goal-tool-core.js +49 -34
  127. package/dist/core/goals/goal-tool-core.js.map +1 -1
  128. package/dist/core/goals/session-goal-state.d.ts +18 -8
  129. package/dist/core/goals/session-goal-state.d.ts.map +1 -1
  130. package/dist/core/goals/session-goal-state.js +134 -11
  131. package/dist/core/goals/session-goal-state.js.map +1 -1
  132. package/dist/core/human-input-controller.d.ts +47 -0
  133. package/dist/core/human-input-controller.d.ts.map +1 -0
  134. package/dist/core/human-input-controller.js +181 -0
  135. package/dist/core/human-input-controller.js.map +1 -0
  136. package/dist/core/local-runtime-controller.d.ts +1 -1
  137. package/dist/core/local-runtime-controller.d.ts.map +1 -1
  138. package/dist/core/local-runtime-controller.js.map +1 -1
  139. package/dist/core/model-capability.d.ts +0 -19
  140. package/dist/core/model-capability.d.ts.map +1 -1
  141. package/dist/core/model-capability.js +0 -19
  142. package/dist/core/model-capability.js.map +1 -1
  143. package/dist/core/model-registry.d.ts +6 -1
  144. package/dist/core/model-registry.d.ts.map +1 -1
  145. package/dist/core/model-registry.js +13 -5
  146. package/dist/core/model-registry.js.map +1 -1
  147. package/dist/core/model-resolver.d.ts +16 -1
  148. package/dist/core/model-resolver.d.ts.map +1 -1
  149. package/dist/core/model-resolver.js +32 -16
  150. package/dist/core/model-resolver.js.map +1 -1
  151. package/dist/core/model-router-controller.d.ts +1 -1
  152. package/dist/core/model-router-controller.d.ts.map +1 -1
  153. package/dist/core/model-router-controller.js.map +1 -1
  154. package/dist/core/model-selection-controller.d.ts +1 -1
  155. package/dist/core/model-selection-controller.d.ts.map +1 -1
  156. package/dist/core/model-selection-controller.js.map +1 -1
  157. package/dist/core/orchestration/delegation-ledger.d.ts.map +1 -1
  158. package/dist/core/orchestration/delegation-ledger.js +3 -0
  159. package/dist/core/orchestration/delegation-ledger.js.map +1 -1
  160. package/dist/core/orchestration/work-state-projection.d.ts.map +1 -1
  161. package/dist/core/orchestration/work-state-projection.js +1 -1
  162. package/dist/core/orchestration/work-state-projection.js.map +1 -1
  163. package/dist/core/package-manager.d.ts.map +1 -1
  164. package/dist/core/package-manager.js +20 -3
  165. package/dist/core/package-manager.js.map +1 -1
  166. package/dist/core/profile-filter-controller.d.ts +8 -1
  167. package/dist/core/profile-filter-controller.d.ts.map +1 -1
  168. package/dist/core/profile-filter-controller.js +23 -5
  169. package/dist/core/profile-filter-controller.js.map +1 -1
  170. package/dist/core/prompt-templates.d.ts +1 -0
  171. package/dist/core/prompt-templates.d.ts.map +1 -1
  172. package/dist/core/prompt-templates.js +18 -29
  173. package/dist/core/prompt-templates.js.map +1 -1
  174. package/dist/core/reflection-controller.d.ts +1 -1
  175. package/dist/core/reflection-controller.d.ts.map +1 -1
  176. package/dist/core/reflection-controller.js +3 -1
  177. package/dist/core/reflection-controller.js.map +1 -1
  178. package/dist/core/request-auth.d.ts +7 -0
  179. package/dist/core/request-auth.d.ts.map +1 -0
  180. package/dist/core/request-auth.js +8 -0
  181. package/dist/core/request-auth.js.map +1 -0
  182. package/dist/core/resource-loader.d.ts.map +1 -1
  183. package/dist/core/resource-loader.js +16 -6
  184. package/dist/core/resource-loader.js.map +1 -1
  185. package/dist/core/risk-classifier.d.ts.map +1 -1
  186. package/dist/core/risk-classifier.js +8 -0
  187. package/dist/core/risk-classifier.js.map +1 -1
  188. package/dist/core/runtime-builder.d.ts +15 -3
  189. package/dist/core/runtime-builder.d.ts.map +1 -1
  190. package/dist/core/runtime-builder.js +132 -79
  191. package/dist/core/runtime-builder.js.map +1 -1
  192. package/dist/core/sdk.d.ts.map +1 -1
  193. package/dist/core/sdk.js +7 -1
  194. package/dist/core/sdk.js.map +1 -1
  195. package/dist/core/secrets/credential-exposure-guard.d.ts +9 -0
  196. package/dist/core/secrets/credential-exposure-guard.d.ts.map +1 -0
  197. package/dist/core/secrets/credential-exposure-guard.js +241 -0
  198. package/dist/core/secrets/credential-exposure-guard.js.map +1 -0
  199. package/dist/core/secrets/secret-dotenv.d.ts +27 -0
  200. package/dist/core/secrets/secret-dotenv.d.ts.map +1 -0
  201. package/dist/core/secrets/secret-dotenv.js +183 -0
  202. package/dist/core/secrets/secret-dotenv.js.map +1 -0
  203. package/dist/core/secrets/secret-vault-format.d.ts +112 -0
  204. package/dist/core/secrets/secret-vault-format.d.ts.map +1 -0
  205. package/dist/core/secrets/secret-vault-format.js +397 -0
  206. package/dist/core/secrets/secret-vault-format.js.map +1 -0
  207. package/dist/core/secrets/secret-vault.d.ts +72 -0
  208. package/dist/core/secrets/secret-vault.d.ts.map +1 -0
  209. package/dist/core/secrets/secret-vault.js +671 -0
  210. package/dist/core/secrets/secret-vault.js.map +1 -0
  211. package/dist/core/session-analytics.d.ts +4 -23
  212. package/dist/core/session-analytics.d.ts.map +1 -1
  213. package/dist/core/session-analytics.js +39 -69
  214. package/dist/core/session-analytics.js.map +1 -1
  215. package/dist/core/session-role.d.ts +5 -0
  216. package/dist/core/session-role.d.ts.map +1 -1
  217. package/dist/core/session-role.js +14 -1
  218. package/dist/core/session-role.js.map +1 -1
  219. package/dist/core/session-tree-navigator.d.ts +4 -6
  220. package/dist/core/session-tree-navigator.d.ts.map +1 -1
  221. package/dist/core/session-tree-navigator.js +4 -1
  222. package/dist/core/session-tree-navigator.js.map +1 -1
  223. package/dist/core/settings-manager.d.ts +1 -1
  224. package/dist/core/settings-manager.d.ts.map +1 -1
  225. package/dist/core/settings-manager.js +1 -1
  226. package/dist/core/settings-manager.js.map +1 -1
  227. package/dist/core/slash-commands.d.ts.map +1 -1
  228. package/dist/core/slash-commands.js +2 -2
  229. package/dist/core/slash-commands.js.map +1 -1
  230. package/dist/core/tool-capability-policy.d.ts.map +1 -1
  231. package/dist/core/tool-capability-policy.js +1 -0
  232. package/dist/core/tool-capability-policy.js.map +1 -1
  233. package/dist/core/tool-gate-controller.d.ts.map +1 -1
  234. package/dist/core/tool-gate-controller.js +8 -2
  235. package/dist/core/tool-gate-controller.js.map +1 -1
  236. package/dist/core/tool-protocol-controller.d.ts +2 -4
  237. package/dist/core/tool-protocol-controller.d.ts.map +1 -1
  238. package/dist/core/tool-protocol-controller.js.map +1 -1
  239. package/dist/core/tool-recovery-stats.d.ts +21 -1
  240. package/dist/core/tool-recovery-stats.d.ts.map +1 -1
  241. package/dist/core/tool-recovery-stats.js.map +1 -1
  242. package/dist/core/tools/bash.d.ts +5 -0
  243. package/dist/core/tools/bash.d.ts.map +1 -1
  244. package/dist/core/tools/bash.js +59 -5
  245. package/dist/core/tools/bash.js.map +1 -1
  246. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  247. package/dist/core/tools/delegate-status.js +6 -7
  248. package/dist/core/tools/delegate-status.js.map +1 -1
  249. package/dist/core/tools/delegate.d.ts.map +1 -1
  250. package/dist/core/tools/delegate.js +6 -8
  251. package/dist/core/tools/delegate.js.map +1 -1
  252. package/dist/core/tools/git-filter.d.ts +1 -8
  253. package/dist/core/tools/git-filter.d.ts.map +1 -1
  254. package/dist/core/tools/git-filter.js +2 -63
  255. package/dist/core/tools/git-filter.js.map +1 -1
  256. package/dist/core/tools/goal.d.ts +5 -3
  257. package/dist/core/tools/goal.d.ts.map +1 -1
  258. package/dist/core/tools/goal.js +97 -19
  259. package/dist/core/tools/goal.js.map +1 -1
  260. package/dist/core/tools/index.d.ts +1 -0
  261. package/dist/core/tools/index.d.ts.map +1 -1
  262. package/dist/core/tools/index.js +1 -0
  263. package/dist/core/tools/index.js.map +1 -1
  264. package/dist/core/tools/orchestration-panel.d.ts +1 -4
  265. package/dist/core/tools/orchestration-panel.d.ts.map +1 -1
  266. package/dist/core/tools/orchestration-panel.js +0 -44
  267. package/dist/core/tools/orchestration-panel.js.map +1 -1
  268. package/dist/core/tools/output-accumulator.d.ts +11 -0
  269. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  270. package/dist/core/tools/output-accumulator.js +36 -3
  271. package/dist/core/tools/output-accumulator.js.map +1 -1
  272. package/dist/core/tools/python.d.ts +2 -0
  273. package/dist/core/tools/python.d.ts.map +1 -1
  274. package/dist/core/tools/python.js +3 -1
  275. package/dist/core/tools/python.js.map +1 -1
  276. package/dist/core/tools/read.d.ts.map +1 -1
  277. package/dist/core/tools/read.js +1 -1
  278. package/dist/core/tools/read.js.map +1 -1
  279. package/dist/core/tools/search-command-guard.d.ts +14 -0
  280. package/dist/core/tools/search-command-guard.d.ts.map +1 -0
  281. package/dist/core/tools/search-command-guard.js +333 -0
  282. package/dist/core/tools/search-command-guard.js.map +1 -0
  283. package/dist/core/tools/secret-store.d.ts +38 -0
  284. package/dist/core/tools/secret-store.d.ts.map +1 -0
  285. package/dist/core/tools/secret-store.js +412 -0
  286. package/dist/core/tools/secret-store.js.map +1 -0
  287. package/dist/core/tools/shell-command-parser.d.ts +16 -0
  288. package/dist/core/tools/shell-command-parser.d.ts.map +1 -0
  289. package/dist/core/tools/shell-command-parser.js +113 -0
  290. package/dist/core/tools/shell-command-parser.js.map +1 -0
  291. package/dist/core/tools/task-steps.d.ts.map +1 -1
  292. package/dist/core/tools/task-steps.js +4 -7
  293. package/dist/core/tools/task-steps.js.map +1 -1
  294. package/dist/core/util/atomic-file.d.ts +6 -2
  295. package/dist/core/util/atomic-file.d.ts.map +1 -1
  296. package/dist/core/util/atomic-file.js +4 -4
  297. package/dist/core/util/atomic-file.js.map +1 -1
  298. package/dist/index.d.ts +3 -2
  299. package/dist/index.d.ts.map +1 -1
  300. package/dist/index.js +2 -1
  301. package/dist/index.js.map +1 -1
  302. package/dist/main.d.ts.map +1 -1
  303. package/dist/main.js +25 -11
  304. package/dist/main.js.map +1 -1
  305. package/dist/modes/interactive/auth-dialogs-controller.d.ts +4 -0
  306. package/dist/modes/interactive/auth-dialogs-controller.d.ts.map +1 -1
  307. package/dist/modes/interactive/auth-dialogs-controller.js +60 -1
  308. package/dist/modes/interactive/auth-dialogs-controller.js.map +1 -1
  309. package/dist/modes/interactive/components/activity-lane.d.ts +55 -0
  310. package/dist/modes/interactive/components/activity-lane.d.ts.map +1 -0
  311. package/dist/modes/interactive/components/activity-lane.js +304 -0
  312. package/dist/modes/interactive/components/activity-lane.js.map +1 -0
  313. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  314. package/dist/modes/interactive/components/assistant-message.js +19 -10
  315. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  316. package/dist/modes/interactive/components/expandable-text.d.ts +12 -0
  317. package/dist/modes/interactive/components/expandable-text.d.ts.map +1 -0
  318. package/dist/modes/interactive/components/expandable-text.js +17 -0
  319. package/dist/modes/interactive/components/expandable-text.js.map +1 -0
  320. package/dist/modes/interactive/components/extension-editor.d.ts +15 -1
  321. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  322. package/dist/modes/interactive/components/extension-editor.js +30 -21
  323. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  324. package/dist/modes/interactive/components/extension-input.d.ts +1 -0
  325. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  326. package/dist/modes/interactive/components/extension-input.js +6 -1
  327. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  328. package/dist/modes/interactive/components/scoped-models-selector.d.ts +2 -2
  329. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  330. package/dist/modes/interactive/components/scoped-models-selector.js +23 -14
  331. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  332. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  333. package/dist/modes/interactive/components/settings-selector.js +4 -4
  334. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  335. package/dist/modes/interactive/components/tool-execution.d.ts +19 -11
  336. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  337. package/dist/modes/interactive/components/tool-execution.js +53 -20
  338. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  339. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
  340. package/dist/modes/interactive/components/tool-group.js +3 -0
  341. package/dist/modes/interactive/components/tool-group.js.map +1 -1
  342. package/dist/modes/interactive/components/usage-action-selector.d.ts +16 -0
  343. package/dist/modes/interactive/components/usage-action-selector.d.ts.map +1 -0
  344. package/dist/modes/interactive/components/usage-action-selector.js +46 -0
  345. package/dist/modes/interactive/components/usage-action-selector.js.map +1 -0
  346. package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -1
  347. package/dist/modes/interactive/extension-ui-host.js +1 -0
  348. package/dist/modes/interactive/extension-ui-host.js.map +1 -1
  349. package/dist/modes/interactive/external-editor.d.ts +15 -0
  350. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  351. package/dist/modes/interactive/external-editor.js +27 -19
  352. package/dist/modes/interactive/external-editor.js.map +1 -1
  353. package/dist/modes/interactive/history-reload-math.d.ts +6 -2
  354. package/dist/modes/interactive/history-reload-math.d.ts.map +1 -1
  355. package/dist/modes/interactive/history-reload-math.js +10 -5
  356. package/dist/modes/interactive/history-reload-math.js.map +1 -1
  357. package/dist/modes/interactive/interactive-event-controller.d.ts +74 -0
  358. package/dist/modes/interactive/interactive-event-controller.d.ts.map +1 -0
  359. package/dist/modes/interactive/interactive-event-controller.js +328 -0
  360. package/dist/modes/interactive/interactive-event-controller.js.map +1 -0
  361. package/dist/modes/interactive/interactive-mode.d.ts +20 -25
  362. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  363. package/dist/modes/interactive/interactive-mode.js +196 -608
  364. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  365. package/dist/modes/interactive/loaded-resources-view.d.ts +20 -0
  366. package/dist/modes/interactive/loaded-resources-view.d.ts.map +1 -0
  367. package/dist/modes/interactive/loaded-resources-view.js +147 -0
  368. package/dist/modes/interactive/loaded-resources-view.js.map +1 -0
  369. package/dist/modes/interactive/resource-display.d.ts.map +1 -1
  370. package/dist/modes/interactive/resource-display.js +8 -2
  371. package/dist/modes/interactive/resource-display.js.map +1 -1
  372. package/dist/modes/interactive/resource-shell-commands.d.ts +1 -5
  373. package/dist/modes/interactive/resource-shell-commands.d.ts.map +1 -1
  374. package/dist/modes/interactive/resource-shell-commands.js +0 -5
  375. package/dist/modes/interactive/resource-shell-commands.js.map +1 -1
  376. package/dist/modes/interactive/session-flow-commands.d.ts +10 -6
  377. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  378. package/dist/modes/interactive/session-flow-commands.js +123 -70
  379. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  380. package/dist/modes/interactive/usage-commands.d.ts +34 -0
  381. package/dist/modes/interactive/usage-commands.d.ts.map +1 -0
  382. package/dist/modes/interactive/usage-commands.js +225 -0
  383. package/dist/modes/interactive/usage-commands.js.map +1 -0
  384. package/dist/utils/shell.d.ts.map +1 -1
  385. package/dist/utils/shell.js +5 -3
  386. package/dist/utils/shell.js.map +1 -1
  387. package/dist/utils/version-check.d.ts.map +1 -1
  388. package/dist/utils/version-check.js +3 -1
  389. package/dist/utils/version-check.js.map +1 -1
  390. package/docs/UI_POLISH_ORCHESTRATION.md +25 -31
  391. package/docs/UI_QUALITY_ORCHESTRATION.md +22 -24
  392. package/docs/providers.md +9 -1
  393. package/docs/ui-reference/README.md +6 -6
  394. package/docs/ui-reference/orchestration-after.txt +14 -7
  395. package/docs/ui-reference/orchestration-before.txt +12 -6
  396. package/docs/ui-reference/orchestration-reference.txt +15 -5
  397. package/docs/usage.md +9 -1
  398. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  399. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  400. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  401. package/examples/extensions/sandbox/package-lock.json +2 -2
  402. package/examples/extensions/sandbox/package.json +1 -1
  403. package/examples/extensions/with-deps/package-lock.json +2 -2
  404. package/examples/extensions/with-deps/package.json +1 -1
  405. package/npm-shrinkwrap.json +13 -13
  406. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"goal-loop-controller.d.ts","sourceRoot":"","sources":["../../src/core/goal-loop-controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACX,2BAA2B,EAC3B,0BAA0B,EAE1B,2BAA2B,EAC3B,0BAA0B,EAC1B,aAAa,EACb,MAAM,oBAAoB,CAAC;AAO5B,OAAO,KAAK,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAiEzG,MAAM,WAAW,sBAAsB;IACtC,mGAAmG;IACnG,sBAAsB,CAAC,QAAQ,EAAE,2BAA2B,GAAG,mBAAmB,CAAC;IACnF,0EAA0E;IAC1E,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D;;;;;OAKG;IACH,0BAA0B,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC/E;AAED,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAyB;IAE9C,YAAY,IAAI,EAAE,sBAAsB,EAEvC;IAEK,gBAAgB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAehG;IAEK,gBAAgB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAkEhG;CACD","sourcesContent":["/**\n * Goal auto-continuation loop.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Drives the bounded \"keep the\n * active goal moving\" loop: each pass reads the goal runtime snapshot, and — only while the snapshot\n * says `continue` — submits one continuation prompt back through the session's own prompt path. It\n * owns no state; the goal state lives in the session log and is read fresh every pass. Termination is\n * fully budget-gated (per-invocation turn cap, per-invocation wall-clock cap, a DURABLE cumulative\n * per-goal budget — turns + active wall-clock, persisted on `GoalState` across every invocation for\n * the goal's lifetime — and a no-progress guard on a MEANINGFUL progress signature — satisfied-\n * requirement count + ref-backed evidence count — so hollow goal-tool calls (e.g. add_requirement/\n * reopen churn that satisfies nothing) cannot defeat the stall guard). Each submitted pass also\n * reports its turn/wall-clock/spend contribution back to the session via `recordGoalContinuationPass`\n * so the cumulative budget stays accurate.\n */\n\nimport type {\n\tGoalContinuationLoopOptions,\n\tGoalContinuationLoopResult,\n\tGoalContinuationLoopStopReason,\n\tGoalContinuationOnceOptions,\n\tGoalContinuationOnceResult,\n\tPromptOptions,\n} from \"./agent-session.ts\";\nimport {\n\tDEFAULT_GOAL_CUMULATIVE_MAX_TURNS,\n\tDEFAULT_GOAL_CUMULATIVE_MAX_WALL_CLOCK_MS,\n\tDEFAULT_GOAL_CUMULATIVE_MAX_WORKER_SPEND_USD,\n} from \"./goals/goal-continuation-defaults.ts\";\nimport { buildGoalContinuationPrompt } from \"./goals/goal-continuation-prompt.ts\";\nimport type { GoalRuntimeSnapshot, GoalRuntimeSnapshotSettings } from \"./goals/goal-runtime-snapshot.ts\";\nimport type { GoalState } from \"./goals/goal-state.ts\";\n\n/**\n * Progress signature for goal-loop stall detection. Keys ONLY on state that reflects actual\n * progress toward the goal — `goalId`, `status`, the count of satisfied requirements, and the\n * count of evidence entries that carry a ref (`uri`) AND are TRUSTED: either actually validated\n * (`verified === true`) or `kind === \"user\"` (a human-confirmed claim). Deliberately excludes\n * `events.length`, `updatedAt`, and `stallTurns`: those change on every goal-tool call (including\n * no-op churn like re-adding/reopening a requirement without satisfying anything), which let hollow\n * passes look like progress and defeat `goal_state_not_advanced`.\n *\n * `verified` is `undefined` both for evidence that hasn't been checked yet AND for evidence kinds\n * that carry no checkable ref at all (`\"user\"`/`\"finding\"`/`\"test\"` — see the doc comment on\n * `GoalEvidenceRef.verified` in `goal-state.ts`). Treating \"undefined\" as trusted would let a model spam\n * `kind:\"finding\"` evidence with a fabricated `uri` every turn — always undefined, always counted —\n * which is the same class of hollow churn this signature exists to stop. So `undefined` does NOT\n * count; only an explicit `verified === true` (a real, checked ref) or `kind === \"user\"` (mirrors\n * the `complete` gate's trusted set in `goal-tool-core.ts`'s `isVerifiedOrUserEvidence`) counts.\n * `satisfiedRequirementCount` still advances the signature for legitimate-but-unverifiable work\n * (e.g. `kind:\"finding\"`/`\"test\"` evidence cited on a `satisfy_requirement` call), and the\n * continuation controller's own `stallTurns` path remains available for the model to self-report.\n */\nfunction goalProgressSignature(state: GoalState | undefined): string | undefined {\n\tif (!state) return undefined;\n\tconst satisfiedRequirementCount = state.requirements.filter(\n\t\t(requirement) => requirement.status === \"satisfied\",\n\t).length;\n\tconst refEvidenceCount = state.evidence.filter(\n\t\t(evidence) =>\n\t\t\ttypeof evidence.uri === \"string\" &&\n\t\t\tevidence.uri.trim().length > 0 &&\n\t\t\t(evidence.verified === true || evidence.kind === \"user\"),\n\t).length;\n\treturn `${state.goalId}:${state.status}:${satisfiedRequirementCount}:${refEvidenceCount}`;\n}\n\n/**\n * Whether the goal's DURABLE cumulative continuation budget (turns and/or active wall-clock,\n * persisted on `GoalState` and summed across every `continueGoalLoop` invocation for the goal's\n * lifetime) has been exhausted. Read fresh at the top of every pass (not just the top of the\n * invocation), so a single long-running invocation that crosses the ceiling mid-loop stops\n * immediately rather than waiting for the next invocation to notice. `undefined` counters (goal\n * state predating this field, or a fresh goal) count as `0` — never exhausted.\n */\nfunction isGoalContinuationBudgetExhausted(state: GoalState | undefined): boolean {\n\tif (!state) return false;\n\tif ((state.continuationTurnsUsed ?? 0) >= DEFAULT_GOAL_CUMULATIVE_MAX_TURNS) return true;\n\tif ((state.continuationWallClockMs ?? 0) >= DEFAULT_GOAL_CUMULATIVE_MAX_WALL_CLOCK_MS) return true;\n\tif ((state.continuationWorkerSpendUsd ?? 0) >= DEFAULT_GOAL_CUMULATIVE_MAX_WORKER_SPEND_USD) return true;\n\treturn false;\n}\n\n/**\n * Maps a non-\"continue\" continuation action onto the loop's own stopReason vocabulary.\n * `\"waiting\"` (a worker is dispatched against an open requirement) gets its OWN benign stopReason so\n * a wait is never misreported as `continuation_not_allowed` (which reads as a terminal refusal) —\n * callers/telemetry can tell \"paused, will resume on its own\" apart from \"stopped, needs a human or a\n * new decision.\" Every other non-continue action (ask-user/finalize/stop) keeps the existing\n * `continuation_not_allowed` stopReason unchanged.\n */\nfunction nonContinueStopReason(snapshot: GoalRuntimeSnapshot): GoalContinuationLoopStopReason {\n\treturn snapshot.continuation.action === \"waiting\" ? \"worker_in_flight\" : \"continuation_not_allowed\";\n}\n\nexport interface GoalLoopControllerDeps {\n\t/** Read the current goal runtime snapshot (continuation decision + goal state) fresh each pass. */\n\tgetGoalRuntimeSnapshot(settings: GoalRuntimeSnapshotSettings): GoalRuntimeSnapshot;\n\t/** Submit a continuation prompt through the session's own prompt path. */\n\tprompt(text: string, options?: PromptOptions): Promise<void>;\n\t/**\n\t * Persist one submitted pass's contribution to the active goal's durable cumulative budget\n\t * (turns + active wall-clock; USD is attributed by the implementation from the session's own\n\t * spend, not passed in here — see `AgentSession.recordGoalContinuationPass`). Called once per\n\t * pass actually SUBMITTED (never for a no-op `continueGoalOnce` call).\n\t */\n\trecordGoalContinuationPass(pass: { turns: number; wallClockMs: number }): void;\n}\n\nexport class GoalLoopController {\n\tprivate readonly deps: GoalLoopControllerDeps;\n\n\tconstructor(deps: GoalLoopControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tasync continueGoalOnce(options: GoalContinuationOnceOptions): Promise<GoalContinuationOnceResult> {\n\t\tconst snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns });\n\n\t\tif (snapshot.continuation.action !== \"continue\") {\n\t\t\treturn { submitted: false, snapshot };\n\t\t}\n\n\t\tconst prompt = buildGoalContinuationPrompt({ snapshot, limits: options.promptLimits });\n\t\tawait this.deps.prompt(prompt.text, {\n\t\t\texpandPromptTemplates: false,\n\t\t\tprocessSlashCommands: false,\n\t\t\tautoContinueGoal: false,\n\t\t});\n\n\t\treturn { submitted: true, snapshot, prompt };\n\t}\n\n\tasync continueGoalLoop(options: GoalContinuationLoopOptions): Promise<GoalContinuationLoopResult> {\n\t\tlet turnsSubmitted = 0;\n\t\tconst now = options.now ?? Date.now;\n\t\tconst maxWallClockMs =\n\t\t\ttypeof options.maxWallClockMinutes === \"number\" && options.maxWallClockMinutes > 0\n\t\t\t\t? options.maxWallClockMinutes * 60_000\n\t\t\t\t: undefined;\n\t\tconst startedAt = now();\n\t\tconst hasReachedWallClockBudget = () => maxWallClockMs !== undefined && now() - startedAt >= maxWallClockMs;\n\t\tconst snapshot = () => this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns });\n\n\t\tif (options.maxTurns <= 0) {\n\t\t\treturn {\n\t\t\t\tturnsSubmitted: 0,\n\t\t\t\tstopReason: \"max_turns_reached\",\n\t\t\t\tfinalSnapshot: snapshot(),\n\t\t\t};\n\t\t}\n\n\t\tif (hasReachedWallClockBudget()) {\n\t\t\treturn { turnsSubmitted, stopReason: \"wall_clock_budget_reached\", finalSnapshot: snapshot() };\n\t\t}\n\n\t\twhile (turnsSubmitted < options.maxTurns) {\n\t\t\tconst beforeSnapshot = snapshot();\n\t\t\tif (beforeSnapshot.continuation.action !== \"continue\") {\n\t\t\t\treturn { turnsSubmitted, stopReason: nonContinueStopReason(beforeSnapshot), finalSnapshot: beforeSnapshot };\n\t\t\t}\n\n\t\t\t// Cumulative (durable, cross-invocation) budget — read fresh every pass, not just at the top\n\t\t\t// of this invocation, so a single long-running call still stops the moment it crosses the\n\t\t\t// ceiling rather than overshooting until the next invocation notices.\n\t\t\tif (isGoalContinuationBudgetExhausted(beforeSnapshot.goalState)) {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"goal_budget_exhausted\", finalSnapshot: beforeSnapshot };\n\t\t\t}\n\n\t\t\tconst beforeKey = goalProgressSignature(beforeSnapshot.goalState);\n\n\t\t\tconst passStartedAt = now();\n\t\t\tconst result = await this.continueGoalOnce(options);\n\t\t\tif (result.submitted) {\n\t\t\t\tturnsSubmitted++;\n\t\t\t\tthis.deps.recordGoalContinuationPass({ turns: 1, wallClockMs: now() - passStartedAt });\n\t\t\t}\n\n\t\t\tif (hasReachedWallClockBudget()) {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"wall_clock_budget_reached\", finalSnapshot: snapshot() };\n\t\t\t}\n\n\t\t\tconst afterSnapshot = snapshot();\n\t\t\tif (afterSnapshot.continuation.action !== \"continue\") {\n\t\t\t\treturn { turnsSubmitted, stopReason: nonContinueStopReason(afterSnapshot), finalSnapshot: afterSnapshot };\n\t\t\t}\n\n\t\t\tconst afterKey = goalProgressSignature(afterSnapshot.goalState);\n\n\t\t\tif (beforeKey === afterKey) {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"goal_state_not_advanced\", finalSnapshot: afterSnapshot };\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tturnsSubmitted,\n\t\t\tstopReason: \"max_turns_reached\",\n\t\t\tfinalSnapshot: snapshot(),\n\t\t};\n\t}\n}\n"]}
1
+ {"version":3,"file":"goal-loop-controller.d.ts","sourceRoot":"","sources":["../../src/core/goal-loop-controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EACX,2BAA2B,EAC3B,0BAA0B,EAE1B,2BAA2B,EAC3B,0BAA0B,EAC1B,aAAa,EACb,MAAM,8BAA8B,CAAC;AAKtC,OAAO,KAAK,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AA4BzG,MAAM,WAAW,sBAAsB;IACtC,mGAAmG;IACnG,sBAAsB,CAAC,QAAQ,EAAE,2BAA2B,GAAG,mBAAmB,CAAC;IACnF,0EAA0E;IAC1E,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,sFAAsF;IACtF,kBAAkB,IAAI,MAAM,GAAG,IAAI,CAAC;IACpC;;;;;OAKG;IACH,0BAA0B,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAC3G,uFAAuF;IACvF,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACpD,gFAAgF;IAChF,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5C;AAED,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAyB;IAE9C,YAAY,IAAI,EAAE,sBAAsB,EAEvC;IAEK,gBAAgB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAgBhG;IAEK,gBAAgB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAsEhG;CACD","sourcesContent":["/**\n * Goal auto-continuation loop.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Drives the bounded \"keep the\n * active goal moving\" loop: each pass reads the goal runtime snapshot, and — only while the snapshot\n * says `continue` — submits one continuation prompt back through the session's own prompt path. It\n * owns no state; the goal state lives in the session log and is read fresh every pass. Termination is\n * gated only by real terminal conditions and limits the owner explicitly supplied: an optional\n * per-invocation turn cap, an optional per-invocation wall-clock cap, and an optional durable token\n * budget on the goal. Each submitted pass still reports exact token/wall-clock/spend contribution\n * for observability. Progress is inferred from real work and terminal goal updates; telemetry never\n * becomes an implicit execution limit.\n */\n\nimport type {\n\tGoalContinuationLoopOptions,\n\tGoalContinuationLoopResult,\n\tGoalContinuationLoopStopReason,\n\tGoalContinuationOnceOptions,\n\tGoalContinuationOnceResult,\n\tPromptOptions,\n} from \"./agent-session-contracts.ts\";\nimport {\n\tbuildGoalContinuationPrompt,\n\tGOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE,\n} from \"./goals/goal-continuation-prompt.ts\";\nimport type { GoalRuntimeSnapshot, GoalRuntimeSnapshotSettings } from \"./goals/goal-runtime-snapshot.ts\";\nimport type { GoalState } from \"./goals/goal-state.ts\";\n\n/**\n * Resolve an owner-supplied durable goal budget. Wall-clock and spend counters are deliberately\n * absent here: they are telemetry unless the public goal contract grows matching explicit limits.\n * Execution limits are policy inputs, not hidden runtime defaults.\n */\nfunction getExplicitGoalBudgetExhaustion(state: GoalState | undefined): string | undefined {\n\tif (!state || state.status !== \"active\") return undefined;\n\tif (state.tokenBudget !== undefined && (state.tokensUsed ?? 0) >= state.tokenBudget) {\n\t\treturn `token budget exhausted (${state.tokensUsed ?? 0}/${state.tokenBudget})`;\n\t}\n\treturn undefined;\n}\n\n/**\n * Maps a non-\"continue\" continuation action onto the loop's own stopReason vocabulary.\n * `\"waiting\"` (a worker is dispatched against an open requirement) gets its OWN benign stopReason so\n * a wait is never misreported as `continuation_not_allowed` (which reads as a terminal refusal) —\n * callers/telemetry can tell \"paused, will resume on its own\" apart from \"stopped, needs a human or a\n * new decision.\" Every other non-continue action (ask-user/finalize/stop) keeps the existing\n * `continuation_not_allowed` stopReason unchanged.\n */\nfunction nonContinueStopReason(snapshot: GoalRuntimeSnapshot): GoalContinuationLoopStopReason {\n\treturn snapshot.continuation.action === \"waiting\" ? \"worker_in_flight\" : \"continuation_not_allowed\";\n}\n\nexport interface GoalLoopControllerDeps {\n\t/** Read the current goal runtime snapshot (continuation decision + goal state) fresh each pass. */\n\tgetGoalRuntimeSnapshot(settings: GoalRuntimeSnapshotSettings): GoalRuntimeSnapshot;\n\t/** Submit a continuation prompt through the session's own prompt path. */\n\tprompt(text: string, options?: PromptOptions): Promise<void>;\n\t/** Capture the append-only branch cursor immediately before a continuation prompt. */\n\tcaptureUsageCursor(): string | null;\n\t/**\n\t * Persist one submitted pass's contribution to the active goal's durable cumulative accounting\n\t * (turns + active wall-clock; USD is attributed by the implementation from the session's own\n\t * spend, not passed in here — see `AgentSession.recordGoalContinuationPass`). Called once per\n\t * pass actually SUBMITTED (never for a no-op `continueGoalOnce` call).\n\t */\n\trecordGoalContinuationPass(pass: { turns: number; wallClockMs: number; usageCursor: string | null }): void;\n\t/** Persist an exhausted/non-retryable continuation failure as a stopped goal state. */\n\trecordGoalContinuationFailure(error: unknown): void;\n\t/** Persist a reason-specific budget terminal state before returning control. */\n\tmarkGoalBudgetLimited(reason: string): void;\n}\n\nexport class GoalLoopController {\n\tprivate readonly deps: GoalLoopControllerDeps;\n\n\tconstructor(deps: GoalLoopControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tasync continueGoalOnce(options: GoalContinuationOnceOptions): Promise<GoalContinuationOnceResult> {\n\t\tconst snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns });\n\n\t\tif (snapshot.continuation.action !== \"continue\") {\n\t\t\treturn { submitted: false, snapshot };\n\t\t}\n\n\t\tconst prompt = buildGoalContinuationPrompt();\n\t\tawait this.deps.prompt(prompt.text, {\n\t\t\texpandPromptTemplates: false,\n\t\t\tprocessSlashCommands: false,\n\t\t\tautoContinueGoal: false,\n\t\t\tinternalContextType: GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE,\n\t\t});\n\n\t\treturn { submitted: true, snapshot, prompt };\n\t}\n\n\tasync continueGoalLoop(options: GoalContinuationLoopOptions): Promise<GoalContinuationLoopResult> {\n\t\tif (!Number.isSafeInteger(options.maxTurns) || options.maxTurns < 0) {\n\t\t\tthrow new Error(\"Goal continuation maxTurns must be a non-negative safe integer; 0 means unbounded.\");\n\t\t}\n\t\tlet turnsSubmitted = 0;\n\t\tconst hasExplicitTurnLimit = options.maxTurns > 0;\n\t\tconst now = options.now ?? Date.now;\n\t\tconst maxWallClockMs =\n\t\t\ttypeof options.maxWallClockMinutes === \"number\" && options.maxWallClockMinutes > 0\n\t\t\t\t? options.maxWallClockMinutes * 60_000\n\t\t\t\t: undefined;\n\t\tconst startedAt = now();\n\t\tconst hasReachedWallClockBudget = () => maxWallClockMs !== undefined && now() - startedAt >= maxWallClockMs;\n\t\tconst snapshot = () => this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns });\n\n\t\tif (hasReachedWallClockBudget()) {\n\t\t\treturn { turnsSubmitted, stopReason: \"wall_clock_budget_reached\", finalSnapshot: snapshot() };\n\t\t}\n\n\t\twhile (!hasExplicitTurnLimit || turnsSubmitted < options.maxTurns) {\n\t\t\tconst beforeSnapshot = snapshot();\n\t\t\tif (beforeSnapshot.continuation.action !== \"continue\") {\n\t\t\t\treturn { turnsSubmitted, stopReason: nonContinueStopReason(beforeSnapshot), finalSnapshot: beforeSnapshot };\n\t\t\t}\n\n\t\t\t// Owner-supplied durable token budget — read fresh every pass so an invocation stops as\n\t\t\t// soon as its own latest persisted usage crosses the explicit ceiling.\n\t\t\tconst beforeBudgetExhaustion = getExplicitGoalBudgetExhaustion(beforeSnapshot.goalState);\n\t\t\tif (beforeBudgetExhaustion) {\n\t\t\t\tthis.deps.markGoalBudgetLimited(beforeBudgetExhaustion);\n\t\t\t\treturn { turnsSubmitted, stopReason: \"goal_budget_exhausted\", finalSnapshot: snapshot() };\n\t\t\t}\n\n\t\t\tconst passStartedAt = now();\n\t\t\tconst usageCursor = this.deps.captureUsageCursor();\n\t\t\tlet result: GoalContinuationOnceResult;\n\t\t\ttry {\n\t\t\t\tresult = await this.continueGoalOnce(options);\n\t\t\t} catch (error) {\n\t\t\t\tturnsSubmitted++;\n\t\t\t\tthis.deps.recordGoalContinuationPass({ turns: 1, wallClockMs: now() - passStartedAt, usageCursor });\n\t\t\t\tthis.deps.recordGoalContinuationFailure(error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tif (result.submitted) {\n\t\t\t\tturnsSubmitted++;\n\t\t\t\tthis.deps.recordGoalContinuationPass({ turns: 1, wallClockMs: now() - passStartedAt, usageCursor });\n\t\t\t}\n\n\t\t\tif (hasReachedWallClockBudget()) {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"wall_clock_budget_reached\", finalSnapshot: snapshot() };\n\t\t\t}\n\n\t\t\tlet afterSnapshot = snapshot();\n\t\t\tconst afterBudgetExhaustion = getExplicitGoalBudgetExhaustion(afterSnapshot.goalState);\n\t\t\tif (afterBudgetExhaustion) {\n\t\t\t\tthis.deps.markGoalBudgetLimited(afterBudgetExhaustion);\n\t\t\t\tafterSnapshot = snapshot();\n\t\t\t\treturn { turnsSubmitted, stopReason: \"goal_budget_exhausted\", finalSnapshot: afterSnapshot };\n\t\t\t}\n\t\t\tif (afterSnapshot.continuation.action !== \"continue\") {\n\t\t\t\treturn { turnsSubmitted, stopReason: nonContinueStopReason(afterSnapshot), finalSnapshot: afterSnapshot };\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tturnsSubmitted,\n\t\t\tstopReason: \"max_turns_reached\",\n\t\t\tfinalSnapshot: snapshot(),\n\t\t};\n\t}\n}\n"]}
@@ -5,63 +5,25 @@
5
5
  * active goal moving" loop: each pass reads the goal runtime snapshot, and — only while the snapshot
6
6
  * says `continue` — submits one continuation prompt back through the session's own prompt path. It
7
7
  * owns no state; the goal state lives in the session log and is read fresh every pass. Termination is
8
- * fully budget-gated (per-invocation turn cap, per-invocation wall-clock cap, a DURABLE cumulative
9
- * per-goal budget — turns + active wall-clock, persisted on `GoalState` across every invocation for
10
- * the goal's lifetime — and a no-progress guard on a MEANINGFUL progress signature — satisfied-
11
- * requirement count + ref-backed evidence count — so hollow goal-tool calls (e.g. add_requirement/
12
- * reopen churn that satisfies nothing) cannot defeat the stall guard). Each submitted pass also
13
- * reports its turn/wall-clock/spend contribution back to the session via `recordGoalContinuationPass`
14
- * so the cumulative budget stays accurate.
8
+ * gated only by real terminal conditions and limits the owner explicitly supplied: an optional
9
+ * per-invocation turn cap, an optional per-invocation wall-clock cap, and an optional durable token
10
+ * budget on the goal. Each submitted pass still reports exact token/wall-clock/spend contribution
11
+ * for observability. Progress is inferred from real work and terminal goal updates; telemetry never
12
+ * becomes an implicit execution limit.
15
13
  */
16
- import { DEFAULT_GOAL_CUMULATIVE_MAX_TURNS, DEFAULT_GOAL_CUMULATIVE_MAX_WALL_CLOCK_MS, DEFAULT_GOAL_CUMULATIVE_MAX_WORKER_SPEND_USD, } from "./goals/goal-continuation-defaults.js";
17
- import { buildGoalContinuationPrompt } from "./goals/goal-continuation-prompt.js";
14
+ import { buildGoalContinuationPrompt, GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE, } from "./goals/goal-continuation-prompt.js";
18
15
  /**
19
- * Progress signature for goal-loop stall detection. Keys ONLY on state that reflects actual
20
- * progress toward the goal — `goalId`, `status`, the count of satisfied requirements, and the
21
- * count of evidence entries that carry a ref (`uri`) AND are TRUSTED: either actually validated
22
- * (`verified === true`) or `kind === "user"` (a human-confirmed claim). Deliberately excludes
23
- * `events.length`, `updatedAt`, and `stallTurns`: those change on every goal-tool call (including
24
- * no-op churn like re-adding/reopening a requirement without satisfying anything), which let hollow
25
- * passes look like progress and defeat `goal_state_not_advanced`.
26
- *
27
- * `verified` is `undefined` both for evidence that hasn't been checked yet AND for evidence kinds
28
- * that carry no checkable ref at all (`"user"`/`"finding"`/`"test"` — see the doc comment on
29
- * `GoalEvidenceRef.verified` in `goal-state.ts`). Treating "undefined" as trusted would let a model spam
30
- * `kind:"finding"` evidence with a fabricated `uri` every turn — always undefined, always counted —
31
- * which is the same class of hollow churn this signature exists to stop. So `undefined` does NOT
32
- * count; only an explicit `verified === true` (a real, checked ref) or `kind === "user"` (mirrors
33
- * the `complete` gate's trusted set in `goal-tool-core.ts`'s `isVerifiedOrUserEvidence`) counts.
34
- * `satisfiedRequirementCount` still advances the signature for legitimate-but-unverifiable work
35
- * (e.g. `kind:"finding"`/`"test"` evidence cited on a `satisfy_requirement` call), and the
36
- * continuation controller's own `stallTurns` path remains available for the model to self-report.
16
+ * Resolve an owner-supplied durable goal budget. Wall-clock and spend counters are deliberately
17
+ * absent here: they are telemetry unless the public goal contract grows matching explicit limits.
18
+ * Execution limits are policy inputs, not hidden runtime defaults.
37
19
  */
38
- function goalProgressSignature(state) {
39
- if (!state)
20
+ function getExplicitGoalBudgetExhaustion(state) {
21
+ if (!state || state.status !== "active")
40
22
  return undefined;
41
- const satisfiedRequirementCount = state.requirements.filter((requirement) => requirement.status === "satisfied").length;
42
- const refEvidenceCount = state.evidence.filter((evidence) => typeof evidence.uri === "string" &&
43
- evidence.uri.trim().length > 0 &&
44
- (evidence.verified === true || evidence.kind === "user")).length;
45
- return `${state.goalId}:${state.status}:${satisfiedRequirementCount}:${refEvidenceCount}`;
46
- }
47
- /**
48
- * Whether the goal's DURABLE cumulative continuation budget (turns and/or active wall-clock,
49
- * persisted on `GoalState` and summed across every `continueGoalLoop` invocation for the goal's
50
- * lifetime) has been exhausted. Read fresh at the top of every pass (not just the top of the
51
- * invocation), so a single long-running invocation that crosses the ceiling mid-loop stops
52
- * immediately rather than waiting for the next invocation to notice. `undefined` counters (goal
53
- * state predating this field, or a fresh goal) count as `0` — never exhausted.
54
- */
55
- function isGoalContinuationBudgetExhausted(state) {
56
- if (!state)
57
- return false;
58
- if ((state.continuationTurnsUsed ?? 0) >= DEFAULT_GOAL_CUMULATIVE_MAX_TURNS)
59
- return true;
60
- if ((state.continuationWallClockMs ?? 0) >= DEFAULT_GOAL_CUMULATIVE_MAX_WALL_CLOCK_MS)
61
- return true;
62
- if ((state.continuationWorkerSpendUsd ?? 0) >= DEFAULT_GOAL_CUMULATIVE_MAX_WORKER_SPEND_USD)
63
- return true;
64
- return false;
23
+ if (state.tokenBudget !== undefined && (state.tokensUsed ?? 0) >= state.tokenBudget) {
24
+ return `token budget exhausted (${state.tokensUsed ?? 0}/${state.tokenBudget})`;
25
+ }
26
+ return undefined;
65
27
  }
66
28
  /**
67
29
  * Maps a non-"continue" continuation action onto the loop's own stopReason vocabulary.
@@ -84,16 +46,21 @@ export class GoalLoopController {
84
46
  if (snapshot.continuation.action !== "continue") {
85
47
  return { submitted: false, snapshot };
86
48
  }
87
- const prompt = buildGoalContinuationPrompt({ snapshot, limits: options.promptLimits });
49
+ const prompt = buildGoalContinuationPrompt();
88
50
  await this.deps.prompt(prompt.text, {
89
51
  expandPromptTemplates: false,
90
52
  processSlashCommands: false,
91
53
  autoContinueGoal: false,
54
+ internalContextType: GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE,
92
55
  });
93
56
  return { submitted: true, snapshot, prompt };
94
57
  }
95
58
  async continueGoalLoop(options) {
59
+ if (!Number.isSafeInteger(options.maxTurns) || options.maxTurns < 0) {
60
+ throw new Error("Goal continuation maxTurns must be a non-negative safe integer; 0 means unbounded.");
61
+ }
96
62
  let turnsSubmitted = 0;
63
+ const hasExplicitTurnLimit = options.maxTurns > 0;
97
64
  const now = options.now ?? Date.now;
98
65
  const maxWallClockMs = typeof options.maxWallClockMinutes === "number" && options.maxWallClockMinutes > 0
99
66
  ? options.maxWallClockMinutes * 60_000
@@ -101,45 +68,50 @@ export class GoalLoopController {
101
68
  const startedAt = now();
102
69
  const hasReachedWallClockBudget = () => maxWallClockMs !== undefined && now() - startedAt >= maxWallClockMs;
103
70
  const snapshot = () => this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns });
104
- if (options.maxTurns <= 0) {
105
- return {
106
- turnsSubmitted: 0,
107
- stopReason: "max_turns_reached",
108
- finalSnapshot: snapshot(),
109
- };
110
- }
111
71
  if (hasReachedWallClockBudget()) {
112
72
  return { turnsSubmitted, stopReason: "wall_clock_budget_reached", finalSnapshot: snapshot() };
113
73
  }
114
- while (turnsSubmitted < options.maxTurns) {
74
+ while (!hasExplicitTurnLimit || turnsSubmitted < options.maxTurns) {
115
75
  const beforeSnapshot = snapshot();
116
76
  if (beforeSnapshot.continuation.action !== "continue") {
117
77
  return { turnsSubmitted, stopReason: nonContinueStopReason(beforeSnapshot), finalSnapshot: beforeSnapshot };
118
78
  }
119
- // Cumulative (durable, cross-invocation) budget — read fresh every pass, not just at the top
120
- // of this invocation, so a single long-running call still stops the moment it crosses the
121
- // ceiling rather than overshooting until the next invocation notices.
122
- if (isGoalContinuationBudgetExhausted(beforeSnapshot.goalState)) {
123
- return { turnsSubmitted, stopReason: "goal_budget_exhausted", finalSnapshot: beforeSnapshot };
79
+ // Owner-supplied durable token budget — read fresh every pass so an invocation stops as
80
+ // soon as its own latest persisted usage crosses the explicit ceiling.
81
+ const beforeBudgetExhaustion = getExplicitGoalBudgetExhaustion(beforeSnapshot.goalState);
82
+ if (beforeBudgetExhaustion) {
83
+ this.deps.markGoalBudgetLimited(beforeBudgetExhaustion);
84
+ return { turnsSubmitted, stopReason: "goal_budget_exhausted", finalSnapshot: snapshot() };
124
85
  }
125
- const beforeKey = goalProgressSignature(beforeSnapshot.goalState);
126
86
  const passStartedAt = now();
127
- const result = await this.continueGoalOnce(options);
87
+ const usageCursor = this.deps.captureUsageCursor();
88
+ let result;
89
+ try {
90
+ result = await this.continueGoalOnce(options);
91
+ }
92
+ catch (error) {
93
+ turnsSubmitted++;
94
+ this.deps.recordGoalContinuationPass({ turns: 1, wallClockMs: now() - passStartedAt, usageCursor });
95
+ this.deps.recordGoalContinuationFailure(error);
96
+ throw error;
97
+ }
128
98
  if (result.submitted) {
129
99
  turnsSubmitted++;
130
- this.deps.recordGoalContinuationPass({ turns: 1, wallClockMs: now() - passStartedAt });
100
+ this.deps.recordGoalContinuationPass({ turns: 1, wallClockMs: now() - passStartedAt, usageCursor });
131
101
  }
132
102
  if (hasReachedWallClockBudget()) {
133
103
  return { turnsSubmitted, stopReason: "wall_clock_budget_reached", finalSnapshot: snapshot() };
134
104
  }
135
- const afterSnapshot = snapshot();
105
+ let afterSnapshot = snapshot();
106
+ const afterBudgetExhaustion = getExplicitGoalBudgetExhaustion(afterSnapshot.goalState);
107
+ if (afterBudgetExhaustion) {
108
+ this.deps.markGoalBudgetLimited(afterBudgetExhaustion);
109
+ afterSnapshot = snapshot();
110
+ return { turnsSubmitted, stopReason: "goal_budget_exhausted", finalSnapshot: afterSnapshot };
111
+ }
136
112
  if (afterSnapshot.continuation.action !== "continue") {
137
113
  return { turnsSubmitted, stopReason: nonContinueStopReason(afterSnapshot), finalSnapshot: afterSnapshot };
138
114
  }
139
- const afterKey = goalProgressSignature(afterSnapshot.goalState);
140
- if (beforeKey === afterKey) {
141
- return { turnsSubmitted, stopReason: "goal_state_not_advanced", finalSnapshot: afterSnapshot };
142
- }
143
115
  }
144
116
  return {
145
117
  turnsSubmitted,
@@ -1 +1 @@
1
- {"version":3,"file":"goal-loop-controller.js","sourceRoot":"","sources":["../../src/core/goal-loop-controller.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Goal auto-continuation loop.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Drives the bounded \"keep the\n * active goal moving\" loop: each pass reads the goal runtime snapshot, and — only while the snapshot\n * says `continue` — submits one continuation prompt back through the session's own prompt path. It\n * owns no state; the goal state lives in the session log and is read fresh every pass. Termination is\n * fully budget-gated (per-invocation turn cap, per-invocation wall-clock cap, a DURABLE cumulative\n * per-goal budget — turns + active wall-clock, persisted on `GoalState` across every invocation for\n * the goal's lifetime — and a no-progress guard on a MEANINGFUL progress signature — satisfied-\n * requirement count + ref-backed evidence count — so hollow goal-tool calls (e.g. add_requirement/\n * reopen churn that satisfies nothing) cannot defeat the stall guard). Each submitted pass also\n * reports its turn/wall-clock/spend contribution back to the session via `recordGoalContinuationPass`\n * so the cumulative budget stays accurate.\n */\n\nimport type {\n\tGoalContinuationLoopOptions,\n\tGoalContinuationLoopResult,\n\tGoalContinuationLoopStopReason,\n\tGoalContinuationOnceOptions,\n\tGoalContinuationOnceResult,\n\tPromptOptions,\n} from \"./agent-session.ts\";\nimport {\n\tDEFAULT_GOAL_CUMULATIVE_MAX_TURNS,\n\tDEFAULT_GOAL_CUMULATIVE_MAX_WALL_CLOCK_MS,\n\tDEFAULT_GOAL_CUMULATIVE_MAX_WORKER_SPEND_USD,\n} from \"./goals/goal-continuation-defaults.ts\";\nimport { buildGoalContinuationPrompt } from \"./goals/goal-continuation-prompt.ts\";\nimport type { GoalRuntimeSnapshot, GoalRuntimeSnapshotSettings } from \"./goals/goal-runtime-snapshot.ts\";\nimport type { GoalState } from \"./goals/goal-state.ts\";\n\n/**\n * Progress signature for goal-loop stall detection. Keys ONLY on state that reflects actual\n * progress toward the goal — `goalId`, `status`, the count of satisfied requirements, and the\n * count of evidence entries that carry a ref (`uri`) AND are TRUSTED: either actually validated\n * (`verified === true`) or `kind === \"user\"` (a human-confirmed claim). Deliberately excludes\n * `events.length`, `updatedAt`, and `stallTurns`: those change on every goal-tool call (including\n * no-op churn like re-adding/reopening a requirement without satisfying anything), which let hollow\n * passes look like progress and defeat `goal_state_not_advanced`.\n *\n * `verified` is `undefined` both for evidence that hasn't been checked yet AND for evidence kinds\n * that carry no checkable ref at all (`\"user\"`/`\"finding\"`/`\"test\"` — see the doc comment on\n * `GoalEvidenceRef.verified` in `goal-state.ts`). Treating \"undefined\" as trusted would let a model spam\n * `kind:\"finding\"` evidence with a fabricated `uri` every turn — always undefined, always counted —\n * which is the same class of hollow churn this signature exists to stop. So `undefined` does NOT\n * count; only an explicit `verified === true` (a real, checked ref) or `kind === \"user\"` (mirrors\n * the `complete` gate's trusted set in `goal-tool-core.ts`'s `isVerifiedOrUserEvidence`) counts.\n * `satisfiedRequirementCount` still advances the signature for legitimate-but-unverifiable work\n * (e.g. `kind:\"finding\"`/`\"test\"` evidence cited on a `satisfy_requirement` call), and the\n * continuation controller's own `stallTurns` path remains available for the model to self-report.\n */\nfunction goalProgressSignature(state: GoalState | undefined): string | undefined {\n\tif (!state) return undefined;\n\tconst satisfiedRequirementCount = state.requirements.filter(\n\t\t(requirement) => requirement.status === \"satisfied\",\n\t).length;\n\tconst refEvidenceCount = state.evidence.filter(\n\t\t(evidence) =>\n\t\t\ttypeof evidence.uri === \"string\" &&\n\t\t\tevidence.uri.trim().length > 0 &&\n\t\t\t(evidence.verified === true || evidence.kind === \"user\"),\n\t).length;\n\treturn `${state.goalId}:${state.status}:${satisfiedRequirementCount}:${refEvidenceCount}`;\n}\n\n/**\n * Whether the goal's DURABLE cumulative continuation budget (turns and/or active wall-clock,\n * persisted on `GoalState` and summed across every `continueGoalLoop` invocation for the goal's\n * lifetime) has been exhausted. Read fresh at the top of every pass (not just the top of the\n * invocation), so a single long-running invocation that crosses the ceiling mid-loop stops\n * immediately rather than waiting for the next invocation to notice. `undefined` counters (goal\n * state predating this field, or a fresh goal) count as `0` — never exhausted.\n */\nfunction isGoalContinuationBudgetExhausted(state: GoalState | undefined): boolean {\n\tif (!state) return false;\n\tif ((state.continuationTurnsUsed ?? 0) >= DEFAULT_GOAL_CUMULATIVE_MAX_TURNS) return true;\n\tif ((state.continuationWallClockMs ?? 0) >= DEFAULT_GOAL_CUMULATIVE_MAX_WALL_CLOCK_MS) return true;\n\tif ((state.continuationWorkerSpendUsd ?? 0) >= DEFAULT_GOAL_CUMULATIVE_MAX_WORKER_SPEND_USD) return true;\n\treturn false;\n}\n\n/**\n * Maps a non-\"continue\" continuation action onto the loop's own stopReason vocabulary.\n * `\"waiting\"` (a worker is dispatched against an open requirement) gets its OWN benign stopReason so\n * a wait is never misreported as `continuation_not_allowed` (which reads as a terminal refusal) —\n * callers/telemetry can tell \"paused, will resume on its own\" apart from \"stopped, needs a human or a\n * new decision.\" Every other non-continue action (ask-user/finalize/stop) keeps the existing\n * `continuation_not_allowed` stopReason unchanged.\n */\nfunction nonContinueStopReason(snapshot: GoalRuntimeSnapshot): GoalContinuationLoopStopReason {\n\treturn snapshot.continuation.action === \"waiting\" ? \"worker_in_flight\" : \"continuation_not_allowed\";\n}\n\nexport interface GoalLoopControllerDeps {\n\t/** Read the current goal runtime snapshot (continuation decision + goal state) fresh each pass. */\n\tgetGoalRuntimeSnapshot(settings: GoalRuntimeSnapshotSettings): GoalRuntimeSnapshot;\n\t/** Submit a continuation prompt through the session's own prompt path. */\n\tprompt(text: string, options?: PromptOptions): Promise<void>;\n\t/**\n\t * Persist one submitted pass's contribution to the active goal's durable cumulative budget\n\t * (turns + active wall-clock; USD is attributed by the implementation from the session's own\n\t * spend, not passed in here — see `AgentSession.recordGoalContinuationPass`). Called once per\n\t * pass actually SUBMITTED (never for a no-op `continueGoalOnce` call).\n\t */\n\trecordGoalContinuationPass(pass: { turns: number; wallClockMs: number }): void;\n}\n\nexport class GoalLoopController {\n\tprivate readonly deps: GoalLoopControllerDeps;\n\n\tconstructor(deps: GoalLoopControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tasync continueGoalOnce(options: GoalContinuationOnceOptions): Promise<GoalContinuationOnceResult> {\n\t\tconst snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns });\n\n\t\tif (snapshot.continuation.action !== \"continue\") {\n\t\t\treturn { submitted: false, snapshot };\n\t\t}\n\n\t\tconst prompt = buildGoalContinuationPrompt({ snapshot, limits: options.promptLimits });\n\t\tawait this.deps.prompt(prompt.text, {\n\t\t\texpandPromptTemplates: false,\n\t\t\tprocessSlashCommands: false,\n\t\t\tautoContinueGoal: false,\n\t\t});\n\n\t\treturn { submitted: true, snapshot, prompt };\n\t}\n\n\tasync continueGoalLoop(options: GoalContinuationLoopOptions): Promise<GoalContinuationLoopResult> {\n\t\tlet turnsSubmitted = 0;\n\t\tconst now = options.now ?? Date.now;\n\t\tconst maxWallClockMs =\n\t\t\ttypeof options.maxWallClockMinutes === \"number\" && options.maxWallClockMinutes > 0\n\t\t\t\t? options.maxWallClockMinutes * 60_000\n\t\t\t\t: undefined;\n\t\tconst startedAt = now();\n\t\tconst hasReachedWallClockBudget = () => maxWallClockMs !== undefined && now() - startedAt >= maxWallClockMs;\n\t\tconst snapshot = () => this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns });\n\n\t\tif (options.maxTurns <= 0) {\n\t\t\treturn {\n\t\t\t\tturnsSubmitted: 0,\n\t\t\t\tstopReason: \"max_turns_reached\",\n\t\t\t\tfinalSnapshot: snapshot(),\n\t\t\t};\n\t\t}\n\n\t\tif (hasReachedWallClockBudget()) {\n\t\t\treturn { turnsSubmitted, stopReason: \"wall_clock_budget_reached\", finalSnapshot: snapshot() };\n\t\t}\n\n\t\twhile (turnsSubmitted < options.maxTurns) {\n\t\t\tconst beforeSnapshot = snapshot();\n\t\t\tif (beforeSnapshot.continuation.action !== \"continue\") {\n\t\t\t\treturn { turnsSubmitted, stopReason: nonContinueStopReason(beforeSnapshot), finalSnapshot: beforeSnapshot };\n\t\t\t}\n\n\t\t\t// Cumulative (durable, cross-invocation) budget — read fresh every pass, not just at the top\n\t\t\t// of this invocation, so a single long-running call still stops the moment it crosses the\n\t\t\t// ceiling rather than overshooting until the next invocation notices.\n\t\t\tif (isGoalContinuationBudgetExhausted(beforeSnapshot.goalState)) {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"goal_budget_exhausted\", finalSnapshot: beforeSnapshot };\n\t\t\t}\n\n\t\t\tconst beforeKey = goalProgressSignature(beforeSnapshot.goalState);\n\n\t\t\tconst passStartedAt = now();\n\t\t\tconst result = await this.continueGoalOnce(options);\n\t\t\tif (result.submitted) {\n\t\t\t\tturnsSubmitted++;\n\t\t\t\tthis.deps.recordGoalContinuationPass({ turns: 1, wallClockMs: now() - passStartedAt });\n\t\t\t}\n\n\t\t\tif (hasReachedWallClockBudget()) {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"wall_clock_budget_reached\", finalSnapshot: snapshot() };\n\t\t\t}\n\n\t\t\tconst afterSnapshot = snapshot();\n\t\t\tif (afterSnapshot.continuation.action !== \"continue\") {\n\t\t\t\treturn { turnsSubmitted, stopReason: nonContinueStopReason(afterSnapshot), finalSnapshot: afterSnapshot };\n\t\t\t}\n\n\t\t\tconst afterKey = goalProgressSignature(afterSnapshot.goalState);\n\n\t\t\tif (beforeKey === afterKey) {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"goal_state_not_advanced\", finalSnapshot: afterSnapshot };\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tturnsSubmitted,\n\t\t\tstopReason: \"max_turns_reached\",\n\t\t\tfinalSnapshot: snapshot(),\n\t\t};\n\t}\n}\n"]}
1
+ {"version":3,"file":"goal-loop-controller.js","sourceRoot":"","sources":["../../src/core/goal-loop-controller.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Goal auto-continuation loop.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Drives the bounded \"keep the\n * active goal moving\" loop: each pass reads the goal runtime snapshot, and — only while the snapshot\n * says `continue` — submits one continuation prompt back through the session's own prompt path. It\n * owns no state; the goal state lives in the session log and is read fresh every pass. Termination is\n * gated only by real terminal conditions and limits the owner explicitly supplied: an optional\n * per-invocation turn cap, an optional per-invocation wall-clock cap, and an optional durable token\n * budget on the goal. Each submitted pass still reports exact token/wall-clock/spend contribution\n * for observability. Progress is inferred from real work and terminal goal updates; telemetry never\n * becomes an implicit execution limit.\n */\n\nimport type {\n\tGoalContinuationLoopOptions,\n\tGoalContinuationLoopResult,\n\tGoalContinuationLoopStopReason,\n\tGoalContinuationOnceOptions,\n\tGoalContinuationOnceResult,\n\tPromptOptions,\n} from \"./agent-session-contracts.ts\";\nimport {\n\tbuildGoalContinuationPrompt,\n\tGOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE,\n} from \"./goals/goal-continuation-prompt.ts\";\nimport type { GoalRuntimeSnapshot, GoalRuntimeSnapshotSettings } from \"./goals/goal-runtime-snapshot.ts\";\nimport type { GoalState } from \"./goals/goal-state.ts\";\n\n/**\n * Resolve an owner-supplied durable goal budget. Wall-clock and spend counters are deliberately\n * absent here: they are telemetry unless the public goal contract grows matching explicit limits.\n * Execution limits are policy inputs, not hidden runtime defaults.\n */\nfunction getExplicitGoalBudgetExhaustion(state: GoalState | undefined): string | undefined {\n\tif (!state || state.status !== \"active\") return undefined;\n\tif (state.tokenBudget !== undefined && (state.tokensUsed ?? 0) >= state.tokenBudget) {\n\t\treturn `token budget exhausted (${state.tokensUsed ?? 0}/${state.tokenBudget})`;\n\t}\n\treturn undefined;\n}\n\n/**\n * Maps a non-\"continue\" continuation action onto the loop's own stopReason vocabulary.\n * `\"waiting\"` (a worker is dispatched against an open requirement) gets its OWN benign stopReason so\n * a wait is never misreported as `continuation_not_allowed` (which reads as a terminal refusal) —\n * callers/telemetry can tell \"paused, will resume on its own\" apart from \"stopped, needs a human or a\n * new decision.\" Every other non-continue action (ask-user/finalize/stop) keeps the existing\n * `continuation_not_allowed` stopReason unchanged.\n */\nfunction nonContinueStopReason(snapshot: GoalRuntimeSnapshot): GoalContinuationLoopStopReason {\n\treturn snapshot.continuation.action === \"waiting\" ? \"worker_in_flight\" : \"continuation_not_allowed\";\n}\n\nexport interface GoalLoopControllerDeps {\n\t/** Read the current goal runtime snapshot (continuation decision + goal state) fresh each pass. */\n\tgetGoalRuntimeSnapshot(settings: GoalRuntimeSnapshotSettings): GoalRuntimeSnapshot;\n\t/** Submit a continuation prompt through the session's own prompt path. */\n\tprompt(text: string, options?: PromptOptions): Promise<void>;\n\t/** Capture the append-only branch cursor immediately before a continuation prompt. */\n\tcaptureUsageCursor(): string | null;\n\t/**\n\t * Persist one submitted pass's contribution to the active goal's durable cumulative accounting\n\t * (turns + active wall-clock; USD is attributed by the implementation from the session's own\n\t * spend, not passed in here — see `AgentSession.recordGoalContinuationPass`). Called once per\n\t * pass actually SUBMITTED (never for a no-op `continueGoalOnce` call).\n\t */\n\trecordGoalContinuationPass(pass: { turns: number; wallClockMs: number; usageCursor: string | null }): void;\n\t/** Persist an exhausted/non-retryable continuation failure as a stopped goal state. */\n\trecordGoalContinuationFailure(error: unknown): void;\n\t/** Persist a reason-specific budget terminal state before returning control. */\n\tmarkGoalBudgetLimited(reason: string): void;\n}\n\nexport class GoalLoopController {\n\tprivate readonly deps: GoalLoopControllerDeps;\n\n\tconstructor(deps: GoalLoopControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tasync continueGoalOnce(options: GoalContinuationOnceOptions): Promise<GoalContinuationOnceResult> {\n\t\tconst snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns });\n\n\t\tif (snapshot.continuation.action !== \"continue\") {\n\t\t\treturn { submitted: false, snapshot };\n\t\t}\n\n\t\tconst prompt = buildGoalContinuationPrompt();\n\t\tawait this.deps.prompt(prompt.text, {\n\t\t\texpandPromptTemplates: false,\n\t\t\tprocessSlashCommands: false,\n\t\t\tautoContinueGoal: false,\n\t\t\tinternalContextType: GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE,\n\t\t});\n\n\t\treturn { submitted: true, snapshot, prompt };\n\t}\n\n\tasync continueGoalLoop(options: GoalContinuationLoopOptions): Promise<GoalContinuationLoopResult> {\n\t\tif (!Number.isSafeInteger(options.maxTurns) || options.maxTurns < 0) {\n\t\t\tthrow new Error(\"Goal continuation maxTurns must be a non-negative safe integer; 0 means unbounded.\");\n\t\t}\n\t\tlet turnsSubmitted = 0;\n\t\tconst hasExplicitTurnLimit = options.maxTurns > 0;\n\t\tconst now = options.now ?? Date.now;\n\t\tconst maxWallClockMs =\n\t\t\ttypeof options.maxWallClockMinutes === \"number\" && options.maxWallClockMinutes > 0\n\t\t\t\t? options.maxWallClockMinutes * 60_000\n\t\t\t\t: undefined;\n\t\tconst startedAt = now();\n\t\tconst hasReachedWallClockBudget = () => maxWallClockMs !== undefined && now() - startedAt >= maxWallClockMs;\n\t\tconst snapshot = () => this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns });\n\n\t\tif (hasReachedWallClockBudget()) {\n\t\t\treturn { turnsSubmitted, stopReason: \"wall_clock_budget_reached\", finalSnapshot: snapshot() };\n\t\t}\n\n\t\twhile (!hasExplicitTurnLimit || turnsSubmitted < options.maxTurns) {\n\t\t\tconst beforeSnapshot = snapshot();\n\t\t\tif (beforeSnapshot.continuation.action !== \"continue\") {\n\t\t\t\treturn { turnsSubmitted, stopReason: nonContinueStopReason(beforeSnapshot), finalSnapshot: beforeSnapshot };\n\t\t\t}\n\n\t\t\t// Owner-supplied durable token budget — read fresh every pass so an invocation stops as\n\t\t\t// soon as its own latest persisted usage crosses the explicit ceiling.\n\t\t\tconst beforeBudgetExhaustion = getExplicitGoalBudgetExhaustion(beforeSnapshot.goalState);\n\t\t\tif (beforeBudgetExhaustion) {\n\t\t\t\tthis.deps.markGoalBudgetLimited(beforeBudgetExhaustion);\n\t\t\t\treturn { turnsSubmitted, stopReason: \"goal_budget_exhausted\", finalSnapshot: snapshot() };\n\t\t\t}\n\n\t\t\tconst passStartedAt = now();\n\t\t\tconst usageCursor = this.deps.captureUsageCursor();\n\t\t\tlet result: GoalContinuationOnceResult;\n\t\t\ttry {\n\t\t\t\tresult = await this.continueGoalOnce(options);\n\t\t\t} catch (error) {\n\t\t\t\tturnsSubmitted++;\n\t\t\t\tthis.deps.recordGoalContinuationPass({ turns: 1, wallClockMs: now() - passStartedAt, usageCursor });\n\t\t\t\tthis.deps.recordGoalContinuationFailure(error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tif (result.submitted) {\n\t\t\t\tturnsSubmitted++;\n\t\t\t\tthis.deps.recordGoalContinuationPass({ turns: 1, wallClockMs: now() - passStartedAt, usageCursor });\n\t\t\t}\n\n\t\t\tif (hasReachedWallClockBudget()) {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"wall_clock_budget_reached\", finalSnapshot: snapshot() };\n\t\t\t}\n\n\t\t\tlet afterSnapshot = snapshot();\n\t\t\tconst afterBudgetExhaustion = getExplicitGoalBudgetExhaustion(afterSnapshot.goalState);\n\t\t\tif (afterBudgetExhaustion) {\n\t\t\t\tthis.deps.markGoalBudgetLimited(afterBudgetExhaustion);\n\t\t\t\tafterSnapshot = snapshot();\n\t\t\t\treturn { turnsSubmitted, stopReason: \"goal_budget_exhausted\", finalSnapshot: afterSnapshot };\n\t\t\t}\n\t\t\tif (afterSnapshot.continuation.action !== \"continue\") {\n\t\t\t\treturn { turnsSubmitted, stopReason: nonContinueStopReason(afterSnapshot), finalSnapshot: afterSnapshot };\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tturnsSubmitted,\n\t\t\tstopReason: \"max_turns_reached\",\n\t\t\tfinalSnapshot: snapshot(),\n\t\t};\n\t}\n}\n"]}
@@ -0,0 +1,11 @@
1
+ import { type AgentMessage } from "@caupulican/pi-agent-core";
2
+ import type { GoalState } from "./goal-state.ts";
3
+ export declare const ACTIVE_GOAL_CONTEXT_CUSTOM_TYPE = "active_goal_context";
4
+ export declare function formatCompactGoalContext(state: GoalState, continuationTurn: boolean): string;
5
+ /**
6
+ * Replace every historical goal continuation payload with one current compact projection. The
7
+ * projection exists only in the provider request returned from context assembly; it is never
8
+ * appended to the transcript or session log.
9
+ */
10
+ export declare function injectCompactGoalContext(messages: AgentMessage[], state: GoalState | undefined): AgentMessage[];
11
+ //# sourceMappingURL=compact-goal-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compact-goal-context.d.ts","sourceRoot":"","sources":["../../../src/core/goals/compact-goal-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAuB,MAAM,2BAA2B,CAAC;AAInF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,eAAO,MAAM,+BAA+B,wBAAwB,CAAC;AA0BrE,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,GAAG,MAAM,CAgB5F;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,EAAE,CAkB/G","sourcesContent":["import { type AgentMessage, createCustomMessage } from \"@caupulican/pi-agent-core\";\nimport type { TextContent } from \"@caupulican/pi-ai\";\nimport { GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE } from \"./goal-continuation-prompt.ts\";\nimport { projectGoalRecord } from \"./goal-record.ts\";\nimport type { GoalState } from \"./goal-state.ts\";\n\nexport const ACTIVE_GOAL_CONTEXT_CUSTOM_TYPE = \"active_goal_context\";\nconst LEGACY_GOAL_CONTINUATION_PREFIX = \"Goal continuation context\\n=========================\";\n\nfunction messageText(message: AgentMessage): string {\n\tif (message.role !== \"user\") return \"\";\n\tif (typeof message.content === \"string\") return message.content;\n\treturn message.content\n\t\t.filter((part): part is TextContent => part.type === \"text\")\n\t\t.map((part) => part.text)\n\t\t.join(\"\\n\");\n}\n\nfunction isGoalContextMessage(message: AgentMessage): boolean {\n\tif (message.role === \"custom\") {\n\t\treturn (\n\t\t\tmessage.customType === GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE ||\n\t\t\tmessage.customType === ACTIVE_GOAL_CONTEXT_CUSTOM_TYPE\n\t\t);\n\t}\n\treturn messageText(message).startsWith(LEGACY_GOAL_CONTINUATION_PREFIX);\n}\n\nfunction escapeXmlText(value: string): string {\n\treturn value.replaceAll(\"&\", \"&amp;\").replaceAll(\"<\", \"&lt;\").replaceAll(\">\", \"&gt;\");\n}\n\nexport function formatCompactGoalContext(state: GoalState, continuationTurn: boolean): string {\n\tconst record = projectGoalRecord(state);\n\tconst budgetText = record.tokenBudget === undefined ? \"unbounded\" : String(record.tokenBudget);\n\tconst remainingText = record.tokensRemaining === undefined ? \"unbounded\" : String(record.tokensRemaining);\n\tconst instruction = continuationTurn\n\t\t? \"Continue now: inspect authoritative current state and make concrete progress toward the full objective.\"\n\t\t: \"This objective persists across turns; the current user message controls immediate steering without replacing it.\";\n\treturn [\n\t\t`<active_goal tokens_used=\"${record.tokensUsed}\" token_budget=\"${budgetText}\" tokens_remaining=\"${remainingText}\">`,\n\t\t\"<objective>\",\n\t\tescapeXmlText(record.objective),\n\t\t\"</objective>\",\n\t\tinstruction,\n\t\t\"Use task_steps for decomposition, delegate for workers, and current tool/artifact results as evidence. Keep the goal active unless completion is proven or the same genuine blocker persists for three goal turns.\",\n\t\t\"</active_goal>\",\n\t].join(\"\\n\");\n}\n\n/**\n * Replace every historical goal continuation payload with one current compact projection. The\n * projection exists only in the provider request returned from context assembly; it is never\n * appended to the transcript or session log.\n */\nexport function injectCompactGoalContext(messages: AgentMessage[], state: GoalState | undefined): AgentMessage[] {\n\tconst continuationTurn = messages.some(\n\t\t(message) =>\n\t\t\t(message.role === \"custom\" && message.customType === GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE) ||\n\t\t\tmessageText(message).startsWith(LEGACY_GOAL_CONTINUATION_PREFIX),\n\t);\n\tconst filtered = messages.filter((message) => !isGoalContextMessage(message));\n\tif (!state || state.status !== \"active\") return filtered;\n\treturn [\n\t\t...filtered,\n\t\tcreateCustomMessage(\n\t\t\tACTIVE_GOAL_CONTEXT_CUSTOM_TYPE,\n\t\t\tformatCompactGoalContext(state, continuationTurn),\n\t\t\tfalse,\n\t\t\t{ goalId: state.goalId, revision: state.revision ?? 0 },\n\t\t\tnew Date().toISOString(),\n\t\t),\n\t];\n}\n"]}
@@ -0,0 +1,59 @@
1
+ import { createCustomMessage } from "@caupulican/pi-agent-core";
2
+ import { GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE } from "./goal-continuation-prompt.js";
3
+ import { projectGoalRecord } from "./goal-record.js";
4
+ export const ACTIVE_GOAL_CONTEXT_CUSTOM_TYPE = "active_goal_context";
5
+ const LEGACY_GOAL_CONTINUATION_PREFIX = "Goal continuation context\n=========================";
6
+ function messageText(message) {
7
+ if (message.role !== "user")
8
+ return "";
9
+ if (typeof message.content === "string")
10
+ return message.content;
11
+ return message.content
12
+ .filter((part) => part.type === "text")
13
+ .map((part) => part.text)
14
+ .join("\n");
15
+ }
16
+ function isGoalContextMessage(message) {
17
+ if (message.role === "custom") {
18
+ return (message.customType === GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE ||
19
+ message.customType === ACTIVE_GOAL_CONTEXT_CUSTOM_TYPE);
20
+ }
21
+ return messageText(message).startsWith(LEGACY_GOAL_CONTINUATION_PREFIX);
22
+ }
23
+ function escapeXmlText(value) {
24
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
25
+ }
26
+ export function formatCompactGoalContext(state, continuationTurn) {
27
+ const record = projectGoalRecord(state);
28
+ const budgetText = record.tokenBudget === undefined ? "unbounded" : String(record.tokenBudget);
29
+ const remainingText = record.tokensRemaining === undefined ? "unbounded" : String(record.tokensRemaining);
30
+ const instruction = continuationTurn
31
+ ? "Continue now: inspect authoritative current state and make concrete progress toward the full objective."
32
+ : "This objective persists across turns; the current user message controls immediate steering without replacing it.";
33
+ return [
34
+ `<active_goal tokens_used="${record.tokensUsed}" token_budget="${budgetText}" tokens_remaining="${remainingText}">`,
35
+ "<objective>",
36
+ escapeXmlText(record.objective),
37
+ "</objective>",
38
+ instruction,
39
+ "Use task_steps for decomposition, delegate for workers, and current tool/artifact results as evidence. Keep the goal active unless completion is proven or the same genuine blocker persists for three goal turns.",
40
+ "</active_goal>",
41
+ ].join("\n");
42
+ }
43
+ /**
44
+ * Replace every historical goal continuation payload with one current compact projection. The
45
+ * projection exists only in the provider request returned from context assembly; it is never
46
+ * appended to the transcript or session log.
47
+ */
48
+ export function injectCompactGoalContext(messages, state) {
49
+ const continuationTurn = messages.some((message) => (message.role === "custom" && message.customType === GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE) ||
50
+ messageText(message).startsWith(LEGACY_GOAL_CONTINUATION_PREFIX));
51
+ const filtered = messages.filter((message) => !isGoalContextMessage(message));
52
+ if (!state || state.status !== "active")
53
+ return filtered;
54
+ return [
55
+ ...filtered,
56
+ createCustomMessage(ACTIVE_GOAL_CONTEXT_CUSTOM_TYPE, formatCompactGoalContext(state, continuationTurn), false, { goalId: state.goalId, revision: state.revision ?? 0 }, new Date().toISOString()),
57
+ ];
58
+ }
59
+ //# sourceMappingURL=compact-goal-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compact-goal-context.js","sourceRoot":"","sources":["../../../src/core/goals/compact-goal-context.ts"],"names":[],"mappings":"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","sourcesContent":["import { type AgentMessage, createCustomMessage } from \"@caupulican/pi-agent-core\";\nimport type { TextContent } from \"@caupulican/pi-ai\";\nimport { GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE } from \"./goal-continuation-prompt.ts\";\nimport { projectGoalRecord } from \"./goal-record.ts\";\nimport type { GoalState } from \"./goal-state.ts\";\n\nexport const ACTIVE_GOAL_CONTEXT_CUSTOM_TYPE = \"active_goal_context\";\nconst LEGACY_GOAL_CONTINUATION_PREFIX = \"Goal continuation context\\n=========================\";\n\nfunction messageText(message: AgentMessage): string {\n\tif (message.role !== \"user\") return \"\";\n\tif (typeof message.content === \"string\") return message.content;\n\treturn message.content\n\t\t.filter((part): part is TextContent => part.type === \"text\")\n\t\t.map((part) => part.text)\n\t\t.join(\"\\n\");\n}\n\nfunction isGoalContextMessage(message: AgentMessage): boolean {\n\tif (message.role === \"custom\") {\n\t\treturn (\n\t\t\tmessage.customType === GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE ||\n\t\t\tmessage.customType === ACTIVE_GOAL_CONTEXT_CUSTOM_TYPE\n\t\t);\n\t}\n\treturn messageText(message).startsWith(LEGACY_GOAL_CONTINUATION_PREFIX);\n}\n\nfunction escapeXmlText(value: string): string {\n\treturn value.replaceAll(\"&\", \"&amp;\").replaceAll(\"<\", \"&lt;\").replaceAll(\">\", \"&gt;\");\n}\n\nexport function formatCompactGoalContext(state: GoalState, continuationTurn: boolean): string {\n\tconst record = projectGoalRecord(state);\n\tconst budgetText = record.tokenBudget === undefined ? \"unbounded\" : String(record.tokenBudget);\n\tconst remainingText = record.tokensRemaining === undefined ? \"unbounded\" : String(record.tokensRemaining);\n\tconst instruction = continuationTurn\n\t\t? \"Continue now: inspect authoritative current state and make concrete progress toward the full objective.\"\n\t\t: \"This objective persists across turns; the current user message controls immediate steering without replacing it.\";\n\treturn [\n\t\t`<active_goal tokens_used=\"${record.tokensUsed}\" token_budget=\"${budgetText}\" tokens_remaining=\"${remainingText}\">`,\n\t\t\"<objective>\",\n\t\tescapeXmlText(record.objective),\n\t\t\"</objective>\",\n\t\tinstruction,\n\t\t\"Use task_steps for decomposition, delegate for workers, and current tool/artifact results as evidence. Keep the goal active unless completion is proven or the same genuine blocker persists for three goal turns.\",\n\t\t\"</active_goal>\",\n\t].join(\"\\n\");\n}\n\n/**\n * Replace every historical goal continuation payload with one current compact projection. The\n * projection exists only in the provider request returned from context assembly; it is never\n * appended to the transcript or session log.\n */\nexport function injectCompactGoalContext(messages: AgentMessage[], state: GoalState | undefined): AgentMessage[] {\n\tconst continuationTurn = messages.some(\n\t\t(message) =>\n\t\t\t(message.role === \"custom\" && message.customType === GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE) ||\n\t\t\tmessageText(message).startsWith(LEGACY_GOAL_CONTINUATION_PREFIX),\n\t);\n\tconst filtered = messages.filter((message) => !isGoalContextMessage(message));\n\tif (!state || state.status !== \"active\") return filtered;\n\treturn [\n\t\t...filtered,\n\t\tcreateCustomMessage(\n\t\t\tACTIVE_GOAL_CONTEXT_CUSTOM_TYPE,\n\t\t\tformatCompactGoalContext(state, continuationTurn),\n\t\t\tfalse,\n\t\t\t{ goalId: state.goalId, revision: state.revision ?? 0 },\n\t\t\tnew Date().toISOString(),\n\t\t),\n\t];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"goal-acceptance.d.ts","sourceRoot":"","sources":["../../../src/core/goals/goal-acceptance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE/E,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAExE;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,GAAG,eAAe,EAAE,CAG3G;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,EAAE,CAOxE;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAQnE","sourcesContent":["import type { GoalEvidenceRef, GoalState, Requirement } from \"./goal-state.ts\";\n\nexport function isTrustedGoalEvidence(evidence: GoalEvidenceRef): boolean {\n\treturn evidence.kind === \"user\" || evidence.verified === true;\n}\n\nexport function getTrustedRequirementEvidence(state: GoalState, requirement: Requirement): GoalEvidenceRef[] {\n\tconst evidenceIds = new Set(requirement.evidenceIds);\n\treturn state.evidence.filter((evidence) => evidenceIds.has(evidence.id) && isTrustedGoalEvidence(evidence));\n}\n\nexport function getUnprovenGoalRequirementIds(state: GoalState): string[] {\n\treturn state.requirements\n\t\t.filter(\n\t\t\t(requirement) =>\n\t\t\t\trequirement.status !== \"satisfied\" || getTrustedRequirementEvidence(state, requirement).length === 0,\n\t\t)\n\t\t.map((requirement) => requirement.id);\n}\n\n/**\n * Human/manual completion and the explicit evidence-gate opt-out are authoritative overrides.\n * Completion events written before the flag existed are treated as legacy owner decisions so an\n * already-completed persisted goal cannot strand durable work during resume.\n */\nexport function hasGoalAcceptanceOverride(state: GoalState): boolean {\n\tconst completion = [...state.events]\n\t\t.reverse()\n\t\t.find((event) => event.type === \"complete_goal\" || event.type === \"complete_goal_manually\");\n\treturn (\n\t\tcompletion?.type === \"complete_goal_manually\" ||\n\t\t(completion?.type === \"complete_goal\" && completion.acceptanceOverride !== false)\n\t);\n}\n"]}
1
+ {"version":3,"file":"goal-acceptance.d.ts","sourceRoot":"","sources":["../../../src/core/goals/goal-acceptance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE/E,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAExE;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,GAAG,eAAe,EAAE,CAG3G;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,EAAE,CAOxE;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CASnE","sourcesContent":["import type { GoalEvidenceRef, GoalState, Requirement } from \"./goal-state.ts\";\n\nexport function isTrustedGoalEvidence(evidence: GoalEvidenceRef): boolean {\n\treturn evidence.kind === \"user\" || evidence.verified === true;\n}\n\nexport function getTrustedRequirementEvidence(state: GoalState, requirement: Requirement): GoalEvidenceRef[] {\n\tconst evidenceIds = new Set(requirement.evidenceIds);\n\treturn state.evidence.filter((evidence) => evidenceIds.has(evidence.id) && isTrustedGoalEvidence(evidence));\n}\n\nexport function getUnprovenGoalRequirementIds(state: GoalState): string[] {\n\treturn state.requirements\n\t\t.filter(\n\t\t\t(requirement) =>\n\t\t\t\trequirement.status !== \"satisfied\" || getTrustedRequirementEvidence(state, requirement).length === 0,\n\t\t)\n\t\t.map((requirement) => requirement.id);\n}\n\n/**\n * Human/manual completion and the explicit evidence-gate opt-out are authoritative overrides.\n * Completion events written before the flag existed are treated as legacy owner decisions so an\n * already-completed persisted goal cannot strand durable work during resume.\n */\nexport function hasGoalAcceptanceOverride(state: GoalState): boolean {\n\tif (state.acceptanceOverride !== undefined) return state.acceptanceOverride;\n\tconst completion = [...state.events]\n\t\t.reverse()\n\t\t.find((event) => event.type === \"complete_goal\" || event.type === \"complete_goal_manually\");\n\treturn (\n\t\tcompletion?.type === \"complete_goal_manually\" ||\n\t\t(completion?.type === \"complete_goal\" && completion.acceptanceOverride !== false)\n\t);\n}\n"]}
@@ -16,6 +16,8 @@ export function getUnprovenGoalRequirementIds(state) {
16
16
  * already-completed persisted goal cannot strand durable work during resume.
17
17
  */
18
18
  export function hasGoalAcceptanceOverride(state) {
19
+ if (state.acceptanceOverride !== undefined)
20
+ return state.acceptanceOverride;
19
21
  const completion = [...state.events]
20
22
  .reverse()
21
23
  .find((event) => event.type === "complete_goal" || event.type === "complete_goal_manually");
@@ -1 +1 @@
1
- {"version":3,"file":"goal-acceptance.js","sourceRoot":"","sources":["../../../src/core/goals/goal-acceptance.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,qBAAqB,CAAC,QAAyB,EAAW;IACzE,OAAO,QAAQ,CAAC,IAAI,KAAK,MAAM,IAAI,QAAQ,CAAC,QAAQ,KAAK,IAAI,CAAC;AAAA,CAC9D;AAED,MAAM,UAAU,6BAA6B,CAAC,KAAgB,EAAE,WAAwB,EAAqB;IAC5G,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;IACrD,OAAO,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,qBAAqB,CAAC,QAAQ,CAAC,CAAC,CAAC;AAAA,CAC5G;AAED,MAAM,UAAU,6BAA6B,CAAC,KAAgB,EAAY;IACzE,OAAO,KAAK,CAAC,YAAY;SACvB,MAAM,CACN,CAAC,WAAW,EAAE,EAAE,CACf,WAAW,CAAC,MAAM,KAAK,WAAW,IAAI,6BAA6B,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,MAAM,KAAK,CAAC,CACrG;SACA,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;AAAA,CACvC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,KAAgB,EAAW;IACpE,MAAM,UAAU,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;SAClC,OAAO,EAAE;SACT,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,eAAe,IAAI,KAAK,CAAC,IAAI,KAAK,wBAAwB,CAAC,CAAC;IAC7F,OAAO,CACN,UAAU,EAAE,IAAI,KAAK,wBAAwB;QAC7C,CAAC,UAAU,EAAE,IAAI,KAAK,eAAe,IAAI,UAAU,CAAC,kBAAkB,KAAK,KAAK,CAAC,CACjF,CAAC;AAAA,CACF","sourcesContent":["import type { GoalEvidenceRef, GoalState, Requirement } from \"./goal-state.ts\";\n\nexport function isTrustedGoalEvidence(evidence: GoalEvidenceRef): boolean {\n\treturn evidence.kind === \"user\" || evidence.verified === true;\n}\n\nexport function getTrustedRequirementEvidence(state: GoalState, requirement: Requirement): GoalEvidenceRef[] {\n\tconst evidenceIds = new Set(requirement.evidenceIds);\n\treturn state.evidence.filter((evidence) => evidenceIds.has(evidence.id) && isTrustedGoalEvidence(evidence));\n}\n\nexport function getUnprovenGoalRequirementIds(state: GoalState): string[] {\n\treturn state.requirements\n\t\t.filter(\n\t\t\t(requirement) =>\n\t\t\t\trequirement.status !== \"satisfied\" || getTrustedRequirementEvidence(state, requirement).length === 0,\n\t\t)\n\t\t.map((requirement) => requirement.id);\n}\n\n/**\n * Human/manual completion and the explicit evidence-gate opt-out are authoritative overrides.\n * Completion events written before the flag existed are treated as legacy owner decisions so an\n * already-completed persisted goal cannot strand durable work during resume.\n */\nexport function hasGoalAcceptanceOverride(state: GoalState): boolean {\n\tconst completion = [...state.events]\n\t\t.reverse()\n\t\t.find((event) => event.type === \"complete_goal\" || event.type === \"complete_goal_manually\");\n\treturn (\n\t\tcompletion?.type === \"complete_goal_manually\" ||\n\t\t(completion?.type === \"complete_goal\" && completion.acceptanceOverride !== false)\n\t);\n}\n"]}
1
+ {"version":3,"file":"goal-acceptance.js","sourceRoot":"","sources":["../../../src/core/goals/goal-acceptance.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,qBAAqB,CAAC,QAAyB,EAAW;IACzE,OAAO,QAAQ,CAAC,IAAI,KAAK,MAAM,IAAI,QAAQ,CAAC,QAAQ,KAAK,IAAI,CAAC;AAAA,CAC9D;AAED,MAAM,UAAU,6BAA6B,CAAC,KAAgB,EAAE,WAAwB,EAAqB;IAC5G,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;IACrD,OAAO,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,qBAAqB,CAAC,QAAQ,CAAC,CAAC,CAAC;AAAA,CAC5G;AAED,MAAM,UAAU,6BAA6B,CAAC,KAAgB,EAAY;IACzE,OAAO,KAAK,CAAC,YAAY;SACvB,MAAM,CACN,CAAC,WAAW,EAAE,EAAE,CACf,WAAW,CAAC,MAAM,KAAK,WAAW,IAAI,6BAA6B,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,MAAM,KAAK,CAAC,CACrG;SACA,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;AAAA,CACvC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,KAAgB,EAAW;IACpE,IAAI,KAAK,CAAC,kBAAkB,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,kBAAkB,CAAC;IAC5E,MAAM,UAAU,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;SAClC,OAAO,EAAE;SACT,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,eAAe,IAAI,KAAK,CAAC,IAAI,KAAK,wBAAwB,CAAC,CAAC;IAC7F,OAAO,CACN,UAAU,EAAE,IAAI,KAAK,wBAAwB;QAC7C,CAAC,UAAU,EAAE,IAAI,KAAK,eAAe,IAAI,UAAU,CAAC,kBAAkB,KAAK,KAAK,CAAC,CACjF,CAAC;AAAA,CACF","sourcesContent":["import type { GoalEvidenceRef, GoalState, Requirement } from \"./goal-state.ts\";\n\nexport function isTrustedGoalEvidence(evidence: GoalEvidenceRef): boolean {\n\treturn evidence.kind === \"user\" || evidence.verified === true;\n}\n\nexport function getTrustedRequirementEvidence(state: GoalState, requirement: Requirement): GoalEvidenceRef[] {\n\tconst evidenceIds = new Set(requirement.evidenceIds);\n\treturn state.evidence.filter((evidence) => evidenceIds.has(evidence.id) && isTrustedGoalEvidence(evidence));\n}\n\nexport function getUnprovenGoalRequirementIds(state: GoalState): string[] {\n\treturn state.requirements\n\t\t.filter(\n\t\t\t(requirement) =>\n\t\t\t\trequirement.status !== \"satisfied\" || getTrustedRequirementEvidence(state, requirement).length === 0,\n\t\t)\n\t\t.map((requirement) => requirement.id);\n}\n\n/**\n * Human/manual completion and the explicit evidence-gate opt-out are authoritative overrides.\n * Completion events written before the flag existed are treated as legacy owner decisions so an\n * already-completed persisted goal cannot strand durable work during resume.\n */\nexport function hasGoalAcceptanceOverride(state: GoalState): boolean {\n\tif (state.acceptanceOverride !== undefined) return state.acceptanceOverride;\n\tconst completion = [...state.events]\n\t\t.reverse()\n\t\t.find((event) => event.type === \"complete_goal\" || event.type === \"complete_goal_manually\");\n\treturn (\n\t\tcompletion?.type === \"complete_goal_manually\" ||\n\t\t(completion?.type === \"complete_goal\" && completion.acceptanceOverride !== false)\n\t);\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import type { AgentSessionEvent, GoalContinuationLoopOptions, GoalContinuationLoopResult, PromptOptions } from "../agent-session.ts";
2
- import { type ModelCapabilityProfile } from "../model-capability.ts";
2
+ import type { ModelCapabilityProfile } from "../model-capability.ts";
3
3
  import type { SettingsManager } from "../settings-manager.ts";
4
4
  import type { GoalRuntimeSnapshot, GoalRuntimeSnapshotSettings } from "./goal-runtime-snapshot.ts";
5
5
  export interface GoalAutoContinueControllerDeps {
@@ -10,6 +10,7 @@ export interface GoalAutoContinueControllerDeps {
10
10
  getGoalRuntimeSnapshot(settings: GoalRuntimeSnapshotSettings): GoalRuntimeSnapshot;
11
11
  hasInFlightLaneForGoal(goalId: string): boolean;
12
12
  continueGoalLoop(options: GoalContinuationLoopOptions): Promise<GoalContinuationLoopResult>;
13
+ markGoalToolUnavailable(): void;
13
14
  emit(event: AgentSessionEvent): void;
14
15
  }
15
16
  /** Owns the single-flight goal continuation loop and its foreground-idle timer. */
@@ -1 +1 @@
1
- {"version":3,"file":"goal-auto-continue-controller.d.ts","sourceRoot":"","sources":["../../../src/core/goals/goal-auto-continue-controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,iBAAiB,EACjB,2BAA2B,EAC3B,0BAA0B,EAC1B,aAAa,EACb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,sBAAsB,EAAyC,MAAM,wBAAwB,CAAC;AAC5G,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAEnG,MAAM,WAAW,8BAA8B;IAC9C,UAAU,IAAI,OAAO,CAAC;IACtB,gBAAgB,IAAI,OAAO,CAAC;IAC5B,kBAAkB,IAAI,eAAe,CAAC;IACtC,yBAAyB,IAAI,sBAAsB,CAAC;IACpD,sBAAsB,CAAC,QAAQ,EAAE,2BAA2B,GAAG,mBAAmB,CAAC;IACnF,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAChD,gBAAgB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC5F,IAAI,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;CACrC;AAED,mFAAmF;AACnF,qBAAa,0BAA0B;IACtC,OAAO,CAAC,MAAM,CAA4C;IAC1D,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiC;IAEtD,YAAY,IAAI,EAAE,8BAA8B,EAE/C;IAED,UAAU,IAAI,IAAI,CAKjB;IAED,gBAAgB,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,CAuB9C;IAEK,iBAAiB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAUjG;YAEa,YAAY;IAwB1B,OAAO,CAAC,aAAa;CAUrB","sourcesContent":["import type {\n\tAgentSessionEvent,\n\tGoalContinuationLoopOptions,\n\tGoalContinuationLoopResult,\n\tPromptOptions,\n} from \"../agent-session.ts\";\nimport { type ModelCapabilityProfile, scaleContinuationBudgetsForCapability } from \"../model-capability.ts\";\nimport type { SettingsManager } from \"../settings-manager.ts\";\nimport type { GoalRuntimeSnapshot, GoalRuntimeSnapshotSettings } from \"./goal-runtime-snapshot.ts\";\n\nexport interface GoalAutoContinueControllerDeps {\n\tisDisposed(): boolean;\n\tisGoalToolActive(): boolean;\n\tgetSettingsManager(): SettingsManager;\n\tgetModelCapabilityProfile(): ModelCapabilityProfile;\n\tgetGoalRuntimeSnapshot(settings: GoalRuntimeSnapshotSettings): GoalRuntimeSnapshot;\n\thasInFlightLaneForGoal(goalId: string): boolean;\n\tcontinueGoalLoop(options: GoalContinuationLoopOptions): Promise<GoalContinuationLoopResult>;\n\temit(event: AgentSessionEvent): void;\n}\n\n/** Owns the single-flight goal continuation loop and its foreground-idle timer. */\nexport class GoalAutoContinueController {\n\tprivate _timer: ReturnType<typeof setTimeout> | undefined;\n\tprivate _isContinuing = false;\n\tprivate readonly deps: GoalAutoContinueControllerDeps;\n\n\tconstructor(deps: GoalAutoContinueControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tclearTimer(): void {\n\t\tif (this._timer !== undefined) {\n\t\t\tclearTimeout(this._timer);\n\t\t\tthis._timer = undefined;\n\t\t}\n\t}\n\n\tscheduleFromIdle(options?: PromptOptions): void {\n\t\tif (options?.autoContinueGoal === false || this._isContinuing || this.deps.isDisposed()) return;\n\t\tif (!this.deps.getModelCapabilityProfile().backgroundLanesEnabled) return;\n\n\t\tconst { maxStallTurns, goalAutoContinue, goalAutoContinueDelayMs } = this.deps\n\t\t\t.getSettingsManager()\n\t\t\t.getAutonomySettings();\n\t\tif (!goalAutoContinue) return;\n\t\tconst snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns });\n\t\tif (snapshot.continuation.action !== \"continue\") return;\n\t\tconst activeGoalId = snapshot.goalState?.goalId;\n\t\tif (activeGoalId !== undefined && this.deps.hasInFlightLaneForGoal(activeGoalId)) return;\n\n\t\tthis.clearTimer();\n\t\tthis._timer = setTimeout(() => {\n\t\t\tthis._timer = undefined;\n\t\t\tvoid this.runScheduled();\n\t\t}, goalAutoContinueDelayMs);\n\t\tconst timer = this._timer;\n\t\tif (typeof timer === \"object\" && timer && \"unref\" in timer) {\n\t\t\tconst { unref } = timer as { unref?: () => void };\n\t\t\tunref?.call(timer);\n\t\t}\n\t}\n\n\tasync continueExclusive(options: GoalContinuationLoopOptions): Promise<GoalContinuationLoopResult> {\n\t\tif (this._isContinuing) return this.skippedResult(options, \"already_continuing\");\n\t\tif (this.deps.isDisposed()) return this.skippedResult(options, \"session_disposed\");\n\t\tif (!this.deps.isGoalToolActive()) return this.skippedResult(options, \"goal_tool_unavailable\");\n\t\tthis._isContinuing = true;\n\t\ttry {\n\t\t\treturn await this.deps.continueGoalLoop(options);\n\t\t} finally {\n\t\t\tthis._isContinuing = false;\n\t\t}\n\t}\n\n\tprivate async runScheduled(): Promise<void> {\n\t\tif (this._isContinuing || this.deps.isDisposed()) return;\n\t\tconst { maxStallTurns, goalContinueTurns, goalContinueMaxWallClockMinutes, goalAutoContinue } = this.deps\n\t\t\t.getSettingsManager()\n\t\t\t.getAutonomySettings();\n\t\tif (!goalAutoContinue) return;\n\t\tconst snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns });\n\t\tif (snapshot.continuation.action !== \"continue\") return;\n\t\tconst scaled = scaleContinuationBudgetsForCapability(this.deps.getModelCapabilityProfile(), {\n\t\t\tmaxTurns: goalContinueTurns,\n\t\t\tmaxWallClockMinutes: goalContinueMaxWallClockMinutes,\n\t\t});\n\t\ttry {\n\t\t\tawait this.continueExclusive({\n\t\t\t\tmaxTurns: scaled.maxTurns,\n\t\t\t\tmaxStallTurns,\n\t\t\t\tmaxWallClockMinutes: scaled.maxWallClockMinutes,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthis.deps.emit({ type: \"warning\", message: `Goal auto-continuation failed: ${message}` });\n\t\t}\n\t}\n\n\tprivate skippedResult(\n\t\toptions: GoalContinuationLoopOptions,\n\t\tstopReason: \"already_continuing\" | \"session_disposed\" | \"goal_tool_unavailable\",\n\t): GoalContinuationLoopResult {\n\t\treturn {\n\t\t\tturnsSubmitted: 0,\n\t\t\tstopReason,\n\t\t\tfinalSnapshot: this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns }),\n\t\t};\n\t}\n}\n"]}
1
+ {"version":3,"file":"goal-auto-continue-controller.d.ts","sourceRoot":"","sources":["../../../src/core/goals/goal-auto-continue-controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,iBAAiB,EACjB,2BAA2B,EAC3B,0BAA0B,EAC1B,aAAa,EACb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAEnG,MAAM,WAAW,8BAA8B;IAC9C,UAAU,IAAI,OAAO,CAAC;IACtB,gBAAgB,IAAI,OAAO,CAAC;IAC5B,kBAAkB,IAAI,eAAe,CAAC;IACtC,yBAAyB,IAAI,sBAAsB,CAAC;IACpD,sBAAsB,CAAC,QAAQ,EAAE,2BAA2B,GAAG,mBAAmB,CAAC;IACnF,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAChD,gBAAgB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC5F,uBAAuB,IAAI,IAAI,CAAC;IAChC,IAAI,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;CACrC;AAED,mFAAmF;AACnF,qBAAa,0BAA0B;IACtC,OAAO,CAAC,MAAM,CAA4C;IAC1D,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiC;IAEtD,YAAY,IAAI,EAAE,8BAA8B,EAE/C;IAED,UAAU,IAAI,IAAI,CAKjB;IAED,gBAAgB,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,CAuB9C;IAEK,iBAAiB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAajG;YAEa,YAAY;IAoB1B,OAAO,CAAC,aAAa;CAUrB","sourcesContent":["import type {\n\tAgentSessionEvent,\n\tGoalContinuationLoopOptions,\n\tGoalContinuationLoopResult,\n\tPromptOptions,\n} from \"../agent-session.ts\";\nimport type { ModelCapabilityProfile } from \"../model-capability.ts\";\nimport type { SettingsManager } from \"../settings-manager.ts\";\nimport type { GoalRuntimeSnapshot, GoalRuntimeSnapshotSettings } from \"./goal-runtime-snapshot.ts\";\n\nexport interface GoalAutoContinueControllerDeps {\n\tisDisposed(): boolean;\n\tisGoalToolActive(): boolean;\n\tgetSettingsManager(): SettingsManager;\n\tgetModelCapabilityProfile(): ModelCapabilityProfile;\n\tgetGoalRuntimeSnapshot(settings: GoalRuntimeSnapshotSettings): GoalRuntimeSnapshot;\n\thasInFlightLaneForGoal(goalId: string): boolean;\n\tcontinueGoalLoop(options: GoalContinuationLoopOptions): Promise<GoalContinuationLoopResult>;\n\tmarkGoalToolUnavailable(): void;\n\temit(event: AgentSessionEvent): void;\n}\n\n/** Owns the single-flight goal continuation loop and its foreground-idle timer. */\nexport class GoalAutoContinueController {\n\tprivate _timer: ReturnType<typeof setTimeout> | undefined;\n\tprivate _isContinuing = false;\n\tprivate readonly deps: GoalAutoContinueControllerDeps;\n\n\tconstructor(deps: GoalAutoContinueControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tclearTimer(): void {\n\t\tif (this._timer !== undefined) {\n\t\t\tclearTimeout(this._timer);\n\t\t\tthis._timer = undefined;\n\t\t}\n\t}\n\n\tscheduleFromIdle(options?: PromptOptions): void {\n\t\tif (options?.autoContinueGoal === false || this._isContinuing || this.deps.isDisposed()) return;\n\t\tif (!this.deps.getModelCapabilityProfile().backgroundLanesEnabled) return;\n\n\t\tconst { maxStallTurns, goalAutoContinue, goalAutoContinueDelayMs } = this.deps\n\t\t\t.getSettingsManager()\n\t\t\t.getAutonomySettings();\n\t\tif (!goalAutoContinue) return;\n\t\tconst snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns });\n\t\tif (snapshot.continuation.action !== \"continue\") return;\n\t\tconst activeGoalId = snapshot.goalState?.goalId;\n\t\tif (activeGoalId !== undefined && this.deps.hasInFlightLaneForGoal(activeGoalId)) return;\n\n\t\tthis.clearTimer();\n\t\tthis._timer = setTimeout(() => {\n\t\t\tthis._timer = undefined;\n\t\t\tvoid this.runScheduled();\n\t\t}, goalAutoContinueDelayMs);\n\t\tconst timer = this._timer;\n\t\tif (typeof timer === \"object\" && timer && \"unref\" in timer) {\n\t\t\tconst { unref } = timer as { unref?: () => void };\n\t\t\tunref?.call(timer);\n\t\t}\n\t}\n\n\tasync continueExclusive(options: GoalContinuationLoopOptions): Promise<GoalContinuationLoopResult> {\n\t\tif (this._isContinuing) return this.skippedResult(options, \"already_continuing\");\n\t\tif (this.deps.isDisposed()) return this.skippedResult(options, \"session_disposed\");\n\t\tif (!this.deps.isGoalToolActive()) {\n\t\t\tthis.deps.markGoalToolUnavailable();\n\t\t\treturn this.skippedResult(options, \"goal_tool_unavailable\");\n\t\t}\n\t\tthis._isContinuing = true;\n\t\ttry {\n\t\t\treturn await this.deps.continueGoalLoop(options);\n\t\t} finally {\n\t\t\tthis._isContinuing = false;\n\t\t}\n\t}\n\n\tprivate async runScheduled(): Promise<void> {\n\t\tif (this._isContinuing || this.deps.isDisposed()) return;\n\t\tconst { maxStallTurns, goalContinueTurns, goalContinueMaxWallClockMinutes, goalAutoContinue } = this.deps\n\t\t\t.getSettingsManager()\n\t\t\t.getAutonomySettings();\n\t\tif (!goalAutoContinue) return;\n\t\tconst snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns });\n\t\tif (snapshot.continuation.action !== \"continue\") return;\n\t\ttry {\n\t\t\tawait this.continueExclusive({\n\t\t\t\tmaxTurns: goalContinueTurns,\n\t\t\t\tmaxStallTurns,\n\t\t\t\tmaxWallClockMinutes: goalContinueMaxWallClockMinutes,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthis.deps.emit({ type: \"warning\", message: `Goal auto-continuation failed: ${message}` });\n\t\t}\n\t}\n\n\tprivate skippedResult(\n\t\toptions: GoalContinuationLoopOptions,\n\t\tstopReason: \"already_continuing\" | \"session_disposed\" | \"goal_tool_unavailable\",\n\t): GoalContinuationLoopResult {\n\t\treturn {\n\t\t\tturnsSubmitted: 0,\n\t\t\tstopReason,\n\t\t\tfinalSnapshot: this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns }),\n\t\t};\n\t}\n}\n"]}
@@ -1,4 +1,3 @@
1
- import { scaleContinuationBudgetsForCapability } from "../model-capability.js";
2
1
  /** Owns the single-flight goal continuation loop and its foreground-idle timer. */
3
2
  export class GoalAutoContinueController {
4
3
  _timer;
@@ -45,8 +44,10 @@ export class GoalAutoContinueController {
45
44
  return this.skippedResult(options, "already_continuing");
46
45
  if (this.deps.isDisposed())
47
46
  return this.skippedResult(options, "session_disposed");
48
- if (!this.deps.isGoalToolActive())
47
+ if (!this.deps.isGoalToolActive()) {
48
+ this.deps.markGoalToolUnavailable();
49
49
  return this.skippedResult(options, "goal_tool_unavailable");
50
+ }
50
51
  this._isContinuing = true;
51
52
  try {
52
53
  return await this.deps.continueGoalLoop(options);
@@ -66,15 +67,11 @@ export class GoalAutoContinueController {
66
67
  const snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns });
67
68
  if (snapshot.continuation.action !== "continue")
68
69
  return;
69
- const scaled = scaleContinuationBudgetsForCapability(this.deps.getModelCapabilityProfile(), {
70
- maxTurns: goalContinueTurns,
71
- maxWallClockMinutes: goalContinueMaxWallClockMinutes,
72
- });
73
70
  try {
74
71
  await this.continueExclusive({
75
- maxTurns: scaled.maxTurns,
72
+ maxTurns: goalContinueTurns,
76
73
  maxStallTurns,
77
- maxWallClockMinutes: scaled.maxWallClockMinutes,
74
+ maxWallClockMinutes: goalContinueMaxWallClockMinutes,
78
75
  });
79
76
  }
80
77
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"goal-auto-continue-controller.js","sourceRoot":"","sources":["../../../src/core/goals/goal-auto-continue-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tAgentSessionEvent,\n\tGoalContinuationLoopOptions,\n\tGoalContinuationLoopResult,\n\tPromptOptions,\n} from \"../agent-session.ts\";\nimport { type ModelCapabilityProfile, scaleContinuationBudgetsForCapability } from \"../model-capability.ts\";\nimport type { SettingsManager } from \"../settings-manager.ts\";\nimport type { GoalRuntimeSnapshot, GoalRuntimeSnapshotSettings } from \"./goal-runtime-snapshot.ts\";\n\nexport interface GoalAutoContinueControllerDeps {\n\tisDisposed(): boolean;\n\tisGoalToolActive(): boolean;\n\tgetSettingsManager(): SettingsManager;\n\tgetModelCapabilityProfile(): ModelCapabilityProfile;\n\tgetGoalRuntimeSnapshot(settings: GoalRuntimeSnapshotSettings): GoalRuntimeSnapshot;\n\thasInFlightLaneForGoal(goalId: string): boolean;\n\tcontinueGoalLoop(options: GoalContinuationLoopOptions): Promise<GoalContinuationLoopResult>;\n\temit(event: AgentSessionEvent): void;\n}\n\n/** Owns the single-flight goal continuation loop and its foreground-idle timer. */\nexport class GoalAutoContinueController {\n\tprivate _timer: ReturnType<typeof setTimeout> | undefined;\n\tprivate _isContinuing = false;\n\tprivate readonly deps: GoalAutoContinueControllerDeps;\n\n\tconstructor(deps: GoalAutoContinueControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tclearTimer(): void {\n\t\tif (this._timer !== undefined) {\n\t\t\tclearTimeout(this._timer);\n\t\t\tthis._timer = undefined;\n\t\t}\n\t}\n\n\tscheduleFromIdle(options?: PromptOptions): void {\n\t\tif (options?.autoContinueGoal === false || this._isContinuing || this.deps.isDisposed()) return;\n\t\tif (!this.deps.getModelCapabilityProfile().backgroundLanesEnabled) return;\n\n\t\tconst { maxStallTurns, goalAutoContinue, goalAutoContinueDelayMs } = this.deps\n\t\t\t.getSettingsManager()\n\t\t\t.getAutonomySettings();\n\t\tif (!goalAutoContinue) return;\n\t\tconst snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns });\n\t\tif (snapshot.continuation.action !== \"continue\") return;\n\t\tconst activeGoalId = snapshot.goalState?.goalId;\n\t\tif (activeGoalId !== undefined && this.deps.hasInFlightLaneForGoal(activeGoalId)) return;\n\n\t\tthis.clearTimer();\n\t\tthis._timer = setTimeout(() => {\n\t\t\tthis._timer = undefined;\n\t\t\tvoid this.runScheduled();\n\t\t}, goalAutoContinueDelayMs);\n\t\tconst timer = this._timer;\n\t\tif (typeof timer === \"object\" && timer && \"unref\" in timer) {\n\t\t\tconst { unref } = timer as { unref?: () => void };\n\t\t\tunref?.call(timer);\n\t\t}\n\t}\n\n\tasync continueExclusive(options: GoalContinuationLoopOptions): Promise<GoalContinuationLoopResult> {\n\t\tif (this._isContinuing) return this.skippedResult(options, \"already_continuing\");\n\t\tif (this.deps.isDisposed()) return this.skippedResult(options, \"session_disposed\");\n\t\tif (!this.deps.isGoalToolActive()) return this.skippedResult(options, \"goal_tool_unavailable\");\n\t\tthis._isContinuing = true;\n\t\ttry {\n\t\t\treturn await this.deps.continueGoalLoop(options);\n\t\t} finally {\n\t\t\tthis._isContinuing = false;\n\t\t}\n\t}\n\n\tprivate async runScheduled(): Promise<void> {\n\t\tif (this._isContinuing || this.deps.isDisposed()) return;\n\t\tconst { maxStallTurns, goalContinueTurns, goalContinueMaxWallClockMinutes, goalAutoContinue } = this.deps\n\t\t\t.getSettingsManager()\n\t\t\t.getAutonomySettings();\n\t\tif (!goalAutoContinue) return;\n\t\tconst snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns });\n\t\tif (snapshot.continuation.action !== \"continue\") return;\n\t\tconst scaled = scaleContinuationBudgetsForCapability(this.deps.getModelCapabilityProfile(), {\n\t\t\tmaxTurns: goalContinueTurns,\n\t\t\tmaxWallClockMinutes: goalContinueMaxWallClockMinutes,\n\t\t});\n\t\ttry {\n\t\t\tawait this.continueExclusive({\n\t\t\t\tmaxTurns: scaled.maxTurns,\n\t\t\t\tmaxStallTurns,\n\t\t\t\tmaxWallClockMinutes: scaled.maxWallClockMinutes,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthis.deps.emit({ type: \"warning\", message: `Goal auto-continuation failed: ${message}` });\n\t\t}\n\t}\n\n\tprivate skippedResult(\n\t\toptions: GoalContinuationLoopOptions,\n\t\tstopReason: \"already_continuing\" | \"session_disposed\" | \"goal_tool_unavailable\",\n\t): GoalContinuationLoopResult {\n\t\treturn {\n\t\t\tturnsSubmitted: 0,\n\t\t\tstopReason,\n\t\t\tfinalSnapshot: this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns }),\n\t\t};\n\t}\n}\n"]}
1
+ {"version":3,"file":"goal-auto-continue-controller.js","sourceRoot":"","sources":["../../../src/core/goals/goal-auto-continue-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tAgentSessionEvent,\n\tGoalContinuationLoopOptions,\n\tGoalContinuationLoopResult,\n\tPromptOptions,\n} from \"../agent-session.ts\";\nimport type { ModelCapabilityProfile } from \"../model-capability.ts\";\nimport type { SettingsManager } from \"../settings-manager.ts\";\nimport type { GoalRuntimeSnapshot, GoalRuntimeSnapshotSettings } from \"./goal-runtime-snapshot.ts\";\n\nexport interface GoalAutoContinueControllerDeps {\n\tisDisposed(): boolean;\n\tisGoalToolActive(): boolean;\n\tgetSettingsManager(): SettingsManager;\n\tgetModelCapabilityProfile(): ModelCapabilityProfile;\n\tgetGoalRuntimeSnapshot(settings: GoalRuntimeSnapshotSettings): GoalRuntimeSnapshot;\n\thasInFlightLaneForGoal(goalId: string): boolean;\n\tcontinueGoalLoop(options: GoalContinuationLoopOptions): Promise<GoalContinuationLoopResult>;\n\tmarkGoalToolUnavailable(): void;\n\temit(event: AgentSessionEvent): void;\n}\n\n/** Owns the single-flight goal continuation loop and its foreground-idle timer. */\nexport class GoalAutoContinueController {\n\tprivate _timer: ReturnType<typeof setTimeout> | undefined;\n\tprivate _isContinuing = false;\n\tprivate readonly deps: GoalAutoContinueControllerDeps;\n\n\tconstructor(deps: GoalAutoContinueControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tclearTimer(): void {\n\t\tif (this._timer !== undefined) {\n\t\t\tclearTimeout(this._timer);\n\t\t\tthis._timer = undefined;\n\t\t}\n\t}\n\n\tscheduleFromIdle(options?: PromptOptions): void {\n\t\tif (options?.autoContinueGoal === false || this._isContinuing || this.deps.isDisposed()) return;\n\t\tif (!this.deps.getModelCapabilityProfile().backgroundLanesEnabled) return;\n\n\t\tconst { maxStallTurns, goalAutoContinue, goalAutoContinueDelayMs } = this.deps\n\t\t\t.getSettingsManager()\n\t\t\t.getAutonomySettings();\n\t\tif (!goalAutoContinue) return;\n\t\tconst snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns });\n\t\tif (snapshot.continuation.action !== \"continue\") return;\n\t\tconst activeGoalId = snapshot.goalState?.goalId;\n\t\tif (activeGoalId !== undefined && this.deps.hasInFlightLaneForGoal(activeGoalId)) return;\n\n\t\tthis.clearTimer();\n\t\tthis._timer = setTimeout(() => {\n\t\t\tthis._timer = undefined;\n\t\t\tvoid this.runScheduled();\n\t\t}, goalAutoContinueDelayMs);\n\t\tconst timer = this._timer;\n\t\tif (typeof timer === \"object\" && timer && \"unref\" in timer) {\n\t\t\tconst { unref } = timer as { unref?: () => void };\n\t\t\tunref?.call(timer);\n\t\t}\n\t}\n\n\tasync continueExclusive(options: GoalContinuationLoopOptions): Promise<GoalContinuationLoopResult> {\n\t\tif (this._isContinuing) return this.skippedResult(options, \"already_continuing\");\n\t\tif (this.deps.isDisposed()) return this.skippedResult(options, \"session_disposed\");\n\t\tif (!this.deps.isGoalToolActive()) {\n\t\t\tthis.deps.markGoalToolUnavailable();\n\t\t\treturn this.skippedResult(options, \"goal_tool_unavailable\");\n\t\t}\n\t\tthis._isContinuing = true;\n\t\ttry {\n\t\t\treturn await this.deps.continueGoalLoop(options);\n\t\t} finally {\n\t\t\tthis._isContinuing = false;\n\t\t}\n\t}\n\n\tprivate async runScheduled(): Promise<void> {\n\t\tif (this._isContinuing || this.deps.isDisposed()) return;\n\t\tconst { maxStallTurns, goalContinueTurns, goalContinueMaxWallClockMinutes, goalAutoContinue } = this.deps\n\t\t\t.getSettingsManager()\n\t\t\t.getAutonomySettings();\n\t\tif (!goalAutoContinue) return;\n\t\tconst snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns });\n\t\tif (snapshot.continuation.action !== \"continue\") return;\n\t\ttry {\n\t\t\tawait this.continueExclusive({\n\t\t\t\tmaxTurns: goalContinueTurns,\n\t\t\t\tmaxStallTurns,\n\t\t\t\tmaxWallClockMinutes: goalContinueMaxWallClockMinutes,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthis.deps.emit({ type: \"warning\", message: `Goal auto-continuation failed: ${message}` });\n\t\t}\n\t}\n\n\tprivate skippedResult(\n\t\toptions: GoalContinuationLoopOptions,\n\t\tstopReason: \"already_continuing\" | \"session_disposed\" | \"goal_tool_unavailable\",\n\t): GoalContinuationLoopResult {\n\t\treturn {\n\t\t\tturnsSubmitted: 0,\n\t\t\tstopReason,\n\t\t\tfinalSnapshot: this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns }),\n\t\t};\n\t}\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import type { GoalState } from "./goal-state.ts";
2
2
  export type GoalContinuationAction = "continue" | "ask-user" | "finalize" | "stop" | "waiting";
3
- export type GoalContinuationReasonCode = "goal_active" | "goal_completed" | "goal_blocked" | "goal_cancelled" | "stall_limit_reached" | "no_open_requirements" | "acceptance_evidence_required" | "blocked_requirements_present" | "missing_goal_state" | "worker_in_flight" | "worker_wait_timeout" | "lane_sync_conflict" | "lane_sync_required";
3
+ export type GoalContinuationReasonCode = "goal_active" | "goal_completed" | "goal_paused" | "goal_blocked" | "goal_usage_limited" | "goal_budget_limited" | "goal_cancelled" | "stall_limit_reached" | "goal_completion_required" | "acceptance_evidence_required" | "blocked_requirements_present" | "missing_goal_state" | "worker_in_flight" | "worker_wait_timeout" | "lane_sync_conflict" | "lane_sync_required";
4
4
  export interface GoalContinuationDecision {
5
5
  action: GoalContinuationAction;
6
6
  reasonCode: GoalContinuationReasonCode;
@@ -22,7 +22,7 @@ export declare function evaluateGoalContinuation(args: {
22
22
  * LaneIds currently queued/running AND tagged with THIS goal's id (see `LaneRecord.goalId`).
23
23
  * When an open requirement is bound (`Requirement.boundLaneId`) to one of these lanes, the
24
24
  * goal is WAITING on that worker rather than stalled or ready for another pass: the loop must not
25
- * submit a hollow continuation prompt (which would then misreport as `goal_state_not_advanced`),
25
+ * submit a hollow continuation prompt (which would waste a turn while no parent work can advance),
26
26
  * and the idle scheduler must not race a re-dispatch against the same open requirement. Optional
27
27
  * so every pre-existing (in-flight-unaware) caller keeps compiling and behaving unchanged.
28
28
  */